function testPagebreakBorderTestNoBorder()
    {
        $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
        $tree = $this->runPipeline('
<html>
<head>
<style type="text/css">
body   { font-size: 10pt; line-height: 1; orphans:0; widows: 0; padding: 0; margin: 0; }
#first { line-height: 1; height: 180pt; }
#second { width: 3em; }
</style>
</head>
<body>
<div id="first">&nbsp;</div>
<div id="second">
LINE1<!--Page break should be here-->
LINE2
LINE3
LINE4
LINE5
</div>
</body>
</html>
', $media);
        /**
         * Calculate page heights
         */
        $page_heights = PageBreakLocator::getPages($tree, mm2pt($media->real_height()), mm2pt($media->height() - $media->margins['top']));
        $first_div = $tree->get_element_by_id('first');
        $second_div = $tree->get_element_by_id('second');
        $this->assertEqual(count($page_heights), 2, sprintf("Two pages expected, got %s", count($page_heights)));
        $this->assertEqual($page_heights[0], $first_div->get_full_height() + pt2pt(20));
    }
    function testPagebreakTable2()
    {
        $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
        $tree = $this->runPipeline('
<html>
<head>
body   { font-size: 10pt; line-height: 1; padding: 0; margin: 0; }
table  { line-height: 1; }
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0" id="table">
<tr><td id="cell">TEXT1_1<br/>TEXT1_2</td></tr>
</table>
</body>
</html>
', $media);
        $locations = PageBreakLocator::_getBreakLocations($tree);
        $table = $tree->get_element_by_id('table');
        $cell = $tree->get_element_by_id('cell');
        $line1 = $cell->content[0]->getLineBox(0);
        $this->assertEqual(count($locations), 3, "Testing number of page breaks inside a table with one cell & several text lines inside [%s]");
        $this->assertEqual($locations[0]->location, $table->get_top_margin(), "First page break should be at the table top [%s]");
        $this->assertEqual($locations[1]->location, $line1->bottom, "Second page break should be at the bottom of the first line box in the table cell [%s]");
        $this->assertEqual($locations[2]->location, $table->get_bottom_margin(), "Last page break should be at the table bottom [%s]");
    }
Example #3
0
 function init()
 {
     // Include the class file and create Html2ps instance
     App::import('vendor', 'Html2PsConfig', array('file' => 'html2ps' . DS . 'config.inc.php'));
     App::import('vendor', 'Html2Ps', array('file' => 'html2ps' . DS . 'pipeline.factory.class.php'));
     parse_config_file(APP . 'vendors' . DS . 'html2ps' . DS . 'html2ps.config');
     global $g_config;
     $g_config = array('cssmedia' => 'screen', 'renderimages' => true, 'renderforms' => false, 'renderlinks' => true, 'mode' => 'html', 'debugbox' => false, 'draw_page_border' => false);
     $this->media = Media::predefined('A4');
     $this->media->set_landscape(false);
     $this->media->set_margins(array('left' => 0, 'right' => 0, 'top' => 0, 'bottom' => 0));
     $this->media->set_pixels(1024);
     global $g_px_scale;
     $g_px_scale = mm2pt($this->media->width() - $this->media->margins['left'] - $this->media->margins['right']) / $this->media->pixels;
     global $g_pt_scale;
     $g_pt_scale = $g_pt_scale * 1.43;
     $this->p = PipelineFactory::create_default_pipeline("", "");
     switch ($this->output) {
         case 'download':
             $this->p->destination = new DestinationDownload($this->filename);
             break;
         case 'file':
             $this->p->destination = new DestinationFile($this->filename);
             break;
         default:
             $this->p->destination = new DestinationBrowser($this->filename);
             break;
     }
 }
 function reflow(&$media)
 {
     $this->put_left(mm2pt($media->margins['left']));
     $this->put_top(mm2pt($media->height() - $media->margins['top']));
     $this->put_width(mm2pt($media->real_width()));
     $this->put_height(mm2pt($media->real_height()));
 }
 function testWidthAbsolutePositioned1()
 {
     $media = null;
     $pipeline = null;
     $tree = $this->runPipeline(file_get_contents('test.width.absolute.positioned.1.html'), $media, $pipeline);
     $font_size = $tree->getCSSProperty(CSS_FONT_SIZE);
     $base = $font_size->getPoints();
     $element =& $tree->get_element_by_id('div1');
     $this->assertWithinMargin($element->get_width(), $pipeline->output_driver->stringwidth('No positioning data at all', 'Times-Roman', 'iso-8859-1', $base), 0);
     $element =& $tree->get_element_by_id('div2');
     $this->assertWithinMargin($element->get_width(), $pipeline->output_driver->stringwidth('Left', 'Times-Roman', 'iso-8859-1', $base), 0);
     $element =& $tree->get_element_by_id('div3');
     $this->assertEqual($element->get_width(), mm2pt($media->real_width()) - px2pt(200));
     $element =& $tree->get_element_by_id('div4');
     $this->assertEqual($element->get_width(), px2pt(100));
     $element =& $tree->get_element_by_id('div5');
     $this->assertEqual($element->get_width(), px2pt(100));
     $element =& $tree->get_element_by_id('div6');
     $this->assertEqual($element->get_width(), px2pt(100));
     $element =& $tree->get_element_by_id('div7');
     $this->assertEqual($element->get_width(), px2pt(100));
     $element =& $tree->get_element_by_id('div8');
     $this->assertWithinMargin($element->get_width(), $pipeline->output_driver->stringwidth('Right', 'Times-Roman', 'iso-8859-1', $base), 0);
     $element =& $tree->get_element_by_id('div9');
     $this->assertEqual($element->get_width(), mm2pt($media->real_width()) - px2pt(100), 'DIV with long text and "left" property has incorrect width [%s]');
     $element =& $tree->get_element_by_id('div10');
     $this->assertEqual($element->get_width(), mm2pt($media->real_width()) - px2pt(100), 'DIV with long text and "right" property has incorrect width [%s]');
     $element =& $tree->get_element_by_id('div11');
     $this->assertEqual($element->get_width(), mm2pt($media->real_width()), 'DIV with long text and no positioning properties has incorrect width [%s]');
     $element =& $tree->get_element_by_id('div12');
     $this->assertEqual($element->get_width(), mm2pt($media->real_width()) - px2pt(200), 'DIV with long text and both "left" and "right" properties has incorrect width [%s]');
 }
Example #6
0
 function parse($value)
 {
     if ($value == '') {
         return null;
     }
     // First attempt to create media with predefined name
     if (preg_match('/^(\\w+)(?:\\s+(portrait|landscape))?$/', $value, $matches)) {
         $name = $matches[1];
         $landscape = isset($matches[2]) && $matches[2] == 'landscape';
         $media =& Media::predefined($name);
         if (is_null($media)) {
             return null;
         }
         return array('size' => array('width' => $media->get_width(), 'height' => $media->get_height()), 'landscape' => $landscape);
     }
     // Second, attempt to create media with predefined size
     $parts = preg_split('/\\s+/', $value);
     $width_str = $parts[0];
     $height_str = isset($parts[1]) ? $parts[1] : $parts[0];
     $width = units2pt($width_str);
     $height = units2pt($height_str);
     if ($width == 0 || $height == 0) {
         return null;
     }
     return array('size' => array('width' => $width / mm2pt(1) / pt2pt(1), 'height' => $height / mm2pt(1) / pt2pt(1)), 'landscape' => false);
 }
function units2pt($value, $font_size = null)
{
    $unit = Value::unit_from_string($value);
    switch ($unit) {
        case UNIT_PT:
            return pt2pt((double) $value);
        case UNIT_PX:
            return px2pt((double) $value);
        case UNIT_MM:
            return pt2pt(mm2pt((double) $value));
        case UNIT_CM:
            return pt2pt(mm2pt((double) $value * 10));
        case UNIT_EM:
            return em2pt((double) $value, $font_size);
        case UNIT_EX:
            return ex2pt((double) $value, $font_size);
        case UNIT_IN:
            return pt2pt((double) $value * 72);
            // points used by CSS 2.1 are equal to 1/72nd of an inch.
        // points used by CSS 2.1 are equal to 1/72nd of an inch.
        case UNIT_PC:
            return pt2pt((double) $value * 12);
            // 1 pica equals to 12 points.
        // 1 pica equals to 12 points.
        default:
            global $g_config;
            if ($g_config['mode'] === 'quirks') {
                return px2pt((double) $value);
            } else {
                return 0;
            }
    }
}
    function TestContainingBlockAbsolute1()
    {
        $tree = $this->runPipeline('
<style type="text/css">
#container {
  padding: 10mm;
  margin: 50mm;
  position: relative;
  top: 0;
  left: 0;
}

#block {
  position: absolute;
  top: 3mm;
  left: 2mm;
  margin: 7mm;
}
</style>
<div id="container">
<div id="block">
&nbsp;
</div><!--#block-->
</div><!--#container-->
');
        $block =& $tree->get_element_by_id('block');
        $container =& $tree->get_element_by_id('container');
        $this->assertEqual($block->get_top_margin(), $container->get_top_padding() - mm2pt(3));
        $this->assertEqual($block->get_left_margin(), $container->get_left_padding() + mm2pt(2));
    }
    function TestTextareaHeight1()
    {
        $tree = $this->runPipeline('
<textarea id="textarea" style="height: 8cm;">TEXT</textarea>
');
        $element =& $tree->get_element_by_id('textarea');
        $this->assertEqual($element->get_full_height(), mm2pt(80));
    }
 function testCSSPageBreakAfter2()
 {
     $tree = $this->runPipeline(file_get_contents('test.css.page.break.after.2.html'), $media);
     $page_heights = PageBreakLocator::getPages($tree, mm2pt($media->real_height()), mm2pt($media->height() - $media->margins['top']));
     $this->assertEqual(count($page_heights), 2);
     $div = $tree->get_element_by_id('div');
     $h1 = $tree->get_element_by_id('h1');
     $this->assertEqual($page_heights[0], $div->get_full_height());
 }
 function run(&$pipeline, &$media, &$box)
 {
     $num_pages = ceil($box->get_height() / mm2pt($media->real_height()));
     $page_heights = array();
     for ($i = 0; $i < $num_pages; $i++) {
         $page_heights[] = mm2pt($media->real_height());
     }
     return $page_heights;
 }
 function testPagebreakFixedHeight1()
 {
     $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
     $tree = $this->runPipeline(file_get_contents('test.pagebreak.fixed.height.1.html'), $media);
     $page_heights = PageBreakLocator::getPages($tree, mm2pt($media->real_height()), mm2pt($media->height() - $media->margins['top']));
     $div = $tree->get_element_by_id('div');
     $this->assertEqual(count($page_heights), 2, sprintf("Two pages expected, got %s", count($page_heights)));
     $this->assertEqual($page_heights[0], 200);
 }
Example #13
0
 function guess_page(&$element, $page_heights, &$media)
 {
     $page_index = 0;
     $bottom = mm2pt($media->height() - $media->margins['top']);
     do {
         $bottom -= $page_heights[$page_index];
         $page_index++;
     } while ($element->get_top() < $bottom);
     return $page_index;
 }
Example #14
0
 function handle_before_page_heights($params)
 {
     $pipeline =& $params['pipeline'];
     $document =& $params['document'];
     $media =& $params['media'];
     $boxes = $pipeline->reflow_margin_boxes(0, $media);
     $this->_top_margin = max($boxes[CSS_MARGIN_BOX_SELECTOR_TOP]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_TOP_CENTER]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER]->get_real_full_height());
     $this->_bottom_margin = max($boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT]->get_real_full_height(), $boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER]->get_real_full_height());
     $media->margins['top'] = $this->_top_margin / mm2pt(1);
     $media->margins['bottom'] = $this->_bottom_margin / mm2pt(1);
     $pipeline->output_driver->update_media($media);
     $pipeline->_setupScales($media);
 }
    function testLineBoxTop1()
    {
        $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
        $tree = $this->runPipeline('
<html>
<head>
body   { font-size: 10pt; line-height: 1; padding: 0; margin: 0; }
</style>
</head>
<body>TEXT</body>
</html>
', $media);
        $line_box = $tree->content[0]->getLineBox(0);
        $this->assertEqual($tree->content[0]->get_top(), $line_box->top, "Comparing line box top and inline box top [%s]");
    }
 function testCSSParseMarginBoxesTopLeftSize()
 {
     parse_config_file('../html2ps.config');
     $media =& Media::predefined('A4');
     $media->set_margins(array('left' => 10, 'top' => 10, 'right' => 10, 'bottom' => 10));
     $pipeline =& PipelineFactory::create_default_pipeline('utf-8', 'test.pdf');
     $pipeline->_prepare($media);
     $pipeline->_cssState = array(new CSSState(CSS::get()));
     parse_css_atpage_rules('@page { @top-left { content: "TEXT"; } }', $pipeline);
     $boxes = $pipeline->reflow_margin_boxes(1, $media);
     $box =& $boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT];
     $this->assertNotEqual($box->get_width(), 0);
     $expected_width = $pipeline->output_driver->stringwidth('TEXT', 'Times-Roman', 'iso-8859-1', 12);
     $this->assertTrue($box->get_width() >= $expected_width);
     $this->assertEqual($box->get_height(), mm2pt(10));
 }
 function testTableColumnWidth4()
 {
     $media = null;
     $tree = $this->runPipeline(file_get_contents('test.table.column.width.4.html'), $media);
     $container_table =& $tree->get_element_by_id('table');
     $cell1 =& $tree->get_element_by_id('cell1');
     $cell2 =& $tree->get_element_by_id('cell2');
     $cell =& $tree->get_element_by_id('container-cell');
     $this->assertEqual($container_table->get_width(), mm2pt($media->real_width()) * 0.9);
     $container_cell_width = $cell->get_width();
     $container_cell_min_width = $cell->content[0]->get_width();
     $this->assertTrue($container_cell_min_width <= $container_cell_width, sprintf('Container cell width (%s) is less than content minimal width (%s)', $container_cell_width, $container_cell_min_width));
     $cell_width = $cell1->get_width() + $cell2->get_width() + $cell->get_width();
     $table_width = $container_table->get_width();
     $this->assertTrue($cell_width <= $table_width, sprintf('Total cell width (%s) is greater than table width (%s)', $cell_width, $table_width));
 }
