/html2pdf.class.php

https://github.com/aotd1/html2pdf · PHP · 6610 lines · 3927 code · 984 blank · 1699 comment · 752 complexity · cf9fafffcd82c2501c9376be98100fcf MD5 · raw file

  1. <?php
  2. /**
  3. * HTML2PDF Librairy - main class
  4. *
  5. * HTML => PDF convertor
  6. * distributed under the LGPL License
  7. *
  8. * @author Laurent MINGUET <webmaster@html2pdf.fr>
  9. * @version 4.03
  10. */
  11. if (!defined('__CLASS_HTML2PDF__')) {
  12. define('__CLASS_HTML2PDF__', '4.03');
  13. define('HTML2PDF_USED_TCPDF_VERSION', '5.9.206');
  14. require_once(dirname(__FILE__).'/_class/exception.class.php');
  15. require_once(dirname(__FILE__).'/_class/locale.class.php');
  16. require_once(dirname(__FILE__).'/_class/myPdf.class.php');
  17. require_once(dirname(__FILE__).'/_class/parsingHtml.class.php');
  18. require_once(dirname(__FILE__).'/_class/parsingCss.class.php');
  19. class HTML2PDF
  20. {
  21. /**
  22. * HTML2PDF_myPdf object, extends from TCPDF
  23. * @var HTML2PDF_myPdf
  24. */
  25. public $pdf = null;
  26. /**
  27. * CSS parsing
  28. * @var HTML2PDF_parsingCss
  29. */
  30. public $parsingCss = null;
  31. /**
  32. * HTML parsing
  33. * @var HTML2PDF_parsingHtml
  34. */
  35. public $parsingHtml = null;
  36. protected $_langue = 'fr'; // locale of the messages
  37. protected $_orientation = 'P'; // page orientation : Portrait ou Landscape
  38. protected $_format = 'A4'; // page format : A4, A3, ...
  39. protected $_encoding = ''; // charset encoding
  40. protected $_unicode = true; // means that the input text is unicode (default = true)
  41. protected $_testTdInOnepage = true; // test of TD that can not take more than one page
  42. protected $_testIsImage = true; // test if the images exist or not
  43. protected $_testIsDeprecated = false; // test the deprecated functions
  44. protected $_parsePos = 0; // position in the parsing
  45. protected $_tempPos = 0; // temporary position for complex table
  46. protected $_page = 0; // current page number
  47. protected $_subHtml = null; // sub html
  48. protected $_subPart = false; // sub HTML2PDF
  49. protected $_subHEADER = array(); // sub action to make the header
  50. protected $_subFOOTER = array(); // sub action to make the footer
  51. protected $_subSTATES = array(); // array to save some parameters
  52. protected $_isSubPart = false; // flag : in a sub html2pdf
  53. protected $_isInThead = false; // flag : in a thead
  54. protected $_isInTfoot = false; // flag : in a tfoot
  55. protected $_isInOverflow = false; // flag : in a overflow
  56. protected $_isInFooter = false; // flag : in a footer
  57. protected $_isInDraw = null; // flag : in a draw (svg)
  58. protected $_isAfterFloat = false; // flag : is just after a float
  59. protected $_isInForm = false; // flag : is in a float. false / action of the form
  60. protected $_isInLink = ''; // flag : is in a link. empty / href of the link
  61. protected $_isInParagraph = false; // flag : is in a paragraph
  62. protected $_isForOneLine = false; // flag : in a specific sub html2pdf to have the height of the next line
  63. protected $_maxX = 0; // maximum X of the current zone
  64. protected $_maxY = 0; // maximum Y of the current zone
  65. protected $_maxE = 0; // number of elements in the current zone
  66. protected $_maxH = 0; // maximum height of the line in the current zone
  67. protected $_maxSave = array(); // save the maximums of the current zone
  68. protected $_currentH = 0; // height of the current line
  69. protected $_defaultLeft = 0; // default marges of the page
  70. protected $_defaultTop = 0;
  71. protected $_defaultRight = 0;
  72. protected $_defaultBottom = 0;
  73. protected $_defaultFont = null; // default font to use, is the asked font does not exist
  74. protected $_margeLeft = 0; // current marges of the page
  75. protected $_margeTop = 0;
  76. protected $_margeRight = 0;
  77. protected $_margeBottom = 0;
  78. protected $_marges = array(); // save the different marges of the current page
  79. protected $_pageMarges = array(); // float marges of the current page
  80. protected $_background = array(); // background informations
  81. protected $_firstPage = true; // flag : first page
  82. protected $_defList = array(); // table to save the stats of the tags UL and OL
  83. protected $_lstAnchor = array(); // list of the anchors
  84. protected $_lstField = array(); // list of the fields
  85. protected $_lstSelect = array(); // list of the options of the current select
  86. protected $_previousCall = null; // last action called
  87. protected $_debugActif = false; // flag : mode debug is active
  88. protected $_debugOkUsage = false; // flag : the function memory_get_usage exist
  89. protected $_debugOkPeak = false; // flag : the function memory_get_peak_usage exist
  90. protected $_debugLevel = 0; // level in the debug
  91. protected $_debugStartTime = 0; // debug start time
  92. protected $_debugLastTime = 0; // debug stop time
  93. static protected $_subobj = null; // object html2pdf prepared in order to accelerate the creation of sub html2pdf
  94. static protected $_tables = array(); // static table to prepare the nested html tables
  95. /**
  96. * class constructor
  97. *
  98. * @access public
  99. * @param string $orientation page orientation, same as TCPDF
  100. * @param mixed $format The format used for pages, same as TCPDF
  101. * @param $tring $langue Langue : fr, en, it...
  102. * @param boolean $unicode TRUE means that the input text is unicode (default = true)
  103. * @param String $encoding charset encoding; default is UTF-8
  104. * @param array $marges Default marges (left, top, right, bottom)
  105. * @return HTML2PDF $this
  106. */
  107. public function __construct($orientation = 'P', $format = 'A4', $langue='fr', $unicode=true, $encoding='UTF-8', $marges = array(5, 5, 5, 8))
  108. {
  109. // init the page number
  110. $this->_page = 0;
  111. $this->_firstPage = true;
  112. $this->_firstPageInSet = array();
  113. $this->_isCalculationPass = true;
  114. $this->_rootPathForURLs = '';
  115. // save the parameters
  116. $this->_orientation = $orientation;
  117. $this->_format = $format;
  118. $this->_langue = strtolower($langue);
  119. $this->_unicode = $unicode;
  120. $this->_encoding = $encoding;
  121. // load the Local
  122. HTML2PDF_locale::load($this->_langue);
  123. // create the HTML2PDF_myPdf object
  124. $this->pdf = new HTML2PDF_myPdf($orientation, 'mm', $format, $unicode, $encoding);
  125. // init the CSS parsing object
  126. $this->parsingCss = new HTML2PDF_parsingCss($this->pdf);
  127. $this->parsingCss->fontSet();
  128. $this->_defList = array();
  129. // init some tests
  130. $this->setTestTdInOnePage(true);
  131. $this->setTestIsImage(true);
  132. $this->setTestIsDeprecated(true);
  133. // init the default font
  134. $this->setDefaultFont(null);
  135. // init the HTML parsing object
  136. $this->parsingHtml = new HTML2PDF_parsingHtml($this->_encoding);
  137. $this->_subHtml = null;
  138. $this->_subPart = false;
  139. // init the marges of the page
  140. if (!is_array($marges)) $marges = array($marges, $marges, $marges, $marges);
  141. $this->_setDefaultMargins($marges[0], $marges[1], $marges[2], $marges[3]);
  142. $this->_setMargins();
  143. $this->_marges = array();
  144. // init the form's fields
  145. $this->_lstField = array();
  146. return $this;
  147. }
  148. /**
  149. * Destructor
  150. *
  151. * @access public
  152. * @return null
  153. */
  154. public function __destruct()
  155. {
  156. }
  157. /**
  158. * Clone to create a sub HTML2PDF from HTML2PDF::$_subobj
  159. *
  160. * @access public
  161. */
  162. public function __clone()
  163. {
  164. $this->pdf = clone $this->pdf;
  165. $this->parsingHtml = clone $this->parsingHtml;
  166. $this->parsingCss = clone $this->parsingCss;
  167. $this->parsingCss->setPdfParent($this->pdf);
  168. }
  169. /**
  170. * set the debug mode to On
  171. *
  172. * @access public
  173. * @return HTML2PDF $this
  174. */
  175. public function setModeDebug()
  176. {
  177. $time = microtime(true);
  178. $this->_debugActif = true;
  179. $this->_debugOkUsage = function_exists('memory_get_usage');
  180. $this->_debugOkPeak = function_exists('memory_get_peak_usage');
  181. $this->_debugStartTime = $time;
  182. $this->_debugLastTime = $time;
  183. $this->_DEBUG_stepline('step', 'time', 'delta', 'memory', 'peak');
  184. $this->_DEBUG_add('Init debug');
  185. return $this;
  186. }
  187. /**
  188. * Set the test of TD thdat can not take more than one page
  189. *
  190. * @access public
  191. * @param boolean $mode
  192. * @return HTML2PDF $this
  193. */
  194. public function setTestTdInOnePage($mode = true)
  195. {
  196. $this->_testTdInOnepage = $mode ? true : false;
  197. return $this;
  198. }
  199. /**
  200. * Set the test if the images exist or not
  201. *
  202. * @access public
  203. * @param boolean $mode
  204. * @return HTML2PDF $this
  205. */
  206. public function setTestIsImage($mode = true)
  207. {
  208. $this->_testIsImage = $mode ? true : false;
  209. return $this;
  210. }
  211. /**
  212. * Set the test on deprecated functions
  213. *
  214. * @access public
  215. * @param boolean $mode
  216. * @return HTML2PDF $this
  217. */
  218. public function setTestIsDeprecated($mode = true)
  219. {
  220. $this->_testIsDeprecated = $mode ? true : false;
  221. return $this;
  222. }
  223. /**
  224. * Set the default font to use, if no font is specify, or if the asked font does not exist
  225. *
  226. * @access public
  227. * @param string $default name of the default font to use. If null : Arial is no font is specify, and error if the asked font does not exist
  228. * @return HTML2PDF $this
  229. */
  230. public function setDefaultFont($default = null)
  231. {
  232. $this->_defaultFont = $default;
  233. $this->parsingCss->setDefaultFont($default);
  234. return $this;
  235. }
  236. /**
  237. * add a font, see TCPDF function addFont
  238. *
  239. * @access public
  240. * @param string $family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font.
  241. * @param string $style Font style. Possible values are (case insensitive):<ul><li>empty string: regular (default)</li><li>B: bold</li><li>I: italic</li><li>BI or IB: bold italic</li></ul>
  242. * @param string $fontfile The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
  243. * @return HTML2PDF $this
  244. * @see TCPDF::addFont
  245. */
  246. public function addFont($family, $style='', $file='')
  247. {
  248. $this->pdf->AddFont($family, $style, $file);
  249. return $this;
  250. }
  251. /**
  252. * display a automatic index, from the bookmarks
  253. *
  254. * @access public
  255. * @param string $titre index title
  256. * @param int $sizeTitle font size of the index title, in mm
  257. * @param int $sizeBookmark font size of the index, in mm
  258. * @param boolean $bookmarkTitle add a bookmark for the index, at his beginning
  259. * @param boolean $displayPage display the page numbers
  260. * @param int $onPage if null : at the end of the document on a new page, else on the $onPage page
  261. * @param string $fontName font name to use
  262. * @return null
  263. */
  264. public function createIndex($titre = 'Index', $sizeTitle = 20, $sizeBookmark = 15, $bookmarkTitle = true, $displayPage = true, $onPage = null, $fontName = 'helvetica')
  265. {
  266. $oldPage = $this->_INDEX_NewPage($onPage);
  267. $this->pdf->createIndex($this, $titre, $sizeTitle, $sizeBookmark, $bookmarkTitle, $displayPage, $onPage, $fontName);
  268. if ($oldPage) $this->pdf->setPage($oldPage);
  269. }
  270. /**
  271. * clean up the objects
  272. *
  273. * @access protected
  274. */
  275. protected function _cleanUp()
  276. {
  277. HTML2PDF::$_subobj = null;
  278. HTML2PDF::$_tables = array();
  279. }
  280. /**
  281. * Send the document to a given destination: string, local file or browser.
  282. * Dest can be :
  283. * I : send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.
  284. * D : send to the browser and force a file download with the name given by name.
  285. * F : save to a local server file with the name given by name.
  286. * S : return the document as a string. name is ignored.
  287. * FI: equivalent to F + I option
  288. * FD: equivalent to F + D option
  289. * true => I
  290. * false => S
  291. *
  292. * @param string $name The name of the file when saved.
  293. * @param string $dest Destination where to send the document.
  294. * @return string content of the PDF, if $dest=S
  295. * @see TCPDF::close
  296. * @access public
  297. */
  298. public function Output($name = '', $dest = false)
  299. {
  300. // close the pdf and clean up
  301. $this->_cleanUp();
  302. // if on debug mode
  303. if ($this->_debugActif) {
  304. $this->_DEBUG_add('Before output');
  305. $this->pdf->Close();
  306. exit;
  307. }
  308. // complete parameters
  309. if ($dest===false) $dest = 'I';
  310. if ($dest===true) $dest = 'S';
  311. if ($dest==='') $dest = 'I';
  312. if ($name=='') $name='document.pdf';
  313. // clean up the destination
  314. $dest = strtoupper($dest);
  315. if (!in_array($dest, array('I', 'D', 'F', 'S', 'FI','FD'))) $dest = 'I';
  316. // the name must be a PDF name
  317. if (strtolower(substr($name, -4))!='.pdf') {
  318. throw new HTML2PDF_exception(0, 'The output document name "'.$name.'" is not a PDF name');
  319. }
  320. // call the output of TCPDF
  321. return $this->pdf->Output($name, $dest);
  322. }
  323. /**
  324. * convert HTML to PDF
  325. *
  326. * @access public
  327. * @param string $html
  328. * @param boolean $debugVue enable the HTML debug vue
  329. * @return null
  330. */
  331. public function writeHTML($html, $debugVue = false)
  332. {
  333. // if it is a real html page, we have to convert it
  334. if (preg_match('/<body/isU', $html))
  335. $html = $this->getHtmlFromPage($html);
  336. $html = str_replace('[[date_y]]', date('Y'), $html);
  337. $html = str_replace('[[date_m]]', date('m'), $html);
  338. $html = str_replace('[[date_d]]', date('d'), $html);
  339. $html = str_replace('[[date_h]]', date('H'), $html);
  340. $html = str_replace('[[date_i]]', date('i'), $html);
  341. $html = str_replace('[[date_s]]', date('s'), $html);
  342. // If we are in HTML debug vue : display the HTML
  343. if ($debugVue) {
  344. return $this->_vueHTML($html);
  345. }
  346. // convert HTMl to PDF
  347. $this->parsingCss->readStyle($html);
  348. $this->parsingHtml->setHTML($html);
  349. $this->parsingHtml->parse();
  350. $this->_makeHTMLcode();
  351. }
  352. /**
  353. * convert the HTML of a real page, to a code adapted to HTML2PDF
  354. *
  355. * @access public
  356. * @param string HTML of a real page
  357. * @return string HTML adapted to HTML2PDF
  358. */
  359. public function getHtmlFromPage($html)
  360. {
  361. $html = str_replace('<BODY', '<body', $html);
  362. $html = str_replace('</BODY', '</body', $html);
  363. // extract the content
  364. $res = explode('<body', $html);
  365. if (count($res)<2) return $html;
  366. $content = '<page'.$res[1];
  367. $content = explode('</body', $content);
  368. $content = $content[0].'</page>';
  369. // extract the link tags
  370. preg_match_all('/<link([^>]*)>/isU', $html, $match);
  371. foreach ($match[0] as $src)
  372. $content = $src.'</link>'.$content;
  373. // extract the css style tags
  374. preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match);
  375. foreach ($match[0] as $src)
  376. $content = $src.$content;
  377. return $content;
  378. }
  379. /**
  380. * init a sub HTML2PDF. does not use it directly. Only the method createSubHTML must use it
  381. *
  382. * @access public
  383. * @param string $format
  384. * @param string $orientation
  385. * @param array $marge
  386. * @param integer $page
  387. * @param array $defLIST
  388. * @param integer $myLastPageGroup
  389. * @param integer $myLastPageGroupNb
  390. */
  391. public function initSubHtml($format, $orientation, $marge, $page, $defLIST, $myLastPageGroup, $myLastPageGroupNb)
  392. {
  393. $this->_isSubPart = true;
  394. $this->parsingCss->setOnlyLeft();
  395. $this->_setNewPage($format, $orientation, null, null, ($myLastPageGroup!==null));
  396. $this->_saveMargin(0, 0, $marge);
  397. $this->_defList = $defLIST;
  398. $this->_page = $page;
  399. $this->pdf->setMyLastPageGroup($myLastPageGroup);
  400. $this->pdf->setMyLastPageGroupNb($myLastPageGroupNb);
  401. $this->pdf->setXY(0, 0);
  402. $this->parsingCss->fontSet();
  403. }
  404. /**
  405. * display the content in HTML moden for debug
  406. *
  407. * @access protected
  408. * @param string $contenu
  409. */
  410. protected function _vueHTML($content)
  411. {
  412. $content = preg_replace('/<page_header([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue01').' : $1<hr><div$1>', $content);
  413. $content = preg_replace('/<page_footer([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue02').' : $1<hr><div$1>', $content);
  414. $content = preg_replace('/<page([^>]*)>/isU', '<hr>'.HTML2PDF_locale::get('vue03').' : $1<hr><div$1>', $content);
  415. $content = preg_replace('/<\/page([^>]*)>/isU', '</div><hr>', $content);
  416. $content = preg_replace('/<bookmark([^>]*)>/isU', '<hr>bookmark : $1<hr>', $content);
  417. $content = preg_replace('/<\/bookmark([^>]*)>/isU', '', $content);
  418. $content = preg_replace('/<barcode([^>]*)>/isU', '<hr>barcode : $1<hr>', $content);
  419. $content = preg_replace('/<\/barcode([^>]*)>/isU', '', $content);
  420. $content = preg_replace('/<qrcode([^>]*)>/isU', '<hr>qrcode : $1<hr>', $content);
  421. $content = preg_replace('/<\/qrcode([^>]*)>/isU', '', $content);
  422. echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  423. <html>
  424. <head>
  425. <title>'.HTML2PDF_locale::get('vue04').' HTML</title>
  426. <meta http-equiv="Content-Type" content="text/html; charset='.$this->_encoding.'" >
  427. </head>
  428. <body style="padding: 10px; font-size: 10pt;font-family: Verdana;">
  429. '.$content.'
  430. </body>
  431. </html>';
  432. exit;
  433. }
  434. /**
  435. * set the default margins of the page
  436. *
  437. * @access protected
  438. * @param int $left (mm, left margin)
  439. * @param int $top (mm, top margin)
  440. * @param int $right (mm, right margin, if null => left=right)
  441. * @param int $bottom (mm, bottom margin, if null => bottom=8mm)
  442. */
  443. protected function _setDefaultMargins($left, $top, $right = null, $bottom = null)
  444. {
  445. if ($right===null) $right = $left;
  446. if ($bottom===null) $bottom = 8;
  447. $this->_defaultLeft = $this->parsingCss->ConvertToMM($left.'mm');
  448. $this->_defaultTop = $this->parsingCss->ConvertToMM($top.'mm');
  449. $this->_defaultRight = $this->parsingCss->ConvertToMM($right.'mm');
  450. $this->_defaultBottom = $this->parsingCss->ConvertToMM($bottom.'mm');
  451. }
  452. /**
  453. * create a new page
  454. *
  455. * @access protected
  456. * @param mixed $format
  457. * @param string $orientation
  458. * @param array $background background information
  459. * @param integer $curr real position in the html parseur (if break line in the write of a text)
  460. * @param boolean $resetPageNumber
  461. */
  462. protected function _setNewPage($format = null, $orientation = '', $background = null, $curr = null, $resetPageNumber=false)
  463. {
  464. $this->_firstPage = false;
  465. $this->_format = $format ? $format : $this->_format;
  466. $this->_orientation = $orientation ? $orientation : $this->_orientation;
  467. $this->_background = $background!==null ? $background : $this->_background;
  468. $this->_maxY = 0;
  469. $this->_maxX = 0;
  470. $this->_maxH = 0;
  471. $this->_maxE = 0;
  472. $this->pdf->SetMargins($this->_defaultLeft, $this->_defaultTop, $this->_defaultRight);
  473. if ($resetPageNumber) {
  474. $this->pdf->startPageGroup();
  475. }
  476. $this->pdf->AddPage($this->_orientation, $this->_format);
  477. if ($resetPageNumber) {
  478. $this->pdf->myStartPageGroup();
  479. }
  480. $this->_page++;
  481. if (!$this->_isSubPart) {
  482. if ($this->_isCalculationPass) {
  483. if ($resetPageNumber || $this->_page == 1) {
  484. $this->_firstPageInSet []= $this->_page;
  485. }
  486. $this->_maxPage = $this->_page;
  487. }
  488. }
  489. if (!$this->_subPart && !$this->_isSubPart) {
  490. if (is_array($this->_background)) {
  491. if (isset($this->_background['color']) && $this->_background['color']) {
  492. $this->pdf->setFillColorArray($this->_background['color']);
  493. $this->pdf->Rect(0, 0, $this->pdf->getW(), $this->pdf->getH(), 'F');
  494. }
  495. if (isset($this->_background['img']) && $this->_background['img'])
  496. $this->pdf->Image($this->_background['img'], $this->_background['posX'], $this->_background['posY'], $this->_background['width']);
  497. }
  498. $this->_setPageHeader();
  499. $this->_setPageFooter();
  500. }
  501. $this->_setMargins();
  502. $this->pdf->setY($this->_margeTop);
  503. $this->_setNewPositionForNewLine($curr);
  504. $this->_maxH = 0;
  505. }
  506. /**
  507. * set the real margin, using the default margins and the page margins
  508. *
  509. * @access protected
  510. */
  511. protected function _setMargins()
  512. {
  513. if (!$this->_isSubPart) {
  514. $first = in_array($this->_page, $this->_firstPageInSet);
  515. // optimized to calculate/set page margins only once per page
  516. $suffix = $first ? '-first' : '';
  517. // prepare the margins
  518. $this->_margeLeft = $this->_defaultLeft + (isset($this->_background['left'.$suffix]) ? $this->_background['left'.$suffix] : 0);
  519. $this->_margeRight = $this->_defaultRight + (isset($this->_background['right'.$suffix]) ? $this->_background['right'.$suffix] : 0);
  520. $this->_margeTop = $this->_defaultTop + (isset($this->_background['top'.$suffix]) ? $this->_background['top'.$suffix] : 0);
  521. $this->_margeBottom = $this->_defaultBottom + (isset($this->_background['bottom'.$suffix]) ? $this->_background['bottom'.$suffix] : 0);
  522. // set the PDF margins
  523. $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
  524. $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
  525. }
  526. // set the float Margins
  527. $this->_pageMarges = array();
  528. if ($this->_isInParagraph!==false) {
  529. $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_isInParagraph[0], $this->pdf->getW()-$this->_isInParagraph[1]);
  530. } else {
  531. $this->_pageMarges[floor($this->_margeTop*100)] = array($this->_margeLeft, $this->pdf->getW()-$this->_margeRight);
  532. }
  533. }
  534. /**
  535. * add a debug step
  536. *
  537. * @access protected
  538. * @param string $name step name
  539. * @param boolean $level (true=up, false=down, null=nothing to do)
  540. * @return $this
  541. */
  542. protected function _DEBUG_add($name, $level=null)
  543. {
  544. // if true : UP
  545. if ($level===true) $this->_debugLevel++;
  546. $name = str_repeat(' ', $this->_debugLevel). $name.($level===true ? ' Begin' : ($level===false ? ' End' : ''));
  547. $time = microtime(true);
  548. $usage = ($this->_debugOkUsage ? memory_get_usage() : 0);
  549. $peak = ($this->_debugOkPeak ? memory_get_peak_usage() : 0);
  550. $this->_DEBUG_stepline(
  551. $name,
  552. number_format(($time - $this->_debugStartTime)*1000, 1, '.', ' ').' ms',
  553. number_format(($time - $this->_debugLastTime)*1000, 1, '.', ' ').' ms',
  554. number_format($usage/1024, 1, '.', ' ').' Ko',
  555. number_format($peak/1024, 1, '.', ' ').' Ko'
  556. );
  557. $this->_debugLastTime = $time;
  558. // it false : DOWN
  559. if ($level===false) $this->_debugLevel--;
  560. return $this;
  561. }
  562. /**
  563. * display a debug line
  564. *
  565. *
  566. * @access protected
  567. * @param string $name
  568. * @param string $timeTotal
  569. * @param string $timeStep
  570. * @param string $memoryUsage
  571. * @param string $memoryPeak
  572. */
  573. protected function _DEBUG_stepline($name, $timeTotal, $timeStep, $memoryUsage, $memoryPeak)
  574. {
  575. $txt = str_pad($name, 30, ' ', STR_PAD_RIGHT).
  576. str_pad($timeTotal, 12, ' ', STR_PAD_LEFT).
  577. str_pad($timeStep, 12, ' ', STR_PAD_LEFT).
  578. str_pad($memoryUsage, 15, ' ', STR_PAD_LEFT).
  579. str_pad($memoryPeak, 15, ' ', STR_PAD_LEFT);
  580. echo '<pre style="padding:0; margin:0">'.$txt.'</pre>';
  581. }
  582. /**
  583. * get the Min and Max X, for Y (use the float margins)
  584. *
  585. * @access protected
  586. * @param float $y
  587. * @return array(float, float)
  588. */
  589. protected function _getMargins($y)
  590. {
  591. $y = floor($y*100);
  592. $x = array($this->pdf->getlMargin(), $this->pdf->getW()-$this->pdf->getrMargin());
  593. foreach ($this->_pageMarges as $mY => $mX)
  594. if ($mY<=$y) $x = $mX;
  595. return $x;
  596. }
  597. /**
  598. * Add margins, for a float
  599. *
  600. * @access protected
  601. * @param string $float (left / right)
  602. * @param float $xLeft
  603. * @param float $yTop
  604. * @param float $xRight
  605. * @param float $yBottom
  606. */
  607. protected function _addMargins($float, $xLeft, $yTop, $xRight, $yBottom)
  608. {
  609. // get the current float margins, for top and bottom
  610. $oldTop = $this->_getMargins($yTop);
  611. $oldBottom = $this->_getMargins($yBottom);
  612. // update the top float margin
  613. if ($float=='left' && $oldTop[0]<$xRight) $oldTop[0] = $xRight;
  614. if ($float=='right' && $oldTop[1]>$xLeft) $oldTop[1] = $xLeft;
  615. $yTop = floor($yTop*100);
  616. $yBottom = floor($yBottom*100);
  617. // erase all the float margins that are smaller than the new one
  618. foreach ($this->_pageMarges as $mY => $mX) {
  619. if ($mY<$yTop) continue;
  620. if ($mY>$yBottom) break;
  621. if ($float=='left' && $this->_pageMarges[$mY][0]<$xRight) unset($this->_pageMarges[$mY]);
  622. if ($float=='right' && $this->_pageMarges[$mY][1]>$xLeft) unset($this->_pageMarges[$mY]);
  623. }
  624. // save the new Top and Bottom margins
  625. $this->_pageMarges[$yTop] = $oldTop;
  626. $this->_pageMarges[$yBottom] = $oldBottom;
  627. // sort the margins
  628. ksort($this->_pageMarges);
  629. // we are just after float
  630. $this->_isAfterFloat = true;
  631. }
  632. /**
  633. * Save old margins (push), and set new ones
  634. *
  635. * @access protected
  636. * @param float $ml left margin
  637. * @param float $mt top margin
  638. * @param float $mr right margin
  639. */
  640. protected function _saveMargin($ml, $mt, $mr)
  641. {
  642. // save old margins
  643. $this->_marges[] = array('l' => $this->pdf->getlMargin(), 't' => $this->pdf->gettMargin(), 'r' => $this->pdf->getrMargin(), 'page' => $this->_pageMarges);
  644. // set new ones
  645. $this->pdf->SetMargins($ml, $mt, $mr);
  646. // prepare for float margins
  647. $this->_pageMarges = array();
  648. $this->_pageMarges[floor($mt*100)] = array($ml, $this->pdf->getW()-$mr);
  649. }
  650. /**
  651. * load the last saved margins (pop)
  652. *
  653. * @access protected
  654. */
  655. protected function _loadMargin()
  656. {
  657. $old = array_pop($this->_marges);
  658. if ($old) {
  659. $ml = $old['l'];
  660. $mt = $old['t'];
  661. $mr = $old['r'];
  662. $mP = $old['page'];
  663. } else {
  664. $ml = $this->_margeLeft;
  665. $mt = 0;
  666. $mr = $this->_margeRight;
  667. $mP = array($mt => array($ml, $this->pdf->getW()-$mr));
  668. }
  669. $this->pdf->SetMargins($ml, $mt, $mr);
  670. $this->_pageMarges = $mP;
  671. }
  672. /**
  673. * save the current maxs (push)
  674. *
  675. * @access protected
  676. */
  677. protected function _saveMax()
  678. {
  679. $this->_maxSave[] = array($this->_maxX, $this->_maxY, $this->_maxH, $this->_maxE);
  680. }
  681. /**
  682. * load the last saved current maxs (pop)
  683. *
  684. * @access protected
  685. */
  686. protected function _loadMax()
  687. {
  688. $old = array_pop($this->_maxSave);
  689. if ($old) {
  690. $this->_maxX = $old[0];
  691. $this->_maxY = $old[1];
  692. $this->_maxH = $old[2];
  693. $this->_maxE = $old[3];
  694. } else {
  695. $this->_maxX = 0;
  696. $this->_maxY = 0;
  697. $this->_maxH = 0;
  698. $this->_maxE = 0;
  699. }
  700. }
  701. /**
  702. * draw the PDF header with the HTML in page_header
  703. *
  704. * @access protected
  705. */
  706. protected function _setPageHeader()
  707. {
  708. $first = in_array($this->_page, $this->_firstPageInSet);
  709. // if there's no 'first' header defined, fallback to normal header
  710. if ($first && !count($this->{'_subFIRST_HEADER'})) {
  711. $first = false;
  712. }
  713. $prop = $first ? '_subFIRST_HEADER' : '_subHEADER';
  714. if (!count($this->{$prop})) return false;
  715. $oldParsePos = $this->_parsePos;
  716. $oldParseCode = $this->parsingHtml->code;
  717. $this->_parsePos = 0;
  718. $this->parsingHtml->code = $this->{$prop};
  719. $this->_makeHTMLcode();
  720. $this->_parsePos = $oldParsePos;
  721. $this->parsingHtml->code = $oldParseCode;
  722. }
  723. /**
  724. * draw the PDF footer with the HTML in page_footer
  725. *
  726. * @access protected
  727. */
  728. protected function _setPageFooter()
  729. {
  730. $last = (!$this->_isCalculationPass && $this->_page == $this->_maxPage);
  731. // if there's no 'last' footer defined, fallback to normal footer
  732. if ($last && !count($this->{'_subLAST_FOOTER'})) {
  733. $last = false;
  734. }
  735. $prop = $last ? '_subLAST_FOOTER' : '_subFOOTER';
  736. if (!count($this->{$prop})) return false;
  737. $oldParsePos = $this->_parsePos;
  738. $oldParseCode = $this->parsingHtml->code;
  739. $this->_parsePos = 0;
  740. $this->parsingHtml->code = $this->{$prop};
  741. $this->_isInFooter = true;
  742. $this->_makeHTMLcode();
  743. $this->_isInFooter = false;
  744. $this->_parsePos = $oldParsePos;
  745. $this->parsingHtml->code = $oldParseCode;
  746. }
  747. /**
  748. * new line, with a specific height
  749. *
  750. * @access protected
  751. * @param float $h
  752. * @param integer $curr real current position in the text, if new line in the write of a text
  753. */
  754. protected function _setNewLine($h, $curr = null)
  755. {
  756. $this->pdf->Ln($h);
  757. $this->_setNewPositionForNewLine($curr);
  758. }
  759. /**
  760. * calculate the start position of the next line, depending on the text-align
  761. *
  762. * @access protected
  763. * @param integer $curr real current position in the text, if new line in the write of a text
  764. */
  765. protected function _setNewPositionForNewLine($curr = null)
  766. {
  767. // get the margins for the current line
  768. list($lx, $rx) = $this->_getMargins($this->pdf->getY());
  769. $this->pdf->setX($lx);
  770. $wMax = $rx-$lx;
  771. $this->_currentH = 0;
  772. // if subPart => return because align left
  773. if ($this->_subPart || $this->_isSubPart || $this->_isForOneLine) {
  774. $this->pdf->setWordSpacing(0);
  775. return null;
  776. }
  777. // create the sub object
  778. $sub = null;
  779. $this->_createSubHTML($sub);
  780. $sub->_saveMargin(0, 0, $sub->pdf->getW()-$wMax);
  781. $sub->_isForOneLine = true;
  782. $sub->_parsePos = $this->_parsePos;
  783. $sub->parsingHtml->code = $this->parsingHtml->code;
  784. // if $curr => adapt the current position of the parsing
  785. if ($curr!==null && $sub->parsingHtml->code[$this->_parsePos]['name']=='write') {
  786. $txt = $sub->parsingHtml->code[$this->_parsePos]['param']['txt'];
  787. $txt = str_replace('[[page_cu]]', $sub->pdf->getMyNumPage($this->_page), $txt);
  788. $sub->parsingHtml->code[$this->_parsePos]['param']['txt'] = substr($txt, $curr+1);
  789. } else
  790. $sub->_parsePos++;
  791. // for each element of the parsing => load the action
  792. $res = null;
  793. for ($sub->_parsePos; $sub->_parsePos<count($sub->parsingHtml->code); $sub->_parsePos++) {
  794. $action = $sub->parsingHtml->code[$sub->_parsePos];
  795. $res = $sub->_executeAction($action);
  796. if (!$res) break;
  797. }
  798. $w = $sub->_maxX; // max width
  799. $h = $sub->_maxH; // max height
  800. $e = ($res===null ? $sub->_maxE : 0); // maxnumber of elemets on the line
  801. // destroy the sub HTML
  802. $this->_destroySubHTML($sub);
  803. // adapt the start of the line, depending on the text-align
  804. if ($this->parsingCss->value['text-align']=='center')
  805. $this->pdf->setX(($rx+$this->pdf->getX()-$w)*0.5-0.01);
  806. else if ($this->parsingCss->value['text-align']=='right')
  807. $this->pdf->setX($rx-$w-0.01);
  808. else
  809. $this->pdf->setX($lx);
  810. // set the height of the line
  811. $this->_currentH = $h;
  812. // if justify => set the word spacing
  813. if ($this->parsingCss->value['text-align']=='justify' && $e>1) {
  814. $this->pdf->setWordSpacing(($wMax-$w)/($e-1));
  815. } else {
  816. $this->pdf->setWordSpacing(0);
  817. }
  818. }
  819. /**
  820. * prepare HTML2PDF::$_subobj (used for create the sub HTML2PDF objects
  821. *
  822. * @access protected
  823. */
  824. protected function _prepareSubObj()
  825. {
  826. $pdf = null;
  827. // create the sub object
  828. HTML2PDF::$_subobj = new HTML2PDF(
  829. $this->_orientation,
  830. $this->_format,
  831. $this->_langue,
  832. $this->_unicode,
  833. $this->_encoding,
  834. array($this->_defaultLeft,$this->_defaultTop,$this->_defaultRight,$this->_defaultBottom)
  835. );
  836. // init
  837. HTML2PDF::$_subobj->setTestTdInOnePage($this->_testTdInOnepage);
  838. HTML2PDF::$_subobj->setTestIsImage($this->_testIsImage);
  839. HTML2PDF::$_subobj->setTestIsDeprecated($this->_testIsDeprecated);
  840. HTML2PDF::$_subobj->setDefaultFont($this->_defaultFont);
  841. HTML2PDF::$_subobj->parsingCss->css = &$this->parsingCss->css;
  842. HTML2PDF::$_subobj->parsingCss->cssKeys = &$this->parsingCss->cssKeys;
  843. // copy global parameters
  844. HTML2PDF::$_subobj->_isCalculationPass = $this->_isCalculationPass;
  845. HTML2PDF::$_subobj->_rootPathForURLs = $this->_rootPathForURLs;
  846. // clone font from the original PDF
  847. HTML2PDF::$_subobj->pdf->cloneFontFrom($this->pdf);
  848. // remove the link to the parent
  849. HTML2PDF::$_subobj->parsingCss->setPdfParent($pdf);
  850. }
  851. /**
  852. * create a sub HTML2PDF, to calculate the multi-tables
  853. *
  854. * @access protected
  855. * @param &HTML2PDF $subHtml sub HTML2PDF to create
  856. * @param integer $cellmargin if in a TD : cellmargin of this td
  857. */
  858. protected function _createSubHTML(&$subHtml, $cellmargin=0)
  859. {
  860. // prepare the subObject, if never prepare before
  861. if (HTML2PDF::$_subobj===null) {
  862. $this->_prepareSubObj();
  863. }
  864. // calculate the width to use
  865. if ($this->parsingCss->value['width']) {
  866. $marge = $cellmargin*2;
  867. $marge+= $this->parsingCss->value['padding']['l'] + $this->parsingCss->value['padding']['r'];
  868. $marge+= $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['border']['r']['width'];
  869. $marge = $this->pdf->getW() - $this->parsingCss->value['width'] + $marge;
  870. } else {
  871. $marge = $this->_margeLeft+$this->_margeRight;
  872. }
  873. // BUGFIX : we have to call the method, because of a bug in php 5.1.6
  874. HTML2PDF::$_subobj->pdf->getPage();
  875. // clone the sub oject
  876. $subHtml = clone HTML2PDF::$_subobj;
  877. $subHtml->parsingCss->table = $this->parsingCss->table;
  878. $subHtml->parsingCss->value = $this->parsingCss->value;
  879. $subHtml->initSubHtml(
  880. $this->_format,
  881. $this->_orientation,
  882. $marge,
  883. $this->_page,
  884. $this->_defList,
  885. $this->pdf->getMyLastPageGroup(),
  886. $this->pdf->getMyLastPageGroupNb()
  887. );
  888. }
  889. /**
  890. * destroy a subHTML2PDF
  891. *
  892. * @access protected
  893. */
  894. protected function _destroySubHTML(&$subHtml)
  895. {
  896. unset($subHtml);
  897. $subHtml = null;
  898. }
  899. /**
  900. * Convert a arabic number in roman number
  901. *
  902. * @access protected
  903. * @param integer $nbArabic
  904. * @return string $nbRoman
  905. */
  906. protected function _listeArab2Rom($nbArabic)
  907. {
  908. $nbBaseTen = array('I','X','C','M');
  909. $nbBaseFive = array('V','L','D');
  910. $nbRoman = '';
  911. if ($nbArabic<1) return $nbArabic;
  912. if ($nbArabic>3999) return $nbArabic;
  913. for ($i=3; $i>=0 ; $i--) {
  914. $chiffre=floor($nbArabic/pow(10, $i));
  915. if ($chiffre>=1) {
  916. $nbArabic=$nbArabic-$chiffre*pow(10, $i);
  917. if ($chiffre<=3) {
  918. for ($j=$chiffre; $j>=1; $j--) {
  919. $nbRoman=$nbRoman.$nbBaseTen[$i];
  920. }
  921. } else if ($chiffre==9) {
  922. $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseTen[$i+1];
  923. } else if ($chiffre==4) {
  924. $nbRoman=$nbRoman.$nbBaseTen[$i].$nbBaseFive[$i];
  925. } else {
  926. $nbRoman=$nbRoman.$nbBaseFive[$i];
  927. for ($j=$chiffre-5; $j>=1; $j--) {
  928. $nbRoman=$nbRoman.$nbBaseTen[$i];
  929. }
  930. }
  931. }
  932. }
  933. return $nbRoman;
  934. }
  935. /**
  936. * add a LI to the current level
  937. *
  938. * @access protected
  939. */
  940. protected function _listeAddLi()
  941. {
  942. $this->_defList[count($this->_defList)-1]['nb']++;
  943. }
  944. /**
  945. * get the width to use for the column of the list
  946. *
  947. * @access protected
  948. * @return string $width
  949. */
  950. protected function _listeGetWidth()
  951. {
  952. return '7mm';
  953. }
  954. /**
  955. * get the padding to use for the column of the list
  956. *
  957. * @access protected
  958. * @return string $padding
  959. */
  960. protected function _listeGetPadding()
  961. {
  962. return '1mm';
  963. }
  964. /**
  965. * get the information of the li on the current level
  966. *
  967. * @access protected
  968. * @return array(fontName, small size, string)
  969. */
  970. protected function _listeGetLi()
  971. {
  972. $im = $this->_defList[count($this->_defList)-1]['img'];
  973. $st = $this->_defList[count($this->_defList)-1]['style'];
  974. $nb = $this->_defList[count($this->_defList)-1]['nb'];
  975. $up = (substr($st, 0, 6)=='upper-');
  976. if ($im) return array(false, false, $im);
  977. switch($st)
  978. {
  979. case 'none':
  980. return array('helvetica', true, ' ');
  981. case 'upper-alpha':
  982. case 'lower-alpha':
  983. $str = '';
  984. while ($nb>26) {
  985. $str = chr(96+$nb%26).$str;
  986. $nb = floor($nb/26);
  987. }
  988. $str = chr(96+$nb).$str;
  989. return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
  990. case 'upper-roman':
  991. case 'lower-roman':
  992. $str = $this->_listeArab2Rom($nb);
  993. return array('helvetica', false, ($up ? strtoupper($str) : $str).'.');
  994. case 'decimal':
  995. return array($this->parsingCss->value['font-family'], false, $nb.'.');
  996. case 'square':
  997. return array('zapfdingbats', true, chr(110));
  998. case 'circle':
  999. return array('zapfdingbats', true, chr(109));
  1000. case 'disc':
  1001. default:
  1002. return array('zapfdingbats', true, chr(108));
  1003. }
  1004. }
  1005. /**
  1006. * add a level to the list
  1007. *
  1008. * @access protected
  1009. * @param string $type : ul, ol
  1010. * @param string $style : lower-alpha, ...
  1011. * @param string $img
  1012. */
  1013. protected function _listeAddLevel($type = 'ul', $style = '', $img = null)
  1014. {
  1015. // get the url of the image, if we want to use a image
  1016. if ($img) {
  1017. if (preg_match('/^url\(([^)]+)\)$/isU', trim($img), $match)) {
  1018. $img = $match[1];
  1019. } else {
  1020. $img = null;
  1021. }
  1022. } else {
  1023. $img = null;
  1024. }
  1025. // prepare the datas
  1026. if (!in_array($type, array('ul', 'ol'))) $type = 'ul';
  1027. if (!in_array($style, array('lower-alpha', 'upper-alpha', 'upper-roman', 'lower-roman', 'decimal', 'square', 'circle', 'disc', 'none'))) $style = '';
  1028. if (!$style) {
  1029. if ($type=='ul') $style = 'disc';
  1030. else $style = 'decimal';
  1031. }
  1032. // add the new level
  1033. $this->_defList[count($this->_defList)] = array('style' => $style, 'nb' => 0, 'img' => $img);
  1034. }
  1035. /**
  1036. * remove a level to the list
  1037. *
  1038. * @access protected
  1039. */
  1040. protected function _listeDelLevel()
  1041. {
  1042. if (count($this->_defList)) {
  1043. unset($this->_defList[count($this->_defList)-1]);
  1044. $this->_defList = array_values($this->_defList);
  1045. }
  1046. }
  1047. /**
  1048. * execute the actions to convert the html
  1049. *
  1050. * @access protected
  1051. */
  1052. protected function _makeHTMLcode()
  1053. {
  1054. // foreach elements of the parsing
  1055. for ($this->_parsePos=0; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) {
  1056. // get the action to do
  1057. $action = $this->parsingHtml->code[$this->_parsePos];
  1058. // if it is a opening of table / ul / ol
  1059. if (in_array($action['name'], array('table', 'ul', 'ol')) && !$action['close']) {
  1060. // we will work as a sub HTML to calculate the size of the element
  1061. $this->_subPart = true;
  1062. // get the name of the opening tag
  1063. $tagOpen = $action['name'];
  1064. // save the actual pos on the parsing
  1065. $this->_tempPos = $this->_parsePos;
  1066. // foreach elements, while we are in the opened tag
  1067. while (isset($this->parsingHtml->code[$this->_tempPos]) && !($this->parsingHtml->code[$this->_tempPos]['name']==$tagOpen && $this->parsingHtml->code[$this->_tempPos]['close'])) {
  1068. // make the action
  1069. $this->_executeAction($this->parsingHtml->code[$this->_tempPos]);
  1070. $this->_tempPos++;
  1071. }
  1072. // execute the closure of the tag
  1073. if (isset($this->parsingHtml->code[$this->_tempPos])) {
  1074. $this->_executeAction($this->parsingHtml->code[$this->_tempPos]);
  1075. }
  1076. // end of the sub part
  1077. $this->_subPart = false;
  1078. }
  1079. // execute the action
  1080. $this->_executeAction($action);
  1081. }
  1082. }
  1083. /**
  1084. * execute the action from the parsing
  1085. *
  1086. * @access protected
  1087. * @param array $action
  1088. */
  1089. protected function _executeAction($action)
  1090. {
  1091. // name of the action
  1092. $fnc = ($action['close'] ? '_tag_close_' : '_tag_open_').strtoupper($action['name']);
  1093. // parameters of the action
  1094. $param = $action['param'];
  1095. // if it the first action of the first page, and if it is not a open tag of PAGE => create the new page
  1096. if ($fnc!='_tag_open_PAGE' && $this->_firstPage) {
  1097. $this->_setNewPage();
  1098. }
  1099. // the action must exist
  1100. if (!is_callable(array(&$this, $fnc))) {
  1101. throw new HTML2PDF_exception(1, strtoupper($action['name']), $this->parsingHtml->getHtmlErrorCode($action['html_pos']));
  1102. }
  1103. // lauch the action
  1104. $res = $this->{$fnc}($param);
  1105. // save the name of the action
  1106. $this->_previousCall = $fnc;
  1107. // return the result
  1108. return $res;
  1109. }
  1110. /**
  1111. * get the position of the element on the current line, depending on his height
  1112. *
  1113. * @access protected
  1114. * @param float $h
  1115. * @return float
  1116. */
  1117. protected function _getElementY($h)
  1118. {
  1119. if ($this->_subPart || $this->_isSubPart || !$this->_currentH || $this->_currentH<$h)
  1120. return 0;
  1121. return ($this->_currentH-$h)*0.8;
  1122. }
  1123. /**
  1124. * make a break line
  1125. *
  1126. * @access protected
  1127. * @param float $h current line height
  1128. * @param integer $curr real current position in the text, if new line in the write of a text
  1129. */
  1130. protected function _makeBreakLine($h, $curr = null)
  1131. {
  1132. if ($h) {
  1133. if (($this->pdf->getY()+$h<$this->pdf->getH() - $this->pdf->getbMargin()) || $this->_isInOverflow || $this->_isInFooter)
  1134. $this->_setNewLine($h, $curr);
  1135. else
  1136. $this->_setNewPage(null, '', null, $curr);
  1137. } else {
  1138. $this->_setNewPositionForNewLine($curr);
  1139. }
  1140. $this->_maxH = 0;
  1141. $this->_maxE = 0;
  1142. }
  1143. /**
  1144. * display a image
  1145. *
  1146. * @access protected
  1147. * @param string $src
  1148. * @param boolean $subLi if true=image of a list
  1149. * @return boolean depending on "isForOneLine"
  1150. */
  1151. protected function _drawImage($src, $subLi=false)
  1152. {
  1153. // for image URLs that start with forward slash, try
  1154. // to map them to a filesystem using the URL_ROOT parameter
  1155. if (strpos($src, '/') === 0) {
  1156. $src = $this->_rootPathForURLs.$src;
  1157. }
  1158. // get the size of the image
  1159. // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
  1160. $infos=@getimagesize($src);
  1161. // if the image does not exist, or can not be loaded
  1162. if (count($infos)<2) {
  1163. // if the test is activ => exception
  1164. if ($this->_testIsImage) {
  1165. throw new HTML2PDF_exception(6, $src);
  1166. }
  1167. // else, display a gray rectangle
  1168. $src = null;
  1169. $infos = array(16, 16);
  1170. }
  1171. // convert the size of the image in the unit of the PDF
  1172. $imageWidth = $infos[0]/$this->pdf->getK();
  1173. $imageHeight = $infos[1]/$this->pdf->getK();
  1174. // calculate the size from the css style
  1175. if ($this->parsingCss->value['width'] && $this->parsingCss->value['height']) {
  1176. $w = $this->parsingCss->value['width'];
  1177. $h = $this->parsingCss->value['height'];
  1178. } else if ($this->parsingCss->value['width']) {
  1179. $w = $this->parsingCss->value['width'];
  1180. $h = $imageHeight*$w/$imageWidth;
  1181. } else if ($this->parsingCss->value['height']) {
  1182. $h = $this->parsingCss->value['height'];
  1183. $w = $imageWidth*$h/$imageHeight;
  1184. } else {
  1185. // convert px to pt
  1186. $w = 72./96.*$imageWidth;
  1187. $h = 72./96.*$imageHeight;
  1188. }
  1189. // are we in a float
  1190. $float = $this->parsingCss->getFloat();
  1191. // if we are in a float, but if something else if on the line => Break Line
  1192. if ($float && $this->_maxH) {
  1193. // make the break line (false if we are in "_isForOneLine" mode)
  1194. if (!$this->_tag_open_BR(array())) {
  1195. return false;
  1196. }
  1197. }
  1198. // position of the image
  1199. $x = $this->pdf->getX();
  1200. $y = $this->pdf->getY();
  1201. // if the image can not be put on the current line => new line
  1202. if (!$float && ($x + $w>$this->pdf->getW() - $this->pdf->getrMargin()) && $this->_maxH) {
  1203. if ($this->_isForOneLine) {
  1204. return false;
  1205. }
  1206. // set the new line
  1207. $hnl = max($this->_maxH, $this->parsingCss->getLineHeight());
  1208. $this->_setNewLine($hnl);
  1209. // get the new position
  1210. $x = $this->pdf->getX();
  1211. $y = $this->pdf->getY();
  1212. }
  1213. // if the image can not be put on the current page
  1214. if (($y + $h>$this->pdf->getH() - $this->pdf->getbMargin()) && !$this->_isInOverflow) {
  1215. // new page
  1216. $this->_setNewPage();
  1217. // get the new position
  1218. $x = $this->pdf->getX();
  1219. $y = $this->pdf->getY();
  1220. }
  1221. // correction for display the image of a list
  1222. $hT = 0.80*$this->parsingCss->value['font-size'];
  1223. if ($subLi && $h<$hT) {
  1224. $y+=($hT-$h);
  1225. }
  1226. // add the margin top
  1227. $yc = $y-$this->parsingCss->value['margin']['t'];
  1228. // get the width and the position of the parent
  1229. $old = $this->parsingCss->getOldValues();
  1230. if ( $old['width']) {
  1231. $parentWidth = $old['width'];
  1232. $parentX = $x;
  1233. } else {
  1234. $parentWidth = $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  1235. $parentX = $this->pdf->getlMargin();
  1236. }
  1237. // if we are in a gloat => adapt the parent position and width
  1238. if ($float) {
  1239. list($lx, $rx) = $this->_getMargins($yc);
  1240. $parentX = $lx;
  1241. $parentWidth = $rx-$lx;
  1242. }
  1243. // calculate the position of the image, if align to the right
  1244. if ($parentWidth>$w && $float!='left') {
  1245. if ($float=='right' || $this->parsingCss->value['text-align']=='li_right') $x = $parentX + $parentWidth - $w-$this->parsingCss->value['margin']['r']-$this->parsingCss->value['margin']['l'];
  1246. }
  1247. // display the image
  1248. if (!$this->_subPart && !$this->_isSubPart) {
  1249. if ($src) {
  1250. $this->pdf->Image($src, $x, $y, $w, $h, '', $this->_isInLink);
  1251. } else {
  1252. // rectangle if the image can not be loaded
  1253. $this->pdf->setFillColorArray(array(240, 220, 220));
  1254. $this->pdf->Rect($x, $y, $w, $h, 'F');
  1255. }
  1256. }
  1257. // apply the margins
  1258. $x-= $this->parsingCss->value['margin']['l'];
  1259. $y-= $this->parsingCss->value['margin']['t'];
  1260. $w+= $this->parsingCss->value['margin']['l'] + $this->parsingCss->value['margin']['r'];
  1261. $h+= $this->parsingCss->value['margin']['t'] + $this->parsingCss->value['margin']['b'];
  1262. if ($float=='left') {
  1263. // save the current max
  1264. $this->_maxX = max($this->_maxX, $x+$w);
  1265. $this->_maxY = max($this->_maxY, $y+$h);
  1266. // add the image to the margins
  1267. $this->_addMargins($float, $x, $y, $x+$w, $y+$h);
  1268. // get the new position
  1269. list($lx, $rx) = $this->_getMargins($yc);
  1270. $this->pdf->setXY($lx, $yc);
  1271. } else if ($float=='right') {
  1272. // save the current max. We don't save the X because it is not the real max of the line
  1273. $this->_maxY = max($this->_maxY, $y+$h);
  1274. // add the image to the margins
  1275. $this->_addMargins($float, $x, $y, $x+$w, $y+$h);
  1276. // get the new position
  1277. list($lx, $rx) = $this->_getMargins($yc);
  1278. $this->pdf->setXY($lx, $yc);
  1279. } else {
  1280. // set the new position at the end of the image
  1281. $this->pdf->setX($x+$w);
  1282. // save the current max
  1283. $this->_maxX = max($this->_maxX, $x+$w);
  1284. $this->_maxY = max($this->_maxY, $y+$h);
  1285. $this->_maxH = max($this->_maxH, $h);
  1286. }
  1287. return true;
  1288. }
  1289. /**
  1290. * draw a rectangle
  1291. *
  1292. * @access protected
  1293. * @param float $x
  1294. * @param float $y
  1295. * @param float $w
  1296. * @param float $h
  1297. * @param array $border
  1298. * @param float $padding - internal marge of the rectanble => not used, but...
  1299. * @param float $margin - external marge of the rectanble
  1300. * @param array $background
  1301. * @return boolean
  1302. */
  1303. protected function _drawRectangle($x, $y, $w, $h, $border, $padding, $margin, $background)
  1304. {
  1305. // if we are in a subpart or if height is null => return false
  1306. if ($this->_subPart || $this->_isSubPart || $h===null) return false;
  1307. // add the margin
  1308. $x+= $margin;
  1309. $y+= $margin;
  1310. $w-= $margin*2;
  1311. $h-= $margin*2;
  1312. // get the radius of the border
  1313. $outTL = $border['radius']['tl'];
  1314. $outTR = $border['radius']['tr'];
  1315. $outBR = $border['radius']['br'];
  1316. $outBL = $border['radius']['bl'];
  1317. // prepare the out radius
  1318. $outTL = ($outTL[0] && $outTL[1]) ? $outTL : null;
  1319. $outTR = ($outTR[0] && $outTR[1]) ? $outTR : null;
  1320. $outBR = ($outBR[0] && $outBR[1]) ? $outBR : null;
  1321. $outBL = ($outBL[0] && $outBL[1]) ? $outBL : null;
  1322. // prepare the in radius
  1323. $inTL = $outTL;
  1324. $inTR = $outTR;
  1325. $inBR = $outBR;
  1326. $inBL = $outBL;
  1327. if (is_array($inTL)) {
  1328. $inTL[0]-= $border['l']['width'];
  1329. $inTL[1]-= $border['t']['width'];
  1330. }
  1331. if (is_array($inTR)) {
  1332. $inTR[0]-= $border['r']['width'];
  1333. $inTR[1]-= $border['t']['width'];
  1334. }
  1335. if (is_array($inBR)) {
  1336. $inBR[0]-= $border['r']['width'];
  1337. $inBR[1]-= $border['b']['width'];
  1338. }
  1339. if (is_array($inBL)) {
  1340. $inBL[0]-= $border['l']['width'];
  1341. $inBL[1]-= $border['b']['width'];
  1342. }
  1343. if ($inTL[0]<=0 || $inTL[1]<=0) $inTL = null;
  1344. if ($inTR[0]<=0 || $inTR[1]<=0) $inTR = null;
  1345. if ($inBR[0]<=0 || $inBR[1]<=0) $inBR = null;
  1346. if ($inBL[0]<=0 || $inBL[1]<=0) $inBL = null;
  1347. // prepare the background color
  1348. $pdfStyle = '';
  1349. if ($background['color']) {
  1350. $this->pdf->setFillColorArray($background['color']);
  1351. $pdfStyle.= 'F';
  1352. }
  1353. // if we have a background to fill => fill it with a path (because of the radius)
  1354. if ($pdfStyle) {
  1355. $this->pdf->clippingPathStart($x, $y, $w, $h, $outTL, $outTR, $outBL, $outBR);
  1356. $this->pdf->Rect($x, $y, $w, $h, $pdfStyle);
  1357. $this->pdf->clippingPathStop();
  1358. }
  1359. // prepare the background image
  1360. if ($background['image']) {
  1361. $iName = $background['image'];
  1362. $iPosition = $background['position']!==null ? $background['position'] : array(0, 0);
  1363. $iRepeat = $background['repeat']!==null ? $background['repeat'] : array(true, true);
  1364. // size of the background without the borders
  1365. $bX = $x;
  1366. $bY = $y;
  1367. $bW = $w;
  1368. $bH = $h;
  1369. if ($border['b']['width']) {
  1370. $bH-= $border['b']['width'];
  1371. }
  1372. if ($border['l']['width']) {
  1373. $bW-= $border['l']['width'];
  1374. $bX+= $border['l']['width'];
  1375. }
  1376. if ($border['t']['width']) {
  1377. $bH-= $border['t']['width'];
  1378. $bY+= $border['t']['width'];
  1379. }
  1380. if ($border['r']['width']) {
  1381. $bW-= $border['r']['width'];
  1382. }
  1383. // get the size of the image
  1384. // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
  1385. $imageInfos=@getimagesize($iName);
  1386. // if the image can not be loaded
  1387. if (count($imageInfos)<2) {
  1388. if ($this->_testIsImage) {
  1389. throw new HTML2PDF_exception(6, $iName);
  1390. }
  1391. } else {
  1392. // convert the size of the image from pixel to the unit of the PDF
  1393. $imageWidth = 72./96.*$imageInfos[0]/$this->pdf->getK();
  1394. $imageHeight = 72./96.*$imageInfos[1]/$this->pdf->getK();
  1395. // prepare the position of the backgroung
  1396. if ($iRepeat[0]) $iPosition[0] = $bX;
  1397. else if (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[0], $match)) $iPosition[0] = $bX + $match[1]*($bW-$imageWidth)/100;
  1398. else $iPosition[0] = $bX+$iPosition[0];
  1399. if ($iRepeat[1]) $iPosition[1] = $bY;
  1400. else if (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[1], $match)) $iPosition[1] = $bY + $match[1]*($bH-$imageHeight)/100;
  1401. else $iPosition[1] = $bY+$iPosition[1];
  1402. $imageXmin = $bX;
  1403. $imageXmax = $bX+$bW;
  1404. $imageYmin = $bY;
  1405. $imageYmax = $bY+$bH;
  1406. if (!$iRepeat[0] && !$iRepeat[1]) {
  1407. $imageXmin = $iPosition[0]; $imageXmax = $iPosition[0]+$imageWidth;
  1408. $imageYmin = $iPosition[1]; $imageYmax = $iPosition[1]+$imageHeight;
  1409. } else if ($iRepeat[0] && !$iRepeat[1]) {
  1410. $imageYmin = $iPosition[1]; $imageYmax = $iPosition[1]+$imageHeight;
  1411. } else if (!$iRepeat[0] && $iRepeat[1]) {
  1412. $imageXmin = $iPosition[0]; $imageXmax = $iPosition[0]+$imageWidth;
  1413. }
  1414. // build the path to display the image (because of radius)
  1415. $this->pdf->clippingPathStart($bX, $bY, $bW, $bH, $inTL, $inTR, $inBL, $inBR);
  1416. // repeat the image
  1417. for ($iY=$imageYmin; $iY<$imageYmax; $iY+=$imageHeight) {
  1418. for ($iX=$imageXmin; $iX<$imageXmax; $iX+=$imageWidth) {
  1419. $cX = null;
  1420. $cY = null;
  1421. $cW = $imageWidth;
  1422. $cH = $imageHeight;
  1423. if ($imageYmax-$iY<$imageHeight) {
  1424. $cX = $iX;
  1425. $cY = $iY;
  1426. $cH = $imageYmax-$iY;
  1427. }
  1428. if ($imageXmax-$iX<$imageWidth) {
  1429. $cX = $iX;
  1430. $cY = $iY;
  1431. $cW = $imageXmax-$iX;
  1432. }
  1433. $this->pdf->Image($iName, $iX, $iY, $imageWidth, $imageHeight, '', '');
  1434. }
  1435. }
  1436. // end of the path
  1437. $this->pdf->clippingPathStop();
  1438. }
  1439. }
  1440. // adding some loose (0.01mm)
  1441. $loose = 0.01;
  1442. $x-= $loose;
  1443. $y-= $loose;
  1444. $w+= 2.*$loose;
  1445. $h+= 2.*$loose;
  1446. if ($border['l']['width']) $border['l']['width']+= 2.*$loose;
  1447. if ($border['t']['width']) $border['t']['width']+= 2.*$loose;
  1448. if ($border['r']['width']) $border['r']['width']+= 2.*$loose;
  1449. if ($border['b']['width']) $border['b']['width']+= 2.*$loose;
  1450. // prepare the test on borders
  1451. $testBl = ($border['l']['width'] && $border['l']['color'][0]!==null);
  1452. $testBt = ($border['t']['width'] && $border['t']['color'][0]!==null);
  1453. $testBr = ($border['r']['width'] && $border['r']['color'][0]!==null);
  1454. $testBb = ($border['b']['width'] && $border['b']['color'][0]!==null);
  1455. // draw the radius bottom-left
  1456. if (is_array($outBL) && ($testBb || $testBl)) {
  1457. if ($inBL) {
  1458. $courbe = array();
  1459. $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h;
  1460. $courbe[] = $x; $courbe[] = $y+$h-$outBL[1];
  1461. $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$border['b']['width'];
  1462. $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$h-$outBL[1];
  1463. $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$outBL[1];
  1464. } else {
  1465. $courbe = array();
  1466. $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h;
  1467. $courbe[] = $x; $courbe[] = $y+$h-$outBL[1];
  1468. $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$h-$border['b']['width'];
  1469. $courbe[] = $x+$outBL[0]; $courbe[] = $y+$h-$outBL[1];
  1470. }
  1471. $this->_drawCurve($courbe, $border['l']['color']);
  1472. }
  1473. // draw the radius left-top
  1474. if (is_array($outTL) && ($testBt || $testBl)) {
  1475. if ($inTL) {
  1476. $courbe = array();
  1477. $courbe[] = $x; $courbe[] = $y+$outTL[1];
  1478. $courbe[] = $x+$outTL[0]; $courbe[] = $y;
  1479. $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$outTL[1];
  1480. $courbe[] = $x+$outTL[0]; $courbe[] = $y+$border['t']['width'];
  1481. $courbe[] = $x+$outTL[0]; $courbe[] = $y+$outTL[1];
  1482. } else {
  1483. $courbe = array();
  1484. $courbe[] = $x; $courbe[] = $y+$outTL[1];
  1485. $courbe[] = $x+$outTL[0]; $courbe[] = $y;
  1486. $courbe[] = $x+$border['l']['width']; $courbe[] = $y+$border['t']['width'];
  1487. $courbe[] = $x+$outTL[0]; $courbe[] = $y+$outTL[1];
  1488. }
  1489. $this->_drawCurve($courbe, $border['t']['color']);
  1490. }
  1491. // draw the radius top-right
  1492. if (is_array($outTR) && ($testBt || $testBr)) {
  1493. if ($inTR) {
  1494. $courbe = array();
  1495. $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y;
  1496. $courbe[] = $x+$w; $courbe[] = $y+$outTR[1];
  1497. $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$border['t']['width'];
  1498. $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$outTR[1];
  1499. $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$outTR[1];
  1500. } else {
  1501. $courbe = array();
  1502. $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y;
  1503. $courbe[] = $x+$w; $courbe[] = $y+$outTR[1];
  1504. $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$border['t']['width'];
  1505. $courbe[] = $x+$w-$outTR[0]; $courbe[] = $y+$outTR[1];
  1506. }
  1507. $this->_drawCurve($courbe, $border['r']['color']);
  1508. }
  1509. // draw the radius right-bottom
  1510. if (is_array($outBR) && ($testBb || $testBr)) {
  1511. if ($inBR) {
  1512. $courbe = array();
  1513. $courbe[] = $x+$w; $courbe[] = $y+$h-$outBR[1];
  1514. $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h;
  1515. $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$h-$outBR[1];
  1516. $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$border['b']['width'];
  1517. $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$outBR[1];
  1518. } else {
  1519. $courbe = array();
  1520. $courbe[] = $x+$w; $courbe[] = $y+$h-$outBR[1];
  1521. $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h;
  1522. $courbe[] = $x+$w-$border['r']['width']; $courbe[] = $y+$h-$border['b']['width'];
  1523. $courbe[] = $x+$w-$outBR[0]; $courbe[] = $y+$h-$outBR[1];
  1524. }
  1525. $this->_drawCurve($courbe, $border['b']['color']);
  1526. }
  1527. // draw the left border
  1528. if ($testBl) {
  1529. $pt = array();
  1530. $pt[] = $x; $pt[] = $y+$h;
  1531. $pt[] = $x; $pt[] = $y+$h-$border['b']['width'];
  1532. $pt[] = $x; $pt[] = $y+$border['t']['width'];
  1533. $pt[] = $x; $pt[] = $y;
  1534. $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width'];
  1535. $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width'];
  1536. $bord = 3;
  1537. if (is_array($outBL)) {
  1538. $bord-=1;
  1539. $pt[3] -= $outBL[1] - $border['b']['width'];
  1540. if ($inBL) $pt[11]-= $inBL[1];
  1541. unset($pt[0]);unset($pt[1]);
  1542. }
  1543. if (is_array($outTL)) {
  1544. $bord-=2;
  1545. $pt[5] += $outTL[1]-$border['t']['width'];
  1546. if ($inTL) $pt[9] += $inTL[1];
  1547. unset($pt[6]);unset($pt[7]);
  1548. }
  1549. $pt = array_values($pt);
  1550. $this->_drawLine($pt, $border['l']['color'], $border['l']['type'], $border['l']['width'], $bord);
  1551. }
  1552. // draw the top border
  1553. if ($testBt) {
  1554. $pt = array();
  1555. $pt[] = $x; $pt[] = $y;
  1556. $pt[] = $x+$border['l']['width']; $pt[] = $y;
  1557. $pt[] = $x+$w-$border['r']['width']; $pt[] = $y;
  1558. $pt[] = $x+$w; $pt[] = $y;
  1559. $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width'];
  1560. $pt[] = $x+$border['l']['width']; $pt[] = $y+$border['t']['width'];
  1561. $bord = 3;
  1562. if (is_array($outTL)) {
  1563. $bord-=1;
  1564. $pt[2] += $outTL[0] - $border['l']['width'];
  1565. if ($inTL) $pt[10]+= $inTL[0];
  1566. unset($pt[0]);unset($pt[1]);
  1567. }
  1568. if (is_array($outTR)) {
  1569. $bord-=2;
  1570. $pt[4] -= $outTR[0] - $border['r']['width'];
  1571. if ($inTR) $pt[8] -= $inTR[0];
  1572. unset($pt[6]);unset($pt[7]);
  1573. }
  1574. $pt = array_values($pt);
  1575. $this->_drawLine($pt, $border['t']['color'], $border['t']['type'], $border['t']['width'], $bord);
  1576. }
  1577. // draw the right border
  1578. if ($testBr) {
  1579. $pt = array();
  1580. $pt[] = $x+$w; $pt[] = $y;
  1581. $pt[] = $x+$w; $pt[] = $y+$border['t']['width'];
  1582. $pt[] = $x+$w; $pt[] = $y+$h-$border['b']['width'];
  1583. $pt[] = $x+$w; $pt[] = $y+$h;
  1584. $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width'];
  1585. $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$border['t']['width'];
  1586. $bord = 3;
  1587. if (is_array($outTR)) {
  1588. $bord-=1;
  1589. $pt[3] += $outTR[1] - $border['t']['width'];
  1590. if ($inTR) $pt[11]+= $inTR[1];
  1591. unset($pt[0]);unset($pt[1]);
  1592. }
  1593. if (is_array($outBR)) {
  1594. $bord-=2;
  1595. $pt[5] -= $outBR[1] - $border['b']['width'];
  1596. if ($inBR) $pt[9] -= $inBR[1];
  1597. unset($pt[6]);unset($pt[7]);
  1598. }
  1599. $pt = array_values($pt);
  1600. $this->_drawLine($pt, $border['r']['color'], $border['r']['type'], $border['r']['width'], $bord);
  1601. }
  1602. // draw the bottom border
  1603. if ($testBb) {
  1604. $pt = array();
  1605. $pt[] = $x+$w; $pt[] = $y+$h;
  1606. $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h;
  1607. $pt[] = $x+$border['l']['width']; $pt[] = $y+$h;
  1608. $pt[] = $x; $pt[] = $y+$h;
  1609. $pt[] = $x+$border['l']['width']; $pt[] = $y+$h-$border['b']['width'];
  1610. $pt[] = $x+$w-$border['r']['width']; $pt[] = $y+$h-$border['b']['width'];
  1611. $bord = 3;
  1612. if (is_array($outBL)) {
  1613. $bord-=2;
  1614. $pt[4] += $outBL[0] - $border['l']['width'];
  1615. if ($inBL) $pt[8] += $inBL[0];
  1616. unset($pt[6]);unset($pt[7]);
  1617. }
  1618. if (is_array($outBR)) {
  1619. $bord-=1;
  1620. $pt[2] -= $outBR[0] - $border['r']['width'];
  1621. if ($inBR) $pt[10]-= $inBR[0];
  1622. unset($pt[0]);unset($pt[1]);
  1623. }
  1624. $pt = array_values($pt);
  1625. $this->_drawLine($pt, $border['b']['color'], $border['b']['type'], $border['b']['width'], $bord);
  1626. }
  1627. if ($background['color']) {
  1628. $this->pdf->setFillColorArray($background['color']);
  1629. }
  1630. return true;
  1631. }
  1632. /**
  1633. * draw a curve (for border radius)
  1634. *
  1635. * @access protected
  1636. * @param array $pt
  1637. * @param array $color
  1638. */
  1639. protected function _drawCurve($pt, $color)
  1640. {
  1641. $this->pdf->setFillColorArray($color);
  1642. if (count($pt)==10)
  1643. $this->pdf->drawCurve($pt[0], $pt[1], $pt[2], $pt[3], $pt[4], $pt[5], $pt[6], $pt[7], $pt[8], $pt[9]);
  1644. else
  1645. $this->pdf->drawCorner($pt[0], $pt[1], $pt[2], $pt[3], $pt[4], $pt[5], $pt[6], $pt[7]);
  1646. }
  1647. /**
  1648. * draw a ligne with a specific type, and specific start and end for radius
  1649. *
  1650. * @access protected
  1651. * @param array $pt
  1652. * @param float $color
  1653. * @param string $type (dashed, dotted, double, solid)
  1654. * @param float $width
  1655. * @param integer $radius (binary from 0 to 3 with 1=>start with a radius, 2=>end with a radius)
  1656. */
  1657. protected function _drawLine($pt, $color, $type, $width, $radius=3)
  1658. {
  1659. // set the fill color
  1660. $this->pdf->setFillColorArray($color);
  1661. // if dashed or dotted
  1662. if ($type=='dashed' || $type=='dotted') {
  1663. // clean the end of the line, if radius
  1664. if ($radius==1) {
  1665. $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
  1666. $this->pdf->Polygon($tmp, 'F');
  1667. $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
  1668. $pt = $tmp;
  1669. } else if ($radius==2) {
  1670. $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7];
  1671. $this->pdf->Polygon($tmp, 'F');
  1672. $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
  1673. $pt = $tmp;
  1674. } else if ($radius==3) {
  1675. $tmp = array(); $tmp[]=$pt[0]; $tmp[]=$pt[1]; $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[10]; $tmp[]=$pt[11];
  1676. $this->pdf->Polygon($tmp, 'F');
  1677. $tmp = array(); $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[6]; $tmp[]=$pt[7]; $tmp[]=$pt[8]; $tmp[]=$pt[9];
  1678. $this->pdf->Polygon($tmp, 'F');
  1679. $tmp = array(); $tmp[]=$pt[2]; $tmp[]=$pt[3]; $tmp[]=$pt[4]; $tmp[]=$pt[5]; $tmp[]=$pt[8]; $tmp[]=$pt[9]; $tmp[]=$pt[10]; $tmp[]=$pt[11];
  1680. $pt = $tmp;
  1681. }
  1682. // horisontal or vertical line
  1683. if ($pt[2]==$pt[0]) {
  1684. $l = abs(($pt[3]-$pt[1])*0.5);
  1685. $px = 0;
  1686. $py = $width;
  1687. $x1 = $pt[0]; $y1 = ($pt[3]+$pt[1])*0.5;
  1688. $x2 = $pt[6]; $y2 = ($pt[7]+$pt[5])*0.5;
  1689. } else {
  1690. $l = abs(($pt[2]-$pt[0])*0.5);
  1691. $px = $width;
  1692. $py = 0;
  1693. $x1 = ($pt[2]+$pt[0])*0.5; $y1 = $pt[1];
  1694. $x2 = ($pt[6]+$pt[4])*0.5; $y2 = $pt[7];
  1695. }
  1696. // if dashed : 3x bigger than dotted
  1697. if ($type=='dashed') {
  1698. $px = $px*3.;
  1699. $py = $py*3.;
  1700. }
  1701. $mode = ($l/($px+$py)<.5);
  1702. // display the dotted/dashed line
  1703. for ($i=0; $l-($px+$py)*($i-0.5)>0; $i++) {
  1704. if (($i%2)==$mode) {
  1705. $j = $i-0.5;
  1706. $lx1 = $px*($j); if ($lx1<-$l) $lx1 =-$l;
  1707. $ly1 = $py*($j); if ($ly1<-$l) $ly1 =-$l;
  1708. $lx2 = $px*($j+1); if ($lx2>$l) $lx2 = $l;
  1709. $ly2 = $py*($j+1); if ($ly2>$l) $ly2 = $l;
  1710. $tmp = array();
  1711. $tmp[] = $x1+$lx1; $tmp[] = $y1+$ly1;
  1712. $tmp[] = $x1+$lx2; $tmp[] = $y1+$ly2;
  1713. $tmp[] = $x2+$lx2; $tmp[] = $y2+$ly2;
  1714. $tmp[] = $x2+$lx1; $tmp[] = $y2+$ly1;
  1715. $this->pdf->Polygon($tmp, 'F');
  1716. if ($j>0) {
  1717. $tmp = array();
  1718. $tmp[] = $x1-$lx1; $tmp[] = $y1-$ly1;
  1719. $tmp[] = $x1-$lx2; $tmp[] = $y1-$ly2;
  1720. $tmp[] = $x2-$lx2; $tmp[] = $y2-$ly2;
  1721. $tmp[] = $x2-$lx1; $tmp[] = $y2-$ly1;
  1722. $this->pdf->Polygon($tmp, 'F');
  1723. }
  1724. }
  1725. }
  1726. } else if ($type=='double') {
  1727. // if double, 2 lines : 0=>1/3 and 2/3=>1
  1728. $pt1 = $pt;
  1729. $pt2 = $pt;
  1730. if (count($pt)==12) {
  1731. // line 1
  1732. $pt1[0] = ($pt[0]-$pt[10])*0.33 + $pt[10];
  1733. $pt1[1] = ($pt[1]-$pt[11])*0.33 + $pt[11];
  1734. $pt1[2] = ($pt[2]-$pt[10])*0.33 + $pt[10];
  1735. $pt1[3] = ($pt[3]-$pt[11])*0.33 + $pt[11];
  1736. $pt1[4] = ($pt[4]-$pt[8])*0.33 + $pt[8];
  1737. $pt1[5] = ($pt[5]-$pt[9])*0.33 + $pt[9];
  1738. $pt1[6] = ($pt[6]-$pt[8])*0.33 + $pt[8];
  1739. $pt1[7] = ($pt[7]-$pt[9])*0.33 + $pt[9];
  1740. $pt2[10]= ($pt[10]-$pt[0])*0.33 + $pt[0];
  1741. $pt2[11]= ($pt[11]-$pt[1])*0.33 + $pt[1];
  1742. // line 2
  1743. $pt2[2] = ($pt[2] -$pt[0])*0.33 + $pt[0];
  1744. $pt2[3] = ($pt[3] -$pt[1])*0.33 + $pt[1];
  1745. $pt2[4] = ($pt[4] -$pt[6])*0.33 + $pt[6];
  1746. $pt2[5] = ($pt[5] -$pt[7])*0.33 + $pt[7];
  1747. $pt2[8] = ($pt[8] -$pt[6])*0.33 + $pt[6];
  1748. $pt2[9] = ($pt[9] -$pt[7])*0.33 + $pt[7];
  1749. } else {
  1750. // line 1
  1751. $pt1[0] = ($pt[0]-$pt[6])*0.33 + $pt[6];
  1752. $pt1[1] = ($pt[1]-$pt[7])*0.33 + $pt[7];
  1753. $pt1[2] = ($pt[2]-$pt[4])*0.33 + $pt[4];
  1754. $pt1[3] = ($pt[3]-$pt[5])*0.33 + $pt[5];
  1755. // line 2
  1756. $pt2[6] = ($pt[6]-$pt[0])*0.33 + $pt[0];
  1757. $pt2[7] = ($pt[7]-$pt[1])*0.33 + $pt[1];
  1758. $pt2[4] = ($pt[4]-$pt[2])*0.33 + $pt[2];
  1759. $pt2[5] = ($pt[5]-$pt[3])*0.33 + $pt[3];
  1760. }
  1761. $this->pdf->Polygon($pt1, 'F');
  1762. $this->pdf->Polygon($pt2, 'F');
  1763. } else if ($type=='solid') {
  1764. // solid line : draw directly the polygon
  1765. $this->pdf->Polygon($pt, 'F');
  1766. }
  1767. }
  1768. /**
  1769. * prepare a transform matrix, only for drawing a SVG graphic
  1770. *
  1771. * @access protected
  1772. * @param string $transform
  1773. * @return array $matrix
  1774. */
  1775. protected function _prepareTransform($transform)
  1776. {
  1777. // it can not be empty
  1778. if (!$transform) return null;
  1779. // sctions must be like scale(...)
  1780. if (!preg_match_all('/([a-z]+)\(([^\)]*)\)/isU', $transform, $match)) return null;
  1781. // prepare the list of the actions
  1782. $actions = array();
  1783. // for actions
  1784. for ($k=0; $k<count($match[0]); $k++) {
  1785. // get the name of the action
  1786. $name = strtolower($match[1][$k]);
  1787. // get the parameters of the action
  1788. $val = explode(',', trim($match[2][$k]));
  1789. foreach ($val as $i => $j) {
  1790. $val[$i] = trim($j);
  1791. }
  1792. // prepare the matrix, depending on the action
  1793. switch($name)
  1794. {
  1795. case 'scale':
  1796. if (!isset($val[0])) $val[0] = 1.; else $val[0] = 1.*$val[0];
  1797. if (!isset($val[1])) $val[1] = $val[0]; else $val[1] = 1.*$val[1];
  1798. $actions[] = array($val[0],0,0,$val[1],0,0);
  1799. break;
  1800. case 'translate':
  1801. if (!isset($val[0])) $val[0] = 0.; else $val[0] = $this->parsingCss->ConvertToMM($val[0], $this->_isInDraw['w']);
  1802. if (!isset($val[1])) $val[1] = 0.; else $val[1] = $this->parsingCss->ConvertToMM($val[1], $this->_isInDraw['h']);
  1803. $actions[] = array(1,0,0,1,$val[0],$val[1]);
  1804. break;
  1805. case 'rotate':
  1806. if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.;
  1807. if (!isset($val[1])) $val[1] = 0.; else $val[1] = $this->parsingCss->ConvertToMM($val[1], $this->_isInDraw['w']);
  1808. if (!isset($val[2])) $val[2] = 0.; else $val[2] = $this->parsingCss->ConvertToMM($val[2], $this->_isInDraw['h']);
  1809. if ($val[1] || $val[2]) $actions[] = array(1,0,0,1,-$val[1],-$val[2]);
  1810. $actions[] = array(cos($val[0]),sin($val[0]),-sin($val[0]),cos($val[0]),0,0);
  1811. if ($val[1] || $val[2]) $actions[] = array(1,0,0,1,$val[1],$val[2]);
  1812. break;
  1813. case 'skewx':
  1814. if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.;
  1815. $actions[] = array(1,0,tan($val[0]),1,0,0);
  1816. break;
  1817. case 'skewy':
  1818. if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*M_PI/180.;
  1819. $actions[] = array(1,tan($val[0]),0,1,0,0);
  1820. break;
  1821. case 'matrix':
  1822. if (!isset($val[0])) $val[0] = 0.; else $val[0] = $val[0]*1.;
  1823. if (!isset($val[1])) $val[1] = 0.; else $val[1] = $val[1]*1.;
  1824. if (!isset($val[2])) $val[2] = 0.; else $val[2] = $val[2]*1.;
  1825. if (!isset($val[3])) $val[3] = 0.; else $val[3] = $val[3]*1.;
  1826. if (!isset($val[4])) $val[4] = 0.; else $val[4] = $this->parsingCss->ConvertToMM($val[4], $this->_isInDraw['w']);
  1827. if (!isset($val[5])) $val[5] = 0.; else $val[5] = $this->parsingCss->ConvertToMM($val[5], $this->_isInDraw['h']);
  1828. $actions[] =$val;
  1829. break;
  1830. }
  1831. }
  1832. // if ther is no actions => return
  1833. if (!$actions) return null;
  1834. // get the first matrix
  1835. $m = $actions[0]; unset($actions[0]);
  1836. // foreach matrix => multiply to the last matrix
  1837. foreach ($actions as $n) {
  1838. $m = array(
  1839. $m[0]*$n[0]+$m[2]*$n[1],
  1840. $m[1]*$n[0]+$m[3]*$n[1],
  1841. $m[0]*$n[2]+$m[2]*$n[3],
  1842. $m[1]*$n[2]+$m[3]*$n[3],
  1843. $m[0]*$n[4]+$m[2]*$n[5]+$m[4],
  1844. $m[1]*$n[4]+$m[3]*$n[5]+$m[5]
  1845. );
  1846. }
  1847. // return the matrix
  1848. return $m;
  1849. }
  1850. /**
  1851. * @access protected
  1852. * @param &array $cases
  1853. * @param &array $corr
  1854. */
  1855. protected function _calculateTableCellSize(&$cases, &$corr)
  1856. {
  1857. if (!isset($corr[0])) return true;
  1858. // for each cell without colspan, we get the max width for each column
  1859. $sw = array();
  1860. for ($x=0; $x<count($corr[0]); $x++) {
  1861. $m=0;
  1862. for ($y=0; $y<count($corr); $y++) {
  1863. if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][2]==1) {
  1864. $m = max($m, $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']);
  1865. }
  1866. }
  1867. $sw[$x] = $m;
  1868. }
  1869. // for each cell with colspan, we adapt the width of each column
  1870. for ($x=0; $x<count($corr[0]); $x++) {
  1871. for ($y=0; $y<count($corr); $y++) {
  1872. if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][2]>1) {
  1873. // sum the max width of each column in colspan
  1874. $s = 0; for ($i=0; $i<$corr[$y][$x][2]; $i++) $s+= $sw[$x+$i];
  1875. // if the max width is < the width of the cell with colspan => we adapt the width of each max width
  1876. if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w']) {
  1877. for ($i=0; $i<$corr[$y][$x][2]; $i++) {
  1878. $sw[$x+$i] = $sw[$x+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'];
  1879. }
  1880. }
  1881. }
  1882. }
  1883. }
  1884. // set the new width, for each cell
  1885. for ($x=0; $x<count($corr[0]); $x++) {
  1886. for ($y=0; $y<count($corr); $y++) {
  1887. if (isset($corr[$y][$x]) && is_array($corr[$y][$x])) {
  1888. // without colspan
  1889. if ($corr[$y][$x][2]==1) {
  1890. $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'] = $sw[$x];
  1891. // with colspan
  1892. } else {
  1893. $s = 0;
  1894. for ($i=0; $i<$corr[$y][$x][2]; $i++) {
  1895. $s+= $sw[$x+$i];
  1896. }
  1897. $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'] = $s;
  1898. }
  1899. }
  1900. }
  1901. }
  1902. // for each cell without rowspan, we get the max height for each line
  1903. $sh = array();
  1904. for ($y=0; $y<count($corr); $y++) {
  1905. $m=0;
  1906. for ($x=0; $x<count($corr[0]); $x++) {
  1907. if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][3]==1) {
  1908. $m = max($m, $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']);
  1909. }
  1910. }
  1911. $sh[$y] = $m;
  1912. }
  1913. // for each cell with rowspan, we adapt the height of each line
  1914. for ($y=0; $y<count($corr); $y++) {
  1915. for ($x=0; $x<count($corr[0]); $x++) {
  1916. if (isset($corr[$y][$x]) && is_array($corr[$y][$x]) && $corr[$y][$x][3]>1) {
  1917. // sum the max height of each line in rowspan
  1918. $s = 0; for ($i=0; $i<$corr[$y][$x][3]; $i++) $s+= $sh[$y+$i];
  1919. // if the max height is < the height of the cell with rowspan => we adapt the height of each max height
  1920. if ($s>0 && $s<$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h']) {
  1921. for ($i=0; $i<$corr[$y][$x][3]; $i++) {
  1922. $sh[$y+$i] = $sh[$y+$i]/$s*$cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'];
  1923. }
  1924. }
  1925. }
  1926. }
  1927. }
  1928. // set the new height, for each cell
  1929. for ($y=0; $y<count($corr); $y++) {
  1930. for ($x=0; $x<count($corr[0]); $x++) {
  1931. if (isset($corr[$y][$x]) && is_array($corr[$y][$x])) {
  1932. // without rowspan
  1933. if ($corr[$y][$x][3]==1) {
  1934. $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'] = $sh[$y];
  1935. // with rowspan
  1936. } else {
  1937. $s = 0;
  1938. for ($i=0; $i<$corr[$y][$x][3]; $i++) {
  1939. $s+= $sh[$y+$i];
  1940. }
  1941. $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['h'] = $s;
  1942. for ($j=1; $j<$corr[$y][$x][3]; $j++) {
  1943. $tx = $x+1;
  1944. $ty = $y+$j;
  1945. for (true; isset($corr[$ty][$tx]) && !is_array($corr[$ty][$tx]); $tx++);
  1946. if (isset($corr[$ty][$tx])) {
  1947. $cases[$corr[$ty][$tx][1]][$corr[$ty][$tx][0]]['dw']+= $cases[$corr[$y][$x][1]][$corr[$y][$x][0]]['w'];
  1948. }
  1949. }
  1950. }
  1951. }
  1952. }
  1953. }
  1954. }
  1955. /**
  1956. * tag : PAGE
  1957. * mode : OPEN
  1958. *
  1959. * @param array $param
  1960. * @return boolean
  1961. */
  1962. protected function _tag_open_PAGE($param)
  1963. {
  1964. if ($this->_isForOneLine) return false;
  1965. if ($this->_debugActif) $this->_DEBUG_add('PAGE '.($this->_page+1), true);
  1966. $newPageSet= (!isset($param['pageset']) || $param['pageset']!='old');
  1967. $resetPageNumber = (isset($param['pagegroup']) && $param['pagegroup']=='new');
  1968. $this->_maxH = 0;
  1969. // if new page set asked
  1970. if ($newPageSet) {
  1971. $this->_subHEADER = array();
  1972. $this->_subFOOTER = array();
  1973. $this->_subFIRST_HEADER = array();
  1974. $this->_subLAST_FOOTER = array();
  1975. // orientation
  1976. $orientation = '';
  1977. if (isset($param['orientation'])) {
  1978. $param['orientation'] = strtolower($param['orientation']);
  1979. if ($param['orientation']=='p') $orientation = 'P';
  1980. if ($param['orientation']=='portrait') $orientation = 'P';
  1981. if ($param['orientation']=='l') $orientation = 'L';
  1982. if ($param['orientation']=='paysage') $orientation = 'L';
  1983. if ($param['orientation']=='landscape') $orientation = 'L';
  1984. }
  1985. // format
  1986. $format = null;
  1987. if (isset($param['format'])) {
  1988. $format = strtolower($param['format']);
  1989. if (preg_match('/^([0-9]+)x([0-9]+)$/isU', $format, $match)) {
  1990. $format = array(intval($match[1]), intval($match[2]));
  1991. }
  1992. }
  1993. // background
  1994. $background = array();
  1995. if (isset($param['backimg'])) {
  1996. $background['img'] = isset($param['backimg']) ? $param['backimg'] : ''; // src of the image
  1997. $background['posX'] = isset($param['backimgx']) ? $param['backimgx'] : 'center'; // horizontale position of the image
  1998. $background['posY'] = isset($param['backimgy']) ? $param['backimgy'] : 'middle'; // vertical position of the image
  1999. $background['width'] = isset($param['backimgw']) ? $param['backimgw'] : '100%'; // width of the image (100% = page width)
  2000. // convert the src of the image, if parameters
  2001. $background['img'] = str_replace('&amp;', '&', $background['img']);
  2002. // convert the positions
  2003. if ($background['posX']=='left') $background['posX'] = '0%';
  2004. if ($background['posX']=='center') $background['posX'] = '50%';
  2005. if ($background['posX']=='right') $background['posX'] = '100%';
  2006. if ($background['posY']=='top') $background['posY'] = '0%';
  2007. if ($background['posY']=='middle') $background['posY'] = '50%';
  2008. if ($background['posY']=='bottom') $background['posY'] = '100%';
  2009. if ($background['img']) {
  2010. // get the size of the image
  2011. // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini
  2012. $infos=@getimagesize($background['img']);
  2013. if (count($infos)>1) {
  2014. $imageWidth = $this->parsingCss->ConvertToMM($background['width'], $this->pdf->getW());
  2015. $imageHeight = $imageWidth*$infos[1]/$infos[0];
  2016. $background['width'] = $imageWidth;
  2017. $background['posX'] = $this->parsingCss->ConvertToMM($background['posX'], $this->pdf->getW() - $imageWidth);
  2018. $background['posY'] = $this->parsingCss->ConvertToMM($background['posY'], $this->pdf->getH() - $imageHeight);
  2019. } else {
  2020. $background = array();
  2021. }
  2022. } else {
  2023. $background = array();
  2024. }
  2025. }
  2026. // margins of the page
  2027. $background['top'] = isset($param['backtop']) ? $param['backtop'] : '0';
  2028. $background['bottom'] = isset($param['backbottom']) ? $param['backbottom'] : '0';
  2029. $background['left'] = isset($param['backleft']) ? $param['backleft'] : '0';
  2030. $background['right'] = isset($param['backright']) ? $param['backright'] : '0';
  2031. $background['top-first'] = isset($param['backtopfirst']) ? $param['backtopfirst'] : $background['top'];
  2032. $background['bottom-first'] = isset($param['backbottomfirst']) ? $param['backbottomfirst'] : $background['bottom'];
  2033. $background['left-first'] = isset($param['backleftfirst']) ? $param['backleftfirst'] : $background['left'];
  2034. $background['right-first'] = isset($param['backrightfirst']) ? $param['backrightfirst'] : $background['right'];
  2035. // if no unit => mm
  2036. if (preg_match('/^([0-9]*)$/isU', $background['top'])) $background['top'] .= 'mm';
  2037. if (preg_match('/^([0-9]*)$/isU', $background['bottom'])) $background['bottom'] .= 'mm';
  2038. if (preg_match('/^([0-9]*)$/isU', $background['left'])) $background['left'] .= 'mm';
  2039. if (preg_match('/^([0-9]*)$/isU', $background['right'])) $background['right'] .= 'mm';
  2040. if (preg_match('/^([0-9]*)$/isU', $background['top-first'])) $background['top-first'] .= 'mm';
  2041. if (preg_match('/^([0-9]*)$/isU', $background['bottom-first'])) $background['bottom-first'] .= 'mm';
  2042. if (preg_match('/^([0-9]*)$/isU', $background['left-first'])) $background['left-first'] .= 'mm';
  2043. if (preg_match('/^([0-9]*)$/isU', $background['right-first'])) $background['right-first'] .= 'mm';
  2044. // convert to mm
  2045. $background['top'] = $this->parsingCss->ConvertToMM($background['top'], $this->pdf->getH());
  2046. $background['bottom'] = $this->parsingCss->ConvertToMM($background['bottom'], $this->pdf->getH());
  2047. $background['left'] = $this->parsingCss->ConvertToMM($background['left'], $this->pdf->getW());
  2048. $background['right'] = $this->parsingCss->ConvertToMM($background['right'], $this->pdf->getW());
  2049. $background['top-first'] = $this->parsingCss->ConvertToMM($background['top-first'], $this->pdf->getH());
  2050. $background['bottom-first'] = $this->parsingCss->ConvertToMM($background['bottom-first'], $this->pdf->getH());
  2051. $background['left-first'] = $this->parsingCss->ConvertToMM($background['left-first'], $this->pdf->getW());
  2052. $background['right-first'] = $this->parsingCss->ConvertToMM($background['right-first'], $this->pdf->getW());
  2053. // get the background color
  2054. $res = false;
  2055. $background['color'] = isset($param['backcolor']) ? $this->parsingCss->convertToColor($param['backcolor'], $res) : null;
  2056. if (!$res) $background['color'] = null;
  2057. $this->parsingCss->save();
  2058. $this->parsingCss->analyse('PAGE', $param);
  2059. $this->parsingCss->setPosition();
  2060. $this->parsingCss->fontSet();
  2061. // new page
  2062. $this->_setNewPage($format, $orientation, $background, null, $resetPageNumber);
  2063. // automatic footer
  2064. if (isset($param['footer'])) {
  2065. $lst = explode(';', $param['footer']);
  2066. foreach ($lst as $key => $val) $lst[$key] = trim(strtolower($val));
  2067. $page = in_array('page', $lst);
  2068. $date = in_array('date', $lst);
  2069. $hour = in_array('heure', $lst);
  2070. $form = in_array('form', $lst);
  2071. } else {
  2072. $page = null;
  2073. $date = null;
  2074. $hour = null;
  2075. $form = null;
  2076. }
  2077. $this->pdf->SetMyFooter($page, $date, $hour, $form);
  2078. // else => we use the last page set used
  2079. } else {
  2080. $this->parsingCss->save();
  2081. $this->parsingCss->analyse('PAGE', $param);
  2082. $this->parsingCss->setPosition();
  2083. $this->parsingCss->fontSet();
  2084. $this->_setNewPage(null, null, null, null, $resetPageNumber);
  2085. }
  2086. return true;
  2087. }
  2088. /**
  2089. * tag : PAGE
  2090. * mode : CLOSE
  2091. *
  2092. * @param array $param
  2093. * @return boolean
  2094. */
  2095. protected function _tag_close_PAGE($param)
  2096. {
  2097. if ($this->_isForOneLine) return false;
  2098. $this->_maxH = 0;
  2099. $this->parsingCss->load();
  2100. $this->parsingCss->fontSet();
  2101. if ($this->_debugActif) $this->_DEBUG_add('PAGE '.$this->_page, false);
  2102. return true;
  2103. }
  2104. /**
  2105. * tag : PAGE_HEADER
  2106. * mode : OPEN
  2107. *
  2108. * @param array $param
  2109. * @return boolean
  2110. */
  2111. protected function _tag_open_PAGE_HEADER($param)
  2112. {
  2113. if ($this->_isForOneLine) return false;
  2114. $first = $param['type'] == 'first';
  2115. $prop = $first ? '_subFIRST_HEADER' : '_subHEADER';
  2116. $this->{$prop} = array();
  2117. for ($this->_parsePos; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) {
  2118. $action = $this->parsingHtml->code[$this->_parsePos];
  2119. if ($action['name']=='page_header') $action['name']='page_header_sub';
  2120. $this->{$prop} []= $action;
  2121. if (strtolower($action['name'])=='page_header_sub' && $action['close']) break;
  2122. }
  2123. $this->_setPageHeader();
  2124. return true;
  2125. }
  2126. /**
  2127. * tag : PAGE_FOOTER
  2128. * mode : OPEN
  2129. *
  2130. * @param array $param
  2131. * @return boolean
  2132. */
  2133. protected function _tag_open_PAGE_FOOTER($param)
  2134. {
  2135. if ($this->_isForOneLine) return false;
  2136. $last = isset($param['type']) && $param['type'] == 'last';
  2137. $prop = $last ? '_subLAST_FOOTER' : '_subFOOTER';
  2138. $this->{$prop} = array();
  2139. for ($this->_parsePos; $this->_parsePos<count($this->parsingHtml->code); $this->_parsePos++) {
  2140. $action = $this->parsingHtml->code[$this->_parsePos];
  2141. if ($action['name']=='page_footer') $action['name']='page_footer_sub';
  2142. $this->{$prop} []= $action;
  2143. if (strtolower($action['name'])=='page_footer_sub' && $action['close']) break;
  2144. }
  2145. $this->_setPageFooter();
  2146. return true;
  2147. }
  2148. /**
  2149. * It is not a real tag. Does not use it directly
  2150. *
  2151. * @param array $param
  2152. * @return boolean
  2153. */
  2154. protected function _tag_open_PAGE_HEADER_SUB($param)
  2155. {
  2156. if ($this->_isForOneLine) return false;
  2157. // save the current stat
  2158. $this->_subSTATES = array();
  2159. $this->_subSTATES['x'] = $this->pdf->getX();
  2160. $this->_subSTATES['y'] = $this->pdf->getY();
  2161. $this->_subSTATES['s'] = $this->parsingCss->value;
  2162. $this->_subSTATES['t'] = $this->parsingCss->table;
  2163. $this->_subSTATES['ml'] = $this->_margeLeft;
  2164. $this->_subSTATES['mr'] = $this->_margeRight;
  2165. $this->_subSTATES['mt'] = $this->_margeTop;
  2166. $this->_subSTATES['mb'] = $this->_margeBottom;
  2167. $this->_subSTATES['mp'] = $this->_pageMarges;
  2168. // new stat for the header
  2169. $this->_pageMarges = array();
  2170. $this->_margeLeft = $this->_defaultLeft;
  2171. $this->_margeRight = $this->_defaultRight;
  2172. $this->_margeTop = $this->_defaultTop;
  2173. $this->_margeBottom = $this->_defaultBottom;
  2174. $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
  2175. $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
  2176. $this->pdf->setXY($this->_defaultLeft, $this->_defaultTop);
  2177. $this->parsingCss->initStyle();
  2178. $this->parsingCss->resetStyle();
  2179. $this->parsingCss->value['width'] = $this->pdf->getW() - $this->_defaultLeft - $this->_defaultRight;
  2180. $this->parsingCss->table = array();
  2181. $this->parsingCss->save();
  2182. $this->parsingCss->analyse('page_header_sub', $param);
  2183. $this->parsingCss->setPosition();
  2184. $this->parsingCss->fontSet();
  2185. $this->_setNewPositionForNewLine();
  2186. return true;
  2187. }
  2188. /**
  2189. * It is not a real tag. Does not use it directly
  2190. *
  2191. * @param array $param
  2192. * @return boolean
  2193. */
  2194. protected function _tag_close_PAGE_HEADER_SUB($param)
  2195. {
  2196. if ($this->_isForOneLine) return false;
  2197. $this->parsingCss->load();
  2198. // restore the stat
  2199. $this->parsingCss->value = $this->_subSTATES['s'];
  2200. $this->parsingCss->table = $this->_subSTATES['t'];
  2201. $this->_pageMarges = $this->_subSTATES['mp'];
  2202. $this->_margeLeft = $this->_subSTATES['ml'];
  2203. $this->_margeRight = $this->_subSTATES['mr'];
  2204. $this->_margeTop = $this->_subSTATES['mt'];
  2205. $this->_margeBottom = $this->_subSTATES['mb'];
  2206. $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
  2207. $this->pdf->setbMargin($this->_margeBottom);
  2208. $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
  2209. $this->pdf->setXY($this->_subSTATES['x'], $this->_subSTATES['y']);
  2210. $this->parsingCss->fontSet();
  2211. $this->_maxH = 0;
  2212. return true;
  2213. }
  2214. /**
  2215. * It is not a real tag. Does not use it directly
  2216. *
  2217. * @param array $param
  2218. * @return boolean
  2219. */
  2220. protected function _tag_open_PAGE_FOOTER_SUB($param)
  2221. {
  2222. if ($this->_isForOneLine) return false;
  2223. // save the current stat
  2224. $this->_subSTATES = array();
  2225. $this->_subSTATES['x'] = $this->pdf->getX();
  2226. $this->_subSTATES['y'] = $this->pdf->getY();
  2227. $this->_subSTATES['s'] = $this->parsingCss->value;
  2228. $this->_subSTATES['t'] = $this->parsingCss->table;
  2229. $this->_subSTATES['ml'] = $this->_margeLeft;
  2230. $this->_subSTATES['mr'] = $this->_margeRight;
  2231. $this->_subSTATES['mt'] = $this->_margeTop;
  2232. $this->_subSTATES['mb'] = $this->_margeBottom;
  2233. $this->_subSTATES['mp'] = $this->_pageMarges;
  2234. // new stat for the footer
  2235. $this->_pageMarges = array();
  2236. $this->_margeLeft = $this->_defaultLeft;
  2237. $this->_margeRight = $this->_defaultRight;
  2238. $this->_margeTop = $this->_defaultTop;
  2239. $this->_margeBottom = $this->_defaultBottom;
  2240. $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
  2241. $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
  2242. $this->pdf->setXY($this->_defaultLeft, $this->_defaultTop);
  2243. $this->parsingCss->initStyle();
  2244. $this->parsingCss->resetStyle();
  2245. $this->parsingCss->value['width'] = $this->pdf->getW() - $this->_defaultLeft - $this->_defaultRight;
  2246. $this->parsingCss->table = array();
  2247. // we create a sub HTML2PFDF, and we execute on it the content of the footer, to get the height of it
  2248. $sub = null;
  2249. $this->_createSubHTML($sub);
  2250. $sub->parsingHtml->code = $this->parsingHtml->getLevel($this->_parsePos);
  2251. $sub->_makeHTMLcode();
  2252. $this->pdf->setY($this->pdf->getH() - $sub->_maxY - $this->_defaultBottom - 0.01);
  2253. $this->_destroySubHTML($sub);
  2254. $this->parsingCss->save();
  2255. $this->parsingCss->analyse('page_footer_sub', $param);
  2256. $this->parsingCss->setPosition();
  2257. $this->parsingCss->fontSet();
  2258. $this->_setNewPositionForNewLine();
  2259. return true;
  2260. }
  2261. /**
  2262. * It is not a real tag. Does not use it directly
  2263. *
  2264. * @param array $param
  2265. * @return boolean
  2266. */
  2267. protected function _tag_close_PAGE_FOOTER_SUB($param)
  2268. {
  2269. if ($this->_isForOneLine) return false;
  2270. $this->parsingCss->load();
  2271. $this->parsingCss->value = $this->_subSTATES['s'];
  2272. $this->parsingCss->table = $this->_subSTATES['t'];
  2273. $this->_pageMarges = $this->_subSTATES['mp'];
  2274. $this->_margeLeft = $this->_subSTATES['ml'];
  2275. $this->_margeRight = $this->_subSTATES['mr'];
  2276. $this->_margeTop = $this->_subSTATES['mt'];
  2277. $this->_margeBottom = $this->_subSTATES['mb'];
  2278. $this->pdf->SetMargins($this->_margeLeft, $this->_margeTop, $this->_margeRight);
  2279. $this->pdf->SetAutoPageBreak(false, $this->_margeBottom);
  2280. $this->pdf->setXY($this->_subSTATES['x'], $this->_subSTATES['y']);
  2281. $this->parsingCss->fontSet();
  2282. $this->_maxH = 0;
  2283. return true;
  2284. }
  2285. /**
  2286. * tag : NOBREAK
  2287. * mode : OPEN
  2288. *
  2289. * @param array $param
  2290. * @return boolean
  2291. */
  2292. protected function _tag_open_NOBREAK($param)
  2293. {
  2294. if ($this->_isForOneLine) return false;
  2295. $this->_maxH = 0;
  2296. $this->_makeBreakLine(0); // see http://www.yaronet.com/posts.php?s=141436
  2297. // create a sub HTML2PDF to execute the content of the tag, to get the dimensions
  2298. $sub = null;
  2299. $this->_createSubHTML($sub);
  2300. $sub->parsingHtml->code = $this->parsingHtml->getLevel($this->_parsePos);
  2301. $sub->_makeHTMLcode();
  2302. $y = $this->pdf->getY();
  2303. // if the content does not fit on the page => new page
  2304. if (
  2305. $sub->_maxY < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin()) &&
  2306. $y + $sub->_maxY>=($this->pdf->getH() - $this->pdf->getbMargin())
  2307. ) {
  2308. $this->_setNewPage();
  2309. }
  2310. // destroy the sub HTML2PDF
  2311. $this->_destroySubHTML($sub);
  2312. return true;
  2313. }
  2314. /**
  2315. * tag : NOBREAK
  2316. * mode : CLOSE
  2317. *
  2318. * @param array $param
  2319. * @return boolean
  2320. */
  2321. protected function _tag_close_NOBREAK($param)
  2322. {
  2323. if ($this->_isForOneLine) return false;
  2324. $this->_maxH = 0;
  2325. return true;
  2326. }
  2327. /**
  2328. * tag : DIV
  2329. * mode : OPEN
  2330. *
  2331. * @param array $param
  2332. * @param string $other name of tag that used the div tag
  2333. * @return boolean
  2334. */
  2335. protected function _tag_open_DIV($param, $other = 'div')
  2336. {
  2337. if ($this->_isForOneLine) return false;
  2338. if ($this->_debugActif) $this->_DEBUG_add(strtoupper($other), true);
  2339. $this->parsingCss->save();
  2340. $this->parsingCss->analyse($other, $param);
  2341. $this->parsingCss->fontSet();
  2342. // for fieldset and legend
  2343. if (in_array($other, array('fieldset', 'legend'))) {
  2344. if (isset($param['moveTop'])) $this->parsingCss->value['margin']['t'] += $param['moveTop'];
  2345. if (isset($param['moveLeft'])) $this->parsingCss->value['margin']['l'] += $param['moveLeft'];
  2346. if (isset($param['moveDown'])) $this->parsingCss->value['margin']['b'] += $param['moveDown'];
  2347. }
  2348. $alignObject = null;
  2349. if ($this->parsingCss->value['margin-auto']) $alignObject = 'center';
  2350. $marge = array();
  2351. $marge['l'] = $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['padding']['l']+0.03;
  2352. $marge['r'] = $this->parsingCss->value['border']['r']['width'] + $this->parsingCss->value['padding']['r']+0.03;
  2353. $marge['t'] = $this->parsingCss->value['border']['t']['width'] + $this->parsingCss->value['padding']['t']+0.03;
  2354. $marge['b'] = $this->parsingCss->value['border']['b']['width'] + $this->parsingCss->value['padding']['b']+0.03;
  2355. // extract the content of the div
  2356. $level = $this->parsingHtml->getLevel($this->_parsePos);
  2357. // create a sub HTML2PDF to get the dimensions of the content of the div
  2358. $w = 0; $h = 0;
  2359. if (count($level)) {
  2360. $sub = null;
  2361. $this->_createSubHTML($sub);
  2362. $sub->parsingHtml->code = $level;
  2363. $sub->_makeHTMLcode();
  2364. $w = $sub->_maxX;
  2365. $h = $sub->_maxY;
  2366. $this->_destroySubHTML($sub);
  2367. }
  2368. $wReel = $w;
  2369. $hReel = $h;
  2370. $w+= $marge['l']+$marge['r']+0.001;
  2371. $h+= $marge['t']+$marge['b']+0.001;
  2372. if ($this->parsingCss->value['overflow']=='hidden') {
  2373. $overW = max($w, $this->parsingCss->value['width']);
  2374. $overH = max($h, $this->parsingCss->value['height']);
  2375. $overflow = true;
  2376. $this->parsingCss->value['old_maxX'] = $this->_maxX;
  2377. $this->parsingCss->value['old_maxY'] = $this->_maxY;
  2378. $this->parsingCss->value['old_maxH'] = $this->_maxH;
  2379. $this->parsingCss->value['old_overflow'] = $this->_isInOverflow;
  2380. $this->_isInOverflow = true;
  2381. } else {
  2382. $overW = null;
  2383. $overH = null;
  2384. $overflow = false;
  2385. $this->parsingCss->value['width'] = max($w, $this->parsingCss->value['width']);
  2386. $this->parsingCss->value['height'] = max($h, $this->parsingCss->value['height']);
  2387. }
  2388. switch($this->parsingCss->value['rotate'])
  2389. {
  2390. case 90:
  2391. $tmp = $overH; $overH = $overW; $overW = $tmp;
  2392. $tmp = $hReel; $hReel = $wReel; $wReel = $tmp;
  2393. unset($tmp);
  2394. $w = $this->parsingCss->value['height'];
  2395. $h = $this->parsingCss->value['width'];
  2396. $tX =-$h;
  2397. $tY = 0;
  2398. break;
  2399. case 180:
  2400. $w = $this->parsingCss->value['width'];
  2401. $h = $this->parsingCss->value['height'];
  2402. $tX = -$w;
  2403. $tY = -$h;
  2404. break;
  2405. case 270:
  2406. $tmp = $overH; $overH = $overW; $overW = $tmp;
  2407. $tmp = $hReel; $hReel = $wReel; $wReel = $tmp;
  2408. unset($tmp);
  2409. $w = $this->parsingCss->value['height'];
  2410. $h = $this->parsingCss->value['width'];
  2411. $tX = 0;
  2412. $tY =-$w;
  2413. break;
  2414. default:
  2415. $w = $this->parsingCss->value['width'];
  2416. $h = $this->parsingCss->value['height'];
  2417. $tX = 0;
  2418. $tY = 0;
  2419. break;
  2420. }
  2421. if (!$this->parsingCss->value['position']) {
  2422. if (
  2423. $w < ($this->pdf->getW() - $this->pdf->getlMargin()-$this->pdf->getrMargin()) &&
  2424. $this->pdf->getX() + $w>=($this->pdf->getW() - $this->pdf->getrMargin())
  2425. )
  2426. $this->_tag_open_BR(array());
  2427. if (
  2428. ($h < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin())) &&
  2429. ($this->pdf->getY() + $h>=($this->pdf->getH() - $this->pdf->getbMargin())) &&
  2430. !$this->_isInOverflow
  2431. )
  2432. $this->_setNewPage();
  2433. $old = $this->parsingCss->getOldValues();
  2434. $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  2435. if ($parentWidth>$w) {
  2436. if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
  2437. else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
  2438. }
  2439. $this->parsingCss->setPosition();
  2440. } else {
  2441. $old = $this->parsingCss->getOldValues();
  2442. $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  2443. if ($parentWidth>$w) {
  2444. if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
  2445. else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
  2446. }
  2447. $this->parsingCss->setPosition();
  2448. $this->_saveMax();
  2449. $this->_maxX = 0;
  2450. $this->_maxY = 0;
  2451. $this->_maxH = 0;
  2452. $this->_maxE = 0;
  2453. }
  2454. if ($this->parsingCss->value['rotate']) {
  2455. $this->pdf->startTransform();
  2456. $this->pdf->setRotation($this->parsingCss->value['rotate']);
  2457. $this->pdf->setTranslate($tX, $tY);
  2458. }
  2459. $this->_drawRectangle(
  2460. $this->parsingCss->value['x'],
  2461. $this->parsingCss->value['y'],
  2462. $this->parsingCss->value['width'],
  2463. $this->parsingCss->value['height'],
  2464. $this->parsingCss->value['border'],
  2465. $this->parsingCss->value['padding'],
  2466. 0,
  2467. $this->parsingCss->value['background']
  2468. );
  2469. $marge = array();
  2470. $marge['l'] = $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['padding']['l']+0.03;
  2471. $marge['r'] = $this->parsingCss->value['border']['r']['width'] + $this->parsingCss->value['padding']['r']+0.03;
  2472. $marge['t'] = $this->parsingCss->value['border']['t']['width'] + $this->parsingCss->value['padding']['t']+0.03;
  2473. $marge['b'] = $this->parsingCss->value['border']['b']['width'] + $this->parsingCss->value['padding']['b']+0.03;
  2474. $this->parsingCss->value['width'] -= $marge['l']+$marge['r'];
  2475. $this->parsingCss->value['height']-= $marge['t']+$marge['b'];
  2476. $xCorr = 0;
  2477. $yCorr = 0;
  2478. if (!$this->_subPart && !$this->_isSubPart) {
  2479. switch($this->parsingCss->value['text-align'])
  2480. {
  2481. case 'right':
  2482. $xCorr = ($this->parsingCss->value['width']-$wReel);
  2483. break;
  2484. case 'center':
  2485. $xCorr = ($this->parsingCss->value['width']-$wReel)*0.5;
  2486. break;
  2487. }
  2488. if ($xCorr>0) $xCorr=0;
  2489. switch($this->parsingCss->value['vertical-align'])
  2490. {
  2491. case 'bottom':
  2492. $yCorr = ($this->parsingCss->value['height']-$hReel);
  2493. break;
  2494. case 'middle':
  2495. $yCorr = ($this->parsingCss->value['height']-$hReel)*0.5;
  2496. break;
  2497. }
  2498. }
  2499. if ($overflow) {
  2500. $overW-= $marge['l']+$marge['r'];
  2501. $overH-= $marge['t']+$marge['b'];
  2502. $this->pdf->clippingPathStart(
  2503. $this->parsingCss->value['x']+$marge['l'],
  2504. $this->parsingCss->value['y']+$marge['t'],
  2505. $this->parsingCss->value['width'],
  2506. $this->parsingCss->value['height']
  2507. );
  2508. $this->parsingCss->value['x']+= $xCorr;
  2509. // marges from the dimension of the content
  2510. $mL = $this->parsingCss->value['x']+$marge['l'];
  2511. $mR = $this->pdf->getW() - $mL - $overW;
  2512. } else {
  2513. // marges from the dimension of the div
  2514. $mL = $this->parsingCss->value['x']+$marge['l'];
  2515. $mR = $this->pdf->getW() - $mL - $this->parsingCss->value['width'];
  2516. }
  2517. $x = $this->parsingCss->value['x']+$marge['l'];
  2518. $y = $this->parsingCss->value['y']+$marge['t']+$yCorr;
  2519. $this->_saveMargin($mL, 0, $mR);
  2520. $this->pdf->setXY($x, $y);
  2521. $this->_setNewPositionForNewLine();
  2522. return true;
  2523. }
  2524. /**
  2525. * tag : BLOCKQUOTE
  2526. * mode : OPEN
  2527. *
  2528. * @param array $param
  2529. * @return boolean
  2530. */
  2531. protected function _tag_open_BLOCKQUOTE($param)
  2532. {
  2533. return $this->_tag_open_DIV($param, 'blockquote');
  2534. }
  2535. /**
  2536. * tag : LEGEND
  2537. * mode : OPEN
  2538. *
  2539. * @param array $param
  2540. * @return boolean
  2541. */
  2542. protected function _tag_open_LEGEND($param)
  2543. {
  2544. return $this->_tag_open_DIV($param, 'legend');
  2545. }
  2546. /**
  2547. * tag : FIELDSET
  2548. * mode : OPEN
  2549. *
  2550. * @author Pavel Kochman
  2551. * @param array $param
  2552. * @return boolean
  2553. */
  2554. protected function _tag_open_FIELDSET($param)
  2555. {
  2556. $this->parsingCss->save();
  2557. $this->parsingCss->analyse('fieldset', $param);
  2558. // get height of LEGEND element and make fieldset corrections
  2559. for ($tempPos = $this->_parsePos + 1; $tempPos<count($this->parsingHtml->code); $tempPos++) {
  2560. $action = $this->parsingHtml->code[$tempPos];
  2561. if ($action['name'] == 'fieldset') break;
  2562. if ($action['name'] == 'legend' && !$action['close']) {
  2563. $legendOpenPos = $tempPos;
  2564. $sub = null;
  2565. $this->_createSubHTML($sub);
  2566. $sub->parsingHtml->code = $this->parsingHtml->getLevel($tempPos - 1);
  2567. $res = null;
  2568. for ($sub->_parsePos = 0; $sub->_parsePos<count($sub->parsingHtml->code); $sub->_parsePos++) {
  2569. $action = $sub->parsingHtml->code[$sub->_parsePos];
  2570. $sub->_executeAction($action);
  2571. if ($action['name'] == 'legend' && $action['close'])
  2572. break;
  2573. }
  2574. $legendH = $sub->_maxY;
  2575. $this->_destroySubHTML($sub);
  2576. $move = $this->parsingCss->value['padding']['t'] + $this->parsingCss->value['border']['t']['width'] + 0.03;
  2577. $param['moveTop'] = $legendH / 2;
  2578. $this->parsingHtml->code[$legendOpenPos]['param']['moveTop'] = - ($legendH / 2 + $move);
  2579. $this->parsingHtml->code[$legendOpenPos]['param']['moveLeft'] = 2 - $this->parsingCss->value['border']['l']['width'] - $this->parsingCss->value['padding']['l'];
  2580. $this->parsingHtml->code[$legendOpenPos]['param']['moveDown'] = $move;
  2581. break;
  2582. }
  2583. }
  2584. $this->parsingCss->load();
  2585. return $this->_tag_open_DIV($param, 'fieldset');
  2586. }
  2587. /**
  2588. * tag : DIV
  2589. * mode : CLOSE
  2590. *
  2591. * @param array $param
  2592. * @param string $other name of tag that used the div tag
  2593. * @return boolean
  2594. */
  2595. protected function _tag_close_DIV($param, $other='div')
  2596. {
  2597. if ($this->_isForOneLine) return false;
  2598. if ($this->parsingCss->value['overflow']=='hidden') {
  2599. $this->_maxX = $this->parsingCss->value['old_maxX'];
  2600. $this->_maxY = $this->parsingCss->value['old_maxY'];
  2601. $this->_maxH = $this->parsingCss->value['old_maxH'];
  2602. $this->_isInOverflow = $this->parsingCss->value['old_overflow'];
  2603. $this->pdf->clippingPathStop();
  2604. }
  2605. if ($this->parsingCss->value['rotate'])
  2606. $this->pdf->stopTransform();
  2607. $marge = array();
  2608. $marge['l'] = $this->parsingCss->value['border']['l']['width'] + $this->parsingCss->value['padding']['l']+0.03;
  2609. $marge['r'] = $this->parsingCss->value['border']['r']['width'] + $this->parsingCss->value['padding']['r']+0.03;
  2610. $marge['t'] = $this->parsingCss->value['border']['t']['width'] + $this->parsingCss->value['padding']['t']+0.03;
  2611. $marge['b'] = $this->parsingCss->value['border']['b']['width'] + $this->parsingCss->value['padding']['b']+0.03;
  2612. $x = $this->parsingCss->value['x'];
  2613. $y = $this->parsingCss->value['y'];
  2614. $w = $this->parsingCss->value['width']+$marge['l']+$marge['r']+$this->parsingCss->value['margin']['r'];
  2615. $h = $this->parsingCss->value['height']+$marge['t']+$marge['b']+$this->parsingCss->value['margin']['b'];
  2616. switch($this->parsingCss->value['rotate'])
  2617. {
  2618. case 90:
  2619. $t = $w; $w = $h; $h = $t;
  2620. break;
  2621. case 270:
  2622. $t = $w; $w = $h; $h = $t;
  2623. break;
  2624. default:
  2625. break;
  2626. }
  2627. if ($this->parsingCss->value['position']!='absolute') {
  2628. $this->pdf->setXY($x+$w, $y);
  2629. $this->_maxX = max($this->_maxX, $x+$w);
  2630. $this->_maxY = max($this->_maxY, $y+$h);
  2631. $this->_maxH = max($this->_maxH, $h);
  2632. } else {
  2633. $this->pdf->setXY($this->parsingCss->value['xc'], $this->parsingCss->value['yc']);
  2634. $this->_loadMax();
  2635. }
  2636. $block = ($this->parsingCss->value['display']!='inline' && $this->parsingCss->value['position']!='absolute');
  2637. $this->parsingCss->load();
  2638. $this->parsingCss->fontSet();
  2639. $this->_loadMargin();
  2640. if ($block) $this->_tag_open_BR(array());
  2641. if ($this->_debugActif) $this->_DEBUG_add(strtoupper($other), false);
  2642. return true;
  2643. }
  2644. /**
  2645. * tag : BLOCKQUOTE
  2646. * mode : CLOSE
  2647. *
  2648. * @param array $param
  2649. * @return boolean
  2650. */
  2651. protected function _tag_close_BLOCKQUOTE($param)
  2652. {
  2653. return $this->_tag_close_DIV($param, 'blockquote');
  2654. }
  2655. /**
  2656. * tag : FIELDSET
  2657. * mode : CLOSE
  2658. *
  2659. * @param array $param
  2660. * @return boolean
  2661. */
  2662. protected function _tag_close_FIELDSET($param)
  2663. {
  2664. return $this->_tag_close_DIV($param, 'fieldset');
  2665. }
  2666. /**
  2667. * tag : LEGEND
  2668. * mode : CLOSE
  2669. *
  2670. * @param array $param
  2671. * @return boolean
  2672. */
  2673. protected function _tag_close_LEGEND($param)
  2674. {
  2675. return $this->_tag_close_DIV($param, 'legend');
  2676. }
  2677. /**
  2678. * tag : BARCODE
  2679. * mode : OPEN
  2680. *
  2681. * @param array $param
  2682. * @return boolean
  2683. */
  2684. protected function _tag_open_BARCODE($param)
  2685. {
  2686. // for compatibility with old versions < 3.29
  2687. $lstBarcode = array();
  2688. $lstBarcode['UPC_A'] = 'UPCA';
  2689. $lstBarcode['CODE39'] = 'C39';
  2690. if (!isset($param['type'])) $param['type'] = 'C39';
  2691. if (!isset($param['value'])) $param['value'] = 0;
  2692. if (!isset($param['label'])) $param['label'] = 'label';
  2693. if (!isset($param['style']['color'])) $param['style']['color'] = '#000000';
  2694. if ($this->_testIsDeprecated && (isset($param['bar_h']) || isset($param['bar_w'])))
  2695. throw new HTML2PDF_exception(9, array('BARCODE', 'bar_h, bar_w'));
  2696. $param['type'] = strtoupper($param['type']);
  2697. if (isset($lstBarcode[$param['type']])) $param['type'] = $lstBarcode[$param['type']];
  2698. $this->parsingCss->save();
  2699. $this->parsingCss->analyse('barcode', $param);
  2700. $this->parsingCss->setPosition();
  2701. $this->parsingCss->fontSet();
  2702. $x = $this->pdf->getX();
  2703. $y = $this->pdf->getY();
  2704. $w = $this->parsingCss->value['width']; if (!$w) $w = $this->parsingCss->ConvertToMM('50mm');
  2705. $h = $this->parsingCss->value['height']; if (!$h) $h = $this->parsingCss->ConvertToMM('10mm');
  2706. $txt = ($param['label']!=='none' ? $this->parsingCss->value['font-size'] : false);
  2707. $c = $this->parsingCss->value['color'];
  2708. $infos = $this->pdf->myBarcode($param['value'], $param['type'], $x, $y, $w, $h, $txt, $c);
  2709. $this->_maxX = max($this->_maxX, $x+$infos[0]);
  2710. $this->_maxY = max($this->_maxY, $y+$infos[1]);
  2711. $this->_maxH = max($this->_maxH, $infos[1]);
  2712. $this->_maxE++;
  2713. $this->pdf->setXY($x+$infos[0], $y);
  2714. $this->parsingCss->load();
  2715. $this->parsingCss->fontSet();
  2716. return true;
  2717. }
  2718. /**
  2719. * tag : BARCODE
  2720. * mode : CLOSE
  2721. *
  2722. * @param array $param
  2723. * @return boolean
  2724. */
  2725. protected function _tag_close_BARCODE($param)
  2726. {
  2727. // there is nothing to do here
  2728. return true;
  2729. }
  2730. /**
  2731. * tag : QRCODE
  2732. * mode : OPEN
  2733. *
  2734. * @param array $param
  2735. * @return boolean
  2736. */
  2737. protected function _tag_open_QRCODE($param)
  2738. {
  2739. if ($this->_testIsDeprecated && (isset($param['size']) || isset($param['noborder'])))
  2740. throw new HTML2PDF_exception(9, array('QRCODE', 'size, noborder'));
  2741. if ($this->_debugActif) $this->_DEBUG_add('QRCODE');
  2742. if (!isset($param['value'])) $param['value'] = '';
  2743. if (!isset($param['ec'])) $param['ec'] = 'H';
  2744. if (!isset($param['style']['color'])) $param['style']['color'] = '#000000';
  2745. if (!isset($param['style']['background-color'])) $param['style']['background-color'] = '#FFFFFF';
  2746. if (isset($param['style']['border'])) {
  2747. $borders = $param['style']['border']!='none';
  2748. unset($param['style']['border']);
  2749. } else {
  2750. $borders = true;
  2751. }
  2752. if ($param['value']==='') return true;
  2753. if (!in_array($param['ec'], array('L', 'M', 'Q', 'H'))) $param['ec'] = 'H';
  2754. $this->parsingCss->save();
  2755. $this->parsingCss->analyse('qrcode', $param);
  2756. $this->parsingCss->setPosition();
  2757. $this->parsingCss->fontSet();
  2758. $x = $this->pdf->getX();
  2759. $y = $this->pdf->getY();
  2760. $w = $this->parsingCss->value['width'];
  2761. $h = $this->parsingCss->value['height'];
  2762. $size = max($w, $h); if (!$size) $size = $this->parsingCss->ConvertToMM('50mm');
  2763. $style = array(
  2764. 'fgcolor' => $this->parsingCss->value['color'],
  2765. 'bgcolor' => $this->parsingCss->value['background']['color'],
  2766. );
  2767. if ($borders) {
  2768. $style['border'] = true;
  2769. $style['padding'] = 'auto';
  2770. } else {
  2771. $style['border'] = false;
  2772. $style['padding'] = 0;
  2773. }
  2774. if (!$this->_subPart && !$this->_isSubPart) {
  2775. $this->pdf->write2DBarcode($param['value'], 'QRCODE,'.$param['ec'], $x, $y, $size, $size, $style);
  2776. }
  2777. $this->_maxX = max($this->_maxX, $x+$size);
  2778. $this->_maxY = max($this->_maxY, $y+$size);
  2779. $this->_maxH = max($this->_maxH, $size);
  2780. $this->_maxE++;
  2781. $this->pdf->setX($x+$size);
  2782. $this->parsingCss->load();
  2783. $this->parsingCss->fontSet();
  2784. return true;
  2785. }
  2786. /**
  2787. * tag : QRCODE
  2788. * mode : CLOSE
  2789. *
  2790. * @param array $param
  2791. * @return boolean
  2792. */
  2793. protected function _tag_close_QRCODE($param)
  2794. {
  2795. // there is nothing to do here
  2796. return true;
  2797. }
  2798. /**
  2799. * tag : BOOKMARK
  2800. * mode : OPEN
  2801. *
  2802. * @param array $param
  2803. * @return boolean
  2804. */
  2805. protected function _tag_open_BOOKMARK($param)
  2806. {
  2807. $titre = isset($param['title']) ? trim($param['title']) : '';
  2808. $level = isset($param['level']) ? floor($param['level']) : 0;
  2809. if ($level<0) $level = 0;
  2810. if ($titre) $this->pdf->Bookmark($titre, $level, -1);
  2811. return true;
  2812. }
  2813. /**
  2814. * tag : BOOKMARK
  2815. * mode : CLOSE
  2816. *
  2817. * @param array $param
  2818. * @return boolean
  2819. */
  2820. protected function _tag_close_BOOKMARK($param)
  2821. {
  2822. // there is nothing to do here
  2823. return true;
  2824. }
  2825. /**
  2826. * this is not a real TAG, it is just to write texts
  2827. *
  2828. * @param array $param
  2829. * @return boolean
  2830. */
  2831. protected function _tag_open_WRITE($param)
  2832. {
  2833. $fill = ($this->parsingCss->value['background']['color']!==null && $this->parsingCss->value['background']['image']===null);
  2834. if (in_array($this->parsingCss->value['id_tag'], array('fieldset', 'legend', 'div', 'table', 'tr', 'td', 'th'))) {
  2835. $fill = false;
  2836. }
  2837. // get the text to write
  2838. $txt = $param['txt'];
  2839. if ($this->_isAfterFloat) {
  2840. $txt = ltrim($txt);
  2841. $this->_isAfterFloat = false;
  2842. }
  2843. $txt = str_replace('[[page_nb]]', $this->pdf->getMyAliasNbPages(), $txt);
  2844. $txt = str_replace('[[page_cu]]', $this->pdf->getMyNumPage($this->_page), $txt);
  2845. if ($this->parsingCss->value['text-transform']!='none') {
  2846. if ($this->parsingCss->value['text-transform']=='capitalize')
  2847. $txt = ucwords($txt);
  2848. else if ($this->parsingCss->value['text-transform']=='uppercase')
  2849. $txt = strtoupper($txt);
  2850. else if ($this->parsingCss->value['text-transform']=='lowercase')
  2851. $txt = strtolower($txt);
  2852. }
  2853. // size of the text
  2854. $h = 1.08*$this->parsingCss->value['font-size'];
  2855. $dh = $h*$this->parsingCss->value['mini-decal'];
  2856. $lh = $this->parsingCss->getLineHeight();
  2857. // identify the align
  2858. $align = 'L';
  2859. if ($this->parsingCss->value['text-align']=='li_right') {
  2860. $w = $this->parsingCss->value['width'];
  2861. $align = 'R';
  2862. }
  2863. // calculate the width of each words, and of all the sentence
  2864. $w = 0;
  2865. $words = explode(' ', $txt);
  2866. foreach ($words as $k => $word) {
  2867. $words[$k] = array($word, $this->pdf->GetStringWidth($word));
  2868. $w+= $words[$k][1];
  2869. }
  2870. $space = $this->pdf->GetStringWidth(' ');
  2871. $w+= $space*(count($words)-1);
  2872. // position in the text
  2873. $currPos = 0;
  2874. // the bigger width of the text, after automatic break line
  2875. $maxX = 0;
  2876. // position of the text
  2877. $x = $this->pdf->getX();
  2878. $y = $this->pdf->getY();
  2879. $dy = $this->_getElementY($lh);
  2880. // margins
  2881. list($left, $right) = $this->_getMargins($y);
  2882. // number of lines after automatic break line
  2883. $nb = 0;
  2884. // while we have words, and the text does not fit on the line => we cut the sentence
  2885. while ($x+$w>$right && $x<$right+$space && count($words)) {
  2886. // adding words 1 by 1 to fit on the line
  2887. $i=0;
  2888. $old = array('', 0);
  2889. $str = $words[0];
  2890. $add = false;
  2891. while (($x+$str[1])<$right) {
  2892. $i++;
  2893. $add = true;
  2894. array_shift($words);
  2895. $old = $str;
  2896. if (!count($words)) break;
  2897. $str[0].= ' '.$words[0][0];
  2898. $str[1]+= $space+$words[0][1];
  2899. }
  2900. $str = $old;
  2901. // if nothing fit on the line, and if the first word does not fit on the line => the word is too long, we put it
  2902. if ($i==0 && (($left+$words[0][1])>=$right)) {
  2903. $str = $words[0];
  2904. array_shift($words);
  2905. $i++;
  2906. $add = true;
  2907. }
  2908. $currPos+= ($currPos ? 1 : 0)+strlen($str[0]);
  2909. // write the extract sentence that fit on the page
  2910. $wc = ($align=='L' ? $str[1] : $this->parsingCss->value['width']);
  2911. if ($right - $left<$wc) $wc = $right - $left;
  2912. if (strlen($str[0])) {
  2913. $this->pdf->setXY($this->pdf->getX(), $y+$dh+$dy);
  2914. $this->pdf->Cell($wc, $h, $str[0], 0, 0, $align, $fill, $this->_isInLink);
  2915. $this->pdf->setXY($this->pdf->getX(), $y);
  2916. }
  2917. $this->_maxH = max($this->_maxH, $lh);
  2918. // max width
  2919. $maxX = max($maxX, $this->pdf->getX());
  2920. // new position and new width for the "while"
  2921. $w-= $str[1];
  2922. $y = $this->pdf->getY();
  2923. $x = $this->pdf->getX();
  2924. $dy = $this->_getElementY($lh);
  2925. // if we have again words to write
  2926. if (count($words)) {
  2927. // remove the space at the end
  2928. if ($add) $w-= $space;
  2929. // if we don't add any word, and if the first word is empty => useless space to skip
  2930. if (!$add && $words[0][0]==='') {
  2931. array_shift($words);
  2932. }
  2933. // if it is just to calculate for one line => adding the number of words
  2934. if ($this->_isForOneLine) {
  2935. $this->_maxE+= $i;
  2936. $this->_maxX = max($this->_maxX, $maxX);
  2937. return null;
  2938. }
  2939. // automatic line break
  2940. $this->_tag_open_BR(array('style' => ''), $currPos);
  2941. // new position
  2942. $y = $this->pdf->getY();
  2943. $x = $this->pdf->getX();
  2944. $dy = $this->_getElementY($lh);
  2945. // if the next line does not fit on the page => new page
  2946. if ($y + $h>=$this->pdf->getH() - $this->pdf->getbMargin()) {
  2947. if (!$this->_isInOverflow && !$this->_isInFooter) {
  2948. $this->_setNewPage(null, '', null, $currPos);
  2949. $y = $this->pdf->getY();
  2950. $x = $this->pdf->getX();
  2951. $dy = $this->_getElementY($lh);
  2952. }
  2953. }
  2954. // if more than 10000 line => error
  2955. $nb++;
  2956. if ($nb>10000) {
  2957. $txt = ''; foreach ($words as $k => $word) $txt.= ($k ? ' ' : '').$word[0];
  2958. throw new HTML2PDF_exception(2, array($txt, $right-$left, $w));
  2959. }
  2960. // new margins for the new line
  2961. list($left, $right) = $this->_getMargins($y);
  2962. }
  2963. }
  2964. // if we have words after automatic cut, it is because they fit on the line => we write the text
  2965. if (count($words)) {
  2966. $txt = ''; foreach ($words as $k => $word) $txt.= ($k ? ' ' : '').$word[0];
  2967. $w+= $this->pdf->getWordSpacing()*(count($words));
  2968. $this->pdf->setXY($this->pdf->getX(), $y+$dh+$dy);
  2969. $this->pdf->Cell(($align=='L' ? $w : $this->parsingCss->value['width']), $h, $txt, 0, 0, $align, $fill, $this->_isInLink);
  2970. $this->pdf->setXY($this->pdf->getX(), $y);
  2971. $this->_maxH = max($this->_maxH, $lh);
  2972. $this->_maxE+= count($words);
  2973. }
  2974. $maxX = max($maxX, $this->pdf->getX());
  2975. $maxY = $this->pdf->getY()+$h;
  2976. $this->_maxX = max($this->_maxX, $maxX);
  2977. $this->_maxY = max($this->_maxY, $maxY);
  2978. return true;
  2979. }
  2980. /**
  2981. * tag : BR
  2982. * mode : OPEN
  2983. *
  2984. * @param array $param
  2985. * @param integer $curr real position in the html parseur (if break line in the write of a text)
  2986. * @return boolean
  2987. */
  2988. protected function _tag_open_BR($param, $curr = null)
  2989. {
  2990. if ($this->_isForOneLine) return false;
  2991. $h = max($this->_maxH, $this->parsingCss->getLineHeight());
  2992. if ($this->_maxH==0) $this->_maxY = max($this->_maxY, $this->pdf->getY()+$h);
  2993. $this->_makeBreakLine($h, $curr);
  2994. $this->_maxH = 0;
  2995. $this->_maxE = 0;
  2996. return true;
  2997. }
  2998. /**
  2999. * tag : HR
  3000. * mode : OPEN
  3001. *
  3002. * @param array $param
  3003. * @return boolean
  3004. */
  3005. protected function _tag_open_HR($param)
  3006. {
  3007. if ($this->_isForOneLine) return false;
  3008. $oldAlign = $this->parsingCss->value['text-align'];
  3009. $this->parsingCss->value['text-align'] = 'left';
  3010. if ($this->_maxH) $this->_tag_open_BR($param);
  3011. $fontSize = $this->parsingCss->value['font-size'];
  3012. $this->parsingCss->value['font-size']=$fontSize*0.5; $this->_tag_open_BR($param);
  3013. $this->parsingCss->value['font-size']=0;
  3014. $param['style']['width'] = '100%';
  3015. $this->parsingCss->save();
  3016. $this->parsingCss->value['height']=$this->parsingCss->ConvertToMM('1mm');
  3017. $this->parsingCss->analyse('hr', $param);
  3018. $this->parsingCss->setPosition();
  3019. $this->parsingCss->fontSet();
  3020. $h = $this->parsingCss->value['height'];
  3021. if ($h) $h-= $this->parsingCss->value['border']['t']['width']+$this->parsingCss->value['border']['b']['width'];
  3022. if ($h<=0) $h = $this->parsingCss->value['border']['t']['width']+$this->parsingCss->value['border']['b']['width'];
  3023. $this->_drawRectangle($this->pdf->getX(), $this->pdf->getY(), $this->parsingCss->value['width'], $h, $this->parsingCss->value['border'], 0, 0, $this->parsingCss->value['background']);
  3024. $this->_maxH = $h;
  3025. $this->parsingCss->load();
  3026. $this->parsingCss->fontSet();
  3027. $this->_tag_open_BR($param);
  3028. $this->parsingCss->value['font-size']=$fontSize*0.5; $this->_tag_open_BR($param);
  3029. $this->parsingCss->value['font-size']=$fontSize;
  3030. $this->parsingCss->value['text-align'] = $oldAlign;
  3031. $this->_setNewPositionForNewLine();
  3032. return true;
  3033. }
  3034. /**
  3035. * tag : B
  3036. * mode : OPEN
  3037. *
  3038. * @param array $param
  3039. * @param string $other
  3040. * @return boolean
  3041. */
  3042. protected function _tag_open_B($param, $other = 'b')
  3043. {
  3044. $this->parsingCss->save();
  3045. $this->parsingCss->value['font-bold'] = true;
  3046. $this->parsingCss->analyse($other, $param);
  3047. $this->parsingCss->setPosition();
  3048. $this->parsingCss->fontSet();
  3049. return true;
  3050. }
  3051. /**
  3052. * tag : STRONG
  3053. * mode : OPEN
  3054. *
  3055. * @param array $param
  3056. * @return boolean
  3057. */
  3058. protected function _tag_open_STRONG($param)
  3059. {
  3060. return $this->_tag_open_B($param, 'strong');
  3061. }
  3062. /**
  3063. * tag : B
  3064. * mode : CLOSE
  3065. *
  3066. * @param array $param
  3067. * @return boolean
  3068. */
  3069. protected function _tag_close_B($param)
  3070. {
  3071. $this->parsingCss->load();
  3072. $this->parsingCss->fontSet();
  3073. return true;
  3074. }
  3075. /**
  3076. * tag : STRONG
  3077. * mode : CLOSE
  3078. *
  3079. * @param array $param
  3080. * @return boolean
  3081. */
  3082. protected function _tag_close_STRONG($param)
  3083. {
  3084. return $this->_tag_close_B($param);
  3085. }
  3086. /**
  3087. * tag : I
  3088. * mode : OPEN
  3089. *
  3090. * @param array $param
  3091. * @param string $other
  3092. * @return boolean
  3093. */
  3094. protected function _tag_open_I($param, $other = 'i')
  3095. {
  3096. $this->parsingCss->save();
  3097. $this->parsingCss->value['font-italic'] = true;
  3098. $this->parsingCss->analyse($other, $param);
  3099. $this->parsingCss->setPosition();
  3100. $this->parsingCss->fontSet();
  3101. return true;
  3102. }
  3103. /**
  3104. * tag : ADDRESS
  3105. * mode : OPEN
  3106. *
  3107. * @param array $param
  3108. * @return boolean
  3109. */
  3110. protected function _tag_open_ADDRESS($param)
  3111. {
  3112. return $this->_tag_open_I($param, 'address');
  3113. }
  3114. /**
  3115. * tag : CITE
  3116. * mode : OPEN
  3117. *
  3118. * @param array $param
  3119. * @return boolean
  3120. */
  3121. protected function _tag_open_CITE($param)
  3122. {
  3123. return $this->_tag_open_I($param, 'cite');
  3124. }
  3125. /**
  3126. * tag : EM
  3127. * mode : OPEN
  3128. *
  3129. * @param array $param
  3130. * @return boolean
  3131. */
  3132. protected function _tag_open_EM($param)
  3133. {
  3134. return $this->_tag_open_I($param, 'em');
  3135. }
  3136. /**
  3137. * tag : SAMP
  3138. * mode : OPEN
  3139. *
  3140. * @param array $param
  3141. * @return boolean
  3142. */
  3143. protected function _tag_open_SAMP($param)
  3144. {
  3145. return $this->_tag_open_I($param, 'samp');
  3146. }
  3147. /**
  3148. * tag : I
  3149. * mode : CLOSE
  3150. *
  3151. * @param array $param
  3152. * @return boolean
  3153. */
  3154. protected function _tag_close_I($param)
  3155. {
  3156. $this->parsingCss->load();
  3157. $this->parsingCss->fontSet();
  3158. return true;
  3159. }
  3160. /**
  3161. * tag : ADDRESS
  3162. * mode : CLOSE
  3163. *
  3164. * @param array $param
  3165. * @return boolean
  3166. */
  3167. protected function _tag_close_ADDRESS($param)
  3168. {
  3169. return $this->_tag_close_I($param);
  3170. }
  3171. /**
  3172. * tag : CITE
  3173. * mode : CLOSE
  3174. *
  3175. * @param array $param
  3176. * @return boolean
  3177. */
  3178. protected function _tag_close_CITE($param)
  3179. {
  3180. return $this->_tag_close_I($param);
  3181. }
  3182. /**
  3183. * tag : EM
  3184. * mode : CLOSE
  3185. *
  3186. * @param array $param
  3187. * @return boolean
  3188. */
  3189. protected function _tag_close_EM($param)
  3190. {
  3191. return $this->_tag_close_I($param);
  3192. }
  3193. /**
  3194. * tag : SAMP
  3195. * mode : CLOSE
  3196. *
  3197. * @param array $param
  3198. * @return boolean
  3199. */
  3200. protected function _tag_close_SAMP($param)
  3201. {
  3202. return $this->_tag_close_I($param);
  3203. }
  3204. /**
  3205. * tag : S
  3206. * mode : OPEN
  3207. *
  3208. * @param array $param
  3209. * @param string $other
  3210. * @return boolean
  3211. */
  3212. protected function _tag_open_S($param, $other = 's')
  3213. {
  3214. $this->parsingCss->save();
  3215. $this->parsingCss->value['font-linethrough'] = true;
  3216. $this->parsingCss->analyse($other, $param);
  3217. $this->parsingCss->setPosition();
  3218. $this->parsingCss->fontSet();
  3219. return true;
  3220. }
  3221. /**
  3222. * tag : DEL
  3223. * mode : OPEN
  3224. *
  3225. * @param array $param
  3226. * @return boolean
  3227. */
  3228. protected function _tag_open_DEL($param)
  3229. {
  3230. return $this->_tag_open_S($param, 'del');
  3231. }
  3232. /**
  3233. * tag : S
  3234. * mode : CLOSE
  3235. *
  3236. * @param array $param
  3237. * @return boolean
  3238. */
  3239. protected function _tag_close_S($param)
  3240. {
  3241. $this->parsingCss->load();
  3242. $this->parsingCss->fontSet();
  3243. return true;
  3244. }
  3245. /**
  3246. * tag : DEL
  3247. * mode : CLOSE
  3248. *
  3249. * @param array $param
  3250. * @return boolean
  3251. */
  3252. protected function _tag_close_DEL($param)
  3253. {
  3254. return $this->_tag_close_S($param);
  3255. }
  3256. /**
  3257. * tag : U
  3258. * mode : OPEN
  3259. *
  3260. * @param array $param
  3261. * @param string $other
  3262. * @return boolean
  3263. */
  3264. protected function _tag_open_U($param, $other='u')
  3265. {
  3266. $this->parsingCss->save();
  3267. $this->parsingCss->value['font-underline'] = true;
  3268. $this->parsingCss->analyse($other, $param);
  3269. $this->parsingCss->setPosition();
  3270. $this->parsingCss->fontSet();
  3271. return true;
  3272. }
  3273. /**
  3274. * tag : INS
  3275. * mode : OPEN
  3276. *
  3277. * @param array $param
  3278. * @return boolean
  3279. */
  3280. protected function _tag_open_INS($param)
  3281. {
  3282. return $this->_tag_open_U($param, 'ins');
  3283. }
  3284. /**
  3285. * tag : U
  3286. * mode : CLOSE
  3287. *
  3288. * @param array $param
  3289. * @return boolean
  3290. */
  3291. protected function _tag_close_U($param)
  3292. {
  3293. $this->parsingCss->load();
  3294. $this->parsingCss->fontSet();
  3295. return true;
  3296. }
  3297. /**
  3298. * tag : INS
  3299. * mode : CLOSE
  3300. *
  3301. * @param array $param
  3302. * @return boolean
  3303. */
  3304. protected function _tag_close_INS($param)
  3305. {
  3306. return $this->_tag_close_U($param);
  3307. }
  3308. /**
  3309. * tag : A
  3310. * mode : OPEN
  3311. *
  3312. * @param array $param
  3313. * @return boolean
  3314. */
  3315. protected function _tag_open_A($param)
  3316. {
  3317. $this->_isInLink = str_replace('&amp;', '&', isset($param['href']) ? $param['href'] : '');
  3318. if (isset($param['name'])) {
  3319. $name = $param['name'];
  3320. if (!isset($this->_lstAnchor[$name])) $this->_lstAnchor[$name] = array($this->pdf->AddLink(), false);
  3321. if (!$this->_lstAnchor[$name][1]) {
  3322. $this->_lstAnchor[$name][1] = true;
  3323. $this->pdf->SetLink($this->_lstAnchor[$name][0], -1, -1);
  3324. }
  3325. }
  3326. if (preg_match('/^#([^#]+)$/isU', $this->_isInLink, $match)) {
  3327. $name = $match[1];
  3328. if (!isset($this->_lstAnchor[$name])) $this->_lstAnchor[$name] = array($this->pdf->AddLink(), false);
  3329. $this->_isInLink = $this->_lstAnchor[$name][0];
  3330. }
  3331. $this->parsingCss->save();
  3332. $this->parsingCss->value['font-underline'] = true;
  3333. $this->parsingCss->value['color'] = array(20, 20, 250);
  3334. $this->parsingCss->analyse('a', $param);
  3335. $this->parsingCss->setPosition();
  3336. $this->parsingCss->fontSet();
  3337. return true;
  3338. }
  3339. /**
  3340. * tag : A
  3341. * mode : CLOSE
  3342. *
  3343. * @param array $param
  3344. * @return boolean
  3345. */
  3346. protected function _tag_close_A($param)
  3347. {
  3348. $this->_isInLink = '';
  3349. $this->parsingCss->load();
  3350. $this->parsingCss->fontSet();
  3351. return true;
  3352. }
  3353. /**
  3354. * tag : H1
  3355. * mode : OPEN
  3356. *
  3357. * @param array $param
  3358. * @param string $other
  3359. * @return boolean
  3360. */
  3361. protected function _tag_open_H1($param, $other = 'h1')
  3362. {
  3363. if ($this->_isForOneLine) return false;
  3364. if ($this->_maxH) $this->_tag_open_BR(array());
  3365. $this->parsingCss->save();
  3366. $this->parsingCss->value['font-bold'] = true;
  3367. $size = array('h1' => '28px', 'h2' => '24px', 'h3' => '20px', 'h4' => '16px', 'h5' => '12px', 'h6' => '9px');
  3368. $this->parsingCss->value['margin']['l'] = 0;
  3369. $this->parsingCss->value['margin']['r'] = 0;
  3370. $this->parsingCss->value['margin']['t'] = $this->parsingCss->ConvertToMM('16px');
  3371. $this->parsingCss->value['margin']['b'] = $this->parsingCss->ConvertToMM('16px');
  3372. $this->parsingCss->value['font-size'] = $this->parsingCss->ConvertToMM($size[$other]);
  3373. $this->parsingCss->analyse($other, $param);
  3374. $this->parsingCss->setPosition();
  3375. $this->parsingCss->fontSet();
  3376. $this->_setNewPositionForNewLine();
  3377. return true;
  3378. }
  3379. /**
  3380. * tag : H2
  3381. * mode : OPEN
  3382. *
  3383. * @param array $param
  3384. * @return boolean
  3385. */
  3386. protected function _tag_open_H2($param)
  3387. {
  3388. return $this->_tag_open_H1($param, 'h2');
  3389. }
  3390. /**
  3391. * tag : H3
  3392. * mode : OPEN
  3393. *
  3394. * @param array $param
  3395. * @return boolean
  3396. */
  3397. protected function _tag_open_H3($param)
  3398. {
  3399. return $this->_tag_open_H1($param, 'h3');
  3400. }
  3401. /**
  3402. * tag : H4
  3403. * mode : OPEN
  3404. *
  3405. * @param array $param
  3406. * @return boolean
  3407. */
  3408. protected function _tag_open_H4($param)
  3409. {
  3410. return $this->_tag_open_H1($param, 'h4');
  3411. }
  3412. /**
  3413. * tag : H5
  3414. * mode : OPEN
  3415. *
  3416. * @param array $param
  3417. * @return boolean
  3418. */
  3419. protected function _tag_open_H5($param)
  3420. {
  3421. return $this->_tag_open_H1($param, 'h5');
  3422. }
  3423. /**
  3424. * tag : H6
  3425. * mode : OPEN
  3426. *
  3427. * @param array $param
  3428. * @return boolean
  3429. */
  3430. protected function _tag_open_H6($param)
  3431. {
  3432. return $this->_tag_open_H1($param, 'h6');
  3433. }
  3434. /**
  3435. * tag : H1
  3436. * mode : CLOSE
  3437. *
  3438. * @param array $param
  3439. * @return boolean
  3440. */
  3441. protected function _tag_close_H1($param)
  3442. {
  3443. if ($this->_isForOneLine) return false;
  3444. $this->_maxH+= $this->parsingCss->value['margin']['b'];
  3445. $h = max($this->_maxH, $this->parsingCss->getLineHeight());
  3446. $this->parsingCss->load();
  3447. $this->parsingCss->fontSet();
  3448. $this->_makeBreakLine($h);
  3449. $this->_maxH = 0;
  3450. $this->_maxY = max($this->_maxY, $this->pdf->getY());
  3451. return true;
  3452. }
  3453. /**
  3454. * tag : H2
  3455. * mode : CLOSE
  3456. *
  3457. * @param array $param
  3458. * @return boolean
  3459. */
  3460. protected function _tag_close_H2($param)
  3461. {
  3462. return $this->_tag_close_H1($param);
  3463. }
  3464. /**
  3465. * tag : H3
  3466. * mode : CLOSE
  3467. *
  3468. * @param array $param
  3469. * @return boolean
  3470. */
  3471. protected function _tag_close_H3($param)
  3472. {
  3473. return $this->_tag_close_H1($param);
  3474. }
  3475. /**
  3476. * tag : H4
  3477. * mode : CLOSE
  3478. *
  3479. * @param array $param
  3480. * @return boolean
  3481. */
  3482. protected function _tag_close_H4($param)
  3483. {
  3484. return $this->_tag_close_H1($param);
  3485. }
  3486. /**
  3487. * tag : H5
  3488. * mode : CLOSE
  3489. *
  3490. * @param array $param
  3491. * @return boolean
  3492. */
  3493. protected function _tag_close_H5($param)
  3494. {
  3495. return $this->_tag_close_H1($param);
  3496. }
  3497. /**
  3498. * tag : H6
  3499. * mode : CLOSE
  3500. *
  3501. * @param array $param
  3502. * @return boolean
  3503. */
  3504. protected function _tag_close_H6($param)
  3505. {
  3506. return $this->_tag_close_H1($param);
  3507. }
  3508. /**
  3509. * tag : SPAN
  3510. * mode : OPEN
  3511. *
  3512. * @param array $param
  3513. * @param string $other
  3514. * @return boolean
  3515. */
  3516. protected function _tag_open_SPAN($param, $other = 'span')
  3517. {
  3518. $this->parsingCss->save();
  3519. $this->parsingCss->analyse($other, $param);
  3520. $this->parsingCss->setPosition();
  3521. $this->parsingCss->fontSet();
  3522. return true;
  3523. }
  3524. /**
  3525. * tag : FONT
  3526. * mode : OPEN
  3527. *
  3528. * @param array $param
  3529. * @return boolean
  3530. */
  3531. protected function _tag_open_FONT($param)
  3532. {
  3533. return $this->_tag_open_SPAN($param, 'font');
  3534. }
  3535. /**
  3536. * tag : LABEL
  3537. * mode : OPEN
  3538. *
  3539. * @param array $param
  3540. * @return boolean
  3541. */
  3542. protected function _tag_open_LABEL($param)
  3543. {
  3544. return $this->_tag_open_SPAN($param, 'label');
  3545. }
  3546. /**
  3547. * tag : SPAN
  3548. * mode : CLOSE
  3549. *
  3550. * @param array $param
  3551. * @return boolean
  3552. */
  3553. protected function _tag_close_SPAN($param)
  3554. {
  3555. $this->parsingCss->restorePosition();
  3556. $this->parsingCss->load();
  3557. $this->parsingCss->fontSet();
  3558. return true;
  3559. }
  3560. /**
  3561. * tag : FONT
  3562. * mode : CLOSE
  3563. *
  3564. * @param array $param
  3565. * @return boolean
  3566. */
  3567. protected function _tag_close_FONT($param)
  3568. {
  3569. return $this->_tag_close_SPAN($param);
  3570. }
  3571. /**
  3572. * tag : LABEL
  3573. * mode : CLOSE
  3574. *
  3575. * @param array $param
  3576. * @return boolean
  3577. */
  3578. protected function _tag_close_LABEL($param)
  3579. {
  3580. return $this->_tag_close_SPAN($param);
  3581. }
  3582. /**
  3583. * tag : P
  3584. * mode : OPEN
  3585. *
  3586. * @param array $param
  3587. * @return boolean
  3588. */
  3589. protected function _tag_open_P($param)
  3590. {
  3591. if ($this->_isForOneLine) return false;
  3592. if (!in_array($this->_previousCall, array('_tag_close_P', '_tag_close_UL'))) {
  3593. if ($this->_maxH) $this->_tag_open_BR(array());
  3594. }
  3595. $this->parsingCss->save();
  3596. $this->parsingCss->analyse('p', $param);
  3597. $this->parsingCss->setPosition();
  3598. $this->parsingCss->fontSet();
  3599. // cancel the effects of the setPosition
  3600. $this->pdf->setXY($this->pdf->getX()-$this->parsingCss->value['margin']['l'], $this->pdf->getY()-$this->parsingCss->value['margin']['t']);
  3601. list($mL, $mR) = $this->_getMargins($this->pdf->getY());
  3602. $mR = $this->pdf->getW()-$mR;
  3603. $mL+= $this->parsingCss->value['margin']['l']+$this->parsingCss->value['padding']['l'];
  3604. $mR+= $this->parsingCss->value['margin']['r']+$this->parsingCss->value['padding']['r'];
  3605. $this->_saveMargin($mL, 0, $mR);
  3606. if ($this->parsingCss->value['text-indent']>0) {
  3607. $y = $this->pdf->getY()+$this->parsingCss->value['margin']['t']+$this->parsingCss->value['padding']['t'];
  3608. $this->_pageMarges[floor($y*100)] = array($mL+$this->parsingCss->value['text-indent'], $this->pdf->getW()-$mR);
  3609. $y+= $this->parsingCss->getLineHeight()*0.1;
  3610. $this->_pageMarges[floor($y*100)] = array($mL, $this->pdf->getW()-$mR);
  3611. }
  3612. $this->_makeBreakLine($this->parsingCss->value['margin']['t']+$this->parsingCss->value['padding']['t']);
  3613. $this->_isInParagraph = array($mL, $mR);
  3614. return true;
  3615. }
  3616. /**
  3617. * tag : P
  3618. * mode : CLOSE
  3619. *
  3620. * @param array $param
  3621. * @return boolean
  3622. */
  3623. protected function _tag_close_P($param)
  3624. {
  3625. if ($this->_isForOneLine) return false;
  3626. if ($this->_maxH) $this->_tag_open_BR(array());
  3627. $this->_isInParagraph = false;
  3628. $this->_loadMargin();
  3629. $h = $this->parsingCss->value['margin']['b']+$this->parsingCss->value['padding']['b'];
  3630. $this->parsingCss->load();
  3631. $this->parsingCss->fontSet();
  3632. $this->_makeBreakLine($h);
  3633. return true;
  3634. }
  3635. /**
  3636. * tag : PRE
  3637. * mode : OPEN
  3638. *
  3639. * @param array $param
  3640. * @param string $other
  3641. * @return boolean
  3642. */
  3643. protected function _tag_open_PRE($param, $other = 'pre')
  3644. {
  3645. if ($other=='pre' && $this->_maxH) $this->_tag_open_BR(array());
  3646. $this->parsingCss->save();
  3647. $this->parsingCss->value['font-family'] = 'courier';
  3648. $this->parsingCss->analyse($other, $param);
  3649. $this->parsingCss->setPosition();
  3650. $this->parsingCss->fontSet();
  3651. if ($other=='pre') return $this->_tag_open_DIV($param, $other);
  3652. return true;
  3653. }
  3654. /**
  3655. * tag : CODE
  3656. * mode : OPEN
  3657. *
  3658. * @param array $param
  3659. * @param string $other
  3660. * @return boolean
  3661. */
  3662. protected function _tag_open_CODE($param)
  3663. {
  3664. return $this->_tag_open_PRE($param, 'code');
  3665. }
  3666. /**
  3667. * tag : PRE
  3668. * mode : CLOSE
  3669. *
  3670. * @param array $param
  3671. * @param string $other
  3672. * @return boolean
  3673. */
  3674. protected function _tag_close_PRE($param, $other = 'pre')
  3675. {
  3676. if ($other=='pre') {
  3677. if ($this->_isForOneLine) return false;
  3678. $this->_tag_close_DIV($param, $other);
  3679. $this->_tag_open_BR(array());
  3680. }
  3681. $this->parsingCss->load();
  3682. $this->parsingCss->fontSet();
  3683. return true;
  3684. }
  3685. /**
  3686. * tag : CODE
  3687. * mode : CLOSE
  3688. *
  3689. * @param array $param
  3690. * @return boolean
  3691. */
  3692. protected function _tag_close_CODE($param)
  3693. {
  3694. return $this->_tag_close_PRE($param, 'code');
  3695. }
  3696. /**
  3697. * tag : BIG
  3698. * mode : OPEN
  3699. *
  3700. * @param array $param
  3701. * @return boolean
  3702. */
  3703. protected function _tag_open_BIG($param)
  3704. {
  3705. $this->parsingCss->save();
  3706. $this->parsingCss->value['mini-decal']-= $this->parsingCss->value['mini-size']*0.12;
  3707. $this->parsingCss->value['mini-size'] *= 1.2;
  3708. $this->parsingCss->analyse('big', $param);
  3709. $this->parsingCss->setPosition();
  3710. $this->parsingCss->fontSet();
  3711. return true;
  3712. }
  3713. /**
  3714. * tag : BIG
  3715. * mode : CLOSE
  3716. *
  3717. * @param array $param
  3718. * @return boolean
  3719. */
  3720. protected function _tag_close_BIG($param)
  3721. {
  3722. $this->parsingCss->load();
  3723. $this->parsingCss->fontSet();
  3724. return true;
  3725. }
  3726. /**
  3727. * tag : SMALL
  3728. * mode : OPEN
  3729. *
  3730. * @param array $param
  3731. * @return boolean
  3732. */
  3733. protected function _tag_open_SMALL($param)
  3734. {
  3735. $this->parsingCss->save();
  3736. $this->parsingCss->value['mini-decal']+= $this->parsingCss->value['mini-size']*0.05;
  3737. $this->parsingCss->value['mini-size'] *= 0.82;
  3738. $this->parsingCss->analyse('small', $param);
  3739. $this->parsingCss->setPosition();
  3740. $this->parsingCss->fontSet();
  3741. return true;
  3742. }
  3743. /**
  3744. * tag : SMALL
  3745. * mode : CLOSE
  3746. *
  3747. * @param array $param
  3748. * @return boolean
  3749. */
  3750. protected function _tag_close_SMALL($param)
  3751. {
  3752. $this->parsingCss->load();
  3753. $this->parsingCss->fontSet();
  3754. return true;
  3755. }
  3756. /**
  3757. * tag : SUP
  3758. * mode : OPEN
  3759. *
  3760. * @param array $param
  3761. * @return boolean
  3762. */
  3763. protected function _tag_open_SUP($param)
  3764. {
  3765. $this->parsingCss->save();
  3766. $this->parsingCss->value['mini-decal']-= $this->parsingCss->value['mini-size']*0.15;
  3767. $this->parsingCss->value['mini-size'] *= 0.75;
  3768. $this->parsingCss->analyse('sup', $param);
  3769. $this->parsingCss->setPosition();
  3770. $this->parsingCss->fontSet();
  3771. return true;
  3772. }
  3773. /**
  3774. * tag : SUP
  3775. * mode : CLOSE
  3776. *
  3777. * @param array $param
  3778. * @return boolean
  3779. */
  3780. protected function _tag_close_SUP($param)
  3781. {
  3782. $this->parsingCss->load();
  3783. $this->parsingCss->fontSet();
  3784. return true;
  3785. }
  3786. /**
  3787. * tag : SUB
  3788. * mode : OPEN
  3789. *
  3790. * @param array $param
  3791. * @return boolean
  3792. */
  3793. protected function _tag_open_SUB($param)
  3794. {
  3795. $this->parsingCss->save();
  3796. $this->parsingCss->value['mini-decal']+= $this->parsingCss->value['mini-size']*0.15;
  3797. $this->parsingCss->value['mini-size'] *= 0.75;
  3798. $this->parsingCss->analyse('sub', $param);
  3799. $this->parsingCss->setPosition();
  3800. $this->parsingCss->fontSet();
  3801. return true;
  3802. }
  3803. /**
  3804. * tag : SUB
  3805. * mode : CLOSE
  3806. *
  3807. * @param array $param
  3808. * @return boolean
  3809. */
  3810. protected function _tag_close_SUB($param)
  3811. {
  3812. $this->parsingCss->load();
  3813. $this->parsingCss->fontSet();
  3814. return true;
  3815. }
  3816. /**
  3817. * tag : UL
  3818. * mode : OPEN
  3819. *
  3820. * @param array $param
  3821. * @param string $other
  3822. * @return boolean
  3823. */
  3824. protected function _tag_open_UL($param, $other = 'ul')
  3825. {
  3826. if ($this->_isForOneLine) return false;
  3827. if (!in_array($this->_previousCall, array('_tag_close_P', '_tag_close_UL'))) {
  3828. if ($this->_maxH) $this->_tag_open_BR(array());
  3829. if (!count($this->_defList)) $this->_tag_open_BR(array());
  3830. }
  3831. if (!isset($param['style']['width'])) $param['allwidth'] = true;
  3832. $param['cellspacing'] = 0;
  3833. // a list is like a table
  3834. $this->_tag_open_TABLE($param, $other);
  3835. // add a level of list
  3836. $this->_listeAddLevel($other, $this->parsingCss->value['list-style-type'], $this->parsingCss->value['list-style-image']);
  3837. return true;
  3838. }
  3839. /**
  3840. * tag : OL
  3841. * mode : OPEN
  3842. *
  3843. * @param array $param
  3844. * @return boolean
  3845. */
  3846. protected function _tag_open_OL($param)
  3847. {
  3848. return $this->_tag_open_UL($param, 'ol');
  3849. }
  3850. /**
  3851. * tag : UL
  3852. * mode : CLOSE
  3853. *
  3854. * @param array $param
  3855. * @return boolean
  3856. */
  3857. protected function _tag_close_UL($param)
  3858. {
  3859. if ($this->_isForOneLine) return false;
  3860. $this->_tag_close_TABLE($param);
  3861. $this->_listeDelLevel();
  3862. if (!$this->_subPart) {
  3863. if (!count($this->_defList)) $this->_tag_open_BR(array());
  3864. }
  3865. return true;
  3866. }
  3867. /**
  3868. * tag : OL
  3869. * mode : CLOSE
  3870. *
  3871. * @param array $param
  3872. * @return boolean
  3873. */
  3874. protected function _tag_close_OL($param)
  3875. {
  3876. return $this->_tag_close_UL($param);
  3877. }
  3878. /**
  3879. * tag : LI
  3880. * mode : OPEN
  3881. *
  3882. * @param array $param
  3883. * @return boolean
  3884. */
  3885. protected function _tag_open_LI($param)
  3886. {
  3887. if ($this->_isForOneLine) return false;
  3888. $this->_listeAddLi();
  3889. if (!isset($param['style']['width'])) $param['style']['width'] = '100%';
  3890. $paramPUCE = $param;
  3891. $inf = $this->_listeGetLi();
  3892. // $inf[0] = font family (if not specified, then bullet is rendered using an image)
  3893. // $inf[1] = 'small' flag (if the bullet should be rendered with a smaller font)
  3894. // $inf[2] = text (bullet char)
  3895. if ($inf[0]) { // text
  3896. $paramPUCE['style']['font-family'] = $inf[0];
  3897. $paramPUCE['style']['text-align'] = 'li_right';
  3898. $paramPUCE['style']['vertical-align'] = 'top';
  3899. $paramPUCE['style']['width'] = $this->_listeGetWidth();
  3900. $paramPUCE['style']['padding-right'] = $this->_listeGetPadding();
  3901. $paramPUCE['txt'] = $inf[2].' '; // added space for visual break between bullet and text
  3902. } else { // image
  3903. $paramPUCE['style']['text-align'] = 'li_right';
  3904. $paramPUCE['style']['vertical-align'] = 'top';
  3905. $paramPUCE['style']['width'] = $this->_listeGetWidth();
  3906. $paramPUCE['style']['padding-right'] = $this->_listeGetPadding();
  3907. $paramPUCE['src'] = $inf[2];
  3908. $paramPUCE['sub_li'] = true;
  3909. }
  3910. $this->_tag_open_TR($param, 'li');
  3911. $this->parsingCss->save();
  3912. // if small LI
  3913. if ($inf[1]) {
  3914. //$this->parsingCss->value['mini-decal'] += $this->parsingCss->value['mini-size'] * 0.035;
  3915. $this->parsingCss->value['mini-size'] *= 0.7;
  3916. }
  3917. // if we are in a sub html => prepare. Else : display
  3918. if ($this->_subPart) {
  3919. // TD for the puce
  3920. $tmpPos = $this->_tempPos;
  3921. $tmpLst1 = $this->parsingHtml->code[$tmpPos+1];
  3922. $tmpLst2 = $this->parsingHtml->code[$tmpPos+2];
  3923. $this->parsingHtml->code[$tmpPos+1] = array();
  3924. $this->parsingHtml->code[$tmpPos+1]['name'] = (isset($paramPUCE['src'])) ? 'img' : 'write';
  3925. $this->parsingHtml->code[$tmpPos+1]['param'] = $paramPUCE; unset($this->parsingHtml->code[$tmpPos+1]['param']['style']['width']);
  3926. $this->parsingHtml->code[$tmpPos+1]['close'] = 0;
  3927. $this->parsingHtml->code[$tmpPos+2] = array();
  3928. $this->parsingHtml->code[$tmpPos+2]['name'] = 'li';
  3929. $this->parsingHtml->code[$tmpPos+2]['param'] = $paramPUCE;
  3930. $this->parsingHtml->code[$tmpPos+2]['close'] = 1;
  3931. $this->_tag_open_TD($paramPUCE, 'li_sub');
  3932. $this->_tag_close_TD($param);
  3933. $this->_tempPos = $tmpPos;
  3934. $this->parsingHtml->code[$tmpPos+1] = $tmpLst1;
  3935. $this->parsingHtml->code[$tmpPos+2] = $tmpLst2;
  3936. } else {
  3937. // TD for the puce
  3938. $this->_tag_open_TD($paramPUCE, 'li_sub');
  3939. unset($paramPUCE['style']['width']);
  3940. if (isset($paramPUCE['src'])) $this->_tag_open_IMG($paramPUCE);
  3941. else $this->_tag_open_WRITE($paramPUCE);
  3942. $this->_tag_close_TD($paramPUCE);
  3943. }
  3944. $this->parsingCss->load();
  3945. // TD for the content
  3946. $this->_tag_open_TD($param, 'li');
  3947. return true;
  3948. }
  3949. /**
  3950. * tag : LI
  3951. * mode : CLOSE
  3952. *
  3953. * @param array $param
  3954. * @return boolean
  3955. */
  3956. protected function _tag_close_LI($param)
  3957. {
  3958. if ($this->_isForOneLine) return false;
  3959. $this->_tag_close_TD($param);
  3960. $this->_tag_close_TR($param);
  3961. return true;
  3962. }
  3963. /**
  3964. * tag : TBODY
  3965. * mode : OPEN
  3966. *
  3967. * @param array $param
  3968. * @return boolean
  3969. */
  3970. protected function _tag_open_TBODY($param)
  3971. {
  3972. if ($this->_isForOneLine) return false;
  3973. $this->parsingCss->save();
  3974. $this->parsingCss->analyse('tbody', $param);
  3975. $this->parsingCss->setPosition();
  3976. $this->parsingCss->fontSet();
  3977. return true;
  3978. }
  3979. /**
  3980. * tag : TBODY
  3981. * mode : CLOSE
  3982. *
  3983. * @param array $param
  3984. * @return boolean
  3985. */
  3986. protected function _tag_close_TBODY($param)
  3987. {
  3988. if ($this->_isForOneLine) return false;
  3989. $this->parsingCss->load();
  3990. $this->parsingCss->fontSet();
  3991. return true;
  3992. }
  3993. /**
  3994. * tag : THEAD
  3995. * mode : OPEN
  3996. *
  3997. * @param array $param
  3998. * @return boolean
  3999. */
  4000. protected function _tag_open_THEAD($param)
  4001. {
  4002. if ($this->_isForOneLine) return false;
  4003. $this->parsingCss->save();
  4004. $this->parsingCss->analyse('thead', $param);
  4005. $this->parsingCss->setPosition();
  4006. $this->parsingCss->fontSet();
  4007. // if we are in a sub part, save the number of the first TR in the thead
  4008. if ($this->_subPart) {
  4009. HTML2PDF::$_tables[$param['num']]['thead']['tr'][0] = HTML2PDF::$_tables[$param['num']]['tr_curr'];
  4010. HTML2PDF::$_tables[$param['num']]['thead']['code'] = array();
  4011. for ($pos=$this->_tempPos; $pos<count($this->parsingHtml->code); $pos++) {
  4012. $action = $this->parsingHtml->code[$pos];
  4013. if (strtolower($action['name'])=='thead') $action['name'] = 'thead_sub';
  4014. HTML2PDF::$_tables[$param['num']]['thead']['code'][] = $action;
  4015. if (strtolower($action['name'])=='thead_sub' && $action['close']) break;
  4016. }
  4017. } else {
  4018. $level = $this->parsingHtml->getLevel($this->_parsePos);
  4019. $this->_parsePos+= count($level);
  4020. HTML2PDF::$_tables[$param['num']]['tr_curr']+= count(HTML2PDF::$_tables[$param['num']]['thead']['tr']);
  4021. }
  4022. return true;
  4023. }
  4024. /**
  4025. * tag : THEAD
  4026. * mode : CLOSE
  4027. *
  4028. * @param array $param
  4029. * @return boolean
  4030. */
  4031. protected function _tag_close_THEAD($param)
  4032. {
  4033. if ($this->_isForOneLine) return false;
  4034. $this->parsingCss->load();
  4035. $this->parsingCss->fontSet();
  4036. // if we are in a sub HTM, construct the list of the TR in the thead
  4037. if ($this->_subPart) {
  4038. $min = HTML2PDF::$_tables[$param['num']]['thead']['tr'][0];
  4039. $max = HTML2PDF::$_tables[$param['num']]['tr_curr']-1;
  4040. HTML2PDF::$_tables[$param['num']]['thead']['tr'] = range($min, $max);
  4041. }
  4042. return true;
  4043. }
  4044. /**
  4045. * tag : TFOOT
  4046. * mode : OPEN
  4047. *
  4048. * @param array $param
  4049. * @return boolean
  4050. */
  4051. protected function _tag_open_TFOOT($param)
  4052. {
  4053. if ($this->_isForOneLine) return false;
  4054. $this->parsingCss->save();
  4055. $this->parsingCss->analyse('tfoot', $param);
  4056. $this->parsingCss->setPosition();
  4057. $this->parsingCss->fontSet();
  4058. // if we are in a sub part, save the number of the first TR in the tfoot
  4059. if ($this->_subPart) {
  4060. HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0] = HTML2PDF::$_tables[$param['num']]['tr_curr'];
  4061. HTML2PDF::$_tables[$param['num']]['tfoot']['code'] = array();
  4062. for ($pos=$this->_tempPos; $pos<count($this->parsingHtml->code); $pos++) {
  4063. $action = $this->parsingHtml->code[$pos];
  4064. if (strtolower($action['name'])=='tfoot') $action['name'] = 'tfoot_sub';
  4065. HTML2PDF::$_tables[$param['num']]['tfoot']['code'][] = $action;
  4066. if (strtolower($action['name'])=='tfoot_sub' && $action['close']) break;
  4067. }
  4068. } else {
  4069. $level = $this->parsingHtml->getLevel($this->_parsePos);
  4070. $this->_parsePos+= count($level);
  4071. HTML2PDF::$_tables[$param['num']]['tr_curr']+= count(HTML2PDF::$_tables[$param['num']]['tfoot']['tr']);
  4072. }
  4073. return true;
  4074. }
  4075. /**
  4076. * tag : TFOOT
  4077. * mode : CLOSE
  4078. *
  4079. * @param array $param
  4080. * @return boolean
  4081. */
  4082. protected function _tag_close_TFOOT($param)
  4083. {
  4084. if ($this->_isForOneLine) return false;
  4085. $this->parsingCss->load();
  4086. $this->parsingCss->fontSet();
  4087. // if we are in a sub HTM, construct the list of the TR in the tfoot
  4088. if ($this->_subPart) {
  4089. $min = HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0];
  4090. $max = HTML2PDF::$_tables[$param['num']]['tr_curr']-1;
  4091. HTML2PDF::$_tables[$param['num']]['tfoot']['tr'] = range($min, $max);
  4092. }
  4093. return true;
  4094. }
  4095. /**
  4096. * It is not a real TAG, does not use it !
  4097. *
  4098. * @param array $param
  4099. * @return boolean
  4100. */
  4101. protected function _tag_open_THEAD_SUB($param)
  4102. {
  4103. if ($this->_isForOneLine) return false;
  4104. $this->parsingCss->save();
  4105. $this->parsingCss->analyse('thead', $param);
  4106. $this->parsingCss->setPosition();
  4107. $this->parsingCss->fontSet();
  4108. return true;
  4109. }
  4110. /**
  4111. * It is not a real TAG, does not use it !
  4112. *
  4113. * @param array $param
  4114. * @return boolean
  4115. */
  4116. protected function _tag_close_THEAD_SUB($param)
  4117. {
  4118. if ($this->_isForOneLine) return false;
  4119. $this->parsingCss->load();
  4120. $this->parsingCss->fontSet();
  4121. return true;
  4122. }
  4123. /**
  4124. * It is not a real TAG, does not use it !
  4125. *
  4126. * @param array $param
  4127. * @return boolean
  4128. */
  4129. protected function _tag_open_TFOOT_SUB($param)
  4130. {
  4131. if ($this->_isForOneLine) return false;
  4132. $this->parsingCss->save();
  4133. $this->parsingCss->analyse('tfoot', $param);
  4134. $this->parsingCss->setPosition();
  4135. $this->parsingCss->fontSet();
  4136. return true;
  4137. }
  4138. /**
  4139. * It is not a real TAG, does not use it !
  4140. *
  4141. * @param array $param
  4142. * @return boolean
  4143. */
  4144. protected function _tag_close_TFOOT_SUB($param)
  4145. {
  4146. if ($this->_isForOneLine) return false;
  4147. $this->parsingCss->load();
  4148. $this->parsingCss->fontSet();
  4149. return true;
  4150. }
  4151. /**
  4152. * tag : FORM
  4153. * mode : OPEN
  4154. *
  4155. * @param array $param
  4156. * @return boolean
  4157. */
  4158. protected function _tag_open_FORM($param)
  4159. {
  4160. $this->parsingCss->save();
  4161. $this->parsingCss->analyse('form', $param);
  4162. $this->parsingCss->setPosition();
  4163. $this->parsingCss->fontSet();
  4164. $this->pdf->setFormDefaultProp(
  4165. array(
  4166. 'lineWidth'=>1,
  4167. 'borderStyle'=>'solid',
  4168. 'fillColor'=>array(220, 220, 255),
  4169. 'strokeColor'=>array(128, 128, 200)
  4170. )
  4171. );
  4172. $this->_isInForm = isset($param['action']) ? $param['action'] : '';
  4173. return true;
  4174. }
  4175. /**
  4176. * tag : FORM
  4177. * mode : CLOSE
  4178. *
  4179. * @param array $param
  4180. * @return boolean
  4181. */
  4182. protected function _tag_close_FORM($param)
  4183. {
  4184. $this->_isInForm = false;
  4185. $this->parsingCss->load();
  4186. $this->parsingCss->fontSet();
  4187. return true;
  4188. }
  4189. /**
  4190. * tag : TABLE
  4191. * mode : OPEN
  4192. *
  4193. * @param array $param
  4194. * @return boolean
  4195. */
  4196. protected function _tag_open_TABLE($param, $other = 'table')
  4197. {
  4198. if ($this->_maxH) {
  4199. if ($this->_isForOneLine) return false;
  4200. $this->_tag_open_BR(array());
  4201. }
  4202. if ($this->_isForOneLine) {
  4203. $this->_maxX = $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  4204. return false;
  4205. }
  4206. $this->_maxH = 0;
  4207. $alignObject = isset($param['align']) ? strtolower($param['align']) : 'left';
  4208. if (isset($param['align'])) unset($param['align']);
  4209. if (!in_array($alignObject, array('left', 'center', 'right'))) $alignObject = 'left';
  4210. $this->parsingCss->save();
  4211. $this->parsingCss->analyse($other, $param);
  4212. $this->parsingCss->setPosition();
  4213. $this->parsingCss->fontSet();
  4214. if ($this->parsingCss->value['margin-auto']) $alignObject = 'center';
  4215. // collapse table ?
  4216. $collapse = false;
  4217. if ($other=='table') {
  4218. $collapse = isset($this->parsingCss->value['border']['collapse']) ? $this->parsingCss->value['border']['collapse'] : false;
  4219. }
  4220. // if collapse => no borders for the table, only for TD
  4221. if ($collapse) {
  4222. $param['style']['border'] = 'none';
  4223. $param['cellspacing'] = 0;
  4224. $none = $this->parsingCss->readBorder('none');
  4225. $this->parsingCss->value['border']['t'] = $none;
  4226. $this->parsingCss->value['border']['r'] = $none;
  4227. $this->parsingCss->value['border']['b'] = $none;
  4228. $this->parsingCss->value['border']['l'] = $none;
  4229. }
  4230. // if we are in a SUB html => prepare the properties of the table
  4231. if ($this->_subPart) {
  4232. if ($this->_debugActif) $this->_DEBUG_add('Table n'.$param['num'], true);
  4233. HTML2PDF::$_tables[$param['num']] = array();
  4234. HTML2PDF::$_tables[$param['num']]['border'] = isset($param['border']) ? $this->parsingCss->readBorder($param['border']) : null;
  4235. HTML2PDF::$_tables[$param['num']]['cellpadding'] = $this->parsingCss->ConvertToMM(isset($param['cellpadding']) ? $param['cellpadding'] : '1px');
  4236. HTML2PDF::$_tables[$param['num']]['cellspacing'] = $this->parsingCss->ConvertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px');
  4237. HTML2PDF::$_tables[$param['num']]['cases'] = array(); // properties of each TR/TD
  4238. HTML2PDF::$_tables[$param['num']]['corr'] = array(); // link between TR/TD and colspan/rowspan
  4239. HTML2PDF::$_tables[$param['num']]['corr_x'] = 0; // position in 'cases'
  4240. HTML2PDF::$_tables[$param['num']]['corr_y'] = 0; // position in 'cases'
  4241. HTML2PDF::$_tables[$param['num']]['td_curr'] = 0; // current column
  4242. HTML2PDF::$_tables[$param['num']]['tr_curr'] = 0; // current row
  4243. HTML2PDF::$_tables[$param['num']]['curr_x'] = $this->pdf->getX();
  4244. HTML2PDF::$_tables[$param['num']]['curr_y'] = $this->pdf->getY();
  4245. HTML2PDF::$_tables[$param['num']]['width'] = 0; // global width
  4246. HTML2PDF::$_tables[$param['num']]['height'] = 0; // global height
  4247. HTML2PDF::$_tables[$param['num']]['align'] = $alignObject;
  4248. HTML2PDF::$_tables[$param['num']]['marge'] = array();
  4249. HTML2PDF::$_tables[$param['num']]['marge']['t'] = $this->parsingCss->value['padding']['t']+$this->parsingCss->value['border']['t']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
  4250. HTML2PDF::$_tables[$param['num']]['marge']['r'] = $this->parsingCss->value['padding']['r']+$this->parsingCss->value['border']['r']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
  4251. HTML2PDF::$_tables[$param['num']]['marge']['b'] = $this->parsingCss->value['padding']['b']+$this->parsingCss->value['border']['b']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
  4252. HTML2PDF::$_tables[$param['num']]['marge']['l'] = $this->parsingCss->value['padding']['l']+$this->parsingCss->value['border']['l']['width']+HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5;
  4253. HTML2PDF::$_tables[$param['num']]['page'] = 0; // number of pages
  4254. HTML2PDF::$_tables[$param['num']]['new_page'] = true; // flag : new page for the current TR
  4255. HTML2PDF::$_tables[$param['num']]['style_value'] = null; // CSS style of the table
  4256. HTML2PDF::$_tables[$param['num']]['thead'] = array(); // properties on the thead
  4257. HTML2PDF::$_tables[$param['num']]['tfoot'] = array(); // properties on the tfoot
  4258. HTML2PDF::$_tables[$param['num']]['thead']['tr'] = array(); // list of the TRs in the thead
  4259. HTML2PDF::$_tables[$param['num']]['tfoot']['tr'] = array(); // list of the TRs in the tfoot
  4260. HTML2PDF::$_tables[$param['num']]['thead']['height'] = 0; // thead height
  4261. HTML2PDF::$_tables[$param['num']]['tfoot']['height'] = 0; // tfoot height
  4262. HTML2PDF::$_tables[$param['num']]['thead']['code'] = array(); // HTML content of the thead
  4263. HTML2PDF::$_tables[$param['num']]['tfoot']['code'] = array(); // HTML content of the tfoot
  4264. HTML2PDF::$_tables[$param['num']]['cols'] = array(); // properties of the COLs
  4265. $this->_saveMargin($this->pdf->getlMargin(), $this->pdf->gettMargin(), $this->pdf->getrMargin());
  4266. $this->parsingCss->value['width']-= HTML2PDF::$_tables[$param['num']]['marge']['l'] + HTML2PDF::$_tables[$param['num']]['marge']['r'];
  4267. } else {
  4268. // we start from the first page and the first page of the table
  4269. HTML2PDF::$_tables[$param['num']]['page'] = 0;
  4270. HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
  4271. HTML2PDF::$_tables[$param['num']]['tr_curr'] = 0;
  4272. HTML2PDF::$_tables[$param['num']]['td_x'] = HTML2PDF::$_tables[$param['num']]['marge']['l']+HTML2PDF::$_tables[$param['num']]['curr_x'];
  4273. HTML2PDF::$_tables[$param['num']]['td_y'] = HTML2PDF::$_tables[$param['num']]['marge']['t']+HTML2PDF::$_tables[$param['num']]['curr_y'];
  4274. // draw the borders/background of the first page/part of the table
  4275. $this->_drawRectangle(
  4276. HTML2PDF::$_tables[$param['num']]['curr_x'],
  4277. HTML2PDF::$_tables[$param['num']]['curr_y'],
  4278. HTML2PDF::$_tables[$param['num']]['width'],
  4279. isset(HTML2PDF::$_tables[$param['num']]['height'][0]) ? HTML2PDF::$_tables[$param['num']]['height'][0] : null,
  4280. $this->parsingCss->value['border'],
  4281. $this->parsingCss->value['padding'],
  4282. 0,
  4283. $this->parsingCss->value['background']
  4284. );
  4285. HTML2PDF::$_tables[$param['num']]['style_value'] = $this->parsingCss->value;
  4286. }
  4287. return true;
  4288. }
  4289. /**
  4290. * tag : TABLE
  4291. * mode : CLOSE
  4292. *
  4293. * @param array $param
  4294. * @return boolean
  4295. */
  4296. protected function _tag_close_TABLE($param)
  4297. {
  4298. if ($this->_isForOneLine) return false;
  4299. $this->_maxH = 0;
  4300. // if we are in a sub HTML
  4301. if ($this->_subPart) {
  4302. // calculate the size of each case
  4303. $this->_calculateTableCellSize(HTML2PDF::$_tables[$param['num']]['cases'], HTML2PDF::$_tables[$param['num']]['corr']);
  4304. // calculate the height of the thead and the tfoot
  4305. $lst = array('thead', 'tfoot');
  4306. foreach ($lst as $mode) {
  4307. HTML2PDF::$_tables[$param['num']][$mode]['height'] = 0;
  4308. foreach (HTML2PDF::$_tables[$param['num']][$mode]['tr'] as $tr) {
  4309. // hauteur de la ligne tr
  4310. $h = 0;
  4311. for ($i=0; $i<count(HTML2PDF::$_tables[$param['num']]['cases'][$tr]); $i++)
  4312. if (HTML2PDF::$_tables[$param['num']]['cases'][$tr][$i]['rowspan']==1)
  4313. $h = max($h, HTML2PDF::$_tables[$param['num']]['cases'][$tr][$i]['h']);
  4314. HTML2PDF::$_tables[$param['num']][$mode]['height']+= $h;
  4315. }
  4316. }
  4317. // calculate the width of the table
  4318. HTML2PDF::$_tables[$param['num']]['width'] = HTML2PDF::$_tables[$param['num']]['marge']['l'] + HTML2PDF::$_tables[$param['num']]['marge']['r'];
  4319. if (isset(HTML2PDF::$_tables[$param['num']]['cases'][0])) {
  4320. foreach (HTML2PDF::$_tables[$param['num']]['cases'][0] as $case) {
  4321. HTML2PDF::$_tables[$param['num']]['width']+= $case['w'];
  4322. }
  4323. }
  4324. // X position of the table
  4325. $old = $this->parsingCss->getOldValues();
  4326. $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  4327. $x = HTML2PDF::$_tables[$param['num']]['curr_x'];
  4328. $w = HTML2PDF::$_tables[$param['num']]['width'];
  4329. if ($parentWidth>$w) {
  4330. if (HTML2PDF::$_tables[$param['num']]['align']=='center')
  4331. $x = $x + ($parentWidth-$w)*0.5;
  4332. else if (HTML2PDF::$_tables[$param['num']]['align']=='right')
  4333. $x = $x + $parentWidth-$w;
  4334. HTML2PDF::$_tables[$param['num']]['curr_x'] = $x;
  4335. }
  4336. // calculate the height of the table
  4337. HTML2PDF::$_tables[$param['num']]['height'] = array();
  4338. // minimum of the height because of margins, and of the thead and tfoot height
  4339. $h0 = HTML2PDF::$_tables[$param['num']]['marge']['t'] + HTML2PDF::$_tables[$param['num']]['marge']['b'];
  4340. $h0+= HTML2PDF::$_tables[$param['num']]['thead']['height'] + HTML2PDF::$_tables[$param['num']]['tfoot']['height'];
  4341. // max height of the page
  4342. $max = $this->pdf->getH() - $this->pdf->getbMargin();
  4343. // current position on the page
  4344. $y = HTML2PDF::$_tables[$param['num']]['curr_y'];
  4345. $height = $h0;
  4346. // we get the height of each line
  4347. for ($k=0; $k<count(HTML2PDF::$_tables[$param['num']]['cases']); $k++) {
  4348. // if it is a TR of the thead or of the tfoot => skip
  4349. if (in_array($k, HTML2PDF::$_tables[$param['num']]['thead']['tr'])) continue;
  4350. if (in_array($k, HTML2PDF::$_tables[$param['num']]['tfoot']['tr'])) continue;
  4351. // height of the line
  4352. $th = 0;
  4353. $h = 0;
  4354. for ($i=0; $i<count(HTML2PDF::$_tables[$param['num']]['cases'][$k]); $i++) {
  4355. $h = max($h, HTML2PDF::$_tables[$param['num']]['cases'][$k][$i]['h']);
  4356. if (HTML2PDF::$_tables[$param['num']]['cases'][$k][$i]['rowspan']==1)
  4357. $th = max($th, HTML2PDF::$_tables[$param['num']]['cases'][$k][$i]['h']);
  4358. }
  4359. // if the row does not fit on the page => new page
  4360. if ($y+$h+$height>$max) {
  4361. if ($height==$h0) $height = null;
  4362. HTML2PDF::$_tables[$param['num']]['height'][] = $height;
  4363. $height = $h0;
  4364. $y = $this->_margeTop;
  4365. }
  4366. $height+= $th;
  4367. }
  4368. // if ther is a height at the end, add it
  4369. if ($height!=$h0 || $k==0) HTML2PDF::$_tables[$param['num']]['height'][] = $height;
  4370. } else {
  4371. // if we have tfoor, draw it
  4372. if (count(HTML2PDF::$_tables[$param['num']]['tfoot']['code'])) {
  4373. $tmpTR = HTML2PDF::$_tables[$param['num']]['tr_curr'];
  4374. $tmpTD = HTML2PDF::$_tables[$param['num']]['td_curr'];
  4375. $oldParsePos = $this->_parsePos;
  4376. $oldParseCode = $this->parsingHtml->code;
  4377. HTML2PDF::$_tables[$param['num']]['tr_curr'] = HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0];
  4378. HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
  4379. $this->_parsePos = 0;
  4380. $this->parsingHtml->code = HTML2PDF::$_tables[$param['num']]['tfoot']['code'];
  4381. $this->_isInTfoot = true;
  4382. $this->_makeHTMLcode();
  4383. $this->_isInTfoot = false;
  4384. $this->_parsePos = $oldParsePos;
  4385. $this->parsingHtml->code = $oldParseCode;
  4386. HTML2PDF::$_tables[$param['num']]['tr_curr'] = $tmpTR;
  4387. HTML2PDF::$_tables[$param['num']]['td_curr'] = $tmpTD;
  4388. }
  4389. // get the positions of the end of the table
  4390. $x = HTML2PDF::$_tables[$param['num']]['curr_x'] + HTML2PDF::$_tables[$param['num']]['width'];
  4391. if (count(HTML2PDF::$_tables[$param['num']]['height'])>1)
  4392. $y = $this->_margeTop+HTML2PDF::$_tables[$param['num']]['height'][count(HTML2PDF::$_tables[$param['num']]['height'])-1];
  4393. else if (count(HTML2PDF::$_tables[$param['num']]['height'])==1)
  4394. $y = HTML2PDF::$_tables[$param['num']]['curr_y']+HTML2PDF::$_tables[$param['num']]['height'][count(HTML2PDF::$_tables[$param['num']]['height'])-1];
  4395. else
  4396. $y = HTML2PDF::$_tables[$param['num']]['curr_y'];
  4397. $this->_maxX = max($this->_maxX, $x);
  4398. $this->_maxY = max($this->_maxY, $y);
  4399. $this->pdf->setXY($this->pdf->getlMargin(), $y);
  4400. $this->_loadMargin();
  4401. if ($this->_debugActif) $this->_DEBUG_add('Table '.$param['num'], false);
  4402. }
  4403. $this->parsingCss->load();
  4404. $this->parsingCss->fontSet();
  4405. return true;
  4406. }
  4407. /**
  4408. * tag : COL
  4409. * mode : OPEN
  4410. *
  4411. * @param array $param
  4412. * @return boolean
  4413. */
  4414. protected function _tag_open_COL($param)
  4415. {
  4416. $span = isset($param['span']) ? $param['span'] : 1;
  4417. for ($k=0; $k<$span; $k++)
  4418. HTML2PDF::$_tables[$param['num']]['cols'][] = $param;
  4419. }
  4420. /**
  4421. * tag : COL
  4422. * mode : CLOSE
  4423. *
  4424. * @param array $param
  4425. * @return boolean
  4426. */
  4427. protected function _tag_close_COL($param)
  4428. {
  4429. // there is nothing to do here
  4430. return true;
  4431. }
  4432. /**
  4433. * tag : TR
  4434. * mode : OPEN
  4435. *
  4436. * @param array $param
  4437. * @return boolean
  4438. */
  4439. protected function _tag_open_TR($param, $other = 'tr')
  4440. {
  4441. if ($this->_isForOneLine) return false;
  4442. $this->_maxH = 0;
  4443. $this->parsingCss->save();
  4444. $this->parsingCss->analyse($other, $param);
  4445. $this->parsingCss->setPosition();
  4446. $this->parsingCss->fontSet();
  4447. // position in the table
  4448. HTML2PDF::$_tables[$param['num']]['tr_curr']++;
  4449. HTML2PDF::$_tables[$param['num']]['td_curr']= 0;
  4450. // if we are not in a sub html
  4451. if (!$this->_subPart) {
  4452. // Y after the row
  4453. $ty=null;
  4454. for ($ii=0; $ii<count(HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1]); $ii++) {
  4455. $ty = max($ty, HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][$ii]['h']);
  4456. }
  4457. // height of the tfoot
  4458. $hfoot = HTML2PDF::$_tables[$param['num']]['tfoot']['height'];
  4459. // if the line does not fit on the page => new page
  4460. if (!$this->_isInTfoot && HTML2PDF::$_tables[$param['num']]['td_y'] + HTML2PDF::$_tables[$param['num']]['marge']['b'] + $ty +$hfoot> $this->pdf->getH() - $this->pdf->getbMargin()) {
  4461. // fi ther is a tfoot => draw it
  4462. if (count(HTML2PDF::$_tables[$param['num']]['tfoot']['code'])) {
  4463. $tmpTR = HTML2PDF::$_tables[$param['num']]['tr_curr'];
  4464. $tmpTD = HTML2PDF::$_tables[$param['num']]['td_curr'];
  4465. $oldParsePos = $this->_parsePos;
  4466. $oldParseCode = $this->parsingHtml->code;
  4467. HTML2PDF::$_tables[$param['num']]['tr_curr'] = HTML2PDF::$_tables[$param['num']]['tfoot']['tr'][0];
  4468. HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
  4469. $this->_parsePos = 0;
  4470. $this->parsingHtml->code = HTML2PDF::$_tables[$param['num']]['tfoot']['code'];
  4471. $this->_isInTfoot = true;
  4472. $this->_makeHTMLcode();
  4473. $this->_isInTfoot = false;
  4474. $this->_parsePos = $oldParsePos;
  4475. $this->parsingHtml->code = $oldParseCode;
  4476. HTML2PDF::$_tables[$param['num']]['tr_curr'] = $tmpTR;
  4477. HTML2PDF::$_tables[$param['num']]['td_curr'] = $tmpTD;
  4478. }
  4479. // new page
  4480. HTML2PDF::$_tables[$param['num']]['new_page'] = true;
  4481. $this->_setNewPage();
  4482. // new position
  4483. HTML2PDF::$_tables[$param['num']]['page']++;
  4484. HTML2PDF::$_tables[$param['num']]['curr_y'] = $this->pdf->getY();
  4485. HTML2PDF::$_tables[$param['num']]['td_y'] = HTML2PDF::$_tables[$param['num']]['curr_y']+HTML2PDF::$_tables[$param['num']]['marge']['t'];
  4486. // if we have the height of the tbale on the page => draw borders and background
  4487. if (isset(HTML2PDF::$_tables[$param['num']]['height'][HTML2PDF::$_tables[$param['num']]['page']])) {
  4488. $old = $this->parsingCss->value;
  4489. $this->parsingCss->value = HTML2PDF::$_tables[$param['num']]['style_value'];
  4490. $this->_drawRectangle(
  4491. HTML2PDF::$_tables[$param['num']]['curr_x'],
  4492. HTML2PDF::$_tables[$param['num']]['curr_y'],
  4493. HTML2PDF::$_tables[$param['num']]['width'],
  4494. HTML2PDF::$_tables[$param['num']]['height'][HTML2PDF::$_tables[$param['num']]['page']],
  4495. $this->parsingCss->value['border'],
  4496. $this->parsingCss->value['padding'],
  4497. HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5,
  4498. $this->parsingCss->value['background']
  4499. );
  4500. $this->parsingCss->value = $old;
  4501. }
  4502. }
  4503. // if we are in a new page, and if we have a thead => draw it
  4504. if (HTML2PDF::$_tables[$param['num']]['new_page'] && count(HTML2PDF::$_tables[$param['num']]['thead']['code'])) {
  4505. HTML2PDF::$_tables[$param['num']]['new_page'] = false;
  4506. $tmpTR = HTML2PDF::$_tables[$param['num']]['tr_curr'];
  4507. $tmpTD = HTML2PDF::$_tables[$param['num']]['td_curr'];
  4508. $oldParsePos = $this->_parsePos;
  4509. $oldParseCode = $this->parsingHtml->code;
  4510. HTML2PDF::$_tables[$param['num']]['tr_curr'] = HTML2PDF::$_tables[$param['num']]['thead']['tr'][0];
  4511. HTML2PDF::$_tables[$param['num']]['td_curr'] = 0;
  4512. $this->_parsePos = 0;
  4513. $this->parsingHtml->code = HTML2PDF::$_tables[$param['num']]['thead']['code'];
  4514. $this->_isInThead = true;
  4515. $this->_makeHTMLcode();
  4516. $this->_isInThead = false;
  4517. $this->_parsePos = $oldParsePos;
  4518. $this->parsingHtml->code = $oldParseCode;
  4519. HTML2PDF::$_tables[$param['num']]['tr_curr'] = $tmpTR;
  4520. HTML2PDF::$_tables[$param['num']]['td_curr'] = $tmpTD;
  4521. HTML2PDF::$_tables[$param['num']]['new_page'] = true;
  4522. }
  4523. // else (in a sub HTML)
  4524. } else {
  4525. // prepare it
  4526. HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1] = array();
  4527. if (!isset(HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']]))
  4528. HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']] = array();
  4529. HTML2PDF::$_tables[$param['num']]['corr_x']=0;
  4530. while(isset(HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']][HTML2PDF::$_tables[$param['num']]['corr_x']]))
  4531. HTML2PDF::$_tables[$param['num']]['corr_x']++;
  4532. }
  4533. return true;
  4534. }
  4535. /**
  4536. * tag : TR
  4537. * mode : CLOSE
  4538. *
  4539. * @param array $param
  4540. * @return boolean
  4541. */
  4542. protected function _tag_close_TR($param)
  4543. {
  4544. if ($this->_isForOneLine) return false;
  4545. $this->_maxH = 0;
  4546. $this->parsingCss->load();
  4547. $this->parsingCss->fontSet();
  4548. // if we are not in a sub HTML
  4549. if (!$this->_subPart) {
  4550. // Y of the current line
  4551. $ty=null;
  4552. for ($ii=0; $ii<count(HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1]); $ii++) {
  4553. if (HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][$ii]['rowspan']==1) {
  4554. $ty = HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][$ii]['h'];
  4555. }
  4556. }
  4557. // new position
  4558. HTML2PDF::$_tables[$param['num']]['td_x'] = HTML2PDF::$_tables[$param['num']]['curr_x']+HTML2PDF::$_tables[$param['num']]['marge']['l'];
  4559. HTML2PDF::$_tables[$param['num']]['td_y']+= $ty;
  4560. HTML2PDF::$_tables[$param['num']]['new_page'] = false;
  4561. } else {
  4562. HTML2PDF::$_tables[$param['num']]['corr_y']++;
  4563. }
  4564. return true;
  4565. }
  4566. /**
  4567. * tag : TD
  4568. * mode : OPEN
  4569. *
  4570. * @param array $param
  4571. * @return boolean
  4572. */
  4573. protected function _tag_open_TD($param, $other = 'td')
  4574. {
  4575. if ($this->_isForOneLine) return false;
  4576. $this->_maxH = 0;
  4577. $param['cellpadding'] = HTML2PDF::$_tables[$param['num']]['cellpadding'].'mm';
  4578. $param['cellspacing'] = HTML2PDF::$_tables[$param['num']]['cellspacing'].'mm';
  4579. // specific style for LI
  4580. if ($other=='li') {
  4581. $specialLi = true;
  4582. } else {
  4583. $specialLi = false;
  4584. if ($other=='li_sub') {
  4585. $param['style']['border'] = 'none';
  4586. $param['style']['background-color'] = 'transparent';
  4587. $param['style']['background-image'] = 'none';
  4588. $param['style']['background-position'] = '';
  4589. $param['style']['background-repeat'] = '';
  4590. $other = 'li';
  4591. }
  4592. }
  4593. // get the properties of the TD
  4594. $x = HTML2PDF::$_tables[$param['num']]['td_curr'];
  4595. $y = HTML2PDF::$_tables[$param['num']]['tr_curr']-1;
  4596. $colspan = isset($param['colspan']) ? $param['colspan'] : 1;
  4597. $rowspan = isset($param['rowspan']) ? $param['rowspan'] : 1;
  4598. // flag for collapse table
  4599. $collapse = false;
  4600. // specific traitment for TD and TH
  4601. if (in_array($other, array('td', 'th'))) {
  4602. // id of the column
  4603. $numCol = isset(HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Xr']) ? HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Xr'] : HTML2PDF::$_tables[$param['num']]['corr_x'];
  4604. // we get the properties of the COL tag, if exist
  4605. if (isset(HTML2PDF::$_tables[$param['num']]['cols'][$numCol])) {
  4606. $colParam = HTML2PDF::$_tables[$param['num']]['cols'][$numCol];
  4607. // for colspans => we get all the neede widths
  4608. $colParam['style']['width'] = array();
  4609. for ($k=0; $k<$colspan; $k++) {
  4610. if (isset(HTML2PDF::$_tables[$param['num']]['cols'][$numCol+$k]['style']['width'])) {
  4611. $colParam['style']['width'][] = HTML2PDF::$_tables[$param['num']]['cols'][$numCol+$k]['style']['width'];
  4612. }
  4613. }
  4614. // calculate the total width of the column
  4615. $total = '';
  4616. $last = $this->parsingCss->getLastWidth();
  4617. if (count($colParam['style']['width'])) {
  4618. $total = $colParam['style']['width'][0]; unset($colParam['style']['width'][0]);
  4619. foreach ($colParam['style']['width'] as $width) {
  4620. if (substr($total, -1)=='%' && substr($width, -1)=='%')
  4621. $total = (str_replace('%', '', $total)+str_replace('%', '', $width)).'%';
  4622. else
  4623. $total = ($this->parsingCss->ConvertToMM($total, $last) + $this->parsingCss->ConvertToMM($width, $last)).'mm';
  4624. }
  4625. }
  4626. // get the final width
  4627. if ($total) {
  4628. $colParam['style']['width'] = $total;
  4629. } else {
  4630. unset($colParam['style']['width']);
  4631. }
  4632. // merge the styles of the COL and the TD
  4633. $param['style'] = array_merge($colParam['style'], $param['style']);
  4634. // merge the class of the COL and the TD
  4635. if (isset($colParam['class'])) {
  4636. $param['class'] = $colParam['class'].(isset($param['class']) ? ' '.$param['class'] : '');
  4637. }
  4638. }
  4639. $collapse = isset($this->parsingCss->value['border']['collapse']) ? $this->parsingCss->value['border']['collapse'] : false;
  4640. }
  4641. $this->parsingCss->save();
  4642. // legacy for TD and TH
  4643. $legacy = null;
  4644. if (in_array($other, array('td', 'th'))) {
  4645. $legacy = array();
  4646. $old = $this->parsingCss->getLastValue('background');
  4647. if ($old && ($old['color'] || $old['image']))
  4648. $legacy['background'] = $old;
  4649. if (HTML2PDF::$_tables[$param['num']]['border']) {
  4650. $legacy['border'] = array();
  4651. $legacy['border']['l'] = HTML2PDF::$_tables[$param['num']]['border'];
  4652. $legacy['border']['t'] = HTML2PDF::$_tables[$param['num']]['border'];
  4653. $legacy['border']['r'] = HTML2PDF::$_tables[$param['num']]['border'];
  4654. $legacy['border']['b'] = HTML2PDF::$_tables[$param['num']]['border'];
  4655. }
  4656. }
  4657. $return = $this->parsingCss->analyse($other, $param, $legacy);
  4658. if ($specialLi) {
  4659. $this->parsingCss->value['width']-= $this->parsingCss->ConvertToMM($this->_listeGetWidth());
  4660. $this->parsingCss->value['width']-= $this->parsingCss->ConvertToMM($this->_listeGetPadding());
  4661. }
  4662. $this->parsingCss->setPosition();
  4663. $this->parsingCss->fontSet();
  4664. // if tale collapse => modify the borders
  4665. if ($collapse) {
  4666. if (!$this->_subPart) {
  4667. if (
  4668. (HTML2PDF::$_tables[$param['num']]['tr_curr']>1 && !HTML2PDF::$_tables[$param['num']]['new_page']) ||
  4669. (!$this->_isInThead && count(HTML2PDF::$_tables[$param['num']]['thead']['code']))
  4670. ) {
  4671. $this->parsingCss->value['border']['t'] = $this->parsingCss->readBorder('none');
  4672. }
  4673. }
  4674. if (HTML2PDF::$_tables[$param['num']]['td_curr']>0) {
  4675. if (!$return) $this->parsingCss->value['width']+= $this->parsingCss->value['border']['l']['width'];
  4676. $this->parsingCss->value['border']['l'] = $this->parsingCss->readBorder('none');
  4677. }
  4678. }
  4679. // margins of the table
  4680. $marge = array();
  4681. $marge['t'] = $this->parsingCss->value['padding']['t']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['t']['width'];
  4682. $marge['r'] = $this->parsingCss->value['padding']['r']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['r']['width'];
  4683. $marge['b'] = $this->parsingCss->value['padding']['b']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['b']['width'];
  4684. $marge['l'] = $this->parsingCss->value['padding']['l']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['l']['width'];
  4685. // if we are in a sub HTML
  4686. if ($this->_subPart) {
  4687. // new position in the table
  4688. HTML2PDF::$_tables[$param['num']]['td_curr']++;
  4689. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x] = array();
  4690. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['w'] = 0;
  4691. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['h'] = 0;
  4692. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['dw'] = 0;
  4693. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['colspan'] = $colspan;
  4694. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['rowspan'] = $rowspan;
  4695. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Xr'] = HTML2PDF::$_tables[$param['num']]['corr_x'];
  4696. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['Yr'] = HTML2PDF::$_tables[$param['num']]['corr_y'];
  4697. // prepare the mapping for rowspan and colspan
  4698. for ($j=0; $j<$rowspan; $j++) {
  4699. for ($i=0; $i<$colspan; $i++) {
  4700. HTML2PDF::$_tables[$param['num']]['corr']
  4701. [HTML2PDF::$_tables[$param['num']]['corr_y']+$j]
  4702. [HTML2PDF::$_tables[$param['num']]['corr_x']+$i] = ($i+$j>0) ? '' : array($x,$y,$colspan,$rowspan);
  4703. }
  4704. }
  4705. HTML2PDF::$_tables[$param['num']]['corr_x']+= $colspan;
  4706. while (isset(HTML2PDF::$_tables[$param['num']]['corr'][HTML2PDF::$_tables[$param['num']]['corr_y']][HTML2PDF::$_tables[$param['num']]['corr_x']])) {
  4707. HTML2PDF::$_tables[$param['num']]['corr_x']++;
  4708. }
  4709. // extract the content of the TD, and calculate his size
  4710. $level = $this->parsingHtml->getLevel($this->_tempPos);
  4711. $this->_createSubHTML($this->_subHtml);
  4712. $this->_subHtml->parsingHtml->code = $level;
  4713. $this->_subHtml->_makeHTMLcode();
  4714. $this->_tempPos+= count($level);
  4715. } else {
  4716. // new position in the table
  4717. HTML2PDF::$_tables[$param['num']]['td_curr']++;
  4718. HTML2PDF::$_tables[$param['num']]['td_x']+= HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['dw'];
  4719. // borders and background of the TD
  4720. $this->_drawRectangle(
  4721. HTML2PDF::$_tables[$param['num']]['td_x'],
  4722. HTML2PDF::$_tables[$param['num']]['td_y'],
  4723. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['w'],
  4724. HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['h'],
  4725. $this->parsingCss->value['border'],
  4726. $this->parsingCss->value['padding'],
  4727. HTML2PDF::$_tables[$param['num']]['cellspacing']*0.5,
  4728. $this->parsingCss->value['background']
  4729. );
  4730. $this->parsingCss->value['width'] = HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['w'] - $marge['l'] - $marge['r'];
  4731. // marges = size of the TD
  4732. $mL = HTML2PDF::$_tables[$param['num']]['td_x']+$marge['l'];
  4733. $mR = $this->pdf->getW() - $mL - $this->parsingCss->value['width'];
  4734. $this->_saveMargin($mL, 0, $mR);
  4735. // position of the content, from vertical-align
  4736. $hCorr = HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['h'];
  4737. $hReel = HTML2PDF::$_tables[$param['num']]['cases'][$y][$x]['real_h'];
  4738. switch($this->parsingCss->value['vertical-align'])
  4739. {
  4740. case 'bottom':
  4741. $yCorr = $hCorr-$hReel;
  4742. break;
  4743. case 'middle':
  4744. $yCorr = ($hCorr-$hReel)*0.5;
  4745. break;
  4746. case 'top':
  4747. default:
  4748. $yCorr = 0;
  4749. break;
  4750. }
  4751. // position of the content
  4752. $x = HTML2PDF::$_tables[$param['num']]['td_x']+$marge['l'];
  4753. $y = HTML2PDF::$_tables[$param['num']]['td_y']+$marge['t']+$yCorr;
  4754. $this->pdf->setXY($x, $y);
  4755. $this->_setNewPositionForNewLine();
  4756. }
  4757. return true;
  4758. }
  4759. /**
  4760. * tag : TD
  4761. * mode : CLOSE
  4762. *
  4763. * @param array $param
  4764. * @return boolean
  4765. */
  4766. protected function _tag_close_TD($param)
  4767. {
  4768. if ($this->_isForOneLine) return false;
  4769. $this->_maxH = 0;
  4770. // get the margins
  4771. $marge = array();
  4772. $marge['t'] = $this->parsingCss->value['padding']['t']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['t']['width'];
  4773. $marge['r'] = $this->parsingCss->value['padding']['r']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['r']['width'];
  4774. $marge['b'] = $this->parsingCss->value['padding']['b']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['b']['width'];
  4775. $marge['l'] = $this->parsingCss->value['padding']['l']+0.5*HTML2PDF::$_tables[$param['num']]['cellspacing']+$this->parsingCss->value['border']['l']['width'];
  4776. $marge['t']+= 0.001;
  4777. $marge['r']+= 0.001;
  4778. $marge['b']+= 0.001;
  4779. $marge['l']+= 0.001;
  4780. // if we are in a sub HTML
  4781. if ($this->_subPart) {
  4782. // it msut take only one page
  4783. if ($this->_testTdInOnepage && $this->_subHtml->pdf->getPage()>1) {
  4784. throw new HTML2PDF_exception(7);
  4785. }
  4786. // size of the content of the TD
  4787. $w0 = $this->_subHtml->_maxX + $marge['l'] + $marge['r'];
  4788. $h0 = $this->_subHtml->_maxY + $marge['t'] + $marge['b'];
  4789. // size from the CSS style
  4790. $w2 = $this->parsingCss->value['width'] + $marge['l'] + $marge['r'];
  4791. $h2 = $this->parsingCss->value['height'] + $marge['t'] + $marge['b'];
  4792. // final size of the TD
  4793. HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['w'] = max(array($w0, $w2));
  4794. HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['h'] = max(array($h0, $h2));
  4795. // real position of the content
  4796. HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['real_w'] = $w0;
  4797. HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['real_h'] = $h0;
  4798. // destroy the sub HTML
  4799. $this->_destroySubHTML($this->_subHtml);
  4800. } else {
  4801. $this->_loadMargin();
  4802. HTML2PDF::$_tables[$param['num']]['td_x']+= HTML2PDF::$_tables[$param['num']]['cases'][HTML2PDF::$_tables[$param['num']]['tr_curr']-1][HTML2PDF::$_tables[$param['num']]['td_curr']-1]['w'];
  4803. }
  4804. $this->parsingCss->load();
  4805. $this->parsingCss->fontSet();
  4806. return true;
  4807. }
  4808. /**
  4809. * tag : TH
  4810. * mode : OPEN
  4811. *
  4812. * @param array $param
  4813. * @return boolean
  4814. */
  4815. protected function _tag_open_TH($param)
  4816. {
  4817. if ($this->_isForOneLine) return false;
  4818. $this->parsingCss->save();
  4819. $this->parsingCss->value['font-bold'] = true;
  4820. $this->_tag_open_TD($param, 'th');
  4821. return true;
  4822. }
  4823. /**
  4824. * tag : TH
  4825. * mode : CLOSE
  4826. *
  4827. * @param array $param
  4828. * @return boolean
  4829. */
  4830. protected function _tag_close_TH($param)
  4831. {
  4832. if ($this->_isForOneLine) return false;
  4833. $this->_tag_close_TD($param);
  4834. $this->parsingCss->load();
  4835. return true;
  4836. }
  4837. /**
  4838. * tag : IMG
  4839. * mode : OPEN
  4840. *
  4841. * @param array $param
  4842. * @return boolean
  4843. */
  4844. protected function _tag_open_IMG($param)
  4845. {
  4846. $src = str_replace('&amp;', '&', $param['src']);
  4847. $this->parsingCss->save();
  4848. $this->parsingCss->value['width'] = 0;
  4849. $this->parsingCss->value['height'] = 0;
  4850. $this->parsingCss->value['border'] = array('type' => 'none', 'width' => 0, 'color' => array(0, 0, 0));
  4851. $this->parsingCss->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
  4852. $this->parsingCss->analyse('img', $param);
  4853. $this->parsingCss->setPosition();
  4854. $this->parsingCss->fontSet();
  4855. $res = $this->_drawImage($src, isset($param['sub_li']));
  4856. if (!$res) return $res;
  4857. $this->parsingCss->load();
  4858. $this->parsingCss->fontSet();
  4859. $this->_maxE++;
  4860. return true;
  4861. }
  4862. /**
  4863. * tag : SELECT
  4864. * mode : OPEN
  4865. *
  4866. * @param array $param
  4867. * @return boolean
  4868. */
  4869. protected function _tag_open_SELECT($param)
  4870. {
  4871. if (!isset($param['name'])) {
  4872. $param['name'] = 'champs_pdf_'.(count($this->_lstField)+1);
  4873. }
  4874. $param['name'] = strtolower($param['name']);
  4875. if (isset($this->_lstField[$param['name']])) {
  4876. $this->_lstField[$param['name']]++;
  4877. } else {
  4878. $this->_lstField[$param['name']] = 1;
  4879. }
  4880. $this->parsingCss->save();
  4881. $this->parsingCss->analyse('select', $param);
  4882. $this->parsingCss->setPosition();
  4883. $this->parsingCss->fontSet();
  4884. $this->_lstSelect = array();
  4885. $this->_lstSelect['name'] = $param['name'];
  4886. $this->_lstSelect['multi'] = isset($param['multiple']) ? true : false;
  4887. $this->_lstSelect['size'] = isset($param['size']) ? $param['size'] : 1;
  4888. $this->_lstSelect['options'] = array();
  4889. if ($this->_lstSelect['multi'] && $this->_lstSelect['size']<3) $this->_lstSelect['size'] = 3;
  4890. return true;
  4891. }
  4892. /**
  4893. * tag : OPTION
  4894. * mode : OPEN
  4895. *
  4896. * @param array $param
  4897. * @return boolean
  4898. */
  4899. protected function _tag_open_OPTION($param)
  4900. {
  4901. // get the content of the option : it is the text of the option
  4902. $level = $this->parsingHtml->getLevel($this->_parsePos);
  4903. $this->_parsePos+= count($level);
  4904. $value = isset($param['value']) ? $param['value'] : 'aut_tag_open_opt_'.(count($this->_lstSelect)+1);
  4905. $this->_lstSelect['options'][$value] = isset($level[0]['param']['txt']) ? $level[0]['param']['txt'] : '';
  4906. return true;
  4907. }
  4908. /**
  4909. * tag : OPTION
  4910. * mode : CLOSE
  4911. *
  4912. * @param array $param
  4913. * @return boolean
  4914. */
  4915. protected function _tag_close_OPTION($param)
  4916. {
  4917. // nothing to do here
  4918. return true;
  4919. }
  4920. /**
  4921. * tag : SELECT
  4922. * mode : CLOSE
  4923. *
  4924. * @param array $param
  4925. * @return boolean
  4926. */
  4927. protected function _tag_close_SELECT()
  4928. {
  4929. // position of the select
  4930. $x = $this->pdf->getX();
  4931. $y = $this->pdf->getY();
  4932. $f = 1.08*$this->parsingCss->value['font-size'];
  4933. // width
  4934. $w = $this->parsingCss->value['width']; if (!$w) $w = 50;
  4935. // height (automatic)
  4936. $h = ($f*1.07*$this->_lstSelect['size'] + 1);
  4937. $prop = $this->parsingCss->getFormStyle();
  4938. // multy select
  4939. if ($this->_lstSelect['multi']) {
  4940. $prop['multipleSelection'] = 'true';
  4941. }
  4942. // single or multi select
  4943. if ($this->_lstSelect['size']>1) {
  4944. $this->pdf->ListBox($this->_lstSelect['name'], $w, $h, $this->_lstSelect['options'], $prop);
  4945. } else {
  4946. $this->pdf->ComboBox($this->_lstSelect['name'], $w, $h, $this->_lstSelect['options'], $prop);
  4947. }
  4948. $this->_maxX = max($this->_maxX, $x+$w);
  4949. $this->_maxY = max($this->_maxY, $y+$h);
  4950. $this->_maxH = max($this->_maxH, $h);
  4951. $this->_maxE++;
  4952. $this->pdf->setX($x+$w);
  4953. $this->parsingCss->load();
  4954. $this->parsingCss->fontSet();
  4955. $this->_lstSelect = array();
  4956. return true;
  4957. }
  4958. /**
  4959. * tag : TEXTAREA
  4960. * mode : OPEN
  4961. *
  4962. * @param array $param
  4963. * @return boolean
  4964. */
  4965. protected function _tag_open_TEXTAREA($param)
  4966. {
  4967. if (!isset($param['name'])) {
  4968. $param['name'] = 'champs_pdf_'.(count($this->_lstField)+1);
  4969. }
  4970. $param['name'] = strtolower($param['name']);
  4971. if (isset($this->_lstField[$param['name']])) {
  4972. $this->_lstField[$param['name']]++;
  4973. } else {
  4974. $this->_lstField[$param['name']] = 1;
  4975. }
  4976. $this->parsingCss->save();
  4977. $this->parsingCss->analyse('textarea', $param);
  4978. $this->parsingCss->setPosition();
  4979. $this->parsingCss->fontSet();
  4980. $x = $this->pdf->getX();
  4981. $y = $this->pdf->getY();
  4982. $fx = 0.65*$this->parsingCss->value['font-size'];
  4983. $fy = 1.08*$this->parsingCss->value['font-size'];
  4984. // extract the content the textarea : value
  4985. $level = $this->parsingHtml->getLevel($this->_parsePos);
  4986. $this->_parsePos+= count($level);
  4987. // automatic size, from cols and rows properties
  4988. $w = $fx*(isset($param['cols']) ? $param['cols'] : 22)+1;
  4989. $h = $fy*1.07*(isset($param['rows']) ? $param['rows'] : 3)+3;
  4990. $prop = $this->parsingCss->getFormStyle();
  4991. $prop['multiline'] = true;
  4992. $prop['value'] = isset($level[0]['param']['txt']) ? $level[0]['param']['txt'] : '';
  4993. $this->pdf->TextField($param['name'], $w, $h, $prop, array(), $x, $y);
  4994. $this->_maxX = max($this->_maxX, $x+$w);
  4995. $this->_maxY = max($this->_maxY, $y+$h);
  4996. $this->_maxH = max($this->_maxH, $h);
  4997. $this->_maxE++;
  4998. $this->pdf->setX($x+$w);
  4999. return true;
  5000. }
  5001. /**
  5002. * tag : TEXTAREA
  5003. * mode : CLOSE
  5004. *
  5005. * @param array $param
  5006. * @return boolean
  5007. */
  5008. protected function _tag_close_TEXTAREA()
  5009. {
  5010. $this->parsingCss->load();
  5011. $this->parsingCss->fontSet();
  5012. return true;
  5013. }
  5014. /**
  5015. * tag : INPUT
  5016. * mode : OPEN
  5017. *
  5018. * @param array $param
  5019. * @return boolean
  5020. */
  5021. protected function _tag_open_INPUT($param)
  5022. {
  5023. if (!isset($param['name'])) $param['name'] = 'champs_pdf_'.(count($this->_lstField)+1);
  5024. if (!isset($param['value'])) $param['value'] = '';
  5025. if (!isset($param['type'])) $param['type'] = 'text';
  5026. $param['name'] = strtolower($param['name']);
  5027. $param['type'] = strtolower($param['type']);
  5028. // the type must be valid
  5029. if (!in_array($param['type'], array('text', 'checkbox', 'radio', 'hidden', 'submit', 'reset', 'button'))) {
  5030. $param['type'] = 'text';
  5031. }
  5032. if (isset($this->_lstField[$param['name']])) {
  5033. $this->_lstField[$param['name']]++;
  5034. } else {
  5035. $this->_lstField[$param['name']] = 1;
  5036. }
  5037. $this->parsingCss->save();
  5038. $this->parsingCss->analyse('input', $param);
  5039. $this->parsingCss->setPosition();
  5040. $this->parsingCss->fontSet();
  5041. $name = $param['name'];
  5042. $x = $this->pdf->getX();
  5043. $y = $this->pdf->getY();
  5044. $f = 1.08*$this->parsingCss->value['font-size'];
  5045. $prop = $this->parsingCss->getFormStyle();
  5046. switch($param['type'])
  5047. {
  5048. case 'checkbox':
  5049. $w = 3;
  5050. $h = $w;
  5051. if ($h<$f) $y+= ($f-$h)*0.5;
  5052. $checked = (isset($param['checked']) && $param['checked']=='checked');
  5053. $this->pdf->CheckBox($name, $w, $checked, $prop, array(), ($param['value'] ? $param['value'] : 'Yes'), $x, $y);
  5054. break;
  5055. case 'radio':
  5056. $w = 3;
  5057. $h = $w;
  5058. if ($h<$f) $y+= ($f-$h)*0.5;
  5059. $checked = (isset($param['checked']) && $param['checked']=='checked');
  5060. $this->pdf->RadioButton($name, $w, $prop, array(), ($param['value'] ? $param['value'] : 'On'), $checked, $x, $y);
  5061. break;
  5062. case 'hidden':
  5063. $w = 0;
  5064. $h = 0;
  5065. $prop['value'] = $param['value'];
  5066. $this->pdf->TextField($name, $w, $h, $prop, array(), $x, $y);
  5067. break;
  5068. case 'text':
  5069. $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
  5070. $h = $f*1.3;
  5071. $prop['value'] = $param['value'];
  5072. $this->pdf->TextField($name, $w, $h, $prop, array(), $x, $y);
  5073. break;
  5074. case 'submit':
  5075. $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
  5076. $h = $this->parsingCss->value['height']; if (!$h) $h = $f*1.3;
  5077. $action = array('S'=>'SubmitForm', 'F'=>$this->_isInForm, 'Flags'=>array('ExportFormat'));
  5078. $this->pdf->Button($name, $w, $h, $param['value'], $action, $prop, array(), $x, $y);
  5079. break;
  5080. case 'reset':
  5081. $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
  5082. $h = $this->parsingCss->value['height']; if (!$h) $h = $f*1.3;
  5083. $action = array('S'=>'ResetForm');
  5084. $this->pdf->Button($name, $w, $h, $param['value'], $action, $prop, array(), $x, $y);
  5085. break;
  5086. case 'button':
  5087. $w = $this->parsingCss->value['width']; if (!$w) $w = 40;
  5088. $h = $this->parsingCss->value['height']; if (!$h) $h = $f*1.3;
  5089. $action = isset($param['onclick']) ? $param['onclick'] : '';
  5090. $this->pdf->Button($name, $w, $h, $param['value'], $action, $prop, array(), $x, $y);
  5091. break;
  5092. default:
  5093. $w = 0;
  5094. $h = 0;
  5095. break;
  5096. }
  5097. $this->_maxX = max($this->_maxX, $x+$w);
  5098. $this->_maxY = max($this->_maxY, $y+$h);
  5099. $this->_maxH = max($this->_maxH, $h);
  5100. $this->_maxE++;
  5101. $this->pdf->setX($x+$w);
  5102. $this->parsingCss->load();
  5103. $this->parsingCss->fontSet();
  5104. return true;
  5105. }
  5106. /**
  5107. * tag : DRAW
  5108. * mode : OPEN
  5109. *
  5110. * @param array $param
  5111. * @return boolean
  5112. */
  5113. protected function _tag_open_DRAW($param)
  5114. {
  5115. if ($this->_isForOneLine) return false;
  5116. if ($this->_debugActif) $this->_DEBUG_add('DRAW', true);
  5117. $this->parsingCss->save();
  5118. $this->parsingCss->analyse('draw', $param);
  5119. $this->parsingCss->fontSet();
  5120. $alignObject = null;
  5121. if ($this->parsingCss->value['margin-auto']) $alignObject = 'center';
  5122. $overW = $this->parsingCss->value['width'];
  5123. $overH = $this->parsingCss->value['height'];
  5124. $this->parsingCss->value['old_maxX'] = $this->_maxX;
  5125. $this->parsingCss->value['old_maxY'] = $this->_maxY;
  5126. $this->parsingCss->value['old_maxH'] = $this->_maxH;
  5127. $w = $this->parsingCss->value['width'];
  5128. $h = $this->parsingCss->value['height'];
  5129. if (!$this->parsingCss->value['position']) {
  5130. if (
  5131. $w < ($this->pdf->getW() - $this->pdf->getlMargin()-$this->pdf->getrMargin()) &&
  5132. $this->pdf->getX() + $w>=($this->pdf->getW() - $this->pdf->getrMargin())
  5133. )
  5134. $this->_tag_open_BR(array());
  5135. if (
  5136. ($h < ($this->pdf->getH() - $this->pdf->gettMargin()-$this->pdf->getbMargin())) &&
  5137. ($this->pdf->getY() + $h>=($this->pdf->getH() - $this->pdf->getbMargin())) &&
  5138. !$this->_isInOverflow
  5139. )
  5140. $this->_setNewPage();
  5141. $old = $this->parsingCss->getOldValues();
  5142. $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  5143. if ($parentWidth>$w) {
  5144. if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
  5145. else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
  5146. }
  5147. $this->parsingCss->setPosition();
  5148. } else {
  5149. $old = $this->parsingCss->getOldValues();
  5150. $parentWidth = $old['width'] ? $old['width'] : $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  5151. if ($parentWidth>$w) {
  5152. if ($alignObject=='center') $this->pdf->setX($this->pdf->getX() + ($parentWidth-$w)*0.5);
  5153. else if ($alignObject=='right') $this->pdf->setX($this->pdf->getX() + $parentWidth-$w);
  5154. }
  5155. $this->parsingCss->setPosition();
  5156. $this->_saveMax();
  5157. $this->_maxX = 0;
  5158. $this->_maxY = 0;
  5159. $this->_maxH = 0;
  5160. $this->_maxE = 0;
  5161. }
  5162. $this->_drawRectangle(
  5163. $this->parsingCss->value['x'],
  5164. $this->parsingCss->value['y'],
  5165. $this->parsingCss->value['width'],
  5166. $this->parsingCss->value['height'],
  5167. $this->parsingCss->value['border'],
  5168. $this->parsingCss->value['padding'],
  5169. 0,
  5170. $this->parsingCss->value['background']
  5171. );
  5172. $marge = array();
  5173. $marge['l'] = $this->parsingCss->value['border']['l']['width'];
  5174. $marge['r'] = $this->parsingCss->value['border']['r']['width'];
  5175. $marge['t'] = $this->parsingCss->value['border']['t']['width'];
  5176. $marge['b'] = $this->parsingCss->value['border']['b']['width'];
  5177. $this->parsingCss->value['width'] -= $marge['l']+$marge['r'];
  5178. $this->parsingCss->value['height']-= $marge['t']+$marge['b'];
  5179. $overW-= $marge['l']+$marge['r'];
  5180. $overH-= $marge['t']+$marge['b'];
  5181. // clipping to draw only in the size opf the DRAW tag
  5182. $this->pdf->clippingPathStart(
  5183. $this->parsingCss->value['x']+$marge['l'],
  5184. $this->parsingCss->value['y']+$marge['t'],
  5185. $this->parsingCss->value['width'],
  5186. $this->parsingCss->value['height']
  5187. );
  5188. // left and right of the DRAW tag
  5189. $mL = $this->parsingCss->value['x']+$marge['l'];
  5190. $mR = $this->pdf->getW() - $mL - $overW;
  5191. // position of the DRAW tag
  5192. $x = $this->parsingCss->value['x']+$marge['l'];
  5193. $y = $this->parsingCss->value['y']+$marge['t'];
  5194. // prepare the drawing area
  5195. $this->_saveMargin($mL, 0, $mR);
  5196. $this->pdf->setXY($x, $y);
  5197. // we are in a draw tag
  5198. $this->_isInDraw = array(
  5199. 'x' => $x,
  5200. 'y' => $y,
  5201. 'w' => $overW,
  5202. 'h' => $overH,
  5203. );
  5204. // init the translate matrix : (0,0) => ($x, $y)
  5205. $this->pdf->doTransform(array(1,0,0,1,$x,$y));
  5206. $this->pdf->SetAlpha(1.);
  5207. return true;
  5208. }
  5209. /**
  5210. * tag : DRAW
  5211. * mode : CLOSE
  5212. *
  5213. * @param array $param
  5214. * @return boolean
  5215. */
  5216. protected function _tag_close_DRAW($param)
  5217. {
  5218. if ($this->_isForOneLine) return false;
  5219. $this->pdf->SetAlpha(1.);
  5220. $this->pdf->undoTransform();
  5221. $this->pdf->clippingPathStop();
  5222. $this->_maxX = $this->parsingCss->value['old_maxX'];
  5223. $this->_maxY = $this->parsingCss->value['old_maxY'];
  5224. $this->_maxH = $this->parsingCss->value['old_maxH'];
  5225. $marge = array();
  5226. $marge['l'] = $this->parsingCss->value['border']['l']['width'];
  5227. $marge['r'] = $this->parsingCss->value['border']['r']['width'];
  5228. $marge['t'] = $this->parsingCss->value['border']['t']['width'];
  5229. $marge['b'] = $this->parsingCss->value['border']['b']['width'];
  5230. $x = $this->parsingCss->value['x'];
  5231. $y = $this->parsingCss->value['y'];
  5232. $w = $this->parsingCss->value['width']+$marge['l']+$marge['r'];
  5233. $h = $this->parsingCss->value['height']+$marge['t']+$marge['b'];
  5234. if ($this->parsingCss->value['position']!='absolute') {
  5235. $this->pdf->setXY($x+$w, $y);
  5236. $this->_maxX = max($this->_maxX, $x+$w);
  5237. $this->_maxY = max($this->_maxY, $y+$h);
  5238. $this->_maxH = max($this->_maxH, $h);
  5239. $this->_maxE++;
  5240. } else {
  5241. // position
  5242. $this->pdf->setXY($this->parsingCss->value['xc'], $this->parsingCss->value['yc']);
  5243. $this->_loadMax();
  5244. }
  5245. $block = ($this->parsingCss->value['display']!='inline' && $this->parsingCss->value['position']!='absolute');
  5246. $this->parsingCss->load();
  5247. $this->parsingCss->fontSet();
  5248. $this->_loadMargin();
  5249. if ($block) $this->_tag_open_BR(array());
  5250. if ($this->_debugActif) $this->_DEBUG_add('DRAW', false);
  5251. $this->_isInDraw = null;
  5252. return true;
  5253. }
  5254. /**
  5255. * tag : LINE
  5256. * mode : OPEN
  5257. *
  5258. * @param array $param
  5259. * @return boolean
  5260. */
  5261. protected function _tag_open_LINE($param)
  5262. {
  5263. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'LINE');
  5264. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5265. $this->parsingCss->save();
  5266. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5267. $styles['fill'] = null;
  5268. $style = $this->pdf->svgSetStyle($styles);
  5269. $x1 = isset($param['x1']) ? $this->parsingCss->ConvertToMM($param['x1'], $this->_isInDraw['w']) : 0.;
  5270. $y1 = isset($param['y1']) ? $this->parsingCss->ConvertToMM($param['y1'], $this->_isInDraw['h']) : 0.;
  5271. $x2 = isset($param['x2']) ? $this->parsingCss->ConvertToMM($param['x2'], $this->_isInDraw['w']) : 0.;
  5272. $y2 = isset($param['y2']) ? $this->parsingCss->ConvertToMM($param['y2'], $this->_isInDraw['h']) : 0.;
  5273. $this->pdf->svgLine($x1, $y1, $x2, $y2);
  5274. $this->pdf->undoTransform();
  5275. $this->parsingCss->load();
  5276. }
  5277. /**
  5278. * tag : RECT
  5279. * mode : OPEN
  5280. *
  5281. * @param array $param
  5282. * @return boolean
  5283. */
  5284. protected function _tag_open_RECT($param)
  5285. {
  5286. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'RECT');
  5287. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5288. $this->parsingCss->save();
  5289. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5290. $style = $this->pdf->svgSetStyle($styles);
  5291. $x = isset($param['x']) ? $this->parsingCss->ConvertToMM($param['x'], $this->_isInDraw['w']) : 0.;
  5292. $y = isset($param['y']) ? $this->parsingCss->ConvertToMM($param['y'], $this->_isInDraw['h']) : 0.;
  5293. $w = isset($param['w']) ? $this->parsingCss->ConvertToMM($param['w'], $this->_isInDraw['w']) : 0.;
  5294. $h = isset($param['h']) ? $this->parsingCss->ConvertToMM($param['h'], $this->_isInDraw['h']) : 0.;
  5295. $this->pdf->svgRect($x, $y, $w, $h, $style);
  5296. $this->pdf->undoTransform();
  5297. $this->parsingCss->load();
  5298. }
  5299. /**
  5300. * tag : CIRCLE
  5301. * mode : OPEN
  5302. *
  5303. * @param array $param
  5304. * @return boolean
  5305. */
  5306. protected function _tag_open_CIRCLE($param)
  5307. {
  5308. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'CIRCLE');
  5309. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5310. $this->parsingCss->save();
  5311. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5312. $style = $this->pdf->svgSetStyle($styles);
  5313. $cx = isset($param['cx']) ? $this->parsingCss->ConvertToMM($param['cx'], $this->_isInDraw['w']) : 0.;
  5314. $cy = isset($param['cy']) ? $this->parsingCss->ConvertToMM($param['cy'], $this->_isInDraw['h']) : 0.;
  5315. $r = isset($param['r']) ? $this->parsingCss->ConvertToMM($param['r'], $this->_isInDraw['w']) : 0.;
  5316. $this->pdf->svgEllipse($cx, $cy, $r, $r, $style);
  5317. $this->pdf->undoTransform();
  5318. $this->parsingCss->load();
  5319. }
  5320. /**
  5321. * tag : ELLIPSE
  5322. * mode : OPEN
  5323. *
  5324. * @param array $param
  5325. * @return boolean
  5326. */
  5327. protected function _tag_open_ELLIPSE($param)
  5328. {
  5329. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'ELLIPSE');
  5330. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5331. $this->parsingCss->save();
  5332. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5333. $style = $this->pdf->svgSetStyle($styles);
  5334. $cx = isset($param['cx']) ? $this->parsingCss->ConvertToMM($param['cx'], $this->_isInDraw['w']) : 0.;
  5335. $cy = isset($param['cy']) ? $this->parsingCss->ConvertToMM($param['cy'], $this->_isInDraw['h']) : 0.;
  5336. $rx = isset($param['ry']) ? $this->parsingCss->ConvertToMM($param['rx'], $this->_isInDraw['w']) : 0.;
  5337. $ry = isset($param['rx']) ? $this->parsingCss->ConvertToMM($param['ry'], $this->_isInDraw['h']) : 0.;
  5338. $this->pdf->svgEllipse($cx, $cy, $rx, $ry, $style);
  5339. $this->pdf->undoTransform();
  5340. $this->parsingCss->load();
  5341. }
  5342. /**
  5343. * tag : POLYLINE
  5344. * mode : OPEN
  5345. *
  5346. * @param array $param
  5347. * @return boolean
  5348. */
  5349. protected function _tag_open_POLYLINE($param)
  5350. {
  5351. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'POLYGON');
  5352. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5353. $this->parsingCss->save();
  5354. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5355. $style = $this->pdf->svgSetStyle($styles);
  5356. $path = isset($param['points']) ? $param['points'] : null;
  5357. if ($path) {
  5358. $path = str_replace(',', ' ', $path);
  5359. $path = preg_replace('/[\s]+/', ' ', trim($path));
  5360. // prepare the path
  5361. $path = explode(' ', $path);
  5362. foreach ($path as $k => $v) {
  5363. $path[$k] = trim($v);
  5364. if ($path[$k]==='') unset($path[$k]);
  5365. }
  5366. $path = array_values($path);
  5367. $actions = array();
  5368. for ($k=0; $k<count($path); $k+=2) {
  5369. $actions[] = array(
  5370. ($k ? 'L' : 'M') ,
  5371. $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']),
  5372. $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h'])
  5373. );
  5374. }
  5375. // drawing
  5376. $this->pdf->svgPolygone($actions, $style);
  5377. }
  5378. $this->pdf->undoTransform();
  5379. $this->parsingCss->load();
  5380. }
  5381. /**
  5382. * tag : POLYGON
  5383. * mode : OPEN
  5384. *
  5385. * @param array $param
  5386. * @return boolean
  5387. */
  5388. protected function _tag_open_POLYGON($param)
  5389. {
  5390. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'POLYGON');
  5391. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5392. $this->parsingCss->save();
  5393. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5394. $style = $this->pdf->svgSetStyle($styles);
  5395. $path = (isset($param['points']) ? $param['points'] : null);
  5396. if ($path) {
  5397. $path = str_replace(',', ' ', $path);
  5398. $path = preg_replace('/[\s]+/', ' ', trim($path));
  5399. // prepare the path
  5400. $path = explode(' ', $path);
  5401. foreach ($path as $k => $v) {
  5402. $path[$k] = trim($v);
  5403. if ($path[$k]==='') unset($path[$k]);
  5404. }
  5405. $path = array_values($path);
  5406. $actions = array();
  5407. for ($k=0; $k<count($path); $k+=2) {
  5408. $actions[] = array(
  5409. ($k ? 'L' : 'M') ,
  5410. $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']),
  5411. $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h'])
  5412. );
  5413. }
  5414. $actions[] = array('z');
  5415. // drawing
  5416. $this->pdf->svgPolygone($actions, $style);
  5417. }
  5418. $this->pdf->undoTransform();
  5419. $this->parsingCss->load();
  5420. }
  5421. /**
  5422. * tag : PATH
  5423. * mode : OPEN
  5424. *
  5425. * @param array $param
  5426. * @return boolean
  5427. */
  5428. protected function _tag_open_PATH($param)
  5429. {
  5430. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'PATH');
  5431. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5432. $this->parsingCss->save();
  5433. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5434. $style = $this->pdf->svgSetStyle($styles);
  5435. $path = isset($param['d']) ? $param['d'] : null;
  5436. if ($path) {
  5437. // prepare the path
  5438. $path = str_replace(',', ' ', $path);
  5439. $path = preg_replace('/([a-zA-Z])([0-9\.\-])/', '$1 $2', $path);
  5440. $path = preg_replace('/([0-9\.])([a-zA-Z])/', '$1 $2', $path);
  5441. $path = preg_replace('/[\s]+/', ' ', trim($path));
  5442. $path = preg_replace('/ ([a-z]{2})/', '$1', $path);
  5443. $path = explode(' ', $path);
  5444. foreach ($path as $k => $v) {
  5445. $path[$k] = trim($v);
  5446. if ($path[$k]==='') unset($path[$k]);
  5447. }
  5448. $path = array_values($path);
  5449. // read each actions in the path
  5450. $actions = array();
  5451. $action = array();
  5452. $lastAction = null; // last action found
  5453. for ($k=0; $k<count($path);true) {
  5454. // for this actions, we can not have multi coordonate
  5455. if (in_array($lastAction, array('z', 'Z'))) {
  5456. $lastAction = null;
  5457. }
  5458. // read the new action (forcing if no action before)
  5459. if (preg_match('/^[a-z]+$/i', $path[$k]) || $lastAction===null) {
  5460. $lastAction = $path[$k];
  5461. $k++;
  5462. }
  5463. // current action
  5464. $action = array();
  5465. $action[] = $lastAction;
  5466. switch($lastAction)
  5467. {
  5468. case 'C':
  5469. case 'c':
  5470. $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x1
  5471. $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // y1
  5472. $action[] = $this->parsingCss->ConvertToMM($path[$k+2], $this->_isInDraw['w']); // x2
  5473. $action[] = $this->parsingCss->ConvertToMM($path[$k+3], $this->_isInDraw['h']); // y2
  5474. $action[] = $this->parsingCss->ConvertToMM($path[$k+4], $this->_isInDraw['w']); // x
  5475. $action[] = $this->parsingCss->ConvertToMM($path[$k+5], $this->_isInDraw['h']); // y
  5476. $k+= 6;
  5477. break;
  5478. case 'Q':
  5479. case 'S':
  5480. case 'q':
  5481. case 's':
  5482. $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x2
  5483. $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // y2
  5484. $action[] = $this->parsingCss->ConvertToMM($path[$k+2], $this->_isInDraw['w']); // x
  5485. $action[] = $this->parsingCss->ConvertToMM($path[$k+3], $this->_isInDraw['h']); // y
  5486. $k+= 4;
  5487. break;
  5488. case 'A':
  5489. case 'a':
  5490. $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // rx
  5491. $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // ry
  5492. $action[] = 1.*$path[$k+2]; // angle de deviation de l'axe X
  5493. $action[] = ($path[$k+3]=='1') ? 1 : 0; // large-arc-flag
  5494. $action[] = ($path[$k+4]=='1') ? 1 : 0; // sweep-flag
  5495. $action[] = $this->parsingCss->ConvertToMM($path[$k+5], $this->_isInDraw['w']); // x
  5496. $action[] = $this->parsingCss->ConvertToMM($path[$k+6], $this->_isInDraw['h']); // y
  5497. $k+= 7;
  5498. break;
  5499. case 'M':
  5500. case 'L':
  5501. case 'T':
  5502. case 'm':
  5503. case 'l':
  5504. case 't':
  5505. $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x
  5506. $action[] = $this->parsingCss->ConvertToMM($path[$k+1], $this->_isInDraw['h']); // y
  5507. $k+= 2;
  5508. break;
  5509. case 'H':
  5510. case 'h':
  5511. $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['w']); // x
  5512. $k+= 1;
  5513. break;
  5514. case 'V':
  5515. case 'v':
  5516. $action[] = $this->parsingCss->ConvertToMM($path[$k+0], $this->_isInDraw['h']); // y
  5517. $k+= 1;
  5518. break;
  5519. case 'z':
  5520. case 'Z':
  5521. default:
  5522. break;
  5523. }
  5524. // add the action
  5525. $actions[] = $action;
  5526. }
  5527. // drawing
  5528. $this->pdf->svgPolygone($actions, $style);
  5529. }
  5530. $this->pdf->undoTransform();
  5531. $this->parsingCss->load();
  5532. }
  5533. /**
  5534. * tag : G
  5535. * mode : OPEN
  5536. *
  5537. * @param array $param
  5538. * @return boolean
  5539. */
  5540. protected function _tag_open_G($param)
  5541. {
  5542. if (!$this->_isInDraw) throw new HTML2PDF_exception(8, 'G');
  5543. $this->pdf->doTransform(isset($param['transform']) ? $this->_prepareTransform($param['transform']) : null);
  5544. $this->parsingCss->save();
  5545. $styles = $this->parsingCss->getSvgStyle('path', $param);
  5546. $style = $this->pdf->svgSetStyle($styles);
  5547. }
  5548. /**
  5549. * tag : G
  5550. * mode : CLOSE
  5551. *
  5552. * @param array $param
  5553. * @return boolean
  5554. */
  5555. protected function _tag_close_G($param)
  5556. {
  5557. $this->pdf->undoTransform();
  5558. $this->parsingCss->load();
  5559. }
  5560. /**
  5561. * tag : DT
  5562. * mode : OPEN
  5563. *
  5564. * @param array $param
  5565. * @return boolean
  5566. */
  5567. protected function _tag_open_DT($param)
  5568. {
  5569. return $this->_tag_open_B($param, 'dd');
  5570. }
  5571. /**
  5572. * tag : DT
  5573. * mode : CLOSE
  5574. *
  5575. * @param array $param
  5576. * @return boolean
  5577. */
  5578. protected function _tag_close_DT($param)
  5579. {
  5580. return $this->_tag_close_B($param);
  5581. }
  5582. /**
  5583. * tag : DD
  5584. * mode : OPEN
  5585. *
  5586. * @param array $param
  5587. * @return boolean
  5588. */
  5589. protected function _tag_open_DD($param)
  5590. {
  5591. return $this->_tag_open_SPAN($param, 'dd');
  5592. }
  5593. /**
  5594. * tag : DD
  5595. * mode : CLOSE
  5596. *
  5597. * @param array $param
  5598. * @return boolean
  5599. */
  5600. protected function _tag_close_DD($param)
  5601. {
  5602. return $this->_tag_close_SPAN($param);
  5603. }
  5604. /**
  5605. * new page for the automatic Index, does not use thie method. Only HTML2PDF_myPdf could use it !!!!
  5606. *
  5607. * @param &int $page
  5608. * @return integer $oldPage
  5609. */
  5610. public function _INDEX_NewPage(&$page)
  5611. {
  5612. if ($page) {
  5613. $oldPage = $this->pdf->getPage();
  5614. $this->pdf->setPage($page);
  5615. $this->pdf->setXY($this->_margeLeft, $this->_margeTop);
  5616. $this->_maxH = 0;
  5617. $page++;
  5618. return $oldPage;
  5619. } else {
  5620. $this->_setNewPage();
  5621. return null;
  5622. }
  5623. }
  5624. }
  5625. }