protected function _line_break($text) { $style = $this->_frame->get_style(); $size = $style->font_size; $font = $style->font_family; $current_line = $this->_block_parent->get_current_line(); // Determine the available width $line_width = $this->_frame->get_containing_block("w"); $current_line_width = $current_line["left"] + $current_line["w"] + $current_line["right"]; $available_width = $line_width - $current_line_width; // split the text into words $words = preg_split('/([\\s-]+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE); $wc = count($words); // Account for word-spacing $word_spacing = $style->length_in_pt($style->word_spacing); $char_spacing = $style->length_in_pt($style->letter_spacing); // Determine the frame width including margin, padding & border $text_width = Font_Metrics::get_text_width($text, $font, $size, $word_spacing, $char_spacing); $mbp_width = $style->length_in_pt(array($style->margin_left, $style->border_left_width, $style->padding_left, $style->padding_right, $style->border_right_width, $style->margin_right), $line_width); $frame_width = $text_width + $mbp_width; // Debugging: // pre_r("Text: '" . htmlspecialchars($text). "'"); // pre_r("width: " .$frame_width); // pre_r("textwidth + delta: $text_width + $mbp_width"); // pre_r("font-size: $size"); // pre_r("cb[w]: " .$line_width); // pre_r("available width: " . $available_width); // pre_r("current line width: " . $current_line_width); // pre_r($words); if ($frame_width <= $available_width) { return false; } // Determine the split point $width = 0; $str = ""; reset($words); // @todo support <shy>, <wbr> for ($i = 0; $i < $wc; $i += 2) { $word = $words[$i] . (isset($words[$i + 1]) ? $words[$i + 1] : ""); $word_width = Font_Metrics::get_text_width($word, $font, $size, $word_spacing, $char_spacing); if ($width + $word_width + $mbp_width > $available_width) { break; } $width += $word_width; $str .= $word; } // The first word has overflowed. Force it onto the line if ($current_line_width == 0 && $width == 0) { $width += $word_width; $str .= $word; } $offset = mb_strlen($str); // More debugging: // pre_var_dump($str); // pre_r("Width: ". $width); // pre_r("Offset: " . $offset); return $offset; }
function reflow(Frame_Decorator $block = null) { // Check if a page break is forced $page = $this->_frame->get_root(); $page->check_forced_page_break($this->_frame); // Bail if the page is full if ($page->is_full()) { return; } // Generated content $this->_set_content(); // Collapse margins if required $this->_collapse_margins(); $style = $this->_frame->get_style(); $cb = $this->_frame->get_containing_block(); if ($style->counter_increment && ($increment = $style->counter_increment) !== "none") { $this->_frame->increment_counter($increment); } if ($style->position === "fixed") { $cb = $this->_frame->get_root()->get_containing_block(); } // Determine the constraints imposed by this frame: calculate the width // of the content area: list($w, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width(); // Store the calculated properties $style->width = $w . "pt"; $style->margin_left = $left_margin . "pt"; $style->margin_right = $right_margin . "pt"; $style->left = $left . "pt"; $style->right = $right . "pt"; // Update the position $this->_frame->position(); list($x, $y) = $this->_frame->get_position(); // Adjust the first line based on the text-indent property $indent = $style->length_in_pt($style->text_indent, $cb["w"]); $this->_frame->increase_line_width($indent); // Determine the content edge $top = $style->length_in_pt(array($style->margin_top, $style->padding_top, $style->border_top_width), $cb["h"]); $bottom = $style->length_in_pt(array($style->border_bottom_width, $style->margin_bottom, $style->padding_bottom), $cb["h"]); $cb_x = $x + $left_margin + $style->length_in_pt(array($style->border_left_width, $style->padding_left), $cb["w"]); $cb_y = $y + $top; $cb_h = $cb["h"] + $cb["y"] - $bottom - $cb_y; // Set the y position of the first line in this block $this->_frame->set_current_line($cb_y); $floating_children = array(); // Set the containing blocks and reflow each child foreach ($this->_frame->get_children() as $child) { // Bail out if the page is full if ($page->is_full()) { break; } // Floating siblings if (DOMPDF_ENABLE_CSS_FLOAT && count($floating_children)) { $offset_left = 0; $offset_right = 0; // We need to reflow the child to know its initial x position $child->set_containing_block($cb_x, $cb_y, $w, $cb_h); $child->reflow($this->_frame); $current_line = $this->_frame->get_current_line(); foreach ($floating_children as $child_key => $floating_child) { $float = $floating_child->get_style()->float; $floating_width = $floating_child->get_margin_width(); $floating_x = $floating_child->get_position("x"); if ($float === "left") { if ($current_line["left"] + $child->get_position("x") > $floating_x + $floating_width) { continue; } } else { if ($current_line["left"] + $child->get_position("x") + $child->get_margin_width() < $w - $floating_width - $current_line["right"]) { continue; } } // If the child is still shifted by the floating element if ($floating_child->get_position("y") + $floating_child->get_margin_height() > $current_line["y"]) { if ($float === "left") { $offset_left += $floating_width; } else { $offset_right += $floating_width; } } else { unset($floating_children[$child_key]); } } if ($offset_left) { $this->_frame->set_current_line(array("left" => $offset_left)); } if ($offset_right) { $this->_frame->set_current_line(array("right" => $offset_right)); } } $child->set_containing_block($cb_x, $cb_y, $w, $cb_h); $child->reflow($this->_frame); // Don't add the child to the line if a page break has occurred if ($page->check_page_break($child)) { break; } $child_style = $child->get_style(); if (DOMPDF_ENABLE_CSS_FLOAT && $child_style->float !== "none") { $floating_children[] = $child; // Remove next frame's beginning whitespace $next = $child->get_next_sibling(); if ($next && $next instanceof Text_Frame_Decorator) { $next->set_text(ltrim($next->get_text())); } $float_x = $cb_x; $float_y = $this->_frame->get_current_line("y"); $child_style = $child->get_style(); switch ($child_style->float) { case "left": break; case "right": $width = $w; $float_x += $width - $child->get_margin_width(); break; } $child->set_position($float_x, $float_y); } } // Determine our height list($height, $margin_top, $margin_bottom, $top, $bottom) = $this->_calculate_restricted_height(); $style->height = $height; $style->margin_top = $margin_top; $style->margin_bottom = $margin_bottom; $style->top = $top; $style->bottom = $bottom; $this->_text_align(); $this->vertical_align(); if ($block) { $block->add_frame_to_line($this->_frame); } }