| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- <?php
- /**
- * @package dompdf
- * @link http://dompdf.github.com/
- * @author Benj Carson <benjcarson@digitaljunkies.ca>
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- */
- namespace Dompdf;
- use Dompdf\Renderer\AbstractRenderer;
- use Dompdf\Renderer\Block;
- use Dompdf\Renderer\Image;
- use Dompdf\Renderer\ListBullet;
- use Dompdf\Renderer\TableCell;
- use Dompdf\Renderer\TableRowGroup;
- use Dompdf\Renderer\Text;
- /**
- * Concrete renderer
- *
- * Instantiates several specific renderers in order to render any given frame.
- *
- * @package dompdf
- */
- class Renderer extends AbstractRenderer
- {
- /**
- * Array of renderers for specific frame types
- *
- * @var AbstractRenderer[]
- */
- protected $_renderers;
- /**
- * Cache of the callbacks array
- *
- * @var array
- */
- private $_callbacks;
- /**
- * Advance the canvas to the next page
- */
- function new_page()
- {
- $this->_canvas->new_page();
- }
- /**
- * Render frames recursively
- *
- * @param Frame $frame the frame to render
- */
- public function render(Frame $frame)
- {
- global $_dompdf_debug;
- $this->_check_callbacks("begin_frame", $frame);
- if ($_dompdf_debug) {
- echo $frame;
- flush();
- }
- $style = $frame->get_style();
- if (in_array($style->visibility, ["hidden", "collapse"])) {
- return;
- }
- $display = $style->display;
- // Starts the CSS transformation
- if ($style->transform && is_array($style->transform)) {
- $this->_canvas->save();
- list($x, $y) = $frame->get_padding_box();
- $origin = $style->transform_origin;
- foreach ($style->transform as $transform) {
- list($function, $values) = $transform;
- if ($function === "matrix") {
- $function = "transform";
- }
- $values = array_map("floatval", $values);
- $values[] = $x + (float)$style->length_in_pt($origin[0], (float)$style->length_in_pt($style->width));
- $values[] = $y + (float)$style->length_in_pt($origin[1], (float)$style->length_in_pt($style->height));
- call_user_func_array([$this->_canvas, $function], $values);
- }
- }
- switch ($display) {
- case "block":
- case "list-item":
- case "inline-block":
- case "table":
- case "inline-table":
- $this->_render_frame("block", $frame);
- break;
- case "inline":
- if ($frame->is_text_node()) {
- $this->_render_frame("text", $frame);
- } else {
- $this->_render_frame("inline", $frame);
- }
- break;
- case "table-cell":
- $this->_render_frame("table-cell", $frame);
- break;
- case "table-row-group":
- case "table-header-group":
- case "table-footer-group":
- $this->_render_frame("table-row-group", $frame);
- break;
- case "-dompdf-list-bullet":
- $this->_render_frame("list-bullet", $frame);
- break;
- case "-dompdf-image":
- $this->_render_frame("image", $frame);
- break;
- case "none":
- $node = $frame->get_node();
- if ($node->nodeName === "script") {
- if ($node->getAttribute("type") === "text/php" ||
- $node->getAttribute("language") === "php"
- ) {
- // Evaluate embedded php scripts
- $this->_render_frame("php", $frame);
- } elseif ($node->getAttribute("type") === "text/javascript" ||
- $node->getAttribute("language") === "javascript"
- ) {
- // Insert JavaScript
- $this->_render_frame("javascript", $frame);
- }
- }
- // Don't render children, so skip to next iter
- return;
- default:
- break;
- }
- // Starts the overflow: hidden box
- if ($style->overflow === "hidden") {
- list($x, $y, $w, $h) = $frame->get_padding_box();
- // get border radii
- $style = $frame->get_style();
- list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
- if ($tl + $tr + $br + $bl > 0) {
- $this->_canvas->clipping_roundrectangle($x, $y, (float)$w, (float)$h, $tl, $tr, $br, $bl);
- } else {
- $this->_canvas->clipping_rectangle($x, $y, (float)$w, (float)$h);
- }
- }
- $stack = [];
- foreach ($frame->get_children() as $child) {
- // < 0 : nagative z-index
- // = 0 : no z-index, no stacking context
- // = 1 : stacking context without z-index
- // > 1 : z-index
- $child_style = $child->get_style();
- $child_z_index = $child_style->z_index;
- $z_index = 0;
- if ($child_z_index !== "auto") {
- $z_index = intval($child_z_index) + 1;
- } elseif ($child_style->float !== "none" || $child->is_positionned()) {
- $z_index = 1;
- }
- $stack[$z_index][] = $child;
- }
- ksort($stack);
- foreach ($stack as $by_index) {
- foreach ($by_index as $child) {
- $this->render($child);
- }
- }
- // Ends the overflow: hidden box
- if ($style->overflow === "hidden") {
- $this->_canvas->clipping_end();
- }
- if ($style->transform && is_array($style->transform)) {
- $this->_canvas->restore();
- }
- // Check for end frame callback
- $this->_check_callbacks("end_frame", $frame);
- }
- /**
- * Check for callbacks that need to be performed when a given event
- * gets triggered on a frame
- *
- * @param string $event the type of event
- * @param Frame $frame the frame that event is triggered on
- */
- protected function _check_callbacks($event, $frame)
- {
- if (!isset($this->_callbacks)) {
- $this->_callbacks = $this->_dompdf->getCallbacks();
- }
- if (is_array($this->_callbacks) && isset($this->_callbacks[$event])) {
- $info = [0 => $this->_canvas, "canvas" => $this->_canvas,
- 1 => $frame, "frame" => $frame];
- $fs = $this->_callbacks[$event];
- foreach ($fs as $f) {
- if (is_callable($f)) {
- if (is_array($f)) {
- $f[0]->{$f[1]}($info);
- } else {
- $f($info);
- }
- }
- }
- }
- }
- /**
- * Render a single frame
- *
- * Creates Renderer objects on demand
- *
- * @param string $type type of renderer to use
- * @param Frame $frame the frame to render
- */
- protected function _render_frame($type, $frame)
- {
- if (!isset($this->_renderers[$type])) {
- switch ($type) {
- case "block":
- $this->_renderers[$type] = new Block($this->_dompdf);
- break;
- case "inline":
- $this->_renderers[$type] = new Renderer\Inline($this->_dompdf);
- break;
- case "text":
- $this->_renderers[$type] = new Text($this->_dompdf);
- break;
- case "image":
- $this->_renderers[$type] = new Image($this->_dompdf);
- break;
- case "table-cell":
- $this->_renderers[$type] = new TableCell($this->_dompdf);
- break;
- case "table-row-group":
- $this->_renderers[$type] = new TableRowGroup($this->_dompdf);
- break;
- case "list-bullet":
- $this->_renderers[$type] = new ListBullet($this->_dompdf);
- break;
- case "php":
- $this->_renderers[$type] = new PhpEvaluator($this->_canvas);
- break;
- case "javascript":
- $this->_renderers[$type] = new JavascriptEmbedder($this->_dompdf);
- break;
- }
- }
- $this->_renderers[$type]->render($frame);
- }
- }
|