Пример #1
1
 function render(Frame $frame)
 {
     if (!$this->_dompdf->get_option("enable_javascript")) {
         return;
     }
     $this->insert($frame->get_node()->nodeValue);
 }
Пример #2
0
 function render(Frame $frame)
 {
     if (!$this->_dompdf->getOptions()->getIsJavascriptEnabled()) {
         return;
     }
     $this->insert($frame->get_node()->nodeValue);
 }
Пример #3
0
 /**
  * Class constructor
  *
  * @param Frame $frame   the bullet frame to decorate
  * @param Dompdf $dompdf the document's dompdf object
  */
 function __construct(Frame $frame, Dompdf $dompdf)
 {
     $style = $frame->get_style();
     $url = $style->list_style_image;
     $frame->get_node()->setAttribute("src", $url);
     $this->_img = new Image($frame, $dompdf);
     parent::__construct($this->_img, $dompdf);
     list($width, $height) = Helpers::dompdf_getimagesize($this->_img->get_image_url());
     // Resample the bullet image to be consistent with 'auto' sized images
     // See also Image::get_min_max_width
     // Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary.
     $dpi = $this->_dompdf->get_option("dpi");
     $this->_width = (double) rtrim($width, "px") * 72 / $dpi;
     $this->_height = (double) rtrim($height, "px") * 72 / $dpi;
     //If an image is taller as the containing block/box, the box should be extended.
     //Neighbour elements are overwriting the overlapping image areas.
     //Todo: Where can the box size be extended?
     //Code below has no effect.
     //See block_frame_reflower _calculate_restricted_height
     //See generated_frame_reflower, Dompdf:render() "list-item", "-dompdf-list-bullet"S.
     //Leave for now
     //if ($style->min_height < $this->_height ) {
     //  $style->min_height = $this->_height;
     //}
     //$style->height = "auto";
 }
Пример #4
0
 function apply_page_style(Frame $frame, $page_number)
 {
     $style = $frame->get_style();
     $page_styles = $style->get_stylesheet()->get_page_styles();
     // http://www.w3.org/TR/CSS21/page.html#page-selectors
     if (count($page_styles) > 1) {
         $odd = $page_number % 2 == 1;
         $first = $page_number == 1;
         $style = clone $page_styles["base"];
         // FIXME RTL
         if ($odd && isset($page_styles[":right"])) {
             $style->merge($page_styles[":right"]);
         }
         if ($odd && isset($page_styles[":odd"])) {
             $style->merge($page_styles[":odd"]);
         }
         // FIXME RTL
         if (!$odd && isset($page_styles[":left"])) {
             $style->merge($page_styles[":left"]);
         }
         if (!$odd && isset($page_styles[":even"])) {
             $style->merge($page_styles[":even"]);
         }
         if ($first && isset($page_styles[":first"])) {
             $style->merge($page_styles[":first"]);
         }
         $frame->set_style($style);
     }
 }
 /**
  * @param Frame $frame
  */
 static function translate_attributes(Frame $frame)
 {
     $node = $frame->get_node();
     $tag = $node->nodeName;
     if (!isset(self::$__ATTRIBUTE_LOOKUP[$tag])) {
         return;
     }
     $valid_attrs = self::$__ATTRIBUTE_LOOKUP[$tag];
     $attrs = $node->attributes;
     $style = rtrim($node->getAttribute(self::$_style_attr), "; ");
     if ($style != "") {
         $style .= ";";
     }
     foreach ($attrs as $attr => $attr_node) {
         if (!isset($valid_attrs[$attr])) {
             continue;
         }
         $value = $attr_node->value;
         $target = $valid_attrs[$attr];
         // Look up $value in $target, if $target is an array:
         if (is_array($target)) {
             if (isset($target[$value])) {
                 $style .= " " . self::_resolve_target($node, $target[$value], $value);
             }
         } else {
             // otherwise use target directly
             $style .= " " . self::_resolve_target($node, $target, $value);
         }
     }
     if (!is_null($style)) {
         $style = ltrim($style);
         $node->setAttribute(self::$_style_attr, $style);
     }
 }
Пример #6
0
 function __construct(Frame $frame, Dompdf $dompdf)
 {
     if (!$frame->is_text_node()) {
         throw new Exception("Text_Decorator can only be applied to #text nodes.");
     }
     parent::__construct($frame, $dompdf);
     $this->_text_spacing = null;
 }
Пример #7
0
 /**
  * @return Frame
  */
 public function next()
 {
     $ret = $this->_cur;
     if (!$ret) {
         return null;
     }
     $this->_cur = $this->_cur->get_next_sibling();
     $this->_num++;
     return $ret;
 }
Пример #8
0
 /**
  * "Destructor": forcibly free all references held by this frame
  *
  * @param bool $recursive if true, call dispose on all children
  */
 public function dispose($recursive = false)
 {
     if ($recursive) {
         while ($child = $this->_first_child) {
             $child->dispose(true);
         }
     }
     // Remove this frame from the tree
     if ($this->_prev_sibling) {
         $this->_prev_sibling->_next_sibling = $this->_next_sibling;
     }
     if ($this->_next_sibling) {
         $this->_next_sibling->_prev_sibling = $this->_prev_sibling;
     }
     if ($this->_parent && $this->_parent->_first_child === $this) {
         $this->_parent->_first_child = $this->_next_sibling;
     }
     if ($this->_parent && $this->_parent->_last_child === $this) {
         $this->_parent->_last_child = $this->_prev_sibling;
     }
     if ($this->_parent) {
         $this->_parent->get_node()->removeChild($this->_node);
     }
     $this->_style->dispose();
     $this->_style = null;
     unset($this->_style);
     $this->_original_style->dispose();
     $this->_original_style = null;
     unset($this->_original_style);
 }
Пример #9
0
 function render(Frame $frame)
 {
     $style = $frame->get_style();
     $this->_set_opacity($frame->get_opacity($style->opacity));
     $this->_render_border($frame);
     $this->_render_outline($frame);
     if ($this->_dompdf->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutBlocks")) {
         $this->_debug_layout($frame->get_border_box(), "red");
         if ($this->_dompdf->get_option("debugLayoutPaddingBox")) {
             $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5));
         }
     }
     if ($this->_dompdf->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutLines") && $frame->get_decorator()) {
         foreach ($frame->get_decorator()->get_line_boxes() as $line) {
             $frame->_debug_layout(array($line->x, $line->y, $line->w, $line->h), "orange");
         }
     }
 }
