PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/pdf/pipeline.class.php

http://simpleinvoices.googlecode.com/
PHP | 1209 lines | 860 code | 238 blank | 111 comment | 71 complexity | 31c10b324d216eaf863c54b9269da7fb MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0, LGPL-3.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->_counters = array();
  258. $this->_footnotes = array();
  259. $this->_base_url = array('');
  260. $this->_reset_page_at_rules();
  261. $this->pre_tree_filters = array();
  262. $this->_dispatcher =& new Dispatcher();
  263. $this->_dispatcher->add_event('before-page-heights');
  264. $this->_dispatcher->add_event('before-page');
  265. $this->_dispatcher->add_event('after-page');
  266. $this->_dispatcher->add_event('before-batch-item');
  267. $this->_dispatcher->add_event('after-batch-item');
  268. $this->_dispatcher->add_event('after-parse');
  269. $this->_dispatcher->add_event('before-document');
  270. $this->_dispatcher->add_event('after-document');
  271. $this->_dispatcher->add_event('before-batch');
  272. $this->_dispatcher->add_event('after-batch');
  273. $this->_page_break_strategy = new StrategyPageBreakSimple();
  274. }
  275. function add_feature($feature_name, $params = array()) {
  276. $feature_object =& FeatureFactory::get($feature_name);
  277. if (is_null($feature_object)) {
  278. die(sprintf('No feature "%s" found', $feature_name));
  279. };
  280. $feature_object->install($this, $params);
  281. }
  282. function add_fetcher(&$fetcher) {
  283. array_unshift($this->fetchers, $fetcher);
  284. }
  285. function calculate_page_heights(&$media, &$box) {
  286. return $this->_page_break_strategy->run($this, $media, $box);
  287. }
  288. function clear_box_id_map() {
  289. $GLOBALS['__html_box_id_map'] = array();
  290. }
  291. function close() {
  292. $this->_dispatcher->fire('after-batch', array('pipeline' => &$this));
  293. $this->output_driver->close();
  294. $this->_output();
  295. $this->output_driver->release();
  296. // Non HTML-specific cleanup
  297. //
  298. Image::clear_cache();
  299. }
  300. function configure($options) {
  301. $defaults = array('compress' => false,
  302. 'cssmedia' => 'screen',
  303. 'debugbox' => false,
  304. 'debugnoclip' => false,
  305. 'draw_page_border' => false,
  306. 'encoding' => '',
  307. 'html2xhtml' => true,
  308. 'imagequality_workaround' => false,
  309. 'landscape' => false,
  310. 'margins' => array('left' => 30,
  311. 'right' => 15,
  312. 'top' => 15,
  313. 'bottom' => 15),
  314. 'media' => 'A4',
  315. 'method' => 'fpdf',
  316. 'mode' => 'html',
  317. 'output' => 0,
  318. 'pagewidth' => 800,
  319. 'pdfversion' => "1.2",
  320. 'ps2pdf' => false,
  321. 'pslevel' => 3,
  322. 'renderfields' => false,
  323. 'renderforms' => false,
  324. 'renderimages' => true,
  325. 'renderlinks' => false,
  326. 'scalepoints' => true,
  327. 'smartpagebreak' => true,
  328. 'transparency_workaround' => false
  329. );
  330. // As a reminder: If the input arrays have the same string keys, then the later value for that key will overwrite the previous one.
  331. $GLOBALS['g_config'] = array_merge($defaults, $options);
  332. // Note that CSS media names should be case-insensitive
  333. $GLOBALS['g_config']['cssmedia'] = strtolower($GLOBALS['g_config']['cssmedia']);
  334. if ($GLOBALS['g_config']['smartpagebreak']) {
  335. $this->_page_break_strategy = new StrategyPageBreakSmart();
  336. } else {
  337. $this->_page_break_strategy = new StrategyPageBreakSimple();
  338. };
  339. }
  340. function _addFootnote(&$note_call) {
  341. $this->_footnotes[] =& $note_call;
  342. }
  343. // function _fillContent($content) {
  344. // $filled = "";
  345. // while (preg_match("/^.*?('.*?'|\".*?\"|counter\(.*?\))(.*)$/", $content, $matches)) {
  346. // $data = $matches[1];
  347. // $content = $matches[2];
  348. // if ($data{0} != '\'' && $data{0} != '"') {
  349. // $filled .= $this->_fillContentCounter($data);
  350. // } else {
  351. // $filled .= $this->_fillContentString($data);
  352. // };
  353. // };
  354. // return $filled;
  355. // }
  356. // function _fillContentString($content) {
  357. // $unescaped_content = css_process_escapes($content);
  358. // $unquoted_content = css_remove_value_quotes($unescaped_content);
  359. // return $unquoted_content;
  360. // }
  361. // function _fillContentCounter($content) {
  362. // preg_match("/counter\((.*?)\)/", $content, $matches);
  363. // return $this->_getCounter($matches[1]);
  364. // }
  365. function &get_counters() {
  366. $counter_collection =& new CSSCounterCollection();
  367. foreach ($this->_counters as $counter_name => $counter_value) {
  368. $counter =& new CSSCounter($counter_name);
  369. $counter->set($counter_value);
  370. $counter_collection->add($counter);
  371. };
  372. return $counter_collection;
  373. }
  374. function &get_dispatcher() {
  375. return $this->_dispatcher;
  376. }
  377. function _getCounter($counter) {
  378. if (isset($this->_counters[$counter])) {
  379. return $this->_counters[$counter];
  380. };
  381. /**
  382. * CSS 2.1: Counters that are not in the scope of any
  383. * 'counter-reset', are assumed to have been reset to 0 by a
  384. * 'counter-reset' on the root element.
  385. */
  386. return 0;
  387. }
  388. function _resetCounter($counter, $value) {
  389. $this->_counters[$counter] = $value;
  390. }
  391. function _incrementCounter($counter, $value) {
  392. $this->_counters[$counter] += $value;
  393. }
  394. function add_at_rule_page($at_rule) {
  395. $selector =& $at_rule->getSelector();
  396. $type = $selector->get_type();
  397. $this->_page_at_rules[$type][] = $at_rule;
  398. }
  399. function _reset_page_at_rules() {
  400. $this->_page_at_rules = array(CSS_PAGE_SELECTOR_ALL => array(),
  401. CSS_PAGE_SELECTOR_FIRST => array(),
  402. CSS_PAGE_SELECTOR_LEFT => array(),
  403. CSS_PAGE_SELECTOR_RIGHT => array(),
  404. CSS_PAGE_SELECTOR_NAMED => array());
  405. }
  406. function &getDefaultCSS() {
  407. return $this->_defaultCSS;
  408. }
  409. function &getCurrentCSS() {
  410. return $this->_css[0];
  411. }
  412. function &getCurrentCSSState() {
  413. return $this->_cssState[0];
  414. }
  415. function pushCSS() {
  416. array_unshift($this->_css, new CSSRuleset());
  417. }
  418. function popCSS() {
  419. array_shift($this->_css);
  420. }
  421. /**
  422. * Note that different pages may define different margin boxes (for
  423. * example, left and right pages may have different headers). In
  424. * this case, we should process @page rules in order of their
  425. * specificity (no selector < :left / :right < :first) and extract
  426. * margin boxes to be drawn
  427. *
  428. * @param $page_no Integer current page index (1-based)
  429. * @param $media
  430. */
  431. function render_margin_boxes($page_no, &$media) {
  432. $boxes =& $this->reflow_margin_boxes($page_no, $media);
  433. foreach ($boxes as $selector => $box) {
  434. $boxes[$selector]->show($this->output_driver);
  435. };
  436. // Memleak fix
  437. for ($i=0, $size = count($boxes); $i < $size; $i++) {
  438. $boxes[$i]->destroy();
  439. };
  440. unset($boxes);
  441. }
  442. function get_page_media($page_no, &$media) {
  443. $page_rules =& $this->get_page_rules($page_no);
  444. $size_landscape = $page_rules->getPropertyValue(CSS_SIZE);
  445. if (!is_null($size_landscape)) {
  446. $media->set_width($size_landscape['size']['width']);
  447. $media->set_height($size_landscape['size']['height']);
  448. $media->set_landscape($size_landscape['landscape']);
  449. };
  450. $margins = $page_rules->getPropertyValue(CSS_MARGIN);
  451. if (!is_null($margins)) {
  452. $media->margins['left'] = $margins->left->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1);
  453. $media->margins['right'] = $margins->right->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1);
  454. $media->margins['top'] = $margins->top->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1);
  455. $media->margins['bottom'] = $margins->bottom->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1);
  456. };
  457. $left_margin = $page_rules->getPropertyValue(CSS_MARGIN_LEFT);
  458. if (!is_null($left_margin)) {
  459. $media->margins['left'] = $left_margin->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1);
  460. };
  461. $right_margin = $page_rules->getPropertyValue(CSS_MARGIN_RIGHT);
  462. if (!is_null($right_margin)) {
  463. $media->margins['right'] = $right_margin->calc(mm2pt($media->get_width())) / mm2pt(1) / pt2pt(1);
  464. };
  465. $top_margin = $page_rules->getPropertyValue(CSS_MARGIN_TOP);
  466. if (!is_null($top_margin)) {
  467. $media->margins['top'] = $top_margin->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1);
  468. };
  469. $bottom_margin = $page_rules->getPropertyValue(CSS_MARGIN_BOTTOM);
  470. if (!is_null($bottom_margin)) {
  471. $media->margins['bottom'] = $bottom_margin->calc(mm2pt($media->get_height())) / mm2pt(1) / pt2pt(1);
  472. };
  473. $pixels = $page_rules->getPropertyValue(CSS_HTML2PS_PIXELS);
  474. if (!is_null($pixels)) {
  475. $media->set_pixels($pixels);
  476. };
  477. }
  478. function &get_page_rules($page_no) {
  479. $collection =& new CSSPropertyCollection();
  480. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_ALL] as $rule) {
  481. $collection->merge($rule->css);
  482. };
  483. /**
  484. * Check which one of :right/:left selector is applicable (assuming that first page matches :right)
  485. */
  486. if ($page_no % 2 == 0) {
  487. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_LEFT] as $rule) {
  488. $collection->merge($rule->css);
  489. };
  490. } else {
  491. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_RIGHT] as $rule) {
  492. $collection->merge($rule->css);
  493. };
  494. };
  495. if ($page_no == 1) {
  496. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_FIRST] as $rule) {
  497. $collection->merge($rule->css);
  498. };
  499. };
  500. return $collection;
  501. }
  502. function &reflow_page_box($page_no, &$media) {
  503. $rules =& $this->get_page_rules($page_no);
  504. $box =& BoxPage::create($this, $rules);
  505. $box->reflow($media);
  506. return $box;
  507. }
  508. function render_page_box($page_no, &$media) {
  509. $box =& $this->reflow_page_box($page_no, $media);
  510. $box->show($this->output_driver);
  511. $box->destroy();
  512. unset($box);
  513. }
  514. function &reflow_margin_boxes($page_no, &$media) {
  515. $at_rules = $this->_getMarginBoxes($page_no, $media);
  516. $boxes = array();
  517. foreach ($at_rules as $at_rule) {
  518. $selector = $at_rule->getSelector();
  519. $boxes[$selector] =& BoxPageMargin::create($this, $at_rule);
  520. };
  521. foreach ($boxes as $selector => $box) {
  522. $linebox_started = false;
  523. $previous_whitespace = false;
  524. $boxes[$selector]->reflow_whitespace($linebox_started, $previous_whitespace);
  525. $boxes[$selector]->reflow_text($this->output_driver);
  526. };
  527. foreach ($boxes as $selector => $box) {
  528. $boxes[$selector]->reflow($this->output_driver,
  529. $media,
  530. $boxes);
  531. };
  532. return $boxes;
  533. }
  534. /**
  535. * Note that "+" operation on arrays will preserve existing elements; thus
  536. * we need to process @page rules in order of decreasing specificity
  537. *
  538. */
  539. function _getMarginBoxes($page_no, $media) {
  540. $applicable_margin_boxes = array();
  541. /**
  542. * Check if :first selector is applicable
  543. */
  544. if ($page_no == 1) {
  545. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_FIRST] as $rule) {
  546. $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes();
  547. };
  548. };
  549. /**
  550. * Check which one of :right/:left selector is applicable (assuming that first page matches :right)
  551. */
  552. if ($page_no % 2 == 0) {
  553. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_LEFT] as $rule) {
  554. $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes();
  555. };
  556. } else {
  557. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_RIGHT] as $rule) {
  558. $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes();
  559. };
  560. };
  561. /**
  562. * Extract margin boxes from plain @page rules
  563. */
  564. foreach ($this->_page_at_rules[CSS_PAGE_SELECTOR_ALL] as $rule) {
  565. $applicable_margin_boxes = $applicable_margin_boxes + $rule->getAtRuleMarginBoxes();
  566. };
  567. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP])) {
  568. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP] =&
  569. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP,$this);
  570. };
  571. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER])) {
  572. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER] =&
  573. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_LEFT_CORNER,$this);
  574. };
  575. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT])) {
  576. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_LEFT] =&
  577. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_LEFT,$this);
  578. };
  579. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_CENTER])) {
  580. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_CENTER] =&
  581. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_CENTER,$this);
  582. };
  583. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT])) {
  584. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT] =&
  585. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT,$this);
  586. };
  587. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER])) {
  588. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER] =&
  589. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_TOP_RIGHT_CORNER,$this);
  590. };
  591. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM])) {
  592. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM] =&
  593. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM,$this);
  594. };
  595. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER])) {
  596. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER] =&
  597. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT_CORNER,$this);
  598. };
  599. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT])) {
  600. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT] =&
  601. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_LEFT,$this);
  602. };
  603. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER])) {
  604. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER] =&
  605. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_CENTER,$this);
  606. };
  607. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT])) {
  608. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT] =&
  609. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT,$this);
  610. };
  611. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER])) {
  612. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER] =&
  613. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_BOTTOM_RIGHT_CORNER,$this);
  614. };
  615. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_TOP])) {
  616. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_TOP] =&
  617. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_LEFT_TOP,$this);
  618. };
  619. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE])) {
  620. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE] =&
  621. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_LEFT_MIDDLE,$this);
  622. };
  623. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM])) {
  624. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM] =&
  625. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_LEFT_BOTTOM,$this);
  626. };
  627. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP])) {
  628. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP] =&
  629. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_RIGHT_TOP,$this);
  630. };
  631. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE])) {
  632. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE] =&
  633. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_RIGHT_MIDDLE,$this);
  634. };
  635. if (!isset($applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM])) {
  636. $applicable_margin_boxes[CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM] =&
  637. new CSSAtRuleMarginBox(CSS_MARGIN_BOX_SELECTOR_RIGHT_BOTTOM,$this);
  638. };
  639. return $applicable_margin_boxes;
  640. }
  641. function _process_item($data_id, &$media, $offset=0) {
  642. $this->_dispatcher->fire('before-batch-item', array('pipeline' => &$this));
  643. $box =& $this->_layout_item($data_id, $media, $offset, $context, $postponed_filter);
  644. if (is_null($box)) {
  645. error_log(sprintf(_('Could not fetch: %s'), (string)$data_id));
  646. return true;
  647. };
  648. $this->_show_item($box, $offset, $context, $media, $postponed_filter);
  649. // Clear CSS for this item
  650. $this->popCSS();
  651. $this->_defaultCSS = null;
  652. // Memory leak fix: caused by circular references?
  653. $box->destroy();
  654. $this->_dispatcher->fire('after-batch-item', array('pipeline' => &$this));
  655. return true;
  656. }
  657. function _show_item(&$box, $offset, &$context, &$media, &$postponed_filter) {
  658. $context->sort_absolute_positioned_by_z_index();
  659. $this->_dispatcher->fire('before-page-heights', array('pipeline' => &$this,
  660. 'document' => &$box,
  661. 'media' => &$media));
  662. // Make batch-processing offset
  663. $page_heights = $this->calculate_page_heights($media, $box);
  664. $box->offset(0, $offset);
  665. $box->reflow_anchors($this->output_driver, $this->output_driver->anchors, $page_heights);
  666. $this->_dispatcher->fire('before-document', array('pipeline' => &$this,
  667. 'document' => &$box,
  668. 'page-heights' => &$page_heights,
  669. 'media' => &$media));
  670. $expected_pages = count($page_heights);
  671. $this->output_driver->set_expected_pages($expected_pages);
  672. $this->_resetCounter('pages', $expected_pages);
  673. $this->_resetCounter('page', 0);
  674. // Output PDF pages using chosen PDF driver
  675. for ($i=0; $i<$expected_pages; $i++) {
  676. $this->get_page_media(1, $media);
  677. $this->output_driver->update_media($media);
  678. $this->_setupScales($media);
  679. $current_page_offset = $i == 0 ? 0 : $page_heights[$i-1];
  680. $current_page_height = $page_heights[$i];
  681. $this->output_driver->next_page($current_page_offset);
  682. // Preparen list of postponed (floating and relative-positioned) boxes for the current page
  683. $postponed_filter->process($box, null, $this);
  684. $this->_resetCounter('footnote', 0);
  685. $this->_incrementCounter('page', 1);
  686. $this->output_driver->save();
  687. /**
  688. * Note that margin boxes should be rendered before 'setup_clip', as it will trim all
  689. * content rendered outside the 'main' page area
  690. */
  691. $this->render_margin_boxes($i+1, $media);
  692. $this->render_page_box($i+1, $media);
  693. $this->output_driver->setPageHeight($current_page_height);
  694. $this->output_driver->setup_clip();
  695. $this->_dispatcher->fire('before-page', array('pipeline' => &$this,
  696. 'document' => &$box,
  697. 'pageno' => $i));
  698. if (is_null($box->show($this->output_driver))) {
  699. error_log('Pipeline::_process_item: output routine failed');
  700. return null;
  701. };
  702. /**
  703. * Show postponed boxes - relative and floating boxes, as they should be
  704. * shown over boxes on the same layer
  705. */
  706. $this->output_driver->show_postponed();
  707. $this->renderAbsolutePositioned($context);
  708. $this->output_driver->restore();
  709. $this->renderFixedPositioned($context);
  710. $this->renderFootnotes();
  711. global $g_config;
  712. if ($g_config['draw_page_border']) {
  713. $this->output_driver->draw_page_border();
  714. };
  715. $this->_dispatcher->fire('after-page', array('pipeline' => &$this,
  716. 'document' => &$box,
  717. 'pageno' => $i));
  718. };
  719. $this->_dispatcher->fire('after-document', array('pipeline' => &$this,
  720. 'document' => &$box));
  721. }
  722. function _output() {
  723. $temporary_output_filename = $this->output_driver->get_filename();
  724. for ($i=0; $i<count($this->output_filters); $i++) {
  725. $temporary_output_filename = $this->output_filters[$i]->process($temporary_output_filename);
  726. };
  727. // Determine the content type of the result
  728. $content_type = null;
  729. $i = count($this->output_filters)-1;
  730. while (($i >= 0) && (is_null($content_type))) {
  731. $content_type = $this->output_filters[$i]->content_type();
  732. $i--;
  733. };
  734. if (is_null($content_type)) {
  735. $content_type = $this->output_driver->content_type();
  736. };
  737. $this->destination->process($temporary_output_filename, $content_type);
  738. unlink($temporary_output_filename);
  739. }
  740. function set_destination(&$destination) {
  741. $this->destination =& $destination;
  742. }
  743. function set_output_driver(&$output_driver) {
  744. $this->output_driver =& $output_driver;
  745. }
  746. function &fetch($data_id) {
  747. if (count($this->fetchers) == 0) {
  748. ob_start();
  749. include(HTML2PS_DIR.'/templates/error._no_fetchers.tpl');
  750. $this->error_message = ob_get_contents();
  751. ob_end_clean();
  752. return null;
  753. };
  754. // Fetch data
  755. for ($i=0; $i<count($this->fetchers); $i++) {
  756. $data = $this->fetchers[$i]->get_data($data_id);
  757. if ($data != null) {
  758. $this->push_base_url($this->fetchers[$i]->get_base_url());
  759. return $data;
  760. };
  761. };
  762. if (defined('DEBUG_MODE')) {
  763. error_log(sprintf('Could not fetch %s', $data_id));
  764. };
  765. $null = null;
  766. return $null;
  767. }
  768. function process($data_id, &$media) {
  769. return $this->process_batch(array($data_id), $media);
  770. }
  771. function _setupScales(&$media) {
  772. global $g_config;
  773. global $g_px_scale;
  774. global $g_pt_scale;
  775. $g_px_scale = floor(mm2pt($media->width() - $media->margins['left'] - $media->margins['right'])) / $media->pixels;
  776. if ($g_config['scalepoints']) {
  777. $g_pt_scale = $g_px_scale * 1.33; // This is a magic number, just don't touch it, or everything will explode!
  778. } else {
  779. $g_pt_scale = 1.0;
  780. };
  781. }
  782. /**
  783. * Processes an set of URLs ot once; every URL is rendered on the separate page and
  784. * merged to one PDF file.
  785. *
  786. * Note: to reduce peak memory requirement, URLs are processed one-after-one.
  787. *
  788. * @param Array $data_id_array Array of page identifiers to be processed (usually URLs or files paths)
  789. * @param Media $media Object describing the media to render for (size, margins, orientaiton & resolution)
  790. */
  791. function process_batch($data_id_array, &$media) {
  792. $this->clear_box_id_map();
  793. // Save and disable magic_quotes_runtime
  794. $mq_runtime = get_magic_quotes_runtime();
  795. set_magic_quotes_runtime(0);
  796. $this->_prepare($media);
  797. $this->_dispatcher->fire('before-batch', array('pipeline' => &$this));
  798. $i = 0;
  799. $offset = 0;
  800. foreach ($data_id_array as $data_id) {
  801. $this->_process_item($data_id, $media, $offset);
  802. $i++;
  803. $offset = $this->output_driver->offset;
  804. };
  805. $this->close();
  806. // Restore magic_quotes_runtime setting
  807. set_magic_quotes_runtime($mq_runtime);
  808. return true;
  809. }
  810. function error_message() {
  811. $message = file_get_contents(HTML2PS_DIR.'/templates/error._header.tpl');
  812. $message .= $this->error_message;
  813. for ($i=0; $i<count($this->fetchers); $i++) {
  814. $message .= $this->fetchers[$i]->error_message();
  815. };
  816. $message .= $this->output_driver->error_message();
  817. $message .= file_get_contents(HTML2PS_DIR.'/templates/error._footer.tpl');
  818. return $message;
  819. }
  820. function push_base_url($url) {
  821. array_unshift($this->_base_url, $url);
  822. }
  823. function pop_base_url() {
  824. array_shift($this->_base_url);
  825. }
  826. function get_base_url() {
  827. return $this->_base_url[0];
  828. }
  829. function &get_output_driver() {
  830. return $this->output_driver;
  831. }
  832. function guess_url($src) {
  833. return guess_url($src, $this->get_base_url());
  834. }
  835. function renderFootnotes() {
  836. /**
  837. * Render every footnote defined (note-call element is visible) on a current page
  838. */
  839. $footnote_y = $this->output_driver->getFootnoteTop() - FOOTNOTE_LINE_TOP_GAP - FOOTNOTE_LINE_BOTTOM_GAP;
  840. $footnote_x = $this->output_driver->getPageLeft();
  841. $footnotes_found = false;
  842. foreach ($this->_footnotes as $footnote) {
  843. // Note that footnote area for current page have been already defined,
  844. // as show_foonote is called after note-call boxes were placed.
  845. if ($this->output_driver->contains($footnote->_note_call_box)) {
  846. $footnotes_found = true;
  847. $footnote_y = $footnote->show_footnote($this->output_driver,
  848. $footnote_x,
  849. $footnote_y);
  850. $footnote_y -= FOOTNOTE_GAP;
  851. };
  852. };
  853. /**
  854. * Draw thin line separating footnotes from page content
  855. */
  856. if ($footnotes_found) {
  857. $this->output_driver->setrgbcolor(0,0,0);
  858. $this->output_driver->moveto($this->output_driver->getPageLeft(),
  859. $this->output_driver->getFootnoteTop() - FOOTNOTE_LINE_TOP_GAP);
  860. $this->output_driver->lineto($this->output_driver->getPageLeft() + $this->output_driver->getPageWidth()*FOOTNOTE_LINE_PERCENT/100,
  861. $this->output_driver->getFootnoteTop() - FOOTNOTE_LINE_TOP_GAP);
  862. $this->output_driver->stroke();
  863. };
  864. }
  865. function renderAbsolutePositioned(&$context) {
  866. for ($j=0, $size = count($context->absolute_positioned); $j<$size; $j++) {
  867. $current_box =& $context->absolute_positioned[$j];
  868. if ($current_box->getCSSProperty(CSS_VISIBILITY) === VISIBILITY_VISIBLE) {
  869. $this->output_driver->save();
  870. $current_box->_setupClip($this->output_driver);
  871. if (is_null($current_box->show($this->output_driver))) {
  872. return null;
  873. };
  874. $this->output_driver->restore();
  875. };
  876. };
  877. $this->output_driver->show_postponed_in_absolute();
  878. }
  879. function renderFixedPositioned(&$context) {
  880. for ($j=0, $size = count($context->fixed_positioned); $j<$size; $j++) {
  881. $current_box =& $context->fixed_positioned[$j];
  882. if ($current_box->getCSSProperty(CSS_VISIBILITY) === VISIBILITY_VISIBLE) {
  883. $this->output_driver->save();
  884. $current_box->_setupClip($this->output_driver);
  885. if (is_null($current_box->show_fixed($this->output_driver))) {
  886. return null;
  887. };
  888. $this->output_driver->restore();
  889. };
  890. };
  891. $this->output_driver->show_postponed_in_fixed();
  892. }
  893. function _prepare(&$media) {
  894. $this->_setupScales($media);
  895. $GLOBALS['g_media'] =& $media;
  896. $this->output_driver->reset($media);
  897. }
  898. function &_layout_item($data_id, &$media, $offset, &$context, &$postponed_filter) {
  899. $this->_reset_page_at_rules();
  900. $css_cache = CSSCache::get();
  901. $this->_defaultCSS = $css_cache->compile('resource://default.css',
  902. file_get_contents(HTML2PS_DIR.'/default.css'));
  903. $this->_css = array();
  904. $this->pushCSS();
  905. $this->_cssState = array(new CSSState(CSS::get()));
  906. $font = $this->_cssState[0]->getProperty(CSS_FONT);
  907. $font->units2pt(0);
  908. $this->_cssState[0]->setProperty(CSS_FONT, $font);
  909. $data = $this->fetch($data_id);
  910. if (is_null($data)) {
  911. $dummy = null;
  912. return $dummy;
  913. };
  914. // Run raw data filters
  915. for ($i=0; $i<count($this->data_filters); $i++) {
  916. $data = $this->data_filters[$i]->process($data);
  917. };
  918. // Parse the raw data
  919. $box =& $this->parser->process($data->get_content(), $this, $media);
  920. $this->_dispatcher->fire('after-parse', array('pipeline' => &$this,
  921. 'document' => &$box,
  922. 'media' => $media));
  923. /**
  924. * Run obligatory tree filters
  925. */
  926. /**
  927. * height-constraint processing filter;
  928. */
  929. $filter = new PreTreeFilterHeightConstraint();
  930. $filter->process($box, $data, $this);
  931. /**
  932. * Footnote support filter
  933. */
  934. $filter = new PreTreeFilterFootnotes();
  935. $filter->process($box, $data, $this);
  936. // Run pre-layout tree filters
  937. for ($i=0, $size = count($this->pre_tree_filters); $i < $size; $i++) {
  938. $this->pre_tree_filters[$i]->process($box, $data, $this);
  939. };
  940. $context = new FlowContext;
  941. /**
  942. * Extract absolute/fixed positioned boxes
  943. */
  944. $positioned_filter = new PostTreeFilterPositioned($context);
  945. $positioned_filter->process($box, null, $this);
  946. $postponed_filter = new PostTreeFilterPostponed($this->output_driver);
  947. $postponed_filter->process($box, null, $this);
  948. $this->output_driver->prepare();
  949. $status = $this->layout_engine->process($box, $media, $this->output_driver, $context);
  950. if (is_null($status)) {
  951. error_log('Pipeline::_process_item: layout routine failed');
  952. $dummy = null;
  953. return $dummy;
  954. };
  955. // Run post-layout tree filters
  956. for ($i=0; $i<count($this->post_tree_filters); $i++) {
  957. $this->post_tree_filters[$i]->process($box);
  958. };
  959. return $box;
  960. }
  961. function &getDispatcher() {
  962. return $this->_dispatcher;
  963. }
  964. function get_current_page_name() {
  965. return $this->_current_page_name;
  966. }
  967. function set_current_page_name($name) {
  968. $this->_current_page_name = $name;
  969. }
  970. }
  971. ?>