block_renderer.cls.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. /**
  3. * @package dompdf
  4. * @link http://dompdf.github.com/
  5. * @author Benj Carson <benjcarson@digitaljunkies.ca>
  6. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  7. */
  8. /**
  9. * Renders block frames
  10. *
  11. * @access private
  12. * @package dompdf
  13. */
  14. class Block_Renderer extends Abstract_Renderer {
  15. //........................................................................
  16. function render(Frame $frame) {
  17. $style = $frame->get_style();
  18. list($x, $y, $w, $h) = $frame->get_border_box();
  19. $this->_set_opacity( $frame->get_opacity( $style->opacity ) );
  20. if ( $frame->get_node()->nodeName === "body" ) {
  21. $h = $frame->get_containing_block("h") - $style->length_in_pt(array(
  22. $style->margin_top,
  23. $style->padding_top,
  24. $style->border_top_width,
  25. $style->border_bottom_width,
  26. $style->padding_bottom,
  27. $style->margin_bottom),
  28. $style->width);
  29. }
  30. // Draw our background, border and content
  31. list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
  32. if ( $tl + $tr + $br + $bl > 0 ) {
  33. $this->_canvas->clipping_roundrectangle( $x, $y, $w, $h, $tl, $tr, $br, $bl );
  34. }
  35. if ( ($bg = $style->background_color) !== "transparent" ) {
  36. $this->_canvas->filled_rectangle( $x, $y, $w, $h, $bg );
  37. }
  38. if ( ($url = $style->background_image) && $url !== "none" ) {
  39. $this->_background_image($url, $x, $y, $w, $h, $style);
  40. }
  41. if ( $tl + $tr + $br + $bl > 0 ) {
  42. $this->_canvas->clipping_end();
  43. }
  44. $this->_render_border($frame);
  45. $this->_render_outline($frame);
  46. if (DEBUG_LAYOUT && DEBUG_LAYOUT_BLOCKS) {
  47. $this->_debug_layout($frame->get_border_box(), "red");
  48. if (DEBUG_LAYOUT_PADDINGBOX) {
  49. $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5));
  50. }
  51. }
  52. if (DEBUG_LAYOUT && DEBUG_LAYOUT_LINES && $frame->get_decorator()) {
  53. foreach ($frame->get_decorator()->get_line_boxes() as $line) {
  54. $frame->_debug_layout(array($line->x, $line->y, $line->w, $line->h), "orange");
  55. }
  56. }
  57. }
  58. protected function _render_border(Frame_Decorator $frame, $corner_style = "bevel") {
  59. $style = $frame->get_style();
  60. $bbox = $frame->get_border_box();
  61. $bp = $style->get_border_properties();
  62. // find the radius
  63. $radius = $style->get_computed_border_radius($bbox["w"], $bbox["h"]);
  64. // Short-cut: If all the borders are "solid" with the same color and style, and no radius, we'd better draw a rectangle
  65. if (
  66. in_array($bp["top"]["style"], array("solid", "dashed", "dotted")) &&
  67. $bp["top"] == $bp["right"] &&
  68. $bp["right"] == $bp["bottom"] &&
  69. $bp["bottom"] == $bp["left"] &&
  70. array_sum($radius) == 0
  71. ) {
  72. $props = $bp["top"];
  73. if ( $props["color"] === "transparent" || $props["width"] <= 0 ) return;
  74. list($x, $y, $w, $h) = $bbox;
  75. $width = $style->length_in_pt($props["width"]);
  76. $pattern = $this->_get_dash_pattern($props["style"], $width);
  77. $this->_canvas->rectangle($x + $width / 2, $y + $width / 2, $w - $width, $h - $width, $props["color"], $width, $pattern);
  78. return;
  79. }
  80. // Do it the long way
  81. $widths = array($style->length_in_pt($bp["top"]["width"]),
  82. $style->length_in_pt($bp["right"]["width"]),
  83. $style->length_in_pt($bp["bottom"]["width"]),
  84. $style->length_in_pt($bp["left"]["width"]));
  85. foreach ($bp as $side => $props) {
  86. list($x, $y, $w, $h) = $bbox;
  87. $length = 0;
  88. $r1 = 0;
  89. $r2 = 0;
  90. if ( !$props["style"] ||
  91. $props["style"] === "none" ||
  92. $props["width"] <= 0 ||
  93. $props["color"] == "transparent" )
  94. continue;
  95. switch($side) {
  96. case "top":
  97. $length = $w;
  98. $r1 = $radius["top-left"];
  99. $r2 = $radius["top-right"];
  100. break;
  101. case "bottom":
  102. $length = $w;
  103. $y += $h;
  104. $r1 = $radius["bottom-left"];
  105. $r2 = $radius["bottom-right"];
  106. break;
  107. case "left":
  108. $length = $h;
  109. $r1 = $radius["top-left"];
  110. $r2 = $radius["bottom-left"];
  111. break;
  112. case "right":
  113. $length = $h;
  114. $x += $w;
  115. $r1 = $radius["top-right"];
  116. $r2 = $radius["bottom-right"];
  117. break;
  118. default:
  119. break;
  120. }
  121. $method = "_border_" . $props["style"];
  122. // draw rounded corners
  123. $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style, $r1, $r2);
  124. }
  125. }
  126. protected function _render_outline(Frame_Decorator $frame, $corner_style = "bevel") {
  127. $style = $frame->get_style();
  128. $props = array(
  129. "width" => $style->outline_width,
  130. "style" => $style->outline_style,
  131. "color" => $style->outline_color,
  132. );
  133. if ( !$props["style"] || $props["style"] === "none" || $props["width"] <= 0 )
  134. return;
  135. $bbox = $frame->get_border_box();
  136. $offset = $style->length_in_pt($props["width"]);
  137. $pattern = $this->_get_dash_pattern($props["style"], $offset);
  138. // If the outline style is "solid" we'd better draw a rectangle
  139. if ( in_array($props["style"], array("solid", "dashed", "dotted")) ) {
  140. $bbox[0] -= $offset / 2;
  141. $bbox[1] -= $offset / 2;
  142. $bbox[2] += $offset;
  143. $bbox[3] += $offset;
  144. list($x, $y, $w, $h) = $bbox;
  145. $this->_canvas->rectangle($x, $y, $w, $h, $props["color"], $offset, $pattern);
  146. return;
  147. }
  148. $bbox[0] -= $offset;
  149. $bbox[1] -= $offset;
  150. $bbox[2] += $offset * 2;
  151. $bbox[3] += $offset * 2;
  152. $method = "_border_" . $props["style"];
  153. $widths = array_fill(0, 4, $props["width"]);
  154. $sides = array("top", "right", "left", "bottom");
  155. $length = 0;
  156. foreach ($sides as $side) {
  157. list($x, $y, $w, $h) = $bbox;
  158. switch($side) {
  159. case "top":
  160. $length = $w;
  161. break;
  162. case "bottom":
  163. $length = $w;
  164. $y += $h;
  165. break;
  166. case "left":
  167. $length = $h;
  168. break;
  169. case "right":
  170. $length = $h;
  171. $x += $w;
  172. break;
  173. default:
  174. break;
  175. }
  176. $this->$method($x, $y, $length, $props["color"], $widths, $side, $corner_style);
  177. }
  178. }
  179. }