PageRenderTime 67ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/pdf/html2ps/pipeline.class.php

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