Пример #10
0
 function render(Frame $frame)
 {
     $style = $frame->get_style();
     $node = $frame->get_node();
     list($x, $y, $w, $h) = $frame->get_border_box();
     $this->_set_opacity($frame->get_opacity($style->opacity));
     if ($node->nodeName === "body") {
         $h = $frame->get_containing_block("h") - $style->length_in_pt(array($style->margin_top, $style->border_top_width, $style->border_bottom_width, $style->margin_bottom), $style->width);
     }
     // Handle anchors & links
     if ($node->nodeName === "a" && ($href = $node->getAttribute("href"))) {
         $href = Helpers::build_url($this->_dompdf->getProtocol(), $this->_dompdf->getBaseHost(), $this->_dompdf->getBasePath(), $href);
         $this->_canvas->add_link($href, $x, $y, $w, $h);
     }
     // Draw our background, border and content
     list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
     if ($tl + $tr + $br + $bl > 0) {
         $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl);
     }
     if (($bg = $style->background_color) !== "transparent") {
         $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
     }
     if (($url = $style->background_image) && $url !== "none") {
         $this->_background_image($url, $x, $y, $w, $h, $style);
     }
     if ($tl + $tr + $br + $bl > 0) {
         $this->_canvas->clipping_end();
     }
     $border_box = array($x, $y, $w, $h);
     $this->_render_border($frame, $border_box);
     $this->_render_outline($frame, $border_box);
     if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutBlocks()) {
         $this->_debug_layout($frame->get_border_box(), "red");
         if ($this->_dompdf->getOptions()->getDebugLayoutPaddingBox()) {
             $this->_debug_layout($frame->get_padding_box(), "red", array(0.5, 0.5));
         }
     }
     if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutLines() && $frame->get_decorator()) {
         foreach ($frame->get_decorator()->get_line_boxes() as $line) {
             $frame->_debug_layout(array($line->x, $line->y, $line->w, $line->h), "orange");
         }
     }
 }
Пример #11
0
 /**
  * Determine current frame width based on contents
  *
  * @return float
  */
 public function calculate_auto_width()
 {
     return $this->_frame->get_margin_width();
 }
Пример #12
0
 function render(Frame $frame)
 {
     $this->evaluate($frame->get_node()->nodeValue);
 }
Пример #13
0
 /**
  * @param Frame $child
  * @param float $cb_x
  * @param float $cb_w
  */
 function process_float(Frame $child, $cb_x, $cb_w)
 {
     $child_style = $child->get_style();
     $root = $this->_frame->get_root();
     // Handle "float"
     if ($child_style->float !== "none") {
         $root->add_floating_frame($child);
         // Remove next frame's beginning whitespace
         $next = $child->get_next_sibling();
         if ($next && $next instanceof TextFrameDecorator) {
             $next->set_text(ltrim($next->get_text()));
         }
         $line_box = $this->_frame->get_current_line_box();
         list($old_x, $old_y) = $child->get_position();
         $float_x = $cb_x;
         $float_y = $old_y;
         $float_w = $child->get_margin_width();
         if ($child_style->clear === "none") {
             switch ($child_style->float) {
                 case "left":
                     $float_x += $line_box->left;
                     break;
                 case "right":
                     $float_x += $cb_w - $line_box->right - $float_w;
                     break;
             }
         } else {
             if ($child_style->float === "right") {
                 $float_x += $cb_w - $float_w;
             }
         }
         if ($cb_w < $float_x + $float_w - $old_x) {
             // TODO handle when floating elements don't fit
         }
         $line_box->get_float_offsets();
         if ($child->_float_next_line) {
             $float_y += $line_box->h;
         }
         $child->set_position($float_x, $float_y);
         $child->move($float_x - $old_x, $float_y - $old_y, true);
     }
 }
Пример #14
0
 function render(Frame $frame)
 {
     // Render background & borders
     $style = $frame->get_style();
     $cb = $frame->get_containing_block();
     list($x, $y, $w, $h) = $frame->get_border_box();
     $this->_set_opacity($frame->get_opacity($style->opacity));
     list($tl, $tr, $br, $bl) = $style->get_computed_border_radius($w, $h);
     $has_border_radius = $tl + $tr + $br + $bl > 0;
     if ($has_border_radius) {
         $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl);
     }
     if (($bg = $style->background_color) !== "transparent") {
         $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
     }
     if (($url = $style->background_image) && $url !== "none") {
         $this->_background_image($url, $x, $y, $w, $h, $style);
     }
     if ($has_border_radius) {
         $this->_canvas->clipping_end();
     }
     $this->_render_border($frame);
     $this->_render_outline($frame);
     list($x, $y) = $frame->get_padding_box();
     $x += $style->length_in_pt($style->padding_left, $cb["w"]);
     $y += $style->length_in_pt($style->padding_top, $cb["h"]);
     $w = $style->length_in_pt($style->width, $cb["w"]);
     $h = $style->length_in_pt($style->height, $cb["h"]);
     if ($has_border_radius) {
         list($wt, $wr, $wb, $wl) = array($style->border_top_width, $style->border_right_width, $style->border_bottom_width, $style->border_left_width);
         // we have to get the "inner" radius
         if ($tl > 0) {
             $tl -= ($wt + $wl) / 2;
         }
         if ($tr > 0) {
             $tr -= ($wt + $wr) / 2;
         }
         if ($br > 0) {
             $br -= ($wb + $wr) / 2;
         }
         if ($bl > 0) {
             $bl -= ($wb + $wl) / 2;
         }
         $this->_canvas->clipping_roundrectangle($x, $y, $w, $h, $tl, $tr, $br, $bl);
     }
     $src = $frame->get_image_url();
     $alt = null;
     if (Cache::is_broken($src) && ($alt = $frame->get_node()->getAttribute("alt"))) {
         $font = $style->font_family;
         $size = $style->font_size;
         $spacing = $style->word_spacing;
         $this->_canvas->text($x, $y, $alt, $font, $size, $style->color, $spacing);
     } else {
         $this->_canvas->image($src, $x, $y, $w, $h, $style->image_resolution);
     }
     if ($has_border_radius) {
         $this->_canvas->clipping_end();
     }
     if ($msg = $frame->get_image_msg()) {
         $parts = preg_split("/\\s*\n\\s*/", $msg);
         $height = 10;
         $_y = $alt ? $y + $h - count($parts) * $height : $y;
         foreach ($parts as $i => $_part) {
             $this->_canvas->text($x, $_y + $i * $height, $_part, "times", $height * 0.8, array(0.5, 0.5, 0.5));
         }
     }
     if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutBlocks()) {
         $this->_debug_layout($frame->get_border_box(), "blue");
         if ($this->_dompdf->getOptions()->getDebugLayoutPaddingBox()) {
             $this->_debug_layout($frame->get_padding_box(), "blue", array(0.5, 0.5));
         }
     }
 }
