PageRenderTime 47ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 1ms

/include/html2pdf_v4.03/_class/parsingCss.class.php

https://bitbucket.org/sleininger/stock_online
PHP | 1812 lines | 1204 code | 232 blank | 376 comment | 293 complexity | e61cea4c670a0d925f11861a9deaf02d MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * HTML2PDF Librairy - parsingCss 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. class HTML2PDF_parsingCss
  12. {
  13. /**
  14. * reference to the pdf object
  15. * @var TCPDF
  16. */
  17. protected $_pdf = null;
  18. protected $_htmlColor = array(); // list of the HTML colors
  19. protected $_onlyLeft = false; // flag if we are in a sub html => only "text-align:left" is used
  20. protected $_defaultFont = null; // default font to use if the asked font does not exist
  21. public $value = array(); // current values
  22. public $css = array(); // css values
  23. public $cssKeys = array(); // css key, for the execution order
  24. public $table = array(); // level history
  25. /**
  26. * Constructor
  27. *
  28. * @param &HTML2PDF_myPdf reference to the PDF $object
  29. * @access public
  30. */
  31. public function __construct(&$pdf)
  32. {
  33. $this->_init();
  34. $this->setPdfParent($pdf);
  35. }
  36. /**
  37. * Set the HTML2PDF parent object
  38. *
  39. * @param &HTML2PDF reference to the HTML2PDF parent $object
  40. * @access public
  41. */
  42. public function setPdfParent(&$pdf)
  43. {
  44. $this->_pdf = &$pdf;
  45. }
  46. /**
  47. * Inform that we want only "test-align:left" because we are in a sub HTML
  48. *
  49. * @access public
  50. */
  51. public function setOnlyLeft()
  52. {
  53. $this->value['text-align'] = 'left';
  54. $this->_onlyLeft = true;
  55. }
  56. /**
  57. * Get the vales of the parent, if exist
  58. *
  59. * @return array CSS values
  60. * @access public
  61. */
  62. public function getOldValues()
  63. {
  64. return isset($this->table[count($this->table)-1]) ? $this->table[count($this->table)-1] : $this->value;
  65. }
  66. /**
  67. * define the Default Font to use, if the font does not exist, or if no font asked
  68. *
  69. * @param string default font-family. If null : Arial for no font asked, and error fot ont does not exist
  70. * @return string old default font-family
  71. * @access public
  72. */
  73. public function setDefaultFont($default = null)
  74. {
  75. $old = $this->_defaultFont;
  76. $this->_defaultFont = $default;
  77. if ($default) $this->value['font-family'] = $default;
  78. return $old;
  79. }
  80. /**
  81. * Init the object
  82. *
  83. * @access protected
  84. */
  85. protected function _init()
  86. {
  87. // get the Web Colors from TCPDF
  88. require(K_PATH_MAIN.'htmlcolors.php');
  89. $this->_htmlColor = $webcolor;
  90. // init the Style
  91. $this->table = array();
  92. $this->value = array();
  93. $this->initStyle();
  94. // Init the styles without legacy
  95. $this->resetStyle();
  96. }
  97. /**
  98. * Init the CSS Style
  99. *
  100. * @access public
  101. */
  102. public function initStyle()
  103. {
  104. $this->value['id_tag'] = 'body'; // tag name
  105. $this->value['id_name'] = null; // tag - attribute name
  106. $this->value['id_id'] = null; // tag - attribute id
  107. $this->value['id_class'] = null; // tag - attribute class
  108. $this->value['id_lst'] = array('*'); // tag - list of legacy
  109. $this->value['mini-size'] = 1.; // specific size report for sup, sub
  110. $this->value['mini-decal'] = 0; // specific position report for sup, sub
  111. $this->value['font-family'] = 'Arial';
  112. $this->value['font-bold'] = false;
  113. $this->value['font-italic'] = false;
  114. $this->value['font-underline'] = false;
  115. $this->value['font-overline'] = false;
  116. $this->value['font-linethrough'] = false;
  117. $this->value['text-transform'] = 'none';
  118. $this->value['font-size'] = $this->convertToMM('10pt');
  119. $this->value['text-indent'] = 0;
  120. $this->value['text-align'] = 'left';
  121. $this->value['vertical-align'] = 'middle';
  122. $this->value['line-height'] = 'normal';
  123. $this->value['position'] = null;
  124. $this->value['x'] = null;
  125. $this->value['y'] = null;
  126. $this->value['width'] = 0;
  127. $this->value['height'] = 0;
  128. $this->value['top'] = null;
  129. $this->value['right'] = null;
  130. $this->value['bottom'] = null;
  131. $this->value['left'] = null;
  132. $this->value['float'] = null;
  133. $this->value['display'] = null;
  134. $this->value['rotate'] = null;
  135. $this->value['overflow'] = 'visible';
  136. $this->value['color'] = array(0, 0, 0);
  137. $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
  138. $this->value['border'] = array();
  139. $this->value['padding'] = array();
  140. $this->value['margin'] = array();
  141. $this->value['margin-auto'] = false;
  142. $this->value['list-style-type'] = '';
  143. $this->value['list-style-image'] = '';
  144. $this->value['xc'] = null;
  145. $this->value['yc'] = null;
  146. }
  147. /**
  148. * Init the CSS Style without legacy
  149. *
  150. * @param string tag name
  151. * @access public
  152. */
  153. public function resetStyle($tagName = '')
  154. {
  155. // prepare somme values
  156. $border = $this->readBorder('solid 1px #000000');
  157. $units = array(
  158. '1px' => $this->convertToMM('1px'),
  159. '5px' => $this->convertToMM('5px'),
  160. );
  161. // prepare the Collapse attribute
  162. $collapse = isset($this->value['border']['collapse']) ? $this->value['border']['collapse'] : false;
  163. if (!in_array($tagName, array('tr', 'td', 'th', 'thead', 'tbody', 'tfoot'))) $collapse = false;
  164. // set the global css values
  165. $this->value['position'] = null;
  166. $this->value['x'] = null;
  167. $this->value['y'] = null;
  168. $this->value['width'] = 0;
  169. $this->value['height'] = 0;
  170. $this->value['top'] = null;
  171. $this->value['right'] = null;
  172. $this->value['bottom'] = null;
  173. $this->value['left'] = null;
  174. $this->value['float'] = null;
  175. $this->value['display'] = null;
  176. $this->value['rotate'] = null;
  177. $this->value['overflow'] = 'visible';
  178. $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
  179. $this->value['border'] = array(
  180. 't' => $this->readBorder('none'),
  181. 'r' => $this->readBorder('none'),
  182. 'b' => $this->readBorder('none'),
  183. 'l' => $this->readBorder('none'),
  184. 'radius' => array(
  185. 'tl' => array(0, 0),
  186. 'tr' => array(0, 0),
  187. 'br' => array(0, 0),
  188. 'bl' => array(0, 0)
  189. ),
  190. 'collapse' => $collapse,
  191. );
  192. // specific values for some tags
  193. if (!in_array($tagName, array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) {
  194. $this->value['margin'] = array('t'=>0,'r'=>0,'b'=>0,'l'=>0);
  195. }
  196. if (in_array($tagName, array('input', 'select', 'textarea'))) {
  197. $this->value['border']['t'] = null;
  198. $this->value['border']['r'] = null;
  199. $this->value['border']['b'] = null;
  200. $this->value['border']['l'] = null;
  201. }
  202. if ($tagName=='p') {
  203. $this->value['margin']['t'] = null;
  204. $this->value['margin']['b'] = null;
  205. }
  206. if ($tagName=='blockquote') {
  207. $this->value['margin']['t'] = 3;
  208. $this->value['margin']['r'] = 3;
  209. $this->value['margin']['b'] = 3;
  210. $this->value['margin']['l'] = 6;
  211. }
  212. $this->value['margin-auto'] = false;
  213. if (in_array($tagName, array('blockquote', 'div', 'fieldset'))) {
  214. $this->value['vertical-align'] = 'top';
  215. }
  216. if (in_array($tagName, array('fieldset', 'legend'))) {
  217. $this->value['border'] = array(
  218. 't' => $border,
  219. 'r' => $border,
  220. 'b' => $border,
  221. 'l' => $border,
  222. 'radius' => array(
  223. 'tl' => array($units['5px'], $units['5px']),
  224. 'tr' => array($units['5px'], $units['5px']),
  225. 'br' => array($units['5px'], $units['5px']),
  226. 'bl' => array($units['5px'], $units['5px'])
  227. ),
  228. 'collapse' => false,
  229. );
  230. }
  231. if (in_array($tagName, array('ul', 'li'))) {
  232. $this->value['list-style-type'] = '';
  233. $this->value['list-style-image'] = '';
  234. }
  235. if (!in_array($tagName, array('tr', 'td'))) {
  236. $this->value['padding'] = array(
  237. 't' => 0,
  238. 'r' => 0,
  239. 'b' => 0,
  240. 'l' => 0
  241. );
  242. } else {
  243. $this->value['padding'] = array(
  244. 't' => $units['1px'],
  245. 'r' => $units['1px'],
  246. 'b' => $units['1px'],
  247. 'l' => $units['1px']
  248. );
  249. }
  250. if ($tagName=='hr') {
  251. $this->value['border'] = array(
  252. 't' => $border,
  253. 'r' => $border,
  254. 'b' => $border,
  255. 'l' => $border,
  256. 'radius' => array(
  257. 'tl' => array(0, 0),
  258. 'tr' => array(0, 0),
  259. 'br' => array(0, 0),
  260. 'bl' => array(0, 0)
  261. ),
  262. 'collapse' => false,
  263. );
  264. $this->convertBackground('#FFFFFF', $this->value['background']);
  265. }
  266. $this->value['xc'] = null;
  267. $this->value['yc'] = null;
  268. }
  269. /**
  270. * Init the PDF Font
  271. *
  272. * @access public
  273. */
  274. public function fontSet()
  275. {
  276. $family = strtolower($this->value['font-family']);
  277. $b = ($this->value['font-bold'] ? 'B' : '');
  278. $i = ($this->value['font-italic'] ? 'I' : '');
  279. $u = ($this->value['font-underline'] ? 'U' : '');
  280. $d = ($this->value['font-linethrough'] ? 'D' : '');
  281. $o = ($this->value['font-overline'] ? 'O' : '');
  282. // font style
  283. $style = $b.$i;
  284. if ($this->_defaultFont) {
  285. if($family=='arial')
  286. $family='helvetica';
  287. elseif($family=='symbol' || $family=='zapfdingbats')
  288. $style='';
  289. $fontkey = $family.$style;
  290. if (!$this->_pdf->isLoadedFont($fontkey))
  291. $family = $this->_defaultFont;
  292. }
  293. if($family=='arial')
  294. $family='helvetica';
  295. elseif($family=='symbol' || $family=='zapfdingbats')
  296. $style='';
  297. // complete style
  298. $style.= $u.$d.$o;
  299. // size : mm => pt
  300. $size = $this->value['font-size'];
  301. $size = 72 * $size / 25.4;
  302. // apply the font
  303. $this->_pdf->SetFont($family, $style, $this->value['mini-size']*$size);
  304. $this->_pdf->setTextColorArray($this->value['color']);
  305. if ($this->value['background']['color'])
  306. $this->_pdf->setFillColorArray($this->value['background']['color']);
  307. else
  308. $this->_pdf->setFillColor(255);
  309. }
  310. /**
  311. * add a level in the CSS history
  312. *
  313. * @access public
  314. */
  315. public function save()
  316. {
  317. array_push($this->table, $this->value);
  318. }
  319. /**
  320. * remove a level in the CSS history
  321. *
  322. * @access public
  323. */
  324. public function load()
  325. {
  326. if (count($this->table)) {
  327. $this->value = array_pop($this->table);
  328. }
  329. }
  330. /**
  331. * restore the Y positiony (used after a span)
  332. *
  333. * @access public
  334. */
  335. public function restorePosition()
  336. {
  337. if ($this->value['y']==$this->_pdf->getY()) $this->_pdf->setY($this->value['yc'], false);
  338. }
  339. /**
  340. * set the New position for the current Tag
  341. *
  342. * @access public
  343. */
  344. public function setPosition()
  345. {
  346. // get the current position
  347. $currentX = $this->_pdf->getX();
  348. $currentY = $this->_pdf->getY();
  349. // save it
  350. $this->value['xc'] = $currentX;
  351. $this->value['yc'] = $currentY;
  352. if ($this->value['position']=='relative' || $this->value['position']=='absolute') {
  353. if ($this->value['right']!==null) {
  354. $x = $this->getLastWidth(true) - $this->value['right'] - $this->value['width'];
  355. if ($this->value['margin']['r']) $x-= $this->value['margin']['r'];
  356. } else {
  357. $x = $this->value['left'];
  358. if ($this->value['margin']['l']) $x+= $this->value['margin']['l'];
  359. }
  360. if ($this->value['bottom']!==null) {
  361. $y = $this->getLastHeight(true) - $this->value['bottom'] - $this->value['height'];
  362. if ($this->value['margin']['b']) $y-= $this->value['margin']['b'];
  363. } else {
  364. $y = $this->value['top'];
  365. if ($this->value['margin']['t']) $y+= $this->value['margin']['t'];
  366. }
  367. if ($this->value['position']=='relative') {
  368. $this->value['x'] = $currentX + $x;
  369. $this->value['y'] = $currentY + $y;
  370. } else {
  371. $this->value['x'] = $this->_getLastAbsoluteX()+$x;
  372. $this->value['y'] = $this->_getLastAbsoluteY()+$y;
  373. }
  374. } else {
  375. $this->value['x'] = $currentX;
  376. $this->value['y'] = $currentY;
  377. if ($this->value['margin']['l']) $this->value['x']+= $this->value['margin']['l'];
  378. if ($this->value['margin']['t']) $this->value['y']+= $this->value['margin']['t'];
  379. }
  380. // save the new position
  381. $this->_pdf->setXY($this->value['x'], $this->value['y']);
  382. }
  383. /**
  384. * Analise the CSS style to convert it into Form style
  385. *
  386. * @access public
  387. * @param array styles
  388. */
  389. public function getFormStyle()
  390. {
  391. $prop = array();
  392. $prop['alignment'] = $this->value['text-align'];
  393. if (isset($this->value['background']['color']) && is_array($this->value['background']['color'])) {
  394. $prop['fillColor'] = $this->value['background']['color'];
  395. }
  396. if (isset($this->value['border']['t']['color'])) {
  397. $prop['strokeColor'] = $this->value['border']['t']['color'];
  398. }
  399. if (isset($this->value['border']['t']['width'])) {
  400. $prop['lineWidth'] = $this->value['border']['t']['width'];
  401. }
  402. if (isset($this->value['border']['t']['type'])) {
  403. $prop['borderStyle'] = $this->value['border']['t']['type'];
  404. }
  405. if (!empty($this->value['color'])) {
  406. $prop['textColor'] = $this->value['color'];
  407. }
  408. if (!empty($this->value['font-size'])) {
  409. $prop['textSize'] = $this->value['font-size'];
  410. }
  411. return $prop;
  412. }
  413. /**
  414. * Analise the CSS style to convert it into SVG style
  415. *
  416. * @access public
  417. * @param string tag name
  418. * @param array styles
  419. */
  420. public function getSvgStyle($tagName, &$param)
  421. {
  422. // prepare
  423. $tagName = strtolower($tagName);
  424. $id = isset($param['id']) ? strtolower(trim($param['id'])) : null; if (!$id) $id = null;
  425. $name = isset($param['name']) ? strtolower(trim($param['name'])) : null; if (!$name) $name = null;
  426. // read the class attribute
  427. $class = array();
  428. $tmp = isset($param['class']) ? strtolower(trim($param['class'])) : '';
  429. $tmp = explode(' ', $tmp);
  430. foreach ($tmp as $k => $v) {
  431. $v = trim($v);
  432. if ($v) $class[] = $v;
  433. }
  434. // identify the tag, and the direct styles
  435. $this->value['id_tag'] = $tagName;
  436. $this->value['id_name'] = $name;
  437. $this->value['id_id'] = $id;
  438. $this->value['id_class'] = $class;
  439. $this->value['id_lst'] = array();
  440. $this->value['id_lst'][] = '*';
  441. $this->value['id_lst'][] = $tagName;
  442. if (!isset($this->value['svg'])) {
  443. $this->value['svg'] = array(
  444. 'stroke' => null,
  445. 'stroke-width' => $this->convertToMM('1pt'),
  446. 'fill' => null,
  447. 'fill-opacity' => null,
  448. );
  449. }
  450. if (count($class)) {
  451. foreach ($class as $v) {
  452. $this->value['id_lst'][] = '*.'.$v;
  453. $this->value['id_lst'][] = '.'.$v;
  454. $this->value['id_lst'][] = $tagName.'.'.$v;
  455. }
  456. }
  457. if ($id) {
  458. $this->value['id_lst'][] = '*#'.$id;
  459. $this->value['id_lst'][] = '#'.$id;
  460. $this->value['id_lst'][] = $tagName.'#'.$id;
  461. }
  462. // CSS style
  463. $styles = $this->_getFromCSS();
  464. // adding the style from the tag
  465. $styles = array_merge($styles, $param['style']);
  466. if (isset($styles['stroke'])) $this->value['svg']['stroke'] = $this->convertToColor($styles['stroke'], $res);
  467. if (isset($styles['stroke-width'])) $this->value['svg']['stroke-width'] = $this->convertToMM($styles['stroke-width']);
  468. if (isset($styles['fill'])) $this->value['svg']['fill'] = $this->convertToColor($styles['fill'], $res);
  469. if (isset($styles['fill-opacity'])) $this->value['svg']['fill-opacity'] = 1.*$styles['fill-opacity'];
  470. return $this->value['svg'];
  471. }
  472. /**
  473. * analyse the css properties from the HTML parsing
  474. *
  475. * @access public
  476. * @param string $tagName
  477. * @param array $param
  478. * @param array $legacy
  479. */
  480. public function analyse($tagName, &$param, $legacy = null)
  481. {
  482. // prepare the informations
  483. $tagName = strtolower($tagName);
  484. $id = isset($param['id']) ? strtolower(trim($param['id'])) : null; if (!$id) $id = null;
  485. $name = isset($param['name']) ? strtolower(trim($param['name'])) : null; if (!$name) $name = null;
  486. // get the class names to use
  487. $class = array();
  488. $tmp = isset($param['class']) ? strtolower(trim($param['class'])) : '';
  489. $tmp = explode(' ', $tmp);
  490. foreach ($tmp as $k => $v) {
  491. $v = trim($v);
  492. if ($v) $class[] = $v;
  493. }
  494. // prepare the values, and the list of css tags to identify
  495. $this->value['id_tag'] = $tagName;
  496. $this->value['id_name'] = $name;
  497. $this->value['id_id'] = $id;
  498. $this->value['id_class'] = $class;
  499. $this->value['id_lst'] = array();
  500. $this->value['id_lst'][] = '*';
  501. $this->value['id_lst'][] = $tagName;
  502. if (count($class)) {
  503. foreach ($class as $v) {
  504. $this->value['id_lst'][] = '*.'.$v;
  505. $this->value['id_lst'][] = '.'.$v;
  506. $this->value['id_lst'][] = $tagName.'.'.$v;
  507. }
  508. }
  509. if ($id) {
  510. $this->value['id_lst'][] = '*#'.$id;
  511. $this->value['id_lst'][] = '#'.$id;
  512. $this->value['id_lst'][] = $tagName.'#'.$id;
  513. }
  514. // get the css styles from class
  515. $styles = $this->_getFromCSS();
  516. // merge with the css styles from tag
  517. $styles = array_merge($styles, $param['style']);
  518. if (isset($param['allwidth']) && !isset($styles['width'])) $styles['width'] = '100%';
  519. // reset some styles, depending on the tag name
  520. $this->resetStyle($tagName);
  521. // add the legacy values
  522. if ($legacy) {
  523. foreach ($legacy as $legacyName => $legacyValue) {
  524. if (is_array($legacyValue)) {
  525. foreach($legacyValue as $legacy2Name => $legacy2Value)
  526. $this->value[$legacyName][$legacy2Name] = $legacy2Value;
  527. } else {
  528. $this->value[$legacyName] = $legacyValue;
  529. }
  530. }
  531. }
  532. // some flags
  533. $correctWidth = false;
  534. $noWidth = true;
  535. // read all the css styles
  536. foreach ($styles as $nom => $val) {
  537. switch($nom)
  538. {
  539. case 'font-family':
  540. $val = explode(',', $val);
  541. $val = trim($val[0]);
  542. if ($val) $this->value['font-family'] = $val;
  543. break;
  544. case 'font-weight':
  545. $this->value['font-bold'] = ($val=='bold');
  546. break;
  547. case 'font-style':
  548. $this->value['font-italic'] = ($val=='italic');
  549. break;
  550. case 'text-decoration':
  551. $val = explode(' ', $val);
  552. $this->value['font-underline'] = (in_array('underline', $val));
  553. $this->value['font-overline'] = (in_array('overline', $val));
  554. $this->value['font-linethrough'] = (in_array('line-through', $val));
  555. break;
  556. case 'text-indent':
  557. $this->value['text-indent'] = $this->convertToMM($val);
  558. break;
  559. case 'text-transform':
  560. if (!in_array($val, array('none', 'capitalize', 'uppercase', 'lowercase'))) $val = 'none';
  561. $this->value['text-transform'] = $val;
  562. break;
  563. case 'font-size':
  564. $val = $this->convertToMM($val, $this->value['font-size']);
  565. if ($val) $this->value['font-size'] = $val;
  566. break;
  567. case 'color':
  568. $res = null;
  569. $this->value['color'] = $this->convertToColor($val, $res);
  570. if ($tagName=='hr') {
  571. $this->value['border']['l']['color'] = $this->value['color'];
  572. $this->value['border']['t']['color'] = $this->value['color'];
  573. $this->value['border']['r']['color'] = $this->value['color'];
  574. $this->value['border']['b']['color'] = $this->value['color'];
  575. }
  576. break;
  577. case 'text-align':
  578. $val = strtolower($val);
  579. if (!in_array($val, array('left', 'right', 'center', 'justify', 'li_right'))) $val = 'left';
  580. $this->value['text-align'] = $val;
  581. break;
  582. case 'vertical-align':
  583. $this->value['vertical-align'] = $val;
  584. break;
  585. case 'width':
  586. $this->value['width'] = $this->convertToMM($val, $this->getLastWidth());
  587. if ($this->value['width'] && substr($val, -1)=='%') $correctWidth=true;
  588. $noWidth = false;
  589. break;
  590. case 'height':
  591. $this->value['height'] = $this->convertToMM($val, $this->getLastHeight());
  592. break;
  593. case 'line-height':
  594. if (preg_match('/^[0-9\.]+$/isU', $val)) $val = floor($val*100).'%';
  595. $this->value['line-height'] = $val;
  596. break;
  597. case 'rotate':
  598. if (!in_array($val, array(0, -90, 90, 180, 270, -180, -270))) $val = null;
  599. if ($val<0) $val+= 360;
  600. $this->value['rotate'] = $val;
  601. break;
  602. case 'overflow':
  603. if (!in_array($val, array('visible', 'hidden'))) $val = 'visible';
  604. $this->value['overflow'] = $val;
  605. break;
  606. case 'padding':
  607. $val = explode(' ', $val);
  608. foreach ($val as $k => $v) {
  609. $v = trim($v);
  610. if ($v!='') {
  611. $val[$k] = $v;
  612. } else {
  613. unset($val[$k]);
  614. }
  615. }
  616. $val = array_values($val);
  617. $this->_duplicateBorder($val);
  618. $this->value['padding']['t'] = $this->convertToMM($val[0], 0);
  619. $this->value['padding']['r'] = $this->convertToMM($val[1], 0);
  620. $this->value['padding']['b'] = $this->convertToMM($val[2], 0);
  621. $this->value['padding']['l'] = $this->convertToMM($val[3], 0);
  622. break;
  623. case 'padding-top':
  624. $this->value['padding']['t'] = $this->convertToMM($val, 0);
  625. break;
  626. case 'padding-right':
  627. $this->value['padding']['r'] = $this->convertToMM($val, 0);
  628. break;
  629. case 'padding-bottom':
  630. $this->value['padding']['b'] = $this->convertToMM($val, 0);
  631. break;
  632. case 'padding-left':
  633. $this->value['padding']['l'] = $this->convertToMM($val, 0);
  634. break;
  635. case 'margin':
  636. if ($val=='auto') {
  637. $this->value['margin-auto'] = true;
  638. break;
  639. }
  640. $val = explode(' ', $val);
  641. foreach ($val as $k => $v) {
  642. $v = trim($v);
  643. if ($v!='') {
  644. $val[$k] = $v;
  645. } else {
  646. unset($val[$k]);
  647. }
  648. }
  649. $val = array_values($val);
  650. $this->_duplicateBorder($val);
  651. $this->value['margin']['t'] = $this->convertToMM($val[0], 0);
  652. $this->value['margin']['r'] = $this->convertToMM($val[1], 0);
  653. $this->value['margin']['b'] = $this->convertToMM($val[2], 0);
  654. $this->value['margin']['l'] = $this->convertToMM($val[3], 0);
  655. break;
  656. case 'margin-top':
  657. $this->value['margin']['t'] = $this->convertToMM($val, 0);
  658. break;
  659. case 'margin-right':
  660. $this->value['margin']['r'] = $this->convertToMM($val, 0);
  661. break;
  662. case 'margin-bottom':
  663. $this->value['margin']['b'] = $this->convertToMM($val, 0);
  664. break;
  665. case 'margin-left':
  666. $this->value['margin']['l'] = $this->convertToMM($val, 0);
  667. break;
  668. case 'border':
  669. $val = $this->readBorder($val);
  670. $this->value['border']['t'] = $val;
  671. $this->value['border']['r'] = $val;
  672. $this->value['border']['b'] = $val;
  673. $this->value['border']['l'] = $val;
  674. break;
  675. case 'border-style':
  676. $val = explode(' ', $val);
  677. foreach ($val as $valK => $valV) {
  678. if (!in_array($valV, array('solid', 'dotted', 'dashed'))) {
  679. $val[$valK] = null;
  680. }
  681. }
  682. $this->_duplicateBorder($val);
  683. if ($val[0]) $this->value['border']['t']['type'] = $val[0];
  684. if ($val[1]) $this->value['border']['r']['type'] = $val[1];
  685. if ($val[2]) $this->value['border']['b']['type'] = $val[2];
  686. if ($val[3]) $this->value['border']['l']['type'] = $val[3];
  687. break;
  688. case 'border-top-style':
  689. if (in_array($val, array('solid', 'dotted', 'dashed'))) {
  690. $this->value['border']['t']['type'] = $val;
  691. }
  692. break;
  693. case 'border-right-style':
  694. if (in_array($val, array('solid', 'dotted', 'dashed'))) {
  695. $this->value['border']['r']['type'] = $val;
  696. }
  697. break;
  698. case 'border-bottom-style':
  699. if (in_array($val, array('solid', 'dotted', 'dashed'))) {
  700. $this->value['border']['b']['type'] = $val;
  701. }
  702. break;
  703. case 'border-left-style':
  704. if (in_array($val, array('solid', 'dotted', 'dashed')))
  705. $this->value['border']['l']['type'] = $val;
  706. break;
  707. case 'border-color':
  708. $res = false;
  709. $val = preg_replace('/,[\s]+/', ',', $val);
  710. $val = explode(' ', $val);
  711. foreach ($val as $valK => $valV) {
  712. $val[$valK] = $this->convertToColor($valV, $res);
  713. if (!$res) {
  714. $val[$valK] = null;
  715. }
  716. }
  717. $this->_duplicateBorder($val);
  718. if (is_array($val[0])) $this->value['border']['t']['color'] = $val[0];
  719. if (is_array($val[1])) $this->value['border']['r']['color'] = $val[1];
  720. if (is_array($val[2])) $this->value['border']['b']['color'] = $val[2];
  721. if (is_array($val[3])) $this->value['border']['l']['color'] = $val[3];
  722. break;
  723. case 'border-top-color':
  724. $res = false;
  725. $val = $this->convertToColor($val, $res);
  726. if ($res) $this->value['border']['t']['color'] = $val;
  727. break;
  728. case 'border-right-color':
  729. $res = false;
  730. $val = $this->convertToColor($val, $res);
  731. if ($res) $this->value['border']['r']['color'] = $val;
  732. break;
  733. case 'border-bottom-color':
  734. $res = false;
  735. $val = $this->convertToColor($val, $res);
  736. if ($res) $this->value['border']['b']['color'] = $val;
  737. break;
  738. case 'border-left-color':
  739. $res = false;
  740. $val = $this->convertToColor($val, $res);
  741. if ($res) $this->value['border']['l']['color'] = $val;
  742. break;
  743. case 'border-width':
  744. $val = explode(' ', $val);
  745. foreach ($val as $valK => $valV) {
  746. $val[$valK] = $this->convertToMM($valV, 0);
  747. }
  748. $this->_duplicateBorder($val);
  749. if ($val[0]) $this->value['border']['t']['width'] = $val[0];
  750. if ($val[1]) $this->value['border']['r']['width'] = $val[1];
  751. if ($val[2]) $this->value['border']['b']['width'] = $val[2];
  752. if ($val[3]) $this->value['border']['l']['width'] = $val[3];
  753. break;
  754. case 'border-top-width':
  755. $val = $this->convertToMM($val, 0);
  756. if ($val) $this->value['border']['t']['width'] = $val;
  757. break;
  758. case 'border-right-width':
  759. $val = $this->convertToMM($val, 0);
  760. if ($val) $this->value['border']['r']['width'] = $val;
  761. break;
  762. case 'border-bottom-width':
  763. $val = $this->convertToMM($val, 0);
  764. if ($val) $this->value['border']['b']['width'] = $val;
  765. break;
  766. case 'border-left-width':
  767. $val = $this->convertToMM($val, 0);
  768. if ($val) $this->value['border']['l']['width'] = $val;
  769. break;
  770. case 'border-collapse':
  771. if ($tagName=='table') $this->value['border']['collapse'] = ($val=='collapse');
  772. break;
  773. case 'border-radius':
  774. $val = explode('/', $val);
  775. if (count($val)>2) {
  776. break;
  777. }
  778. $valH = $this->convertToRadius(trim($val[0]));
  779. if (count($valH)<1 || count($valH)>4) {
  780. break;
  781. }
  782. if (!isset($valH[1])) $valH[1] = $valH[0];
  783. if (!isset($valH[2])) $valH = array($valH[0], $valH[0], $valH[1], $valH[1]);
  784. if (!isset($valH[3])) $valH[3] = $valH[1];
  785. if (isset($val[1])) {
  786. $valV = $this->convertToRadius(trim($val[1]));
  787. if (count($valV)<1 || count($valV)>4) {
  788. break;
  789. }
  790. if (!isset($valV[1])) $valV[1] = $valV[0];
  791. if (!isset($valV[2])) $valV = array($valV[0], $valV[0], $valV[1], $valV[1]);
  792. if (!isset($valV[3])) $valV[3] = $valV[1];
  793. } else {
  794. $valV = $valH;
  795. }
  796. $this->value['border']['radius'] = array(
  797. 'tl' => array($valH[0], $valV[0]),
  798. 'tr' => array($valH[1], $valV[1]),
  799. 'br' => array($valH[2], $valV[2]),
  800. 'bl' => array($valH[3], $valV[3])
  801. );
  802. break;
  803. case 'border-top-left-radius':
  804. $val = $this->convertToRadius($val);
  805. if (count($val)<1 || count($val)>2) {
  806. break;
  807. }
  808. $this->value['border']['radius']['tl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  809. break;
  810. case 'border-top-right-radius':
  811. $val = $this->convertToRadius($val);
  812. if (count($val)<1 || count($val)>2) {
  813. break;
  814. }
  815. $this->value['border']['radius']['tr'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  816. break;
  817. case 'border-bottom-right-radius':
  818. $val = $this->convertToRadius($val);
  819. if (count($val)<1 || count($val)>2) {
  820. break;
  821. }
  822. $this->value['border']['radius']['br'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  823. break;
  824. case 'border-bottom-left-radius':
  825. $val = $this->convertToRadius($val);
  826. if (count($val)<1 || count($val)>2) {
  827. break;
  828. }
  829. $this->value['border']['radius']['bl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  830. break;
  831. case 'border-top':
  832. $this->value['border']['t'] = $this->readBorder($val);
  833. break;
  834. case 'border-right':
  835. $this->value['border']['r'] = $this->readBorder($val);
  836. break;
  837. case 'border-bottom':
  838. $this->value['border']['b'] = $this->readBorder($val);
  839. break;
  840. case 'border-left':
  841. $this->value['border']['l'] = $this->readBorder($val);
  842. break;
  843. case 'background-color':
  844. $this->value['background']['color'] = $this->convertBackgroundColor($val);
  845. break;
  846. case 'background-image':
  847. $this->value['background']['image'] = $this->convertBackgroundImage($val);
  848. break;
  849. case 'background-position':
  850. $res = null;
  851. $this->value['background']['position'] = $this->convertBackgroundPosition($val, $res);
  852. break;
  853. case 'background-repeat':
  854. $this->value['background']['repeat'] = $this->convertBackgroundRepeat($val);
  855. break;
  856. case 'background':
  857. $this->convertBackground($val, $this->value['background']);
  858. break;
  859. case 'position':
  860. if ($val=='absolute') $this->value['position'] = 'absolute';
  861. else if ($val=='relative') $this->value['position'] = 'relative';
  862. else $this->value['position'] = null;
  863. break;
  864. case 'float':
  865. if ($val=='left') $this->value['float'] = 'left';
  866. else if ($val=='right') $this->value['float'] = 'right';
  867. else $this->value['float'] = null;
  868. break;
  869. case 'display':
  870. if ($val=='inline') $this->value['display'] = 'inline';
  871. else if ($val=='block') $this->value['display'] = 'block';
  872. else if ($val=='none') $this->value['display'] = 'none';
  873. else $this->value['display'] = null;
  874. break;
  875. case 'top':
  876. case 'bottom':
  877. case 'left':
  878. case 'right':
  879. $this->value[$nom] = $val;
  880. break;
  881. case 'list-style':
  882. case 'list-style-type':
  883. case 'list-style-image':
  884. if ($nom=='list-style') $nom = 'list-style-type';
  885. $this->value[$nom] = $val;
  886. break;
  887. default:
  888. break;
  889. }
  890. }
  891. $return = true;
  892. // only for P tag
  893. if ($this->value['margin']['t']===null) $this->value['margin']['t'] = $this->value['font-size'];
  894. if ($this->value['margin']['b']===null) $this->value['margin']['b'] = $this->value['font-size'];
  895. // force the text align to left, if asked by html2pdf
  896. if ($this->_onlyLeft) $this->value['text-align'] = 'left';
  897. // correction on the width (quick box)
  898. if ($noWidth && in_array($tagName, array('div', 'blockquote', 'fieldset')) && $this->value['position']!='absolute') {
  899. $this->value['width'] = $this->getLastWidth();
  900. $this->value['width']-= $this->value['margin']['l'] + $this->value['margin']['r'];
  901. } else {
  902. if ($correctWidth) {
  903. if (!in_array($tagName, array('table', 'div', 'blockquote', 'fieldset', 'hr'))) {
  904. $this->value['width']-= $this->value['padding']['l'] + $this->value['padding']['r'];
  905. $this->value['width']-= $this->value['border']['l']['width'] + $this->value['border']['r']['width'];
  906. }
  907. if (in_array($tagName, array('th', 'td'))) {
  908. $this->value['width']-= $this->convertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px');
  909. $return = false;
  910. }
  911. if ($this->value['width']<0) $this->value['width']=0;
  912. } else {
  913. if ($this->value['width']) {
  914. if ($this->value['border']['l']['width']) $this->value['width'] += $this->value['border']['l']['width'];
  915. if ($this->value['border']['r']['width']) $this->value['width'] += $this->value['border']['r']['width'];
  916. if ($this->value['padding']['l']) $this->value['width'] += $this->value['padding']['l'];
  917. if ($this->value['padding']['r']) $this->value['width'] += $this->value['padding']['r'];
  918. }
  919. }
  920. }
  921. if ($this->value['height']) {
  922. if ($this->value['border']['b']['width']) $this->value['height'] += $this->value['border']['b']['width'];
  923. if ($this->value['border']['t']['width']) $this->value['height'] += $this->value['border']['t']['width'];
  924. if ($this->value['padding']['b']) $this->value['height'] += $this->value['padding']['b'];
  925. if ($this->value['padding']['t']) $this->value['height'] += $this->value['padding']['t'];
  926. }
  927. if ($this->value['top']!=null) $this->value['top'] = $this->convertToMM($this->value['top'], $this->getLastHeight(true));
  928. if ($this->value['bottom']!=null) $this->value['bottom'] = $this->convertToMM($this->value['bottom'], $this->getLastHeight(true));
  929. if ($this->value['left']!=null) $this->value['left'] = $this->convertToMM($this->value['left'], $this->getLastWidth(true));
  930. if ($this->value['right']!=null) $this->value['right'] = $this->convertToMM($this->value['right'], $this->getLastWidth(true));
  931. if ($this->value['top'] && $this->value['bottom'] && $this->value['height']) $this->value['bottom'] = null;
  932. if ($this->value['left'] && $this->value['right'] && $this->value['width']) $this->value['right'] = null;
  933. return $return;
  934. }
  935. /**
  936. * get the height of the current line
  937. *
  938. * @access public
  939. * @return float $height in mm
  940. */
  941. public function getLineHeight()
  942. {
  943. $val = $this->value['line-height'];
  944. if ($val=='normal') $val = '108%';
  945. return $this->convertToMM($val, $this->value['font-size']);
  946. }
  947. /**
  948. * get the width of the parent
  949. *
  950. * @access public
  951. * @param boolean $mode true => adding padding and border
  952. * @return float $width in mm
  953. */
  954. public function getLastWidth($mode = false)
  955. {
  956. for ($k=count($this->table)-1; $k>=0; $k--) {
  957. if ($this->table[$k]['width']) {
  958. $w = $this->table[$k]['width'];
  959. if ($mode) {
  960. $w+= $this->table[$k]['border']['l']['width'] + $this->table[$k]['padding']['l'] + 0.02;
  961. $w+= $this->table[$k]['border']['r']['width'] + $this->table[$k]['padding']['r'] + 0.02;
  962. }
  963. return $w;
  964. }
  965. }
  966. return $this->_pdf->getW() - $this->_pdf->getlMargin() - $this->_pdf->getrMargin();
  967. }
  968. /**
  969. * get the height of the parent
  970. *
  971. * @access public
  972. * @param boolean $mode true => adding padding and border
  973. * @return float $height in mm
  974. */
  975. public function getLastHeight($mode = false)
  976. {
  977. for ($k=count($this->table)-1; $k>=0; $k--) {
  978. if ($this->table[$k]['height']) {
  979. $h = $this->table[$k]['height'];
  980. if ($mode) {
  981. $h+= $this->table[$k]['border']['t']['width'] + $this->table[$k]['padding']['t'] + 0.02;
  982. $h+= $this->table[$k]['border']['b']['width'] + $this->table[$k]['padding']['b'] + 0.02;
  983. }
  984. return $h;
  985. }
  986. }
  987. return $this->_pdf->getH() - $this->_pdf->gettMargin() - $this->_pdf->getbMargin();
  988. }
  989. /**
  990. * get the value of the float property
  991. *
  992. * @access public
  993. * @return $float left/right
  994. */
  995. public function getFloat()
  996. {
  997. if ($this->value['float']=='left') return 'left';
  998. if ($this->value['float']=='right') return 'right';
  999. return null;
  1000. }
  1001. /**
  1002. * get the last value for a specific key
  1003. *
  1004. * @access public
  1005. * @param string $key
  1006. * @return mixed
  1007. */
  1008. public function getLastValue($key)
  1009. {
  1010. $nb = count($this->table);
  1011. if ($nb>0) {
  1012. return $this->table[$nb-1][$key];
  1013. } else {
  1014. return null;
  1015. }
  1016. }
  1017. /**
  1018. * get the last absolute X
  1019. *
  1020. * @access protected
  1021. * @return float $x
  1022. */
  1023. protected function _getLastAbsoluteX()
  1024. {
  1025. for ($k=count($this->table)-1; $k>=0; $k--) {
  1026. if ($this->table[$k]['x'] && $this->table[$k]['position']) return $this->table[$k]['x'];
  1027. }
  1028. return $this->_pdf->getlMargin();
  1029. }
  1030. /**
  1031. * get the last absolute Y
  1032. *
  1033. * @access protected
  1034. * @return float $y
  1035. */
  1036. protected function _getLastAbsoluteY()
  1037. {
  1038. for ($k=count($this->table)-1; $k>=0; $k--) {
  1039. if ($this->table[$k]['y'] && $this->table[$k]['position']) return $this->table[$k]['y'];
  1040. }
  1041. return $this->_pdf->gettMargin();
  1042. }
  1043. /**
  1044. * get the CSS properties of the current tag
  1045. *
  1046. * @access protected
  1047. * @return array $styles
  1048. */
  1049. protected function _getFromCSS()
  1050. {
  1051. // styles to apply
  1052. $styles = array();
  1053. // list of the selectors to get in the CSS files
  1054. $getit = array();
  1055. // get the list of the selectors of each tags
  1056. $lst = array();
  1057. $lst[] = $this->value['id_lst'];
  1058. for ($i=count($this->table)-1; $i>=0; $i--) {
  1059. $lst[] = $this->table[$i]['id_lst'];
  1060. }
  1061. // foreach selectors in the CSS files, verify if it match with the list of selectors
  1062. foreach ($this->cssKeys as $key => $num) {
  1063. if ($this->_getReccursiveStyle($key, $lst)) {
  1064. $getit[$key] = $num;
  1065. }
  1066. }
  1067. // if we have selectors
  1068. if (count($getit)) {
  1069. // get them, but in the definition order, because of priority
  1070. asort($getit);
  1071. foreach ($getit as $key => $val) $styles = array_merge($styles, $this->css[$key]);
  1072. }
  1073. return $styles;
  1074. }
  1075. /**
  1076. * identify if the selector $key match with the list of tag selectors
  1077. *
  1078. * @access protected
  1079. * @param string $key CSS selector to analyse
  1080. * @param array $lst list of the selectors of each tags
  1081. * @param string $next next step of parsing the selector
  1082. * @return boolean
  1083. */
  1084. protected function _getReccursiveStyle($key, $lst, $next = null)
  1085. {
  1086. // if next step
  1087. if ($next!==null) {
  1088. // we remove this step
  1089. if ($next) $key = trim(substr($key, 0, -strlen($next)));
  1090. array_shift($lst);
  1091. // if no more step to identify => return false
  1092. if (!count($lst)) {
  1093. return false;
  1094. }
  1095. }
  1096. // for each selector of the current step
  1097. foreach ($lst[0] as $name) {
  1098. // if selector = key => ok
  1099. if ($key==$name) {
  1100. return true;
  1101. }
  1102. // if the end of the key = the selector and the next step is ok => ok
  1103. if (substr($key, -strlen(' '.$name))==' '.$name && $this->_getReccursiveStyle($key, $lst, $name)) {
  1104. return true;
  1105. }
  1106. }
  1107. // if we are not in the first step, we analyse the sub steps (the pareng tag of the current tag)
  1108. if ($next!==null && $this->_getReccursiveStyle($key, $lst, '')) {
  1109. return true;
  1110. }
  1111. // no corresponding found
  1112. return false;
  1113. }
  1114. /**
  1115. * Analyse a border
  1116. *
  1117. * @access public
  1118. * @param string $css css border properties
  1119. * @return array border properties
  1120. */
  1121. public function readBorder($css)
  1122. {
  1123. // border none
  1124. $none = array('type' => 'none', 'width' => 0, 'color' => array(0, 0, 0));
  1125. // default value
  1126. $type = 'solid';
  1127. $width = $this->convertToMM('1pt');
  1128. $color = array(0, 0, 0);
  1129. // clean up the values
  1130. $css = explode(' ', $css);
  1131. foreach ($css as $k => $v) {
  1132. $v = trim($v);
  1133. if ($v) $css[$k] = $v;
  1134. else unset($css[$k]);
  1135. }
  1136. $css = array_values($css);
  1137. // read the values
  1138. $res = null;
  1139. foreach ($css as $value) {
  1140. // if no border => return none
  1141. if ($value=='none' || $value=='hidden') {
  1142. return $none;
  1143. }
  1144. // try to convert the value as a distance
  1145. $tmp = $this->convertToMM($value);
  1146. // if the convert is ok => it is a width
  1147. if ($tmp!==null) {
  1148. $width = $tmp;
  1149. // else, it could be the type
  1150. } else if (in_array($value, array('solid', 'dotted', 'dashed', 'double'))) {
  1151. $type = $value;
  1152. // else, it could be the color
  1153. } else {
  1154. $tmp = $this->convertToColor($value, $res);
  1155. if ($res) $color = $tmp;
  1156. }
  1157. }
  1158. // if no witdh => return none
  1159. if (!$width) return $none;
  1160. // return the border properties
  1161. return array('type' => $type, 'width' => $width, 'color' => $color);
  1162. }
  1163. /**
  1164. * duplicate the borders if needed
  1165. *
  1166. * @access protected
  1167. * @param &array $val
  1168. */
  1169. protected function _duplicateBorder(&$val)
  1170. {
  1171. // 1 value => L => RTB
  1172. if (count($val)==1) {
  1173. $val[1] = $val[0];
  1174. $val[2] = $val[0];
  1175. $val[3] = $val[0];
  1176. // 2 values => L => R & T => B
  1177. } else if (count($val)==2) {
  1178. $val[2] = $val[0];
  1179. $val[3] = $val[1];
  1180. // 3 values => T => B
  1181. } else if (count($val)==3) {
  1182. $val[3] = $val[1];
  1183. }
  1184. }
  1185. /**
  1186. * Analyse a background
  1187. *
  1188. * @access public
  1189. * @param string $css css background properties
  1190. * @par…

Large files files are truncated, but you can click here to view the full file