function get_min_max_width()
 {
     if (!is_null($this->_min_max_cache)) {
         return $this->_min_max_cache;
     }
     $style = $this->_frame->get_style();
     // Account for margins & padding
     $dims = array($style->padding_left, $style->padding_right, $style->border_left_width, $style->border_right_width, $style->margin_left, $style->margin_right);
     $cb_w = $this->_frame->get_containing_block("w");
     $delta = $style->length_in_pt($dims, $cb_w);
     // Handle degenerate case
     if (!$this->_frame->get_first_child()) {
         return $this->_min_max_cache = array($delta, $delta, "min" => $delta, "max" => $delta);
     }
     $low = array();
     $high = array();
     for ($iter = $this->_frame->get_children()->getIterator(); $iter->valid(); $iter->next()) {
         $inline_min = 0;
         $inline_max = 0;
         // Add all adjacent inline widths together to calculate max width
         while ($iter->valid() && in_array($iter->current()->get_style()->display, Style::$INLINE_TYPES)) {
             $child = $iter->current();
             $minmax = $child->get_min_max_width();
             if (in_array($iter->current()->get_style()->white_space, array("pre", "nowrap"))) {
                 $inline_min += $minmax["min"];
             } else {
                 $low[] = $minmax["min"];
             }
             $inline_max += $minmax["max"];
             $iter->next();
         }
         if ($inline_max > 0) {
             $high[] = $inline_max;
         }
         if ($inline_min > 0) {
             $low[] = $inline_min;
         }
         if ($iter->valid()) {
             list($low[], $high[]) = $iter->current()->get_min_max_width();
             continue;
         }
     }
     $min = count($low) ? max($low) : 0;
     $max = count($high) ? max($high) : 0;
     // Use specified width if it is greater than the minimum defined by the
     // content.  If the width is a percentage ignore it for now.
     $width = $style->width;
     if ($width !== "auto" && !is_percent($width)) {
         $width = $style->length_in_pt($width, $cb_w);
         if ($min < $width) {
             $min = $width;
         }
         if ($max < $width) {
             $max = $width;
         }
     }
     $min += $delta;
     $max += $delta;
     return $this->_min_max_cache = array($min, $max, "min" => $min, "max" => $max);
 }
Example #2
0
 /**
  * Render all frames recursively
  *
  * @param Frame $root the root frame
  */
 function render(Frame $root)
 {
     // count() doesn't work on iterated elements
     // FIXME: look into the ArrayAccess interface - need 5.1 for SPL better
     // support.
     $count = 0;
     foreach ($root->get_children() as $page) {
         $count++;
     }
     $this->_canvas->set_page_count($count);
     // Create pages
     foreach ($root->get_children() as $page) {
         if ($page !== $root->get_first_child()) {
             $this->_canvas->new_page();
         }
         $this->_render_frame($page);
     }
 }
 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"))) {
                 $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 (DEBUG_LAYOUT && DEBUG_LAYOUT_INLINE) {
             $this->_debug_layout($child->get_border_box(), "blue");
             if (DEBUG_LAYOUT_PADDINGBOX) {
                 $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");
     }
     //    pre_var_dump(get_class($frame->get_next_sibling()));
     //    $last_row = get_class($frame->get_next_sibling()) !== 'Inline_Frame_Decorator';
     // 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")) {
             $this->_canvas->add_link($href, $x, $y, $w, $h);
         }
     }
 }
 function add_frame_to_line(Frame $frame)
 {
     // Handle inline frames (which are effectively wrappers)
     if ($frame instanceof Inline_Frame_Decorator) {
         // Handle line breaks
         if ($frame->get_node()->nodeName == "br") {
             $this->maximize_line_height($frame->get_style()->length_in_pt($frame->get_style()->line_height));
             $this->add_line();
             return;
         }
         // Add each child of the inline frame to the line individually
         foreach ($frame->get_children() as $child) {
             $this->add_frame_to_line($child);
         }
         return;
     }
     // Trim leading text if this is an empty line.  Kinda a hack to put it here,
     // but what can you do...
     if ($this->_lines[$this->_cl]["w"] == 0 && $frame->get_node()->nodeName == "#text" && ($frame->get_style()->white_space != "pre" || $frame->get_style()->white_space != "pre-wrap")) {
         $frame->set_text(ltrim($frame->get_text()));
         $frame->recalculate_width();
     }
     $w = $frame->get_margin_width();
     if ($w == 0) {
         return;
     }
     // Debugging code:
     /*
     pre_r("\nAdding frame to line:");
     
     //    pre_r("Me: " . $this->get_node()->nodeName . " (" . (string)$this->get_node() . ")");
     //    pre_r("Node: " . $frame->get_node()->nodeName . " (" . (string)$frame->get_node() . ")");
     if ( $frame->get_node()->nodeName == "#text" )
       pre_r($frame->get_node()->nodeValue);
     
     pre_r("Line width: " . $this->_lines[$this->_cl]["w"]);
     pre_r("Frame: " . get_class($frame));
     pre_r("Frame width: "  . $w);
     pre_r("Frame height: " . $frame->get_margin_height());
     pre_r("Containing block width: " . $this->get_containing_block("w"));
     */
     // End debugging
     if ($this->_lines[$this->_cl]["w"] + $w > $this->get_containing_block("w")) {
         $this->add_line();
     }
     $frame->position();
     $this->_lines[$this->_cl]["frames"][] = $frame;
     if ($frame->get_node()->nodeName == "#text") {
         $this->_lines[$this->_cl]["wc"] += count(preg_split("/\\s+/", $frame->get_text()));
     }
     $this->_lines[$this->_cl]["w"] += $w;
     $this->_lines[$this->_cl]["h"] = max($this->_lines[$this->_cl]["h"], $frame->get_margin_height());
 }