Пример #15
0
 function render(Frame $frame)
 {
     $style = $frame->get_style();
     $font_size = $style->get_font_size();
     $line_height = $style->length_in_pt($style->line_height, $frame->get_containing_block("w"));
     $this->_set_opacity($frame->get_opacity($style->opacity));
     $li = $frame->get_parent();
     // Don't render bullets twice if if was split
     if ($li->_splitted) {
         return;
     }
     // Handle list-style-image
     // If list style image is requested but missing, fall back to predefined types
     if ($style->list_style_image !== "none" && !Cache::is_broken($img = $frame->get_image_url())) {
         list($x, $y) = $frame->get_position();
         //For expected size and aspect, instead of box size, use image natural size scaled to DPI.
         // Resample the bullet image to be consistent with 'auto' sized images
         // See also Image::get_min_max_width
         // Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary.
         //$w = $frame->get_width();
         //$h = $frame->get_height();
         list($width, $height) = Helpers::dompdf_getimagesize($img, $this->_dompdf->getHttpContext());
         $dpi = $this->_dompdf->getOptions()->getDpi();
         $w = (double) rtrim($width, "px") * 72 / $dpi;
         $h = (double) rtrim($height, "px") * 72 / $dpi;
         $x -= $w;
         $y -= ($line_height - $font_size) / 2;
         //Reverse hinting of list_bullet_positioner
         $this->_canvas->image($img, $x, $y, $w, $h);
     } else {
         $bullet_style = $style->list_style_type;
         $fill = false;
         switch ($bullet_style) {
             default:
             case "disc":
                 $fill = true;
             case "circle":
                 list($x, $y) = $frame->get_position();
                 $r = $font_size * ListBulletFrameDecorator::BULLET_SIZE / 2;
                 $x -= $font_size * (ListBulletFrameDecorator::BULLET_SIZE / 2);
                 $y += $font_size * (1 - ListBulletFrameDecorator::BULLET_DESCENT) / 2;
                 $o = $font_size * ListBulletFrameDecorator::BULLET_THICKNESS;
                 $this->_canvas->circle($x, $y, $r, $style->color, $o, null, $fill);
                 break;
             case "square":
                 list($x, $y) = $frame->get_position();
                 $w = $font_size * ListBulletFrameDecorator::BULLET_SIZE;
                 $x -= $w;
                 $y += $font_size * (1 - ListBulletFrameDecorator::BULLET_DESCENT - ListBulletFrameDecorator::BULLET_SIZE) / 2;
                 $this->_canvas->filled_rectangle($x, $y, $w, $w, $style->color);
                 break;
             case "decimal-leading-zero":
             case "decimal":
             case "lower-alpha":
             case "lower-latin":
             case "lower-roman":
             case "lower-greek":
             case "upper-alpha":
             case "upper-latin":
             case "upper-roman":
             case "1":
                 // HTML 4.0 compatibility
             // HTML 4.0 compatibility
             case "a":
             case "i":
             case "A":
             case "I":
                 $pad = null;
                 if ($bullet_style === "decimal-leading-zero") {
                     $pad = strlen($li->get_parent()->get_node()->getAttribute("dompdf-children-count"));
                 }
                 $node = $frame->get_node();
                 if (!$node->hasAttribute("dompdf-counter")) {
                     return;
                 }
                 $index = $node->getAttribute("dompdf-counter");
                 $text = $this->make_counter($index, $bullet_style, $pad);
                 if (trim($text) == "") {
                     return;
                 }
                 $spacing = 0;
                 $font_family = $style->font_family;
                 $line = $li->get_containing_line();
                 list($x, $y) = array($frame->get_position("x"), $line->y);
                 $x -= $this->_dompdf->getFontMetrics()->getTextWidth($text, $font_family, $font_size, $spacing);
                 // Take line-height into account
                 $line_height = $style->line_height;
                 $y += ($line_height - $font_size) / 4;
                 // FIXME I thought it should be 2, but 4 gives better results
                 $this->_canvas->text($x, $y, $text, $font_family, $font_size, $style->color, $spacing);
             case "none":
                 break;
         }
     }
 }
Пример #16
0
 public function get_lowest_float_offset(Frame $child)
 {
     $style = $child->get_style();
     $side = $style->clear;
     $float = $style->float;
     $y = 0;
     foreach ($this->_floating_frames as $key => $frame) {
         if ($side === "both" || $frame->get_style()->float === $side) {
             $y = max($y, $frame->get_position("y") + $frame->get_margin_height());
             if ($float !== "none") {
                 $this->remove_floating_frame($key);
             }
         }
     }
     return $y;
 }
Пример #17
0
 /**
  * Sets the generated content of a generated frame
  */
 protected function _set_content()
 {
     $frame = $this->_frame;
     $style = $frame->get_style();
     // if the element was pushed to a new page use the saved counter value, otherwise use the CSS reset value
     if ($style->counter_reset && ($reset = $style->counter_reset) !== "none") {
         $vars = preg_split('/\\s+/', trim($reset), 2);
         $frame->reset_counter($vars[0], isset($frame->_counters['__' . $vars[0]]) ? $frame->_counters['__' . $vars[0]] : (isset($vars[1]) ? $vars[1] : 0));
     }
     if ($style->counter_increment && ($increment = $style->counter_increment) !== "none") {
         $frame->increment_counters($increment);
     }
     if ($style->content && !$frame->get_first_child() && $frame->get_node()->nodeName === "dompdf_generated") {
         $content = $this->_parse_content();
         // add generated content to the font subset
         // FIXME: This is currently too late because the font subset has already been generated.
         //        See notes in issue #750.
         if ($frame->get_dompdf()->get_option("enable_font_subsetting") && $frame->get_dompdf()->get_canvas() instanceof CPDF) {
             $frame->get_dompdf()->get_canvas()->register_string_subset($style->font_family, $content);
         }
         $node = $frame->get_node()->ownerDocument->createTextNode($content);
         $new_style = $style->get_stylesheet()->create_style();
         $new_style->inherit($style);
         $new_frame = new Frame($node);
         $new_frame->set_style($new_style);
         Factory::decorate_frame($new_frame, $frame->get_dompdf(), $frame->get_root());
         $frame->append_child($new_frame);
     }
 }
Пример #18
0
 /**
  * Update a row group after rows have been removed
  *
  * @param Frame $group    The group to update
  * @param Frame $last_row The last row in the row group
  */
 public function update_row_group(Frame $group, Frame $last_row)
 {
     $g_key = $group->get_id();
     $r_key = $last_row->get_id();
     $r_rows = $this->_frames[$r_key]["rows"];
     $this->_frames[$g_key]["rows"] = range($this->_frames[$g_key]["rows"][0], end($r_rows));
 }
