source: trunk/client/inc/hpdf5/spipu/html2pdf/src/Html2Pdf.php@ 424

Last change on this file since 424 was 347, checked in by roby, 4 years ago

Aggiornamento per compatibilità con php7.4

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