Blame | Letzte Änderung | Log anzeigen | RSS feed
<?php// $Header: /cvsroot/html2ps/box.container.php,v 1.68 2007/05/06 18:49:29 Konstantin Exp $require_once(HTML2PS_DIR.'strategy.width.min.php');require_once(HTML2PS_DIR.'strategy.width.min.nowrap.php');require_once(HTML2PS_DIR.'strategy.width.max.php');require_once(HTML2PS_DIR.'strategy.width.max.natural.php');/*** @package HTML2PS* @subpackage Document** This file contains the abstract class describing the behavior of document element* containing some other document elements.*//*** @package HTML2PS* @subpackage Document** The GenericContainerBox class is a common superclass for all document elements able* to contain other elements. This class does provide the line-box handling utilies and* some minor float related-functions.**/class GenericContainerBox extends GenericFormattedBox {/*** @var Array A list of contained elements (of type GenericFormattedBox)* @access public*/var $content;var $_first_line;/*** @var Array A list of child nodes in the current line box; changes dynamically* during the reflow process.* @access private*/var $_line;/*** Sometimes floats may appear inside the line box, consider the following code,* for example: "<div>text<div style='float:left'>float</div>word</div>". In* this case, the floating DIV should be rendered below the "text word" line;* thus, we need to keep a list of deferred floating elements and render them* when current line box closes.** @var Array A list of floats which should be flown after current line box ends;* @access private*/var $_deferred_floats;/*** @var float Current output X value inside the current element* @access public*/var $_current_x;/*** @var float Current output Y value inside the current element* @access public*/var $_current_y;function destroy() {for ($i=0, $size = count($this->content); $i < $size; $i++) {$this->content[$i]->destroy();};unset($this->content);parent::destroy();}/*** Render current container box using the specified output method.** @param OutputDriver $driver The output driver object** @return Boolean flag indicating the success or 'null' value in case of critical rendering* error*/function show(&$driver) {GenericFormattedBox::show($driver);$overflow = $this->get_css_property(CSS_OVERFLOW);/*** Sometimes the content may overflow container boxes. This situation arise, for example,* for relative-positioned child boxes, boxes having constrained height and in some* other cases. If the container box does not have CSS 'overflow' property* set to 'visible' value, the content should be visually clipped using container box* padding area.*/if ($overflow !== OVERFLOW_VISIBLE) {$driver->save();$this->_setupClip($driver);};/*** Render child elements*/for ($i=0, $size = count($this->content); $i < $size; $i++) {$child =& $this->content[$i];/*** We'll check the visibility property here* Reason: all boxes (except the top-level one) are contained in some other box,* so every box will pass this check. The alternative is to add this check into every* box class show member.** The only exception of absolute positioned block boxes which are drawn separately;* their show method is called explicitly; the similar check should be performed there*/if ($child->isVisibleInFlow()) {/*** To reduce the drawing overhead, we'll check if some part if current child element* belongs to current output page. If not, there will be no reason to draw this* child this time.** @see OutputDriver::contains()** @todo In rare cases the element content may be placed outside the element itself;* in such situantion content may be visible on the page, while element is not.* This situation should be resolved somehow.*/if ($driver->contains($child)) {if (is_null($child->show($driver))) {return null;};};};}/*** Restore previous clipping mode, if it have been modified for non-'overflow: visible'* box.*/if ($overflow !== OVERFLOW_VISIBLE) {$driver->restore();};return true;}/*** Render current fixed-positioned container box using the specified output method. Unlike* the 'show' method, there's no check if current page viewport contains current element, as* fixed-positioned may be drawn on the page margins, outside the viewport.** @param OutputDriver $driver The output driver object** @return Boolean flag indicating the success or 'null' value in case of critical rendering* error** @see GenericContainerBox::show()** @todo the 'show' and 'show_fixed' method code are almost the same except the child element* method called in the inner loop; also, no check is done if current viewport contains this element,* thus sllowinf printing data on page margins, where no data should be printed normally* I suppose some more generic method containing the common code should be made.*/function show_fixed(&$driver) {GenericFormattedBox::show($driver);$overflow = $this->get_css_property(CSS_OVERFLOW);/*** Sometimes the content may overflow container boxes. This situation arise, for example,* for relative-positioned child boxes, boxes having constrained height and in some* other cases. If the container box does not have CSS 'overflow' property* set to 'visible' value, the content should be visually clipped using container box* padding area.*/if ($overflow !== OVERFLOW_VISIBLE) {// Save graphics state (of course, BEFORE the clipping area will be set)$driver->save();$this->_setupClip($driver);};/*** Render child elements*/$size = count($this->content);for ($i=0; $i < $size; $i++) {/*** We'll check the visibility property here* Reason: all boxes (except the top-level one) are contained in some other box,* so every box will pass this check. The alternative is to add this check into every* box class show member.** The only exception of absolute positioned block boxes which are drawn separately;* their show method is called explicitly; the similar check should be performed there*/$child =& $this->content[$i];if ($child->get_css_property(CSS_VISIBILITY) === VISIBILITY_VISIBLE) {// Fixed-positioned blocks are displayed separately;// If we call them now, they will be drawn twiceif ($child->get_css_property(CSS_POSITION) != POSITION_FIXED) {if (is_null($child->show_fixed($driver))) {return null;};};};}/*** Restore previous clipping mode, if it have been modified for non-'overflow: visible'* box.*/if ($overflow !== OVERFLOW_VISIBLE) {$driver->restore();};return true;}function _find(&$box) {$size = count($this->content);for ($i=0; $i<$size; $i++) {if ($this->content[$i]->uid == $box->uid) {return $i;};}return null;}// Inserts new child box at the specified (zero-based) offset; 0 stands for first child//// @param $index index to insert child at// @param $box child to be inserted//function insert_child($index, &$box) {$box->parent =& $this;// Offset the content arrayfor ($i = count($this->content)-1; $i>= $index; $i--) {$this->content[$i+1] =& $this->content[$i];};$this->content[$index] =& $box;}function insert_before(&$what, &$where) {if ($where) {$index = $this->_find($where);if (is_null($index)) {return null;};$this->insert_child($index, $what);} else {// If 'where' is not specified, 'what' should become the last child$this->add_child($what);};return $what;}function add_child(&$box) {$this->append_child($box);}function append_child(&$box) {// In general, this function is called like following:// $box->add_child(create_pdf_box(...))// As create_pdf_box _may_ return null value (for example, for an empty text node),// we should process the case of $box == null hereif ($box) {$box->parent =& $this;$this->content[] =& $box;};}// Get first child of current box which actually will be drawn// on the page. So, whitespace and null boxes will be ignored//// See description of is_null for null box definition.// (not only NullBox is treated as null box)//// @return reference to the first visible child of current boxfunction &get_first() {$size = count($this->content);for ($i=0; $i<$size; $i++) {if (!is_whitespace($this->content[$i]) &&!$this->content[$i]->is_null()) {return $this->content[$i];};};// We use this construct to avoid notice messages in PHP 4.4 and PHP 5$dummy = null;return $dummy;}// Get first text or image child of current box which actually will be drawn// on the page.//// See description of is_null for null box definition.// (not only NullBox is treated as null box)//// @return reference to the first visible child of current boxfunction &get_first_data() {$size = count($this->content);for ($i=0; $i<$size; $i++) {if (!is_whitespace($this->content[$i]) && !$this->content[$i]->is_null()) {if (is_container($this->content[$i])) {$data =& $this->content[$i]->get_first_data();if (!is_null($data)) { return $data; };} else {return $this->content[$i];};};};// We use this construct to avoid notice messages in PHP 4.4 and PHP 5$dummy = null;return $dummy;}// Get last child of current box which actually will be drawn// on the page. So, whitespace and null boxes will be ignored//// See description of is_null for null box definition.// (not only NullBox is treated as null box)//// @return reference to the last visible child of current boxfunction &get_last() {for ($i=count($this->content)-1; $i>=0; $i--) {if (!is_whitespace($this->content[$i]) && !$this->content[$i]->is_null()) {return $this->content[$i];};};// We use this construct to avoid notice messages in PHP 4.4 and PHP 5$dummy = null;return $dummy;}function offset_if_first(&$box, $dx, $dy) {if ($this->is_first($box)) {// The top-level box (page box) should never be offsetif ($this->parent) {if (!$this->parent->offset_if_first($box, $dx, $dy)) {$this->offset($dx, $dy);return true;};};};return false;}function offset($dx, $dy) {parent::offset($dx, $dy);$this->_current_x += $dx;$this->_current_y += $dy;// Offset contents$size = count($this->content);for ($i=0; $i < $size; $i++) {$this->content[$i]->offset($dx, $dy);}}function GenericContainerBox() {$this->GenericFormattedBox();// By default, box does not have any content$this->content = array();// Initialize line box$this->_line = array();// Initialize floats-related stuff$this->_deferred_floats = array();$this->_additional_text_indent = 0;// Current-point$this->_current_x = 0;$this->_current_y = 0;// Initialize floating children array$this->_floats = array();}function add_deferred_float(&$float) {$this->_deferred_floats[] =& $float;}/*** Create the child nodes of current container object using the parsed HTML data** @param mixed $root node corresponding to the current container object*/function create_content(&$root, &$pipeline) {// Initialize content$child = $root->first_child();while ($child) {$box_child =& create_pdf_box($child, $pipeline);$this->add_child($box_child);$child = $child->next_sibling();};}// Content-handling functionsfunction is_container() {return true;}function get_content() {return join('', array_map(array($this, 'get_content_callback'), $this->content));}function get_content_callback(&$node) {return $node->get_content();}// Get total height of this box content (including floats, if any)// Note that floats can be contained inside children, so we'll need to use// this function recusivelyfunction get_real_full_height() {$content_size = count($this->content);$overflow = $this->get_css_property(CSS_OVERFLOW);// Treat items with overflow: hidden specifically,// as floats flown out of this boxes will not be visibleif ($overflow == OVERFLOW_HIDDEN) {return $this->get_full_height();};// Check if this object is totally empty$first = $this->get_first();if (is_null($first)) {return 0;};// Initialize the vertical extent taken by content using the// very first child$max_top = $first->get_top_margin();$min_bottom = $first->get_bottom_margin();for ($i=0; $i<$content_size; $i++) {if (!$this->content[$i]->is_null()) {// Check if top margin of current child is to the up// of vertical extent top margin$max_top = max($max_top, $this->content[$i]->get_top_margin());/*** Check if current child bottom margin will extend* the vertical space OR if it contains floats extending* this, unless this child have overflow: hidden, because this* will prevent additional content to be visible*/if (!$this->content[$i]->is_container()) {$min_bottom = min($min_bottom,$this->content[$i]->get_bottom_margin());} else {$content_overflow = $this->content[$i]->get_css_property(CSS_OVERFLOW);if ($content_overflow == OVERFLOW_HIDDEN) {$min_bottom = min($min_bottom,$this->content[$i]->get_bottom_margin());} else {$min_bottom = min($min_bottom,$this->content[$i]->get_bottom_margin(),$this->content[$i]->get_top_margin() -$this->content[$i]->get_real_full_height());};};};}return max(0, $max_top - $min_bottom) + $this->_get_vert_extra();}// LINE-LENGTH RELATED FUNCTIONSfunction _line_length() {$sum = 0;$size = count($this->_line);for ($i=0; $i < $size; $i++) {// Note that the line length should include the inline boxes margin/padding// as inline boxes are not directly included to the parent line box,// we'll need to check the parent of current line box element,// and, if it is an inline box, AND this element is last or first contained element// add correcponsing padding value$element =& $this->_line[$i];if (isset($element->wrapped) && !is_null($element->wrapped)) {if ($i==0) {$sum += $element->get_full_width() - $element->getWrappedWidth();} else {$sum += $element->getWrappedWidthAndHyphen();};} else {$sum += $element->get_full_width();};if ($element->parent) {$first = $element->parent->get_first();$last = $element->parent->get_last();if (!is_null($first) && $first->uid === $element->uid) {$sum += $element->parent->get_extra_line_left();}if (!is_null($last) && $last->uid === $element->uid) {$sum += $element->parent->get_extra_line_right();}};}if ($this->_first_line) {$ti = $this->get_css_property(CSS_TEXT_INDENT);$sum += $ti->calculate($this);$sum += $this->_additional_text_indent;};return $sum;}function _line_length_delta(&$context) {return max($this->get_available_width($context) - $this->_line_length(),0);}/*** Get the last box in current line box*/function &last_in_line() {$size = count($this->_line);if ($size < 1) {$dummy = null;return $dummy;};return $this->_line[$size-1];}// WIDTHfunction get_min_width_natural(&$context) {$content_size = count($this->content);/*** If box does not have any context, its minimal width is determined by extra horizontal space:* padding, border width and margins*/if ($content_size == 0) {$min_width = $this->_get_hor_extra();return $min_width;};/*** If we're in 'nowrap' mode, minimal and maximal width will be equal*/$white_space = $this->get_css_property(CSS_WHITE_SPACE);$pseudo_nowrap = $this->get_css_property(CSS_HTML2PS_NOWRAP);if ($white_space == WHITESPACE_NOWRAP ||$pseudo_nowrap == NOWRAP_NOWRAP) {$min_width = $this->get_min_nowrap_width($context);return $min_width;}/*** We need to add text indent size to the width of the first item*/$start_index = 0;while ($start_index < $content_size &&$this->content[$start_index]->out_of_flow()) {$start_index++;};if ($start_index < $content_size) {$ti = $this->get_css_property(CSS_TEXT_INDENT);$minw =$ti->calculate($this) +$this->content[$start_index]->get_min_width_natural($context);} else {$minw = 0;};for ($i=$start_index; $i<$content_size; $i++) {$item =& $this->content[$i];if (!$item->out_of_flow()) {$minw = max($minw, $item->get_min_width($context));};}/*** Apply width constraint to min width. Return maximal value*/$wc = $this->get_css_property(CSS_WIDTH);$containing_block =& $this->_get_containing_block();$min_width = $minw;return $min_width;}function get_min_width(&$context) {$strategy = new StrategyWidthMin();return $strategy->apply($this, $context);}function get_min_nowrap_width(&$context) {$strategy = new StrategyWidthMinNowrap();return $strategy->apply($this, $context);}// Note: <table width="100%" inside some block box cause this box to expand// $limit - maximal width which should not be exceeded; by default, there's no limit at all//function get_max_width_natural(&$context, $limit=10E6) {$strategy = new StrategyWidthMaxNatural($limit);return $strategy->apply($this, $context);}function get_max_width(&$context, $limit=10E6) {$strategy = new StrategyWidthMax($limit);return $strategy->apply($this, $context);}function close_line(&$context, $lastline = false) {// Align line-box using 'text-align' property$size = count($this->_line);if ($size > 0) {$last_item =& $this->_line[$size-1];if (is_whitespace($last_item)) {$last_item->width = 0;$last_item->height = 0;};};// Note that text-align should not be applied to the block boxes!// As block boxes will be alone in the line-box, we can check// if the very first box in the line is inline; if not - no justification should be made//if ($size > 0) {if (is_inline($this->_line[0])) {$cb = CSSTextAlign::value2pdf($this->get_css_property(CSS_TEXT_ALIGN));$cb($this, $context, $lastline);} else {// Nevertheless, CENTER tag and P/DIV with ALIGN attribute set should affect the// position of non-inline children.$cb = CSSPseudoAlign::value2pdf($this->get_css_property(CSS_HTML2PS_ALIGN));$cb($this, $context, $lastline);};};// Apply vertical align to all of the line content// first, we need to aling all baseline-aligned boxes to determine the basic line-box height, top and bottom edges// then, SUP and SUP positioned boxes (as they can extend the top and bottom edges, but not affected themselves)// then, MIDDLE, BOTTOM and TOP positioned boxes in the given order//$baselined = array();$baseline = 0;$height = 0;for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_BASELINE) {// Add current baseline-aligned item to the baseline//$baselined[] =& $this->_line[$i];$baseline = max($baseline,$this->_line[$i]->default_baseline);};};$size_baselined = count($baselined);for ($i=0; $i < $size_baselined; $i++) {$baselined[$i]->baseline = $baseline;$height = max($height,$baselined[$i]->get_full_height() + $baselined[$i]->getBaselineOffset(),$baselined[$i]->get_ascender() + $baselined[$i]->get_descender());};// SUB vertical align//for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_SUB) {$this->_line[$i]->baseline =$baseline + $this->_line[$i]->get_full_height()/2;};}// SUPER vertical align//for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_SUPER) {$this->_line[$i]->baseline = $this->_line[$i]->get_full_height()/2;};}// MIDDLE vertical align//$middle = 0;for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_MIDDLE) {$middle = max($middle, $this->_line[$i]->get_full_height() / 2);};};if ($middle * 2 > $height) {// Offset already aligned items//for ($i=0; $i < $size; $i++) {$this->_line[$i]->baseline += ($middle - $height/2);};$height = $middle * 2;};for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_MIDDLE) {$this->_line[$i]->baseline = $this->_line[$i]->default_baseline + ($height/2 - $this->_line[$i]->get_full_height()/2);};}// BOTTOM vertical align//$bottom = 0;for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_BOTTOM) {$bottom = max($bottom, $this->_line[$i]->get_full_height());};};if ($bottom > $height) {// Offset already aligned items//for ($i=0; $i < $size; $i++) {$this->_line[$i]->baseline += ($bottom - $height);};$height = $bottom;};for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_BOTTOM) {$this->_line[$i]->baseline = $this->_line[$i]->default_baseline + $height - $this->_line[$i]->get_full_height();};}// TOP vertical align//$bottom = 0;for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_TOP) {$bottom = max($bottom, $this->_line[$i]->get_full_height());};};if ($bottom > $height) {$height = $bottom;};for ($i=0; $i < $size; $i++) {$vertical_align = $this->_line[$i]->get_css_property(CSS_VERTICAL_ALIGN);if ($vertical_align == VA_TOP) {$this->_line[$i]->baseline = $this->_line[$i]->default_baseline;};}// Calculate the bottom Y coordinate of last line box//$line_bottom = $this->_current_y;foreach ($this->_line AS $line_element) {// This line is required; say, we have sequence of text and image inside the container,// AND image have greater baseline than text; in out case, text will be offset to the bottom// of the page and we lose the gap between text and container bottom edge, unless we'll re-extend// containier height// Note that we're using the colapsed margin value to get the Y coordinate to extend height to,// as bottom margin may be collapsed with parent$effective_bottom =$line_element->get_top() -$line_element->get_height() -$line_element->get_extra_bottom();$this->extend_height($effective_bottom);$line_bottom = min($effective_bottom, $line_bottom);}$this->extend_height($line_bottom);// Clear the line box$this->_line = array();// Reset current X coordinate to the far left$this->_current_x = $this->get_left();// Extend Y coordinate$this->_current_y = $line_bottom;// Render the deferred floatsfor ($i = 0, $size = count($this->_deferred_floats); $i < $size; $i++) {$this->_deferred_floats[$i]->reflow_static_float($this, $context);};// Clear deferred float list$this->_deferred_floats = array();// modify the current-x value, so that next inline box will not intersect any floating boxes$this->_current_x = $context->float_left_x($this->_current_x, $this->_current_y);$this->_first_line = false;}function append_line(&$item) {$this->_line[] =& $item;}// Line box should be treated as empty in following cases:// 1. It is really empty (so, it contains 0 boxes)// 2. It contains only whitespace boxesfunction line_box_empty() {$size = count($this->_line);if ($size == 0) { return true; }// Scan line boxfor ($i=0; $i<$size; $i++) {if (!is_whitespace($this->_line[$i]) &&!$this->_line[$i]->is_null()) { return false; };}// No non-whitespace boxes were foundreturn true;}function reflow_anchors(&$viewport, &$anchors, $page_heights) {GenericFormattedBox::reflow_anchors($viewport, $anchors, $page_heights);$size = count($this->content);for ($i=0; $i<$size; $i++) {$this->content[$i]->reflow_anchors($viewport, $anchors, $page_heights);}}function fitFloats(&$context) {$float_bottom = $context->float_bottom();if (!is_null($float_bottom)) {$this->extend_height($float_bottom);};$float_right = $context->float_right();if (!is_null($float_right)) {$this->extend_width($float_right);};}function reflow_content(&$context) {$text_indent = $this->get_css_property(CSS_TEXT_INDENT);$this->close_line($context);$this->_first_line = true;// If first child is inline - apply text-indent$first = $this->get_first();if (!is_null($first)) {if (is_inline($first)) {$this->_current_x += $text_indent->calculate($this);$this->_current_x += $this->_additional_text_indent;};};$this->height = 0;// Reset current Y value$this->_current_y = $this->get_top();$size = count($this->content);for ($i=0; $i < $size; $i++) {$child =& $this->content[$i];$child->reflow($this, $context);};$this->close_line($context, true);}function reflow_inline() {$size = count($this->content);for ($i=0; $i<$size; $i++) {$this->content[$i]->reflow_inline();};}function reflow_text(&$viewport) {$size = count($this->content);for ($i=0; $i<$size; $i++) {if (is_null($this->content[$i]->reflow_text($viewport))) {return null;};}return true;}/*** Position/size current box as floating one*/function reflow_static_float(&$parent, &$context) {// Defer the float rendering till the next line boxif (!$parent->line_box_empty()) {$parent->add_deferred_float($this);return;};// Calculate margin values if they have been set as a percentage$this->_calc_percentage_margins($parent);$this->_calc_percentage_padding($parent);// Calculate width value if it have been set as a percentage$this->_calc_percentage_width($parent, $context);// Calculate margins and/or width is 'auto' values have been specified$this->_calc_auto_width_margins($parent);// Determine the actual width of the floating box// Note that get_max_width returns both content and extra width$this->put_full_width($this->get_max_width_natural($context, $this->parent->get_width()));// We need to call this function before determining the horizontal coordinate// as after vertical offset the additional space to the left may apperar$y = $this->apply_clear($parent->_current_y, $context);// determine the position of top-left floating box cornerif ($this->get_css_property(CSS_FLOAT) === FLOAT_RIGHT) {$context->float_right_xy($parent, $this->get_full_width(), $x, $y);$x -= $this->get_full_width();} else {$context->float_left_xy($parent, $this->get_full_width(), $x, $y);};// Note that $x and $y contain just a free space corner coordinate;// If our float has a margin/padding space, we'll need to offset ot a little;// Remember that float margins are never collapsed!$this->moveto($x + $this->get_extra_left(), $y - $this->get_extra_top());// Reflow contents.// Note that floating box creates a new float flow context for it children.$context->push_floats();// Floating box create a separate margin collapsing context$context->push_collapsed_margin(0);$this->reflow_content($context);$context->pop_collapsed_margin();// Floats and boxes with overflow: hidden// should completely enclose its child floats$this->fitFloats($context);// restore old float flow context$context->pop_floats();// Add this box to the list of floats in current context$context->add_float($this);// Now fix the value of _current_x for the parent box; it is required// in the following case:// <body><img align="left">some text// in such situation floating image is flown immediately, but it the close_line call have been made before,// so _current_x value of container box will be still equal to ots left content edge; by calling float_left_x again,// we'll force "some text" to be offset to the right$parent->_current_x = $context->float_left_x($parent->_current_x, $parent->_current_y);}function reflow_whitespace(&$linebox_started, &$previous_whitespace) {$previous_whitespace = false;$linebox_started = false;$size = count($this->content);for ($i=0; $i<$size; $i++) {$child =& $this->content[$i];$child->reflow_whitespace($linebox_started, $previous_whitespace);};// remove the last whitespace in block box$this->remove_last_whitespace();// Non-inline box have terminated; we may be sure that line box will be closed// at this moment and new line box after this will be generatedif (!is_inline($this)) {$linebox_started = false;};return;}function remove_last_whitespace() {if (count($this->content) == 0) {return;};$i = count($this->content)-1;$last = $this->content[$i];while ($i >= 0 && is_whitespace($this->content[$i])) {$this->remove($this->content[$i]);$i --;if ($i >= 0) {$last = $this->content[$i];};};if ($i >= 0) {if (is_container($this->content[$i])) {$this->content[$i]->remove_last_whitespace();};};}function remove(&$box) {$size = count($this->content);for ($i=0; $i<$size; $i++) {if ($this->content[$i]->uid === $box->uid) {$this->content[$i] = NullBox::create();};};return;}function is_first(&$box) {$first =& $this->get_first();// Check if there's no first box at all//if (is_null($first)) { return false; };return $first->uid == $box->uid;}function is_null() {$size = count($this->content);for ($i=0; $i<$size; $i++) {if (!$this->content[$i]->is_null()) { return false; };};return true;}// Calculate the available widths - e.g. content width minus space occupied by floats;// as floats may not fill the whole height of this box, this value depends on Y-coordinate.// We use current_Y in calculations//function get_available_width(&$context) {$left_float_width = $context->float_left_x($this->get_left(), $this->_current_y) - $this->get_left();$right_float_width = $this->get_right() - $context->float_right_x($this->get_right(), $this->_current_y);return $this->get_width() - $left_float_width - $right_float_width;}function pre_reflow_images() {$size = count($this->content);for ($i=0; $i<$size; $i++) {$this->content[$i]->pre_reflow_images();};}function _setupClip(&$driver) {if (!is_null($this->parent)) {$this->parent->_setupClip($driver);};$overflow = $this->get_css_property(CSS_OVERFLOW);if ($overflow !== OVERFLOW_VISIBLE && !$GLOBALS['g_config']['debugnoclip']) {$driver->moveto( $this->get_left_border() , $this->get_top_border());$driver->lineto( $this->get_right_border(), $this->get_top_border());$driver->lineto( $this->get_right_border(), $this->get_bottom_border());$driver->lineto( $this->get_left_border() , $this->get_bottom_border());$driver->closepath();$driver->clip();};}/*** DOMish functions*/function &get_element_by_id($id) {if (isset($GLOBALS['__html_box_id_map'])) {return $GLOBALS['__html_box_id_map'][$id];} else {$dummy = null;return $dummy;};}/** this is just a fake at the moment*/function get_body() {return $this;}function getChildNodes() {return $this->content;}}?>