function units2pt($value, $font_size = null)
{
    $units = substr($value, strlen($value) - 2, 2);
    switch ($units) {
        case "pt":
            return pt2pt((double) $value);
        case "px":
            return px2pt((double) $value);
        case "mm":
            return mm2pt((double) $value);
        case "cm":
            return mm2pt((double) $value * 10);
            // FIXME: check if it will work correcty in all situations (order of css rule application may vary).
        // FIXME: check if it will work correcty in all situations (order of css rule application may vary).
        case "em":
            if (is_null($font_size)) {
                $fs = get_font_size();
                //       $fs_parts = explode(" ", $fs);
                //       if (count($fs_parts) == 2) {
                //         return units2pt(((double)$value) * $fs_parts[0]*EM_KOEFF . $fs_parts[1]);
                //       } else {
                return pt2pt((double) $value * $fs * EM_KOEFF);
                //       };
            } else {
                return $font_size * (double) $value * EM_KOEFF;
            }
        case "ex":
            if (is_null($font_size)) {
                $fs = get_font_size();
                //       $fs_parts = explode(" ", $fs);
                //       if (count($fs_parts) == 2) {
                //         return units2pt(((double)$value) * $fs_parts[0]*EX_KOEFF . $fs_parts[1]);
                //       } else {
                return pt2pt((double) $value * $fs * EX_KOEFF);
                //       };
            } else {
                return $font_size * (double) $value * EX_KOEFF;
            }
        default:
            global $g_config;
            if ($g_config['mode'] === 'quirks') {
                return px2pt((double) $value);
            } else {
                return 0;
            }
    }
}
 function testPositionHorizontalbsolutePositioned1()
 {
     $media = null;
     $pipeline = null;
     $tree = $this->runPipeline(file_get_contents('test.position.horizontal.absolute.positioned.1.html'), $media, $pipeline);
     $font_size = $tree->getCSSProperty(CSS_FONT_SIZE);
     $base = $font_size->getPoints();
     $element =& $tree->get_element_by_id('div1');
     $this->assertEqual($element->get_left(), mm2pt($media->margins['left']), 'DIV with no positioning is positioned incorrectly [%s]');
     $element =& $tree->get_element_by_id('div2');
     $this->assertEqual($element->get_left(), mm2pt($media->margins['left']) + px2pt(100), 'DIV with "left" property is positioned incorrectly [%s]');
     $element =& $tree->get_element_by_id('div3');
     $this->assertEqual($element->get_right(), mm2pt($media->width() - $media->margins['right']) - px2pt(100), 'DIV with "right" property is positioned incorrectly [%s]');
     $element =& $tree->get_element_by_id('div4');
     $this->assertEqual($element->get_left(), mm2pt($media->margins['left']), 'DIV with long text and "right" property is positioned incorrectly [%s]');
     $element =& $tree->get_element_by_id('div5');
     $this->assertEqual($element->get_left(), mm2pt($media->margins['left']) + px2pt(100), 'DIV with long text and "left" property is positioned incorrectly [%s]');
 }
    function TestTableAbsolute1()
    {
        $tree = $this->runPipeline('
<style type="text/css">
body {
  margin: 0;
  padding: 0;
}
</style>
<table id="table" style="position: absolute; left: 11mm; top: 17mm;" cellpadding="0" cellspacing="0">
<tr><td>&nbsp;</td></tr>
</table>
');
        $table = $tree->get_element_by_id('table');
        $body = $tree->get_body();
        $this->assertEqual($table->get_top_margin(), $body->get_top() - mm2pt(17));
        $this->assertEqual($table->get_left_margin(), mm2pt(11));
    }
    function TestBlockAbsolute1()
    {
        $tree = $this->runPipeline('
<style type="text/css">
body {
  margin: 0;
  padding: 0;
}
</style>
<div id="block" style="position: absolute; left: 10mm; top: 20mm;">
&nbsp;
</div>
');
        $block = $tree->get_element_by_id('block');
        $body = $tree->get_body();
        $this->assertEqual($block->get_top_margin(), $body->get_top() - mm2pt(20));
        $this->assertEqual($block->get_left_margin(), mm2pt(10));
    }
    function testFontSizeMM()
    {
        $tree = $this->runPipeline('
<html>
<head>
<style type="text/css">
body { font-size: 10mm; line-height: 1; }
</style>
</head>
<body>
TEXT
</body>
</html>
');
        $inline = $tree->get_first();
        $text = $inline->get_first();
        $this->assertEqual($text->words[0], "TEXT");
        $this->assertWithinMargin($text->get_full_height(), mm2pt(10), 0.01);
    }
Example #23
0
 function process(&$box, &$media, &$driver)
 {
     // Calculate the size of text boxes
     $box->reflow_text($driver);
     // Explicitly remove any height declarations from the BODY-generated box;
     // BODY should always fill last page completely. Percentage height of the BODY is meaningless
     // on the paged media.
     $box->_height_constraint = new HCConstraint(null, null, null);
     // As BODY generated box have zero calculated width at the very moment,
     // and we need some box to use as a parameter to _calc_percentage_margins,
     // we'll create a fake box having with equal to the viewport width.
     $media_box = new BlockBox();
     $media_box->width = mm2pt($media->width() - $media->margins['left'] - $media->margins['right']);
     // Calculate actual margin values
     $box->_calc_percentage_margins($media_box);
     $box->width = mm2pt($media->width() - $media->margins['left'] - $media->margins['right']) - $box->_get_hor_extra();
     $box->height = mm2pt($media->height() - $media->margins['top'] - $media->margins['bottom']) - $box->_get_vert_extra();
     $box->put_top(mm2pt($media->height() - $media->margins['top']) - $box->get_extra_top());
     $box->put_left(mm2pt($media->margins['left']) + $box->get_extra_left());
     $box->to_ps($driver);
 }
    /**
     * Checks if it is possible to make an incorrect page break in a table with
     * different font size in different cells
     */
    function testPagebreakTableBr1()
    {
        $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
        $tree = $this->runPipeline('
<html>
<head>
body { 
  font-size: 10pt; 
  line-height: 1; 
  padding: 0; 
  margin: 0; 
}

td.small { 
  font-size: 20pt; 
}
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0">
<tr>
<td>
SMALL<br/>
SMALL<br/>
SMALL<br/>
SMALL<br/>
SMALL<br/>
</td>
</tr>
</table>
</body>
</html>
', $media);
        /**
         * Calculate page heights
         */
        $locations = PageBreakLocator::_getBreakLocations($tree);
        $this->assertEqual(count($locations), 6);
    }
    function testTableTopBoundary2()
    {
        $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
        $tree = $this->runPipeline('
<html>
<head>
body   { font-size: 10pt; line-height: 1; padding: 0; margin: 0; }
</style>
</head>
<body>
<table cellpadding="0" cellspacing="0" id="table">
<tr><td id="cell">TEXT1<br/>TEXT2</td></tr>
</table>
</body>
</html>
', $media);
        $table = $tree->get_element_by_id('table');
        $cell = $tree->get_element_by_id('cell');
        $this->assertEqual($table->get_top_margin(), $cell->get_top_margin(), "Comparing table and cell top margins for the table containins one cell [%s]");
        $text = $cell->content[0]->content[0];
        $this->assertEqual($text->get_top_margin(), $cell->get_top_margin(), "Comparing cell and cell content top margins for the table containins one cell [%s]");
    }
Example #26
0
    function testPagebreakWithBR()
    {
        $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
        $tree = $this->runPipeline('
<html>
<head>
body   { font-size: 10pt; line-height: 1; padding: 0; margin: 0; }
</style>
</head>
<body>
<div>
LINE1<br/>
LINE2<br/>
LINE3<br/>
LINE4<br/>
LINE5<br/>
</div>
</body>
</html>
', $media);
        $locations = PageBreakLocator::_getBreakLocations($tree);
        $this->assertEqual(count($locations), 6);
    }
    function testLineBoxNested1()
    {
        $media = new Media(array('width' => 100, 'height' => 200 / mm2pt(1)), array('top' => 0, 'bottom' => 0, 'left' => 0, 'right' => 0));
        $tree = $this->runPipeline('
<html>
<head>
body   { font-size: 10pt; line-height: 1; padding: 0; margin: 0; }
</style>
</head>
<body>
<span id="outer" style="border: solid black 1px;">
<span id="inner1" style="background-color: red;">TEXT</span>
<span id="inner2" style="background-color: green; font-size: 2em;">TEXT</span>
<span id="inner3" style="background-color: red;">TEXT</span>
</span>
</body>
</html>
', $media);
        $outer = $tree->get_element_by_id('outer');
        $outer_line = $outer->getLineBox(0);
        $inner1 = $tree->get_element_by_id('inner1');
        $inner1_line = $inner1->getLineBox(0);
        $inner2 = $tree->get_element_by_id('inner2');
        $inner2_line = $inner2->getLineBox(0);
        $inner3 = $tree->get_element_by_id('inner3');
        $inner3_line = $inner3->getLineBox(0);
        // Note that it will emulate IE behavior (line box includes all
        // nested line boxes), which (in my opinion)
        // is more standard than Firefox (line box height is calculated
        // using the first child line box).
        $this->assertEqual($outer_line->top, $inner2_line->top);
        $this->assertEqual($outer_line->bottom, $inner2_line->bottom);
        $this->assertEqual($inner1_line->bottom, $inner3_line->bottom);
        $this->assertEqual($inner1_line->top, $inner3_line->top);
        $this->assertTrue($inner1_line->top < $inner2_line->top);
        $this->assertTrue($inner1_line->bottom > $inner2_line->bottom);
    }
 function update_media(&$media)
 {
     $this->media =& $media;
     $this->width = mm2pt($media->width() - $media->margins['left'] - $media->margins['right']);
     $this->height = mm2pt($media->height() - $media->margins['top'] - $media->margins['bottom']);
     $this->left = mm2pt($media->margins['left']);
     $this->bottom = mm2pt($media->margins['bottom']);
     $this->setPageHeight(mm2pt($media->real_height()));
 }
 function process(&$box, &$media, &$driver, &$context)
 {
     // Calculate the size of text boxes
     if (is_null($box->reflow_text($driver))) {
         error_log("LayoutEngineDefault::process: reflow_text call failed");
         return null;
     }
     // Explicitly remove any height declarations from the BODY-generated box;
     // BODY should always fill last page completely. Percentage height of the BODY is meaningless
     // on the paged media.
     $box->_height_constraint = new HCConstraint(null, null, null);
     $margin = $box->getCSSProperty(CSS_MARGIN);
     $margin->calcPercentages(mm2pt($media->width() - $media->margins['left'] - $media->margins['right']));
     $box->setCSSProperty(CSS_MARGIN, $margin);
     $box->width = mm2pt($media->width() - $media->margins['left'] - $media->margins['right']) - $box->_get_hor_extra();
     $box->setCSSProperty(CSS_WIDTH, new WCConstant($box->width));
     $box->height = mm2pt($media->real_height()) - $box->_get_vert_extra();
     $box->put_top(mm2pt($media->height() - $media->margins['top']) - $box->get_extra_top());
     $box->put_left(mm2pt($media->margins['left']) + $box->get_extra_left());
     $flag = false;
     $whitespace_flag = false;
     $box->reflow_whitespace($flag, $whitespace_flag);
     $box->pre_reflow_images();
     $viewport = new FlowViewport();
     $viewport->left = mm2pt($media->margins['left']);
     $viewport->top = mm2pt($media->height() - $media->margins['top']);
     $viewport->width = mm2pt($media->width() - $media->margins['left'] - $media->margins['right']);
     $viewport->height = mm2pt($media->height() - $media->margins['top'] - $media->margins['bottom']);
     $fake_parent = null;
     $context->push_viewport($viewport);
     $box->reflow($fake_parent, $context);
     // Make the top-level box competely fill the last page
     $page_real_height = mm2pt($media->real_height());
     // Note we cannot have less than 1 page in our doc; max() call
     // is required as we, in general, CAN have the content height strictly equal to 0.
     // In this case wi still render the very first page
     $pages = max(1, ceil($box->get_full_height() / $page_real_height));
     /**
      * Set body box height so it will fit the page exactly
      */
     $box->height = $pages * $page_real_height - $box->_get_vert_extra();
     $driver->set_expected_pages($pages);
     $driver->anchors = array();
     $box->reflow_anchors($driver, $driver->anchors);
     /**
      * Flow absolute-positioned boxes;
      * note that we should know the number of expected pages at this moment, unless
      * we will not be able to calculate positions for elements using 'bottom: ...' CSS property
      */
     for ($i = 0, $num_positioned = count($context->absolute_positioned); $i < $num_positioned; $i++) {
         $context->push();
         $context->absolute_positioned[$i]->reflow_absolute($context);
         $context->pop();
     }
     // Flow fixed-positioned box
     for ($i = 0, $num_positioned = count($context->fixed_positioned); $i < $num_positioned; $i++) {
         $context->push();
         $context->fixed_positioned[$i]->reflow_fixed($context);
         $context->pop();
     }
     $box->reflow_inline();
     return true;
 }
 function to_bbox()
 {
     return '0 0 ' . ceil(mm2pt($this->size['width'])) . ' ' . ceil(mm2pt($this->size['height']));
 }