1<?php 2 3require_once(HTML2PS_DIR.'utils_array.php'); 4require_once(HTML2PS_DIR.'utils_graphic.php'); 5require_once(HTML2PS_DIR.'utils_url.php'); 6require_once(HTML2PS_DIR.'utils_text.php'); 7require_once(HTML2PS_DIR.'utils_units.php'); 8require_once(HTML2PS_DIR.'utils_number.php'); 9 10require_once(HTML2PS_DIR.'value.color.php'); 11 12require_once(HTML2PS_DIR.'config.parse.php'); 13 14require_once(HTML2PS_DIR.'flow_context.class.inc.php'); 15require_once(HTML2PS_DIR.'flow_viewport.class.inc.php'); 16 17require_once(HTML2PS_DIR.'output._interface.class.php'); 18require_once(HTML2PS_DIR.'output._generic.class.php'); 19require_once(HTML2PS_DIR.'output._generic.pdf.class.php'); 20require_once(HTML2PS_DIR.'output._generic.ps.class.php'); 21require_once(HTML2PS_DIR.'output.pdflib.old.class.php'); 22require_once(HTML2PS_DIR.'output.pdflib.1.6.class.php'); 23require_once(HTML2PS_DIR.'output.fpdf.class.php'); 24require_once(HTML2PS_DIR.'output.fastps.class.php'); 25require_once(HTML2PS_DIR.'output.fastps.l2.class.php'); 26require_once(HTML2PS_DIR.'output.png.class.php'); 27// require_once(HTML2PS_DIR.'output.pcl.class.php'); 28 29require_once(HTML2PS_DIR.'stubs.common.inc.php'); 30 31require_once(HTML2PS_DIR.'media.layout.inc.php'); 32 33require_once(HTML2PS_DIR.'box.php'); 34require_once(HTML2PS_DIR.'box.generic.php'); 35require_once(HTML2PS_DIR.'box.generic.formatted.php'); 36require_once(HTML2PS_DIR.'box.container.php'); 37require_once(HTML2PS_DIR.'box.generic.inline.php'); 38require_once(HTML2PS_DIR.'box.inline.php'); 39require_once(HTML2PS_DIR.'box.inline.control.php'); 40 41require_once(HTML2PS_DIR.'font.class.php'); 42require_once(HTML2PS_DIR.'font_factory.class.php'); 43 44require_once(HTML2PS_DIR.'box.br.php'); 45require_once(HTML2PS_DIR.'box.block.php'); 46require_once(HTML2PS_DIR.'box.page.php'); 47require_once(HTML2PS_DIR.'box.page.margin.class.php'); 48require_once(HTML2PS_DIR.'box.body.php'); 49require_once(HTML2PS_DIR.'box.block.inline.php'); 50require_once(HTML2PS_DIR.'box.button.php'); 51require_once(HTML2PS_DIR.'box.button.submit.php'); 52require_once(HTML2PS_DIR.'box.button.reset.php'); 53require_once(HTML2PS_DIR.'box.checkbutton.php'); 54require_once(HTML2PS_DIR.'box.form.php'); 55require_once(HTML2PS_DIR.'box.frame.php'); 56require_once(HTML2PS_DIR.'box.iframe.php'); 57require_once(HTML2PS_DIR.'box.input.text.php'); 58require_once(HTML2PS_DIR.'box.input.textarea.php'); 59require_once(HTML2PS_DIR.'box.input.password.php'); 60require_once(HTML2PS_DIR.'box.legend.php'); 61require_once(HTML2PS_DIR.'box.list-item.php'); 62require_once(HTML2PS_DIR.'box.null.php'); 63require_once(HTML2PS_DIR.'box.radiobutton.php'); 64require_once(HTML2PS_DIR.'box.select.php'); 65require_once(HTML2PS_DIR.'box.table.php'); 66require_once(HTML2PS_DIR.'box.table.cell.php'); 67require_once(HTML2PS_DIR.'box.table.cell.fake.php'); 68require_once(HTML2PS_DIR.'box.table.row.php'); 69require_once(HTML2PS_DIR.'box.table.section.php'); 70 71require_once(HTML2PS_DIR.'box.text.php'); 72require_once(HTML2PS_DIR.'box.text.string.php'); 73require_once(HTML2PS_DIR.'box.field.pageno.php'); 74require_once(HTML2PS_DIR.'box.field.pages.php'); 75 76require_once(HTML2PS_DIR.'box.whitespace.php'); 77 78require_once(HTML2PS_DIR.'box.img.php'); // Inherited from the text box! 79require_once(HTML2PS_DIR.'box.input.img.php'); 80 81require_once(HTML2PS_DIR.'box.utils.text-align.inc.php'); 82 83require_once(HTML2PS_DIR.'manager.encoding.php'); 84 85require_once(HTML2PS_DIR.'ps.unicode.inc.php'); 86require_once(HTML2PS_DIR.'ps.utils.inc.php'); 87require_once(HTML2PS_DIR.'ps.whitespace.inc.php'); 88 89require_once(HTML2PS_DIR.'ps.image.encoder.inc.php'); 90require_once(HTML2PS_DIR.'ps.image.encoder.simple.inc.php'); 91require_once(HTML2PS_DIR.'ps.l2.image.encoder.stream.inc.php'); 92require_once(HTML2PS_DIR.'ps.l3.image.encoder.stream.inc.php'); 93 94require_once(HTML2PS_DIR.'tag.body.inc.php'); 95require_once(HTML2PS_DIR.'tag.font.inc.php'); 96require_once(HTML2PS_DIR.'tag.frame.inc.php'); 97require_once(HTML2PS_DIR.'tag.input.inc.php'); 98require_once(HTML2PS_DIR.'tag.img.inc.php'); 99require_once(HTML2PS_DIR.'tag.select.inc.php'); 100require_once(HTML2PS_DIR.'tag.span.inc.php'); 101require_once(HTML2PS_DIR.'tag.table.inc.php'); 102require_once(HTML2PS_DIR.'tag.td.inc.php'); 103require_once(HTML2PS_DIR.'tag.utils.inc.php'); 104 105require_once(HTML2PS_DIR.'tree.navigation.inc.php'); 106 107require_once(HTML2PS_DIR.'html.attrs.inc.php'); 108 109require_once(HTML2PS_DIR.'xhtml.autoclose.inc.php'); 110require_once(HTML2PS_DIR.'xhtml.utils.inc.php'); 111require_once(HTML2PS_DIR.'xhtml.tables.inc.php'); 112require_once(HTML2PS_DIR.'xhtml.p.inc.php'); 113require_once(HTML2PS_DIR.'xhtml.lists.inc.php'); 114require_once(HTML2PS_DIR.'xhtml.deflist.inc.php'); 115require_once(HTML2PS_DIR.'xhtml.script.inc.php'); 116require_once(HTML2PS_DIR.'xhtml.entities.inc.php'); 117require_once(HTML2PS_DIR.'xhtml.comments.inc.php'); 118require_once(HTML2PS_DIR.'xhtml.style.inc.php'); 119require_once(HTML2PS_DIR.'xhtml.selects.inc.php'); 120 121require_once(HTML2PS_DIR.'background.image.php'); 122require_once(HTML2PS_DIR.'background.position.php'); 123 124require_once(HTML2PS_DIR.'list-style.image.php'); 125 126require_once(HTML2PS_DIR.'height.php'); 127require_once(HTML2PS_DIR.'width.php'); 128 129require_once(HTML2PS_DIR.'css.counter.php'); 130require_once(HTML2PS_DIR.'css.counter.collection.php'); 131 132require_once(HTML2PS_DIR.'css.colors.inc.php'); 133 134require_once(HTML2PS_DIR.'css.constants.inc.php'); 135require_once(HTML2PS_DIR.'css.inc.php'); 136require_once(HTML2PS_DIR.'css.state.class.php'); 137require_once(HTML2PS_DIR.'css.cache.class.php'); 138require_once(HTML2PS_DIR.'css.property.handler.class.php'); 139require_once(HTML2PS_DIR.'css.property.stringset.class.php'); 140require_once(HTML2PS_DIR.'css.property.sub.class.php'); 141require_once(HTML2PS_DIR.'css.property.sub.field.class.php'); 142require_once(HTML2PS_DIR.'css.utils.inc.php'); 143require_once(HTML2PS_DIR.'css.parse.inc.php'); 144require_once(HTML2PS_DIR.'css.parse.media.inc.php'); 145 146require_once(HTML2PS_DIR.'css.background.attachment.inc.php'); 147require_once(HTML2PS_DIR.'css.background.color.inc.php'); 148require_once(HTML2PS_DIR.'css.background.image.inc.php'); 149require_once(HTML2PS_DIR.'css.background.repeat.inc.php'); 150require_once(HTML2PS_DIR.'css.background.position.inc.php'); 151require_once(HTML2PS_DIR.'css.background.inc.php'); 152 153require_once(HTML2PS_DIR.'css.border.inc.php'); 154require_once(HTML2PS_DIR.'css.border.style.inc.php'); 155require_once(HTML2PS_DIR.'css.border.collapse.inc.php'); 156require_once(HTML2PS_DIR.'css.bottom.inc.php'); 157require_once(HTML2PS_DIR.'css.clear.inc.php'); 158require_once(HTML2PS_DIR.'css.color.inc.php'); 159require_once(HTML2PS_DIR.'css.direction.inc.php'); 160require_once(HTML2PS_DIR.'css.html2ps.html.content.inc.php'); 161require_once(HTML2PS_DIR.'css.html2ps.pseudoelements.inc.php'); 162require_once(HTML2PS_DIR.'css.html2ps.pixels.php'); 163require_once(HTML2PS_DIR.'css.content.inc.php'); 164require_once(HTML2PS_DIR.'css.display.inc.php'); 165require_once(HTML2PS_DIR.'css.float.inc.php'); 166require_once(HTML2PS_DIR.'css.font.inc.php'); 167require_once(HTML2PS_DIR.'css.height.inc.php'); 168require_once(HTML2PS_DIR.'css.min-height.inc.php'); 169require_once(HTML2PS_DIR.'css.max-height.inc.php'); 170require_once(HTML2PS_DIR.'css.left.inc.php'); 171require_once(HTML2PS_DIR.'css.letter-spacing.inc.php'); 172 173require_once(HTML2PS_DIR.'css.list-style-image.inc.php'); 174require_once(HTML2PS_DIR.'css.list-style-position.inc.php'); 175require_once(HTML2PS_DIR.'css.list-style-type.inc.php'); 176require_once(HTML2PS_DIR.'css.list-style.inc.php'); 177 178require_once(HTML2PS_DIR.'css.margin.inc.php'); 179require_once(HTML2PS_DIR.'css.overflow.inc.php'); 180require_once(HTML2PS_DIR.'css.padding.inc.php'); 181 182require_once(HTML2PS_DIR.'css.page.inc.php'); 183require_once(HTML2PS_DIR.'css.page-break.inc.php'); 184require_once(HTML2PS_DIR.'css.page-break-after.inc.php'); 185require_once(HTML2PS_DIR.'css.page-break-before.inc.php'); 186require_once(HTML2PS_DIR.'css.page-break-inside.inc.php'); 187require_once(HTML2PS_DIR.'css.orphans.inc.php'); 188require_once(HTML2PS_DIR.'css.size.inc.php'); 189require_once(HTML2PS_DIR.'css.widows.inc.php'); 190 191require_once(HTML2PS_DIR.'css.position.inc.php'); 192require_once(HTML2PS_DIR.'css.right.inc.php'); 193require_once(HTML2PS_DIR.'css.property.declaration.php'); 194require_once(HTML2PS_DIR.'css.rules.inc.php'); 195require_once(HTML2PS_DIR.'css.ruleset.class.php'); 196require_once(HTML2PS_DIR.'css.selectors.inc.php'); 197require_once(HTML2PS_DIR.'css.table-layout.inc.php'); 198require_once(HTML2PS_DIR.'css.text-align.inc.php'); 199require_once(HTML2PS_DIR.'css.text-decoration.inc.php'); 200require_once(HTML2PS_DIR.'css.text-transform.inc.php'); 201require_once(HTML2PS_DIR.'css.text-indent.inc.php'); 202require_once(HTML2PS_DIR.'css.top.inc.php'); 203require_once(HTML2PS_DIR.'css.vertical-align.inc.php'); 204require_once(HTML2PS_DIR.'css.visibility.inc.php'); 205require_once(HTML2PS_DIR.'css.white-space.inc.php'); 206require_once(HTML2PS_DIR.'css.width.inc.php'); 207require_once(HTML2PS_DIR.'css.word-spacing.inc.php'); 208require_once(HTML2PS_DIR.'css.z-index.inc.php'); 209 210require_once(HTML2PS_DIR.'css.pseudo.add.margin.inc.php'); 211require_once(HTML2PS_DIR.'css.pseudo.align.inc.php'); 212require_once(HTML2PS_DIR.'css.pseudo.cellspacing.inc.php'); 213require_once(HTML2PS_DIR.'css.pseudo.cellpadding.inc.php'); 214require_once(HTML2PS_DIR.'css.pseudo.form.action.inc.php'); 215require_once(HTML2PS_DIR.'css.pseudo.form.radiogroup.inc.php'); 216require_once(HTML2PS_DIR.'css.pseudo.link.destination.inc.php'); 217require_once(HTML2PS_DIR.'css.pseudo.link.target.inc.php'); 218require_once(HTML2PS_DIR.'css.pseudo.listcounter.inc.php'); 219require_once(HTML2PS_DIR.'css.pseudo.localalign.inc.php'); 220require_once(HTML2PS_DIR.'css.pseudo.nowrap.inc.php'); 221require_once(HTML2PS_DIR.'css.pseudo.table.border.inc.php'); 222 223// After all CSS utilities and constants have been initialized, load the default (precomiled) CSS stylesheet 224require_once(HTML2PS_DIR.'converter.class.php'); 225require_once(HTML2PS_DIR.'treebuilder.class.php'); 226require_once(HTML2PS_DIR.'image.class.php'); 227 228require_once(HTML2PS_DIR.'fetched_data._interface.class.php'); 229require_once(HTML2PS_DIR.'fetched_data._html.class.php'); 230require_once(HTML2PS_DIR.'fetched_data.url.class.php'); 231require_once(HTML2PS_DIR.'fetched_data.file.class.php'); 232 233require_once(HTML2PS_DIR.'filter.data._interface.class.php'); 234require_once(HTML2PS_DIR.'filter.data.doctype.class.php'); 235 236require_once(HTML2PS_DIR.'filter.data.utf8.class.php'); 237require_once(HTML2PS_DIR.'filter.data.ucs2.class.php'); 238 239require_once(HTML2PS_DIR.'filter.data.html2xhtml.class.php'); 240require_once(HTML2PS_DIR.'filter.data.xhtml2xhtml.class.php'); 241 242require_once(HTML2PS_DIR.'parser._interface.class.php'); 243require_once(HTML2PS_DIR.'parser.xhtml.class.php'); 244 245require_once(HTML2PS_DIR.'filter.pre._interface.class.php'); 246require_once(HTML2PS_DIR.'filter.pre.fields.class.php'); 247require_once(HTML2PS_DIR.'filter.pre.headfoot.class.php'); 248require_once(HTML2PS_DIR.'filter.pre.footnotes.class.php'); 249require_once(HTML2PS_DIR.'filter.pre.height-constraint.class.php'); 250 251require_once(HTML2PS_DIR.'layout._interface.class.php'); 252require_once(HTML2PS_DIR.'layout.default.class.php'); 253require_once(HTML2PS_DIR.'layout.page.breaks.php'); 254 255require_once(HTML2PS_DIR.'filter.post._interface.class.php'); 256require_once(HTML2PS_DIR.'filter.post.positioned.class.php'); 257require_once(HTML2PS_DIR.'filter.post.postponed.class.php'); 258 259require_once(HTML2PS_DIR.'filter.output._interface.class.php'); 260require_once(HTML2PS_DIR.'filter.output.ps2pdf.class.php'); 261require_once(HTML2PS_DIR.'filter.output.gzip.class.php'); 262 263require_once(HTML2PS_DIR.'destination._interface.class.php'); 264require_once(HTML2PS_DIR.'destination._http.class.php'); 265require_once(HTML2PS_DIR.'destination.browser.class.php'); 266require_once(HTML2PS_DIR.'destination.download.class.php'); 267require_once(HTML2PS_DIR.'destination.file.class.php'); 268 269require_once(HTML2PS_DIR.'xml.validation.inc.php'); 270 271require_once(HTML2PS_DIR.'content_type.class.php'); 272require_once(HTML2PS_DIR.'dispatcher.class.php'); 273require_once(HTML2PS_DIR.'observer.class.php'); 274 275require_once(HTML2PS_DIR.'strategy.page.break.simple.php'); 276require_once(HTML2PS_DIR.'strategy.page.break.smart.php'); 277 278require_once(HTML2PS_DIR.'strategy.link.rendering.normal.php'); 279require_once(HTML2PS_DIR.'strategy.position.absolute.php'); 280require_once(HTML2PS_DIR.'strategy.width.absolute.positioned.php'); 281require_once(HTML2PS_DIR.'autofix.url.php'); 282 283require_once(HTML2PS_DIR.'fetcher._interface.class.php'); 284require_once(HTML2PS_DIR.'features/_factory.php'); 285 286class Pipeline { 287 var $fetchers; 288 var $data_filters; 289 var $error_message; 290 var $parser; 291 var $pre_tree_filters; 292 var $layout_engine; 293 var $post_tree_filters; 294 var $output_driver; 295 var $output_filters; 296 var $destination; 297 298 var $_base_url; 299 300 var $_page_at_rules; 301 var $_counters; 302 var $_footnotes; 303 304 var $_cssState; 305 var $_css; 306 var $_defaultCSS; 307 308 var $_dispatcher; 309 310 var $_current_page_name; 311 312 var $_page_break_strategy; 313 314 function Pipeline() { 315 $this->_css = array(); 316 317 $this->_counters = array(); 318 $this->_footnotes = array(); 319 320 $this->_base_url = array(''); 321 $this->_reset_page_at_rules(); 322 323 $this->pre_tree_filters = array(); 324 325 $this->_dispatcher =& new Dispatcher(); 326 327 $this->_dispatcher->add_event('before-page-heights'); 328 $this->_dispatcher->add_event('before-page'); 329 $this->_dispatcher->add_event('after-page'); 330 $this->_dispatcher->add_event('before-batch-item'); 331 $this->_dispatcher->add_event('after-batch-item'); 332 $this->_dispatcher->add_event('after-parse'); 333 $this->_dispatcher->add_event('before-document'); 334 $this->_dispatcher->add_event('after-document'); 335 $this->_dispatcher->add_event('before-batch'); 336 $this->_dispatcher->add_event('after-batch'); 337 338 $this->_page_break_strategy = new StrategyPageBreakSimple(); 339 } 340 341 function add_feature($feature_name, $params = array()) { 342 $feature_object =& FeatureFactory::get($feature_name); 343 if (is_null($feature_object)) { 344 die(sprintf('No feature "%s" found', $feature_name)); 345 }; 346 347 $feature_object->install($this, $params); 348 } 349 350 function add_fetcher(&$fetcher) { 351 array_unshift($this->fetchers, $fetcher); 352 } 353 354 function calculate_page_heights(&$media, &$box) { 355 return $this->_page_break_strategy->run($this, $media, $box); 356 } 357 358 function clear_box_id_map() { 359 $GLOBALS['__html_box_id_map'] = array(); 360 } 361 362 function close() { 363 $this->_dispatcher->fire('after-batch', array('pipeline' => &$this)); 364 365 $this->output_driver->close(); 366 $this->_output(); 367 $this->output_driver->release(); 368 369 // Non HTML-specific cleanup 370 // 371 ImageFactory::clear_cache(); 372 } 373 374 function configure($options) { 375 $defaults = array('compress' => false, 376 'cssmedia' => 'screen', 377 'debugbox' => false, 378 'debugnoclip' => false, 379 'draw_page_border' => false, 380 'encoding' => '', 381 'html2xhtml' => true, 382 'imagequality_workaround' => false, 383 'landscape' => false, 384 'margins' => array('left' => 30, 385 'right' => 15, 386 'top' => 15, 387 'bottom' => 15), 388 'media' => 'A4', 389 'method' => 'fpdf', 390 'mode' => 'html', 391 'output' => 0, 392 'pagewidth' => 800, 393 'pdfversion' => "1.2", 394 'ps2pdf' => false, 395 'pslevel' => 3, 396 'renderfields' => false, 397 'renderforms' => false, 398 'renderimages' => true, 399 'renderlinks' => false, 400 'scalepoints' => true, 401 'smartpagebreak' => true, 402 'transparency_workaround' => false 403 ); 404 405 // As a reminder: If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. 406 $GLOBALS['g_config'] = array_merge($defaults, $options); 407 408 // Note that CSS media names should be case-insensitive 409 $GLOBALS['g_config']['cssmedia'] = strtolower($GLOBALS['g_config']['cssmedia']); 410 411 if ($GLOBALS['g_config']['smartpagebreak']) { 412 $this->_page_break_strategy = new StrategyPageBreakSmart(); 413 } else { 414 $this->_page_break_strategy = new StrategyPageBreakSimple(); 415 }; 416 } 417 418 function _addFootnote(&$note_call) { 419 $this->_footnotes[] =& $note_call; 420 } 421 422// function _fillContent($content) { 423// $filled = ""; 424 425// while (preg_match("/^.*?('.*?'|\".*?\"|counter\(.*?\))(.*)$/", $content, $matches)) { 426// $data = $matches[1]; 427// $content = $matches[2]; 428 429// if ($data{0} != '\'' && $data{0} != '"') { 430// $filled .= $this->_fillContentCounter($data); 431// } else { 432// $filled .= $this->_fillContentString($data); 433// }; 434// }; 435 436// return $filled; 437// } 438 439// function _fillContentString($content) { 440// $unescaped_content = css_process_escapes($content); 441// $unquoted_content = css_remove_value_quotes($unescaped_content); 442// return $unquoted_content; 443// } 444 445// function _fillContentCounter($content) { 446// preg_match("/counter\((.*?)\)/", $content, $matches); 447// return $this->_getCounter($matches[1]); 448// } 449 450 function &get_counters() { 451 $counter_collection =& new CSSCounterCollection(); 452 453 foreach ($this->_counters as $counter_name => $counter_value) { 454 $counter =& new CSSCounter($counter_name); 455 $counter->set($counter_value); 456 $counter_collection->add($counter); 457 }; 458 459 return $counter_collection; 460 } 461 462 function &get_dispatcher() { 463 return $this->_dispatcher; 464 } 465 466 function get_counter($counter) { 467 if (isset($this->_counters[$counter])) { 468 return $this->_counters[$counter]; 469 }; 470 471 /** 472 * CSS 2.1: Counters that are not in the scope of any 473 * 'counter-reset', are assumed to have been reset to 0 by a 474 * 'counter-reset' on the root element. 475 */ 476 return 0; 477 } 478 479 function reset_counter($counter, $value) { 480 $this->_counters[$counter] = $value; 481 } 482 483 function increment_counter($counter, $value) { 484 $this->_counters[$counter] += $value; 485 } 486 487 function add_at_rule_page($at_rule) { 488 $selector =& $at_rule->getSelector(); 489 $type = $selector->get_type(); 490 $this->_page_at_rules[$type][] = $at_rule; 491 } 492 493 function _reset_page_at_rules() { 494 $this->_page_at_rules = array(CSS_PAGE_SELECTOR_ALL => array(), 495 CSS_PAGE_SELECTOR_FIRST => array(), 496 CSS_PAGE_SELECTOR_LEFT => array(), 497 CSS_PAGE_SELECTOR_RIGHT => array(), 498 CSS_PAGE_SELECTOR_NAMED => array()); 499 } 500 501 function &get_default_css() { 502 return $this->_defaultCSS; 503 } 504 505 function &get_current_css() { 506 return $this->_css[0]; 507 } 508 509 function &get_current_css_state() { 510 return $this->_cssState[0]; 511 } 512 513 function push_css() { 514 array_unshift($this->_css, new CSSRuleset()); 515 } 516 517 function pop_css() { 518 array_shift($this->_css); 519 } 520 521 /** 522 * Note that different pages may define different margin boxes (for 523 * example, left and right pages may have different headers). In 524 * this case, we should process @page rules in order of their 525 * specificity (no selector < :left / :right < :first) and extract 526 * margin boxes to be drawn 527 * 528 * @param $page_no Integer current page index (1-based) 529 * @param $media 530 */ 531 function render_margin_boxes($page_no, &$media) { 532 $boxes =& $this->reflow_margin_boxes($page_no, $media); 533 534 foreach ($boxes as $selector => $box) { 535 $boxes[$selector]->show($this->output_driver); 536 }; 537 538 // Memleak fix 539 for ($i=0, $size = count($boxes); $i < $size; $i++) { 540 $boxes[$i]->destroy(); 541 }; 542 unset($boxes); 543 } 544 545 function get_page_media($page_no, &$media) { 546 $page_rules =& $this->get_page_rules($page_no); 547 $size_landscape = $page_rules->get_property_value(CSS_SIZE); 548 if (!is_null($size_landscape)) { 549 $media->set_width($size_landscape['size']['width']); 550 $media->set_height($size_landscape['size']['height']); 551 $media->set_landscape($size_landscape['landscape']); 552 }; 553 554 $margins = $page_rules->get_property_value(CSS_MARGIN); 555 if (!is_null($margins)) { 556 $media->margins['left'] = $margins->left->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1); 557 $media->margins['right'] = $margins->right->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1); 558 $media->margins['top'] = $margins->top->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1); 559 $media->margins['bottom'] = $margins->bottom->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1); 560 }; 561 562 $left_margin = $page_rules->get_property_value(CSS_MARGIN_LEFT); 563 if (!is_null($left_margin)) { 564 $media->margins['left'] = $left_margin->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1); 565 }; 566 567 $right_margin = $page_rules->get_property_value(CSS_MARGIN_RIGHT); 568 if (!is_null($right_margin)) { 569 $media->margins['right'] = $right_margin->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1); 570 }; 571 572 $top_margin = $page_rules->get_property_value(CSS_MARGIN_TOP); 573 if (!is_null($top_margin)) { 574 $media->margins['top'] = $top_margin->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1); 575 }; 576 577 $bottom_margin = $page_rules->get_property_value(CSS_MARGIN_BOTTOM); 578 if (!is_null($bottom_margin)) { 579 $media->margins['bottom'] = $bottom_margin->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1); 580 }; 581 582 $pixels = $page_rules->get_property_value(CSS_HTML2PS_PIXELS); 583 if (!is_null($pixels)) { 584 $media->set_pixels($pixels); 585 }; 586 } 587 588 function &get_page_rules($page_no) { 589 $collection =& new CSSPropertyCollection(); 590 591 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_ALL] as $rule) { 592 $collection->merge($rule->css); 593 }; 594 595 /** 596 * Check which one of :right/:left selector is applicable (assuming that first page matches :right) 597 */ 598 if ($page_no % 2 == 0) { 599 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_LEFT] as $rule) { 600 $collection->merge($rule->css); 601 }; 602 } else { 603 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_RIGHT] as $rule) { 604 $collection->merge($rule->css); 605 }; 606 }; 607 608 if ($page_no == 1) { 609 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_FIRST] as $rule) { 610 $collection->merge($rule->css); 611 }; 612 }; 613 614 return $collection; 615 } 616 617 function &reflow_page_box($page_no, &$media) { 618 $rules =& $this->get_page_rules($page_no); 619 $box =& BoxPage::create($this, $rules); 620 $box->reflow($media); 621 return $box; 622 } 623 624 function render_page_box($page_no, &$media) { 625 $box =& $this->reflow_page_box($page_no, $media); 626 $box->show($this->output_driver); 627 $box->destroy(); 628 unset($box); 629 } 630 631 function &reflow_margin_boxes($page_no, &$media) { 632 $at_rules = $this->_getMarginBoxes($page_no, $media); 633 634 $boxes = array(); 635 foreach ($at_rules as $at_rule) { 636 $selector = $at_rule->getSelector(); 637 $boxes[$selector] =& BoxPageMargin::create($this, $at_rule); 638 }; 639 640 foreach ($boxes as $selector => $box) { 641 $linebox_started = false; 642 $previous_whitespace = false; 643 $boxes[$selector]->reflow_whitespace($linebox_started, $previous_whitespace); 644 $boxes[$selector]->reflow_text($this->output_driver); 645 }; 646 647 foreach ($boxes as $selector => $box) { 648 $boxes[$selector]->reflow($this->output_driver, 649 $media, 650 $boxes); 651 }; 652 653 return $boxes; 654 } 655 656 /** 657 * Note that "+" operation on arrays will preserve existing elements; thus 658 * we need to process @page rules in order of decreasing specificity 659 * 660 */ 661 function _getMarginBoxes($page_no, $media) { 662 $applicable_margin_boxes = array(); 663 664 /** 665 * Check if :first selector is applicable 666 */ 667 if ($page_no == 1) { 668 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_FIRST] as $rule) { 669 $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes(); 670 }; 671 }; 672 673 /** 674 * Check which one of :right/:left selector is applicable (assuming that first page matches :right) 675 */ 676 if ($page_no % 2 == 0) { 677 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_LEFT] as $rule) { 678 $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes(); 679 }; 680 } else { 681 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_RIGHT] as $rule) { 682 $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes(); 683 }; 684 }; 685 686 /** 687 * Extract margin boxes from plain @page rules 688 */ 689 foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_ALL] as $rule) { 690 $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes(); 691 }; 692 693 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP])) { 694 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP] =& 695 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP,$this); 696 }; 697 698 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER])) { 699 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER] =& 700 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER,$this); 701 }; 702 703 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT])) { 704 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT] =& 705 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_LEFT,$this); 706 }; 707 708 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_CENTER])) { 709 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_CENTER] =& 710 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_CENTER,$this); 711 }; 712 713 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT])) { 714 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT] =& 715 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT,$this); 716 }; 717 718 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER])) { 719 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER] =& 720 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER,$this); 721 }; 722 723 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM])) { 724 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM] =& 725 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM,$this); 726 }; 727 728 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER])) { 729 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER] =& 730 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER,$this); 731 }; 732 733 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT])) { 734 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT] =& 735 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT,$this); 736 }; 737 738 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER])) { 739 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER] =& 740 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER,$this); 741 }; 742 743 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT])) { 744 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT] =& 745 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT,$this); 746 }; 747 748 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER])) { 749 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER] =& 750 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER,$this); 751 }; 752 753 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_TOP])) { 754 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_TOP] =& 755 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_LEFT_TOP,$this); 756 }; 757 758 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE])) { 759 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE] =& 760 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE,$this); 761 }; 762 763 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM])) { 764 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM] =& 765 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM,$this); 766 }; 767 768 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP])) { 769 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP] =& 770 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP,$this); 771 }; 772 773 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE])) { 774 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE] =& 775 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE,$this); 776 }; 777 778 if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM])) { 779 $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM] =& 780 new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM,$this); 781 }; 782 783 return $applicable_margin_boxes; 784 } 785 786 function _process_item($data_id, &$media, $offset=0) { 787 $this->_dispatcher->fire('before-batch-item', array('pipeline' => &$this)); 788 789 $box =& $this->_layout_item($data_id, $media, $offset, $context, $postponed_filter); 790 791 if (is_null($box)) { 792 error_log(sprintf(_('Could not fetch: %s'), (string)$data_id)); 793 return true; 794 }; 795 796 $this->_show_item($box, $offset, $context, $media, $postponed_filter); 797 798 // Clear CSS for this item 799 $this->pop_css(); 800 $this->_defaultCSS = null; 801 802 // Memory leak fix: caused by circular references? 803 $box->destroy(); 804 805 $this->_dispatcher->fire('after-batch-item', array('pipeline' => &$this)); 806 return true; 807 } 808 809 function _show_item(&$box, $offset, &$context, &$media, &$postponed_filter) { 810 $context->sort_absolute_positioned_by_z_index(); 811 812 $this->_dispatcher->fire('before-page-heights', array('pipeline' => &$this, 813 'document' => &$box, 814 'media' => &$media)); 815 816 // Make batch-processing offset 817 $page_heights = $this->calculate_page_heights($media, $box); 818 $box->offset(0, $offset); 819 820 $box->reflow_anchors($this->output_driver, $this->output_driver->anchors, $page_heights); 821 822 $this->_dispatcher->fire('before-document', array('pipeline' => &$this, 823 'document' => &$box, 824 'page-heights' => &$page_heights, 825 'media' => &$media)); 826 827 $expected_pages = count($page_heights); 828 $this->output_driver->set_expected_pages($expected_pages); 829 $this->reset_counter('pages', $expected_pages); 830 $this->reset_counter('page', 0); 831 832 // Output PDF pages using chosen PDF driver 833 for ($i = 0; $i < $expected_pages; $i++) { 834 $this->get_page_media(1, $media); 835 836 $this->output_driver->update_media($media); 837 $this->_setupScales($media); 838 839 $current_page_offset = $i == 0 ? 0 : $page_heights[$i-1]; 840 $current_page_height = $page_heights[$i]; 841 842 $this->output_driver->next_page($current_page_offset); 843 844 // Preparen list of postponed (floating and relative-positioned) boxes for the current page 845 $postponed_filter->process($box, null, $this); 846 847 $this->reset_counter('footnote', 0); 848 $this->increment_counter('page', 1); 849 850 $this->output_driver->save(); 851 852 /** 853 * Note that margin boxes should be rendered before 'setup_clip', as it will trim all 854 * content rendered outside the 'main' page area 855 */ 856 $this->render_margin_boxes($i+1, $media); 857 $this->render_page_box($i+1, $media); 858 859 $this->output_driver->setPageHeight($current_page_height); 860 $this->output_driver->setup_clip(); 861 862 $this->_dispatcher->fire('before-page', array('pipeline' => &$this, 863 'document' => &$box, 864 'pageno' => $i)); 865 866 if (is_null($box->show($this->output_driver))) { 867 error_log('Pipeline::_process_item: output routine failed'); 868 return null; 869 }; 870 871 /** 872 * Show postponed boxes - relative and floating boxes, as they should be 873 * shown over boxes on the same layer 874 */ 875 $this->output_driver->show_postponed(); 876 877 $this->renderAbsolutePositioned($context); 878 $this->output_driver->restore(); 879 $this->renderFixedPositioned($context); 880 $this->renderFootnotes(); 881 882 global $g_config; 883 if ($g_config['draw_page_border']) { 884 $this->output_driver->draw_page_border(); 885 }; 886 887 $this->_dispatcher->fire('after-page', array('pipeline' => &$this, 888 'document' => &$box, 889 'pageno' => $i)); 890 }; 891 892 $this->_dispatcher->fire('after-document', array('pipeline' => &$this, 893 'document' => &$box)); 894 } 895 896 function _output() { 897 $temporary_output_filename = $this->output_driver->get_filename(); 898 899 for ($i=0; $i<count($this->output_filters); $i++) { 900 $temporary_output_filename = $this->output_filters[$i]->process($temporary_output_filename); 901 }; 902 903 // Determine the content type of the result 904 $content_type = null; 905 $i = count($this->output_filters)-1; 906 while (($i >= 0) && (is_null($content_type))) { 907 $content_type = $this->output_filters[$i]->content_type(); 908 $i--; 909 }; 910 911 if (is_null($content_type)) { 912 $content_type = $this->output_driver->content_type(); 913 }; 914 915 $this->destination->process($temporary_output_filename, $content_type); 916 unlink($temporary_output_filename); 917 } 918 919 function set_destination(&$destination) { 920 $this->destination =& $destination; 921 } 922 923 function set_output_driver(&$output_driver) { 924 $this->output_driver =& $output_driver; 925 } 926 927 function &fetch($data_id) { 928 if (count($this->fetchers) == 0) { 929 ob_start(); 930 include(HTML2PS_DIR.'templates/error._no_fetchers.tpl'); 931 $this->error_message = ob_get_contents(); 932 ob_end_clean(); 933 934 $null = null; 935 return $null; 936 }; 937 938 // Fetch data 939 for ($i=0; $i<count($this->fetchers); $i++) { 940 $data = $this->fetchers[$i]->get_data($data_id); 941 942 if ($data != null) { 943 $this->push_base_url($this->fetchers[$i]->get_base_url()); 944 return $data; 945 }; 946 }; 947 948 if (defined('DEBUG_MODE')) { 949 error_log(sprintf('Could not fetch %s', $data_id)); 950 }; 951 952 $null = null; 953 return $null; 954 } 955 956 function process($data_id, &$media) { 957 return $this->process_batch(array($data_id), $media); 958 } 959 960 function _setupScales(&$media) { 961 global $g_config; 962 global $g_px_scale; 963 global $g_pt_scale; 964 965 $g_px_scale = floor(mm2pt($media->width() - $media->margins['left'] - $media->margins['right'])) / $media->pixels; 966 967 if ($g_config['scalepoints']) { 968 $g_pt_scale = $g_px_scale * 1.33; // This is a magic number, just don't touch it, or everything will explode! 969 } else { 970 $g_pt_scale = 1.0; 971 }; 972 } 973 974 /** 975 * Processes an set of URLs ot once; every URL is rendered on the separate page and 976 * merged to one PDF file. 977 * 978 * Note: to reduce peak memory requirement, URLs are processed one-after-one. 979 * 980 * @param Array $data_id_array Array of page identifiers to be processed (usually URLs or files paths) 981 * @param Media $media Object describing the media to render for (size, margins, orientaiton & resolution) 982 */ 983 function process_batch($data_id_array, &$media) { 984 $this->clear_box_id_map(); 985 986 // Save and disable magic_quotes_runtime 987 $mq_runtime = get_magic_quotes_runtime(); 988 set_magic_quotes_runtime(0); 989 990 $this->_prepare($media); 991 992 $this->_dispatcher->fire('before-batch', array('pipeline' => &$this)); 993 994 $i = 0; 995 $offset = 0; 996 foreach ($data_id_array as $data_id) { 997 $this->_process_item($data_id, $media, $offset); 998 999 $i++; 1000 $offset = $this->output_driver->offset; 1001 }; 1002 1003 $this->close(); 1004 1005 // Restore magic_quotes_runtime setting 1006 set_magic_quotes_runtime($mq_runtime); 1007 1008 return true; 1009 } 1010 1011 function error_message() { 1012 $message = file_get_contents(HTML2PS_DIR.'templates/error._header.tpl'); 1013 1014 $message .= $this->error_message; 1015 1016 for ($i=0; $i<count($this->fetchers); $i++) { 1017 $message .= $this->fetchers[$i]->error_message(); 1018 }; 1019 1020 $message .= $this->output_driver->error_message(); 1021 1022 $message .= file_get_contents(HTML2PS_DIR.'templates/error._footer.tpl'); 1023 return $message; 1024 } 1025 1026 function push_base_url($url) { 1027 array_unshift($this->_base_url, $url); 1028 } 1029 1030 function pop_base_url() { 1031 array_shift($this->_base_url); 1032 } 1033 1034 function get_base_url() { 1035 return $this->_base_url[0]; 1036 } 1037 1038 function &get_output_driver() { 1039 return $this->output_driver; 1040 } 1041 1042 function guess_url($src) { 1043 return guess_url($src, $this->get_base_url()); 1044 } 1045 1046 function renderFootnotes() { 1047 /** 1048 * Render every footnote defined (note-call element is visible) on a current page 1049 */ 1050 1051 $footnote_y = $this->output_driver->getFootnoteTop() - FOOTNOTE_LINE_TOP_GAP - FOOTNOTE_LINE_BOTTOM_GAP; 1052 $footnote_x = $this->output_driver->getPageLeft(); 1053 $footnotes_found = false; 1054 1055 foreach ($this->_footnotes as $footnote) { 1056 // Note that footnote area for current page have been already defined, 1057 // as show_foonote is called after note-call boxes were placed. 1058 if ($this->output_driver->contains($footnote->_note_call_box)) { 1059 $footnotes_found = true; 1060 $footnote_y = $footnote->show_footnote($this->output_driver, 1061 $footnote_x, 1062 $footnote_y); 1063 $footnote_y -= FOOTNOTE_GAP; 1064 }; 1065 }; 1066 1067 /** 1068 * Draw thin line separating footnotes from page content 1069 */ 1070 if ($footnotes_found) { 1071 $this->output_driver->setrgbcolor(0,0,0); 1072 $this->output_driver->moveto($this->output_driver->getPageLeft(), 1073 $this->output_driver->getFootnoteTop() - FOOTNOTE_LINE_TOP_GAP); 1074 $this->output_driver->lineto($this->output_driver->getPageLeft() + $this->output_driver->getPageWidth()*FOOTNOTE_LINE_PERCENT/100, 1075 $this->output_driver->getFootnoteTop() - FOOTNOTE_LINE_TOP_GAP); 1076 $this->output_driver->stroke(); 1077 }; 1078 } 1079 1080 function renderAbsolutePositioned(&$context) { 1081 for ($j=0, $size = count($context->absolute_positioned); $j<$size; $j++) { 1082 $current_box =& $context->absolute_positioned[$j]; 1083 if ($current_box->get_css_property(CSS_VISIBILITY) === VISIBILITY_VISIBLE) { 1084 $this->output_driver->save(); 1085 $current_box->_setupClip($this->output_driver); 1086 if (is_null($current_box->show($this->output_driver))) { 1087 return null; 1088 }; 1089 $this->output_driver->restore(); 1090 }; 1091 }; 1092 $this->output_driver->show_postponed_in_absolute(); 1093 } 1094 1095 function renderFixedPositioned(&$context) { 1096 for ($j=0, $size = count($context->fixed_positioned); $j<$size; $j++) { 1097 $current_box =& $context->fixed_positioned[$j]; 1098 if ($current_box->get_css_property(CSS_VISIBILITY) === VISIBILITY_VISIBLE) { 1099 $this->output_driver->save(); 1100 $current_box->_setupClip($this->output_driver); 1101 if (is_null($current_box->show_fixed($this->output_driver))) { 1102 return null; 1103 }; 1104 $this->output_driver->restore(); 1105 }; 1106 }; 1107 $this->output_driver->show_postponed_in_fixed(); 1108 } 1109 1110 function _prepare(&$media) { 1111 $this->_setupScales($media); 1112 $GLOBALS['g_media'] =& $media; 1113 $this->output_driver->reset($media); 1114 } 1115 1116 function reset_css() { 1117 $css_cache = CSSCache::get(); 1118 $this->_defaultCSS = $css_cache->compile('resource://default.css', 1119 file_get_contents(HTML2PS_DIR.'default.css'), 1120 $this); 1121 $this->_css = array(); 1122 $this->push_css(); 1123 1124 $this->_cssState = array(new CSSState(CSS::get())); 1125 } 1126 1127 function &_layout_item($data_id, &$media, $offset, &$context, &$postponed_filter) { 1128 $this->_reset_page_at_rules(); 1129 1130 $this->reset_css(); 1131 1132 $font = $this->_cssState[0]->get_property(CSS_FONT); 1133 $font->units2pt(0); 1134 $this->_cssState[0]->set_property(CSS_FONT, $font); 1135 1136 $data = $this->fetch($data_id); 1137 1138 if (is_null($data)) { 1139 $dummy = null; 1140 return $dummy; 1141 }; 1142 1143 // Run raw data filters 1144 for ($i = 0; $i < count($this->data_filters); $i++) { 1145 $data = $this->data_filters[$i]->process($data); 1146 }; 1147 1148 // Parse the raw data 1149 $box =& $this->parser->process($data->get_content(), $this, $media); 1150 1151 $this->_dispatcher->fire('after-parse', array('pipeline' => &$this, 1152 'document' => &$box, 1153 'media' => $media)); 1154 1155 /** 1156 * Run obligatory tree filters 1157 */ 1158 1159 /** 1160 * height-constraint processing filter; 1161 */ 1162 $filter = new PreTreeFilterHeightConstraint(); 1163 $filter->process($box, $data, $this); 1164 1165 /** 1166 * Footnote support filter 1167 */ 1168 $filter = new PreTreeFilterFootnotes(); 1169 $filter->process($box, $data, $this); 1170 1171 // Run pre-layout tree filters 1172 for ($i=0, $size = count($this->pre_tree_filters); $i < $size; $i++) { 1173 $this->pre_tree_filters[$i]->process($box, $data, $this); 1174 }; 1175 1176 $context = new FlowContext; 1177 1178 /** 1179 * Extract absolute/fixed positioned boxes 1180 */ 1181 $positioned_filter = new PostTreeFilterPositioned($context); 1182 $positioned_filter->process($box, null, $this); 1183 1184 $postponed_filter = new PostTreeFilterPostponed($this->output_driver); 1185 $postponed_filter->process($box, null, $this); 1186 1187 $this->output_driver->prepare(); 1188 1189 // Force generation of custom characters for margin boxes 1190 for ($i = 0; $i <= 1; $i++) { 1191 $this->get_page_media(1, $media); 1192 $at_rules = $this->_getMarginBoxes($i, $media); 1193 1194 $boxes = array(); 1195 foreach ($at_rules as $at_rule) { 1196 $selector = $at_rule->getSelector(); 1197 $boxes[$selector] =& BoxPageMargin::create($this, $at_rule); 1198 }; 1199 }; 1200 1201 $status = $this->layout_engine->process($box, $media, $this->output_driver, $context); 1202 if (is_null($status)) { 1203 error_log('Pipeline::_process_item: layout routine failed'); 1204 $dummy = null; 1205 return $dummy; 1206 }; 1207 1208 // Run post-layout tree filters 1209 for ($i=0; $i<count($this->post_tree_filters); $i++) { 1210 $this->post_tree_filters[$i]->process($box); 1211 }; 1212 1213 return $box; 1214 } 1215 1216 function &getDispatcher() { 1217 return $this->_dispatcher; 1218 } 1219 1220 function get_current_page_name() { 1221 return $this->_current_page_name; 1222 } 1223 1224 function set_current_page_name($name) { 1225 $this->_current_page_name = $name; 1226 } 1227} 1228 1229?>