Example #5
0
 function add_frame(Frame $frame)
 {
     $style = $frame->get_style();
     $display = $style->display;
     $collapse = $this->_table->get_style()->border_collapse == "collapse";
     // Recursively add the frames within tables, table-row-groups and table-rows
     if ($display == "table-row" || $display == "table" || $display == "inline-table" || in_array($display, Table_Frame_Decorator::$ROW_GROUPS)) {
         $start_row = $this->__row;
         foreach ($frame->get_children() as $child) {
             $this->add_frame($child);
         }
         if ($display == "table-row") {
             $this->add_row();
         }
         $num_rows = $this->__row - $start_row - 1;
         $key = $frame->get_id();
         // Row groups always span across the entire table
         $this->_frames[$key]["columns"] = range(0, max(0, $this->_num_cols - 1));
         $this->_frames[$key]["rows"] = range($start_row, max(0, $this->__row - 1));
         $this->_frames[$key]["frame"] = $frame;
         if ($display != "table-row" && $collapse) {
             $bp = $style->get_border_properties();
             // Resolve the borders
             for ($i = 0; $i < $num_rows + 1; $i++) {
                 $this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
                 $this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
             }
             for ($j = 0; $j < $this->_num_cols; $j++) {
                 $this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
                 $this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
             }
         }
         return;
     }
     // Determine where this cell is going
     $colspan = $frame->get_node()->getAttribute("colspan");
     $rowspan = $frame->get_node()->getAttribute("rowspan");
     if (!$colspan) {
         $colspan = 1;
         $frame->get_node()->setAttribute("colspan", 1);
     }
     if (!$rowspan) {
         $rowspan = 1;
         $frame->get_node()->setAttribute("rowspan", 1);
     }
     $key = $frame->get_id();
     $bp = $style->get_border_properties();
     // Add the frame to the cellmap
     $max_left = $max_right = 0;
     // Find the next available column (fix by Ciro Mondueri)
     $ac = $this->__col;
     while (isset($this->_cells[$this->__row][$ac])) {
         $ac++;
     }
     $this->__col = $ac;
     // Rows:
     for ($i = 0; $i < $rowspan; $i++) {
         $row = $this->__row + $i;
         $this->_frames[$key]["rows"][] = $row;
         for ($j = 0; $j < $colspan; $j++) {
             $this->_cells[$row][$this->__col + $j] = $frame;
         }
         if ($collapse) {
             // Resolve vertical borders
             $max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]));
             $max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]));
         }
     }
     $max_top = $max_bottom = 0;
     // Columns:
     for ($j = 0; $j < $colspan; $j++) {
         $col = $this->__col + $j;
         $this->_frames[$key]["columns"][] = $col;
         if ($collapse) {
             // Resolve horizontal borders
             $max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]));
             $max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]));
         }
     }
     $this->_frames[$key]["frame"] = $frame;
     // Handle seperated border model
     if (!$collapse) {
         list($h, $v) = $this->_table->get_style()->border_spacing;
         // Border spacing is effectively a margin between cells
         $v = $style->length_in_pt($v) / 2;
         $h = $style->length_in_pt($h) / 2;
         $style->margin = "{$v} {$h}";
         // The additional 1/2 width gets added to the table proper
     } else {
         // Drop the frame's actual border
         $style->border_left_width = $max_left / 2;
         $style->border_right_width = $max_right / 2;
         $style->border_top_width = $max_top / 2;
         $style->border_bottom_width = $max_bottom / 2;
         $style->margin = "none";
     }
     // Resolve the frame's width
     list($frame_min, $frame_max) = $frame->get_min_max_width();
     $width = $style->width;
     if (is_percent($width)) {
         $var = "percent";
         $val = (double) rtrim($width, "% ") / $colspan;
     } else {
         if ($width !== "auto") {
             $var = "absolute";
             $val = $style->length_in_pt($frame_min) / $colspan;
         }
     }
     $min = 0;
     $max = 0;
     for ($cs = 0; $cs < $colspan; $cs++) {
         // Resolve the frame's width(s) with other cells
         $col =& $this->get_column($this->__col + $cs);
         // Note: $var is either 'percent' or 'absolute'.  We compare the
         // requested percentage or absolute values with the existing widths
         // and adjust accordingly.
         if (isset($var) && $val > $col[$var]) {
             $col[$var] = $val;
             $col["auto"] = false;
         }
         $min += $col["min-width"];
         $max += $col["max-width"];
     }
     if ($frame_min > $min) {
         // The frame needs more space.  Expand each sub-column
         $inc = ($frame_min - $min) / $colspan;
         for ($c = 0; $c < $colspan; $c++) {
             $col =& $this->get_column($this->__col + $c);
             $col["min-width"] += $inc;
         }
     }
     if ($frame_max > $max) {
         $inc = ($frame_max - $max) / $colspan;
         for ($c = 0; $c < $colspan; $c++) {
             $col =& $this->get_column($this->__col + $c);
             $col["max-width"] += $inc;
         }
     }
     $this->__col += $colspan;
     if ($this->__col > $this->_num_cols) {
         $this->_num_cols = $this->__col;
     }
 }
 /**
  * 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 DOMPDF_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 Frame_Reflower::_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 DOMPDF_Exception("Unable to split: frame is not a child of this one.");
     }
     $node = $this->_frame->get_node();
     $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;
     }
     $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]];
     }
 }
 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];
     $first_row = true;
     foreach ($frame->get_children() as $child) {
         list($child_x, $child_y, $child_w, $child_h) = $child->get_padding_box();
         $child_h += $widths[2];
         if (!is_null($w) && $child_x < $x + $w) {
             // The next child is on another line.  Draw the background on this line.
             if (($bg = $style->background_color) !== "transparent") {
                 $this->_canvas->filled_rectangle($x, $y, $w, $h, $style->background_color);
             }
             // If this is the first row, draw the left border
             if ($first_row) {
                 if ($bp["left"]["style"] != "none" && $bp["left"]["width"] > 0) {
                     $method = "_border_" . $bp["left"]["style"];
                     $this->{$method}($x, $y, $h, $bp["left"]["color"], $widths, "left");
                 }
                 $first_row = false;
             }
             // Draw the top & bottom borders
             if ($bp["top"]["style"] != "none" && $bp["top"]["width"] > 0) {
                 $method = "_border_" . $bp["top"]["style"];
                 $this->{$method}($x, $y, $w, $bp["top"]["color"], $widths, "top");
             }
             if ($bp["bottom"]["style"] != "none" && $bp["bottom"]["width"] > 0) {
                 $method = "_border_" . $bp["bottom"]["style"];
                 $this->{$method}($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom");
             }
             $x = $child_x + $widths[3];
             $y = $child_y + $widths[0];
             $w = $child_w;
             $h = $child_h;
             continue;
         }
         if (is_null($w)) {
             $w = $child_w;
         } else {
             $w += $child_w;
         }
         $h = max($h, $child_h);
     }
     // Handle the last child
     if (($bg = $style->background_color) !== "transparent") {
         $this->_canvas->filled_rectangle($x, $y, $w, $h, $style->background_color);
     }
     // If this is the first row, draw the left border too
     if ($first_row && $bp["left"]["style"] != "none" && $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" && $widths[0] > 0) {
         $method = "_border_" . $bp["top"]["style"];
         $this->{$method}($x, $y, $w, $bp["top"]["color"], $widths, "top");
     }
     if ($bp["bottom"]["style"] != "none" && $widths[2] > 0) {
         $method = "_border_" . $bp["bottom"]["style"];
         $this->{$method}($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom");
     }
     // Draw the right border
     if ($bp["right"]["style"] != "none" && $widths[1] > 0) {
         $method = "_border_" . $bp["right"]["style"];
         $this->{$method}($x + $w, $y, $h, $bp["right"]["color"], $widths, "right");
     }
 }
 /**
  * Render frames recursively
  *
  * @param Frame $frame the frame to render
  */
 private function _render(Frame $frame, $depth = 0)
 {
     //$sRet = '';
     $this->_level = $depth;
     $node = $frame->get_node();
     $properties = $frame->get_style();
     $this->countTags = array_count_values(self::$openTags);
     switch ($node->nodeName) {
         case 'p':
         case 'div':
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             if (self::$openPs) {
                 self::$WordML .= '</w:p><w:p>';
             } else {
                 self::$WordML .= '<w:p>';
                 self::$openPs = true;
             }
             self::$WordML .= $this->generatePPr($properties);
             self::$openTags[$depth] = $node->nodeName;
             break;
         case 'ul':
         case 'ol':
             self::$openTags[$depth] = $node->nodeName;
             break;
         case 'li':
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             if (self::$openPs) {
                 self::$WordML .= '</w:p><w:p>';
             } else {
                 self::$WordML .= '<w:p>';
                 self::$openPs = true;
             }
             self::$WordML .= $this->generateListPr($properties);
             self::$openTags[$depth] = $node->nodeName;
             break;
         case 'table':
             self::$openTable = array();
             //TODO cambiar para tablas anidadas
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             if (self::$openPs) {
                 self::$WordML .= '</w:p><w:tbl>';
                 self::$openPs = false;
             } else {
                 self::$WordML .= '<w:tbl>';
             }
             self::$WordML .= $this->generateTblPr($properties);
             self::$openTags[$depth] = $node->nodeName;
             break;
         case 'tr':
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             array_push(self::$openTable, array());
             self::$WordML .= '<w:tr>';
             self::$WordML .= $this->generateTrPr($properties);
             self::$openTags[$depth] = $node->nodeName;
             break;
         case 'td':
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             $firstRow = false;
             //Now we have to deal with the details associated to the rowspan and colspan of this table cell
             $colspan = (int) $node->getAttribute('colspan');
             $colspan = empty($colspan) ? 1 : $colspan;
             $rowspan = (int) $node->getAttribute('rowspan');
             $rowspan = empty($rowspan) ? 1 : $rowspan;
             $row = count(self::$openTable) - 1;
             $column = count(self::$openTable[$row]);
             $vmerge = $this->countEmptyColumns($row, $column);
             for ($k = 0; $k < $colspan; $k++) {
                 array_push(self::$openTable[count(self::$openTable) - 1], $rowspan);
             }
             if ($vmerge > 0) {
                 self::$WordML .= '<w:tc><w:tcPr><w:gridSpan  w:val="' . $vmerge . '" /><w:vMerge w:val="continue" /></w:tcPr><w:p /></w:tc>';
             }
             self::$WordML .= '<w:tc>';
             self::$WordML .= $this->generateTcPr($properties, $colspan, $rowspan, $firstRow);
             //FIXME
             self::$openTags[$depth] = $node->nodeName;
             break;
         case 'th':
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             $firstRow = true;
             //Now we have to deal with the details associated to the rowspan and colspan of this table cell
             $colspan = (int) $node->getAttribute('colspan');
             $colspan = empty($colspan) ? 1 : $colspan;
             $rowspan = (int) $node->getAttribute('rowspan');
             $rowspan = empty($rowspan) ? 1 : $rowspan;
             $row = count(self::$openTable) - 1;
             $column = count(self::$openTable[$row]);
             $vmerge = $this->countEmptyColumns($row, $column);
             for ($k = 0; $k < $colspan; $k++) {
                 array_push(self::$openTable[count(self::$openTable) - 1], $rowspan);
             }
             if ($vmerge > 0) {
                 self::$WordML .= '<w:tc><w:tcPr><w:gridSpan  w:val="' . $vmerge . '" /><w:vMerge w:val="continue" /></w:tcPr><w:p /></w:tc>';
             }
             self::$WordML .= '<w:tc>';
             self::$WordML .= $this->generateTcPr($properties, $colspan, $rowspan, $firstRow);
             //FIXME
             self::$openTags[$depth] = $node->nodeName;
             break;
         case '#text':
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             if (self::$openPs) {
                 self::$WordML .= '<w:r>';
             } else {
                 self::$WordML .= '<w:p>';
                 self::$WordML .= $this->generatePPr($properties);
                 self::$WordML .= '<w:r>';
                 self::$openPs = true;
             }
             self::$WordML .= $this->generateRPr($properties);
             self::$WordML .= '<w:t>' . htmlspecialchars($node->nodeValue);
             self::$WordML .= '</w:t></w:r>';
             self::$openTags[$depth] = $node->nodeName;
             break;
         case 'br':
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             if (self::$openPs) {
                 self::$WordML .= '<w:r><w:br /><w:t></w:t></w:r>';
             } else {
                 self::$WordML .= '<w:p />';
             }
             break;
         case 'close':
             //if(strpos(self::$WordML, '#<w:gridCol/>#') !== false) self::$WordML = str_replace('#<w:gridCol/>#', '<w:gridCol/>', self::$WordML); //TODO forzar limpieza de columnas de tabla?
             self::$WordML .= $this->closePreviousTags($depth, $node->nodeName);
             break;
         default:
             self::$openTags[$depth] = $node->nodeName;
             break;
     }
     ++$depth;
     foreach ($frame->get_children() as $child) {
         //var_dump(gettype($child));
         $this->_render($child, $depth);
     }
 }
 function render(Frame $frame)
 {
     $style = $frame->get_style();
     if (!$frame->get_first_child()) {
         return;
     }
     $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"]));
     list($x, $y) = $frame->get_first_child()->get_position();
     $w = null;
     $h = 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) {
             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 ($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;
             }
             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");
             }
             $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"))) {
                 $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 (($bg = $style->background_color) !== "transparent") {
         $this->_canvas->filled_rectangle($x + $widths[3], $y + $widths[0], $w, $h, $bg);
     }
     if (($url = $style->background_image) && $url !== "none") {
         $this->_background_image($url, $x + $widths[3], $y + $widths[0], $w, $h, $style);
     }
     $w += $widths[1] + $widths[3];
     $h += $widths[0] + $widths[2];
     $left_margin = $style->length_in_pt($style->margin_left);
     $x += $left_margin;
     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");
     }
     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");
     }
     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");
     }
     $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();
     }
     if ($link_node) {
         if ($href = $link_node->getAttribute("href")) {
             $this->_canvas->add_link($href, $x, $y, $w, $h);
         }
     }
     if (DEBUG_LAYOUT && DEBUG_LAYOUT_INLINE) {
         $this->_debug_layout($child->get_border_box(), "blue");
         if (DEBUG_LAYOUT_PADDINGBOX) {
             $this->_debug_layout($child->get_padding_box(), "blue", array(0.5, 0.5));
         }
     }
 }
 function add_frame_to_line(Frame $frame)
 {
     // Handle inline frames (which are effectively wrappers)
     if ($frame instanceof Inline_Frame_Decorator) {
         // Add each child of the inline frame to the line individually
         foreach ($frame->get_children() as $child) {
             $this->add_frame_to_line($child);
         }
         return;
     }
     if ($frame->get_margin_width() == 0) {
         return;
     }
     $w = $frame->get_margin_width();
     // Debugging code:
     //     pre_r("\nAdding frame to line:");
     //     pre_r("Me: " . $this->get_node()->nodeName . " (" . (string)$this->get_node() . ")");
     //     pre_r("Node: " . $frame->get_node()->nodeName . " (" . (string)$frame->get_node() . ")");
     //     if ( $frame->get_node()->nodeName == "#text" )
     //       pre_r($frame->get_node()->nodeValue);
     //     pre_r("Line width: " . $this->_lines[$this->_cl]["w"]);
     //     pre_r("Frame width: "  . $w);
     //     pre_r("Frame height: " . $frame->get_margin_height());
     //     pre_r("Containing block width: " . $this->get_containing_block("w"));
     // End debugging
     if ($this->_lines[$this->_cl]["w"] + $w >= $this->get_containing_block("w")) {
         $this->add_line();
     }
     $frame->position();
     $this->_lines[$this->_cl]["frames"][] = $frame;
     if ($frame->get_node()->nodeName == "#text") {
         $this->_lines[$this->_cl]["wc"] += count(preg_split("/\\s+/", $frame->get_text()));
     }
     $this->_lines[$this->_cl]["w"] += $w;
     $this->_lines[$this->_cl]["h"] = max($this->_lines[$this->_cl]["h"], $frame->get_margin_height());
 }
