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
10 use Dompdf\Renderer\AbstractRenderer
;
11 use Dompdf\Renderer\Block
;
12 use Dompdf\Renderer\Image
;
13 use Dompdf\Renderer\ListBullet
;
14 use Dompdf\Renderer\TableCell
;
15 use Dompdf\Renderer\TableRowGroup
;
16 use Dompdf\Renderer\Text
;
21 * Instantiates several specific renderers in order to render any given frame.
25 class Renderer
extends AbstractRenderer
29 * Array of renderers for specific frame types
31 * @var AbstractRenderer[]
33 protected $_renderers;
36 * Cache of the callbacks array
43 * Advance the canvas to the next page
47 $this->_canvas
->new_page();
51 * Render frames recursively
53 * @param Frame $frame the frame to render
55 public function render(Frame
$frame)
57 global $_dompdf_debug;
59 $this->_check_callbacks("begin_frame", $frame);
66 $style = $frame->get_style();
68 if (in_array($style->visibility
, array("hidden", "collapse"))) {
72 $display = $style->display
;
74 // Starts the CSS transformation
75 if ($style->transform
&& is_array($style->transform
)) {
76 $this->_canvas
->save();
77 list($x, $y) = $frame->get_padding_box();
78 $origin = $style->transform_origin
;
80 foreach ($style->transform
as $transform) {
81 list($function, $values) = $transform;
82 if ($function === "matrix") {
83 $function = "transform";
86 $values = array_map("floatval", $values);
87 $values[] = $x +
(float)$style->length_in_pt($origin[0], (float)$style->length_in_pt($style->width
));
88 $values[] = $y +
(float)$style->length_in_pt($origin[1], (float)$style->length_in_pt($style->height
));
90 call_user_func_array(array($this->_canvas
, $function), $values);
101 $this->_render_frame("block", $frame);
105 if ($frame->is_text_node()) {
106 $this->_render_frame("text", $frame);
108 $this->_render_frame("inline", $frame);
113 $this->_render_frame("table-cell", $frame);
116 case "table-row-group":
117 case "table-header-group":
118 case "table-footer-group":
119 $this->_render_frame("table-row-group", $frame);
122 case "-dompdf-list-bullet":
123 $this->_render_frame("list-bullet", $frame);
126 case "-dompdf-image":
127 $this->_render_frame("image", $frame);
131 $node = $frame->get_node();
133 if ($node->nodeName
=== "script") {
134 if ($node->getAttribute("type") === "text/php" ||
135 $node->getAttribute("language") === "php"
137 // Evaluate embedded php scripts
138 $this->_render_frame("php", $frame);
139 } elseif ($node->getAttribute("type") === "text/javascript" ||
140 $node->getAttribute("language") === "javascript"
143 $this->_render_frame("javascript", $frame);
147 // Don't render children, so skip to next iter
155 // Starts the overflow: hidden box
156 if ($style->overflow
=== "hidden") {
157 list($x, $y, $w, $h) = $frame->get_padding_box();
160 $style = $frame->get_style();
161 list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
163 if ($tl +
$tr +
$br +
$bl > 0) {
164 $this->_canvas
->clipping_roundrectangle($x, $y, (float)$w, (float)$h, $tl, $tr, $br, $bl);
166 $this->_canvas
->clipping_rectangle($x, $y, (float)$w, (float)$h);
172 foreach ($frame->get_children() as $child) {
173 // < 0 : nagative z-index
174 // = 0 : no z-index, no stacking context
175 // = 1 : stacking context without z-index
177 $child_style = $child->get_style();
178 $child_z_index = $child_style->z_index
;
181 if ($child_z_index !== "auto") {
182 $z_index = intval($child_z_index) +
1;
183 } elseif ($child_style->float !== "none" ||
$child->is_positionned()) {
187 $stack[$z_index][] = $child;
192 foreach ($stack as $by_index) {
193 foreach ($by_index as $child) {
194 $this->render($child);
198 // Ends the overflow: hidden box
199 if ($style->overflow
=== "hidden") {
200 $this->_canvas
->clipping_end();
203 if ($style->transform
&& is_array($style->transform
)) {
204 $this->_canvas
->restore();
207 // Check for end frame callback
208 $this->_check_callbacks("end_frame", $frame);
212 * Check for callbacks that need to be performed when a given event
213 * gets triggered on a frame
215 * @param string $event the type of event
216 * @param Frame $frame the frame that event is triggered on
218 protected function _check_callbacks($event, $frame)
220 if (!isset($this->_callbacks
)) {
221 $this->_callbacks
= $this->_dompdf
->getCallbacks();
224 if (is_array($this->_callbacks
) && isset($this->_callbacks
[$event])) {
225 $info = array(0 => $this->_canvas
, "canvas" => $this->_canvas
,
226 1 => $frame, "frame" => $frame);
227 $fs = $this->_callbacks
[$event];
228 foreach ($fs as $f) {
229 if (is_callable($f)) {
231 $f[0]->{$f[1]}($info);
241 * Render a single frame
243 * Creates Renderer objects on demand
245 * @param string $type type of renderer to use
246 * @param Frame $frame the frame to render
248 protected function _render_frame($type, $frame)
251 if (!isset($this->_renderers
[$type])) {
255 $this->_renderers
[$type] = new Block($this->_dompdf
);
259 $this->_renderers
[$type] = new Renderer\
Inline($this->_dompdf
);
263 $this->_renderers
[$type] = new Text($this->_dompdf
);
267 $this->_renderers
[$type] = new Image($this->_dompdf
);
271 $this->_renderers
[$type] = new TableCell($this->_dompdf
);
274 case "table-row-group":
275 $this->_renderers
[$type] = new TableRowGroup($this->_dompdf
);
279 $this->_renderers
[$type] = new ListBullet($this->_dompdf
);
283 $this->_renderers
[$type] = new PhpEvaluator($this->_canvas
);
287 $this->_renderers
[$type] = new JavascriptEmbedder($this->_dompdf
);
293 $this->_renderers
[$type]->render($frame);