Пример #19
0
 /**
  * Recursively adds {@link Frame} objects to the tree
  *
  * Recursively build a tree of Frame objects based on a dom tree.
  * No layout information is calculated at this time, although the
  * tree may be adjusted (i.e. nodes and frames for generated content
  * and images may be created).
  *
  * @param DOMNode $node the current DOMNode being considered
  *
  * @return Frame
  */
 protected function _build_tree_r(DOMNode $node)
 {
     $frame = new Frame($node);
     $id = $frame->get_id();
     $this->_registry[$id] = $frame;
     if (!$node->hasChildNodes()) {
         return $frame;
     }
     // Store the children in an array so that the tree can be modified
     $children = array();
     $length = $node->childNodes->length;
     for ($i = 0; $i < $length; $i++) {
         $children[] = $node->childNodes->item($i);
     }
     $index = 0;
     // INFO: We don't advance $index if a node is removed to avoid skipping nodes
     while ($index < count($children)) {
         $child = $children[$index];
         $nodeName = strtolower($child->nodeName);
         // Skip non-displaying nodes
         if (in_array($nodeName, self::$HIDDEN_TAGS)) {
             if ($nodeName !== "head" && $nodeName !== "style") {
                 $this->_remove_node($node, $children, $index);
             } else {
                 $index++;
             }
             continue;
         }
         // Skip empty text nodes
         if ($nodeName === "#text" && $child->nodeValue === "") {
             $this->_remove_node($node, $children, $index);
             continue;
         }
         // Skip empty image nodes
         if ($nodeName === "img" && $child->getAttribute("src") === "") {
             $this->_remove_node($node, $children, $index);
             continue;
         }
         if (is_object($child)) {
             $frame->append_child($this->_build_tree_r($child), false);
         }
         $index++;
     }
     return $frame;
 }
Пример #20
0
 /**
  * Decorate a Frame
  *
  * @param Frame $frame   The frame to decorate
  * @param Dompdf $dompdf The dompdf instance
  * @param Frame $root    The frame to decorate
  *
  * @throws Exception
  * @return AbstractFrameDecorator
  * FIXME: this is admittedly a little smelly...
  */
 static function decorate_frame(Frame $frame, Dompdf $dompdf, Frame $root = null)
 {
     if (is_null($dompdf)) {
         throw new Exception("The DOMPDF argument is required");
     }
     $style = $frame->get_style();
     // Floating (and more generally out-of-flow) elements are blocks
     // http://coding.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/
     if (!$frame->is_in_flow() && in_array($style->display, Style::$INLINE_TYPES)) {
         $style->display = "block";
     }
     $display = $style->display;
     switch ($display) {
         case "block":
             $positioner = "Block";
             $decorator = "Block";
             $reflower = "Block";
             break;
         case "inline-block":
             $positioner = "Inline";
             $decorator = "Block";
             $reflower = "Block";
             break;
         case "inline":
             $positioner = "Inline";
             if ($frame->is_text_node()) {
                 $decorator = "Text";
                 $reflower = "Text";
             } else {
                 $enable_css_float = $dompdf->get_option("enable_css_float");
                 if ($enable_css_float && $style->float !== "none") {
                     $decorator = "Block";
                     $reflower = "Block";
                 } else {
                     $decorator = "Inline";
                     $reflower = "Inline";
                 }
             }
             break;
         case "table":
             $positioner = "Block";
             $decorator = "Table";
             $reflower = "Table";
             break;
         case "inline-table":
             $positioner = "Inline";
             $decorator = "Table";
             $reflower = "Table";
             break;
         case "table-row-group":
         case "table-header-group":
         case "table-footer-group":
             $positioner = "Null";
             $decorator = "TableRowGroup";
             $reflower = "TableRowGroup";
             break;
         case "table-row":
             $positioner = "Null";
             $decorator = "TableRow";
             $reflower = "TableRow";
             break;
         case "table-cell":
             $positioner = "TableCell";
             $decorator = "TableCell";
             $reflower = "TableCell";
             break;
         case "list-item":
             $positioner = "Block";
             $decorator = "Block";
             $reflower = "Block";
             break;
         case "-dompdf-list-bullet":
             if ($style->list_style_position === "inside") {
                 $positioner = "Inline";
             } else {
                 $positioner = "ListBullet";
             }
             if ($style->list_style_image !== "none") {
                 $decorator = "ListBulletImage";
             } else {
                 $decorator = "ListBullet";
             }
             $reflower = "ListBullet";
             break;
         case "-dompdf-image":
             $positioner = "Inline";
             $decorator = "Image";
             $reflower = "Image";
             break;
         case "-dompdf-br":
             $positioner = "Inline";
             $decorator = "Inline";
             $reflower = "Inline";
             break;
         default:
             // FIXME: should throw some sort of warning or something?
         // FIXME: should throw some sort of warning or something?
         case "none":
             if ($style->_dompdf_keep !== "yes") {
                 // Remove the node and the frame
                 $frame->get_parent()->remove_child($frame);
                 return;
             }
             $positioner = "Null";
             $decorator = "Null";
             $reflower = "Null";
             break;
     }
     // Handle CSS position
     $position = $style->position;
     if ($position === "absolute") {
         $positioner = "Absolute";
     } else {
         if ($position === "fixed") {
             $positioner = "Fixed";
         }
     }
     $node = $frame->get_node();
     // Handle nodeName
     if ($node->nodeName === "img") {
         $style->display = "-dompdf-image";
         $decorator = "Image";
         $reflower = "Image";
     }
     $positioner = "Dompdf\\Positioner\\{$positioner}";
     $decorator = "Dompdf\\FrameDecorator\\{$decorator}";
     $reflower = "Dompdf\\FrameReflower\\{$reflower}";
     /** @var AbstractFrameDecorator $deco */
     $deco = new $decorator($frame, $dompdf);
     $deco->set_positioner(new $positioner($deco));
     $deco->set_reflower(new $reflower($deco, $dompdf->getFontMetrics()));
     if ($root) {
         $deco->set_root($root);
     }
     if ($display === "list-item") {
         // Insert a list-bullet frame
         $xml = $dompdf->get_dom();
         $bullet_node = $xml->createElement("bullet");
         // arbitrary choice
         $b_f = new Frame($bullet_node);
         $node = $frame->get_node();
         $parent_node = $node->parentNode;
         if ($parent_node) {
             if (!$parent_node->hasAttribute("dompdf-children-count")) {
                 $xpath = new DOMXPath($xml);
                 $count = $xpath->query("li", $parent_node)->length;
                 $parent_node->setAttribute("dompdf-children-count", $count);
             }
             if (is_numeric($node->getAttribute("value"))) {
                 $index = intval($node->getAttribute("value"));
             } else {
                 if (!$parent_node->hasAttribute("dompdf-counter")) {
                     $index = $parent_node->hasAttribute("start") ? $parent_node->getAttribute("start") : 1;
                 } else {
                     $index = $parent_node->getAttribute("dompdf-counter") + 1;
                 }
             }
             $parent_node->setAttribute("dompdf-counter", $index);
             $bullet_node->setAttribute("dompdf-counter", $index);
         }
         $new_style = $dompdf->get_css()->create_style();
         $new_style->display = "-dompdf-list-bullet";
         $new_style->inherit($style);
         $b_f->set_style($new_style);
         $deco->prepend_child(Factory::decorate_frame($b_f, $dompdf, $root));
     }
     return $deco;
 }