Example #11
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];
     $first_row = true;
     foreach ($frame->get_children() as $child) {
         list($child_x, $child_y, $child_w, $child_h) = $child->get_padding_box();
         $child_h += $widths[2];
         if (!is_null($w) && $child_x < $x + $w) {
             // 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, $style->background_color);
             }
             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"]["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"]["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"]["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
             if ($frame->get_node()->nodeName == "a") {
                 if ($href = $frame->get_node()->getAttribute("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);
     }
     // Handle the last child
     if (($bg = $style->background_color) !== "transparent") {
         $this->_canvas->filled_rectangle($x + $widths[3], $y + $widths[0], $w, $h, $style->background_color);
     }
     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" && $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" && $widths[0] > 0) {
         $method = "_border_" . $bp["top"]["style"];
         $this->{$method}($x, $y, $w, $bp["top"]["color"], $widths, "top");
     }
     if ($bp["bottom"]["style"] != "none" && $widths[2] > 0) {
         $method = "_border_" . $bp["bottom"]["style"];
         $this->{$method}($x, $y + $h, $w, $bp["bottom"]["color"], $widths, "bottom");
     }
     //    pre_var_dump(get_class($frame->get_next_sibling()));
     //    $last_row = get_class($frame->get_next_sibling()) != 'Inline_Frame_Decorator';
     // Draw the right border if this is the last row
     if ($bp["right"]["style"] != "none" && $widths[1] > 0) {
         $method = "_border_" . $bp["right"]["style"];
         $this->{$method}($x + $w, $y, $h, $bp["right"]["color"], $widths, "right");
     }
     // Handle anchors & links
     if ($frame->get_node()->nodeName == "a") {
         if ($name = $frame->get_node()->getAttribute("name")) {
             $this->_canvas->add_named_dest($name);
         }
         if ($href = $frame->get_node()->getAttribute("href")) {
             $this->_canvas->add_link($href, $x, $y, $w, $h);
         }
     }
 }
 /**
  * Render frames recursively
  *
  * @param Frame $frame The frame to render
  */
 private function _render(Frame $frame, $id)
 {
     $aDompdfTree = array();
     $node = $frame->get_node();
     switch ($node->nodeName) {
         case 'caption':
             //ignore these tags
         //ignore these tags
         case 'meta':
         case 'script':
         case 'title':
             break;
         case '#text':
         case 'a':
         case 'br':
         case 'dd':
         case 'div':
         case 'dl':
         case 'dt':
         case 'h1':
         case 'h2':
         case 'h3':
         case 'h4':
         case 'h5':
         case 'h6':
         case 'li':
         case 'ol':
         case 'p':
         case 'table':
         case 'td':
         case 'th':
         case 'tr':
         case 'ul':
         case 'img':
         case 'img_inner':
             $aDompdfTree['nodeName'] = $node->nodeName;
             $aDompdfTree['nodeValue'] = $node->nodeValue;
             $aDompdfTree['attributes'] = $this->getAttributes($node);
             $aDompdfTree['properties'] = $this->getProperties($frame->get_style());
             if ($id == '*' || isset($aDompdfTree['attributes']['id']) && $id == $aDompdfTree['attributes']['id']) {
                 $id = '*';
             } else {
                 $aDompdfTree['nodeName'] .= '_noPaint';
             }
             $aTempTree = array();
             foreach ($frame->get_children() as $child) {
                 $aTemp = $this->_render($child, $id);
                 if (!empty($aTemp)) {
                     $aTempTree[] = $aTemp;
                 }
             }
             $aDompdfTree['children'] = empty($aTempTree) ? array() : $aTempTree;
             return $aDompdfTree;
             break;
         case 'close':
             $aDompdfTree['nodeName'] = $node->nodeName;
             foreach ($frame->get_children() as $child) {
                 $aTemp = $this->_render($child, $id);
                 if (!empty($aTemp)) {
                     $aTempTree[] = $aTemp;
                 }
             }
             $aDompdfTree['children'] = empty($aTempTree) ? array() : $aTempTree;
             return $aDompdfTree;
             break;
         default:
             $aDompdfTree['nodeName'] = $node->nodeName;
             if ($id == '*' || isset($aDompdfTree['attributes']['id']) && $id == $aDompdfTree['attributes']['id']) {
                 $id = '*';
             } else {
                 $aDompdfTree['nodeName'] .= '_noPaint';
             }
             foreach ($frame->get_children() as $child) {
                 $aTemp = $this->_render($child, $id);
                 if (!empty($aTemp)) {
                     $aTempTree[] = $aTemp;
                 }
             }
             $aDompdfTree['children'] = empty($aTempTree) ? array() : $aTempTree;
             return $aDompdfTree;
             break;
     }
     return false;
 }
 function add_frame(Frame $frame)
 {
     $style = $frame->get_style();
     $display = $style->display;
     $collapse = $this->_table->get_style()->border_collapse == "collapse";
     if ($display === "table-row" || $display === "table" || $display === "inline-table" || in_array($display, Table_Frame_Decorator::$ROW_GROUPS)) {
         $start_row = $this->__row;
         foreach ($frame->get_children() as $child) {
             $this->add_frame($child);
         }
         if ($display === "table-row") {
             $this->add_row();
         }
         $num_rows = $this->__row - $start_row - 1;
         $key = $frame->get_id();
         $this->_frames[$key]["columns"] = range(0, max(0, $this->_num_cols - 1));
         $this->_frames[$key]["rows"] = range($start_row, max(0, $this->__row - 1));
         $this->_frames[$key]["frame"] = $frame;
         if ($display !== "table-row" && $collapse) {
             $bp = $style->get_border_properties();
             for ($i = 0; $i < $num_rows + 1; $i++) {
                 $this->_resolve_border($start_row + $i, 0, "vertical", $bp["left"]);
                 $this->_resolve_border($start_row + $i, $this->_num_cols, "vertical", $bp["right"]);
             }
             for ($j = 0; $j < $this->_num_cols; $j++) {
                 $this->_resolve_border($start_row, $j, "horizontal", $bp["top"]);
                 $this->_resolve_border($this->__row, $j, "horizontal", $bp["bottom"]);
             }
         }
         return;
     }
     $node = $frame->get_node();
     $colspan = $node->getAttribute("colspan");
     $rowspan = $node->getAttribute("rowspan");
     if (!$colspan) {
         $colspan = 1;
         $node->setAttribute("colspan", 1);
     }
     if (!$rowspan) {
         $rowspan = 1;
         $node->setAttribute("rowspan", 1);
     }
     $key = $frame->get_id();
     $bp = $style->get_border_properties();
     $max_left = $max_right = 0;
     $ac = $this->__col;
     while (isset($this->_cells[$this->__row][$ac])) {
         $ac++;
     }
     $this->__col = $ac;
     for ($i = 0; $i < $rowspan; $i++) {
         $row = $this->__row + $i;
         $this->_frames[$key]["rows"][] = $row;
         for ($j = 0; $j < $colspan; $j++) {
             $this->_cells[$row][$this->__col + $j] = $frame;
         }
         if ($collapse) {
             $max_left = max($max_left, $this->_resolve_border($row, $this->__col, "vertical", $bp["left"]));
             $max_right = max($max_right, $this->_resolve_border($row, $this->__col + $colspan, "vertical", $bp["right"]));
         }
     }
     $max_top = $max_bottom = 0;
     for ($j = 0; $j < $colspan; $j++) {
         $col = $this->__col + $j;
         $this->_frames[$key]["columns"][] = $col;
         if ($collapse) {
             $max_top = max($max_top, $this->_resolve_border($this->__row, $col, "horizontal", $bp["top"]));
             $max_bottom = max($max_bottom, $this->_resolve_border($this->__row + $rowspan, $col, "horizontal", $bp["bottom"]));
         }
     }
     $this->_frames[$key]["frame"] = $frame;
     if (!$collapse) {
         list($h, $v) = $this->_table->get_style()->border_spacing;
         $v = $style->length_in_pt($v) / 2;
         $h = $style->length_in_pt($h) / 2;
         $style->margin = "{$v} {$h}";
     } else {
         $style->border_left_width = $max_left / 2;
         $style->border_right_width = $max_right / 2;
         $style->border_top_width = $max_top / 2;
         $style->border_bottom_width = $max_bottom / 2;
         $style->margin = "none";
     }
     list($frame_min, $frame_max) = $frame->get_min_max_width();
     $width = $style->width;
     if (is_percent($width)) {
         $var = "percent";
         $val = (double) rtrim($width, "% ") / $colspan;
     } else {
         if ($width !== "auto") {
             $var = "absolute";
             $val = $style->length_in_pt($frame_min) / $colspan;
         }
     }
     if (!$this->_columns_locked) {
         $min = 0;
         $max = 0;
         for ($cs = 0; $cs < $colspan; $cs++) {
             $col =& $this->get_column($this->__col + $cs);
             if (isset($var) && $val > $col[$var]) {
                 $col[$var] = $val;
                 $col["auto"] = false;
             }
             $min += $col["min-width"];
             $max += $col["max-width"];
         }
         if ($frame_min > $min) {
             $inc = ($frame_min - $min) / $colspan;
             for ($c = 0; $c < $colspan; $c++) {
                 $col =& $this->get_column($this->__col + $c);
                 $col["min-width"] += $inc;
             }
         }
         if ($frame_max > $max) {
             $inc = ($frame_max - $max) / $colspan;
             for ($c = 0; $c < $colspan; $c++) {
                 $col =& $this->get_column($this->__col + $c);
                 $col["max-width"] += $inc;
             }
         }
     }
     $this->__col += $colspan;
     if ($this->__col > $this->_num_cols) {
         $this->_num_cols = $this->__col;
     }
 }