PageRenderTime 64ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/common/libraries/plugin/html2pdf/styleHTML.class.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 1873 lines | 1511 code | 196 blank | 166 comment | 318 complexity | f8879e82f341749efdac8655c3db1840 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT, GPL-2.0
  1. <?php
  2. /**
  3. * Logiciel : HTML2PDF - classe styleHTML
  4. *
  5. * Convertisseur HTML => PDF, utilise TCPDF
  6. * Distribu� sous la licence LGPL.
  7. *
  8. * @author Laurent MINGUET <webmaster@html2pdf.fr>
  9. * @version 4.00
  10. */
  11. class styleHTML
  12. {
  13. protected $pdf = null; // r�f�rence au PDF parent
  14. protected $htmlColor = array(); // liste des couleurs HTML
  15. protected $onlyLeft = false; // indique si on est dans un sous HTML et qu'on bloque � gauche
  16. protected $defaultFont = null; // fonte par d�faut si la fonte demand�e n'existe pas
  17. public $value = array(); // valeurs actuelles
  18. public $css = array(); // tableau des CSS
  19. public $css_keys = array(); // tableau des clefs CSS, pour l'ordre d'execution
  20. public $table = array(); // tableau d'empilement pour historisation des niveaux
  21. /**
  22. * Constructeur
  23. *
  24. * @param &pdf r�f�rence � l'objet HTML2PDF parent
  25. * @return null
  26. */
  27. public function __construct(&$pdf)
  28. {
  29. $this->init(); // initialisation
  30. $this->setPdfParent($pdf);
  31. }
  32. public function setPdfParent(&$pdf)
  33. {
  34. $this->pdf = &$pdf;
  35. }
  36. public function setOnlyLeft()
  37. {
  38. $this->value['text-align'] = 'left';
  39. $this->onlyLeft = true;
  40. }
  41. public function getOldValues()
  42. {
  43. return isset($this->table[count($this->table) - 1]) ? $this->table[count($this->table) - 1] : $this->value;
  44. }
  45. /**
  46. * d�finit la fonte par d�faut si aucun fonte n'est sp�cifi�e, ou si la fonte demand�e n'existe pas
  47. *
  48. * @param string nom de la fonte par defaut. si null : Arial pour fonte non sp�cifi�e, et erreur pour fonte non existante
  49. * @return string nom de l'ancienne fonte par defaut
  50. */
  51. public function setDefaultFont($default = null)
  52. {
  53. $old = $this->defaultFont;
  54. $this->defaultFont = $default;
  55. if ($default)
  56. $this->value['font-family'] = $default;
  57. return $old;
  58. }
  59. /**
  60. * Initialisation du style
  61. *
  62. * @return null
  63. */
  64. protected function init()
  65. {
  66. $color = array();
  67. $color['AliceBlue'] = '#F0F8FF';
  68. $color['AntiqueWhite'] = '#FAEBD7';
  69. $color['Aqua'] = '#00FFFF';
  70. $color['Aquamarine'] = '#7FFFD4';
  71. $color['Azure'] = '#F0FFFF';
  72. $color['Beige'] = '#F5F5DC';
  73. $color['Bisque'] = '#FFE4C4';
  74. $color['Black'] = '#000000';
  75. $color['BlanchedAlmond'] = '#FFEBCD';
  76. $color['Blue'] = '#0000FF';
  77. $color['BlueViolet'] = '#8A2BE2';
  78. $color['Brown'] = '#A52A2A';
  79. $color['BurlyWood'] = '#DEB887';
  80. $color['CadetBlue'] = '#5F9EA0';
  81. $color['Chartreuse'] = '#7FFF00';
  82. $color['Chocolate'] = '#D2691E';
  83. $color['Coral'] = '#FF7F50';
  84. $color['CornflowerBlue'] = '#6495ED';
  85. $color['Cornsilk'] = '#FFF8DC';
  86. $color['Crimson'] = '#DC143C';
  87. $color['Cyan'] = '#00FFFF';
  88. $color['DarkBlue'] = '#00008B';
  89. $color['DarkCyan'] = '#008B8B';
  90. $color['DarkGoldenRod'] = '#B8860B';
  91. $color['DarkGray'] = '#A9A9A9';
  92. $color['DarkGrey'] = '#A9A9A9';
  93. $color['DarkGreen'] = '#006400';
  94. $color['DarkKhaki'] = '#BDB76B';
  95. $color['DarkMagenta'] = '#8B008B';
  96. $color['DarkOliveGreen'] = '#556B2F';
  97. $color['Darkorange'] = '#FF8C00';
  98. $color['DarkOrchid'] = '#9932CC';
  99. $color['DarkRed'] = '#8B0000';
  100. $color['DarkSalmon'] = '#E9967A';
  101. $color['DarkSeaGreen'] = '#8FBC8F';
  102. $color['DarkSlateBlue'] = '#483D8B';
  103. $color['DarkSlateGray'] = '#2F4F4F';
  104. $color['DarkSlateGrey'] = '#2F4F4F';
  105. $color['DarkTurquoise'] = '#00CED1';
  106. $color['DarkViolet'] = '#9400D3';
  107. $color['DeepPink'] = '#FF1493';
  108. $color['DeepSkyBlue'] = '#00BFFF';
  109. $color['DimGray'] = '#696969';
  110. $color['DimGrey'] = '#696969';
  111. $color['DodgerBlue'] = '#1E90FF';
  112. $color['FireBrick'] = '#B22222';
  113. $color['FloralWhite'] = '#FFFAF0';
  114. $color['ForestGreen'] = '#228B22';
  115. $color['Fuchsia'] = '#FF00FF';
  116. $color['Gainsboro'] = '#DCDCDC';
  117. $color['GhostWhite'] = '#F8F8FF';
  118. $color['Gold'] = '#FFD700';
  119. $color['GoldenRod'] = '#DAA520';
  120. $color['Gray'] = '#808080';
  121. $color['Grey'] = '#808080';
  122. $color['Green'] = '#008000';
  123. $color['GreenYellow'] = '#ADFF2F';
  124. $color['HoneyDew'] = '#F0FFF0';
  125. $color['HotPink'] = '#FF69B4';
  126. $color['IndianRed'] = '#CD5C5C';
  127. $color['Indigo'] = '#4B0082';
  128. $color['Ivory'] = '#FFFFF0';
  129. $color['Khaki'] = '#F0E68C';
  130. $color['Lavender'] = '#E6E6FA';
  131. $color['LavenderBlush'] = '#FFF0F5';
  132. $color['LawnGreen'] = '#7CFC00';
  133. $color['LemonChiffon'] = '#FFFACD';
  134. $color['LightBlue'] = '#ADD8E6';
  135. $color['LightCoral'] = '#F08080';
  136. $color['LightCyan'] = '#E0FFFF';
  137. $color['LightGoldenRodYellow'] = '#FAFAD2';
  138. $color['LightGray'] = '#D3D3D3';
  139. $color['LightGrey'] = '#D3D3D3';
  140. $color['LightGreen'] = '#90EE90';
  141. $color['LightPink'] = '#FFB6C1';
  142. $color['LightSalmon'] = '#FFA07A';
  143. $color['LightSeaGreen'] = '#20B2AA';
  144. $color['LightSkyBlue'] = '#87CEFA';
  145. $color['LightSlateGray'] = '#778899';
  146. $color['LightSlateGrey'] = '#778899';
  147. $color['LightSteelBlue'] = '#B0C4DE';
  148. $color['LightYellow'] = '#FFFFE0';
  149. $color['Lime'] = '#00FF00';
  150. $color['LimeGreen'] = '#32CD32';
  151. $color['Linen'] = '#FAF0E6';
  152. $color['Magenta'] = '#FF00FF';
  153. $color['Maroon'] = '#800000';
  154. $color['MediumAquaMarine'] = '#66CDAA';
  155. $color['MediumBlue'] = '#0000CD';
  156. $color['MediumOrchid'] = '#BA55D3';
  157. $color['MediumPurple'] = '#9370D8';
  158. $color['MediumSeaGreen'] = '#3CB371';
  159. $color['MediumSlateBlue'] = '#7B68EE';
  160. $color['MediumSpringGreen'] = '#00FA9A';
  161. $color['MediumTurquoise'] = '#48D1CC';
  162. $color['MediumVioletRed'] = '#C71585';
  163. $color['MidnightBlue'] = '#191970';
  164. $color['MintCream'] = '#F5FFFA';
  165. $color['MistyRose'] = '#FFE4E1';
  166. $color['Moccasin'] = '#FFE4B5';
  167. $color['NavajoWhite'] = '#FFDEAD';
  168. $color['Navy'] = '#000080';
  169. $color['OldLace'] = '#FDF5E6';
  170. $color['Olive'] = '#808000';
  171. $color['OliveDrab'] = '#6B8E23';
  172. $color['Orange'] = '#FFA500';
  173. $color['OrangeRed'] = '#FF4500';
  174. $color['Orchid'] = '#DA70D6';
  175. $color['PaleGoldenRod'] = '#EEE8AA';
  176. $color['PaleGreen'] = '#98FB98';
  177. $color['PaleTurquoise'] = '#AFEEEE';
  178. $color['PaleVioletRed'] = '#D87093';
  179. $color['PapayaWhip'] = '#FFEFD5';
  180. $color['PeachPuff'] = '#FFDAB9';
  181. $color['Peru'] = '#CD853F';
  182. $color['Pink'] = '#FFC0CB';
  183. $color['Plum'] = '#DDA0DD';
  184. $color['PowderBlue'] = '#B0E0E6';
  185. $color['Purple'] = '#800080';
  186. $color['Red'] = '#FF0000';
  187. $color['RosyBrown'] = '#BC8F8F';
  188. $color['RoyalBlue'] = '#4169E1';
  189. $color['SaddleBrown'] = '#8B4513';
  190. $color['Salmon'] = '#FA8072';
  191. $color['SandyBrown'] = '#F4A460';
  192. $color['SeaGreen'] = '#2E8B57';
  193. $color['SeaShell'] = '#FFF5EE';
  194. $color['Sienna'] = '#A0522D';
  195. $color['Silver'] = '#C0C0C0';
  196. $color['SkyBlue'] = '#87CEEB';
  197. $color['SlateBlue'] = '#6A5ACD';
  198. $color['SlateGray'] = '#708090';
  199. $color['SlateGrey'] = '#708090';
  200. $color['Snow'] = '#FFFAFA';
  201. $color['SpringGreen'] = '#00FF7F';
  202. $color['SteelBlue'] = '#4682B4';
  203. $color['Tan'] = '#D2B48C';
  204. $color['Teal'] = '#008080';
  205. $color['Thistle'] = '#D8BFD8';
  206. $color['Tomato'] = '#FF6347';
  207. $color['Turquoise'] = '#40E0D0';
  208. $color['Violet'] = '#EE82EE';
  209. $color['Wheat'] = '#F5DEB3';
  210. $color['White'] = '#FFFFFF';
  211. $color['WhiteSmoke'] = '#F5F5F5';
  212. $color['Yellow'] = '#FFFF00';
  213. $color['YellowGreen'] = '#9ACD32';
  214. $this->htmlColor = array();
  215. foreach ($color as $key => $val)
  216. $this->htmlColor[strtolower($key)] = $val;
  217. unset($color);
  218. $this->table = array();
  219. $this->value = array();
  220. $this->initStyle();
  221. // initialisation des styles sans h�ritages
  222. $this->resetStyle();
  223. }
  224. public function initStyle()
  225. {
  226. $this->value['id_balise'] = 'body'; // balise
  227. $this->value['id_name'] = null; // name
  228. $this->value['id_id'] = null; // id
  229. $this->value['id_class'] = null; // class
  230. $this->value['id_lst'] = array('*'); // lst de dependance
  231. $this->value['mini-size'] = 1.; // rapport de taille sp�cifique aux sup, sub
  232. $this->value['mini-decal'] = 0; // rapport de position sp�cifique aux sup, sub
  233. $this->value['font-family'] = 'Arial';
  234. $this->value['font-bold'] = false;
  235. $this->value['font-italic'] = false;
  236. $this->value['font-underline'] = false;
  237. $this->value['font-overline'] = false;
  238. $this->value['font-linethrough'] = false;
  239. $this->value['text-transform'] = 'none';
  240. $this->value['font-size'] = $this->ConvertToMM('10pt');
  241. $this->value['text-indent'] = 0;
  242. $this->value['text-align'] = 'left';
  243. $this->value['vertical-align'] = 'middle';
  244. $this->value['line-height'] = 'normal';
  245. $this->value['position'] = null;
  246. $this->value['x'] = null;
  247. $this->value['y'] = null;
  248. $this->value['width'] = 0;
  249. $this->value['height'] = 0;
  250. $this->value['top'] = null;
  251. $this->value['right'] = null;
  252. $this->value['bottom'] = null;
  253. $this->value['left'] = null;
  254. $this->value['float'] = null;
  255. $this->value['display'] = null;
  256. $this->value['rotate'] = null;
  257. $this->value['overflow'] = 'visible';
  258. $this->value['color'] = array(0, 0, 0);
  259. $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
  260. $this->value['border'] = array();
  261. $this->value['padding'] = array();
  262. $this->value['margin'] = array();
  263. $this->value['margin-auto'] = false;
  264. $this->value['list-style-type'] = '';
  265. $this->value['list-style-image'] = '';
  266. $this->value['xc'] = null;
  267. $this->value['yc'] = null;
  268. }
  269. /**
  270. * Initialisation des styles sans h�ritages
  271. *
  272. * @param string balise HTML
  273. * @return null
  274. */
  275. public function resetStyle($balise = '')
  276. {
  277. $collapse = isset($this->value['border']['collapse']) ? $this->value['border']['collapse'] : false;
  278. if (! in_array($balise, array('tr', 'td', 'th', 'thead', 'tbody', 'tfoot')))
  279. $collapse = false;
  280. $this->value['position'] = null;
  281. $this->value['x'] = null;
  282. $this->value['y'] = null;
  283. $this->value['width'] = 0;
  284. $this->value['height'] = 0;
  285. $this->value['top'] = null;
  286. $this->value['right'] = null;
  287. $this->value['bottom'] = null;
  288. $this->value['left'] = null;
  289. $this->value['float'] = null;
  290. $this->value['display'] = null;
  291. $this->value['rotate'] = null;
  292. $this->value['overflow'] = 'visible';
  293. $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
  294. $this->value['border'] = array('t' => $this->readBorder('none'), 'r' => $this->readBorder('none'),
  295. 'b' => $this->readBorder('none'), 'l' => $this->readBorder('none'),
  296. 'radius' => array('tl' => array(0, 0), 'tr' => array(0, 0), 'br' => array(0, 0), 'bl' => array(0, 0)),
  297. 'collapse' => $collapse);
  298. if (! in_array($balise, array('h1', 'h2', 'h3', 'h4', 'h5', 'h6')))
  299. $this->value['margin'] = array('t' => 0, 'r' => 0, 'b' => 0, 'l' => 0);
  300. if ($balise == 'p')
  301. {
  302. $this->value['margin']['t'] = null;
  303. $this->value['margin']['b'] = null;
  304. }
  305. $this->value['margin-auto'] = false;
  306. if (in_array($balise, array('div')))
  307. $this->value['vertical-align'] = 'top';
  308. if (in_array($balise, array('ul', 'li')))
  309. {
  310. $this->value['list-style-type'] = '';
  311. $this->value['list-style-image'] = '';
  312. }
  313. if (! in_array($balise, array('tr', 'td')))
  314. {
  315. $this->value['padding'] = array('t' => 0, 'r' => 0, 'b' => 0, 'l' => 0);
  316. }
  317. else
  318. {
  319. $this->value['padding'] = array('t' => $this->ConvertToMM('1px'), 'r' => $this->ConvertToMM('1px'),
  320. 'b' => $this->ConvertToMM('1px'), 'l' => $this->ConvertToMM('1px'));
  321. }
  322. if ($balise == 'hr')
  323. {
  324. $this->value['border'] = array('t' => $this->readBorder('solid 1px #000000'),
  325. 'r' => $this->readBorder('solid 1px #000000'), 'b' => $this->readBorder('solid 1px #000000'),
  326. 'l' => $this->readBorder('solid 1px #000000'),
  327. 'radius' => array('tl' => array(0, 0), 'tr' => array(0, 0), 'br' => array(0, 0),
  328. 'bl' => array(0, 0)), 'collapse' => false);
  329. $this->ConvertBackground('#FFFFFF', $this->value['background']);
  330. }
  331. $this->value['xc'] = null;
  332. $this->value['yc'] = null;
  333. }
  334. /**
  335. * Initialisation de la font PDF
  336. *
  337. * @return null
  338. */
  339. public function FontSet()
  340. {
  341. $family = strtolower($this->value['font-family']);
  342. $b = ($this->value['font-bold'] ? 'B' : '');
  343. $i = ($this->value['font-italic'] ? 'I' : '');
  344. $u = ($this->value['font-underline'] ? 'U' : '');
  345. $d = ($this->value['font-linethrough'] ? 'D' : '');
  346. if ($this->defaultFont)
  347. {
  348. $style = $b . $i;
  349. if ($family == 'arial')
  350. $family = 'helvetica';
  351. elseif ($family == 'symbol' || $family == 'zapfdingbats')
  352. $style = '';
  353. $fontkey = $family . $style;
  354. if (! $this->pdf->isLoadedFont($fontkey))
  355. $family = $this->defaultFont;
  356. }
  357. if ($family == 'arial')
  358. $family = 'helvetica';
  359. elseif ($family == 'symbol' || $family == 'zapfdingbats')
  360. $style = '';
  361. // taille en mm, � ramener en pt
  362. $size = $this->value['font-size'];
  363. $size = 72 * $size / 25.4;
  364. $this->pdf->setOverline($this->value['font-overline']);
  365. // application de la fonte
  366. $this->pdf->SetFont($family, $b . $i . $u . $d, $this->value['mini-size'] * $size);
  367. $this->pdf->setTextColorArray($this->value['color']);
  368. if ($this->value['background']['color'])
  369. $this->pdf->setFillColorArray($this->value['background']['color']);
  370. else
  371. $this->pdf->setFillColor(255);
  372. }
  373. /**
  374. * Monter d'un niveau dans l'historisation
  375. *
  376. * @return null
  377. */
  378. public function save()
  379. {
  380. $this->table[count($this->table)] = $this->value;
  381. }
  382. /**
  383. * Descendre d'un niveau dans l'historisation
  384. *
  385. * @return null
  386. */
  387. public function load()
  388. {
  389. if (count($this->table))
  390. {
  391. $this->value = $this->table[count($this->table) - 1];
  392. unset($this->table[count($this->table) - 1]);
  393. }
  394. }
  395. public function restorePosition()
  396. {
  397. if ($this->value['y'] == $this->pdf->getY())
  398. $this->pdf->setY($this->value['yc'], false);
  399. }
  400. public function setPosition()
  401. {
  402. $current_x = $this->pdf->getX();
  403. $current_y = $this->pdf->getY();
  404. $this->value['xc'] = $current_x;
  405. $this->value['yc'] = $current_y;
  406. if ($this->value['position'] == 'relative' || $this->value['position'] == 'absolute')
  407. {
  408. if ($this->value['right'] !== null)
  409. {
  410. $x = $this->getLastWidth(true) - $this->value['right'] - $this->value['width'];
  411. if ($this->value['margin']['r'])
  412. $x -= $this->value['margin']['r'];
  413. }
  414. else
  415. {
  416. $x = $this->value['left'];
  417. if ($this->value['margin']['l'])
  418. $x += $this->value['margin']['l'];
  419. }
  420. if ($this->value['bottom'] !== null)
  421. {
  422. $y = $this->getLastHeight(true) - $this->value['bottom'] - $this->value['height'];
  423. if ($this->value['margin']['b'])
  424. $y -= $this->value['margin']['b'];
  425. }
  426. else
  427. {
  428. $y = $this->value['top'];
  429. if ($this->value['margin']['t'])
  430. $y += $this->value['margin']['t'];
  431. }
  432. if ($this->value['position'] == 'relative')
  433. {
  434. $this->value['x'] = $current_x + $x;
  435. $this->value['y'] = $current_y + $y;
  436. }
  437. else
  438. {
  439. $this->value['x'] = $this->getLastAbsoluteX() + $x;
  440. $this->value['y'] = $this->getLastAbsoluteY() + $y;
  441. }
  442. }
  443. else
  444. {
  445. $this->value['x'] = $current_x;
  446. $this->value['y'] = $current_y;
  447. if ($this->value['margin']['l'])
  448. $this->value['x'] += $this->value['margin']['l'];
  449. if ($this->value['margin']['t'])
  450. $this->value['y'] += $this->value['margin']['t'];
  451. }
  452. $this->pdf->setXY($this->value['x'], $this->value['y']);
  453. }
  454. /**
  455. * Analyse un tableau de style provenant du parseurHTML
  456. *
  457. * @param string nom de la balise
  458. * @param array tableau de style
  459. * @return null
  460. */
  461. public function getSvgStyle($balise, &$param)
  462. {
  463. // preparation
  464. $balise = strtolower($balise);
  465. $id = isset($param['id']) ? strtolower(trim($param['id'])) : null;
  466. if (! $id)
  467. $id = null;
  468. $name = isset($param['name']) ? strtolower(trim($param['name'])) : null;
  469. if (! $name)
  470. $name = null;
  471. // lecture de la propriete classe
  472. $class = array();
  473. $tmp = isset($param['class']) ? strtolower(trim($param['class'])) : '';
  474. $tmp = explode(' ', $tmp);
  475. foreach ($tmp as $k => $v)
  476. {
  477. $v = trim($v);
  478. if ($v)
  479. $class[] = $v;
  480. }
  481. // identification de la balise et des styles direct qui pourraient lui �tre appliqu�s
  482. $this->value['id_balise'] = $balise;
  483. $this->value['id_name'] = $name;
  484. $this->value['id_id'] = $id;
  485. $this->value['id_class'] = $class;
  486. $this->value['id_lst'] = array();
  487. $this->value['id_lst'][] = '*';
  488. $this->value['id_lst'][] = $balise;
  489. if (! isset($this->value['svg']))
  490. {
  491. $this->value['svg'] = array('stroke' => null, 'stroke-width' => $this->ConvertToMM('1pt'), 'fill' => null,
  492. 'fill-opacity' => null);
  493. }
  494. if (count($class))
  495. {
  496. foreach ($class as $v)
  497. {
  498. $this->value['id_lst'][] = '*.' . $v;
  499. $this->value['id_lst'][] = '.' . $v;
  500. $this->value['id_lst'][] = $balise . '.' . $v;
  501. }
  502. }
  503. if ($id)
  504. {
  505. $this->value['id_lst'][] = '*#' . $id;
  506. $this->value['id_lst'][] = '#' . $id;
  507. $this->value['id_lst'][] = $balise . '#' . $id;
  508. }
  509. // style CSS
  510. $styles = $this->getFromCSS();
  511. // on ajoute le style propre � la balise
  512. $styles = array_merge($styles, $param['style']);
  513. if (isset($styles['stroke']))
  514. $this->value['svg']['stroke'] = $this->ConvertToColor($styles['stroke'], $res);
  515. if (isset($styles['stroke-width']))
  516. $this->value['svg']['stroke-width'] = $this->ConvertToMM($styles['stroke-width']);
  517. if (isset($styles['fill']))
  518. $this->value['svg']['fill'] = $this->ConvertToColor($styles['fill'], $res);
  519. if (isset($styles['fill-opacity']))
  520. $this->value['svg']['fill-opacity'] = 1. * $styles['fill-opacity'];
  521. return $this->value['svg'];
  522. }
  523. /**
  524. * Analyse un tableau de style provenant du parseurHTML
  525. *
  526. * @param string nom de la balise
  527. * @param array tableau de style
  528. * @param array tableau initialisant des styles
  529. * @return null
  530. */
  531. public function analyse($balise, &$param, $heritage = null)
  532. {
  533. // preparation
  534. $balise = strtolower($balise);
  535. $id = isset($param['id']) ? strtolower(trim($param['id'])) : null;
  536. if (! $id)
  537. $id = null;
  538. $name = isset($param['name']) ? strtolower(trim($param['name'])) : null;
  539. if (! $name)
  540. $name = null;
  541. // lecture de la propriete classe
  542. $class = array();
  543. $tmp = isset($param['class']) ? strtolower(trim($param['class'])) : '';
  544. $tmp = explode(' ', $tmp);
  545. foreach ($tmp as $k => $v)
  546. {
  547. $v = trim($v);
  548. if ($v)
  549. $class[] = $v;
  550. }
  551. // identification de la balise et des styles direct qui pourraient lui �tre appliqu�s
  552. $this->value['id_balise'] = $balise;
  553. $this->value['id_name'] = $name;
  554. $this->value['id_id'] = $id;
  555. $this->value['id_class'] = $class;
  556. $this->value['id_lst'] = array();
  557. $this->value['id_lst'][] = '*';
  558. $this->value['id_lst'][] = $balise;
  559. if (count($class))
  560. {
  561. foreach ($class as $v)
  562. {
  563. $this->value['id_lst'][] = '*.' . $v;
  564. $this->value['id_lst'][] = '.' . $v;
  565. $this->value['id_lst'][] = $balise . '.' . $v;
  566. }
  567. }
  568. if ($id)
  569. {
  570. $this->value['id_lst'][] = '*#' . $id;
  571. $this->value['id_lst'][] = '#' . $id;
  572. $this->value['id_lst'][] = $balise . '#' . $id;
  573. }
  574. // style CSS
  575. $styles = $this->getFromCSS();
  576. // on ajoute le style propre � la balise
  577. $styles = array_merge($styles, $param['style']);
  578. if (isset($param['allwidth']) && ! isset($styles['width']))
  579. $styles['width'] = '100%';
  580. // mise � zero des styles non h�rit�s
  581. $this->resetStyle($balise);
  582. if ($heritage)
  583. {
  584. foreach ($heritage as $he_nom => $he_val)
  585. {
  586. if (is_array($he_val))
  587. {
  588. foreach ($he_val as $he2_nom => $he2_val)
  589. $this->value[$he_nom][$he2_nom] = $he2_val;
  590. }
  591. else
  592. $this->value[$he_nom] = $he_val;
  593. }
  594. }
  595. // interpreration des nouvelles valeurs
  596. $correct_width = false;
  597. $no_width = true;
  598. foreach ($styles as $nom => $val)
  599. {
  600. switch ($nom)
  601. {
  602. case 'font-family' :
  603. $val = explode(',', $val);
  604. $val = trim($val[0]);
  605. if ($val)
  606. $this->value['font-family'] = $val;
  607. break;
  608. case 'font-weight' :
  609. $this->value['font-bold'] = ($val == 'bold');
  610. break;
  611. case 'font-style' :
  612. $this->value['font-italic'] = ($val == 'italic');
  613. break;
  614. case 'text-decoration' :
  615. $val = explode(' ', $val);
  616. $this->value['font-underline'] = (in_array('underline', $val));
  617. $this->value['font-overline'] = (in_array('overline', $val));
  618. $this->value['font-linethrough'] = (in_array('line-through', $val));
  619. break;
  620. case 'text-indent' :
  621. $this->value['text-indent'] = $this->ConvertToMM($val);
  622. break;
  623. case 'text-transform' :
  624. if (! in_array($val, array('none', 'capitalize', 'uppercase', 'lowercase')))
  625. $val = 'none';
  626. $this->value['text-transform'] = $val;
  627. break;
  628. case 'font-size' :
  629. $val = $this->ConvertToMM($val, $this->value['font-size']);
  630. if ($val)
  631. $this->value['font-size'] = $val;
  632. break;
  633. case 'color' :
  634. $res = null;
  635. $this->value['color'] = $this->ConvertToColor($val, $res);
  636. if ($balise == 'hr')
  637. {
  638. $this->value['border']['l']['color'] = $this->value['color'];
  639. $this->value['border']['t']['color'] = $this->value['color'];
  640. $this->value['border']['r']['color'] = $this->value['color'];
  641. $this->value['border']['b']['color'] = $this->value['color'];
  642. }
  643. break;
  644. case 'text-align' :
  645. $val = strtolower($val);
  646. if (! in_array($val, array('left', 'right', 'center', 'justify', 'li_right')))
  647. $val = 'left';
  648. $this->value['text-align'] = $val;
  649. break;
  650. case 'vertical-align' :
  651. $this->value['vertical-align'] = $val;
  652. break;
  653. case 'width' :
  654. $this->value['width'] = $this->ConvertToMM($val, $this->getLastWidth());
  655. if ($this->value['width'] && substr($val, - 1) == '%')
  656. $correct_width = true;
  657. $no_width = false;
  658. break;
  659. case 'height' :
  660. $this->value['height'] = $this->ConvertToMM($val, $this->getLastHeight());
  661. break;
  662. case 'line-height' :
  663. if (preg_match('/^[0-9\.]+$/isU', $val))
  664. $val = floor($val * 100) . '%';
  665. $this->value['line-height'] = $val;
  666. break;
  667. case 'rotate' :
  668. if (! in_array($val, array(0, - 90, 90, 180, 270, - 180, - 270)))
  669. $val = null;
  670. if ($val < 0)
  671. $val += 360;
  672. $this->value['rotate'] = $val;
  673. break;
  674. case 'overflow' :
  675. if (! in_array($val, array('visible', 'hidden')))
  676. $val = 'visible';
  677. $this->value['overflow'] = $val;
  678. break;
  679. case 'padding' :
  680. $val = explode(' ', $val);
  681. foreach ($val as $k => $v)
  682. {
  683. $v = trim($v);
  684. if ($v != '')
  685. $val[$k] = $v;
  686. else
  687. unset($val[$k]);
  688. }
  689. $val = array_values($val);
  690. if (count($val) != 4)
  691. {
  692. $val = $this->ConvertToMM($val[0], 0);
  693. $this->value['padding']['t'] = $val;
  694. $this->value['padding']['r'] = $val;
  695. $this->value['padding']['b'] = $val;
  696. $this->value['padding']['l'] = $val;
  697. }
  698. else
  699. {
  700. $this->value['padding']['t'] = $this->ConvertToMM($val[0], 0);
  701. $this->value['padding']['r'] = $this->ConvertToMM($val[1], 0);
  702. $this->value['padding']['b'] = $this->ConvertToMM($val[2], 0);
  703. $this->value['padding']['l'] = $this->ConvertToMM($val[3], 0);
  704. }
  705. break;
  706. case 'padding-top' :
  707. $this->value['padding']['t'] = $this->ConvertToMM($val, 0);
  708. break;
  709. case 'padding-right' :
  710. $this->value['padding']['r'] = $this->ConvertToMM($val, 0);
  711. break;
  712. case 'padding-bottom' :
  713. $this->value['padding']['b'] = $this->ConvertToMM($val, 0);
  714. break;
  715. case 'padding-left' :
  716. $this->value['padding']['l'] = $this->ConvertToMM($val, 0);
  717. break;
  718. case 'margin' :
  719. if ($val == 'auto')
  720. {
  721. $this->value['margin-auto'] = true;
  722. break;
  723. }
  724. $val = explode(' ', $val);
  725. foreach ($val as $k => $v)
  726. {
  727. $v = trim($v);
  728. if ($v != '')
  729. $val[$k] = $v;
  730. else
  731. unset($val[$k]);
  732. }
  733. $val = array_values($val);
  734. if (count($val) != 4)
  735. {
  736. $val = $this->ConvertToMM($val[0], 0);
  737. $this->value['margin']['t'] = $val;
  738. $this->value['margin']['r'] = $val;
  739. $this->value['margin']['b'] = $val;
  740. $this->value['margin']['l'] = $val;
  741. }
  742. else
  743. {
  744. $this->value['margin']['t'] = $this->ConvertToMM($val[0], 0);
  745. $this->value['margin']['r'] = $this->ConvertToMM($val[1], 0);
  746. $this->value['margin']['b'] = $this->ConvertToMM($val[2], 0);
  747. $this->value['margin']['l'] = $this->ConvertToMM($val[3], 0);
  748. }
  749. break;
  750. case 'margin-top' :
  751. $this->value['margin']['t'] = $this->ConvertToMM($val, 0);
  752. break;
  753. case 'margin-right' :
  754. $this->value['margin']['r'] = $this->ConvertToMM($val, 0);
  755. break;
  756. case 'margin-bottom' :
  757. $this->value['margin']['b'] = $this->ConvertToMM($val, 0);
  758. break;
  759. case 'margin-left' :
  760. $this->value['margin']['l'] = $this->ConvertToMM($val, 0);
  761. break;
  762. case 'border' :
  763. $val = $this->readBorder($val);
  764. $this->value['border']['t'] = $val;
  765. $this->value['border']['r'] = $val;
  766. $this->value['border']['b'] = $val;
  767. $this->value['border']['l'] = $val;
  768. break;
  769. case 'border-style' :
  770. $val = explode(' ', $val);
  771. foreach ($val as $val_k => $val_v)
  772. if (! in_array($val_v, array('solid', 'dotted', 'dashed')))
  773. $val[$val_k] = null;
  774. $this->duplicateBorder($val);
  775. if ($val[0])
  776. $this->value['border']['t']['type'] = $val[0];
  777. if ($val[1])
  778. $this->value['border']['r']['type'] = $val[1];
  779. if ($val[2])
  780. $this->value['border']['b']['type'] = $val[2];
  781. if ($val[3])
  782. $this->value['border']['l']['type'] = $val[3];
  783. break;
  784. case 'border-top-style' :
  785. if (in_array($val, array('solid', 'dotted', 'dashed')))
  786. $this->value['border']['t']['type'] = $val;
  787. break;
  788. case 'border-right-style' :
  789. if (in_array($val, array('solid', 'dotted', 'dashed')))
  790. $this->value['border']['r']['type'] = $val;
  791. break;
  792. case 'border-bottom-style' :
  793. if (in_array($val, array('solid', 'dotted', 'dashed')))
  794. $this->value['border']['b']['type'] = $val;
  795. break;
  796. case 'border-left-style' :
  797. if (in_array($val, array('solid', 'dotted', 'dashed')))
  798. $this->value['border']['l']['type'] = $val;
  799. break;
  800. case 'border-color' :
  801. $res = false;
  802. $val = preg_replace('/,[\s]+/', ',', $val);
  803. $val = explode(' ', $val);
  804. foreach ($val as $val_k => $val_v)
  805. {
  806. $val[$val_k] = $this->ConvertToColor($val_v, $res);
  807. if (! $res)
  808. $val[$val_k] = null;
  809. }
  810. $this->duplicateBorder($val);
  811. if (is_array($val[0]))
  812. $this->value['border']['t']['color'] = $val[0];
  813. if (is_array($val[1]))
  814. $this->value['border']['r']['color'] = $val[1];
  815. if (is_array($val[2]))
  816. $this->value['border']['b']['color'] = $val[2];
  817. if (is_array($val[3]))
  818. $this->value['border']['l']['color'] = $val[3];
  819. break;
  820. case 'border-top-color' :
  821. $res = false;
  822. $val = $this->ConvertToColor($val, $res);
  823. if ($res)
  824. $this->value['border']['t']['color'] = $val;
  825. break;
  826. case 'border-right-color' :
  827. $res = false;
  828. $val = $this->ConvertToColor($val, $res);
  829. if ($res)
  830. $this->value['border']['r']['color'] = $val;
  831. break;
  832. case 'border-bottom-color' :
  833. $res = false;
  834. $val = $this->ConvertToColor($val, $res);
  835. if ($res)
  836. $this->value['border']['b']['color'] = $val;
  837. break;
  838. case 'border-left-color' :
  839. $res = false;
  840. $val = $this->ConvertToColor($val, $res);
  841. if ($res)
  842. $this->value['border']['l']['color'] = $val;
  843. break;
  844. case 'border-width' :
  845. $val = explode(' ', $val);
  846. foreach ($val as $val_k => $val_v)
  847. {
  848. $val[$val_k] = $this->ConvertToMM($val_v, 0);
  849. }
  850. $this->duplicateBorder($val);
  851. if ($val[0])
  852. $this->value['border']['t']['width'] = $val[0];
  853. if ($val[1])
  854. $this->value['border']['r']['width'] = $val[1];
  855. if ($val[2])
  856. $this->value['border']['b']['width'] = $val[2];
  857. if ($val[3])
  858. $this->value['border']['l']['width'] = $val[3];
  859. break;
  860. case 'border-top-width' :
  861. $val = $this->ConvertToMM($val, 0);
  862. ;
  863. if ($val)
  864. $this->value['border']['t']['width'] = $val;
  865. break;
  866. case 'border-right-width' :
  867. $val = $this->ConvertToMM($val, 0);
  868. ;
  869. if ($val)
  870. $this->value['border']['r']['width'] = $val;
  871. break;
  872. case 'border-bottom-width' :
  873. $val = $this->ConvertToMM($val, 0);
  874. ;
  875. if ($val)
  876. $this->value['border']['b']['width'] = $val;
  877. break;
  878. case 'border-left-width' :
  879. $val = $this->ConvertToMM($val, 0);
  880. ;
  881. if ($val)
  882. $this->value['border']['l']['width'] = $val;
  883. break;
  884. case 'border-collapse' :
  885. if ($balise == 'table')
  886. $this->value['border']['collapse'] = ($val == 'collapse');
  887. break;
  888. case 'border-radius' :
  889. $val = explode('/', $val);
  890. if (count($val) > 2)
  891. break;
  892. $val_h = $this->ConvertToRadius(trim($val[0]));
  893. if (count($val_h) < 1 || count($val_h) > 4)
  894. break;
  895. if (! isset($val_h[1]))
  896. $val_h[1] = $val_h[0];
  897. if (! isset($val_h[2]))
  898. $val_h = array($val_h[0], $val_h[0], $val_h[1], $val_h[1]);
  899. if (! isset($val_h[3]))
  900. $val_h[3] = $val_h[1];
  901. if (isset($val[1]))
  902. {
  903. $val_v = $this->ConvertToRadius(trim($val[1]));
  904. if (count($val_v) < 1 || count($val_v) > 4)
  905. break;
  906. if (! isset($val_v[1]))
  907. $val_v[1] = $val_v[0];
  908. if (! isset($val_v[2]))
  909. $val_v = array($val_v[0], $val_v[0], $val_v[1], $val_v[1]);
  910. if (! isset($val_v[3]))
  911. $val_v[3] = $val_v[1];
  912. }
  913. else
  914. $val_v = $val_h;
  915. $this->value['border']['radius'] = array('tl' => array($val_h[0], $val_v[0]),
  916. 'tr' => array($val_h[1], $val_v[1]), 'br' => array($val_h[2], $val_v[2]),
  917. 'bl' => array($val_h[3], $val_v[3]));
  918. break;
  919. case 'border-top-left-radius' :
  920. $val = $this->ConvertToRadius($val);
  921. if (count($val) < 1 || count($val) > 2)
  922. break;
  923. $this->value['border']['radius']['tl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  924. break;
  925. case 'border-top-right-radius' :
  926. $val = $this->ConvertToRadius($val);
  927. if (count($val) < 1 || count($val) > 2)
  928. break;
  929. $this->value['border']['radius']['tr'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  930. break;
  931. case 'border-bottom-right-radius' :
  932. $val = $this->ConvertToRadius($val);
  933. if (count($val) < 1 || count($val) > 2)
  934. break;
  935. $this->value['border']['radius']['br'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  936. break;
  937. case 'border-bottom-left-radius' :
  938. $val = $this->ConvertToRadius($val);
  939. if (count($val) < 1 || count($val) > 2)
  940. break;
  941. $this->value['border']['radius']['bl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]);
  942. break;
  943. case 'border-top' :
  944. $this->value['border']['t'] = $this->readBorder($val);
  945. break;
  946. case 'border-right' :
  947. $this->value['border']['r'] = $this->readBorder($val);
  948. break;
  949. case 'border-bottom' :
  950. $this->value['border']['b'] = $this->readBorder($val);
  951. break;
  952. case 'border-left' :
  953. $this->value['border']['l'] = $this->readBorder($val);
  954. break;
  955. case 'background-color' :
  956. $this->value['background']['color'] = $this->ConvertBackgroundColor($val);
  957. break;
  958. case 'background-image' :
  959. $this->value['background']['image'] = $this->ConvertBackgroundImage($val);
  960. break;
  961. case 'background-position' :
  962. $res = null;
  963. $this->value['background']['position'] = $this->ConvertBackgroundPosition($val, $res);
  964. break;
  965. case 'background-repeat' :
  966. $this->value['background']['repeat'] = $this->ConvertBackgroundRepeat($val);
  967. break;
  968. case 'background' :
  969. $this->ConvertBackground($val, $this->value['background']);
  970. break;
  971. case 'position' :
  972. if ($val == 'absolute')
  973. $this->value['position'] = 'absolute';
  974. else
  975. if ($val == 'relative')
  976. $this->value['position'] = 'relative';
  977. else
  978. $this->value['position'] = null;
  979. break;
  980. case 'float' :
  981. if ($val == 'left')
  982. $this->value['float'] = 'left';
  983. else
  984. if ($val == 'right')
  985. $this->value['float'] = 'right';
  986. else
  987. $this->value['float'] = null;
  988. break;
  989. case 'display' :
  990. if ($val == 'inline')
  991. $this->value['display'] = 'inline';
  992. else
  993. if ($val == 'block')
  994. $this->value['display'] = 'block';
  995. else
  996. if ($val == 'none')
  997. $this->value['display'] = 'none';
  998. else
  999. $this->value['display'] = null;
  1000. break;
  1001. case 'top' :
  1002. case 'bottom' :
  1003. case 'left' :
  1004. case 'right' :
  1005. $this->value[$nom] = $val;
  1006. break;
  1007. case 'list-style' :
  1008. case 'list-style-type' :
  1009. case 'list-style-image' :
  1010. if ($nom == 'list-style')
  1011. $nom = 'list-style-type';
  1012. $this->value[$nom] = $val;
  1013. break;
  1014. default :
  1015. break;
  1016. }
  1017. }
  1018. if ($this->value['margin']['t'] === null)
  1019. $this->value['margin']['t'] = $this->value['font-size'];
  1020. if ($this->value['margin']['b'] === null)
  1021. $this->value['margin']['b'] = $this->value['font-size'];
  1022. if ($this->onlyLeft)
  1023. $this->value['text-align'] = 'left';
  1024. // correction de la largeur pour correspondre au mod�le de boite quick
  1025. if ($no_width && in_array($balise, array('div')) && $this->value['position'] != 'absolute')
  1026. {
  1027. $this->value['width'] = $this->getLastWidth();
  1028. $this->value['width'] -= $this->value['margin']['l'] + $this->value['margin']['r'];
  1029. }
  1030. else
  1031. {
  1032. if ($correct_width)
  1033. {
  1034. if (! in_array($balise, array('table', 'div', 'hr')))
  1035. {
  1036. $this->value['width'] -= $this->value['padding']['l'] + $this->value['padding']['r'];
  1037. $this->value['width'] -= $this->value['border']['l']['width'] + $this->value['border']['r']['width'];
  1038. }
  1039. if (in_array($balise, array('th', 'td')))
  1040. {
  1041. $this->value['width'] -= $this->ConvertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px');
  1042. }
  1043. if ($this->value['width'] < 0)
  1044. $this->value['width'] = 0;
  1045. }
  1046. else
  1047. {
  1048. if ($this->value['width'])
  1049. {
  1050. if ($this->value['border']['l']['width'])
  1051. $this->value['width'] += $this->value['border']['l']['width'];
  1052. if ($this->value['border']['r']['width'])
  1053. $this->value['width'] += $this->value['border']['r']['width'];
  1054. if ($this->value['padding']['l'])
  1055. $this->value['width'] += $this->value['padding']['l'];
  1056. if ($this->value['padding']['r'])
  1057. $this->value['width'] += $this->value['padding']['r'];
  1058. }
  1059. }
  1060. }
  1061. if ($this->value['height'])
  1062. {
  1063. if ($this->value['border']['b']['width'])
  1064. {
  1065. $this->value['height'] += $this->value['border']['b']['width'];
  1066. }
  1067. if ($this->value['border']['t']['width'])
  1068. {
  1069. $this->value['height'] += $this->value['border']['t']['width'];
  1070. }
  1071. if ($this->value['padding']['b'])
  1072. $this->value['height'] += $this->value['padding']['b'];
  1073. if ($this->value['padding']['t'])
  1074. $this->value['height'] += $this->value['padding']['t'];
  1075. }
  1076. if ($this->value['top'] != null)
  1077. $this->value['top'] = $this->ConvertToMM($this->value['top'], $this->getLastHeight(true));
  1078. if ($this->value['bottom'] != null)
  1079. $this->value['bottom'] = $this->ConvertToMM($this->value['bottom'], $this->getLastHeight(true));
  1080. if ($this->value['left'] != null)
  1081. $this->value['left'] = $this->ConvertToMM($this->value['left'], $this->getLastWidth(true));
  1082. if ($this->value['right'] != null)
  1083. $this->value['right'] = $this->ConvertToMM($this->value['right'], $this->getLastWidth(true));
  1084. if ($this->value['top'] && $this->value['bottom'] && $this->value['height'])
  1085. $this->value['bottom'] = null;
  1086. if ($this->value['left'] && $this->value['right'] && $this->value['width'])
  1087. $this->value['right'] = null;
  1088. }
  1089. /**
  1090. * R�cup�ration de la hauteur de ligne courante
  1091. *
  1092. * @return float hauteur en mm
  1093. */
  1094. public function getLineHeight()
  1095. {
  1096. $val = $this->value['line-height'];
  1097. if ($val == 'normal')
  1098. $val = '108%';
  1099. return $this->ConvertToMM($val, $this->value['font-size']);
  1100. }
  1101. /**
  1102. * R�cup�ration de la largeur de l'objet parent
  1103. *
  1104. * @return float largeur
  1105. */
  1106. public function getLastWidth($mode = false)
  1107. {
  1108. for($k = count($this->table); $k > 0; $k --)
  1109. {
  1110. if ($this->table[$k - 1]['width'])
  1111. {
  1112. $w = $this->table[$k - 1]['width'];
  1113. if ($mode)
  1114. {
  1115. $w += $this->table[$k - 1]['border']['l']['width'] + $this->table[$k - 1]['padding']['l'] + 0.02;
  1116. $w += $this->table[$k - 1]['border']['r']['width'] + $this->table[$k - 1]['padding']['r'] + 0.02;
  1117. }
  1118. return $w;
  1119. }
  1120. }
  1121. return $this->pdf->getW() - $this->pdf->getlMargin() - $this->pdf->getrMargin();
  1122. }
  1123. /**
  1124. * R�cup�ration de la hauteur de l'objet parent
  1125. *
  1126. * @return float hauteur
  1127. */
  1128. public function getLastHeight($mode = false)
  1129. {
  1130. for($k = count($this->table); $k > 0; $k --)
  1131. {
  1132. if ($this->table[$k - 1]['height'])
  1133. {
  1134. $h = $this->table[$k - 1]['height'];
  1135. if ($mode)
  1136. {
  1137. $h += $this->table[$k - 1]['border']['t']['width'] + $this->table[$k - 1]['padding']['t'] + 0.02;
  1138. $h += $this->table[$k - 1]['border']['b']['width'] + $this->table[$k - 1]['padding']['b'] + 0.02;
  1139. }
  1140. return $h;
  1141. }
  1142. }
  1143. return $this->pdf->getH() - $this->pdf->gettMargin() - $this->pdf->getbMargin();
  1144. }
  1145. public function getFloat()
  1146. {
  1147. if ($this->value['float'] == 'left')
  1148. return 'left';
  1149. if ($this->value['float'] == 'right')
  1150. return 'right';
  1151. return null;
  1152. }
  1153. public function getLastValue($key)
  1154. {
  1155. $nb = count($this->table);
  1156. if ($nb > 0)
  1157. return $this->table[$nb - 1][$key];
  1158. return null;
  1159. }
  1160. protected function getLastAbsoluteX()
  1161. {
  1162. for($k = count($this->table); $k > 0; $k --)
  1163. {
  1164. if ($this->table[$k - 1]['x'] && $this->table[$k - 1]['position'])
  1165. return $this->table[$k - 1]['x'];
  1166. }
  1167. return $this->pdf->getlMargin();
  1168. }
  1169. protected function getLastAbsoluteY()
  1170. {
  1171. for($k = count($this->table); $k > 0; $k --)
  1172. {
  1173. if ($this->table[$k - 1]['y'] && $this->table[$k - 1]['position'])
  1174. return $this->table[$k - 1]['y'];
  1175. }
  1176. return $this->pdf->gettMargin();
  1177. }
  1178. /**
  1179. * R�cup�ration des propri�t�s CSS de la balise en cours
  1180. *
  1181. * @return array() tableau des propri�t�s CSS
  1182. */
  1183. protected function getFromCSS()
  1184. {
  1185. $styles = array(); // style � appliquer
  1186. $getit = array(); // styles � r�cuperer
  1187. // identification des styles direct, et ceux des parents
  1188. $lst = array();
  1189. $lst[] = $this->value['id_lst'];
  1190. for($i = count($this->table) - 1; $i >= 0; $i --)
  1191. $lst[] = $this->table[$i]['id_lst'];
  1192. // identification des styles � r�cuperer
  1193. foreach ($this->css_keys as $key => $num)
  1194. if ($this->getReccursiveStyle($key, $lst))
  1195. $getit[$key] = $num;
  1196. // si des styles sont � recuperer
  1197. if (count($getit))
  1198. {
  1199. // on les r�cup�re, mais dans l'odre de d�finition, afin de garder les priorit�s
  1200. asort($getit);
  1201. foreach ($getit as $key => $val)
  1202. $styles = array_merge($styles, $this->css[$key]);
  1203. }
  1204. return $styles;
  1205. }
  1206. /**
  1207. * Identification des styles � r�cuperer, en fonction de la balise et de ses parents
  1208. *
  1209. * @param string clef CSS � analyser
  1210. * @param array() tableau des styles direct, et ceux des parents
  1211. * @param string prochaine etape
  1212. * @return boolean clef autoris�e ou non
  1213. */
  1214. protected function getReccursiveStyle($key, $lst, $next = null)
  1215. {
  1216. // si propchaine etape, on construit les valeurs
  1217. if ($next !== null)
  1218. {
  1219. if ($next)
  1220. $key = trim(substr($key, 0, - strlen($next))); // on el�ve cette etape
  1221. unset($lst[0]);
  1222. if (! count($lst))
  1223. return false; // pas d'etape possible
  1224. $lst = array_values($lst);
  1225. }
  1226. // pour chaque style direct possible de l'etape en cours
  1227. foreach ($lst[0] as $nom)
  1228. {
  1229. if ($key == $nom)
  1230. return true; // si la clef conrrespond => ok
  1231. if (substr($key, - strlen(' ' . $nom)) == ' ' . $nom && $this->getReccursiveStyle($key, $lst, $nom))
  1232. return true; // si la clef est la fin, on analyse ce qui pr�c�de
  1233. }
  1234. // si on est pas � la premiere etape, on doit analyse toutes les sous etapes
  1235. if ($next !== null && $this->getReccursiveStyle($key, $lst, ''))
  1236. return true;
  1237. // aucun style trouv�
  1238. return false;
  1239. }
  1240. /**
  1241. * Analyse d'une propri�t� Border
  1242. *
  1243. * @param string propri�t� border
  1244. * @return array() propri�t� d�cod�e
  1245. */
  1246. public function readBorder($val)
  1247. {
  1248. $none = array('type' => 'none', 'width' => 0, 'color' => array(0, 0, 0));
  1249. // valeurs par d�fault
  1250. $type = 'solid';
  1251. $width = $this->ConvertToMM('1pt');
  1252. $color = array(0, 0, 0);
  1253. // nettoyage des valeurs
  1254. $val = explode(' ', $val);
  1255. foreach ($val as $k => $v)
  1256. {
  1257. $v = trim($v);
  1258. if ($v)
  1259. $val[$k] = $v;
  1260. else
  1261. unset($val[$k]);
  1262. }
  1263. $val = array_values($val);
  1264. // identification des valeurs
  1265. $res = null;
  1266. foreach ($val as $key)
  1267. {
  1268. if ($key == 'none' || $key == 'hidden')
  1269. return $none;
  1270. if ($this->ConvertToMM($key) !== null)
  1271. $width = $this->ConvertToMM($key);
  1272. else
  1273. if (in_array($key, array('solid', 'dotted', 'dashed', 'double')))
  1274. $type = $key;
  1275. else
  1276. {
  1277. $tmp = $this->ConvertToColor($key, $res);
  1278. if ($res)
  1279. $color = $tmp;
  1280. }
  1281. }
  1282. if (! $width)
  1283. return $none;
  1284. return array('type' => $type, 'width' => $width, 'color' => $color);
  1285. }
  1286. protected function duplicateBorder(&$val)
  1287. {
  1288. if (count($val) == 1)
  1289. {
  1290. $val[1] = $val[0];
  1291. $val[2] = $val[0];
  1292. $val[3] = $val[0];
  1293. }
  1294. else
  1295. if (count($val) == 2)
  1296. {
  1297. $val[2] = $val[0];
  1298. $val[3] = $val[1];
  1299. }
  1300. else
  1301. if (count($val) == 3)
  1302. {
  1303. $val[3] = $val[1];
  1304. }
  1305. }
  1306. public function ConvertBackground($stl, &$res)
  1307. {
  1308. // Image
  1309. $text = '/url\(([^)]*)\)/isU';
  1310. if (preg_match($text, $stl, $match))
  1311. {
  1312. $res['image'] = $this->ConvertBackgroundImage($match[0]);
  1313. $stl = preg_replace($text, '', $stl);
  1314. $stl = preg_replace('/[\s]+/', ' ', $stl);
  1315. }
  1316. // protection des espaces
  1317. $stl = preg_replace('/,[\s]+/', ',', $stl);
  1318. $lst = explode(' ', $stl);
  1319. $pos = '';
  1320. foreach ($lst as $val)
  1321. {
  1322. $ok = false;
  1323. $color = $this->ConvertToColor($val, $ok);
  1324. if ($ok)
  1325. {
  1326. $res['color'] = $color;
  1327. }
  1328. else
  1329. if ($val == 'transparent')
  1330. {
  1331. $res['color'] = null;
  1332. }
  1333. else
  1334. {
  1335. $repeat = $this->ConvertBackgroundRepeat($val);
  1336. if ($repeat)
  1337. {
  1338. $res['repeat'] = $repeat;
  1339. }
  1340. else
  1341. {
  1342. $pos .= ($pos ? ' ' : '') . $val;
  1343. }
  1344. }
  1345. }
  1346. if ($pos)
  1347. {
  1348. $pos = $this->ConvertBackgroundPosition($pos, $ok);
  1349. if ($ok)
  1350. $res['position'] = $pos;
  1351. }
  1352. }
  1353. public function ConvertBackgroundColor($val)
  1354. {
  1355. $res = null;
  1356. if ($val == 'transparent')
  1357. return null;
  1358. else
  1359. return $this->ConvertToColor($val, $res);
  1360. }
  1361. public function ConvertBackgroundImage($val)
  1362. {
  1363. if ($val == 'none')
  1364. return null;
  1365. else
  1366. if (preg_match('/^url\(([^)]*)\)$/isU', $val, $match))
  1367. return $match[1];
  1368. else
  1369. return null;
  1370. }
  1371. public function ConvertBackgroundPosition($val, &$res)
  1372. {
  1373. $val = explode(' ', $val);
  1374. if (count($val) < 2)
  1375. {
  1376. if (! $val[0])
  1377. return null;
  1378. $val[1] = 'center';
  1379. }
  1380. if (count($val) > 2)
  1381. return null;
  1382. $x = 0;
  1383. $y = 0;
  1384. $res = true;
  1385. if ($val[0] == 'left')
  1386. $x = '0%';
  1387. else
  1388. if ($val[0] == 'center')
  1389. $x = '50%';
  1390. else
  1391. if ($val[0] == 'right')
  1392. $x = '100%';
  1393. else
  1394. if ($val[0] == 'top')
  1395. $y = '0%';
  1396. else
  1397. if ($val[0] == 'bottom')
  1398. $y = '100%';
  1399. else
  1400. if (preg_match('/^[-]?[0-9\.]+%$/isU', $val[0]))
  1401. $x = $val[0];
  1402. else
  1403. if ($this->ConvertToMM($val[0]))
  1404. $x = $this->ConvertToMM($val[0]);
  1405. else
  1406. $res = false;
  1407. if ($val[1] == 'left')
  1408. $x = '0%';
  1409. else
  1410. if ($val[1] == 'right')
  1411. $x = '100%';
  1412. else
  1413. if ($val[1] == 'top')
  1414. $y = '0%';
  1415. else
  1416. if ($val[1] == 'center')
  1417. $y = '50%';
  1418. else
  1419. if ($val[1] == 'bottom')
  1420. $y = '100%';
  1421. else
  1422. if (preg_match('/^[-]?[0-9\.]+%$/isU', $val[1]))
  1423. $y = $val[1];
  1424. else
  1425. if ($this->ConvertToMM($val[1]))
  1426. $y = $this->ConvertToMM($val[1]);
  1427. else
  1428. $res = false;
  1429. $val[0] = $x;
  1430. $val[1] = $y;
  1431. return $val;
  1432. }
  1433. public function ConvertBackgroundRepeat($val)
  1434. {
  1435. switch ($val)
  1436. {
  1437. case 'repeat' :
  1438. return array(true, true);
  1439. case 'repeat-x' :
  1440. return array(true, false);
  1441. case 'repeat-y' :
  1442. return array(false, true);
  1443. case 'no-repeat' :
  1444. return array(false, false);
  1445. }
  1446. return null;
  1447. }
  1448. /**
  1449. * Convertir une longueur en mm
  1450. *
  1451. * @param string longueur, avec unit�, � convertir
  1452. * @param float longueur du parent
  1453. * @return float longueur exprim�e en mm
  1454. */
  1455. public function ConvertToMM($val, $old = 0.)
  1456. {
  1457. $val = trim($val);
  1458. if (preg_match('/^[0-9\.\-]+$/isU', $val))
  1459. $val .= 'px';
  1460. if (preg_match('/^[0-9\.\-]+px$/isU', $val))
  1461. $val = 25.4 / 96. * str_replace('px', '', $val);
  1462. else
  1463. if (preg_match('/^[0-9\.\-]+pt$/isU', $val))
  1464. $val = 25.4 / 72. * str_replace('pt', '', $val);
  1465. else
  1466. if (preg_match('/^[0-9\.\-]+in$/isU', $val))
  1467. $val = 25.4 * str_replace('in', '', $val);
  1468. else
  1469. if (preg_match('/^[0-9\.\-]+mm$/isU', $val))
  1470. $val = 1. * str_replace('mm', '', $val);
  1471. else
  1472. if (preg_match('/^[0-9\.\-]+%$/isU', $val))
  1473. $val = 1. * $old * str_replace('%', '', $val) / 100.;
  1474. else
  1475. $val = null;
  1476. return $val;
  1477. }
  1478. public function ConvertToRadius($val)
  1479. {
  1480. $val = explode(' ', $val);
  1481. foreach ($val as $k => $v)
  1482. {
  1483. $v = trim($v);
  1484. if ($v)
  1485. {
  1486. $v = $this->ConvertToMM($v, 0);
  1487. if ($v !== null)
  1488. $val[$k] = $v;
  1489. else
  1490. unset($val[$k]);
  1491. }
  1492. else
  1493. unset($val[$k]);
  1494. }
  1495. return array_values($val);
  1496. }
  1497. /**
  1498. * D�composition d'un code couleur HTML
  1499. *
  1500. * @param string couleur au format CSS
  1501. * @return array(r, v, b) couleur exprim� par ses comporantes R, V, B, de 0 � 255.
  1502. */
  1503. public function ConvertToColor($val, &$res)
  1504. {
  1505. $val = trim($val);
  1506. $res = true;
  1507. if (strtolower($val) == 'transparent')
  1508. return array(null, null, null);
  1509. if (isset($this->htmlColor[strtolower($val)]))
  1510. $val = $this->htmlColor[strtolower($val)];
  1511. if (preg_match('/^#[0-9A-Fa-f]{6}$/isU', $val))
  1512. {
  1513. $r = floatVal(hexdec(substr($val, 1, 2)));
  1514. $v = floatVal(hexdec(substr($val, 3, 2)));
  1515. $b = floatVal(hexdec(substr($val, 5, 2)));
  1516. $col = array($r, $v, $b);
  1517. }
  1518. elseif (preg_match('/^#[0-9A-F]{3}$/isU', $val))
  1519. {
  1520. $r = floatVal(hexdec(substr($val, 1, 1) . substr($val, 1, 1)));
  1521. $v = floatVal(hexdec(substr($val, 2, 1) . substr($val, 2, 1)));
  1522. $b = floatVal(hexdec(substr($val, 3, 1) . substr($val, 3, 1)));
  1523. $col = array($r, $v, $b);
  1524. }
  1525. elseif (preg_match('/rgb\([\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*\)/isU', $val, $match))
  1526. {
  1527. $r = $this->ConvertSubColor($match[1]) * 255.;
  1528. $v = $this->ConvertSubColor($match[2]) * 255.;
  1529. $b = $this->ConvertSubColor($match[3]) * 255.;
  1530. $col = array($r, $v, $b);
  1531. }
  1532. elseif (preg_match('/cmyk\([\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*\)/isU', $val, $match))
  1533. {
  1534. $c = $this->ConvertSubColor($match[1]) * 100.;
  1535. $m = $this->ConvertSubColor($match[2]) * 100.;
  1536. $y = $this->ConvertSubColor($match[3]) * 100.;
  1537. $k = $this->ConvertSubColor($match[4]) * 100.;
  1538. $col = array($c, $m, $y, $k);
  1539. }
  1540. else
  1541. {
  1542. $col = array(0., 0., 0.);
  1543. $res = false;
  1544. }
  1545. return $col;
  1546. }
  1547. protected function ConvertSubColor($c)
  1548. {
  1549. if (substr($c, - 1) == '%')
  1550. $c = floatVal(substr($c, 0, - 1)) / 100.;
  1551. else
  1552. {
  1553. $c = floatVal($c);
  1554. if ($c > 1)
  1555. $c = $c / 255.;
  1556. }
  1557. return $c;
  1558. }
  1559. /**
  1560. * Analyser une feuille de style
  1561. *
  1562. * @param string code CSS
  1563. * @return null
  1564. */
  1565. protected function analyseStyle(&$code)
  1566. {
  1567. // on remplace tous les espaces, tab, \r, \n, par des espaces uniques
  1568. $code = preg_replace('/[\s]+/', ' ', $code);
  1569. // on enl�ve les commentaires
  1570. $code = preg_replace('/\/\*.*?\*\//s', '', $code);
  1571. // on analyse chaque style
  1572. preg_match_all('/([^{}]+){([^}]*)}/isU', $code, $match);
  1573. for($k = 0; $k < count($match[0]); $k ++)
  1574. {
  1575. // noms
  1576. $noms = strtolower(trim($match[1][$k]));
  1577. // style, s�par� par des; => on remplie le tableau correspondant
  1578. $styles = trim($match[2][$k]);
  1579. $styles = explode(';', $styles);
  1580. $stl = array();
  1581. foreach ($styles as $style)
  1582. {
  1583. $tmp = explode(':', $style);
  1584. if (count($tmp) > 1)
  1585. {
  1586. $cod = $tmp[0];
  1587. unset($tmp[0]);
  1588. $tmp = implode(':', $tmp);
  1589. $stl[trim(strtolower($cod))] = trim($tmp);
  1590. }
  1591. }
  1592. // d�composition des noms par les ,
  1593. $noms = explode(',', $noms);
  1594. foreach ($noms as $nom)
  1595. {
  1596. $nom = trim($nom);
  1597. // Si il a une fonction sp�cifique, comme :hover => on zap
  1598. if (strpos($nom, ':') !== false)
  1599. continue;
  1600. if (! isset($this->css[$nom]))
  1601. $this->css[$nom] = $stl;
  1602. else
  1603. $this->css[$nom] = array_merge($this->css[$nom], $stl);
  1604. }
  1605. }
  1606. $this->css_keys = array_flip(array_keys($this->css));
  1607. }
  1608. /**
  1609. * Extraction des feuille de style du code HTML
  1610. *
  1611. * @param string code HTML
  1612. * @return null
  1613. */
  1614. public function readStyle(&$html)
  1615. {
  1616. $style = ' ';
  1617. // extraction des balises link, et suppression de celles-ci dans le code HTML
  1618. preg_match_all('/<link([^>]*)>/isU', $html, $match);
  1619. $html = preg_replace('/<link[^>]*>/isU', '', $html);
  1620. $html = preg_replace('/<\/link[^>]*>/isU', '', $html);
  1621. // analyse de chaque balise
  1622. foreach ($match[1] as $code)
  1623. {
  1624. $tmp = array();
  1625. // lecture des param�tres du type nom=valeur
  1626. $prop = '([a-zA-Z0-9_]+)=([^"\'\s>]+)';
  1627. preg_match_all('/' . $prop . '/is', $code, $match);
  1628. for($k = 0; $k < count($match[0]); $k ++)
  1629. $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]);
  1630. // lecture des param�tres du type nom="valeur"
  1631. $prop = '([a-zA-Z0-9_]+)=["]([^"]*)["]';
  1632. preg_match_all('/' . $prop . '/is', $code, $match);
  1633. for($k = 0; $k < count($match[0]); $k ++)
  1634. $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]);
  1635. // lecture des param�tres du type nom='valeur'
  1636. $prop = "([a-zA-Z0-9_]+)=[']([^']*)[']";
  1637. preg_match_all('/' . $prop . '/is', $code, $match);
  1638. for($k = 0; $k < count($match[0]); $k ++)
  1639. $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]);
  1640. // si de type text/css => on garde
  1641. if (isset($tmp['type']) && strtolower($tmp['type']) == 'text/css' && isset($tmp['href']))
  1642. {
  1643. $content = @file_get_contents($tmp['href']);
  1644. $url = $tmp['href'];
  1645. if (strpos($url, 'http://') !== false)
  1646. {
  1647. $url = str_replace('http://', '', $url);
  1648. $url = explode('/', $url);
  1649. $url_main = 'http://' . $url[0] . '/';
  1650. $url_self = $url;
  1651. unset($url_self[count($url_self) - 1]);
  1652. $url_self = 'http://' . implode('/', $url_self) . '/';
  1653. $content = preg_replace('/url\(([^\\\\][^)]*)\)/isU', 'url(' . $url_self . '$1)', $content);
  1654. $content = preg_replace('/url\((\\\\[^)]*)\)/isU', 'url(' . $url_main . '$1)', $content);
  1655. }
  1656. else
  1657. {
  1658. // @todo
  1659. // $content = preg_replace('/url\(([^)]*)\)/isU', 'url('.dirname($url).'/$1)', $content);
  1660. }
  1661. $style .= $content . "\n";
  1662. }
  1663. }
  1664. // extraction des balises style, et suppression de celles-ci dans le code HTML
  1665. preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match);
  1666. $html = preg_replace('/<style[^>]*>(.*)<\/style[^>]*>/isU', '', $html);
  1667. // analyse de chaque balise
  1668. foreach ($match[1] as $code)
  1669. {
  1670. $code = str_replace('<!--', '', $code);
  1671. $code = str_replace('-->', '', $code);
  1672. $style .= $code . "\n";
  1673. }
  1674. $this->analyseStyle($style);
  1675. }
  1676. }