Пример #21
0
 /**
  * Restructure tree so that the table has the correct structure.
  * Invalid children (i.e. all non-table-rows) are moved below the
  * table.
  */
 public function normalise()
 {
     // Store frames generated by invalid tags and move them outside the table
     $erroneous_frames = array();
     $anon_row = false;
     $iter = $this->get_first_child();
     while ($iter) {
         $child = $iter;
         $iter = $iter->get_next_sibling();
         $display = $child->get_style()->display;
         if ($anon_row) {
             if ($display === "table-row") {
                 // Add the previous anonymous row
                 $this->insert_child_before($table_row, $child);
                 $table_row->normalise();
                 $child->normalise();
                 $anon_row = false;
                 continue;
             }
             // add the child to the anonymous row
             $table_row->append_child($child);
             continue;
         } else {
             if ($display === "table-row") {
                 $child->normalise();
                 continue;
             }
             if ($display === "table-cell") {
                 // Create an anonymous table row
                 $tr = $this->get_node()->ownerDocument->createElement("tr");
                 $frame = new Frame($tr);
                 $css = $this->get_style()->get_stylesheet();
                 $style = $css->create_style();
                 $style->inherit($this->get_style());
                 // Lookup styles for tr tags.  If the user wants styles to work
                 // better, they should make the tr explicit... I'm not going to
                 // try to guess what they intended.
                 if ($tr_style = $css->lookup("tr")) {
                     $style->merge($tr_style);
                 }
                 // Okay, I have absolutely no idea why I need this clone here, but
                 // if it's omitted, php (as of 2004-07-28) segfaults.
                 $frame->set_style(clone $style);
                 $table_row = Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
                 // Add the cell to the row
                 $table_row->append_child($child);
                 $anon_row = true;
                 continue;
             }
             if (!in_array($display, self::$VALID_CHILDREN)) {
                 $erroneous_frames[] = $child;
                 continue;
             }
             // Normalise other table parts (i.e. row groups)
             foreach ($child->get_children() as $grandchild) {
                 if ($grandchild->get_style()->display === "table-row") {
                     $grandchild->normalise();
                 }
             }
             // Add headers and footers
             if ($display === "table-header-group") {
                 $this->_headers[] = $child;
             } elseif ($display === "table-footer-group") {
                 $this->_footers[] = $child;
             }
         }
     }
     if ($anon_row && $table_row instanceof DOMNode) {
         // Add the row to the table
         $this->_frame->append_child($table_row);
         $table_row->normalise();
         $this->_cellmap->add_row();
     }
     foreach ($erroneous_frames as $frame) {
         $this->move_after($frame);
     }
 }
Пример #22
0
 /**
  * @param Frame $frame
  */
 function add_frame_to_line(Frame $frame)
 {
     if (!$frame->is_in_flow()) {
         return;
     }
     $style = $frame->get_style();
     $frame->set_containing_line($this->_line_boxes[$this->_cl]);
     /*
             // Adds a new line after a block, only if certain conditions are met
             if ((($frame instanceof Inline && $frame->get_node()->nodeName !== "br") ||
                   $frame instanceof Text && trim($frame->get_text())) &&
                 ($frame->get_prev_sibling() && $frame->get_prev_sibling()->get_style()->display === "block" &&
                  $this->_line_boxes[$this->_cl]->w > 0 )) {
     
                    $this->maximize_line_height( $style->length_in_pt($style->line_height), $frame );
                    $this->add_line();
     
                    // Add each child of the inline frame to the line individually
                    foreach ($frame->get_children() as $child)
                      $this->add_frame_to_line( $child );
             }
             else*/
     // Handle inline frames (which are effectively wrappers)
     if ($frame instanceof Inline) {
         // Handle line breaks
         if ($frame->get_node()->nodeName === "br") {
             $this->maximize_line_height($style->length_in_pt($style->line_height), $frame);
             $this->add_line(true);
         }
         return;
     }
     // Trim leading text if this is an empty line.  Kinda a hack to put it here,
     // but what can you do...
     if ($this->get_current_line_box()->w == 0 && $frame->is_text_node() && !$frame->is_pre()) {
         $frame->set_text(ltrim($frame->get_text()));
         $frame->recalculate_width();
     }
     $w = $frame->get_margin_width();
     if ($w == 0) {
         return;
     }
     // Debugging code:
     /*
     Helpers::pre_r("\n<h3>Adding frame to line:</h3>");
     
     //    Helpers::pre_r("Me: " . $this->get_node()->nodeName . " (" . spl_object_hash($this->get_node()) . ")");
     //    Helpers::pre_r("Node: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")");
     if ( $frame->is_text_node() )
       Helpers::pre_r('"'.$frame->get_node()->nodeValue.'"');
     
     Helpers::pre_r("Line width: " . $this->_line_boxes[$this->_cl]->w);
     Helpers::pre_r("Frame: " . get_class($frame));
     Helpers::pre_r("Frame width: "  . $w);
     Helpers::pre_r("Frame height: " . $frame->get_margin_height());
     Helpers::pre_r("Containing block width: " . $this->get_containing_block("w"));
     */
     // End debugging
     $line = $this->_line_boxes[$this->_cl];
     if ($line->left + $line->w + $line->right + $w > $this->get_containing_block("w")) {
         $this->add_line();
     }
     $frame->position();
     $current_line = $this->_line_boxes[$this->_cl];
     $current_line->add_frame($frame);
     if ($frame->is_text_node()) {
         $current_line->wc += count(preg_split("/\\s+/", trim($frame->get_text())));
     }
     $this->increase_line_width($w);
     $this->maximize_line_height($frame->get_margin_height(), $frame);
 }
Пример #23
0
 /**
  * Recursively adds {@link Frame} objects to the tree
  *
  * Recursively build a tree of Frame objects based on a dom tree.
  * No layout information is calculated at this time, although the
  * tree may be adjusted (i.e. nodes and frames for generated content
  * and images may be created).
  *
  * @param DOMNode $node the current DOMNode being considered
  *
  * @return Frame
  */
 protected function _build_tree_r(DOMNode $node)
 {
     $frame = new Frame($node);
     $id = $frame->get_id();
     $this->_registry[$id] = $frame;
     if (!$node->hasChildNodes()) {
         return $frame;
     }
     for ($i = 0; $i < $node->childNodes->length; $i++) {
         $child = $node->childNodes->item($i);
         if (in_array($child->nodeName, self::$HIDDEN_TAGS)) {
             if ($child->nodeName !== "head" && $child->nodeName !== "HEAD" && ($child->nodeName !== "style" && $child->nodeName !== "STYLE")) {
                 $child->parentNode->removeChild($child);
             }
         } elseif (($child->nodeName === "#text" || $child->nodeName === "#TEXT") && $child->nodeValue == "") {
             $child->parentNode->removeChild($child);
         } elseif (($child->nodeName === "img" || $child->nodeName === "IMG") && $child->getAttribute("src") == "") {
             $child->parentNode->removeChild($child);
         } elseif (is_object($child)) {
             $frame->append_child($this->_build_tree_r($child), false);
         }
     }
     return $frame;
 }
