[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3master/var/www/se3/html2pdf/ -> html2pdf.class.php (source)

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


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1