PageRenderTime 832ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/app/vendors/pipeline.class.php

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