Пример #24
0
 function render(Frame $frame)
 {
     $style = $frame->get_style();
     if (trim($frame->get_node()->nodeValue) === "" && $style->empty_cells === "hide") {
         return;
     }
     $this->_set_opacity($frame->get_opacity($style->opacity));
     list($x, $y, $w, $h) = $frame->get_border_box();
     // Draw our background, border and content
     if (($bg = $style->background_color) !== "transparent") {
         $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
     }
     if (($url = $style->background_image) && $url !== "none") {
         $this->_background_image($url, $x, $y, $w, $h, $style);
     }
     $table = Table::find_parent_table($frame);
     if ($table->get_style()->border_collapse !== "collapse") {
         $this->_render_border($frame);
         $this->_render_outline($frame);
         return;
     }
     // The collapsed case is slightly complicated...
     // @todo Add support for outlines here
     $cellmap = $table->get_cellmap();
     $cells = $cellmap->get_spanned_cells($frame);
     $num_rows = $cellmap->get_num_rows();
     $num_cols = $cellmap->get_num_cols();
     // Determine the top row spanned by this cell
     $i = $cells["rows"][0];
     $top_row = $cellmap->get_row($i);
     // Determine if this cell borders on the bottom of the table.  If so,
     // then we draw its bottom border.  Otherwise the next row down will
     // draw its top border instead.
     if (in_array($num_rows - 1, $cells["rows"])) {
         $draw_bottom = true;
         $bottom_row = $cellmap->get_row($num_rows - 1);
     } else {
         $draw_bottom = false;
     }
     // Draw the horizontal borders
     foreach ($cells["columns"] as $j) {
         $bp = $cellmap->get_border_properties($i, $j);
         $y = $top_row["y"] - $bp["top"]["width"] / 2;
         $col = $cellmap->get_column($j);
         $x = $col["x"] - $bp["left"]["width"] / 2;
         $w = $col["used-width"] + ($bp["left"]["width"] + $bp["right"]["width"]) / 2;
         if ($bp["top"]["style"] !== "none" && $bp["top"]["width"] > 0) {
             $widths = array($bp["top"]["width"], $bp["right"]["width"], $bp["bottom"]["width"], $bp["left"]["width"]);
             $method = "_border_" . $bp["top"]["style"];
             $this->{$method}($x, $y, $w, $bp["top"]["color"], $widths, "top", "square");
         }
         if ($draw_bottom) {
             $bp = $cellmap->get_border_properties($num_rows - 1, $j);
             if ($bp["bottom"]["style"] === "none" || $bp["bottom"]["width"] <= 0) {
                 continue;
             }
             $y = $bottom_row["y"] + $bottom_row["height"] + $bp["bottom"]["width"] / 2;
             $widths = array($bp["top"]["width"], $bp["right"]["width"], $bp["bottom"]["width"], $bp["left"]["width"]);
             $method = "_border_" . $bp["bottom"]["style"];
             $this->{$method}($x, $y, $w, $bp["bottom"]["color"], $widths, "bottom", "square");
         }
     }
     $j = $cells["columns"][0];
     $left_col = $cellmap->get_column($j);
     if (in_array($num_cols - 1, $cells["columns"])) {
         $draw_right = true;
         $right_col = $cellmap->get_column($num_cols - 1);
     } else {
         $draw_right = false;
     }
     // Draw the vertical borders
     foreach ($cells["rows"] as $i) {
         $bp = $cellmap->get_border_properties($i, $j);
         $x = $left_col["x"] - $bp["left"]["width"] / 2;
         $row = $cellmap->get_row($i);
         $y = $row["y"] - $bp["top"]["width"] / 2;
         $h = $row["height"] + ($bp["top"]["width"] + $bp["bottom"]["width"]) / 2;
         if ($bp["left"]["style"] !== "none" && $bp["left"]["width"] > 0) {
             $widths = array($bp["top"]["width"], $bp["right"]["width"], $bp["bottom"]["width"], $bp["left"]["width"]);
             $method = "_border_" . $bp["left"]["style"];
             $this->{$method}($x, $y, $h, $bp["left"]["color"], $widths, "left", "square");
         }
         if ($draw_right) {
             $bp = $cellmap->get_border_properties($i, $num_cols - 1);
             if ($bp["right"]["style"] === "none" || $bp["right"]["width"] <= 0) {
                 continue;
             }
             $x = $right_col["x"] + $right_col["used-width"] + $bp["right"]["width"] / 2;
             $widths = array($bp["top"]["width"], $bp["right"]["width"], $bp["bottom"]["width"], $bp["left"]["width"]);
             $method = "_border_" . $bp["right"]["style"];
             $this->{$method}($x, $y, $h, $bp["right"]["color"], $widths, "right", "square");
         }
     }
 }
