function get_float_offsets() { if (!DOMPDF_ENABLE_CSS_FLOAT) { return; } static $anti_infinite_loop = 500; // FIXME smelly hack $reflower = $this->_block_frame->get_reflower(); if (!$reflower) return; $cb_w = null; $block = $this->_block_frame; $root = $block->get_root(); $floating_frames = $this->get_floats_inside($root); foreach ($floating_frames as $child_key => $floating_frame) { $id = $floating_frame->get_id(); if (isset($this->floating_blocks[$id])) { continue; } $floating_style = $floating_frame->get_style(); $clear = $floating_style->clear; $float = $floating_style->float; $floating_width = $floating_frame->get_margin_width(); if (!$cb_w) { $cb_w = $floating_frame->get_containing_block("w"); } $line_w = $this->get_width(); if (!$floating_frame->_float_next_line && ($cb_w <= $line_w + $floating_width) && ($cb_w > $line_w)) { $floating_frame->_float_next_line = true; continue; } // If the child is still shifted by the floating element if ($anti_infinite_loop-- > 0 && $floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y && $block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x") ) { if ($float === "left") $this->left += $floating_width; else $this->right += $floating_width; $this->floating_blocks[$id] = true; } // else, the floating element won't shift anymore else { $root->remove_floating_frame($child_key); } } }
function reflow(Block_Frame_Decorator $block = null) { $this->_frame->position(); //FLOAT //$frame = $this->_frame; //$page = $frame->get_root(); //if (DOMPDF_ENABLE_CSS_FLOAT && $frame->get_style()->float !== "none" ) { // $page->add_floating_frame($this); //} // Set the frame's width $this->get_min_max_width(); if ($block) { $block->add_frame_to_line($this->_frame); } }
function get_float_offsets() { $enable_css_float = $this->_block_frame->get_dompdf()->get_option("enable_css_float"); if (!$enable_css_float) { return; } static $anti_infinite_loop = 500; // FIXME smelly hack $reflower = $this->_block_frame->get_reflower(); if (!$reflower) { return; } $cb_w = null; $block = $this->_block_frame; $root = $block->get_root(); if (!$root) { return; } $floating_frames = $this->get_floats_inside($root); foreach ($floating_frames as $child_key => $floating_frame) { $id = $floating_frame->get_id(); if (isset($this->floating_blocks[$id])) { continue; } $floating_style = $floating_frame->get_style(); $float = $floating_style->float; $floating_width = $floating_frame->get_margin_width(); if (!$cb_w) { $cb_w = $floating_frame->get_containing_block("w"); } $line_w = $this->get_width(); if (!$floating_frame->_float_next_line && $cb_w <= $line_w + $floating_width && $cb_w > $line_w) { $floating_frame->_float_next_line = true; continue; } // If the child is still shifted by the floating element if ($anti_infinite_loop-- > 0 && $floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y && $block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x")) { if ($float === "left") { $this->left += $floating_width; } else { $this->right += $floating_width; } $this->floating_blocks[$id] = true; } else { $root->remove_floating_frame($child_key); } } }
function reset() { parent::reset(); $this->_resolved_borders = array(); $this->_content_height = 0; $this->_frame->reset(); }
function reflow(Block_Frame_Decorator $block = null) { $this->_frame->position(); //FLOAT //$frame = $this->_frame; //$page = $frame->get_root(); //$enable_css_float = $this->get_dompdf()->get_option("enable_css_float"); //if ($enable_css_float && $frame->get_style()->float !== "none" ) { // $page->add_floating_frame($this); //} // Set the frame's width $this->get_min_max_width(); if ($block) { $block->add_frame_to_line($this->_frame); } }
function reflow(Block_Frame_Decorator $block = null) { $frame = $this->_frame; // Check if a page break is forced $page = $frame->get_root(); $page->check_forced_page_break($frame); if ( $page->is_full() ) return; $style = $frame->get_style(); // Generated content $this->_set_content(); $frame->position(); $cb = $frame->get_containing_block(); // Add our margin, padding & border to the first and last children if ( ($f = $frame->get_first_child()) && $f instanceof Text_Frame_Decorator ) { $f_style = $f->get_style(); $f_style->margin_left = $style->margin_left; $f_style->padding_left = $style->padding_left; $f_style->border_left = $style->border_left; } if ( ($l = $frame->get_last_child()) && $l instanceof Text_Frame_Decorator ) { $l_style = $l->get_style(); $l_style->margin_right = $style->margin_right; $l_style->padding_right = $style->padding_right; $l_style->border_right = $style->border_right; } if ( $block ) { $block->add_frame_to_line($this->_frame); } // Set the containing blocks and reflow each child. The containing // block is not changed by line boxes. foreach ( $frame->get_children() as $child ) { $child->set_containing_block($cb); $child->reflow($block); } }
function get_float_offsets() { static $anti_infinite_loop; $reflower = $this->_block_frame->get_reflower(); if (!$reflower) { return; } $cb_w = null; if (DOMPDF_ENABLE_CSS_FLOAT) { $block = $this->_block_frame; $root = $block->get_root(); $floating_frames = $root->get_floating_frames(); foreach ($floating_frames as $child_key => $floating_frame) { $id = $floating_frame->get_id(); if (isset($this->floating_blocks[$id])) { continue; } $float = $floating_frame->get_style()->float; $floating_width = $floating_frame->get_margin_width(); if (!$cb_w) { $cb_w = $floating_frame->get_containing_block("w"); } $line_w = $this->get_width(); if (!$floating_frame->_float_next_line && $cb_w <= $line_w + $floating_width && $cb_w > $line_w) { $floating_frame->_float_next_line = true; continue; } // If the child is still shifted by the floating element if ($anti_infinite_loop++ < 1000 && $floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y && $block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x")) { if ($float === "left") { $this->left += $floating_width; } else { $this->right += $floating_width; } $this->floating_blocks[$id] = true; } else { $root->remove_floating_frame($child_key); } } } }
/** * Align inline children vertically. * Aligns each child vertically after each line is reflowed */ function vertical_align() { $canvas = null; foreach ($this->_frame->get_line_boxes() as $line) { $height = $line->h; foreach ($line->get_frames() as $frame) { $style = $frame->get_style(); if ($style->display !== "inline" && $style->display !== "text") { continue; } // FIXME? if ($this instanceof Table_Cell_Frame_Reflower) { $align = $frame->get_frame()->get_style()->vertical_align; } else { $align = $frame->get_frame()->get_parent()->get_style()->vertical_align; } $frame_h = $frame->get_margin_height(); if (!isset($canvas)) { $canvas = $frame->get_root()->get_dompdf()->get_canvas(); } $baseline = $canvas->get_font_baseline($style->font_family, $style->font_size); $y_offset = 0; switch ($align) { case "baseline": $y_offset = $height * 0.8 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning break; case "middle": $y_offset = ($height * 0.8 - $baseline) / 2; break; case "sub": $y_offset = 0.3 * $height; break; case "super": $y_offset = -0.2 * $height; break; case "text-top": case "top": // Not strictly accurate, but good enough for now break; case "text-bottom": case "bottom": $y_offset = $height * 0.8 - $baseline; break; } if ($y_offset) { $frame->move(0, $y_offset); } } } }
function get_float_offsets() { $reflower = $this->_block_frame->get_reflower(); if (!$reflower) { return; } $floating_children = $reflower->get_floating_children(); $cb_w = null; if (DOMPDF_ENABLE_CSS_FLOAT && !empty($floating_children)) { foreach ($floating_children as $child_key => $floating_child) { $id = $floating_child->get_id(); if (isset($this->floating_blocks[$id])) { continue; } $float = $floating_child->get_style()->float; $floating_width = $floating_child->get_margin_width(); if (!$cb_w) { $cb_w = $floating_child->get_containing_block("w"); } $line_w = $this->get_width(); if (!$floating_child->_float_next_line && $cb_w <= $line_w + $floating_width && $cb_w > $line_w) { $floating_child->_float_next_line = true; continue; } // If the child is still shifted by the floating element if ($floating_child->get_position("y") + $floating_child->get_margin_height() > $this->y) { if ($float === "left") { $this->left += $floating_width; } else { $this->right += $floating_width; } $this->floating_blocks[$id] = true; } else { $reflower->remove_floating_child($child_key); } } } }
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->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); $this->_frame->get_current_line_box()->get_float_offsets(); // 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; } $child->set_containing_block($cb_x, $cb_y, $w, $cb_h); $this->process_clear($child); $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; } $this->process_float($child, $cb_x, $w); } // 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; $needs_reposition = $style->position === "absolute" && ($style->right !== "auto" || $style->bottom !== "auto"); // Absolute positioning measurement if ($needs_reposition) { $orig_style = $this->_frame->get_original_style(); if ($orig_style->width === "auto" && ($orig_style->left === "auto" || $orig_style->right === "auto")) { $width = 0; foreach ($this->_frame->get_line_boxes() as $line) { $width = max($line->w, $width); } $style->width = $width; } $style->left = $orig_style->left; $style->right = $orig_style->right; } $this->_text_align(); $this->vertical_align(); // Absolute positioning if ($needs_reposition) { list($x, $y) = $this->_frame->get_position(); $this->_frame->position(); list($new_x, $new_y) = $this->_frame->get_position(); $this->_frame->move($new_x - $x, $new_y - $y, true); } if ($block && $this->_frame->is_in_flow()) { $block->add_frame_to_line($this->_frame); // May be inline-block if ($style->display === "block") { $block->add_line(); } } }
protected function _layout_line() { $style = $this->_frame->get_style(); $text = $this->_frame->get_text(); $size = $style->font_size; $font = $style->font_family; $word_spacing = $style->length_in_pt($style->word_spacing); $char_spacing = $style->length_in_pt($style->letter_spacing); // Determine the text height $style->height = Font_Metrics::get_font_height($font, $size); $split = false; $add_line = false; // Handle text transform: // http://www.w3.org/TR/CSS21/text.html#propdef-text-transform switch (strtolower($style->text_transform)) { default: break; case "capitalize": $text = mb_convert_case($text, MB_CASE_TITLE); break; case "uppercase": $text = mb_convert_case($text, MB_CASE_UPPER); break; case "lowercase": $text = mb_convert_case($text, MB_CASE_LOWER); break; } // Handle white-space property: // http://www.w3.org/TR/CSS21/text.html#propdef-white-space switch ($style->white_space) { default: case "normal": $this->_frame->set_text($text = $this->_collapse_white_space($text)); if ($text == "") { break; } $split = $this->_line_break($text); break; case "pre": $split = $this->_newline_break($text); $add_line = $split !== false; break; case "nowrap": $this->_frame->set_text($text = $this->_collapse_white_space($text)); break; case "pre-wrap": $split = $this->_newline_break($text); if (($tmp = $this->_line_break($text)) !== false) { $add_line = $split < $tmp; $split = min($tmp, $split); } else { $add_line = true; } break; case "pre-line": // Collapse white-space except for \n $this->_frame->set_text($text = preg_replace("/[ \t]+/u", " ", $text)); if ($text == "") { break; } $split = $this->_newline_break($text); if (($tmp = $this->_line_break($text)) !== false) { $add_line = $split < $tmp; $split = min($tmp, $split); } else { $add_line = true; } break; } // Handle degenerate case if ($text === "") { return; } if ($split !== false) { // Handle edge cases if ($split == 0 && $text === " ") { $this->_frame->set_text(""); return; } if ($split == 0) { // Trim newlines from the beginning of the line //$this->_frame->set_text(ltrim($text, "\n\r")); $this->_block_parent->add_line(); $this->_frame->position(); // Layout the new line $this->_layout_line(); } else { if ($split < mb_strlen($this->_frame->get_text())) { // split the line if required $this->_frame->split_text($split); $t = $this->_frame->get_text(); // Remove any trailing newlines if ($split > 1 && $t[$split - 1] === "\n") { $this->_frame->set_text(mb_substr($t, 0, -1)); } // Do we need to trim spaces on wrapped lines? This might be desired, however, we // can't trim the lines here or the layout will be affected if trimming the line // leaves enough space to fit the next word in the text stream (because pdf layout // is performed elsewhere). /*if (!$this->_frame->get_prev_sibling() && !$this->_frame->get_next_sibling()) { $t = $this->_frame->get_text(); $this->_frame->set_text( trim($t) ); }*/ } } if ($add_line) { $this->_block_parent->add_line(); $this->_frame->position(); } } else { // Remove empty space from start and end of line, but only where there isn't an inline sibling // and the parent node isn't an inline element with siblings // FIXME: Include non-breaking spaces? $t = $this->_frame->get_text(); $parent = $this->_frame->get_parent(); $is_inline_frame = get_class($parent) === 'Inline_Frame_Decorator'; if (!$is_inline_frame && !$this->_frame->get_next_sibling() || $is_inline_frame && !$parent->get_next_sibling()) { $t = rtrim($t); } if (!$is_inline_frame && !$this->_frame->get_prev_sibling() || $is_inline_frame && !$parent->get_prev_sibling()) { $t = ltrim($t); } $this->_frame->set_text($t); } // Set our new width $width = $this->_frame->recalculate_width(); }
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); } }
function reflow(Block_Frame_Decorator $block = null) { $frame = $this->_frame; $page = $frame->get_root(); $page->check_forced_page_break($this->_frame); if ($page->is_full()) { return; } $this->_block_parent = $frame->find_block_parent(); // Left trim the text if this is the first text on the line and we're // collapsing white space // if ( $this->_block_parent->get_current_line()->w == 0 && // ($frame->get_style()->white_space !== "pre" || // $frame->get_style()->white_space !== "pre-wrap") ) { // $frame->set_text( ltrim( $frame->get_text() ) ); // } $frame->position(); $this->_layout_line(); if ($block) { $block->add_frame_to_line($frame); } }
/** * @param Block_Frame_Decorator $block */ function reflow(Block_Frame_Decorator $block = null) { /** * @var Table_Frame_Decorator */ $frame = $this->_frame; // Check if a page break is forced $page = $frame->get_root(); $page->check_forced_page_break($frame); // Bail if the page is full if ($page->is_full()) { return; } // Let the page know that we're reflowing a table so that splits // are suppressed (simply setting page-break-inside: avoid won't // work because we may have an arbitrary number of block elements // inside tds.) $page->table_reflow_start(); // Collapse vertical margins, if required $this->_collapse_margins(); $frame->position(); // Table layout algorithm: // http://www.w3.org/TR/CSS21/tables.html#auto-table-layout if (is_null($this->_state)) { $this->get_min_max_width(); } $cb = $frame->get_containing_block(); $style = $frame->get_style(); // This is slightly inexact, but should be okay. Add half the // border-spacing to the table as padding. The other half is added to // the cells themselves. if ($style->border_collapse === "separate") { list($h, $v) = $style->border_spacing; $v = $style->length_in_pt($v) / 2; $h = $style->length_in_pt($h) / 2; $style->padding_left = $style->length_in_pt($style->padding_left, $cb["w"]) + $h; $style->padding_right = $style->length_in_pt($style->padding_right, $cb["w"]) + $h; $style->padding_top = $style->length_in_pt($style->padding_top, $cb["h"]) + $v; $style->padding_bottom = $style->length_in_pt($style->padding_bottom, $cb["h"]) + $v; } $this->_assign_widths(); // Adjust left & right margins, if they are auto $width = $style->width; $left = $style->margin_left; $right = $style->margin_right; $diff = $cb["w"] - $width; if ($left === "auto" && $right === "auto") { if ($diff < 0) { $left = 0; $right = $diff; } else { $left = $right = $diff / 2; } $style->margin_left = "{$left} pt"; $style->margin_right = "{$right} pt"; } else { if ($left === "auto") { $left = $style->length_in_pt($cb["w"] - $right - $width, $cb["w"]); } if ($right === "auto") { $left = $style->length_in_pt($left, $cb["w"]); } } list($x, $y) = $frame->get_position(); // Determine the content edge $content_x = $x + $left + $style->length_in_pt(array($style->padding_left, $style->border_left_width), $cb["w"]); $content_y = $y + $style->length_in_pt(array($style->margin_top, $style->border_top_width, $style->padding_top), $cb["h"]); if (isset($cb["h"])) { $h = $cb["h"]; } else { $h = null; } $cellmap = $frame->get_cellmap(); $col =& $cellmap->get_column(0); $col["x"] = $content_x; $row =& $cellmap->get_row(0); $row["y"] = $content_y; $cellmap->assign_x_positions(); // Set the containing block of each child & reflow foreach ($frame->get_children() as $child) { // Bail if the page is full if (!$page->in_nested_table() && $page->is_full()) { break; } $child->set_containing_block($content_x, $content_y, $width, $h); $child->reflow(); if (!$page->in_nested_table()) { $page->check_page_break($child); } } // Assign heights to our cells: $style->height = $this->_calculate_height(); if ($style->border_collapse === "collapse") { // Unset our borders because our cells are now using them $style->border_style = "none"; } $page->table_reflow_end(); // Debugging: //echo ($this->_frame->get_cellmap()); if ($block && $style->float === "none" && $frame->is_in_flow()) { $block->add_frame_to_line($frame); $block->add_line(); } }
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_box(); // 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; } $break_word = ($style->word_wrap === "break-word"); // The first word has overflowed. Force it onto the line if ($current_line_width == 0 && $width == 0) { $s = ""; $last_width = 0; if ($break_word) { for ($j = 0; $j < strlen($word); $j++) { $s .= $word[$j]; $_width = Font_Metrics::get_text_width($s, $font, $size, $word_spacing, $char_spacing); if ($_width > $available_width) { break; } $last_width = $_width; } } if ($break_word && $last_width > 0) { $width += $last_width; $str .= substr($s, 0, -1); } else { $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; }