_cache = array();
$this->_css = array();
$this->_cached_base_font_size = null;
$this->_left = 0;
$this->_top = 0;
$this->_parent = null;
$this->baseline = 0;
$this->default_baseline = 0;
$this->set_tagname(null);
/**
* Assign an unique box identifier
*/
$GLOBALS['g_box_uid']++;
$this->uid = $GLOBALS['g_box_uid'];
$this->_id = null;
}
function destroy() {
unset($this->_cache);
unset($this->_css);
unset($this->_left);
unset($this->_top);
unset($this->_parent);
unset($this->baseline);
unset($this->default_baseline);
}
/**
* see get_property for optimization description
*/
function setCSSProperty($code, $value) {
static $cache = array();
if (!isset($cache[$code])) {
$cache[$code] =& CSS::get_handler($code);
};
$cache[$code]->replace_array($value, $this->_css);
}
/**
* Optimization: this function is called very often,
* so even a slight overhead for CSS::get_handler call
* accumulates in a significiant processing delay.
*/
function &get_css_property($code) {
static $cache = array();
if (!isset($cache[$code])) {
$cache[$code] =& CSS::get_handler($code);
};
$value =& $cache[$code]->get($this->_css);
return $value;
}
function get_tagname() {
return $this->_tagname;
}
function set_tagname($tagname) {
$this->_tagname = $tagname;
}
function get_content() {
return '';
}
function show_postponed(&$driver) {
$this->show($driver);
}
function copy_style(&$box) {
// TODO: object references
$this->_css = $box->_css;
}
/**
* Optimization: _readCSSLength is usually called several times
* while initializing box object. $base_font_size cound be calculated
* only once and stored in a static variable.
*/
function _readCSSLengths($state, $property_list) {
if (is_null($this->_cached_base_font_size)) {
$font =& $this->get_css_property(CSS_FONT);
$this->_cached_base_font_size = $font->size->getPoints();
};
foreach ($property_list as $property) {
$value =& $state->get_property($property);
if ($value === CSS_PROPERTY_INHERIT) {
$value =& $state->getInheritedProperty($property);
};
if (is_object($value)) {
$value =& $value->copy();
$value->doInherit($state);
$value->units2pt($this->_cached_base_font_size);
};
$this->setCSSProperty($property, $value);
}
}
function _readCSS($state, $property_list) {
foreach ($property_list as $property) {
$value = $state->get_property($property);
// Note that order is important; composite object-value could be inherited and
// object itself could contain subvalues with 'inherit' value
if ($value === CSS_PROPERTY_INHERIT) {
$value = $state->getInheritedProperty($property);
};
if (is_object($value)) {
$value = $value->copy();
$value->doInherit($state);
};
$this->setCSSProperty($property, $value);
}
}
function readCSS(&$state) {
/**
* Determine font size to be used in this box (required for em/ex units)
*/
$value = $state->get_property(CSS_FONT);
if ($value === CSS_PROPERTY_INHERIT) {
$value = $state->getInheritedProperty(CSS_FONT);
};
$base_font_size = $state->getBaseFontSize();
if (is_object($value)) {
$value = $value->copy();
$value->doInherit($state);
$value->units2pt($base_font_size);
};
$this->setCSSProperty(CSS_FONT, $value);
/**
* Continue working with other properties
*/
$this->_readCSS($state,
array(CSS_COLOR,
CSS_DISPLAY,
CSS_VISIBILITY));
$this->_readCSSLengths($state,
array(CSS_VERTICAL_ALIGN));
// '-html2ps-link-destination'
global $g_config;
if ($g_config["renderlinks"]) {
$this->_readCSS($state,
array(CSS_HTML2PS_LINK_DESTINATION));
};
// Save ID attribute value
$id = $state->get_property(CSS_HTML2PS_LINK_DESTINATION);
if (!is_null($id)) {
$this->set_id($id);
};
}
function set_id($id) {
$this->_id = $id;
if (!isset($GLOBALS['__html_box_id_map'][$id])) {
$GLOBALS['__html_box_id_map'][$id] =& $this;
};
}
function get_id() {
return $this->_id;
}
function show(&$driver) {
// If debugging mode is on, draw the box outline
global $g_config;
if ($g_config['debugbox']) {
// Copy the border object of current box
$driver->setlinewidth(0.1);
$driver->setrgbcolor(0,0,0);
$driver->rect($this->get_left(), $this->get_top(), $this->get_width(), -$this->get_height());
$driver->stroke();
}
// Set current text color
// Note that text color is used not only for text drawing (for example, list item markers
// are drawn with text color)
$color = $this->get_css_property(CSS_COLOR);
$color->apply($driver);
}
/**
* Render box having position: fixed or contained in such box
* (Default behaviour)
*/
function show_fixed(&$driver) {
return $this->show($driver);
}
function pre_reflow_images() {}
function set_top($value) {
$this->_top = $value;
}
function set_left($value) {
$this->_left = $value;
}
function offset($dx, $dy) {
$this->_left += $dx;
$this->_top += $dy;
}
// Calculate the content upper-left corner position in curent flow
function guess_corner(&$parent) {
$this->put_left($parent->_current_x + $this->get_extra_left());
$this->put_top($parent->_current_y - $this->get_extra_top());
}
function put_left($value) {
$this->_left = $value;
}
function put_top($value) {
$this->_top = $value + $this->getBaselineOffset();
}
/**
* Get Y coordinate of the top content area edge
*/
function get_top() {
return
$this->_top -
$this->getBaselineOffset();
}
function get_right() {
return $this->get_left() + $this->get_width();
}
function get_left() {
return $this->_left;
}
function get_bottom() {
return $this->get_top() - $this->get_height();
}
function getBaselineOffset() {
return $this->baseline - $this->default_baseline;
}
function &make_anchor(&$media, $link_destination, $page_heights) {
$page_index = 0;
$pages_count = count($page_heights);
$bottom = mm2pt($media->height() - $media->margins['top']);
do {
$bottom -= $page_heights[$page_index];
$page_index ++;
} while ($this->get_top() < $bottom && $page_index < $pages_count);
/**
* Now let's calculate the coordinates on this particular page
*
* X coordinate calculation is pretty straightforward (and, actually, unused, as it would be
* a bad idea to scroll PDF horiaontally).
*/
$x = $this->get_left();
/**
* Y coordinate should be calculated relatively to the bottom page edge
*/
$y = ($this->get_top() - $bottom) + (mm2pt($media->real_height()) - $page_heights[$page_index-1]) + mm2pt($media->margins['bottom']);
$anchor =& new Anchor($link_destination,
$page_index,
$x,
$y);
return $anchor;
}
function reflow_anchors(&$driver, &$anchors, $page_heights) {
if ($this->is_null()) {
return;
};
$link_destination = $this->get_css_property(CSS_HTML2PS_LINK_DESTINATION);
if (!is_null($link_destination)) {
$anchors[$link_destination] =& $this->make_anchor($driver->media, $link_destination, $page_heights);
};
}
function reflow(&$parent, &$context) {}
function reflow_inline() { }
function out_of_flow() {
return false;
}
function get_bottom_margin() { return $this->get_bottom(); }
function get_top_margin() {
return $this->get_top();
}
function get_full_height() { return $this->get_height(); }
function get_width() { return $this->width; }
function get_full_width() {
return $this->width;
}
function get_height() {
return $this->height;
}
function get_baseline() {
return $this->baseline;
}
function is_container() { return false; }
function isVisibleInFlow() { return true; }
function reflow_text() { return true; }
/**
* Note that linebox is started by any non-whitespace inline element; all whitespace elements before
* that moment should be ignored.
*
* @param boolean $linebox_started Flag indicating that a new line box have just started and it already contains
* some inline elements
* @param boolean $previous_whitespace Flag indicating that a previous inline element was an whitespace element.
*/
function reflow_whitespace(&$linebox_started, &$previous_whitespace) {
return;
}
function is_null() {
return false;
}
function isCell() {
return false;
}
function isTableRow() {
return false;
}
function isTableSection() {
return false;
}
// CSS 2.1:
// 9.2.1 Block-level elements and block boxes
// Block-level elements are those elements of the source document that are formatted visually as blocks
// (e.g., paragraphs). Several values of the 'display' property make an element block-level:
// 'block', 'list-item', 'compact' and 'run-in' (part of the time; see compact and run-in boxes), and 'table'.
//
function isBlockLevel() {
return false;
}
function hasAbsolutePositionedParent() {
if (is_null($this->parent)) {
return false;
};
return
$this->parent->get_css_property(CSS_POSITION) == POSITION_ABSOLUTE ||
$this->parent->hasAbsolutePositionedParent();
}
function hasFixedPositionedParent() {
if (is_null($this->parent)) {
return false;
};
return
$this->parent->get_css_property(CSS_POSITION) == POSITION_FIXED ||
$this->parent->hasFixedPositionedParent();
}
/**
* Box can be expanded if it has no width constrains and
* all it parents has no width constraints
*/
function mayBeExpanded() {
$wc = $this->get_css_property(CSS_WIDTH);
if (!$wc->isNull()) { return false; };
if ($this->get_css_property(CSS_FLOAT) <> FLOAT_NONE) {
return true;
};
if ($this->get_css_property(CSS_POSITION) <> POSITION_STATIC &&
$this->get_css_property(CSS_POSITION) <> POSITION_RELATIVE) {
return true;
};
if (is_null($this->parent)) {
return true;
};
return $this->parent->mayBeExpanded();
}
function isLineBreak() {
return false;
}
function get_min_width_natural($context) {
return $this->get_min_width($context);
}
function is_note_call() {
return isset($this->note_call);
}
/* DOM compatibility */
function &get_parent_node() {
return $this->parent;
}
}
?>