readCSS($pipeline->get_current_css_state()); return $box; } function reflow(&$parent, &$context) { // If frame contains no boxes (for example, the src link is broken) // we just return - no further processing will be done if (count($this->content) == 0) { return; }; // First box contained in a frame should always fill all its height $this->content[0]->put_full_height($this->get_height()); $hc = new HCConstraint(array($this->get_height(), false), array($this->get_height(), false), array($this->get_height(), false)); $this->content[0]->put_height_constraint($hc); $context->push_collapsed_margin(0); $context->push_container_uid($this->uid); $this->reflow_content($context); $context->pop_collapsed_margin(); $context->pop_container_uid(); } /** * Reflow absolutely positioned block box. Note that according to CSS 2.1 * the only types of boxes which could be absolutely positioned are * 'block' and 'table' * * @param FlowContext $context A flow context object containing the additional layout data. * * @link http://www.w3.org/TR/CSS21/visuren.html#dis-pos-flo CSS 2.1: Relationships between 'display', 'position', and 'float' */ function reflow_absolute(&$context) { GenericFormattedBox::reflow($this->parent, $context); $position_strategy =& new StrategyPositionAbsolute(); $position_strategy->apply($this); /** * As sometimes left/right values may not be set, we need to use the "fit" width here. * If box have a width constraint, 'get_max_width' will return constrained value; * othersise, an intrictic width will be returned. * * Note that get_max_width returns width _including_ external space line margins, borders and padding; * as we're setting the "internal" - content width, we must subtract "extra" space width from the * value received * * @see GenericContainerBox::get_max_width() */ $this->put_width($this->get_max_width($context) - $this->_get_hor_extra()); /** * Update the width, as it should be calculated based upon containing block width, not real parent. * After this we should remove width constraints or we may encounter problem * in future when we'll try to call get_..._width functions for this box * * @todo Update the family of get_..._width function so that they would apply constraint * using the containing block width, not "real" parent width */ $wc = $this->get_css_property(CSS_WIDTH); $containing_block =& $this->_get_containing_block(); $this->put_width($wc->apply($this->get_width(), $containing_block['right'] - $containing_block['left'])); $this->setCSSProperty(CSS_WIDTH, new WCNone()); /** * Layout element's children */ $this->reflow_content($context); /** * As absolute-positioned box generated new flow contexy, extend the height to fit all floats */ $this->fitFloats($context); /** * If element have been positioned using 'right' or 'bottom' property, * we need to offset it, as we assumed it had zero width and height at * the moment we placed it */ $right = $this->get_css_property(CSS_RIGHT); $left = $this->get_css_property(CSS_LEFT); if ($left->isAuto() && !$right->isAuto()) { $this->offset(-$this->get_width(), 0); }; $bottom = $this->get_css_property(CSS_BOTTOM); $top = $this->get_css_property(CSS_TOP); if ($top->isAuto() && !$bottom->isAuto()) { $this->offset(0, $this->get_height()); }; } function FrameBox(&$root, &$pipeline) { $css_state =& $pipeline->get_current_css_state(); // Inherit 'border' CSS value from parent (FRAMESET tag), if current FRAME // has no FRAMEBORDER attribute, and FRAMESET has one $parent = $root->parent(); if (!$root->has_attribute('frameborder') && $parent->has_attribute('frameborder')) { $parent_border = $css_state->get_propertyOnLevel(CSS_BORDER, CSS_PROPERTY_LEVEL_PARENT); $css_state->set_property(CSS_BORDER, $parent_border->copy()); } $this->GenericContainerBox($root); // If NO src attribute specified, just return. if (!$root->has_attribute('src')) { return; }; // Determine the fullly qualified URL of the frame content $src = $root->get_attribute('src'); $url = $pipeline->guess_url($src); $data = $pipeline->fetch($url); /** * If framed page could not be fetched return immediately */ if (is_null($data)) { return; }; /** * Render only iframes containing HTML only * * Note that content-type header may contain additional information after the ';' sign */ $content_type = $data->get_additional_data('Content-Type'); $content_type_array = explode(';', $content_type); if ($content_type_array[0] != "text/html") { return; }; $html = $data->get_content(); // Remove control symbols if any $html = preg_replace('/[\x00-\x07]/', "", $html); $converter = Converter::create(); $html = $converter->to_utf8($html, $data->detect_encoding()); $html = html2xhtml($html); $tree = TreeBuilder::build($html); // Save current stylesheet, as each frame may load its own stylesheets // $pipeline->pushCSS(); $css =& $pipeline->get_current_css(); $css->scan_styles($tree, $pipeline); $frame_root = traverse_dom_tree_pdf($tree); $box_child =& create_pdf_box($frame_root, $pipeline); $this->add_child($box_child); // Restore old stylesheet // $pipeline->pop_css(); $pipeline->pop_base_url(); } /** * Note that if both top and bottom are 'auto', box will use vertical coordinate * calculated using guess_corder in 'reflow' method which could be used if this * box had 'position: static' */ function _positionAbsoluteVertically($containing_block) { $bottom = $this->get_css_property(CSS_BOTTOM); $top = $this->get_css_property(CSS_TOP); if (!$top->isAuto()) { if ($top->isPercentage()) { $top_value = ($containing_block['top'] - $containing_block['bottom']) / 100 * $top->getPercentage(); } else { $top_value = $top->getPoints(); }; $this->put_top($containing_block['top'] - $top_value - $this->get_extra_top()); } elseif (!$bottom->isAuto()) { if ($bottom->isPercentage()) { $bottom_value = ($containing_block['top'] - $containing_block['bottom']) / 100 * $bottom->getPercentage(); } else { $bottom_value = $bottom->getPoints(); }; $this->put_top($containing_block['bottom'] + $bottom_value + $this->get_extra_bottom()); }; } /** * Note that if both 'left' and 'right' are 'auto', box will use * horizontal coordinate calculated using guess_corder in 'reflow' * method which could be used if this box had 'position: static' */ function _positionAbsoluteHorizontally($containing_block) { $left = $this->get_css_property(CSS_LEFT); $right = $this->get_css_property(CSS_RIGHT); if (!$left->isAuto()) { if ($left->isPercentage()) { $left_value = ($containing_block['right'] - $containing_block['left']) / 100 * $left->getPercentage(); } else { $left_value = $left->getPoints(); }; $this->put_left($containing_block['left'] + $left_value + $this->get_extra_left()); } elseif (!$right->isAuto()) { if ($right->isPercentage()) { $right_value = ($containing_block['right'] - $containing_block['left']) / 100 * $right->getPercentage(); } else { $right_value = $right->getPoints(); }; $this->put_left($containing_block['right'] - $right_value - $this->get_extra_right()); }; } } class FramesetBox extends GenericContainerBox { var $rows; var $cols; function &create(&$root, &$pipeline) { $box =& new FramesetBox($root, $pipeline); $box->readCSS($pipeline->get_current_css_state()); return $box; } function FramesetBox(&$root, $pipeline) { $this->GenericContainerBox($root); $this->create_content($root, $pipeline); // Now determine the frame layout inside the frameset $this->rows = $root->has_attribute('rows') ? $root->get_attribute('rows') : "100%"; $this->cols = $root->has_attribute('cols') ? $root->get_attribute('cols') : "100%"; } function reflow(&$parent, &$context) { $viewport =& $context->get_viewport(); // Frameset always fill all available space in viewport $this->put_left($viewport->get_left() + $this->get_extra_left()); $this->put_top($viewport->get_top() - $this->get_extra_top()); $this->put_full_width($viewport->get_width()); $this->setCSSProperty(CSS_WIDTH, new WCConstant($viewport->get_width())); $this->put_full_height($viewport->get_height()); $this->put_height_constraint(new WCConstant($viewport->get_height())); // Parse layout-control values $rows = guess_lengths($this->rows, $this->get_height()); $cols = guess_lengths($this->cols, $this->get_width()); // Now reflow all frames in frameset $cur_col = 0; $cur_row = 0; for ($i=0; $i < count($this->content); $i++) { // Had we run out of cols/rows? if ($cur_row >= count($rows)) { // In valid HTML we never should get here, but someone can provide less frame cells // than frames. Extra frames will not be rendered at all return; } $frame =& $this->content[$i]; /** * Depending on the source HTML, FramesetBox may contain some non-frame boxes; * we'll just ignore them */ if (!is_a($frame, "FramesetBox") && !is_a($frame, "FrameBox")) { continue; }; // Guess frame size and position $frame->put_left($this->get_left() + array_sum(array_slice($cols, 0, $cur_col)) + $frame->get_extra_left()); $frame->put_top($this->get_top() - array_sum(array_slice($rows, 0, $cur_row)) - $frame->get_extra_top()); $frame->put_full_width($cols[$cur_col]); $frame->setCSSProperty(CSS_WIDTH, new WCConstant($frame->get_width())); $frame->put_full_height($rows[$cur_row]); $frame->put_height_constraint(new WCConstant($frame->get_height())); // Reflow frame contents $context->push_viewport(FlowViewport::create($frame)); $frame->reflow($this, $context); $context->pop_viewport(); // Move to the next frame position // Next columns $cur_col ++; if ($cur_col >= count($cols)) { // Next row $cur_col = 0; $cur_row ++; } } } } ?>