Пример #25
0
 function render(Frame $frame)
 {
     $style = $frame->get_style();
     if (!$frame->get_first_child()) {
         return;
     }
     // No children, no service
     // Draw the left border if applicable
     $bp = $style->get_border_properties();
     $widths = array($style->length_in_pt($bp["top"]["width"]), $style->length_in_pt($bp["right"]["width"]), $style->length_in_pt($bp["bottom"]["width"]), $style->length_in_pt($bp["left"]["width"]));
     // Draw the background & border behind each child.  To do this we need
     // to figure out just how much space each child takes:
     list($x, $y) = $frame->get_first_child()->get_position();
     $w = null;
     $h = 0;
     //     $x += $widths[3];
     //     $y += $widths[0];
     $this->_set_opacity($frame->get_opacity($style->opacity));
     $first_row = true;
     foreach ($frame->get_children() as $child) {
         list($child_x, $child_y, $child_w, $child_h) = $child->get_padding_box();
         if (!is_null($w) && $child_x < $x + $w) {
             //This branch seems to be supposed to being called on the first part
             //of an inline html element, and the part after the if clause for the
             //parts after a line break.
             //But because $w initially mostly is 0, and gets updated only on the next
             //round, this seem to be never executed and the common close always.
             // The next child is on another line.  Draw the background &
             // borders on this line.
             // Background:
             if (($bg = $style->background_color) !== "transparent") {
                 $this->_canvas->filled_rectangle($x, $y, $w, $h, $bg);
             }
             if (($url = $style->background_image) && $url !== "none") {
                 $this->_background_image($url, $x, $y, $w, $h, $style);
             }
             // If this is the first row, draw the left border
             if ($first_row) {
                 if ($bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $bp["left"]["width"] > 0) {
                     $method = "_border_" . $bp["left"]["style"];
                     $this->{$method}($x, $y, $h + $widths[0] + $widths[2], $bp["left"]["color"], $widths, "left");
                 }
                 $first_row = false;
             }
             // Draw the top & bottom borders
             if ($bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $bp["top"]["width"] > 0) {
                 $method = "_border_" . $bp["top"]["style"];
                 $this->{$method}($x, $y, $w + $widths[1] + $widths[3], $bp["top"]["color"], $widths, "top");
             }
             if ($bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $bp["bottom"]["width"] > 0) {
                 $method = "_border_" . $bp["bottom"]["style"];
                 $this->{$method}($x, $y + $h + $widths[0] + $widths[2], $w + $widths[1] + $widths[3], $bp["bottom"]["color"], $widths, "bottom");
             }
             // Handle anchors & links
             $link_node = null;
             if ($frame->get_node()->nodeName === "a") {
                 $link_node = $frame->get_node();
             } else {
                 if ($frame->get_parent()->get_node()->nodeName === "a") {
                     $link_node = $frame->get_parent()->get_node();
                 }
             }
             if ($link_node && ($href = $link_node->getAttribute("href"))) {
                 $href = Helpers::build_url($this->_dompdf->getProtocol(), $this->_dompdf->getBaseHost(), $this->_dompdf->getBasePath(), $href);
                 $this->_canvas->add_link($href, $x, $y, $w, $h);
             }
             $x = $child_x;
             $y = $child_y;
             $w = $child_w;
             $h = $child_h;
             continue;
         }
         if (is_null($w)) {
             $w = $child_w;
         } else {
             $w += $child_w;
         }
         $h = max($h, $child_h);
         if ($this->_dompdf->get_option("debugLayout") && $this->_dompdf->get_option("debugLayoutInline")) {
             $this->_debug_layout($child->get_border_box(), "blue");
             if ($this->_dompdf->get_option("debugLayoutPaddingBox")) {
                 $this->_debug_layout($child->get_padding_box(), "blue", array(0.5, 0.5));
             }
         }
     }
     // Handle the last child
     if (($bg = $style->background_color) !== "transparent") {
         $this->_canvas->filled_rectangle($x + $widths[3], $y + $widths[0], $w, $h, $bg);
     }
     //On continuation lines (after line break) of inline elements, the style got copied.
     //But a non repeatable background image should not be repeated on the next line.
     //But removing the background image above has never an effect, and removing it below
     //removes it always, even on the initial line.
     //Need to handle it elsewhere, e.g. on certain ...clone()... usages.
     // Repeat not given: default is Style::__construct
     // ... && (!($repeat = $style->background_repeat) || $repeat === "repeat" ...
     //different position? $this->_background_image($url, $x, $y, $w, $h, $style);
     if (($url = $style->background_image) && $url !== "none") {
         $this->_background_image($url, $x + $widths[3], $y + $widths[0], $w, $h, $style);
     }
     // Add the border widths
     $w += $widths[1] + $widths[3];
     $h += $widths[0] + $widths[2];
     // make sure the border and background start inside the left margin
     $left_margin = $style->length_in_pt($style->margin_left);
     $x += $left_margin;
     // If this is the first row, draw the left border too
     if ($first_row && $bp["left"]["style"] !== "none" && $bp["left"]["color"] !== "transparent" && $widths[3] > 0) {
         $method = "_border_" . $bp["left"]["style"];
         $this->{$method}($x, $y, $h, $bp["left"]["color"], $widths, "left");
     }
     // Draw the top & bottom borders
     if ($bp["top"]["style"] !== "none" && $bp["top"]["color"] !== "transparent" && $widths[0] > 0) {
         $method = "_border_" . $bp["top"]["style"];
         $this->{$method}($x, $y, $w, $bp["top"]["color"], $widths, "top");
     }
     if ($bp["bottom"]["style"] !== "none" && $bp["bottom"]["color"] !== "transparent" && $widths[2] > 0) {
         $method = "_border_" . $bp["bottom"]["style"];
         $this->{$method}($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom");
     }
     //    Helpers::var_dump(get_class($frame->get_next_sibling()));
     //    $last_row = get_class($frame->get_next_sibling()) !== 'Inline';
     // Draw the right border if this is the last row
     if ($bp["right"]["style"] !== "none" && $bp["right"]["color"] !== "transparent" && $widths[1] > 0) {
         $method = "_border_" . $bp["right"]["style"];
         $this->{$method}($x + $w, $y, $h, $bp["right"]["color"], $widths, "right");
     }
     // Only two levels of links frames
     $link_node = null;
     if ($frame->get_node()->nodeName === "a") {
         $link_node = $frame->get_node();
         if (($name = $link_node->getAttribute("name")) || ($name = $link_node->getAttribute("id"))) {
             $this->_canvas->add_named_dest($name);
         }
     }
     if ($frame->get_parent() && $frame->get_parent()->get_node()->nodeName === "a") {
         $link_node = $frame->get_parent()->get_node();
     }
     // Handle anchors & links
     if ($link_node) {
         if ($href = $link_node->getAttribute("href")) {
             $href = Helpers::build_url($this->_dompdf->getProtocol(), $this->_dompdf->getBaseHost(), $this->_dompdf->getBasePath(), $href);
             $this->_canvas->add_link($href, $x, $y, $w, $h);
         }
     }
 }
Пример #26
0
 /**
  * @param \Dompdf\FrameDecorator\Text $frame
  */
 function render(Frame $frame)
 {
     $text = $frame->get_text();
     if (trim($text) === "") {
         return;
     }
     $style = $frame->get_style();
     list($x, $y) = $frame->get_position();
     $cb = $frame->get_containing_block();
     if (($ml = $style->margin_left) === "auto" || $ml === "none") {
         $ml = 0;
     }
     if (($pl = $style->padding_left) === "auto" || $pl === "none") {
         $pl = 0;
     }
     if (($bl = $style->border_left_width) === "auto" || $bl === "none") {
         $bl = 0;
     }
     $x += $style->length_in_pt(array($ml, $pl, $bl), $cb["w"]);
     $font = $style->font_family;
     $size = $frame_font_size = $style->font_size;
     $height = $style->height;
     $word_spacing = $frame->get_text_spacing() + $style->length_in_pt($style->word_spacing);
     $char_spacing = $style->length_in_pt($style->letter_spacing);
     $width = $style->width;
     /*$text = str_replace(
         array("{PAGE_NUM}"),
         array($this->_canvas->get_page_number()),
         $text
       );*/
     $this->_canvas->text($x, $y, $text, $font, $size, $style->color, $word_spacing, $char_spacing);
     $line = $frame->get_containing_line();
     // FIXME Instead of using the tallest frame to position,
     // the decoration, the text should be well placed
     if (false && $line->tallest_frame) {
         $base_frame = $line->tallest_frame;
         $style = $base_frame->get_style();
         $size = $style->font_size;
         $height = $line->h * ($size / $style->line_height);
     }
     $line_thickness = $size * self::DECO_THICKNESS;
     $underline_offset = $size * self::UNDERLINE_OFFSET;
     $overline_offset = $size * self::OVERLINE_OFFSET;
     $linethrough_offset = $size * self::LINETHROUGH_OFFSET;
     $underline_position = -0.08;
     if ($this->_canvas instanceof CPDF) {
         $cpdf_font = $this->_canvas->get_cpdf()->fonts[$style->font_family];
         if (isset($cpdf_font["UnderlinePosition"])) {
             $underline_position = $cpdf_font["UnderlinePosition"] / 1000;
         }
         if (isset($cpdf_font["UnderlineThickness"])) {
             $line_thickness = $size * ($cpdf_font["UnderlineThickness"] / 1000);
         }
     }
     $descent = $size * $underline_position;
     $base = $size;
     // Handle text decoration:
     // http://www.w3.org/TR/CSS21/text.html#propdef-text-decoration
     // Draw all applicable text-decorations.  Start with the root and work our way down.
     $p = $frame;
     $stack = array();
     while ($p = $p->get_parent()) {
         $stack[] = $p;
     }
     while (isset($stack[0])) {
         $f = array_pop($stack);
         if (($text_deco = $f->get_style()->text_decoration) === "none") {
             continue;
         }
         $deco_y = $y;
         //$line->y;
         $color = $f->get_style()->color;
         switch ($text_deco) {
             default:
                 continue;
             case "underline":
                 $deco_y += $base - $descent + $underline_offset + $line_thickness / 2;
                 break;
             case "overline":
                 $deco_y += $overline_offset + $line_thickness / 2;
                 break;
             case "line-through":
                 $deco_y += $base * 0.7 + $linethrough_offset;
                 break;
         }
         $dx = 0;
         $x1 = $x - self::DECO_EXTENSION;
         $x2 = $x + $width + $dx + self::DECO_EXTENSION;
         $this->_canvas->line($x1, $deco_y, $x2, $deco_y, $color, $line_thickness);
     }
     if ($this->_dompdf->getOptions()->getDebugLayout() && $this->_dompdf->getOptions()->getDebugLayoutLines()) {
         $text_width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $frame_font_size);
         $this->_debug_layout(array($x, $y, $text_width + ($line->wc - 1) * $word_spacing, $frame_font_size), "orange", array(0.5, 0.5));
     }
 }
