[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * HTML2PDF Librairy - parsingCss class 4 * 5 * HTML => PDF convertor 6 * distributed under the LGPL License 7 * 8 * @author Laurent MINGUET <webmaster@html2pdf.fr> 9 * @version 4.03 10 */ 11 12 class HTML2PDF_parsingCss 13 { 14 /** 15 * reference to the pdf object 16 * @var TCPDF 17 */ 18 protected $_pdf = null; 19 20 protected $_htmlColor = array(); // list of the HTML colors 21 protected $_onlyLeft = false; // flag if we are in a sub html => only "text-align:left" is used 22 protected $_defaultFont = null; // default font to use if the asked font does not exist 23 24 public $value = array(); // current values 25 public $css = array(); // css values 26 public $cssKeys = array(); // css key, for the execution order 27 public $table = array(); // level history 28 29 /** 30 * Constructor 31 * 32 * @param &HTML2PDF_myPdf reference to the PDF $object 33 * @access public 34 */ 35 public function __construct(&$pdf) 36 { 37 $this->_init(); 38 $this->setPdfParent($pdf); 39 } 40 41 /** 42 * Set the HTML2PDF parent object 43 * 44 * @param &HTML2PDF reference to the HTML2PDF parent $object 45 * @access public 46 */ 47 public function setPdfParent(&$pdf) 48 { 49 $this->_pdf = &$pdf; 50 } 51 52 /** 53 * Inform that we want only "test-align:left" because we are in a sub HTML 54 * 55 * @access public 56 */ 57 public function setOnlyLeft() 58 { 59 $this->value['text-align'] = 'left'; 60 $this->_onlyLeft = true; 61 } 62 63 /** 64 * Get the vales of the parent, if exist 65 * 66 * @return array CSS values 67 * @access public 68 */ 69 public function getOldValues() 70 { 71 return isset($this->table[count($this->table)-1]) ? $this->table[count($this->table)-1] : $this->value; 72 } 73 74 /** 75 * define the Default Font to use, if the font does not exist, or if no font asked 76 * 77 * @param string default font-family. If null : Arial for no font asked, and error fot ont does not exist 78 * @return string old default font-family 79 * @access public 80 */ 81 public function setDefaultFont($default = null) 82 { 83 $old = $this->_defaultFont; 84 $this->_defaultFont = $default; 85 if ($default) $this->value['font-family'] = $default; 86 return $old; 87 } 88 89 /** 90 * Init the object 91 * 92 * @access protected 93 */ 94 protected function _init() 95 { 96 // get the Web Colors from TCPDF 97 require(K_PATH_MAIN.'htmlcolors.php'); 98 $this->_htmlColor = $webcolor; 99 100 // init the Style 101 $this->table = array(); 102 $this->value = array(); 103 $this->initStyle(); 104 105 // Init the styles without legacy 106 $this->resetStyle(); 107 } 108 109 /** 110 * Init the CSS Style 111 * 112 * @access public 113 */ 114 public function initStyle() 115 { 116 $this->value['id_tag'] = 'body'; // tag name 117 $this->value['id_name'] = null; // tag - attribute name 118 $this->value['id_id'] = null; // tag - attribute id 119 $this->value['id_class'] = null; // tag - attribute class 120 $this->value['id_lst'] = array('*'); // tag - list of legacy 121 $this->value['mini-size'] = 1.; // specific size report for sup, sub 122 $this->value['mini-decal'] = 0; // specific position report for sup, sub 123 $this->value['font-family'] = 'Arial'; 124 $this->value['font-bold'] = false; 125 $this->value['font-italic'] = false; 126 $this->value['font-underline'] = false; 127 $this->value['font-overline'] = false; 128 $this->value['font-linethrough'] = false; 129 $this->value['text-transform'] = 'none'; 130 $this->value['font-size'] = $this->convertToMM('10pt'); 131 $this->value['text-indent'] = 0; 132 $this->value['text-align'] = 'left'; 133 $this->value['vertical-align'] = 'middle'; 134 $this->value['line-height'] = 'normal'; 135 136 $this->value['position'] = null; 137 $this->value['x'] = null; 138 $this->value['y'] = null; 139 $this->value['width'] = 0; 140 $this->value['height'] = 0; 141 $this->value['top'] = null; 142 $this->value['right'] = null; 143 $this->value['bottom'] = null; 144 $this->value['left'] = null; 145 $this->value['float'] = null; 146 $this->value['display'] = null; 147 $this->value['rotate'] = null; 148 $this->value['overflow'] = 'visible'; 149 150 $this->value['color'] = array(0, 0, 0); 151 $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null); 152 $this->value['border'] = array(); 153 $this->value['padding'] = array(); 154 $this->value['margin'] = array(); 155 $this->value['margin-auto'] = false; 156 157 $this->value['list-style-type'] = ''; 158 $this->value['list-style-image'] = ''; 159 160 $this->value['xc'] = null; 161 $this->value['yc'] = null; 162 } 163 164 /** 165 * Init the CSS Style without legacy 166 * 167 * @param string tag name 168 * @access public 169 */ 170 public function resetStyle($tagName = '') 171 { 172 // prepare somme values 173 $border = $this->readBorder('solid 1px #000000'); 174 $units = array( 175 '1px' => $this->convertToMM('1px'), 176 '5px' => $this->convertToMM('5px'), 177 ); 178 179 180 // prepare the Collapse attribute 181 $collapse = isset($this->value['border']['collapse']) ? $this->value['border']['collapse'] : false; 182 if (!in_array($tagName, array('tr', 'td', 'th', 'thead', 'tbody', 'tfoot'))) $collapse = false; 183 184 // set the global css values 185 $this->value['position'] = null; 186 $this->value['x'] = null; 187 $this->value['y'] = null; 188 $this->value['width'] = 0; 189 $this->value['height'] = 0; 190 $this->value['top'] = null; 191 $this->value['right'] = null; 192 $this->value['bottom'] = null; 193 $this->value['left'] = null; 194 $this->value['float'] = null; 195 $this->value['display'] = null; 196 $this->value['rotate'] = null; 197 $this->value['overflow'] = 'visible'; 198 $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null); 199 $this->value['border'] = array( 200 't' => $this->readBorder('none'), 201 'r' => $this->readBorder('none'), 202 'b' => $this->readBorder('none'), 203 'l' => $this->readBorder('none'), 204 'radius' => array( 205 'tl' => array(0, 0), 206 'tr' => array(0, 0), 207 'br' => array(0, 0), 208 'bl' => array(0, 0) 209 ), 210 'collapse' => $collapse, 211 ); 212 213 // specific values for some tags 214 if (!in_array($tagName, array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { 215 $this->value['margin'] = array('t'=>0,'r'=>0,'b'=>0,'l'=>0); 216 } 217 218 if (in_array($tagName, array('input', 'select', 'textarea'))) { 219 $this->value['border']['t'] = null; 220 $this->value['border']['r'] = null; 221 $this->value['border']['b'] = null; 222 $this->value['border']['l'] = null; 223 } 224 225 if ($tagName=='p') { 226 $this->value['margin']['t'] = null; 227 $this->value['margin']['b'] = null; 228 } 229 if ($tagName=='blockquote') { 230 $this->value['margin']['t'] = 3; 231 $this->value['margin']['r'] = 3; 232 $this->value['margin']['b'] = 3; 233 $this->value['margin']['l'] = 6; 234 } 235 $this->value['margin-auto'] = false; 236 237 if (in_array($tagName, array('blockquote', 'div', 'fieldset'))) { 238 $this->value['vertical-align'] = 'top'; 239 } 240 241 if (in_array($tagName, array('fieldset', 'legend'))) { 242 $this->value['border'] = array( 243 't' => $border, 244 'r' => $border, 245 'b' => $border, 246 'l' => $border, 247 'radius' => array( 248 'tl' => array($units['5px'], $units['5px']), 249 'tr' => array($units['5px'], $units['5px']), 250 'br' => array($units['5px'], $units['5px']), 251 'bl' => array($units['5px'], $units['5px']) 252 ), 253 'collapse' => false, 254 ); 255 } 256 257 if (in_array($tagName, array('ul', 'li'))) { 258 $this->value['list-style-type'] = ''; 259 $this->value['list-style-image'] = ''; 260 } 261 262 if (!in_array($tagName, array('tr', 'td'))) { 263 $this->value['padding'] = array( 264 't' => 0, 265 'r' => 0, 266 'b' => 0, 267 'l' => 0 268 ); 269 } else { 270 $this->value['padding'] = array( 271 't' => $units['1px'], 272 'r' => $units['1px'], 273 'b' => $units['1px'], 274 'l' => $units['1px'] 275 ); 276 } 277 278 if ($tagName=='hr') { 279 $this->value['border'] = array( 280 't' => $border, 281 'r' => $border, 282 'b' => $border, 283 'l' => $border, 284 'radius' => array( 285 'tl' => array(0, 0), 286 'tr' => array(0, 0), 287 'br' => array(0, 0), 288 'bl' => array(0, 0) 289 ), 290 'collapse' => false, 291 ); 292 $this->convertBackground('#FFFFFF', $this->value['background']); 293 } 294 295 $this->value['xc'] = null; 296 $this->value['yc'] = null; 297 } 298 299 /** 300 * Init the PDF Font 301 * 302 * @access public 303 */ 304 public function fontSet() 305 { 306 $family = strtolower($this->value['font-family']); 307 308 $b = ($this->value['font-bold'] ? 'B' : ''); 309 $i = ($this->value['font-italic'] ? 'I' : ''); 310 $u = ($this->value['font-underline'] ? 'U' : ''); 311 $d = ($this->value['font-linethrough'] ? 'D' : ''); 312 $o = ($this->value['font-overline'] ? 'O' : ''); 313 314 // font style 315 $style = $b.$i; 316 317 if ($this->_defaultFont) { 318 if($family=='arial') 319 $family='helvetica'; 320 elseif($family=='symbol' || $family=='zapfdingbats') 321 $style=''; 322 323 $fontkey = $family.$style; 324 if (!$this->_pdf->isLoadedFont($fontkey)) 325 $family = $this->_defaultFont; 326 } 327 328 if($family=='arial') 329 $family='helvetica'; 330 elseif($family=='symbol' || $family=='zapfdingbats') 331 $style=''; 332 333 // complete style 334 $style.= $u.$d.$o; 335 336 // size : mm => pt 337 $size = $this->value['font-size']; 338 $size = 72 * $size / 25.4; 339 340 // apply the font 341 $this->_pdf->SetFont($family, $style, $this->value['mini-size']*$size); 342 $this->_pdf->setTextColorArray($this->value['color']); 343 if ($this->value['background']['color']) 344 $this->_pdf->setFillColorArray($this->value['background']['color']); 345 else 346 $this->_pdf->setFillColor(255); 347 } 348 349 /** 350 * add a level in the CSS history 351 * 352 * @access public 353 */ 354 public function save() 355 { 356 array_push($this->table, $this->value); 357 } 358 359 /** 360 * remove a level in the CSS history 361 * 362 * @access public 363 */ 364 public function load() 365 { 366 if (count($this->table)) { 367 $this->value = array_pop($this->table); 368 } 369 } 370 371 /** 372 * restore the Y positiony (used after a span) 373 * 374 * @access public 375 */ 376 public function restorePosition() 377 { 378 if ($this->value['y']==$this->_pdf->getY()) $this->_pdf->setY($this->value['yc'], false); 379 } 380 381 /** 382 * set the New position for the current Tag 383 * 384 * @access public 385 */ 386 public function setPosition() 387 { 388 // get the current position 389 $currentX = $this->_pdf->getX(); 390 $currentY = $this->_pdf->getY(); 391 392 // save it 393 $this->value['xc'] = $currentX; 394 $this->value['yc'] = $currentY; 395 396 if ($this->value['position']=='relative' || $this->value['position']=='absolute') { 397 if ($this->value['right']!==null) { 398 $x = $this->getLastWidth(true) - $this->value['right'] - $this->value['width']; 399 if ($this->value['margin']['r']) $x-= $this->value['margin']['r']; 400 } else { 401 $x = $this->value['left']; 402 if ($this->value['margin']['l']) $x+= $this->value['margin']['l']; 403 } 404 405 if ($this->value['bottom']!==null) { 406 $y = $this->getLastHeight(true) - $this->value['bottom'] - $this->value['height']; 407 if ($this->value['margin']['b']) $y-= $this->value['margin']['b']; 408 } else { 409 $y = $this->value['top']; 410 if ($this->value['margin']['t']) $y+= $this->value['margin']['t']; 411 } 412 413 if ($this->value['position']=='relative') { 414 $this->value['x'] = $currentX + $x; 415 $this->value['y'] = $currentY + $y; 416 } else { 417 $this->value['x'] = $this->_getLastAbsoluteX()+$x; 418 $this->value['y'] = $this->_getLastAbsoluteY()+$y; 419 } 420 } else { 421 $this->value['x'] = $currentX; 422 $this->value['y'] = $currentY; 423 if ($this->value['margin']['l']) $this->value['x']+= $this->value['margin']['l']; 424 if ($this->value['margin']['t']) $this->value['y']+= $this->value['margin']['t']; 425 } 426 427 // save the new position 428 $this->_pdf->setXY($this->value['x'], $this->value['y']); 429 } 430 431 /** 432 * Analise the CSS style to convert it into Form style 433 * 434 * @access public 435 * @param array styles 436 */ 437 public function getFormStyle() 438 { 439 $prop = array(); 440 441 $prop['alignment'] = $this->value['text-align']; 442 443 if (isset($this->value['background']['color']) && is_array($this->value['background']['color'])) { 444 $prop['fillColor'] = $this->value['background']['color']; 445 } 446 447 if (isset($this->value['border']['t']['color'])) { 448 $prop['strokeColor'] = $this->value['border']['t']['color']; 449 } 450 451 if (isset($this->value['border']['t']['width'])) { 452 $prop['lineWidth'] = $this->value['border']['t']['width']; 453 } 454 455 if (isset($this->value['border']['t']['type'])) { 456 $prop['borderStyle'] = $this->value['border']['t']['type']; 457 } 458 459 if (!empty($this->value['color'])) { 460 $prop['textColor'] = $this->value['color']; 461 } 462 463 if (!empty($this->value['font-size'])) { 464 $prop['textSize'] = $this->value['font-size']; 465 } 466 467 return $prop; 468 } 469 470 /** 471 * Analise the CSS style to convert it into SVG style 472 * 473 * @access public 474 * @param string tag name 475 * @param array styles 476 */ 477 public function getSvgStyle($tagName, &$param) 478 { 479 // prepare 480 $tagName = strtolower($tagName); 481 $id = isset($param['id']) ? strtolower(trim($param['id'])) : null; if (!$id) $id = null; 482 $name = isset($param['name']) ? strtolower(trim($param['name'])) : null; if (!$name) $name = null; 483 484 // read the class attribute 485 $class = array(); 486 $tmp = isset($param['class']) ? strtolower(trim($param['class'])) : ''; 487 $tmp = explode(' ', $tmp); 488 foreach ($tmp as $k => $v) { 489 $v = trim($v); 490 if ($v) $class[] = $v; 491 } 492 493 // identify the tag, and the direct styles 494 $this->value['id_tag'] = $tagName; 495 $this->value['id_name'] = $name; 496 $this->value['id_id'] = $id; 497 $this->value['id_class'] = $class; 498 $this->value['id_lst'] = array(); 499 $this->value['id_lst'][] = '*'; 500 $this->value['id_lst'][] = $tagName; 501 if (!isset($this->value['svg'])) { 502 $this->value['svg'] = array( 503 'stroke' => null, 504 'stroke-width' => $this->convertToMM('1pt'), 505 'fill' => null, 506 'fill-opacity' => null, 507 ); 508 } 509 510 if (count($class)) { 511 foreach ($class as $v) { 512 $this->value['id_lst'][] = '*.'.$v; 513 $this->value['id_lst'][] = '.'.$v; 514 $this->value['id_lst'][] = $tagName.'.'.$v; 515 } 516 } 517 if ($id) { 518 $this->value['id_lst'][] = '*#'.$id; 519 $this->value['id_lst'][] = '#'.$id; 520 $this->value['id_lst'][] = $tagName.'#'.$id; 521 } 522 523 // CSS style 524 $styles = $this->_getFromCSS(); 525 526 // adding the style from the tag 527 $styles = array_merge($styles, $param['style']); 528 529 if (isset($styles['stroke'])) $this->value['svg']['stroke'] = $this->convertToColor($styles['stroke'], $res); 530 if (isset($styles['stroke-width'])) $this->value['svg']['stroke-width'] = $this->convertToMM($styles['stroke-width']); 531 if (isset($styles['fill'])) $this->value['svg']['fill'] = $this->convertToColor($styles['fill'], $res); 532 if (isset($styles['fill-opacity'])) $this->value['svg']['fill-opacity'] = 1.*$styles['fill-opacity']; 533 534 return $this->value['svg']; 535 } 536 537 /** 538 * analyse the css properties from the HTML parsing 539 * 540 * @access public 541 * @param string $tagName 542 * @param array $param 543 * @param array $legacy 544 */ 545 public function analyse($tagName, &$param, $legacy = null) 546 { 547 // prepare the informations 548 $tagName = strtolower($tagName); 549 $id = isset($param['id']) ? strtolower(trim($param['id'])) : null; if (!$id) $id = null; 550 $name = isset($param['name']) ? strtolower(trim($param['name'])) : null; if (!$name) $name = null; 551 552 // get the class names to use 553 $class = array(); 554 $tmp = isset($param['class']) ? strtolower(trim($param['class'])) : ''; 555 $tmp = explode(' ', $tmp); 556 foreach ($tmp as $k => $v) { 557 $v = trim($v); 558 if ($v) $class[] = $v; 559 } 560 561 // prepare the values, and the list of css tags to identify 562 $this->value['id_tag'] = $tagName; 563 $this->value['id_name'] = $name; 564 $this->value['id_id'] = $id; 565 $this->value['id_class'] = $class; 566 $this->value['id_lst'] = array(); 567 $this->value['id_lst'][] = '*'; 568 $this->value['id_lst'][] = $tagName; 569 if (count($class)) { 570 foreach ($class as $v) { 571 $this->value['id_lst'][] = '*.'.$v; 572 $this->value['id_lst'][] = '.'.$v; 573 $this->value['id_lst'][] = $tagName.'.'.$v; 574 } 575 } 576 if ($id) { 577 $this->value['id_lst'][] = '*#'.$id; 578 $this->value['id_lst'][] = '#'.$id; 579 $this->value['id_lst'][] = $tagName.'#'.$id; 580 } 581 582 // get the css styles from class 583 $styles = $this->_getFromCSS(); 584 585 // merge with the css styles from tag 586 $styles = array_merge($styles, $param['style']); 587 if (isset($param['allwidth']) && !isset($styles['width'])) $styles['width'] = '100%'; 588 589 // reset some styles, depending on the tag name 590 $this->resetStyle($tagName); 591 592 // add the legacy values 593 if ($legacy) { 594 foreach ($legacy as $legacyName => $legacyValue) { 595 if (is_array($legacyValue)) { 596 foreach($legacyValue as $legacy2Name => $legacy2Value) 597 $this->value[$legacyName][$legacy2Name] = $legacy2Value; 598 } else { 599 $this->value[$legacyName] = $legacyValue; 600 } 601 } 602 } 603 604 // some flags 605 $correctWidth = false; 606 $noWidth = true; 607 608 // read all the css styles 609 foreach ($styles as $nom => $val) { 610 switch($nom) 611 { 612 case 'font-family': 613 $val = explode(',', $val); 614 $val = trim($val[0]); 615 if ($val) $this->value['font-family'] = $val; 616 break; 617 618 case 'font-weight': 619 $this->value['font-bold'] = ($val=='bold'); 620 break; 621 622 case 'font-style': 623 $this->value['font-italic'] = ($val=='italic'); 624 break; 625 626 case 'text-decoration': 627 $val = explode(' ', $val); 628 $this->value['font-underline'] = (in_array('underline', $val)); 629 $this->value['font-overline'] = (in_array('overline', $val)); 630 $this->value['font-linethrough'] = (in_array('line-through', $val)); 631 break; 632 633 case 'text-indent': 634 $this->value['text-indent'] = $this->convertToMM($val); 635 break; 636 637 case 'text-transform': 638 if (!in_array($val, array('none', 'capitalize', 'uppercase', 'lowercase'))) $val = 'none'; 639 $this->value['text-transform'] = $val; 640 break; 641 642 case 'font-size': 643 $val = $this->convertToMM($val, $this->value['font-size']); 644 if ($val) $this->value['font-size'] = $val; 645 break; 646 647 case 'color': 648 $res = null; 649 $this->value['color'] = $this->convertToColor($val, $res); 650 if ($tagName=='hr') { 651 $this->value['border']['l']['color'] = $this->value['color']; 652 $this->value['border']['t']['color'] = $this->value['color']; 653 $this->value['border']['r']['color'] = $this->value['color']; 654 $this->value['border']['b']['color'] = $this->value['color']; 655 } 656 break; 657 658 case 'text-align': 659 $val = strtolower($val); 660 if (!in_array($val, array('left', 'right', 'center', 'justify', 'li_right'))) $val = 'left'; 661 $this->value['text-align'] = $val; 662 break; 663 664 case 'vertical-align': 665 $this->value['vertical-align'] = $val; 666 break; 667 668 case 'width': 669 $this->value['width'] = $this->convertToMM($val, $this->getLastWidth()); 670 if ($this->value['width'] && substr($val, -1)=='%') $correctWidth=true; 671 $noWidth = false; 672 break; 673 674 case 'height': 675 $this->value['height'] = $this->convertToMM($val, $this->getLastHeight()); 676 break; 677 678 case 'line-height': 679 if (preg_match('/^[0-9\.]+$/isU', $val)) $val = floor($val*100).'%'; 680 $this->value['line-height'] = $val; 681 break; 682 683 case 'rotate': 684 if (!in_array($val, array(0, -90, 90, 180, 270, -180, -270))) $val = null; 685 if ($val<0) $val+= 360; 686 $this->value['rotate'] = $val; 687 break; 688 689 case 'overflow': 690 if (!in_array($val, array('visible', 'hidden'))) $val = 'visible'; 691 $this->value['overflow'] = $val; 692 break; 693 694 case 'padding': 695 $val = explode(' ', $val); 696 foreach ($val as $k => $v) { 697 $v = trim($v); 698 if ($v!='') { 699 $val[$k] = $v; 700 } else { 701 unset($val[$k]); 702 } 703 } 704 $val = array_values($val); 705 $this->_duplicateBorder($val); 706 $this->value['padding']['t'] = $this->convertToMM($val[0], 0); 707 $this->value['padding']['r'] = $this->convertToMM($val[1], 0); 708 $this->value['padding']['b'] = $this->convertToMM($val[2], 0); 709 $this->value['padding']['l'] = $this->convertToMM($val[3], 0); 710 break; 711 712 case 'padding-top': 713 $this->value['padding']['t'] = $this->convertToMM($val, 0); 714 break; 715 716 case 'padding-right': 717 $this->value['padding']['r'] = $this->convertToMM($val, 0); 718 break; 719 720 case 'padding-bottom': 721 $this->value['padding']['b'] = $this->convertToMM($val, 0); 722 break; 723 724 case 'padding-left': 725 $this->value['padding']['l'] = $this->convertToMM($val, 0); 726 break; 727 728 case 'margin': 729 if ($val=='auto') { 730 $this->value['margin-auto'] = true; 731 break; 732 } 733 $val = explode(' ', $val); 734 foreach ($val as $k => $v) { 735 $v = trim($v); 736 if ($v!='') { 737 $val[$k] = $v; 738 } else { 739 unset($val[$k]); 740 } 741 } 742 $val = array_values($val); 743 $this->_duplicateBorder($val); 744 $this->value['margin']['t'] = $this->convertToMM($val[0], 0); 745 $this->value['margin']['r'] = $this->convertToMM($val[1], 0); 746 $this->value['margin']['b'] = $this->convertToMM($val[2], 0); 747 $this->value['margin']['l'] = $this->convertToMM($val[3], 0); 748 break; 749 750 case 'margin-top': 751 $this->value['margin']['t'] = $this->convertToMM($val, 0); 752 break; 753 754 case 'margin-right': 755 $this->value['margin']['r'] = $this->convertToMM($val, 0); 756 break; 757 758 case 'margin-bottom': 759 $this->value['margin']['b'] = $this->convertToMM($val, 0); 760 break; 761 762 case 'margin-left': 763 $this->value['margin']['l'] = $this->convertToMM($val, 0); 764 break; 765 766 case 'border': 767 $val = $this->readBorder($val); 768 $this->value['border']['t'] = $val; 769 $this->value['border']['r'] = $val; 770 $this->value['border']['b'] = $val; 771 $this->value['border']['l'] = $val; 772 break; 773 774 case 'border-style': 775 $val = explode(' ', $val); 776 foreach ($val as $valK => $valV) { 777 if (!in_array($valV, array('solid', 'dotted', 'dashed'))) { 778 $val[$valK] = null; 779 } 780 } 781 $this->_duplicateBorder($val); 782 if ($val[0]) $this->value['border']['t']['type'] = $val[0]; 783 if ($val[1]) $this->value['border']['r']['type'] = $val[1]; 784 if ($val[2]) $this->value['border']['b']['type'] = $val[2]; 785 if ($val[3]) $this->value['border']['l']['type'] = $val[3]; 786 break; 787 788 case 'border-top-style': 789 if (in_array($val, array('solid', 'dotted', 'dashed'))) { 790 $this->value['border']['t']['type'] = $val; 791 } 792 break; 793 794 case 'border-right-style': 795 if (in_array($val, array('solid', 'dotted', 'dashed'))) { 796 $this->value['border']['r']['type'] = $val; 797 } 798 break; 799 800 case 'border-bottom-style': 801 if (in_array($val, array('solid', 'dotted', 'dashed'))) { 802 $this->value['border']['b']['type'] = $val; 803 } 804 break; 805 806 case 'border-left-style': 807 if (in_array($val, array('solid', 'dotted', 'dashed'))) 808 $this->value['border']['l']['type'] = $val; 809 break; 810 811 case 'border-color': 812 $res = false; 813 $val = preg_replace('/,[\s]+/', ',', $val); 814 $val = explode(' ', $val); 815 foreach ($val as $valK => $valV) { 816 $val[$valK] = $this->convertToColor($valV, $res); 817 if (!$res) { 818 $val[$valK] = null; 819 } 820 } 821 $this->_duplicateBorder($val); 822 if (is_array($val[0])) $this->value['border']['t']['color'] = $val[0]; 823 if (is_array($val[1])) $this->value['border']['r']['color'] = $val[1]; 824 if (is_array($val[2])) $this->value['border']['b']['color'] = $val[2]; 825 if (is_array($val[3])) $this->value['border']['l']['color'] = $val[3]; 826 827 break; 828 829 case 'border-top-color': 830 $res = false; 831 $val = $this->convertToColor($val, $res); 832 if ($res) $this->value['border']['t']['color'] = $val; 833 break; 834 835 case 'border-right-color': 836 $res = false; 837 $val = $this->convertToColor($val, $res); 838 if ($res) $this->value['border']['r']['color'] = $val; 839 break; 840 841 case 'border-bottom-color': 842 $res = false; 843 $val = $this->convertToColor($val, $res); 844 if ($res) $this->value['border']['b']['color'] = $val; 845 break; 846 847 case 'border-left-color': 848 $res = false; 849 $val = $this->convertToColor($val, $res); 850 if ($res) $this->value['border']['l']['color'] = $val; 851 break; 852 853 case 'border-width': 854 $val = explode(' ', $val); 855 foreach ($val as $valK => $valV) { 856 $val[$valK] = $this->convertToMM($valV, 0); 857 } 858 $this->_duplicateBorder($val); 859 if ($val[0]) $this->value['border']['t']['width'] = $val[0]; 860 if ($val[1]) $this->value['border']['r']['width'] = $val[1]; 861 if ($val[2]) $this->value['border']['b']['width'] = $val[2]; 862 if ($val[3]) $this->value['border']['l']['width'] = $val[3]; 863 break; 864 865 case 'border-top-width': 866 $val = $this->convertToMM($val, 0); 867 if ($val) $this->value['border']['t']['width'] = $val; 868 break; 869 870 case 'border-right-width': 871 $val = $this->convertToMM($val, 0); 872 if ($val) $this->value['border']['r']['width'] = $val; 873 break; 874 875 case 'border-bottom-width': 876 $val = $this->convertToMM($val, 0); 877 if ($val) $this->value['border']['b']['width'] = $val; 878 break; 879 880 case 'border-left-width': 881 $val = $this->convertToMM($val, 0); 882 if ($val) $this->value['border']['l']['width'] = $val; 883 break; 884 885 case 'border-collapse': 886 if ($tagName=='table') $this->value['border']['collapse'] = ($val=='collapse'); 887 break; 888 889 case 'border-radius': 890 $val = explode('/', $val); 891 if (count($val)>2) { 892 break; 893 } 894 $valH = $this->convertToRadius(trim($val[0])); 895 if (count($valH)<1 || count($valH)>4) { 896 break; 897 } 898 if (!isset($valH[1])) $valH[1] = $valH[0]; 899 if (!isset($valH[2])) $valH = array($valH[0], $valH[0], $valH[1], $valH[1]); 900 if (!isset($valH[3])) $valH[3] = $valH[1]; 901 if (isset($val[1])) { 902 $valV = $this->convertToRadius(trim($val[1])); 903 if (count($valV)<1 || count($valV)>4) { 904 break; 905 } 906 if (!isset($valV[1])) $valV[1] = $valV[0]; 907 if (!isset($valV[2])) $valV = array($valV[0], $valV[0], $valV[1], $valV[1]); 908 if (!isset($valV[3])) $valV[3] = $valV[1]; 909 } else { 910 $valV = $valH; 911 } 912 $this->value['border']['radius'] = array( 913 'tl' => array($valH[0], $valV[0]), 914 'tr' => array($valH[1], $valV[1]), 915 'br' => array($valH[2], $valV[2]), 916 'bl' => array($valH[3], $valV[3]) 917 ); 918 break; 919 920 case 'border-top-left-radius': 921 $val = $this->convertToRadius($val); 922 if (count($val)<1 || count($val)>2) { 923 break; 924 } 925 $this->value['border']['radius']['tl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); 926 break; 927 928 case 'border-top-right-radius': 929 $val = $this->convertToRadius($val); 930 if (count($val)<1 || count($val)>2) { 931 break; 932 } 933 $this->value['border']['radius']['tr'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); 934 break; 935 936 case 'border-bottom-right-radius': 937 $val = $this->convertToRadius($val); 938 if (count($val)<1 || count($val)>2) { 939 break; 940 } 941 $this->value['border']['radius']['br'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); 942 break; 943 944 case 'border-bottom-left-radius': 945 $val = $this->convertToRadius($val); 946 if (count($val)<1 || count($val)>2) { 947 break; 948 } 949 $this->value['border']['radius']['bl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); 950 break; 951 952 case 'border-top': 953 $this->value['border']['t'] = $this->readBorder($val); 954 break; 955 956 case 'border-right': 957 $this->value['border']['r'] = $this->readBorder($val); 958 break; 959 960 case 'border-bottom': 961 $this->value['border']['b'] = $this->readBorder($val); 962 break; 963 964 case 'border-left': 965 $this->value['border']['l'] = $this->readBorder($val); 966 break; 967 968 case 'background-color': 969 $this->value['background']['color'] = $this->convertBackgroundColor($val); 970 break; 971 972 case 'background-image': 973 $this->value['background']['image'] = $this->convertBackgroundImage($val); 974 break; 975 976 case 'background-position': 977 $res = null; 978 $this->value['background']['position'] = $this->convertBackgroundPosition($val, $res); 979 break; 980 981 case 'background-repeat': 982 $this->value['background']['repeat'] = $this->convertBackgroundRepeat($val); 983 break; 984 985 case 'background': 986 $this->convertBackground($val, $this->value['background']); 987 break; 988 989 case 'position': 990 if ($val=='absolute') $this->value['position'] = 'absolute'; 991 else if ($val=='relative') $this->value['position'] = 'relative'; 992 else $this->value['position'] = null; 993 break; 994 995 case 'float': 996 if ($val=='left') $this->value['float'] = 'left'; 997 else if ($val=='right') $this->value['float'] = 'right'; 998 else $this->value['float'] = null; 999 break; 1000 1001 case 'display': 1002 if ($val=='inline') $this->value['display'] = 'inline'; 1003 else if ($val=='block') $this->value['display'] = 'block'; 1004 else if ($val=='none') $this->value['display'] = 'none'; 1005 else $this->value['display'] = null; 1006 break; 1007 1008 case 'top': 1009 case 'bottom': 1010 case 'left': 1011 case 'right': 1012 $this->value[$nom] = $val; 1013 break; 1014 1015 case 'list-style': 1016 case 'list-style-type': 1017 case 'list-style-image': 1018 if ($nom=='list-style') $nom = 'list-style-type'; 1019 $this->value[$nom] = $val; 1020 break; 1021 1022 default: 1023 break; 1024 } 1025 } 1026 1027 $return = true; 1028 1029 // only for P tag 1030 if ($this->value['margin']['t']===null) $this->value['margin']['t'] = $this->value['font-size']; 1031 if ($this->value['margin']['b']===null) $this->value['margin']['b'] = $this->value['font-size']; 1032 1033 // force the text align to left, if asked by html2pdf 1034 if ($this->_onlyLeft) $this->value['text-align'] = 'left'; 1035 1036 // correction on the width (quick box) 1037 if ($noWidth && in_array($tagName, array('div', 'blockquote', 'fieldset')) && $this->value['position']!='absolute') { 1038 $this->value['width'] = $this->getLastWidth(); 1039 $this->value['width']-= $this->value['margin']['l'] + $this->value['margin']['r']; 1040 } else { 1041 if ($correctWidth) { 1042 if (!in_array($tagName, array('table', 'div', 'blockquote', 'fieldset', 'hr'))) { 1043 $this->value['width']-= $this->value['padding']['l'] + $this->value['padding']['r']; 1044 $this->value['width']-= $this->value['border']['l']['width'] + $this->value['border']['r']['width']; 1045 } 1046 if (in_array($tagName, array('th', 'td'))) { 1047 $this->value['width']-= $this->convertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px'); 1048 $return = false; 1049 } 1050 if ($this->value['width']<0) $this->value['width']=0; 1051 } else { 1052 if ($this->value['width']) { 1053 if ($this->value['border']['l']['width']) $this->value['width'] += $this->value['border']['l']['width']; 1054 if ($this->value['border']['r']['width']) $this->value['width'] += $this->value['border']['r']['width']; 1055 if ($this->value['padding']['l']) $this->value['width'] += $this->value['padding']['l']; 1056 if ($this->value['padding']['r']) $this->value['width'] += $this->value['padding']['r']; 1057 } 1058 } 1059 } 1060 if ($this->value['height']) { 1061 if ($this->value['border']['b']['width']) $this->value['height'] += $this->value['border']['b']['width']; 1062 if ($this->value['border']['t']['width']) $this->value['height'] += $this->value['border']['t']['width']; 1063 if ($this->value['padding']['b']) $this->value['height'] += $this->value['padding']['b']; 1064 if ($this->value['padding']['t']) $this->value['height'] += $this->value['padding']['t']; 1065 } 1066 1067 if ($this->value['top']!=null) $this->value['top'] = $this->convertToMM($this->value['top'], $this->getLastHeight(true)); 1068 if ($this->value['bottom']!=null) $this->value['bottom'] = $this->convertToMM($this->value['bottom'], $this->getLastHeight(true)); 1069 if ($this->value['left']!=null) $this->value['left'] = $this->convertToMM($this->value['left'], $this->getLastWidth(true)); 1070 if ($this->value['right']!=null) $this->value['right'] = $this->convertToMM($this->value['right'], $this->getLastWidth(true)); 1071 1072 if ($this->value['top'] && $this->value['bottom'] && $this->value['height']) $this->value['bottom'] = null; 1073 if ($this->value['left'] && $this->value['right'] && $this->value['width']) $this->value['right'] = null; 1074 1075 return $return; 1076 } 1077 1078 /** 1079 * get the height of the current line 1080 * 1081 * @access public 1082 * @return float $height in mm 1083 */ 1084 public function getLineHeight() 1085 { 1086 $val = $this->value['line-height']; 1087 if ($val=='normal') $val = '108%'; 1088 return $this->convertToMM($val, $this->value['font-size']); 1089 } 1090 1091 /** 1092 * get the width of the parent 1093 * 1094 * @access public 1095 * @param boolean $mode true => adding padding and border 1096 * @return float $width in mm 1097 */ 1098 public function getLastWidth($mode = false) 1099 { 1100 for ($k=count($this->table)-1; $k>=0; $k--) { 1101 if ($this->table[$k]['width']) { 1102 $w = $this->table[$k]['width']; 1103 if ($mode) { 1104 $w+= $this->table[$k]['border']['l']['width'] + $this->table[$k]['padding']['l'] + 0.02; 1105 $w+= $this->table[$k]['border']['r']['width'] + $this->table[$k]['padding']['r'] + 0.02; 1106 } 1107 return $w; 1108 } 1109 } 1110 return $this->_pdf->getW() - $this->_pdf->getlMargin() - $this->_pdf->getrMargin(); 1111 } 1112 1113 /** 1114 * get the height of the parent 1115 * 1116 * @access public 1117 * @param boolean $mode true => adding padding and border 1118 * @return float $height in mm 1119 */ 1120 public function getLastHeight($mode = false) 1121 { 1122 for ($k=count($this->table)-1; $k>=0; $k--) { 1123 if ($this->table[$k]['height']) { 1124 $h = $this->table[$k]['height']; 1125 if ($mode) { 1126 $h+= $this->table[$k]['border']['t']['width'] + $this->table[$k]['padding']['t'] + 0.02; 1127 $h+= $this->table[$k]['border']['b']['width'] + $this->table[$k]['padding']['b'] + 0.02; 1128 } 1129 return $h; 1130 } 1131 } 1132 return $this->_pdf->getH() - $this->_pdf->gettMargin() - $this->_pdf->getbMargin(); 1133 } 1134 1135 /** 1136 * get the value of the float property 1137 * 1138 * @access public 1139 * @return $float left/right 1140 */ 1141 public function getFloat() 1142 { 1143 if ($this->value['float']=='left') return 'left'; 1144 if ($this->value['float']=='right') return 'right'; 1145 return null; 1146 } 1147 1148 /** 1149 * get the last value for a specific key 1150 * 1151 * @access public 1152 * @param string $key 1153 * @return mixed 1154 */ 1155 public function getLastValue($key) 1156 { 1157 $nb = count($this->table); 1158 if ($nb>0) { 1159 return $this->table[$nb-1][$key]; 1160 } else { 1161 return null; 1162 } 1163 } 1164 1165 /** 1166 * get the last absolute X 1167 * 1168 * @access protected 1169 * @return float $x 1170 */ 1171 protected function _getLastAbsoluteX() 1172 { 1173 for ($k=count($this->table)-1; $k>=0; $k--) { 1174 if ($this->table[$k]['x'] && $this->table[$k]['position']) return $this->table[$k]['x']; 1175 } 1176 return $this->_pdf->getlMargin(); 1177 } 1178 1179 /** 1180 * get the last absolute Y 1181 * 1182 * @access protected 1183 * @return float $y 1184 */ 1185 protected function _getLastAbsoluteY() 1186 { 1187 for ($k=count($this->table)-1; $k>=0; $k--) { 1188 if ($this->table[$k]['y'] && $this->table[$k]['position']) return $this->table[$k]['y']; 1189 } 1190 return $this->_pdf->gettMargin(); 1191 } 1192 1193 /** 1194 * get the CSS properties of the current tag 1195 * 1196 * @access protected 1197 * @return array $styles 1198 */ 1199 protected function _getFromCSS() 1200 { 1201 // styles to apply 1202 $styles = array(); 1203 1204 // list of the selectors to get in the CSS files 1205 $getit = array(); 1206 1207 // get the list of the selectors of each tags 1208 $lst = array(); 1209 $lst[] = $this->value['id_lst']; 1210 for ($i=count($this->table)-1; $i>=0; $i--) { 1211 $lst[] = $this->table[$i]['id_lst']; 1212 } 1213 1214 // foreach selectors in the CSS files, verify if it match with the list of selectors 1215 foreach ($this->cssKeys as $key => $num) { 1216 if ($this->_getReccursiveStyle($key, $lst)) { 1217 $getit[$key] = $num; 1218 } 1219 } 1220 1221 // if we have selectors 1222 if (count($getit)) { 1223 // get them, but in the definition order, because of priority 1224 asort($getit); 1225 foreach ($getit as $key => $val) $styles = array_merge($styles, $this->css[$key]); 1226 } 1227 1228 return $styles; 1229 } 1230 1231 /** 1232 * identify if the selector $key match with the list of tag selectors 1233 * 1234 * @access protected 1235 * @param string $key CSS selector to analyse 1236 * @param array $lst list of the selectors of each tags 1237 * @param string $next next step of parsing the selector 1238 * @return boolean 1239 */ 1240 protected function _getReccursiveStyle($key, $lst, $next = null) 1241 { 1242 // if next step 1243 if ($next!==null) { 1244 // we remove this step 1245 if ($next) $key = trim(substr($key, 0, -strlen($next))); 1246 array_shift($lst); 1247 1248 // if no more step to identify => return false 1249 if (!count($lst)) { 1250 return false; 1251 } 1252 } 1253 1254 // for each selector of the current step 1255 foreach ($lst[0] as $name) { 1256 // if selector = key => ok 1257 if ($key==$name) { 1258 return true; 1259 } 1260 1261 // if the end of the key = the selector and the next step is ok => ok 1262 if (substr($key, -strlen(' '.$name))==' '.$name && $this->_getReccursiveStyle($key, $lst, $name)) { 1263 return true; 1264 } 1265 } 1266 1267 // if we are not in the first step, we analyse the sub steps (the pareng tag of the current tag) 1268 if ($next!==null && $this->_getReccursiveStyle($key, $lst, '')) { 1269 return true; 1270 } 1271 1272 // no corresponding found 1273 return false; 1274 } 1275 1276 /** 1277 * Analyse a border 1278 * 1279 * @access public 1280 * @param string $css css border properties 1281 * @return array border properties 1282 */ 1283 public function readBorder($css) 1284 { 1285 // border none 1286 $none = array('type' => 'none', 'width' => 0, 'color' => array(0, 0, 0)); 1287 1288 // default value 1289 $type = 'solid'; 1290 $width = $this->convertToMM('1pt'); 1291 $color = array(0, 0, 0); 1292 1293 // clean up the values 1294 $css = explode(' ', $css); 1295 foreach ($css as $k => $v) { 1296 $v = trim($v); 1297 if ($v) $css[$k] = $v; 1298 else unset($css[$k]); 1299 } 1300 $css = array_values($css); 1301 1302 // read the values 1303 $res = null; 1304 foreach ($css as $value) { 1305 1306 // if no border => return none 1307 if ($value=='none' || $value=='hidden') { 1308 return $none; 1309 } 1310 1311 // try to convert the value as a distance 1312 $tmp = $this->convertToMM($value); 1313 1314 // if the convert is ok => it is a width 1315 if ($tmp!==null) { 1316 $width = $tmp; 1317 // else, it could be the type 1318 } else if (in_array($value, array('solid', 'dotted', 'dashed', 'double'))) { 1319 $type = $value; 1320 // else, it could be the color 1321 } else { 1322 $tmp = $this->convertToColor($value, $res); 1323 if ($res) $color = $tmp; 1324 } 1325 } 1326 1327 // if no witdh => return none 1328 if (!$width) return $none; 1329 1330 // return the border properties 1331 return array('type' => $type, 'width' => $width, 'color' => $color); 1332 } 1333 1334 /** 1335 * duplicate the borders if needed 1336 * 1337 * @access protected 1338 * @param &array $val 1339 */ 1340 protected function _duplicateBorder(&$val) 1341 { 1342 // 1 value => L => RTB 1343 if (count($val)==1) { 1344 $val[1] = $val[0]; 1345 $val[2] = $val[0]; 1346 $val[3] = $val[0]; 1347 // 2 values => L => R & T => B 1348 } else if (count($val)==2) { 1349 $val[2] = $val[0]; 1350 $val[3] = $val[1]; 1351 // 3 values => T => B 1352 } else if (count($val)==3) { 1353 $val[3] = $val[1]; 1354 } 1355 } 1356 1357 /** 1358 * Analyse a background 1359 * 1360 * @access public 1361 * @param string $css css background properties 1362 * @param &array $value parsed values (by reference, because, ther is a legacy of the parent CSS properties) 1363 */ 1364 public function convertBackground($css, &$value) 1365 { 1366 // is there a image ? 1367 $text = '/url\(([^)]*)\)/isU'; 1368 if (preg_match($text, $css, $match)) { 1369 // get the image 1370 $value['image'] = $this->convertBackgroundImage($match[0]); 1371 1372 // remove if from the css properties 1373 $css = preg_replace($text, '', $css); 1374 $css = preg_replace('/[\s]+/', ' ', $css); 1375 } 1376 1377 // protect some spaces 1378 $css = preg_replace('/,[\s]+/', ',', $css); 1379 1380 // explode the values 1381 $css = explode(' ', $css); 1382 1383 // background position to parse 1384 $pos = ''; 1385 1386 // foreach value 1387 foreach ($css as $val) { 1388 // try to parse the value as a color 1389 $ok = false; 1390 $color = $this->convertToColor($val, $ok); 1391 1392 // if ok => it is a color 1393 if ($ok) { 1394 $value['color'] = $color; 1395 // else if transparent => no coloà r 1396 } else if ($val=='transparent') { 1397 $value['color'] = null; 1398 // else 1399 } else { 1400 // try to parse the value as a repeat 1401 $repeat = $this->convertBackgroundRepeat($val); 1402 1403 // if ok => it is repeat 1404 if ($repeat) { 1405 $value['repeat'] = $repeat; 1406 // else => it could only be a position 1407 } else { 1408 $pos.= ($pos ? ' ' : '').$val; 1409 } 1410 } 1411 } 1412 1413 // if we have a position to parse 1414 if ($pos) { 1415 // try to read it 1416 $pos = $this->convertBackgroundPosition($pos, $ok); 1417 if ($ok) $value['position'] = $pos; 1418 } 1419 } 1420 1421 /** 1422 * parse a background color 1423 * 1424 * @access public 1425 * @param string $css 1426 * @return string $value 1427 */ 1428 public function convertBackgroundColor($css) 1429 { 1430 $res = null; 1431 if ($css=='transparent') return null; 1432 else return $this->convertToColor($css, $res); 1433 } 1434 1435 /** 1436 * parse a background image 1437 * 1438 * @access public 1439 * @param string $css 1440 * @return string $value 1441 */ 1442 public function convertBackgroundImage($css) 1443 { 1444 if ($css=='none') 1445 return null; 1446 else if (preg_match('/^url\(([^)]*)\)$/isU', $css, $match)) 1447 return $match[1]; 1448 else 1449 return null; 1450 } 1451 1452 /** 1453 * parse a background position 1454 * 1455 * @access public 1456 * @param string $css 1457 * @param &boolean $res flag if conver is ok or not 1458 * @return array ($x, $y) 1459 */ 1460 public function convertBackgroundPosition($css, &$res) 1461 { 1462 // init the res 1463 $res = false; 1464 1465 // explode the value 1466 $css = explode(' ', $css); 1467 1468 // we must have 2 values. if 0 or >2 : error. if 1 => put center for 2 1469 if (count($css)<2) { 1470 if (!$css[0]) return null; 1471 $css[1] = 'center'; 1472 } 1473 if (count($css)>2) return null; 1474 1475 // prepare the values 1476 $x = 0; 1477 $y = 0; 1478 $res = true; 1479 1480 // convert the first value 1481 if ($css[0]=='left') $x = '0%'; 1482 else if ($css[0]=='center') $x = '50%'; 1483 else if ($css[0]=='right') $x = '100%'; 1484 else if ($css[0]=='top') $y = '0%'; 1485 else if ($css[0]=='bottom') $y = '100%'; 1486 else if (preg_match('/^[-]?[0-9\.]+%$/isU', $css[0])) $x = $css[0]; 1487 else if ($this->convertToMM($css[0])) $x = $this->convertToMM($css[0]); 1488 else $res = false; 1489 1490 // convert the second value 1491 if ($css[1]=='left') $x = '0%'; 1492 else if ($css[1]=='right') $x = '100%'; 1493 else if ($css[1]=='top') $y = '0%'; 1494 else if ($css[1]=='center') $y = '50%'; 1495 else if ($css[1]=='bottom') $y = '100%'; 1496 else if (preg_match('/^[-]?[0-9\.]+%$/isU', $css[1])) $y = $css[1]; 1497 else if ($this->convertToMM($css[1])) $y = $this->convertToMM($css[1]); 1498 else $res = false; 1499 1500 // return the values 1501 return array($x, $y); 1502 } 1503 1504 /** 1505 * parse a background repeat 1506 * 1507 * @access public 1508 * @param string $css 1509 * @return string $value 1510 */ 1511 public function convertBackgroundRepeat($css) 1512 { 1513 switch($css) 1514 { 1515 case 'repeat': 1516 return array(true, true); 1517 case 'repeat-x': 1518 return array(true, false); 1519 case 'repeat-y': 1520 return array(false, true); 1521 case 'no-repeat': 1522 return array(false, false); 1523 } 1524 return null; 1525 } 1526 1527 /** 1528 * convert a distance to mm 1529 * 1530 * @access public 1531 * @param string $css distance to convert 1532 * @param float $old parent distance 1533 * @return float $value 1534 */ 1535 public function convertToMM($css, $old=0.) 1536 { 1537 $css = trim($css); 1538 if (preg_match('/^[0-9\.\-]+$/isU', $css)) $css.= 'px'; 1539 if (preg_match('/^[0-9\.\-]+px$/isU', $css)) $css = 25.4/96. * str_replace('px', '', $css); 1540 else if (preg_match('/^[0-9\.\-]+pt$/isU', $css)) $css = 25.4/72. * str_replace('pt', '', $css); 1541 else if (preg_match('/^[0-9\.\-]+in$/isU', $css)) $css = 25.4 * str_replace('in', '', $css); 1542 else if (preg_match('/^[0-9\.\-]+mm$/isU', $css)) $css = 1.*str_replace('mm', '', $css); 1543 else if (preg_match('/^[0-9\.\-]+%$/isU', $css)) $css = 1.*$old*str_replace('%', '', $css)/100.; 1544 else $css = null; 1545 1546 return $css; 1547 } 1548 1549 /** 1550 * convert a css radius 1551 * 1552 * @access public 1553 * @param string $css 1554 * @return float $value 1555 */ 1556 public function convertToRadius($css) 1557 { 1558 // explode the value 1559 $css = explode(' ', $css); 1560 1561 foreach ($css as $k => $v) { 1562 $v = trim($v); 1563 if ($v) { 1564 $v = $this->convertToMM($v, 0); 1565 if ($v!==null) { 1566 $css[$k] = $v; 1567 } else { 1568 unset($css[$k]); 1569 } 1570 } else { 1571 unset($css[$k]); 1572 } 1573 } 1574 1575 return array_values($css); 1576 } 1577 1578 /** 1579 * convert a css color 1580 * 1581 * @access public 1582 * @param string $css 1583 * @param &boolean $res 1584 * @return array (r,g, b) 1585 */ 1586 public function convertToColor($css, &$res) 1587 { 1588 // prepare the value 1589 $css = trim($css); 1590 $res = true; 1591 1592 // if transparent => return null 1593 if (strtolower($css)=='transparent') return array(null, null, null); 1594 1595 // HTML color 1596 if (isset($this->_htmlColor[strtolower($css)])) { 1597 $css = $this->_htmlColor[strtolower($css)]; 1598 $r = floatVal(hexdec(substr($css, 0, 2))); 1599 $v = floatVal(hexdec(substr($css, 2, 2))); 1600 $b = floatVal(hexdec(substr($css, 4, 2))); 1601 return array($r, $v, $b); 1602 } 1603 1604 // like #FFFFFF 1605 if (preg_match('/^#[0-9A-Fa-f]{6}$/isU', $css)) { 1606 $r = floatVal(hexdec(substr($css, 1, 2))); 1607 $v = floatVal(hexdec(substr($css, 3, 2))); 1608 $b = floatVal(hexdec(substr($css, 5, 2))); 1609 return array($r, $v, $b); 1610 } 1611 1612 // like #FFF 1613 if (preg_match('/^#[0-9A-F]{3}$/isU', $css)) { 1614 $r = floatVal(hexdec(substr($css, 1, 1).substr($css, 1, 1))); 1615 $v = floatVal(hexdec(substr($css, 2, 1).substr($css, 2, 1))); 1616 $b = floatVal(hexdec(substr($css, 3, 1).substr($css, 3, 1))); 1617 return array($r, $v, $b); 1618 } 1619 1620 // like rgb(100, 100, 100) 1621 if (preg_match('/rgb\([\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*\)/isU', $css, $match)) { 1622 $r = $this->_convertSubColor($match[1]); 1623 $v = $this->_convertSubColor($match[2]); 1624 $b = $this->_convertSubColor($match[3]); 1625 return array($r*255., $v*255., $b*255.); 1626 } 1627 1628 // like cmyk(100, 100, 100, 100) 1629 if (preg_match('/cmyk\([\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*,[\s]*([0-9%\.]+)[\s]*\)/isU', $css, $match)) { 1630 $c = $this->_convertSubColor($match[1]); 1631 $m = $this->_convertSubColor($match[2]); 1632 $y = $this->_convertSubColor($match[3]); 1633 $k = $this->_convertSubColor($match[4]); 1634 return array($c*100., $m*100., $y*100., $k*100.); 1635 } 1636 1637 $res = false; 1638 return array(0., 0., 0.); 1639 } 1640 1641 /** 1642 * color value to convert 1643 * 1644 * @access protected 1645 * @param string $c 1646 * @return float $c 0.->1. 1647 */ 1648 protected function _convertSubColor($c) 1649 { 1650 if (substr($c, -1)=='%') { 1651 $c = floatVal(substr($c, 0, -1))/100.; 1652 } else { 1653 $c = floatVal($c); 1654 if ($c>1) $c = $c/255.; 1655 } 1656 1657 return $c; 1658 } 1659 1660 /** 1661 * read a css content 1662 * 1663 * @access protected 1664 * @param &string $code 1665 */ 1666 protected function _analyseStyle(&$code) 1667 { 1668 // clean the spaces 1669 $code = preg_replace('/[\s]+/', ' ', $code); 1670 1671 // remove the comments 1672 $code = preg_replace('/\/\*.*?\*\//s', '', $code); 1673 1674 // split each CSS code "selector { value }" 1675 preg_match_all('/([^{}]+){([^}]*)}/isU', $code, $match); 1676 1677 // for each CSS code 1678 for ($k=0; $k<count($match[0]); $k++) { 1679 1680 // selectors 1681 $names = strtolower(trim($match[1][$k])); 1682 1683 // css style 1684 $styles = trim($match[2][$k]); 1685 1686 // explode each value 1687 $styles = explode(';', $styles); 1688 1689 // parse each value 1690 $css = array(); 1691 foreach ($styles as $style) { 1692 $tmp = explode(':', $style); 1693 if (count($tmp)>1) { 1694 $cod = $tmp[0]; unset($tmp[0]); $tmp = implode(':', $tmp); 1695 $css[trim(strtolower($cod))] = trim($tmp); 1696 } 1697 } 1698 1699 // explode the names 1700 $names = explode(',', $names); 1701 1702 // save the values for each names 1703 foreach ($names as $name) { 1704 // clean the name 1705 $name = trim($name); 1706 1707 // if a selector with somethink lige :hover => continue 1708 if (strpos($name, ':')!==false) continue; 1709 1710 // save the value 1711 if (!isset($this->css[$name])) 1712 $this->css[$name] = $css; 1713 else 1714 $this->css[$name] = array_merge($this->css[$name], $css); 1715 1716 } 1717 } 1718 1719 // get he list of the keys 1720 $this->cssKeys = array_flip(array_keys($this->css)); 1721 } 1722 1723 /** 1724 * Extract the css files from a html code 1725 * 1726 * @access public 1727 * @param string &$html 1728 */ 1729 public function readStyle(&$html) 1730 { 1731 // the CSS content 1732 $style = ' '; 1733 1734 // extract the link tags, and remove them in the html code 1735 preg_match_all('/<link([^>]*)>/isU', $html, $match); 1736 $html = preg_replace('/<link[^>]*>/isU', '', $html); 1737 $html = preg_replace('/<\/link[^>]*>/isU', '', $html); 1738 1739 // analyse each link tag 1740 foreach ($match[1] as $code) { 1741 $tmp = array(); 1742 1743 // read the attributes name=value 1744 $prop = '([a-zA-Z0-9_]+)=([^"\'\s>]+)'; 1745 preg_match_all('/'.$prop.'/is', $code, $match); 1746 for ($k=0; $k<count($match[0]); $k++) { 1747 $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]); 1748 } 1749 1750 // read the attributes name="value" 1751 $prop = '([a-zA-Z0-9_]+)=["]([^"]*)["]'; 1752 preg_match_all('/'.$prop.'/is', $code, $match); 1753 for ($k=0; $k<count($match[0]); $k++) { 1754 $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]); 1755 } 1756 1757 // read the attributes name='value' 1758 $prop = "([a-zA-Z0-9_]+)=[']([^']*)[']"; 1759 preg_match_all('/'.$prop.'/is', $code, $match); 1760 for ($k=0; $k<count($match[0]); $k++) { 1761 $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]); 1762 } 1763 1764 // if type text/css => we keep it 1765 if (isset($tmp['type']) && strtolower($tmp['type'])=='text/css' && isset($tmp['href'])) { 1766 1767 // get the href 1768 $url = $tmp['href']; 1769 1770 // get the content of the css file 1771 $content = @file_get_contents($url); 1772 1773 // if "http://" in the url 1774 if (strpos($url, 'http://')!==false) { 1775 1776 // get the domain "http://xxx/" 1777 $url = str_replace('http://', '', $url); 1778 $url = explode('/', $url); 1779 $urlMain = 'http://'.$url[0].'/'; 1780 1781 // get the absolute url of the path 1782 $urlSelf = $url; unset($urlSelf[count($urlSelf)-1]); $urlSelf = 'http://'.implode('/', $urlSelf).'/'; 1783 1784 // adapt the url in the css content 1785 $content = preg_replace('/url\(([^\\\\][^)]*)\)/isU', 'url('.$urlSelf.'$1)', $content); 1786 $content = preg_replace('/url\((\\\\[^)]*)\)/isU', 'url('.$urlMain.'$1)', $content); 1787 } else { 1788 // @TODO correction on url in absolute on a local css content 1789 // $content = preg_replace('/url\(([^)]*)\)/isU', 'url('.dirname($url).'/$1)', $content); 1790 } 1791 1792 // add to the CSS content 1793 $style.= $content."\n"; 1794 } 1795 } 1796 1797 // extract the style tags des tags style, and remove them in the html code 1798 preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match); 1799 $html = preg_replace('/<style[^>]*>(.*)<\/style[^>]*>/isU', '', $html); 1800 1801 // analyse each style tags 1802 foreach ($match[1] as $code) { 1803 // add to the CSS content 1804 $code = str_replace('<!--', '', $code); 1805 $code = str_replace('-->', '', $code); 1806 $style.= $code."\n"; 1807 } 1808 1809 //analyse the css content 1810 $this->_analyseStyle($style); 1811 } 1812 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |