function render(Frame $frame) { if (!$this->_dompdf->get_option("enable_javascript")) { return; } $this->insert($frame->get_node()->nodeValue); }
function render(Frame $frame) { if (!$this->_dompdf->getOptions()->getIsJavascriptEnabled()) { return; } $this->insert($frame->get_node()->nodeValue); }
/** * 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"; }
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); } }
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; }
/** * @return Frame */ public function next() { $ret = $this->_cur; if (!$ret) { return null; } $this->_cur = $this->_cur->get_next_sibling(); $this->_num++; return $ret; }
/** * "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); }
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"); } } }
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"); } } }
/** * Determine current frame width based on contents * * @return float */ public function calculate_auto_width() { return $this->_frame->get_margin_width(); }
function render(Frame $frame) { $this->evaluate($frame->get_node()->nodeValue); }
/** * @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); } }
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)); } } }
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; } } }
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; }
/** * 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); } }
/** * 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)); }
/** * 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; }
/** * 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; }
/** * 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); } }
/** * @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); }
/** * 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; }
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"); } } }
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); } } }
/** * @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)); } }
/** * 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]]; } }