Пример #27
0
 /**
  * Render frames recursively
  *
  * @param Frame $frame the frame to render
  */
 function render(Frame $frame)
 {
     global $_dompdf_debug;
     if ($_dompdf_debug) {
         echo $frame;
         flush();
     }
     $style = $frame->get_style();
     if (in_array($style->visibility, array("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 + $style->length_in_pt($origin[0], $style->width);
             $values[] = $y + $style->length_in_pt($origin[1], $style->height);
             call_user_func_array(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, $w, $h, $tl, $tr, $br, $bl);
         } else {
             $this->_canvas->clipping_rectangle($x, $y, $w, $h);
         }
     }
     $stack = array();
     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);
 }
 /**
  * split this frame at $child.
  * The current frame is cloned and $child and all children following
  * $child are added to the clone.  The clone is then passed to the
  * current frame's parent->split() method.
  *
  * @param Frame $child
  * @param boolean $force_pagebreak
  *
  * @throws Exception
  * @return void
  */
 function split(Frame $child = null, $force_pagebreak = false)
 {
     // decrement any counters that were incremented on the current node, unless that node is the body
     $style = $this->_frame->get_style();
     if ($this->_frame->get_node()->nodeName !== "body" && $style->counter_increment && ($decrement = $style->counter_increment) !== "none") {
         $this->decrement_counters($decrement);
     }
     if (is_null($child)) {
         // check for counter increment on :before content (always a child of the selected element @link AbstractFrameReflower::_set_content)
         // this can push the current node to the next page before counter rules have bubbled up (but only if
         // it's been rendered, thus the position check)
         if (!$this->is_text_node() && $this->get_node()->hasAttribute("dompdf_before_frame_id")) {
             foreach ($this->_frame->get_children() as $child) {
                 if ($this->get_node()->getAttribute("dompdf_before_frame_id") == $child->get_id() && $child->get_position('x') !== null) {
                     $style = $child->get_style();
                     if ($style->counter_increment && ($decrement = $style->counter_increment) !== "none") {
                         $this->decrement_counters($decrement);
                     }
                 }
             }
         }
         $this->get_parent()->split($this, $force_pagebreak);
         return;
     }
     if ($child->get_parent() !== $this) {
         throw new Exception("Unable to split: frame is not a child of this one.");
     }
     $node = $this->_frame->get_node();
     if ($node instanceof DOMElement && $node->hasAttribute("id")) {
         $node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
         $node->removeAttribute("id");
     }
     $split = $this->copy($node->cloneNode());
     $split->reset();
     $split->get_original_style()->text_indent = 0;
     $split->_splitted = true;
     // The body's properties must be kept
     if ($node->nodeName !== "body") {
         // Style reset on the first and second parts
         $style = $this->_frame->get_style();
         $style->margin_bottom = 0;
         $style->padding_bottom = 0;
         $style->border_bottom = 0;
         // second
         $orig_style = $split->get_original_style();
         $orig_style->text_indent = 0;
         $orig_style->margin_top = 0;
         $orig_style->padding_top = 0;
         $orig_style->border_top = 0;
         $orig_style->page_break_before = "auto";
     }
     $this->get_parent()->insert_child_after($split, $this);
     // Add $frame and all following siblings to the new split node
     $iter = $child;
     while ($iter) {
         $frame = $iter;
         $iter = $iter->get_next_sibling();
         $frame->reset();
         $split->append_child($frame);
     }
     $this->get_parent()->split($split, $force_pagebreak);
     // If this node resets a counter save the current value to use when rendering on the next page
     if ($style->counter_reset && ($reset = $style->counter_reset) !== "none") {
         $vars = preg_split('/\\s+/', trim($reset), 2);
         $split->_counters['__' . $vars[0]] = $this->lookup_counter_frame($vars[0])->_counters[$vars[0]];
     }
 }