mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-31 01:34:09 +02:00
parent
208e49a616
commit
9acc8ee7a9
@ -3,13 +3,32 @@
|
||||
|
||||
namespace Icinga\File;
|
||||
|
||||
use Dompdf\Autoloader;
|
||||
use Dompdf\Dompdf;
|
||||
use Dompdf\Options;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
require_once 'dompdf/autoload.inc.php';
|
||||
call_user_func(function () {
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @author Alexander A. Klimov <alexander.klimov@icinga.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
$baseDir = __DIR__ . '/../../vendor/dompdf';
|
||||
|
||||
require_once "$baseDir/lib/html5lib/Parser.php";
|
||||
require_once "$baseDir/lib/php-font-lib/src/FontLib/Autoloader.php";
|
||||
require_once "$baseDir/lib/php-svg-lib/src/autoload.php";
|
||||
require_once "$baseDir/src/Autoloader.php";
|
||||
|
||||
Autoloader::register();
|
||||
});
|
||||
|
||||
class Pdf
|
||||
{
|
||||
|
6
library/vendor/dompdf/SOURCE
vendored
6
library/vendor/dompdf/SOURCE
vendored
@ -1,8 +1,8 @@
|
||||
GLOBIGNORE=$0; rm -rf *
|
||||
|
||||
curl https://codeload.github.com/dompdf/dompdf/tar.gz/v0.7.0 -o dompdf-0.7.0.tar.gz
|
||||
tar xzf dompdf-0.7.0.tar.gz --strip-components 1 dompdf-0.7.0/{lib,src,autoload.inc.php,LICENSE.LGPL}
|
||||
rm dompdf-0.7.0.tar.gz
|
||||
curl https://codeload.github.com/dompdf/dompdf/tar.gz/v0.8.2 -o dompdf-0.8.2.tar.gz
|
||||
tar xzf dompdf-0.8.2.tar.gz --strip-components 1 dompdf-0.8.2/{lib,src,LICENSE.LGPL}
|
||||
rm dompdf-0.8.2.tar.gz
|
||||
mv LICENSE.LGPL LICENSE
|
||||
|
||||
curl https://codeload.github.com/PhenX/php-font-lib/tar.gz/0.4 -o php-font-lib-0.4.tar.gz
|
||||
|
28
library/vendor/dompdf/autoload.inc.php
vendored
28
library/vendor/dompdf/autoload.inc.php
vendored
@ -1,28 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dompdf autoload function
|
||||
*
|
||||
* If you have an existing autoload function, add a call to this function
|
||||
* from your existing __autoload() implementation.
|
||||
*
|
||||
* @param string $class
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/lib/html5lib/Parser.php';
|
||||
require_once __DIR__ . '/lib/php-font-lib/src/FontLib/Autoloader.php';
|
||||
require_once __DIR__ . '/lib/php-svg-lib/src/autoload.php';
|
||||
|
||||
/*
|
||||
* New PHP 5.3.0 namespaced autoloader
|
||||
*/
|
||||
require_once __DIR__ . '/src/Autoloader.php';
|
||||
|
||||
Dompdf\Autoloader::register();
|
978
library/vendor/dompdf/lib/Cpdf.php
vendored
978
library/vendor/dompdf/lib/Cpdf.php
vendored
File diff suppressed because it is too large
Load Diff
@ -130,7 +130,7 @@ C 167 ; WX 600 ; N section ; B 83 -70 517 580 ;
|
||||
C 164 ; WX 600 ; N currency ; B 54 49 546 517 ;
|
||||
C 39 ; WX 600 ; N quotesingle ; B 227 277 373 562 ;
|
||||
C 147 ; WX 600 ; N quotedblleft ; B 71 277 535 562 ;
|
||||
C 170 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
|
||||
C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
|
||||
C 139 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ;
|
||||
C 155 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ;
|
||||
C -1 ; WX 600 ; N fi ; B 12 0 593 626 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 600 ; N section ; B 74 -70 620 580 ;
|
||||
C 164 ; WX 600 ; N currency ; B 77 49 644 517 ;
|
||||
C 39 ; WX 600 ; N quotesingle ; B 303 277 493 562 ;
|
||||
C 147 ; WX 600 ; N quotedblleft ; B 190 277 594 562 ;
|
||||
C 170 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ;
|
||||
C 171 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ;
|
||||
C 139 ; WX 600 ; N guilsinglleft ; B 195 70 545 446 ;
|
||||
C 155 ; WX 600 ; N guilsinglright ; B 165 70 514 446 ;
|
||||
C -1 ; WX 600 ; N fi ; B 12 0 644 626 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 600 ; N section ; B 104 -78 590 580 ;
|
||||
C 164 ; WX 600 ; N currency ; B 94 58 628 506 ;
|
||||
C 39 ; WX 600 ; N quotesingle ; B 345 328 460 562 ;
|
||||
C 147 ; WX 600 ; N quotedblleft ; B 262 328 541 562 ;
|
||||
C 170 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
|
||||
C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
|
||||
C 139 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ;
|
||||
C 155 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ;
|
||||
C -1 ; WX 600 ; N fi ; B 3 0 619 629 ;
|
||||
|
2
library/vendor/dompdf/lib/fonts/Courier.afm
vendored
2
library/vendor/dompdf/lib/fonts/Courier.afm
vendored
@ -130,7 +130,7 @@ C 167 ; WX 600 ; N section ; B 113 -78 488 580 ;
|
||||
C 164 ; WX 600 ; N currency ; B 73 58 527 506 ;
|
||||
C 39 ; WX 600 ; N quotesingle ; B 259 328 341 562 ;
|
||||
C 147 ; WX 600 ; N quotedblleft ; B 143 328 471 562 ;
|
||||
C 170 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
|
||||
C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
|
||||
C 139 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ;
|
||||
C 155 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ;
|
||||
C -1 ; WX 600 ; N fi ; B 3 0 597 629 ;
|
||||
|
BIN
library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ttf
vendored
BIN
library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ttf
vendored
Binary file not shown.
9002
library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ufm
vendored
9002
library/vendor/dompdf/lib/fonts/DejaVuSans-Bold.ufm
vendored
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
8050
library/vendor/dompdf/lib/fonts/DejaVuSans-Oblique.ufm
vendored
8050
library/vendor/dompdf/lib/fonts/DejaVuSans-Oblique.ufm
vendored
File diff suppressed because it is too large
Load Diff
BIN
library/vendor/dompdf/lib/fonts/DejaVuSans.ttf
vendored
BIN
library/vendor/dompdf/lib/fonts/DejaVuSans.ttf
vendored
Binary file not shown.
9140
library/vendor/dompdf/lib/fonts/DejaVuSans.ufm
vendored
9140
library/vendor/dompdf/lib/fonts/DejaVuSans.ufm
vendored
File diff suppressed because it is too large
Load Diff
Binary file not shown.
4906
library/vendor/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm
vendored
4906
library/vendor/dompdf/lib/fonts/DejaVuSansMono-Bold.ufm
vendored
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
library/vendor/dompdf/lib/fonts/DejaVuSansMono.ttf
vendored
BIN
library/vendor/dompdf/lib/fonts/DejaVuSansMono.ttf
vendored
Binary file not shown.
5032
library/vendor/dompdf/lib/fonts/DejaVuSansMono.ufm
vendored
5032
library/vendor/dompdf/lib/fonts/DejaVuSansMono.ufm
vendored
File diff suppressed because it is too large
Load Diff
BIN
library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ttf
vendored
BIN
library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ttf
vendored
Binary file not shown.
5011
library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ufm
vendored
5011
library/vendor/dompdf/lib/fonts/DejaVuSerif-Bold.ufm
vendored
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
5131
library/vendor/dompdf/lib/fonts/DejaVuSerif-Italic.ufm
vendored
5131
library/vendor/dompdf/lib/fonts/DejaVuSerif-Italic.ufm
vendored
File diff suppressed because it is too large
Load Diff
BIN
library/vendor/dompdf/lib/fonts/DejaVuSerif.ttf
vendored
BIN
library/vendor/dompdf/lib/fonts/DejaVuSerif.ttf
vendored
Binary file not shown.
5160
library/vendor/dompdf/lib/fonts/DejaVuSerif.ufm
vendored
5160
library/vendor/dompdf/lib/fonts/DejaVuSerif.ufm
vendored
File diff suppressed because it is too large
Load Diff
@ -130,7 +130,7 @@ C 167 ; WX 556 ; N section ; B 34 -184 522 727 ;
|
||||
C 164 ; WX 556 ; N currency ; B -3 76 559 636 ;
|
||||
C 39 ; WX 238 ; N quotesingle ; B 70 447 168 718 ;
|
||||
C 147 ; WX 500 ; N quotedblleft ; B 64 454 436 727 ;
|
||||
C 170 ; WX 556 ; N guillemotleft ; B 88 76 468 484 ;
|
||||
C 171 ; WX 556 ; N guillemotleft ; B 88 76 468 484 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 83 76 250 484 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 83 76 250 484 ;
|
||||
C -1 ; WX 611 ; N fi ; B 10 0 542 727 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 556 ; N section ; B 61 -184 598 727 ;
|
||||
C 164 ; WX 556 ; N currency ; B 27 76 680 636 ;
|
||||
C 39 ; WX 238 ; N quotesingle ; B 165 447 321 718 ;
|
||||
C 147 ; WX 500 ; N quotedblleft ; B 160 454 588 727 ;
|
||||
C 170 ; WX 556 ; N guillemotleft ; B 135 76 571 484 ;
|
||||
C 171 ; WX 556 ; N guillemotleft ; B 135 76 571 484 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 130 76 353 484 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 99 76 322 484 ;
|
||||
C -1 ; WX 611 ; N fi ; B 87 0 696 727 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 556 ; N section ; B 76 -191 584 737 ;
|
||||
C 164 ; WX 556 ; N currency ; B 60 99 646 603 ;
|
||||
C 39 ; WX 191 ; N quotesingle ; B 157 463 285 718 ;
|
||||
C 147 ; WX 333 ; N quotedblleft ; B 138 470 461 725 ;
|
||||
C 170 ; WX 556 ; N guillemotleft ; B 146 108 554 446 ;
|
||||
C 171 ; WX 556 ; N guillemotleft ; B 146 108 554 446 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 137 108 340 446 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 111 108 314 446 ;
|
||||
C -1 ; WX 500 ; N fi ; B 86 0 587 728 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 556 ; N section ; B 43 -191 512 737 ;
|
||||
C 164 ; WX 556 ; N currency ; B 28 99 528 603 ;
|
||||
C 39 ; WX 191 ; N quotesingle ; B 59 463 132 718 ;
|
||||
C 147 ; WX 333 ; N quotedblleft ; B 38 470 307 725 ;
|
||||
C 170 ; WX 556 ; N guillemotleft ; B 97 108 459 446 ;
|
||||
C 171 ; WX 556 ; N guillemotleft ; B 97 108 459 446 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 88 108 245 446 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 88 108 245 446 ;
|
||||
C -1 ; WX 500 ; N fi ; B 14 0 434 728 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 500 ; N section ; B 57 -132 443 691 ;
|
||||
C 164 ; WX 500 ; N currency ; B -26 61 526 613 ;
|
||||
C 39 ; WX 278 ; N quotesingle ; B 75 404 204 691 ;
|
||||
C 147 ; WX 500 ; N quotedblleft ; B 32 356 486 691 ;
|
||||
C 170 ; WX 500 ; N guillemotleft ; B 23 36 473 415 ;
|
||||
C 171 ; WX 500 ; N guillemotleft ; B 23 36 473 415 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 51 36 305 415 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 28 36 282 415 ;
|
||||
C -1 ; WX 556 ; N fi ; B 14 0 536 691 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 500 ; N section ; B 36 -143 459 685 ;
|
||||
C 164 ; WX 500 ; N currency ; B -26 34 526 586 ;
|
||||
C 39 ; WX 278 ; N quotesingle ; B 128 398 268 685 ;
|
||||
C 147 ; WX 500 ; N quotedblleft ; B 53 369 513 685 ;
|
||||
C 170 ; WX 500 ; N guillemotleft ; B 12 32 468 415 ;
|
||||
C 171 ; WX 500 ; N guillemotleft ; B 12 32 468 415 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 32 32 303 415 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 10 32 281 415 ;
|
||||
C -1 ; WX 556 ; N fi ; B -188 -205 514 703 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 500 ; N section ; B 53 -162 461 666 ;
|
||||
C 164 ; WX 500 ; N currency ; B -22 53 522 597 ;
|
||||
C 39 ; WX 214 ; N quotesingle ; B 132 421 241 666 ;
|
||||
C 147 ; WX 556 ; N quotedblleft ; B 166 436 514 666 ;
|
||||
C 170 ; WX 500 ; N guillemotleft ; B 53 37 445 403 ;
|
||||
C 171 ; WX 500 ; N guillemotleft ; B 53 37 445 403 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 51 37 281 403 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 52 37 282 403 ;
|
||||
C -1 ; WX 500 ; N fi ; B -141 -207 481 681 ;
|
||||
|
@ -130,7 +130,7 @@ C 167 ; WX 500 ; N section ; B 70 -148 426 676 ;
|
||||
C 164 ; WX 500 ; N currency ; B -22 58 522 602 ;
|
||||
C 39 ; WX 180 ; N quotesingle ; B 48 431 133 676 ;
|
||||
C 147 ; WX 444 ; N quotedblleft ; B 43 433 414 676 ;
|
||||
C 170 ; WX 500 ; N guillemotleft ; B 42 33 456 416 ;
|
||||
C 171 ; WX 500 ; N guillemotleft ; B 42 33 456 416 ;
|
||||
C 139 ; WX 333 ; N guilsinglleft ; B 63 33 285 416 ;
|
||||
C 155 ; WX 333 ; N guilsinglright ; B 48 33 270 416 ;
|
||||
C -1 ; WX 556 ; N fi ; B 31 0 521 683 ;
|
||||
|
@ -92,5 +92,4 @@ return array(
|
||||
'italic' => $distFontDir . 'DejaVuSerif-Italic',
|
||||
'normal' => $distFontDir . 'DejaVuSerif'
|
||||
)
|
||||
)
|
||||
?>
|
||||
);
|
23
library/vendor/dompdf/lib/html5lib/Data.php
vendored
23
library/vendor/dompdf/lib/html5lib/Data.php
vendored
@ -56,8 +56,11 @@ class HTML5_Data
|
||||
* reference.
|
||||
*/
|
||||
public static function getRealCodepoint($ref) {
|
||||
if (!isset(self::$realCodepointTable[$ref])) return false;
|
||||
else return self::$realCodepointTable[$ref];
|
||||
if (!isset(self::$realCodepointTable[$ref])) {
|
||||
return false;
|
||||
} else {
|
||||
return self::$realCodepointTable[$ref];
|
||||
}
|
||||
}
|
||||
|
||||
public static function getNamedCharacterReferences() {
|
||||
@ -82,7 +85,7 @@ class HTML5_Data
|
||||
return "\xEF\xBF\xBD";
|
||||
}*/
|
||||
|
||||
$x = $y = $z = $w = 0;
|
||||
$y = $z = $w = 0;
|
||||
if ($code < 0x80) {
|
||||
// regular ASCII character
|
||||
$x = $code;
|
||||
@ -93,7 +96,7 @@ class HTML5_Data
|
||||
$y = (($code & 0x7FF) >> 6) | 0xC0;
|
||||
} else {
|
||||
$y = (($code & 0xFC0) >> 6) | 0x80;
|
||||
if($code < 0x10000) {
|
||||
if ($code < 0x10000) {
|
||||
$z = (($code >> 12) & 0x0F) | 0xE0;
|
||||
} else {
|
||||
$z = (($code >> 12) & 0x3F) | 0x80;
|
||||
@ -103,9 +106,15 @@ class HTML5_Data
|
||||
}
|
||||
// set up the actual character
|
||||
$ret = '';
|
||||
if($w) $ret .= chr($w);
|
||||
if($z) $ret .= chr($z);
|
||||
if($y) $ret .= chr($y);
|
||||
if ($w) {
|
||||
$ret .= chr($w);
|
||||
}
|
||||
if ($z) {
|
||||
$ret .= chr($z);
|
||||
}
|
||||
if ($y) {
|
||||
$ret .= chr($y);
|
||||
}
|
||||
$ret .= chr($x);
|
||||
|
||||
return $ret;
|
||||
|
@ -51,7 +51,8 @@ class HTML5_InputStream {
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* @param $data Data to parse
|
||||
* @param $data | Data to parse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct($data) {
|
||||
|
||||
@ -76,7 +77,7 @@ class HTML5_InputStream {
|
||||
$data = @iconv('UTF-8', 'UTF-8//IGNORE', $data);
|
||||
} else {
|
||||
// we can make a conforming native implementation
|
||||
throw new Exception('Not implemented, please install mbstring or iconv');
|
||||
throw new Exception('Not implemented, please install iconv');
|
||||
}
|
||||
|
||||
/* One leading U+FEFF BYTE ORDER MARK character must be
|
||||
@ -161,10 +162,12 @@ class HTML5_InputStream {
|
||||
|
||||
/**
|
||||
* Returns the current line that the tokenizer is at.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCurrentLine() {
|
||||
// Check the string isn't empty
|
||||
if($this->EOF) {
|
||||
if ($this->EOF) {
|
||||
// Add one to $this->char because we want the number for the next
|
||||
// byte to be processed.
|
||||
return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1;
|
||||
@ -176,6 +179,8 @@ class HTML5_InputStream {
|
||||
|
||||
/**
|
||||
* Returns the current column of the current line that the tokenizer is at.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getColumnOffset() {
|
||||
// strrpos is weird, and the offset needs to be negative for what we
|
||||
@ -187,18 +192,18 @@ class HTML5_InputStream {
|
||||
|
||||
// However, for here we want the length up until the next byte to be
|
||||
// processed, so add one to the current byte ($this->char).
|
||||
if($lastLine !== false) {
|
||||
if ($lastLine !== false) {
|
||||
$findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine);
|
||||
} else {
|
||||
$findLengthOf = substr($this->data, 0, $this->char);
|
||||
}
|
||||
|
||||
// Get the length for the string we need.
|
||||
if(extension_loaded('iconv')) {
|
||||
if (extension_loaded('iconv')) {
|
||||
return iconv_strlen($findLengthOf, 'utf-8');
|
||||
} elseif(extension_loaded('mbstring')) {
|
||||
} elseif (extension_loaded('mbstring')) {
|
||||
return mb_strlen($findLengthOf, 'utf-8');
|
||||
} elseif(extension_loaded('xml')) {
|
||||
} elseif (extension_loaded('xml')) {
|
||||
return strlen(utf8_decode($findLengthOf));
|
||||
} else {
|
||||
$count = count_chars($findLengthOf);
|
||||
@ -212,6 +217,8 @@ class HTML5_InputStream {
|
||||
/**
|
||||
* Retrieve the currently consume character.
|
||||
* @note This performs bounds checking
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function char() {
|
||||
return ($this->char++ < $this->EOF)
|
||||
@ -222,9 +229,11 @@ class HTML5_InputStream {
|
||||
/**
|
||||
* Get all characters until EOF.
|
||||
* @note This performs bounds checking
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
public function remainingChars() {
|
||||
if($this->char < $this->EOF) {
|
||||
if ($this->char < $this->EOF) {
|
||||
$data = substr($this->data, $this->char);
|
||||
$this->char = $this->EOF;
|
||||
return $data;
|
||||
@ -236,7 +245,10 @@ class HTML5_InputStream {
|
||||
/**
|
||||
* Matches as far as possible until we reach a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
* @param $bytes Bytes to match.
|
||||
*
|
||||
* @param $bytes | Bytes to match.
|
||||
* @param null $max
|
||||
* @return bool|string
|
||||
*/
|
||||
public function charsUntil($bytes, $max = null) {
|
||||
if ($this->char < $this->EOF) {
|
||||
@ -256,7 +268,10 @@ class HTML5_InputStream {
|
||||
/**
|
||||
* Matches as far as possible with a certain set of bytes
|
||||
* and returns the matched substring.
|
||||
* @param $bytes Bytes to match.
|
||||
*
|
||||
* @param $bytes | Bytes to match.
|
||||
* @param null $max
|
||||
* @return bool|string
|
||||
*/
|
||||
public function charsWhile($bytes, $max = null) {
|
||||
if ($this->char < $this->EOF) {
|
||||
|
13
library/vendor/dompdf/lib/html5lib/Parser.php
vendored
13
library/vendor/dompdf/lib/html5lib/Parser.php
vendored
@ -12,21 +12,22 @@ class HTML5_Parser
|
||||
{
|
||||
/**
|
||||
* Parses a full HTML document.
|
||||
* @param $text HTML text to parse
|
||||
* @param $builder Custom builder implementation
|
||||
* @return Parsed HTML as DOMDocument
|
||||
* @param $text | HTML text to parse
|
||||
* @param $builder | Custom builder implementation
|
||||
* @return DOMDocument|DOMNodeList Parsed HTML as DOMDocument
|
||||
*/
|
||||
static public function parse($text, $builder = null) {
|
||||
$tokenizer = new HTML5_Tokenizer($text, $builder);
|
||||
$tokenizer->parse();
|
||||
return $tokenizer->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an HTML fragment.
|
||||
* @param $text HTML text to parse
|
||||
* @param $text | HTML text to parse
|
||||
* @param $context String name of context element to pretend parsing is in.
|
||||
* @param $builder Custom builder implementation
|
||||
* @return Parsed HTML as DOMDocument
|
||||
* @param $builder | Custom builder implementation
|
||||
* @return DOMDocument|DOMNodeList Parsed HTML as DOMDocument
|
||||
*/
|
||||
static public function parseFragment($text, $context = null, $builder = null) {
|
||||
$tokenizer = new HTML5_Tokenizer($text, $builder);
|
||||
|
323
library/vendor/dompdf/lib/html5lib/Tokenizer.php
vendored
323
library/vendor/dompdf/lib/html5lib/Tokenizer.php
vendored
@ -35,16 +35,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
class HTML5_Tokenizer {
|
||||
/**
|
||||
* @var HTML5_InputStream
|
||||
*
|
||||
* Points to an InputStream object.
|
||||
*/
|
||||
protected $stream;
|
||||
|
||||
/**
|
||||
* @var HTML5_TreeBuilder
|
||||
*
|
||||
* Tree builder that the tokenizer emits token to.
|
||||
*/
|
||||
private $tree;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* Current content model we are parsing as.
|
||||
*/
|
||||
protected $content_model;
|
||||
@ -82,15 +88,22 @@ class HTML5_Tokenizer {
|
||||
const WHITESPACE = "\t\n\x0c ";
|
||||
|
||||
/**
|
||||
* @param $data Data to parse
|
||||
* @param $data | Data to parse
|
||||
* @param HTML5_TreeBuilder|null $builder
|
||||
*/
|
||||
public function __construct($data, $builder = null) {
|
||||
$this->stream = new HTML5_InputStream($data);
|
||||
if (!$builder) $this->tree = new HTML5_TreeBuilder;
|
||||
else $this->tree = $builder;
|
||||
if (!$builder) {
|
||||
$this->tree = new HTML5_TreeBuilder;
|
||||
} else {
|
||||
$this->tree = $builder;
|
||||
}
|
||||
$this->content_model = self::PCDATA;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $context
|
||||
*/
|
||||
public function parseFragment($context = null) {
|
||||
$this->tree->setupContext($context);
|
||||
if ($this->tree->content_model) {
|
||||
@ -118,7 +131,7 @@ class HTML5_Tokenizer {
|
||||
$escape = false;
|
||||
//echo "\n\n";
|
||||
while($state !== null) {
|
||||
|
||||
|
||||
/*echo $state . ' ';
|
||||
switch ($this->content_model) {
|
||||
case self::PCDATA: echo 'PCDATA'; break;
|
||||
@ -128,17 +141,19 @@ class HTML5_Tokenizer {
|
||||
}
|
||||
if ($escape) echo " escape";
|
||||
echo "\n";*/
|
||||
|
||||
|
||||
switch($state) {
|
||||
case 'data':
|
||||
|
||||
/* Consume the next input character */
|
||||
$char = $this->stream->char();
|
||||
$lastFourChars .= $char;
|
||||
if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4);
|
||||
if (strlen($lastFourChars) > 4) {
|
||||
$lastFourChars = substr($lastFourChars, -4);
|
||||
}
|
||||
|
||||
// see below for meaning
|
||||
$hyp_cond =
|
||||
$hyp_cond =
|
||||
!$escape &&
|
||||
(
|
||||
$this->content_model === self::RCDATA ||
|
||||
@ -159,14 +174,14 @@ class HTML5_Tokenizer {
|
||||
) &&
|
||||
!$escape
|
||||
);
|
||||
$gt_cond =
|
||||
$gt_cond =
|
||||
$escape &&
|
||||
(
|
||||
$this->content_model === self::RCDATA ||
|
||||
$this->content_model === self::CDATA
|
||||
);
|
||||
|
||||
if($char === '&' && $amp_cond) {
|
||||
if ($char === '&' && $amp_cond === true) {
|
||||
/* U+0026 AMPERSAND (&)
|
||||
When the content model flag is set to one of the PCDATA or RCDATA
|
||||
states and the escape flag is false: switch to the
|
||||
@ -174,9 +189,9 @@ class HTML5_Tokenizer {
|
||||
the "anything else" entry below. */
|
||||
$state = 'character reference data';
|
||||
|
||||
} elseif(
|
||||
} elseif (
|
||||
$char === '-' &&
|
||||
$hyp_cond &&
|
||||
$hyp_cond === true &&
|
||||
$lastFourChars === '<!--'
|
||||
) {
|
||||
/*
|
||||
@ -198,7 +213,7 @@ class HTML5_Tokenizer {
|
||||
// We do the "any case" part as part of "anything else".
|
||||
|
||||
/* U+003C LESS-THAN SIGN (<) */
|
||||
} elseif($char === '<' && $lt_cond) {
|
||||
} elseif ($char === '<' && $lt_cond === true) {
|
||||
/* When the content model flag is set to the PCDATA state: switch
|
||||
to the tag open state.
|
||||
|
||||
@ -210,9 +225,9 @@ class HTML5_Tokenizer {
|
||||
$state = 'tag open';
|
||||
|
||||
/* U+003E GREATER-THAN SIGN (>) */
|
||||
} elseif(
|
||||
} elseif (
|
||||
$char === '>' &&
|
||||
$gt_cond &&
|
||||
$gt_cond === true &&
|
||||
substr($lastFourChars, 1) === '-->'
|
||||
) {
|
||||
/* If the content model flag is set to either the RCDATA state or
|
||||
@ -230,15 +245,15 @@ class HTML5_Tokenizer {
|
||||
));
|
||||
// We do the "any case" part as part of "anything else".
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Emit an end-of-file token. */
|
||||
$state = null;
|
||||
$this->tree->emitToken(array(
|
||||
'type' => self::EOF
|
||||
));
|
||||
|
||||
} elseif($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
|
||||
} elseif ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
// Directly after emitting a token you switch back to the "data
|
||||
// state". At that point spaceCharacters are important so they are
|
||||
// emitted separately.
|
||||
@ -248,19 +263,28 @@ class HTML5_Tokenizer {
|
||||
'data' => $char . $chars
|
||||
));
|
||||
$lastFourChars .= $chars;
|
||||
if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4);
|
||||
|
||||
if (strlen($lastFourChars) > 4) {
|
||||
$lastFourChars = substr($lastFourChars, -4);
|
||||
}
|
||||
} else {
|
||||
/* Anything else
|
||||
THIS IS AN OPTIMIZATION: Get as many character that
|
||||
otherwise would also be treated as a character token and emit it
|
||||
as a single character token. Stay in the data state. */
|
||||
|
||||
|
||||
$mask = '';
|
||||
if ($hyp_cond) $mask .= '-';
|
||||
if ($amp_cond) $mask .= '&';
|
||||
if ($lt_cond) $mask .= '<';
|
||||
if ($gt_cond) $mask .= '>';
|
||||
if ($hyp_cond === true) {
|
||||
$mask .= '-';
|
||||
}
|
||||
if ($amp_cond === true) {
|
||||
$mask .= '&';
|
||||
}
|
||||
if ($lt_cond === true) {
|
||||
$mask .= '<';
|
||||
}
|
||||
if ($gt_cond === true) {
|
||||
$mask .= '>';
|
||||
}
|
||||
|
||||
if ($mask === '') {
|
||||
$chars = $this->stream->remainingChars();
|
||||
@ -274,7 +298,9 @@ class HTML5_Tokenizer {
|
||||
));
|
||||
|
||||
$lastFourChars .= $chars;
|
||||
if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4);
|
||||
if (strlen($lastFourChars) > 4) {
|
||||
$lastFourChars = substr($lastFourChars, -4);
|
||||
}
|
||||
|
||||
$state = 'data';
|
||||
}
|
||||
@ -304,7 +330,7 @@ class HTML5_Tokenizer {
|
||||
case 'tag open':
|
||||
$char = $this->stream->char();
|
||||
|
||||
switch($this->content_model) {
|
||||
switch ($this->content_model) {
|
||||
case self::RCDATA:
|
||||
case self::CDATA:
|
||||
/* Consume the next input character. If it is a
|
||||
@ -314,9 +340,8 @@ class HTML5_Tokenizer {
|
||||
character in the data state. */
|
||||
// We consumed above.
|
||||
|
||||
if($char === '/') {
|
||||
if ($char === '/') {
|
||||
$state = 'close tag open';
|
||||
|
||||
} else {
|
||||
$this->emitToken(array(
|
||||
'type' => self::CHARACTER,
|
||||
@ -334,17 +359,17 @@ class HTML5_Tokenizer {
|
||||
Consume the next input character: */
|
||||
// We consumed above.
|
||||
|
||||
if($char === '!') {
|
||||
if ($char === '!') {
|
||||
/* U+0021 EXCLAMATION MARK (!)
|
||||
Switch to the markup declaration open state. */
|
||||
$state = 'markup declaration open';
|
||||
|
||||
} elseif($char === '/') {
|
||||
} elseif ($char === '/') {
|
||||
/* U+002F SOLIDUS (/)
|
||||
Switch to the close tag open state. */
|
||||
$state = 'close tag open';
|
||||
|
||||
} elseif('A' <= $char && $char <= 'Z') {
|
||||
} elseif ('A' <= $char && $char <= 'Z') {
|
||||
/* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z
|
||||
Create a new start tag token, set its tag name to the lowercase
|
||||
version of the input character (add 0x0020 to the character's code
|
||||
@ -358,7 +383,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'tag name';
|
||||
|
||||
} elseif('a' <= $char && $char <= 'z') {
|
||||
} elseif ('a' <= $char && $char <= 'z') {
|
||||
/* U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z
|
||||
Create a new start tag token, set its tag name to the input
|
||||
character, then switch to the tag name state. (Don't emit
|
||||
@ -372,7 +397,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'tag name';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Parse error. Emit a U+003C LESS-THAN SIGN character token and a
|
||||
U+003E GREATER-THAN SIGN character token. Switch to the data state. */
|
||||
@ -387,7 +412,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'data';
|
||||
|
||||
} elseif($char === '?') {
|
||||
} elseif ($char === '?') {
|
||||
/* U+003F QUESTION MARK (?)
|
||||
Parse error. Switch to the bogus comment state. */
|
||||
$this->emitToken(array(
|
||||
@ -508,7 +533,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'tag name';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Parse error. Switch to the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -517,7 +542,7 @@ class HTML5_Tokenizer {
|
||||
));
|
||||
$state = 'data';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F
|
||||
SOLIDUS character token. Reconsume the EOF character in the data state. */
|
||||
@ -552,7 +577,7 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -560,18 +585,18 @@ class HTML5_Tokenizer {
|
||||
Switch to the before attribute name state. */
|
||||
$state = 'before attribute name';
|
||||
|
||||
} elseif($char === '/') {
|
||||
} elseif ($char === '/') {
|
||||
/* U+002F SOLIDUS (/)
|
||||
Switch to the self-closing start tag state. */
|
||||
$state = 'self-closing start tag';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the current tag token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif('A' <= $char && $char <= 'Z') {
|
||||
} elseif ('A' <= $char && $char <= 'Z') {
|
||||
/* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
|
||||
Append the lowercase version of the current input
|
||||
character (add 0x0020 to the character's code point) to
|
||||
@ -581,7 +606,7 @@ class HTML5_Tokenizer {
|
||||
$this->token['name'] .= strtolower($char . $chars);
|
||||
$state = 'tag name';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Reconsume the EOF character in the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -608,7 +633,7 @@ class HTML5_Tokenizer {
|
||||
$char = $this->stream->char();
|
||||
|
||||
// this conditional is optimized, check bottom
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -616,18 +641,18 @@ class HTML5_Tokenizer {
|
||||
Stay in the before attribute name state. */
|
||||
$state = 'before attribute name';
|
||||
|
||||
} elseif($char === '/') {
|
||||
} elseif ($char === '/') {
|
||||
/* U+002F SOLIDUS (/)
|
||||
Switch to the self-closing start tag state. */
|
||||
$state = 'self-closing start tag';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the current tag token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif('A' <= $char && $char <= 'Z') {
|
||||
} elseif ('A' <= $char && $char <= 'Z') {
|
||||
/* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
|
||||
Start a new attribute in the current tag token. Set that
|
||||
attribute's name to the lowercase version of the current
|
||||
@ -641,7 +666,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'attribute name';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Reconsume the EOF character in the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -659,7 +684,7 @@ class HTML5_Tokenizer {
|
||||
U+003D EQUALS SIGN (=)
|
||||
Parse error. Treat it as per the "anything else" entry
|
||||
below. */
|
||||
if($char === '"' || $char === "'" || $char === '<' || $char === '=') {
|
||||
if ($char === '"' || $char === "'" || $char === '<' || $char === '=') {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'invalid-character-in-attribute-name'
|
||||
@ -684,7 +709,7 @@ class HTML5_Tokenizer {
|
||||
$char = $this->stream->char();
|
||||
|
||||
// this conditional is optimized, check bottom
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -692,23 +717,23 @@ class HTML5_Tokenizer {
|
||||
Switch to the after attribute name state. */
|
||||
$state = 'after attribute name';
|
||||
|
||||
} elseif($char === '/') {
|
||||
} elseif ($char === '/') {
|
||||
/* U+002F SOLIDUS (/)
|
||||
Switch to the self-closing start tag state. */
|
||||
$state = 'self-closing start tag';
|
||||
|
||||
} elseif($char === '=') {
|
||||
} elseif ($char === '=') {
|
||||
/* U+003D EQUALS SIGN (=)
|
||||
Switch to the before attribute value state. */
|
||||
$state = 'before attribute value';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the current tag token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif('A' <= $char && $char <= 'Z') {
|
||||
} elseif ('A' <= $char && $char <= 'Z') {
|
||||
/* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
|
||||
Append the lowercase version of the current input
|
||||
character (add 0x0020 to the character's code point) to
|
||||
@ -721,7 +746,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'attribute name';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Reconsume the EOF character in the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -738,7 +763,7 @@ class HTML5_Tokenizer {
|
||||
U+003C LESS-THAN SIGN (<)
|
||||
Parse error. Treat it as per the "anything else"
|
||||
entry below. */
|
||||
if($char === '"' || $char === "'" || $char === '<') {
|
||||
if ($char === '"' || $char === "'" || $char === '<') {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'invalid-character-in-attribute-name'
|
||||
@ -771,7 +796,7 @@ class HTML5_Tokenizer {
|
||||
$char = $this->stream->char();
|
||||
|
||||
// this is an optimized conditional, check the bottom
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -779,23 +804,23 @@ class HTML5_Tokenizer {
|
||||
Stay in the after attribute name state. */
|
||||
$state = 'after attribute name';
|
||||
|
||||
} elseif($char === '/') {
|
||||
} elseif ($char === '/') {
|
||||
/* U+002F SOLIDUS (/)
|
||||
Switch to the self-closing start tag state. */
|
||||
$state = 'self-closing start tag';
|
||||
|
||||
} elseif($char === '=') {
|
||||
} elseif ($char === '=') {
|
||||
/* U+003D EQUALS SIGN (=)
|
||||
Switch to the before attribute value state. */
|
||||
$state = 'before attribute value';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the current tag token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif('A' <= $char && $char <= 'Z') {
|
||||
} elseif ('A' <= $char && $char <= 'Z') {
|
||||
/* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
|
||||
Start a new attribute in the current tag token. Set that
|
||||
attribute's name to the lowercase version of the current
|
||||
@ -809,7 +834,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'attribute name';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Reconsume the EOF character in the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -826,7 +851,7 @@ class HTML5_Tokenizer {
|
||||
U+003C LESS-THAN SIGN(<)
|
||||
Parse error. Treat it as per the "anything else"
|
||||
entry below. */
|
||||
if($char === '"' || $char === "'" || $char === "<") {
|
||||
if ($char === '"' || $char === "'" || $char === "<") {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'invalid-character-after-attribute-name'
|
||||
@ -851,7 +876,7 @@ class HTML5_Tokenizer {
|
||||
$char = $this->stream->char();
|
||||
|
||||
// this is an optimized conditional
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -859,24 +884,24 @@ class HTML5_Tokenizer {
|
||||
Stay in the before attribute value state. */
|
||||
$state = 'before attribute value';
|
||||
|
||||
} elseif($char === '"') {
|
||||
} elseif ($char === '"') {
|
||||
/* U+0022 QUOTATION MARK (")
|
||||
Switch to the attribute value (double-quoted) state. */
|
||||
$state = 'attribute value (double-quoted)';
|
||||
|
||||
} elseif($char === '&') {
|
||||
} elseif ($char === '&') {
|
||||
/* U+0026 AMPERSAND (&)
|
||||
Switch to the attribute value (unquoted) state and reconsume
|
||||
this input character. */
|
||||
$this->stream->unget();
|
||||
$state = 'attribute value (unquoted)';
|
||||
|
||||
} elseif($char === '\'') {
|
||||
} elseif ($char === '\'') {
|
||||
/* U+0027 APOSTROPHE (')
|
||||
Switch to the attribute value (single-quoted) state. */
|
||||
$state = 'attribute value (single-quoted)';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Parse error. Emit the current tag token. Switch to the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -886,7 +911,7 @@ class HTML5_Tokenizer {
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Reconsume the EOF character in the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -900,7 +925,7 @@ class HTML5_Tokenizer {
|
||||
/* U+003D EQUALS SIGN (=)
|
||||
* U+003C LESS-THAN SIGN (<)
|
||||
Parse error. Treat it as per the "anything else" entry below. */
|
||||
if($char === '=' || $char === '<') {
|
||||
if ($char === '=' || $char === '<') {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'equals-in-unquoted-attribute-value'
|
||||
@ -921,19 +946,19 @@ class HTML5_Tokenizer {
|
||||
// Consume the next input character:
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === '"') {
|
||||
if ($char === '"') {
|
||||
/* U+0022 QUOTATION MARK (")
|
||||
Switch to the after attribute value (quoted) state. */
|
||||
$state = 'after attribute value (quoted)';
|
||||
|
||||
} elseif($char === '&') {
|
||||
} elseif ($char === '&') {
|
||||
/* U+0026 AMPERSAND (&)
|
||||
Switch to the character reference in attribute value
|
||||
state, with the additional allowed character
|
||||
being U+0022 QUOTATION MARK ("). */
|
||||
$this->characterReferenceInAttributeValue('"');
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Reconsume the EOF character in the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -961,17 +986,17 @@ class HTML5_Tokenizer {
|
||||
// Consume the next input character:
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "'") {
|
||||
if ($char === "'") {
|
||||
/* U+0022 QUOTATION MARK (')
|
||||
Switch to the after attribute value state. */
|
||||
$state = 'after attribute value (quoted)';
|
||||
|
||||
} elseif($char === '&') {
|
||||
} elseif ($char === '&') {
|
||||
/* U+0026 AMPERSAND (&)
|
||||
Switch to the entity in attribute value state. */
|
||||
$this->characterReferenceInAttributeValue("'");
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Reconsume the EOF character in the data state. */
|
||||
$this->emitToken(array(
|
||||
@ -999,7 +1024,7 @@ class HTML5_Tokenizer {
|
||||
// Consume the next input character:
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -1007,14 +1032,14 @@ class HTML5_Tokenizer {
|
||||
Switch to the before attribute name state. */
|
||||
$state = 'before attribute name';
|
||||
|
||||
} elseif($char === '&') {
|
||||
} elseif ($char === '&') {
|
||||
/* U+0026 AMPERSAND (&)
|
||||
Switch to the entity in attribute value state, with the
|
||||
additional allowed character being U+003E
|
||||
Switch to the entity in attribute value state, with the
|
||||
additional allowed character being U+003E
|
||||
GREATER-THAN SIGN (>). */
|
||||
$this->characterReferenceInAttributeValue('>');
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the current tag token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
@ -1037,7 +1062,7 @@ class HTML5_Tokenizer {
|
||||
U+003D EQUALS SIGN (=)
|
||||
Parse error. Treat it as per the "anything else"
|
||||
entry below. */
|
||||
if($char === '"' || $char === "'" || $char === '=' || $char == '<') {
|
||||
if ($char === '"' || $char === "'" || $char === '=' || $char == '<') {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'unexpected-character-in-unquoted-attribute-value'
|
||||
@ -1060,7 +1085,7 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -1169,7 +1194,7 @@ class HTML5_Tokenizer {
|
||||
/* If the next two characters are both U+002D HYPHEN-MINUS (-)
|
||||
characters, consume those two characters, create a comment token whose
|
||||
data is the empty string, and switch to the comment state. */
|
||||
if($hyphens === '--') {
|
||||
if ($hyphens === '--') {
|
||||
$state = 'comment start';
|
||||
$this->token = array(
|
||||
'data' => '',
|
||||
@ -1179,7 +1204,7 @@ class HTML5_Tokenizer {
|
||||
/* Otherwise if the next seven characters are a case-insensitive match
|
||||
for the word "DOCTYPE", then consume those characters and switch to the
|
||||
DOCTYPE state. */
|
||||
} elseif(strtoupper($alpha) === 'DOCTYPE') {
|
||||
} elseif (strtoupper($alpha) === 'DOCTYPE') {
|
||||
$state = 'DOCTYPE';
|
||||
|
||||
// XXX not implemented
|
||||
@ -1283,12 +1308,12 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === '-') {
|
||||
if ($char === '-') {
|
||||
/* U+002D HYPHEN-MINUS (-)
|
||||
Switch to the comment end dash state */
|
||||
$state = 'comment end dash';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Emit the comment token. Reconsume the EOF character
|
||||
in the data state. */
|
||||
@ -1314,12 +1339,12 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === '-') {
|
||||
if ($char === '-') {
|
||||
/* U+002D HYPHEN-MINUS (-)
|
||||
Switch to the comment end state */
|
||||
$state = 'comment end';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Emit the comment token. Reconsume the EOF character
|
||||
in the data state. */
|
||||
@ -1344,13 +1369,13 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === '>') {
|
||||
if ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the comment token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif($char === '-') {
|
||||
} elseif ($char === '-') {
|
||||
/* U+002D HYPHEN-MINUS (-)
|
||||
Parse error. Append a U+002D HYPHEN-MINUS (-) character
|
||||
to the comment token's data. Stay in the comment end
|
||||
@ -1361,7 +1386,7 @@ class HTML5_Tokenizer {
|
||||
));
|
||||
$this->token['data'] .= '-';
|
||||
|
||||
} elseif($char === "\t" || $char === "\n" || $char === "\x0a" || $char === ' ') {
|
||||
} elseif ($char === "\t" || $char === "\n" || $char === "\x0a" || $char === ' ') {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'unexpected-space-after-double-dash-in-comment'
|
||||
@ -1369,14 +1394,14 @@ class HTML5_Tokenizer {
|
||||
$this->token['data'] .= '--' . $char;
|
||||
$state = 'comment end space';
|
||||
|
||||
} elseif($char === '!') {
|
||||
} elseif ($char === '!') {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'unexpected-bang-after-double-dash-in-comment'
|
||||
));
|
||||
$state = 'comment end bang';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Emit the comment token. Reconsume the
|
||||
EOF character in the data state. */
|
||||
@ -1451,15 +1476,15 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
U+0020 SPACE
|
||||
Switch to the before DOCTYPE name state. */
|
||||
$state = 'before DOCTYPE name';
|
||||
|
||||
} elseif($char === false) {
|
||||
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Create a new DOCTYPE token. Set its
|
||||
force-quirks flag to on. Emit the token. Reconsume the
|
||||
@ -1494,14 +1519,14 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
U+0020 SPACE
|
||||
Stay in the before DOCTYPE name state. */
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Parse error. Create a new DOCTYPE token. Set its
|
||||
force-quirks flag to on. Emit the token. Switch to the
|
||||
@ -1519,7 +1544,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'data';
|
||||
|
||||
} elseif('A' <= $char && $char <= 'Z') {
|
||||
} elseif ('A' <= $char && $char <= 'Z') {
|
||||
/* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
|
||||
Create a new DOCTYPE token. Set the token's name to the
|
||||
lowercase version of the input character (add 0x0020 to
|
||||
@ -1533,7 +1558,7 @@ class HTML5_Tokenizer {
|
||||
|
||||
$state = 'DOCTYPE name';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Create a new DOCTYPE token. Set its
|
||||
force-quirks flag to on. Emit the token. Reconsume the
|
||||
@ -1570,7 +1595,7 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -1578,20 +1603,20 @@ class HTML5_Tokenizer {
|
||||
Switch to the after DOCTYPE name state. */
|
||||
$state = 'after DOCTYPE name';
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the current DOCTYPE token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif('A' <= $char && $char <= 'Z') {
|
||||
} elseif ('A' <= $char && $char <= 'Z') {
|
||||
/* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z
|
||||
Append the lowercase version of the input character
|
||||
(add 0x0020 to the character's code point) to the current
|
||||
DOCTYPE token's name. Stay in the DOCTYPE name state. */
|
||||
$this->token['name'] .= strtolower($char);
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Set the DOCTYPE token's force-quirks flag
|
||||
to on. Emit that DOCTYPE token. Reconsume the EOF
|
||||
@ -1624,20 +1649,20 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
U+0020 SPACE
|
||||
Stay in the after DOCTYPE name state. */
|
||||
|
||||
} elseif($char === '>') {
|
||||
} elseif ($char === '>') {
|
||||
/* U+003E GREATER-THAN SIGN (>)
|
||||
Emit the current DOCTYPE token. Switch to the data state. */
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Parse error. Set the DOCTYPE token's force-quirks flag
|
||||
to on. Emit that DOCTYPE token. Reconsume the EOF
|
||||
@ -1688,7 +1713,7 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -1828,7 +1853,7 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -1882,7 +1907,7 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -2022,7 +2047,7 @@ class HTML5_Tokenizer {
|
||||
/* Consume the next input character: */
|
||||
$char = $this->stream->char();
|
||||
|
||||
if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
if ($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') {
|
||||
/* U+0009 CHARACTER TABULATION
|
||||
U+000A LINE FEED (LF)
|
||||
U+000C FORM FEED (FF)
|
||||
@ -2068,7 +2093,7 @@ class HTML5_Tokenizer {
|
||||
$this->emitToken($this->token);
|
||||
$state = 'data';
|
||||
|
||||
} elseif($char === false) {
|
||||
} elseif ($char === false) {
|
||||
/* EOF
|
||||
Emit the DOCTYPE token. Reconsume the EOF character in
|
||||
the data state. */
|
||||
@ -2083,32 +2108,42 @@ class HTML5_Tokenizer {
|
||||
break;
|
||||
|
||||
// case 'cdataSection':
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a serialized representation of the tree.
|
||||
*
|
||||
* @return DOMDocument|DOMNodeList
|
||||
*/
|
||||
public function save() {
|
||||
return $this->tree->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HTML5_TreeBuilder The tree
|
||||
*/
|
||||
public function getTree() {
|
||||
return $this->tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HTML5_TreeBuilder The tree
|
||||
*/
|
||||
public function getTree()
|
||||
{
|
||||
return $this->tree;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the input stream.
|
||||
*
|
||||
* @return HTML5_InputStream
|
||||
*/
|
||||
public function stream() {
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $allowed
|
||||
* @param bool $inattr
|
||||
* @return string
|
||||
*/
|
||||
private function consumeCharacterReference($allowed = false, $inattr = false) {
|
||||
// This goes quite far against spec, and is far closer to the Python
|
||||
// impl., mainly because we don't do the large unconsuming the spec
|
||||
@ -2223,8 +2258,8 @@ class HTML5_Tokenizer {
|
||||
));
|
||||
return HTML5_Data::utf8chr($new_codepoint);
|
||||
} else {
|
||||
/* Otherwise, if the number is greater than 0x10FFFF, then
|
||||
* this is a parse error. Return a U+FFFD REPLACEMENT
|
||||
/* Otherwise, if the number is greater than 0x10FFFF, then
|
||||
* this is a parse error. Return a U+FFFD REPLACEMENT
|
||||
* CHARACTER. */
|
||||
if ($codepoint > 0x10FFFF) {
|
||||
$this->emitToken(array(
|
||||
@ -2233,16 +2268,16 @@ class HTML5_Tokenizer {
|
||||
));
|
||||
return "\xEF\xBF\xBD";
|
||||
}
|
||||
/* Otherwise, return a character token for the Unicode
|
||||
* character whose code point is that number. If the
|
||||
* number is in the range 0x0001 to 0x0008, 0x000E to
|
||||
* 0x001F, 0x007F to 0x009F, 0xD800 to 0xDFFF, 0xFDD0 to
|
||||
* 0xFDEF, or is one of 0x000B, 0xFFFE, 0xFFFF, 0x1FFFE,
|
||||
* 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF, 0x4FFFE,
|
||||
* 0x4FFFF, 0x5FFFE, 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE,
|
||||
* 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE,
|
||||
* 0xAFFFF, 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
|
||||
* 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, 0x10FFFE,
|
||||
/* Otherwise, return a character token for the Unicode
|
||||
* character whose code point is that number. If the
|
||||
* number is in the range 0x0001 to 0x0008, 0x000E to
|
||||
* 0x001F, 0x007F to 0x009F, 0xD800 to 0xDFFF, 0xFDD0 to
|
||||
* 0xFDEF, or is one of 0x000B, 0xFFFE, 0xFFFF, 0x1FFFE,
|
||||
* 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF, 0x4FFFE,
|
||||
* 0x4FFFF, 0x5FFFE, 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE,
|
||||
* 0x7FFFF, 0x8FFFE, 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE,
|
||||
* 0xAFFFF, 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
|
||||
* 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, 0x10FFFE,
|
||||
* or 0x10FFFF, then this is a parse error. */
|
||||
// && has higher precedence than ||
|
||||
if (
|
||||
@ -2263,7 +2298,6 @@ class HTML5_Tokenizer {
|
||||
return HTML5_Data::utf8chr($codepoint);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Anything else */
|
||||
|
||||
@ -2275,7 +2309,7 @@ class HTML5_Tokenizer {
|
||||
// matches the start of one of the identifiers in the first column.
|
||||
|
||||
$refs = HTML5_Data::getNamedCharacterReferences();
|
||||
|
||||
|
||||
// Get the longest string which is the start of an identifier
|
||||
// ($chars) as well as the longest identifier which matches ($id)
|
||||
// and its codepoint ($codepoint).
|
||||
@ -2289,7 +2323,7 @@ class HTML5_Tokenizer {
|
||||
}
|
||||
$chars .= $char = $this->stream->char();
|
||||
}
|
||||
|
||||
|
||||
// Unconsume the one character we just took which caused the while
|
||||
// statement to fail. This could be anything and could cause state
|
||||
// changes (as if it matches the while loop it must be
|
||||
@ -2353,6 +2387,9 @@ class HTML5_Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $allowed
|
||||
*/
|
||||
private function characterReferenceInAttributeValue($allowed = false) {
|
||||
/* Attempt to consume a character reference. */
|
||||
$entity = $this->consumeCharacterReference($allowed, true);
|
||||
@ -2375,15 +2412,19 @@ class HTML5_Tokenizer {
|
||||
|
||||
/**
|
||||
* Emits a token, passing it on to the tree builder.
|
||||
*
|
||||
* @param $token
|
||||
* @param bool $checkStream
|
||||
* @param bool $dry
|
||||
*/
|
||||
protected function emitToken($token, $checkStream = true, $dry = false) {
|
||||
if ($checkStream) {
|
||||
if ($checkStream === true) {
|
||||
// Emit errors from input stream.
|
||||
while ($this->stream->errors) {
|
||||
$this->emitToken(array_shift($this->stream->errors), false);
|
||||
}
|
||||
}
|
||||
if($token['type'] === self::ENDTAG && !empty($token['attr'])) {
|
||||
if ($token['type'] === self::ENDTAG && !empty($token['attr'])) {
|
||||
for ($i = 0; $i < count($token['attr']); $i++) {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
@ -2391,13 +2432,13 @@ class HTML5_Tokenizer {
|
||||
));
|
||||
}
|
||||
}
|
||||
if($token['type'] === self::ENDTAG && !empty($token['self-closing'])) {
|
||||
if ($token['type'] === self::ENDTAG && !empty($token['self-closing'])) {
|
||||
$this->emitToken(array(
|
||||
'type' => self::PARSEERROR,
|
||||
'data' => 'self-closing-flag-on-end-tag',
|
||||
));
|
||||
}
|
||||
if($token['type'] === self::STARTTAG) {
|
||||
if ($token['type'] === self::STARTTAG) {
|
||||
// This could be changed to actually pass the tree-builder a hash
|
||||
$hash = array();
|
||||
foreach ($token['attr'] as $keypair) {
|
||||
@ -2412,16 +2453,16 @@ class HTML5_Tokenizer {
|
||||
}
|
||||
}
|
||||
|
||||
if(!$dry) {
|
||||
if ($dry === false) {
|
||||
// the current structure of attributes is not a terribly good one
|
||||
$this->tree->emitToken($token);
|
||||
}
|
||||
|
||||
if(!$dry && is_int($this->tree->content_model)) {
|
||||
if ($dry === false && is_int($this->tree->content_model)) {
|
||||
$this->content_model = $this->tree->content_model;
|
||||
$this->tree->content_model = null;
|
||||
|
||||
} elseif($token['type'] === self::ENDTAG) {
|
||||
} elseif ($token['type'] === self::ENDTAG) {
|
||||
$this->content_model = self::PCDATA;
|
||||
}
|
||||
}
|
||||
|
6109
library/vendor/dompdf/lib/html5lib/TreeBuilder.php
vendored
6109
library/vendor/dompdf/lib/html5lib/TreeBuilder.php
vendored
File diff suppressed because it is too large
Load Diff
133
library/vendor/dompdf/lib/res/html.css
vendored
133
library/vendor/dompdf/lib/res/html.css
vendored
@ -1,33 +1,48 @@
|
||||
/**
|
||||
* dompdf default stylesheet.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998 the Initial Developer.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* @package dompdf
|
||||
* @link http://dompdf.github.com/
|
||||
* @author Benj Carson <benjcarson@digitaljunkies.ca>
|
||||
* @author Blake Ross <BlakeR1234@aol.com>
|
||||
* @author Fabien Ménager <fabien.menager@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @version $Id$
|
||||
*
|
||||
* Portions from Mozilla
|
||||
* @link https://dxr.mozilla.org/mozilla-central/source/layout/style/res/html.css
|
||||
* @license http://mozilla.org/MPL/2.0/ Mozilla Public License, v. 2.0
|
||||
*
|
||||
* Portions from W3C
|
||||
* @link https://drafts.csswg.org/css-ui-3/#default-style-sheet
|
||||
*
|
||||
*/
|
||||
|
||||
@page {
|
||||
margin: 1.2cm;
|
||||
}
|
||||
|
||||
html {
|
||||
display: -dompdf-page;
|
||||
html {
|
||||
display: -dompdf-page !important;
|
||||
counter-reset: page;
|
||||
}
|
||||
|
||||
/* blocks */
|
||||
|
||||
div, map, dt, isindex {
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
div,
|
||||
dt,
|
||||
figcaption,
|
||||
footer,
|
||||
form,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
nav,
|
||||
noscript,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@ -47,7 +62,7 @@ dd {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
blockquote, figure {
|
||||
display: block;
|
||||
margin: 1em 40px;
|
||||
}
|
||||
@ -64,7 +79,7 @@ center {
|
||||
|
||||
blockquote[type=cite] {
|
||||
display: block;
|
||||
margin: 1em 0px;
|
||||
margin: 1em 0;
|
||||
padding-left: 1em;
|
||||
border-left: solid;
|
||||
border-color: blue;
|
||||
@ -113,25 +128,18 @@ listing {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
plaintext, xmp, pre {
|
||||
plaintext, pre, xmp {
|
||||
display: block;
|
||||
font-family: fixed;
|
||||
white-space: pre;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
article, aside, details,
|
||||
figcaption, figure,
|
||||
footer, header, hgroup,
|
||||
nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* tables */
|
||||
|
||||
table {
|
||||
display: table;
|
||||
border-spacing: 2px;
|
||||
border-spacing: 2px;
|
||||
border-collapse: separate;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
@ -155,10 +163,10 @@ table[border] th {
|
||||
td, th, tr {
|
||||
background: inherit;
|
||||
}
|
||||
|
||||
/* caption inherits from table not table-outer */
|
||||
|
||||
/* caption inherits from table not table-outer */
|
||||
caption {
|
||||
display: block;
|
||||
display: table-caption;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@ -195,10 +203,10 @@ table > tr {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
td {
|
||||
td {
|
||||
display: table-cell;
|
||||
vertical-align: inherit;
|
||||
text-align: inherit;
|
||||
text-align: inherit;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
@ -207,7 +215,6 @@ th {
|
||||
vertical-align: inherit;
|
||||
font-weight: bold;
|
||||
padding: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* inlines */
|
||||
@ -248,10 +255,6 @@ s, strike, del {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
blink {
|
||||
text-decoration: blink;
|
||||
}
|
||||
|
||||
big {
|
||||
font-size: larger;
|
||||
}
|
||||
@ -276,6 +279,17 @@ nobr {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
mark {
|
||||
background: yellow;
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* titles */
|
||||
|
||||
abbr[title], acronym[title] {
|
||||
text-decoration: dotted underline;
|
||||
}
|
||||
|
||||
/* lists */
|
||||
|
||||
ul, menu, dir {
|
||||
@ -303,40 +317,32 @@ li {
|
||||
}*/
|
||||
|
||||
/* nested lists have no top/bottom margins */
|
||||
ul ul, ul ol, ul dir, ul menu, ul dl,
|
||||
ol ul, ol ol, ol dir, ol menu, ol dl,
|
||||
dir ul, dir ol, dir dir, dir menu, dir dl,
|
||||
menu ul, menu ol, menu dir, menu menu, menu dl,
|
||||
dl ul, dl ol, dl dir, dl menu, dl dl {
|
||||
:matches(ul, ol, dir, menu, dl) ul,
|
||||
:matches(ul, ol, dir, menu, dl) ol,
|
||||
:matches(ul, ol, dir, menu, dl) dir,
|
||||
:matches(ul, ol, dir, menu, dl) menu,
|
||||
:matches(ul, ol, dir, menu, dl) dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* 2 deep unordered lists use a circle */
|
||||
ol ul, ul ul, menu ul, dir ul,
|
||||
ol menu, ul menu, menu menu, dir menu,
|
||||
ol dir, ul dir, menu dir, dir dir {
|
||||
:matches(ul, ol, dir, menu) ul,
|
||||
:matches(ul, ol, dir, menu) ul,
|
||||
:matches(ul, ol, dir, menu) ul,
|
||||
:matches(ul, ol, dir, menu) ul {
|
||||
list-style-type: circle;
|
||||
}
|
||||
|
||||
/* 3 deep (or more) unordered lists use a square */
|
||||
ol ol ul, ol ul ul, ol menu ul, ol dir ul,
|
||||
ol ol menu, ol ul menu, ol menu menu, ol dir menu,
|
||||
ol ol dir, ol ul dir, ol menu dir, ol dir dir,
|
||||
ul ol ul, ul ul ul, ul menu ul, ul dir ul,
|
||||
ul ol menu, ul ul menu, ul menu menu, ul dir menu,
|
||||
ul ol dir, ul ul dir, ul menu dir, ul dir dir,
|
||||
menu ol ul, menu ul ul, menu menu ul, menu dir ul,
|
||||
menu ol menu, menu ul menu, menu menu menu, menu dir menu,
|
||||
menu ol dir, menu ul dir, menu menu dir, menu dir dir,
|
||||
dir ol ul, dir ul ul, dir menu ul, dir dir ul,
|
||||
dir ol menu, dir ul menu, dir menu menu, dir dir menu,
|
||||
dir ol dir, dir ul dir, dir menu dir, dir dir dir {
|
||||
:matches(ul, ol, dir, menu) :matches(ul, ol, dir, menu) ul,
|
||||
:matches(ul, ol, dir, menu) :matches(ul, ol, dir, menu) menu,
|
||||
:matches(ul, ol, dir, menu) :matches(ul, ol, dir, menu) dir {
|
||||
list-style-type: square;
|
||||
}
|
||||
|
||||
/* forms */
|
||||
/* From http://dev.w3.org/csswg/css3-ui/#appearance */
|
||||
/* From https://drafts.csswg.org/css-ui-3/#default-style-sheet */
|
||||
form {
|
||||
display: block;
|
||||
}
|
||||
@ -373,10 +379,13 @@ input[type=reset],
|
||||
input[type=file],
|
||||
button {
|
||||
background: #CCC;
|
||||
width: 8em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
input[type=file] {
|
||||
width: 8em;
|
||||
}
|
||||
|
||||
input[type=text]:before,
|
||||
input[type=button]:before,
|
||||
input[type=submit]:before,
|
||||
@ -385,11 +394,11 @@ input[type=reset]:before {
|
||||
}
|
||||
|
||||
input[type=file]:before {
|
||||
content: "Chose a file";
|
||||
content: "Choose a file";
|
||||
}
|
||||
|
||||
input[type=password][value]:before {
|
||||
font-family: "DejaVu Sans";
|
||||
font-family: "DejaVu Sans" !important;
|
||||
content: "\2022\2022\2022\2022\2022\2022\2022\2022";
|
||||
line-height: 1em;
|
||||
}
|
||||
@ -397,7 +406,7 @@ input[type=password][value]:before {
|
||||
input[type=checkbox],
|
||||
input[type=radio],
|
||||
select:after {
|
||||
font-family: "DejaVu Sans";
|
||||
font-family: "DejaVu Sans" !important;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
@ -480,20 +489,24 @@ hr {
|
||||
margin: 0.5em auto 0.5em auto;
|
||||
}
|
||||
|
||||
hr[size="1"] {
|
||||
border-style: solid none none none;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 2px inset;
|
||||
}
|
||||
|
||||
noframes {
|
||||
display: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
br {
|
||||
br {
|
||||
display: -dompdf-br;
|
||||
}
|
||||
|
||||
img, img_generated {
|
||||
display: -dompdf-image;
|
||||
display: -dompdf-image !important;
|
||||
}
|
||||
|
||||
dompdf_generated {
|
||||
@ -502,7 +515,7 @@ dompdf_generated {
|
||||
|
||||
/* hidden elements */
|
||||
area, base, basefont, head, meta, script, style, title,
|
||||
noembed, noscript, param {
|
||||
noembed, param {
|
||||
display: none;
|
||||
-dompdf-keep: yes;
|
||||
}
|
||||
|
379
library/vendor/dompdf/src/Adapter/CPDF.php
vendored
379
library/vendor/dompdf/src/Adapter/CPDF.php
vendored
@ -89,6 +89,7 @@ class CPDF implements Canvas
|
||||
"sra3" => array(0, 0, 907.09, 1275.59),
|
||||
"sra4" => array(0, 0, 637.80, 907.09),
|
||||
"letter" => array(0, 0, 612.00, 792.00),
|
||||
"half-letter" => array(0, 0, 396.00, 612.00),
|
||||
"legal" => array(0, 0, 612.00, 1008.00),
|
||||
"ledger" => array(0, 0, 1224.00, 792.00),
|
||||
"tabloid" => array(0, 0, 792.00, 1224.00),
|
||||
@ -164,6 +165,13 @@ class CPDF implements Canvas
|
||||
*/
|
||||
private $_image_cache;
|
||||
|
||||
/**
|
||||
* Currently-applied opacity level (0 - 1)
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
private $_current_opacity = 1;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
@ -171,7 +179,7 @@ class CPDF implements Canvas
|
||||
* @param string $orientation The orientation of the document (either 'landscape' or 'portrait')
|
||||
* @param Dompdf $dompdf The Dompdf instance
|
||||
*/
|
||||
function __construct($paper = "letter", $orientation = "portrait", Dompdf $dompdf)
|
||||
public function __construct($paper = "letter", $orientation = "portrait", Dompdf $dompdf)
|
||||
{
|
||||
if (is_array($paper)) {
|
||||
$size = $paper;
|
||||
@ -190,8 +198,8 @@ class CPDF implements Canvas
|
||||
$this->_pdf = new \Cpdf(
|
||||
$size,
|
||||
true,
|
||||
$dompdf->get_option("font_cache"),
|
||||
$dompdf->get_option("temp_dir")
|
||||
$dompdf->getOptions()->getFontCache(),
|
||||
$dompdf->getOptions()->getTempDir()
|
||||
);
|
||||
|
||||
$this->_pdf->addInfo("Producer", sprintf("%s + CPDF", $dompdf->version));
|
||||
@ -210,7 +218,10 @@ class CPDF implements Canvas
|
||||
$this->_image_cache = array();
|
||||
}
|
||||
|
||||
function get_dompdf()
|
||||
/**
|
||||
* @return Dompdf
|
||||
*/
|
||||
public function get_dompdf()
|
||||
{
|
||||
return $this->_dompdf;
|
||||
}
|
||||
@ -220,7 +231,7 @@ class CPDF implements Canvas
|
||||
*
|
||||
* Deletes all temporary image files
|
||||
*/
|
||||
function __destruct()
|
||||
public function __destruct()
|
||||
{
|
||||
foreach ($this->_image_cache as $img) {
|
||||
// The file might be already deleted by 3rd party tmp cleaner,
|
||||
@ -231,8 +242,12 @@ class CPDF implements Canvas
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->_dompdf->get_option("debugPng")) print '[__destruct unlink ' . $img . ']';
|
||||
if (!$this->_dompdf->get_option("debugKeepTemp")) unlink($img);
|
||||
if ($this->_dompdf->getOptions()->getDebugPng()) {
|
||||
print '[__destruct unlink ' . $img . ']';
|
||||
}
|
||||
if (!$this->_dompdf->getOptions()->getDebugKeepTemp()) {
|
||||
unlink($img);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +256,7 @@ class CPDF implements Canvas
|
||||
*
|
||||
* @return \Cpdf
|
||||
*/
|
||||
function get_cpdf()
|
||||
public function get_cpdf()
|
||||
{
|
||||
return $this->_pdf;
|
||||
}
|
||||
@ -252,7 +267,7 @@ class CPDF implements Canvas
|
||||
* @param string $label label of the value (Creator, Producer, etc.)
|
||||
* @param string $value the text to set
|
||||
*/
|
||||
function add_info($label, $value)
|
||||
public function add_info($label, $value)
|
||||
{
|
||||
$this->_pdf->addInfo($label, $value);
|
||||
}
|
||||
@ -266,12 +281,12 @@ class CPDF implements Canvas
|
||||
*
|
||||
* The return value is an integer ID for the new object.
|
||||
*
|
||||
* @see CPDF_Adapter::close_object()
|
||||
* @see CPDF_Adapter::add_object()
|
||||
* @see CPDF::close_object()
|
||||
* @see CPDF::add_object()
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function open_object()
|
||||
public function open_object()
|
||||
{
|
||||
$ret = $this->_pdf->openObject();
|
||||
$this->_pdf->saveState();
|
||||
@ -281,10 +296,10 @@ class CPDF implements Canvas
|
||||
/**
|
||||
* Reopens an existing 'object'
|
||||
*
|
||||
* @see CPDF_Adapter::open_object()
|
||||
* @see CPDF::open_object()
|
||||
* @param int $object the ID of a previously opened object
|
||||
*/
|
||||
function reopen_object($object)
|
||||
public function reopen_object($object)
|
||||
{
|
||||
$this->_pdf->reopenObject($object);
|
||||
$this->_pdf->saveState();
|
||||
@ -293,9 +308,9 @@ class CPDF implements Canvas
|
||||
/**
|
||||
* Closes the current 'object'
|
||||
*
|
||||
* @see CPDF_Adapter::open_object()
|
||||
* @see CPDF::open_object()
|
||||
*/
|
||||
function close_object()
|
||||
public function close_object()
|
||||
{
|
||||
$this->_pdf->restoreState();
|
||||
$this->_pdf->closeObject();
|
||||
@ -319,7 +334,7 @@ class CPDF implements Canvas
|
||||
* @param int $object
|
||||
* @param string $where
|
||||
*/
|
||||
function add_object($object, $where = 'all')
|
||||
public function add_object($object, $where = 'all')
|
||||
{
|
||||
$this->_pdf->addObject($object, $where);
|
||||
}
|
||||
@ -332,7 +347,7 @@ class CPDF implements Canvas
|
||||
*
|
||||
* @param int $object
|
||||
*/
|
||||
function stop_object($object)
|
||||
public function stop_object($object)
|
||||
{
|
||||
$this->_pdf->stopObject($object);
|
||||
}
|
||||
@ -340,7 +355,7 @@ class CPDF implements Canvas
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
function serialize_object($id)
|
||||
public function serialize_object($id)
|
||||
{
|
||||
// Serialize the pdf object's current state for retrieval later
|
||||
return $this->_pdf->serializeObject($id);
|
||||
@ -349,7 +364,7 @@ class CPDF implements Canvas
|
||||
/**
|
||||
* @access private
|
||||
*/
|
||||
function reopen_serialized_object($obj)
|
||||
public function reopen_serialized_object($obj)
|
||||
{
|
||||
return $this->_pdf->restoreSerializedObject($obj);
|
||||
}
|
||||
@ -360,7 +375,7 @@ class CPDF implements Canvas
|
||||
* Returns the PDF's width in points
|
||||
* @return float
|
||||
*/
|
||||
function get_width()
|
||||
public function get_width()
|
||||
{
|
||||
return $this->_width;
|
||||
}
|
||||
@ -369,7 +384,7 @@ class CPDF implements Canvas
|
||||
* Returns the PDF's height in points
|
||||
* @return float
|
||||
*/
|
||||
function get_height()
|
||||
public function get_height()
|
||||
{
|
||||
return $this->_height;
|
||||
}
|
||||
@ -378,7 +393,7 @@ class CPDF implements Canvas
|
||||
* Returns the current page number
|
||||
* @return int
|
||||
*/
|
||||
function get_page_number()
|
||||
public function get_page_number()
|
||||
{
|
||||
return $this->_page_number;
|
||||
}
|
||||
@ -387,7 +402,7 @@ class CPDF implements Canvas
|
||||
* Returns the total number of pages in the document
|
||||
* @return int
|
||||
*/
|
||||
function get_page_count()
|
||||
public function get_page_count()
|
||||
{
|
||||
return $this->_page_count;
|
||||
}
|
||||
@ -397,7 +412,7 @@ class CPDF implements Canvas
|
||||
*
|
||||
* @param int $num
|
||||
*/
|
||||
function set_page_number($num)
|
||||
public function set_page_number($num)
|
||||
{
|
||||
$this->_page_number = $num;
|
||||
}
|
||||
@ -407,7 +422,7 @@ class CPDF implements Canvas
|
||||
*
|
||||
* @param int $count
|
||||
*/
|
||||
function set_page_count($count)
|
||||
public function set_page_count($count)
|
||||
{
|
||||
$this->_page_count = $count;
|
||||
}
|
||||
@ -421,6 +436,11 @@ class CPDF implements Canvas
|
||||
protected function _set_stroke_color($color)
|
||||
{
|
||||
$this->_pdf->setStrokeColor($color);
|
||||
$alpha = isset($color["alpha"]) ? $color["alpha"] : 1;
|
||||
if ($this->_current_opacity != 1) {
|
||||
$alpha *= $this->_current_opacity;
|
||||
}
|
||||
$this->_set_line_transparency("Normal", $alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -432,6 +452,11 @@ class CPDF implements Canvas
|
||||
protected function _set_fill_color($color)
|
||||
{
|
||||
$this->_pdf->setColor($color);
|
||||
$alpha = isset($color["alpha"]) ? $color["alpha"] : 1;
|
||||
if ($this->_current_opacity) {
|
||||
$alpha *= $this->_current_opacity;
|
||||
}
|
||||
$this->_set_fill_transparency("Normal", $alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -491,13 +516,14 @@ class CPDF implements Canvas
|
||||
* @param $opacity
|
||||
* @param $mode
|
||||
*/
|
||||
function set_opacity($opacity, $mode = "Normal")
|
||||
public function set_opacity($opacity, $mode = "Normal")
|
||||
{
|
||||
$this->_set_line_transparency($mode, $opacity);
|
||||
$this->_set_fill_transparency($mode, $opacity);
|
||||
$this->_current_opacity = $opacity;
|
||||
}
|
||||
|
||||
function set_default_view($view, $options = array())
|
||||
public function set_default_view($view, $options = array())
|
||||
{
|
||||
array_unshift($options, $view);
|
||||
call_user_func_array(array($this->_pdf, "openHere"), $options);
|
||||
@ -514,26 +540,47 @@ class CPDF implements Canvas
|
||||
return $this->_height - $y;
|
||||
}
|
||||
|
||||
// Canvas implementation
|
||||
function line($x1, $y1, $x2, $y2, $color, $width, $style = array())
|
||||
/**
|
||||
* Canvas implementation
|
||||
*
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $x2
|
||||
* @param float $y2
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
public function line($x1, $y1, $x2, $y2, $color, $width, $style = array())
|
||||
{
|
||||
$this->_set_stroke_color($color);
|
||||
$this->_set_line_style($width, "butt", "", $style);
|
||||
|
||||
$this->_pdf->line($x1, $this->y($y1),
|
||||
$x2, $this->y($y2));
|
||||
$this->_set_line_transparency("Normal", $this->_current_opacity);
|
||||
}
|
||||
|
||||
function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array())
|
||||
/**
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param float $r1
|
||||
* @param float $r2
|
||||
* @param float $astart
|
||||
* @param float $aend
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
public function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array())
|
||||
{
|
||||
$this->_set_stroke_color($color);
|
||||
$this->_set_line_style($width, "butt", "", $style);
|
||||
|
||||
$this->_pdf->ellipse($x, $this->y($y), $r1, $r2, 0, 8, $astart, $aend, false, false, true, false);
|
||||
$this->_set_line_transparency("Normal", $this->_current_opacity);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Convert a GIF or BMP image to a PNG image
|
||||
*
|
||||
@ -560,7 +607,7 @@ class CPDF implements Canvas
|
||||
if ($im) {
|
||||
imageinterlace($im, false);
|
||||
|
||||
$tmp_dir = $this->_dompdf->get_option("temp_dir");
|
||||
$tmp_dir = $this->_dompdf->getOptions()->getTempDir();
|
||||
$tmp_name = tempnam($tmp_dir, "{$type}dompdf_img_");
|
||||
@unlink($tmp_name);
|
||||
$filename = "$tmp_name.png";
|
||||
@ -577,70 +624,149 @@ class CPDF implements Canvas
|
||||
return $filename;
|
||||
}
|
||||
|
||||
function rectangle($x1, $y1, $w, $h, $color, $width, $style = array())
|
||||
/**
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
public function rectangle($x1, $y1, $w, $h, $color, $width, $style = array())
|
||||
{
|
||||
$this->_set_stroke_color($color);
|
||||
$this->_set_line_style($width, "butt", "", $style);
|
||||
$this->_pdf->rectangle($x1, $this->y($y1) - $h, $w, $h);
|
||||
$this->_set_line_transparency("Normal", $this->_current_opacity);
|
||||
}
|
||||
|
||||
function filled_rectangle($x1, $y1, $w, $h, $color)
|
||||
/**
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param array $color
|
||||
*/
|
||||
public function filled_rectangle($x1, $y1, $w, $h, $color)
|
||||
{
|
||||
$this->_set_fill_color($color);
|
||||
$this->_pdf->filledRectangle($x1, $this->y($y1) - $h, $w, $h);
|
||||
$this->_set_fill_transparency("Normal", $this->_current_opacity);
|
||||
}
|
||||
|
||||
function clipping_rectangle($x1, $y1, $w, $h)
|
||||
/**
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
*/
|
||||
public function clipping_rectangle($x1, $y1, $w, $h)
|
||||
{
|
||||
$this->_pdf->clippingRectangle($x1, $this->y($y1) - $h, $w, $h);
|
||||
}
|
||||
|
||||
function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
|
||||
/**
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
* @param float $rTL
|
||||
* @param float $rTR
|
||||
* @param float $rBR
|
||||
* @param float $rBL
|
||||
*/
|
||||
public function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
|
||||
{
|
||||
$this->_pdf->clippingRectangleRounded($x1, $this->y($y1) - $h, $w, $h, $rTL, $rTR, $rBR, $rBL);
|
||||
}
|
||||
|
||||
function clipping_end()
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function clipping_end()
|
||||
{
|
||||
$this->_pdf->clippingEnd();
|
||||
}
|
||||
|
||||
function save()
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$this->_pdf->saveState();
|
||||
}
|
||||
|
||||
function restore()
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function restore()
|
||||
{
|
||||
$this->_pdf->restoreState();
|
||||
}
|
||||
|
||||
function rotate($angle, $x, $y)
|
||||
/**
|
||||
* @param $angle
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public function rotate($angle, $x, $y)
|
||||
{
|
||||
$this->_pdf->rotate($angle, $x, $y);
|
||||
}
|
||||
|
||||
function skew($angle_x, $angle_y, $x, $y)
|
||||
/**
|
||||
* @param $angle_x
|
||||
* @param $angle_y
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public function skew($angle_x, $angle_y, $x, $y)
|
||||
{
|
||||
$this->_pdf->skew($angle_x, $angle_y, $x, $y);
|
||||
}
|
||||
|
||||
function scale($s_x, $s_y, $x, $y)
|
||||
/**
|
||||
* @param $s_x
|
||||
* @param $s_y
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public function scale($s_x, $s_y, $x, $y)
|
||||
{
|
||||
$this->_pdf->scale($s_x, $s_y, $x, $y);
|
||||
}
|
||||
|
||||
function translate($t_x, $t_y)
|
||||
/**
|
||||
* @param $t_x
|
||||
* @param $t_y
|
||||
*/
|
||||
public function translate($t_x, $t_y)
|
||||
{
|
||||
$this->_pdf->translate($t_x, $t_y);
|
||||
}
|
||||
|
||||
function transform($a, $b, $c, $d, $e, $f)
|
||||
/**
|
||||
* @param $a
|
||||
* @param $b
|
||||
* @param $c
|
||||
* @param $d
|
||||
* @param $e
|
||||
* @param $f
|
||||
*/
|
||||
public function transform($a, $b, $c, $d, $e, $f)
|
||||
{
|
||||
$this->_pdf->transform(array($a, $b, $c, $d, $e, $f));
|
||||
}
|
||||
|
||||
function polygon($points, $color, $width = null, $style = array(), $fill = false)
|
||||
/**
|
||||
* @param array $points
|
||||
* @param array $color
|
||||
* @param null $width
|
||||
* @param array $style
|
||||
* @param bool $fill
|
||||
*/
|
||||
public function polygon($points, $color, $width = null, $style = array(), $fill = false)
|
||||
{
|
||||
$this->_set_fill_color($color);
|
||||
$this->_set_stroke_color($color);
|
||||
@ -651,9 +777,21 @@ class CPDF implements Canvas
|
||||
}
|
||||
|
||||
$this->_pdf->polygon($points, count($points) / 2, $fill);
|
||||
|
||||
$this->_set_fill_transparency("Normal", $this->_current_opacity);
|
||||
$this->_set_line_transparency("Normal", $this->_current_opacity);
|
||||
}
|
||||
|
||||
function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false)
|
||||
/**
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param float $r1
|
||||
* @param array $color
|
||||
* @param null $width
|
||||
* @param null $style
|
||||
* @param bool $fill
|
||||
*/
|
||||
public function circle($x, $y, $r1, $color, $width = null, $style = null, $fill = false)
|
||||
{
|
||||
$this->_set_fill_color($color);
|
||||
$this->_set_stroke_color($color);
|
||||
@ -663,23 +801,39 @@ class CPDF implements Canvas
|
||||
}
|
||||
|
||||
$this->_pdf->ellipse($x, $this->y($y), $r1, 0, 0, 8, 0, 360, 1, $fill);
|
||||
|
||||
$this->_set_fill_transparency("Normal", $this->_current_opacity);
|
||||
$this->_set_line_transparency("Normal", $this->_current_opacity);
|
||||
}
|
||||
|
||||
function image($img, $x, $y, $w, $h, $resolution = "normal")
|
||||
/**
|
||||
* @param string $img
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param int $w
|
||||
* @param int $h
|
||||
* @param string $resolution
|
||||
*/
|
||||
public function image($img, $x, $y, $w, $h, $resolution = "normal")
|
||||
{
|
||||
list($width, $height, $type) = Helpers::dompdf_getimagesize($img, $this->get_dompdf()->getHttpContext());
|
||||
|
||||
$debug_png = $this->_dompdf->get_option("debug_png");
|
||||
$debug_png = $this->_dompdf->getOptions()->getDebugPng();
|
||||
|
||||
if ($debug_png) print "[image:$img|$width|$height|$type]";
|
||||
if ($debug_png) {
|
||||
print "[image:$img|$width|$height|$type]";
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case "jpeg":
|
||||
if ($debug_png) print '!!!jpg!!!';
|
||||
if ($debug_png) {
|
||||
print '!!!jpg!!!';
|
||||
}
|
||||
$this->_pdf->addJpegFromFile($img, $x, $this->y($y) - $h, $w, $h);
|
||||
break;
|
||||
|
||||
case "gif":
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case "bmp":
|
||||
if ($debug_png) print '!!!bmp or gif!!!';
|
||||
// @todo use cache for BMP and GIF
|
||||
@ -702,11 +856,22 @@ class CPDF implements Canvas
|
||||
}
|
||||
}
|
||||
|
||||
function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
|
||||
/**
|
||||
* @param float $x
|
||||
* @param float $y
|
||||
* @param string $text
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
* @param array $color
|
||||
* @param float $word_space
|
||||
* @param float $char_space
|
||||
* @param float $angle
|
||||
*/
|
||||
public function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
|
||||
{
|
||||
$pdf = $this->_pdf;
|
||||
|
||||
$pdf->setColor($color);
|
||||
$this->_set_fill_color($color);
|
||||
|
||||
$font .= ".afm";
|
||||
$pdf->selectFont($font);
|
||||
@ -741,11 +906,14 @@ class CPDF implements Canvas
|
||||
//
|
||||
//$pdf->addText($x, $this->y($y) - ($pdf->fonts[$pdf->currentFont]['FontBBox'][3]*$size)/1000, $size, $text, $angle, $word_space, $char_space);
|
||||
$pdf->addText($x, $this->y($y) - $pdf->getFontHeight($size), $size, $text, $angle, $word_space, $char_space);
|
||||
|
||||
$this->_set_fill_transparency("Normal", $this->_current_opacity);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function javascript($code)
|
||||
/**
|
||||
* @param string $code
|
||||
*/
|
||||
public function javascript($code)
|
||||
{
|
||||
$this->_pdf->addJavascript($code);
|
||||
}
|
||||
@ -757,13 +925,11 @@ class CPDF implements Canvas
|
||||
*
|
||||
* @param string $anchorname The name of the named destination
|
||||
*/
|
||||
function add_named_dest($anchorname)
|
||||
public function add_named_dest($anchorname)
|
||||
{
|
||||
$this->_pdf->addDestination($anchorname, "Fit");
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Add a link to the pdf
|
||||
*
|
||||
@ -773,9 +939,8 @@ class CPDF implements Canvas
|
||||
* @param float $width The width of the link
|
||||
* @param float $height The height of the link
|
||||
*/
|
||||
function add_link($url, $x, $y, $width, $height)
|
||||
public function add_link($url, $x, $y, $width, $height)
|
||||
{
|
||||
|
||||
$y = $this->y($y) - $height;
|
||||
|
||||
if (strpos($url, '#') === 0) {
|
||||
@ -784,40 +949,61 @@ class CPDF implements Canvas
|
||||
if ($name) {
|
||||
$this->_pdf->addInternalLink($name, $x, $y, $x + $width, $y + $height);
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->_pdf->addLink(rawurldecode($url), $x, $y, $x + $width, $y + $height);
|
||||
}
|
||||
}
|
||||
|
||||
function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0)
|
||||
/**
|
||||
* @param string $text
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
* @param int $word_spacing
|
||||
* @param int $char_spacing
|
||||
* @return float|int
|
||||
*/
|
||||
public function get_text_width($text, $font, $size, $word_spacing = 0, $char_spacing = 0)
|
||||
{
|
||||
$this->_pdf->selectFont($font);
|
||||
return $this->_pdf->getTextWidth($size, $text, $word_spacing, $char_spacing);
|
||||
}
|
||||
|
||||
function register_string_subset($font, $string)
|
||||
/**
|
||||
* @param $font
|
||||
* @param $string
|
||||
*/
|
||||
public function register_string_subset($font, $string)
|
||||
{
|
||||
$this->_pdf->registerText($font, $string);
|
||||
}
|
||||
|
||||
function get_font_height($font, $size)
|
||||
/**
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
* @return float|int
|
||||
*/
|
||||
public function get_font_height($font, $size)
|
||||
{
|
||||
$this->_pdf->selectFont($font);
|
||||
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
$ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
|
||||
return $this->_pdf->getFontHeight($size) * $ratio;
|
||||
}
|
||||
|
||||
/*function get_font_x_height($font, $size) {
|
||||
$this->_pdf->selectFont($font);
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
$ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
|
||||
return $this->_pdf->getFontXHeight($size) * $ratio;
|
||||
}*/
|
||||
|
||||
function get_font_baseline($font, $size)
|
||||
/**
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
* @return float
|
||||
*/
|
||||
public function get_font_baseline($font, $size)
|
||||
{
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
$ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
|
||||
return $this->get_font_height($font, $size) / $ratio;
|
||||
}
|
||||
|
||||
@ -839,7 +1025,7 @@ class CPDF implements Canvas
|
||||
* @param float $char_space char spacing adjustment
|
||||
* @param float $angle angle to write the text at, measured CW starting from the x-axis
|
||||
*/
|
||||
function page_text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
|
||||
public function page_text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0)
|
||||
{
|
||||
$_t = "text";
|
||||
$this->_page_text[] = compact("_t", "x", "y", "text", "font", "size", "color", "word_space", "char_space", "angle");
|
||||
@ -856,13 +1042,16 @@ class CPDF implements Canvas
|
||||
* @param string $code the script code
|
||||
* @param string $type the language type for script
|
||||
*/
|
||||
function page_script($code, $type = "text/php")
|
||||
public function page_script($code, $type = "text/php")
|
||||
{
|
||||
$_t = "script";
|
||||
$this->_page_text[] = compact("_t", "code", "type");
|
||||
}
|
||||
|
||||
function new_page()
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function new_page()
|
||||
{
|
||||
$this->_page_number++;
|
||||
$this->_page_count++;
|
||||
@ -877,7 +1066,6 @@ class CPDF implements Canvas
|
||||
*/
|
||||
protected function _add_page_text()
|
||||
{
|
||||
|
||||
if (!count($this->_page_text)) {
|
||||
return;
|
||||
}
|
||||
@ -913,31 +1101,50 @@ class CPDF implements Canvas
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the PDF directly to the browser
|
||||
* Streams the PDF to the client.
|
||||
*
|
||||
* @param string $filename the name of the PDF file
|
||||
* @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
|
||||
* @param string $filename The filename to present to the client.
|
||||
* @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
|
||||
*/
|
||||
function stream($filename, $options = null)
|
||||
public function stream($filename = "document.pdf", $options = array())
|
||||
{
|
||||
// Add page text
|
||||
if (headers_sent()) {
|
||||
die("Unable to stream pdf: headers already sent");
|
||||
}
|
||||
|
||||
if (!isset($options["compress"])) $options["compress"] = true;
|
||||
if (!isset($options["Attachment"])) $options["Attachment"] = true;
|
||||
|
||||
$this->_add_page_text();
|
||||
|
||||
$options["Content-Disposition"] = $filename;
|
||||
$this->_pdf->stream($options);
|
||||
$debug = !$options['compress'];
|
||||
$tmp = ltrim($this->_pdf->output($debug));
|
||||
|
||||
header("Cache-Control: private");
|
||||
header("Content-Type: application/pdf");
|
||||
header("Content-Length: " . mb_strlen($tmp, "8bit"));
|
||||
|
||||
$filename = str_replace(array("\n", "'"), "", basename($filename, ".pdf")) . ".pdf";
|
||||
$attachment = $options["Attachment"] ? "attachment" : "inline";
|
||||
header(Helpers::buildContentDispositionHeader($attachment, $filename));
|
||||
|
||||
echo $tmp;
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PDF as a string
|
||||
* Returns the PDF as a string.
|
||||
*
|
||||
* @param array $options Output options
|
||||
* @param array $options Associative array: 'compress' => 1 or 0 (default 1).
|
||||
* @return string
|
||||
*/
|
||||
function output($options = null)
|
||||
public function output($options = array())
|
||||
{
|
||||
if (!isset($options["compress"])) $options["compress"] = true;
|
||||
|
||||
$this->_add_page_text();
|
||||
|
||||
$debug = isset($options["compress"]) && $options["compress"] != 1;
|
||||
$debug = !$options['compress'];
|
||||
|
||||
return $this->_pdf->output($debug);
|
||||
}
|
||||
@ -947,7 +1154,7 @@ class CPDF implements Canvas
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function get_messages()
|
||||
public function get_messages()
|
||||
{
|
||||
return $this->_pdf->messages;
|
||||
}
|
||||
|
420
library/vendor/dompdf/src/Adapter/GD.php
vendored
420
library/vendor/dompdf/src/Adapter/GD.php
vendored
@ -138,7 +138,7 @@ class GD implements Canvas
|
||||
* @param float $aa_factor Anti-aliasing factor, 1 for no AA
|
||||
* @param array $bg_color Image background color: array(r,g,b,a), 0 <= r,g,b,a <= 1
|
||||
*/
|
||||
function __construct($size = 'letter', $orientation = "portrait", Dompdf $dompdf, $aa_factor = 1.0, $bg_color = array(1, 1, 1, 0))
|
||||
public function __construct($size = 'letter', $orientation = "portrait", Dompdf $dompdf, $aa_factor = 1.0, $bg_color = array(1, 1, 1, 0))
|
||||
{
|
||||
|
||||
if (!is_array($size)) {
|
||||
@ -157,7 +157,7 @@ class GD implements Canvas
|
||||
|
||||
$this->_dompdf = $dompdf;
|
||||
|
||||
$this->dpi = $this->get_dompdf()->get_option('dpi');
|
||||
$this->dpi = $this->get_dompdf()->getOptions()->getDpi();
|
||||
|
||||
if ($aa_factor < 1) {
|
||||
$aa_factor = 1;
|
||||
@ -184,7 +184,10 @@ class GD implements Canvas
|
||||
$this->new_page();
|
||||
}
|
||||
|
||||
function get_dompdf()
|
||||
/**
|
||||
* @return Dompdf
|
||||
*/
|
||||
public function get_dompdf()
|
||||
{
|
||||
return $this->_dompdf;
|
||||
}
|
||||
@ -194,7 +197,7 @@ class GD implements Canvas
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
function get_image()
|
||||
public function get_image()
|
||||
{
|
||||
return $this->_img;
|
||||
}
|
||||
@ -204,7 +207,7 @@ class GD implements Canvas
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_width()
|
||||
public function get_width()
|
||||
{
|
||||
return $this->_width / $this->_aa_factor;
|
||||
}
|
||||
@ -214,7 +217,7 @@ class GD implements Canvas
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_height()
|
||||
public function get_height()
|
||||
{
|
||||
return $this->_height / $this->_aa_factor;
|
||||
}
|
||||
@ -223,7 +226,7 @@ class GD implements Canvas
|
||||
* Returns the current page number
|
||||
* @return int
|
||||
*/
|
||||
function get_page_number()
|
||||
public function get_page_number()
|
||||
{
|
||||
return $this->_page_number;
|
||||
}
|
||||
@ -232,7 +235,7 @@ class GD implements Canvas
|
||||
* Returns the total number of pages in the document
|
||||
* @return int
|
||||
*/
|
||||
function get_page_count()
|
||||
public function get_page_count()
|
||||
{
|
||||
return $this->_page_count;
|
||||
}
|
||||
@ -242,7 +245,7 @@ class GD implements Canvas
|
||||
*
|
||||
* @param int $num
|
||||
*/
|
||||
function set_page_number($num)
|
||||
public function set_page_number($num)
|
||||
{
|
||||
$this->_page_number = $num;
|
||||
}
|
||||
@ -252,7 +255,7 @@ class GD implements Canvas
|
||||
*
|
||||
* @param int $count
|
||||
*/
|
||||
function set_page_count($count)
|
||||
public function set_page_count($count)
|
||||
{
|
||||
$this->_page_count = $count;
|
||||
}
|
||||
@ -263,7 +266,7 @@ class GD implements Canvas
|
||||
* @param $opacity
|
||||
* @param $mode
|
||||
*/
|
||||
function set_opacity($opacity, $mode = "Normal")
|
||||
public function set_opacity($opacity, $mode = "Normal")
|
||||
{
|
||||
// FIXME
|
||||
}
|
||||
@ -277,21 +280,18 @@ class GD implements Canvas
|
||||
*/
|
||||
private function _allocate_color($color)
|
||||
{
|
||||
$a = isset($color["alpha"]) ? $color["alpha"] : 1;
|
||||
|
||||
if (isset($color["c"])) {
|
||||
$color = Helpers::cmyk_to_rgb($color);
|
||||
}
|
||||
|
||||
// Full opacity if no alpha set
|
||||
if (!isset($color[3]))
|
||||
$color[3] = 0;
|
||||
|
||||
list($r, $g, $b, $a) = $color;
|
||||
list($r, $g, $b) = $color;
|
||||
|
||||
$r *= 255;
|
||||
$g *= 255;
|
||||
$b *= 255;
|
||||
$a *= 127;
|
||||
$a = 127 - ($a * 127);
|
||||
|
||||
// Clip values
|
||||
$r = $r > 255 ? 255 : $r;
|
||||
@ -306,16 +306,17 @@ class GD implements Canvas
|
||||
|
||||
$key = sprintf("#%02X%02X%02X%02X", $r, $g, $b, $a);
|
||||
|
||||
if (isset($this->_colors[$key]))
|
||||
if (isset($this->_colors[$key])) {
|
||||
return $this->_colors[$key];
|
||||
}
|
||||
|
||||
if ($a != 0)
|
||||
if ($a != 0) {
|
||||
$this->_colors[$key] = imagecolorallocatealpha($this->get_image(), $r, $g, $b, $a);
|
||||
else
|
||||
} else {
|
||||
$this->_colors[$key] = imagecolorallocate($this->get_image(), $r, $g, $b);
|
||||
}
|
||||
|
||||
return $this->_colors[$key];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -355,7 +356,7 @@ class GD implements Canvas
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
function line($x1, $y1, $x2, $y2, $color, $width, $style = null)
|
||||
public function line($x1, $y1, $x2, $y2, $color, $width, $style = null)
|
||||
{
|
||||
|
||||
// Scale by the AA factor and DPI
|
||||
@ -379,28 +380,26 @@ class GD implements Canvas
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
|
||||
$gd_style[] = $this->_bg_color;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$i = 0;
|
||||
foreach ($style as $length) {
|
||||
|
||||
if ($i % 2 == 0) {
|
||||
// 'On' pattern
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
|
||||
$gd_style[] = $c;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Off pattern
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++)
|
||||
for ($i = 0; $i < $style[0] * $this->_aa_factor; $i++) {
|
||||
$gd_style[] = $this->_bg_color;
|
||||
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($gd_style)) {
|
||||
if (!empty($gd_style)) {
|
||||
imagesetstyle($this->get_image(), $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
@ -409,10 +408,20 @@ class GD implements Canvas
|
||||
imagesetthickness($this->get_image(), $width);
|
||||
|
||||
imageline($this->get_image(), $x1, $y1, $x2, $y2, $c);
|
||||
|
||||
}
|
||||
|
||||
function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = array())
|
||||
/**
|
||||
* @param float $x1
|
||||
* @param float $y1
|
||||
* @param float $r1
|
||||
* @param float $r2
|
||||
* @param float $astart
|
||||
* @param float $aend
|
||||
* @param array $color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
public function arc($x1, $y1, $r1, $r2, $astart, $aend, $color, $width, $style = array())
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
@ -432,7 +441,7 @@ class GD implements Canvas
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*/
|
||||
function rectangle($x1, $y1, $w, $h, $color, $width, $style = null)
|
||||
public function rectangle($x1, $y1, $w, $h, $color, $width, $style = null)
|
||||
{
|
||||
|
||||
// Scale by the AA factor and DPI
|
||||
@ -454,7 +463,7 @@ class GD implements Canvas
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($gd_style)) {
|
||||
if (!empty($gd_style)) {
|
||||
imagesetstyle($this->get_image(), $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
@ -463,7 +472,6 @@ class GD implements Canvas
|
||||
imagesetthickness($this->get_image(), $width);
|
||||
|
||||
imagerectangle($this->get_image(), $x1, $y1, $x1 + $w, $y1 + $h, $c);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -477,9 +485,8 @@ class GD implements Canvas
|
||||
* @param float $h
|
||||
* @param array $color
|
||||
*/
|
||||
function filled_rectangle($x1, $y1, $w, $h, $color)
|
||||
public function filled_rectangle($x1, $y1, $w, $h, $color)
|
||||
{
|
||||
|
||||
// Scale by the AA factor and DPI
|
||||
$x1 = $this->_upscale($x1);
|
||||
$y1 = $this->_upscale($y1);
|
||||
@ -489,7 +496,6 @@ class GD implements Canvas
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
imagefilledrectangle($this->get_image(), $x1, $y1, $x1 + $w, $y1 + $h, $c);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,12 +506,12 @@ class GD implements Canvas
|
||||
* @param float $w
|
||||
* @param float $h
|
||||
*/
|
||||
function clipping_rectangle($x1, $y1, $w, $h)
|
||||
public function clipping_rectangle($x1, $y1, $w, $h)
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
|
||||
function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
|
||||
public function clipping_roundrectangle($x1, $y1, $w, $h, $rTL, $rTR, $rBR, $rBL)
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
@ -513,42 +519,77 @@ class GD implements Canvas
|
||||
/**
|
||||
* Ends the last clipping shape
|
||||
*/
|
||||
function clipping_end()
|
||||
public function clipping_end()
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
|
||||
function save()
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$this->get_dompdf()->set_option('dpi', 72);
|
||||
$this->get_dompdf()->getOptions()->setDpi(72);
|
||||
}
|
||||
|
||||
function restore()
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function restore()
|
||||
{
|
||||
$this->get_dompdf()->set_option('dpi', $this->dpi);
|
||||
$this->get_dompdf()->getOptions()->setDpi($this->dpi);
|
||||
}
|
||||
|
||||
function rotate($angle, $x, $y)
|
||||
/**
|
||||
* @param $angle
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public function rotate($angle, $x, $y)
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
|
||||
function skew($angle_x, $angle_y, $x, $y)
|
||||
/**
|
||||
* @param $angle_x
|
||||
* @param $angle_y
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public function skew($angle_x, $angle_y, $x, $y)
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
|
||||
function scale($s_x, $s_y, $x, $y)
|
||||
/**
|
||||
* @param $s_x
|
||||
* @param $s_y
|
||||
* @param $x
|
||||
* @param $y
|
||||
*/
|
||||
public function scale($s_x, $s_y, $x, $y)
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
|
||||
function translate($t_x, $t_y)
|
||||
/**
|
||||
* @param $t_x
|
||||
* @param $t_y
|
||||
*/
|
||||
public function translate($t_x, $t_y)
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
|
||||
function transform($a, $b, $c, $d, $e, $f)
|
||||
/**
|
||||
* @param $a
|
||||
* @param $b
|
||||
* @param $c
|
||||
* @param $d
|
||||
* @param $e
|
||||
* @param $f
|
||||
*/
|
||||
public function transform($a, $b, $c, $d, $e, $f)
|
||||
{
|
||||
// @todo
|
||||
}
|
||||
@ -577,12 +618,13 @@ class GD implements Canvas
|
||||
* @param array $style
|
||||
* @param bool $fill Fills the polygon if true
|
||||
*/
|
||||
function polygon($points, $color, $width = null, $style = null, $fill = false)
|
||||
public function polygon($points, $color, $width = null, $style = null, $fill = false)
|
||||
{
|
||||
|
||||
// Scale each point by the AA factor and DPI
|
||||
foreach (array_keys($points) as $i)
|
||||
foreach (array_keys($points) as $i) {
|
||||
$points[$i] = $this->_upscale($points[$i]);
|
||||
}
|
||||
|
||||
$c = $this->_allocate_color($color);
|
||||
|
||||
@ -596,7 +638,7 @@ class GD implements Canvas
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($gd_style)) {
|
||||
if (!empty($gd_style)) {
|
||||
imagesetstyle($this->get_image(), $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
@ -604,11 +646,11 @@ class GD implements Canvas
|
||||
|
||||
imagesetthickness($this->get_image(), $width);
|
||||
|
||||
if ($fill)
|
||||
if ($fill) {
|
||||
imagefilledpolygon($this->get_image(), $points, count($points) / 2, $c);
|
||||
else
|
||||
} else {
|
||||
imagepolygon($this->get_image(), $points, count($points) / 2, $c);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -626,9 +668,8 @@ class GD implements Canvas
|
||||
* @param array $style
|
||||
* @param bool $fill Fills the circle if true
|
||||
*/
|
||||
function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false)
|
||||
public function circle($x, $y, $r, $color, $width = null, $style = null, $fill = false)
|
||||
{
|
||||
|
||||
// Scale by the AA factor and DPI
|
||||
$x = $this->_upscale($x);
|
||||
$y = $this->_upscale($y);
|
||||
@ -646,7 +687,7 @@ class GD implements Canvas
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($gd_style)) {
|
||||
if (!empty($gd_style)) {
|
||||
imagesetstyle($this->get_image(), $gd_style);
|
||||
$c = IMG_COLOR_STYLED;
|
||||
}
|
||||
@ -654,11 +695,11 @@ class GD implements Canvas
|
||||
|
||||
imagesetthickness($this->get_image(), $width);
|
||||
|
||||
if ($fill)
|
||||
if ($fill) {
|
||||
imagefilledellipse($this->get_image(), $x, $y, $r, $r, $c);
|
||||
else
|
||||
} else {
|
||||
imageellipse($this->get_image(), $x, $y, $r, $r, $c);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -672,11 +713,12 @@ class GD implements Canvas
|
||||
* @param int $w width (in pixels)
|
||||
* @param int $h height (in pixels)
|
||||
* @param string $resolution
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Exception
|
||||
* @internal param string $img_type the type (e.g. extension) of the image
|
||||
*/
|
||||
function image($img_url, $x, $y, $w, $h, $resolution = "normal")
|
||||
public function image($img_url, $x, $y, $w, $h, $resolution = "normal")
|
||||
{
|
||||
$img_type = Cache::detect_type($img_url, $this->get_dompdf()->getHttpContext());
|
||||
|
||||
@ -684,14 +726,14 @@ class GD implements Canvas
|
||||
return;
|
||||
}
|
||||
|
||||
$func = "imagecreatefrom$img_type";
|
||||
$func_name = "imagecreatefrom$img_type";
|
||||
if (!function_exists($func_name)) {
|
||||
if (!method_exists("Dompdf\Helpers", $func_name)) {
|
||||
throw new Exception("Function $func_name() not found. Cannot convert $type image: $image_url. Please install the image PHP extension.");
|
||||
throw new \Exception("Function $func_name() not found. Cannot convert $type image: $img_url. Please install the image PHP extension.");
|
||||
}
|
||||
$func_name = "\\Dompdf\\Helpers::" . $func_name;
|
||||
}
|
||||
$src = @call_user_func($func_name, $image_url);
|
||||
$src = @call_user_func($func_name, $img_url);
|
||||
|
||||
if (!$src) {
|
||||
return; // Probably should add to $_dompdf_errors or whatever here
|
||||
@ -708,7 +750,6 @@ class GD implements Canvas
|
||||
$img_h = imagesy($src);
|
||||
|
||||
imagecopyresampled($this->get_image(), $src, $x, $y, 0, 0, $w, $h, $img_w, $img_h);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -727,9 +768,8 @@ class GD implements Canvas
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_spacing = 0.0, $char_spacing = 0.0, $angle = 0.0)
|
||||
public function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_spacing = 0.0, $char_spacing = 0.0, $angle = 0.0)
|
||||
{
|
||||
|
||||
// Scale by the AA factor and DPI
|
||||
$x = $this->_upscale($x);
|
||||
$y = $this->_upscale($y);
|
||||
@ -750,10 +790,9 @@ class GD implements Canvas
|
||||
|
||||
// FIXME: word spacing
|
||||
imagettftext($this->get_image(), $size, $angle, $x, $y + $h, $c, $font, $text);
|
||||
|
||||
}
|
||||
|
||||
function javascript($code)
|
||||
public function javascript($code)
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
@ -763,7 +802,7 @@ class GD implements Canvas
|
||||
*
|
||||
* @param string $anchorname The name of the named destination
|
||||
*/
|
||||
function add_named_dest($anchorname)
|
||||
public function add_named_dest($anchorname)
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
@ -777,7 +816,7 @@ class GD implements Canvas
|
||||
* @param float $width The width of the link
|
||||
* @param float $height The height of the link
|
||||
*/
|
||||
function add_link($url, $x, $y, $width, $height)
|
||||
public function add_link($url, $x, $y, $width, $height)
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
@ -788,12 +827,16 @@ class GD implements Canvas
|
||||
* @param string $label label of the value (Creator, Producer, etc.)
|
||||
* @param string $value the text to set
|
||||
*/
|
||||
function add_info($label, $value)
|
||||
public function add_info($label, $value)
|
||||
{
|
||||
// N/A
|
||||
}
|
||||
|
||||
function set_default_view($view, $options = array())
|
||||
/**
|
||||
* @param string $view
|
||||
* @param array $options
|
||||
*/
|
||||
public function set_default_view($view, $options = array())
|
||||
{
|
||||
// N/A
|
||||
}
|
||||
@ -809,7 +852,7 @@ class GD implements Canvas
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0)
|
||||
public function get_text_width($text, $font, $size, $word_spacing = 0.0, $char_spacing = 0.0)
|
||||
{
|
||||
$font = $this->get_ttf_file($font);
|
||||
$size = $this->_upscale($size) * self::FONT_SCALE;
|
||||
@ -829,16 +872,31 @@ class GD implements Canvas
|
||||
return $this->_downscale($x2 - $x1) + 1;
|
||||
}
|
||||
|
||||
function get_ttf_file($font)
|
||||
/**
|
||||
* @param $font
|
||||
* @return string
|
||||
*/
|
||||
public function get_ttf_file($font)
|
||||
{
|
||||
if (strpos($font, '.ttf') === false)
|
||||
if ( stripos($font, ".ttf") === false ) {
|
||||
$font .= ".ttf";
|
||||
}
|
||||
|
||||
/*$filename = substr(strtolower(basename($font)), 0, -4);
|
||||
|
||||
if ( in_array($filename, Dompdf::$native_fonts) ) {
|
||||
return "arial.ttf";
|
||||
}*/
|
||||
if (!file_exists($font)) {
|
||||
$font_metrics = $this->_dompdf->getFontMetrics();
|
||||
$font = $font_metrics->getFont($this->_dompdf->getOptions()->getDefaultFont()) . ".ttf";
|
||||
if (!file_exists($font)) {
|
||||
if (strpos($font, "mono")) {
|
||||
$font = $font_metrics->getFont("DejaVu Mono") . ".ttf";
|
||||
} elseif (strpos($font, "sans") !== false) {
|
||||
$font = $font_metrics->getFont("DejaVu Sans") . ".ttf";
|
||||
} elseif (strpos($font, "serif")) {
|
||||
$font = $font_metrics->getFont("DejaVu Serif") . ".ttf";
|
||||
} else {
|
||||
$font = $font_metrics->getFont("DejaVu Sans") . ".ttf";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $font;
|
||||
}
|
||||
@ -850,7 +908,7 @@ class GD implements Canvas
|
||||
* @param float $size
|
||||
* @return float
|
||||
*/
|
||||
function get_font_height($font, $size)
|
||||
public function get_font_height($font, $size)
|
||||
{
|
||||
$size = $this->_upscale($size) * self::FONT_SCALE;
|
||||
|
||||
@ -862,16 +920,21 @@ class GD implements Canvas
|
||||
private function get_font_height_actual($font, $size)
|
||||
{
|
||||
$font = $this->get_ttf_file($font);
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
$ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
|
||||
|
||||
// FIXME: word spacing
|
||||
list(, $y2, , , , $y1) = imagettfbbox($size, 0, $font, "MXjpqytfhl"); // Test string with ascenders, descenders and caps
|
||||
return ($y2 - $y1) * $ratio;
|
||||
}
|
||||
|
||||
function get_font_baseline($font, $size)
|
||||
/**
|
||||
* @param string $font
|
||||
* @param float $size
|
||||
* @return float
|
||||
*/
|
||||
public function get_font_baseline($font, $size)
|
||||
{
|
||||
$ratio = $this->_dompdf->get_option("font_height_ratio");
|
||||
$ratio = $this->_dompdf->getOptions()->getFontHeightRatio();
|
||||
return $this->get_font_height($font, $size) / $ratio;
|
||||
}
|
||||
|
||||
@ -880,7 +943,7 @@ class GD implements Canvas
|
||||
*
|
||||
* Subsequent drawing operations will appear on the new page.
|
||||
*/
|
||||
function new_page()
|
||||
public function new_page()
|
||||
{
|
||||
$this->_page_number++;
|
||||
$this->_page_count++;
|
||||
@ -895,39 +958,99 @@ class GD implements Canvas
|
||||
$this->_imgs[] = $this->_img;
|
||||
}
|
||||
|
||||
function open_object()
|
||||
public function open_object()
|
||||
{
|
||||
// N/A
|
||||
}
|
||||
|
||||
function close_object()
|
||||
public function close_object()
|
||||
{
|
||||
// N/A
|
||||
}
|
||||
|
||||
function add_object()
|
||||
public function add_object()
|
||||
{
|
||||
// N/A
|
||||
}
|
||||
|
||||
function page_text()
|
||||
public function page_text()
|
||||
{
|
||||
// N/A
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the image directly to the browser
|
||||
* Streams the image to the client.
|
||||
*
|
||||
* @param string $filename the name of the image file (ignored)
|
||||
* @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
|
||||
* @param string $filename The filename to present to the client.
|
||||
* @param array $options Associative array: 'type' => jpeg|jpg|png; 'quality' => 0 - 100 (JPEG only);
|
||||
* 'page' => Number of the page to output (defaults to the first); 'Attachment': 1 or 0 (default 1).
|
||||
*/
|
||||
function stream($filename, $options = null)
|
||||
public function stream($filename, $options = array())
|
||||
{
|
||||
if (headers_sent()) {
|
||||
die("Unable to stream image: headers already sent");
|
||||
}
|
||||
|
||||
$img = $this->_imgs[0];
|
||||
if (!isset($options["type"])) $options["type"] = "png";
|
||||
if (!isset($options["Attachment"])) $options["Attachment"] = true;
|
||||
$type = strtolower($options["type"]);
|
||||
|
||||
if (isset($options['page']) && isset($this->_imgs[$options['page'] - 1])) {
|
||||
$img = $this->_imgs[$options['page'] - 1];
|
||||
switch ($type) {
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
$contentType = "image/jpeg";
|
||||
$extension = ".jpg";
|
||||
break;
|
||||
case "png":
|
||||
default:
|
||||
$contentType = "image/png";
|
||||
$extension = ".png";
|
||||
break;
|
||||
}
|
||||
|
||||
header("Cache-Control: private");
|
||||
header("Content-Type: $contentType");
|
||||
|
||||
$filename = str_replace(array("\n", "'"), "", basename($filename, ".$type")) . $extension;
|
||||
$attachment = $options["Attachment"] ? "attachment" : "inline";
|
||||
header(Helpers::buildContentDispositionHeader($attachment, $filename));
|
||||
|
||||
$this->_output($options);
|
||||
flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the image as a string.
|
||||
*
|
||||
* @param array $options Associative array: 'type' => jpeg|jpg|png; 'quality' => 0 - 100 (JPEG only);
|
||||
* 'page' => Number of the page to output (defaults to the first).
|
||||
* @return string
|
||||
*/
|
||||
public function output($options = array())
|
||||
{
|
||||
ob_start();
|
||||
|
||||
$this->_output($options);
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the image stream directly.
|
||||
*
|
||||
* @param array $options Associative array: 'type' => jpeg|jpg|png; 'quality' => 0 - 100 (JPEG only);
|
||||
* 'page' => Number of the page to output (defaults to the first).
|
||||
*/
|
||||
private function _output($options = array())
|
||||
{
|
||||
if (!isset($options["type"])) $options["type"] = "png";
|
||||
if (!isset($options["page"])) $options["page"] = 1;
|
||||
$type = strtolower($options["type"]);
|
||||
|
||||
if (isset($this->_imgs[$options["page"] - 1])) {
|
||||
$img = $this->_imgs[$options["page"] - 1];
|
||||
} else {
|
||||
$img = $this->_imgs[0];
|
||||
}
|
||||
|
||||
// Perform any antialiasing
|
||||
@ -942,114 +1065,23 @@ class GD implements Canvas
|
||||
$dst = $img;
|
||||
}
|
||||
|
||||
if (!isset($options["type"]))
|
||||
$options["type"] = "png";
|
||||
|
||||
$type = strtolower($options["type"]);
|
||||
|
||||
header("Cache-Control: private");
|
||||
|
||||
$filename = str_replace(array("\n", "'"), "", basename($filename));
|
||||
switch ($type) {
|
||||
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
$filename .= ".jpg";
|
||||
break;
|
||||
|
||||
case "png":
|
||||
default:
|
||||
$filename .= ".png";
|
||||
break;
|
||||
}
|
||||
$attach = (isset($options["Attachment"]) && $options["Attachment"]) ? "attachment" : "inline";
|
||||
|
||||
// detect the character encoding of the incoming file
|
||||
$encoding = mb_detect_encoding($filename);
|
||||
$fallbackfilename = mb_convert_encoding($filename, "ISO-8859-1", $encoding);
|
||||
$encodedfallbackfilename = rawurlencode($fallbackfilename);
|
||||
$encodedfilename = rawurlencode($filename);
|
||||
|
||||
header("Content-Disposition: $attach; filename=". $encodedfallbackfilename ."; filename*=UTF-8''$encodedfilename");
|
||||
|
||||
switch ($type) {
|
||||
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
if (!isset($options["quality"]))
|
||||
if (!isset($options["quality"])) {
|
||||
$options["quality"] = 75;
|
||||
}
|
||||
|
||||
header("Content-type: image/jpeg");
|
||||
imagejpeg($dst, '', $options["quality"]);
|
||||
imagejpeg($dst, null, $options["quality"]);
|
||||
break;
|
||||
|
||||
case "png":
|
||||
default:
|
||||
header("Content-type: image/png");
|
||||
imagepng($dst);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->_aa_factor != 1)
|
||||
imagedestroy($dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PNG as a string
|
||||
*
|
||||
* @param array $options associative array, 'type' => jpeg|jpg|png, 'quality' => 0 - 100 (jpeg only)
|
||||
* @return string
|
||||
*/
|
||||
function output($options = null)
|
||||
{
|
||||
|
||||
$img = $this->_imgs[0];
|
||||
|
||||
if (isset($options['page']) && isset($this->_imgs[$options['page'] - 1])) {
|
||||
$img = $this->_imgs[$options['page'] - 1];
|
||||
}
|
||||
|
||||
if ($this->_aa_factor != 1) {
|
||||
$dst_w = $this->_actual_width / $this->_aa_factor;
|
||||
$dst_h = $this->_actual_height / $this->_aa_factor;
|
||||
$dst = imagecreatetruecolor($dst_w, $dst_h);
|
||||
imagecopyresampled($dst, $img, 0, 0, 0, 0,
|
||||
$dst_w, $dst_h,
|
||||
$this->_actual_width, $this->_actual_height);
|
||||
} else {
|
||||
$dst = $img;
|
||||
}
|
||||
|
||||
if (!isset($options["type"]))
|
||||
$options["type"] = "png";
|
||||
|
||||
$type = $options["type"];
|
||||
|
||||
ob_start();
|
||||
|
||||
switch ($type) {
|
||||
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
if (!isset($options["quality"]))
|
||||
$options["quality"] = 75;
|
||||
|
||||
imagejpeg($dst, '', $options["quality"]);
|
||||
break;
|
||||
|
||||
case "png":
|
||||
default:
|
||||
imagepng($dst);
|
||||
break;
|
||||
}
|
||||
|
||||
$image = ob_get_clean();
|
||||
|
||||
if ($this->_aa_factor != 1)
|
||||
imagedestroy($dst);
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
642
library/vendor/dompdf/src/Adapter/PDFLib.php
vendored
642
library/vendor/dompdf/src/Adapter/PDFLib.php
vendored
File diff suppressed because it is too large
Load Diff
60
library/vendor/dompdf/src/Canvas.php
vendored
60
library/vendor/dompdf/src/Canvas.php
vendored
@ -142,26 +142,51 @@ interface Canvas
|
||||
|
||||
/**
|
||||
* Rotate
|
||||
*
|
||||
* @param float $angle angle in degrees for counter-clockwise rotation
|
||||
* @param float $x Origin abscissa
|
||||
* @param float $y Origin ordinate
|
||||
*/
|
||||
function rotate($angle, $x, $y);
|
||||
|
||||
/**
|
||||
* Skew
|
||||
*
|
||||
* @param float $angle_x
|
||||
* @param float $angle_y
|
||||
* @param float $x Origin abscissa
|
||||
* @param float $y Origin ordinate
|
||||
*/
|
||||
function skew($angle_x, $angle_y, $x, $y);
|
||||
|
||||
/**
|
||||
* Scale
|
||||
*
|
||||
* @param float $s_x scaling factor for width as percent
|
||||
* @param float $s_y scaling factor for height as percent
|
||||
* @param float $x Origin abscissa
|
||||
* @param float $y Origin ordinate
|
||||
*/
|
||||
function scale($s_x, $s_y, $x, $y);
|
||||
|
||||
/**
|
||||
* Translate
|
||||
*
|
||||
* @param float $t_x movement to the right
|
||||
* @param float $t_y movement to the bottom
|
||||
*/
|
||||
function translate($t_x, $t_y);
|
||||
|
||||
/**
|
||||
* Transform
|
||||
*
|
||||
* @param $a
|
||||
* @param $b
|
||||
* @param $c
|
||||
* @param $d
|
||||
* @param $e
|
||||
* @param $f
|
||||
* @return
|
||||
*/
|
||||
function transform($a, $b, $c, $d, $e, $f);
|
||||
|
||||
@ -236,8 +261,6 @@ interface Canvas
|
||||
* @param array $color Color
|
||||
* @param float $width
|
||||
* @param array $style
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function arc($x, $y, $r1, $r2, $astart, $aend, $color, $width, $style = array());
|
||||
|
||||
@ -254,8 +277,6 @@ interface Canvas
|
||||
* @param float $word_space word spacing adjustment
|
||||
* @param float $char_space char spacing adjustment
|
||||
* @param float $angle angle
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function text($x, $y, $text, $font, $size, $color = array(0, 0, 0), $word_space = 0.0, $char_space = 0.0, $angle = 0.0);
|
||||
|
||||
@ -274,8 +295,6 @@ interface Canvas
|
||||
* @param float $y The y position of the link
|
||||
* @param float $width The width of the link
|
||||
* @param float $height The height of the link
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function add_link($url, $x, $y, $width, $height);
|
||||
|
||||
@ -320,6 +339,21 @@ interface Canvas
|
||||
*/
|
||||
function get_font_baseline($font, $size);
|
||||
|
||||
/**
|
||||
* Returns the PDF's width in points
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_width();
|
||||
|
||||
|
||||
/**
|
||||
* Return the image's height in pixels
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function get_height();
|
||||
|
||||
/**
|
||||
* Returns the font x-height, in points
|
||||
*
|
||||
@ -371,18 +405,18 @@ interface Canvas
|
||||
function new_page();
|
||||
|
||||
/**
|
||||
* Streams the PDF directly to the browser
|
||||
* Streams the PDF directly to the browser.
|
||||
*
|
||||
* @param string $filename the name of the PDF file
|
||||
* @param array $options associative array, 'Attachment' => 0 or 1, 'compress' => 1 or 0
|
||||
* @param string $filename The filename to present to the browser.
|
||||
* @param array $options Associative array: 'compress' => 1 or 0 (default 1); 'Attachment' => 1 or 0 (default 1).
|
||||
*/
|
||||
function stream($filename, $options = null);
|
||||
function stream($filename, $options = array());
|
||||
|
||||
/**
|
||||
* Returns the PDF as a string
|
||||
* Returns the PDF as a string.
|
||||
*
|
||||
* @param array $options associative array: 'compress' => 1 or 0
|
||||
* @param array $options Associative array: 'compress' => 1 or 0 (default 1).
|
||||
* @return string
|
||||
*/
|
||||
function output($options = null);
|
||||
function output($options = array());
|
||||
}
|
||||
|
2
library/vendor/dompdf/src/CanvasFactory.php
vendored
2
library/vendor/dompdf/src/CanvasFactory.php
vendored
@ -34,7 +34,7 @@ class CanvasFactory
|
||||
*/
|
||||
static function get_instance(Dompdf $dompdf, $paper = null, $orientation = null, $class = null)
|
||||
{
|
||||
$backend = strtolower($dompdf->get_option('pdf_backend'));
|
||||
$backend = strtolower($dompdf->getOptions()->getPdfBackend());
|
||||
|
||||
if (isset($class) && class_exists($class, false)) {
|
||||
$class .= "_Adapter";
|
||||
|
18
library/vendor/dompdf/src/Cellmap.php
vendored
18
library/vendor/dompdf/src/Cellmap.php
vendored
@ -7,8 +7,6 @@
|
||||
*/
|
||||
namespace Dompdf;
|
||||
|
||||
use Dompdf\Exception;
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\FrameDecorator\Table as TableFrameDecorator;
|
||||
use Dompdf\FrameDecorator\TableCell as TableCellFrameDecorator;
|
||||
|
||||
@ -513,7 +511,6 @@ class Cellmap
|
||||
$display === "inline-table" ||
|
||||
in_array($display, TableFrameDecorator::$ROW_GROUPS)
|
||||
) {
|
||||
|
||||
$start_row = $this->__row;
|
||||
foreach ($frame->get_children() as $child) {
|
||||
// Ignore all Text frames and :before/:after pseudo-selector elements.
|
||||
@ -535,7 +532,6 @@ class Cellmap
|
||||
$this->_frames[$key]["frame"] = $frame;
|
||||
|
||||
if ($display !== "table-row" && $collapse) {
|
||||
|
||||
$bp = $style->get_border_properties();
|
||||
|
||||
// Resolve the borders
|
||||
@ -621,8 +617,14 @@ class Cellmap
|
||||
list($h, $v) = $this->_table->get_style()->border_spacing;
|
||||
|
||||
// Border spacing is effectively a margin between cells
|
||||
$v = $style->length_in_pt($v) / 2;
|
||||
$h = $style->length_in_pt($h) / 2;
|
||||
$v = $style->length_in_pt($v);
|
||||
if (is_numeric($v)) {
|
||||
$v = $v / 2;
|
||||
}
|
||||
$h = $style->length_in_pt($h);
|
||||
if (is_numeric($h)) {
|
||||
$h = $h / 2;
|
||||
}
|
||||
$style->margin = "$v $h";
|
||||
|
||||
// The additional 1/2 width gets added to the table proper
|
||||
@ -741,7 +743,7 @@ class Cellmap
|
||||
|
||||
$this->_cells[$r][$c] = null;
|
||||
unset($this->_cells[$r][$c]);
|
||||
|
||||
|
||||
// has multiple rows?
|
||||
if (isset($this->_frames[$id]) && count($this->_frames[$id]["rows"]) > 1) {
|
||||
// remove just the desired row, but leave the frame
|
||||
@ -797,7 +799,7 @@ class Cellmap
|
||||
$g_key = $group->get_id();
|
||||
$r_key = $last_row->get_id();
|
||||
|
||||
$r_rows = $this->_frames[$r_key]["rows"];
|
||||
$r_rows = $this->_frames[$g_key]["rows"];
|
||||
$this->_frames[$g_key]["rows"] = range($this->_frames[$g_key]["rows"][0], end($r_rows));
|
||||
}
|
||||
|
||||
|
@ -32,11 +32,11 @@ class AttributeTranslator
|
||||
'left' => 'float: left;',
|
||||
'right' => 'float: right;'
|
||||
),
|
||||
'border' => 'border: %0.2F px solid;',
|
||||
'height' => 'height: %s px;',
|
||||
'hspace' => 'padding-left: %1$0.2F px; padding-right: %1$0.2F px;',
|
||||
'vspace' => 'padding-top: %1$0.2F px; padding-bottom: %1$0.2F px;',
|
||||
'width' => 'width: %s px;',
|
||||
'border' => 'border: %0.2Fpx solid;',
|
||||
'height' => 'height: %spx;',
|
||||
'hspace' => 'padding-left: %1$0.2Fpx; padding-right: %1$0.2Fpx;',
|
||||
'vspace' => 'padding-top: %1$0.2Fpx; padding-bottom: %1$0.2Fpx;',
|
||||
'width' => 'width: %spx;',
|
||||
),
|
||||
'table' => array(
|
||||
'align' => array(
|
||||
@ -89,6 +89,10 @@ class AttributeTranslator
|
||||
'h6' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
//TODO: translate more form element attributes
|
||||
'input' => array(
|
||||
'size' => '!set_input_width'
|
||||
),
|
||||
'p' => array(
|
||||
'align' => 'text-align: %s;',
|
||||
),
|
||||
@ -508,6 +512,23 @@ class AttributeTranslator
|
||||
return ltrim($style, "; ");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $node
|
||||
* @param string $value
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
static protected function _set_input_width(\DOMElement $node, $value)
|
||||
{
|
||||
if (empty($value)) { return null; }
|
||||
|
||||
if ($node->hasAttribute("type") && in_array(strtolower($node->getAttribute("type")), array("text","password"))) {
|
||||
return sprintf("width: %Fem", (((int)$value * .65)+2));
|
||||
} else {
|
||||
return sprintf("width: %upx;", (int)$value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DOMElement $node
|
||||
* @param string $value
|
||||
|
41
library/vendor/dompdf/src/Css/Color.php
vendored
41
library/vendor/dompdf/src/Css/Color.php
vendored
@ -10,6 +10,8 @@
|
||||
|
||||
namespace Dompdf\Css;
|
||||
|
||||
use Dompdf\Helpers;
|
||||
|
||||
class Color
|
||||
{
|
||||
static $cssColorNames = array(
|
||||
@ -162,6 +164,10 @@ class Color
|
||||
"yellowgreen" => "9ACD32",
|
||||
);
|
||||
|
||||
/**
|
||||
* @param $color
|
||||
* @return array|mixed|null|string
|
||||
*/
|
||||
static function parse($color)
|
||||
{
|
||||
if (is_array($color)) {
|
||||
@ -191,10 +197,18 @@ class Color
|
||||
// #rgb format
|
||||
if ($length == 4 && $color[0] === "#") {
|
||||
return $cache[$color] = self::getArray($color[1] . $color[1] . $color[2] . $color[2] . $color[3] . $color[3]);
|
||||
} // #rgba format
|
||||
else if ($length == 5 && $color[0] === "#") {
|
||||
$alpha = round(hexdec($color[4] . $color[4])/255, 2);
|
||||
return $cache[$color] = self::getArray($color[1] . $color[1] . $color[2] . $color[2] . $color[3] . $color[3], $alpha);
|
||||
} // #rrggbb format
|
||||
else if ($length == 7 && $color[0] === "#") {
|
||||
return $cache[$color] = self::getArray(mb_substr($color, 1, 6));
|
||||
} // rgb( r,g,b ) / rgbaa( r,g,b,α ) format
|
||||
} // #rrggbbaa format
|
||||
else if ($length == 9 && $color[0] === "#") {
|
||||
$alpha = round(hexdec(mb_substr($color, 7, 2))/255, 2);
|
||||
return $cache[$color] = self::getArray(mb_substr($color, 1, 8), $alpha);
|
||||
} // rgb( r,g,b ) / rgba( r,g,b,α ) format
|
||||
else if (mb_strpos($color, "rgb") !== false) {
|
||||
$i = mb_strpos($color, "(");
|
||||
$j = mb_strpos($color, ")");
|
||||
@ -208,12 +222,12 @@ class Color
|
||||
|
||||
// alpha transparency
|
||||
// FIXME: not currently using transparency
|
||||
$alpha = 1;
|
||||
$alpha = 1.0;
|
||||
if (count($triplet) == 4) {
|
||||
$alpha = (float)(trim(array_pop($triplet)));
|
||||
// bad value, set to fully opaque
|
||||
if ($alpha > 1 || $alpha < 0) {
|
||||
$alpha = 1;
|
||||
if ($alpha > 1.0 || $alpha < 0.0) {
|
||||
$alpha = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,12 +238,12 @@ class Color
|
||||
foreach (array_keys($triplet) as $c) {
|
||||
$triplet[$c] = trim($triplet[$c]);
|
||||
|
||||
if ($triplet[$c][mb_strlen($triplet[$c]) - 1] === "%") {
|
||||
$triplet[$c] = round($triplet[$c] * 2.55);
|
||||
if (Helpers::is_percent($triplet[$c])) {
|
||||
$triplet[$c] = round((float)$triplet[$c] * 2.55);
|
||||
}
|
||||
}
|
||||
|
||||
return $cache[$color] = self::getArray(vsprintf("%02X%02X%02X", $triplet));
|
||||
return $cache[$color] = self::getArray(vsprintf("%02X%02X%02X", $triplet), $alpha);
|
||||
|
||||
}
|
||||
|
||||
@ -260,9 +274,14 @@ class Color
|
||||
return null;
|
||||
}
|
||||
|
||||
static function getArray($color)
|
||||
/**
|
||||
* @param $color
|
||||
* @param float $alpha
|
||||
* @return array
|
||||
*/
|
||||
static function getArray($color, $alpha = 1.0)
|
||||
{
|
||||
$c = array(null, null, null, null, "hex" => null);
|
||||
$c = array(null, null, null, null, "alpha" => $alpha, "hex" => null);
|
||||
|
||||
if (is_array($color)) {
|
||||
$c = $color;
|
||||
@ -270,6 +289,7 @@ class Color
|
||||
$c["m"] = $c[1];
|
||||
$c["y"] = $c[2];
|
||||
$c["k"] = $c[3];
|
||||
$c["alpha"] = $alpha;
|
||||
$c["hex"] = "cmyk($c[0],$c[1],$c[2],$c[3])";
|
||||
} else {
|
||||
$c[0] = hexdec(mb_substr($color, 0, 2)) / 0xff;
|
||||
@ -278,7 +298,8 @@ class Color
|
||||
$c["r"] = $c[0];
|
||||
$c["g"] = $c[1];
|
||||
$c["b"] = $c[2];
|
||||
$c["hex"] = "#$color";
|
||||
$c["alpha"] = $alpha;
|
||||
$c["hex"] = sprintf("#%s%02X", mb_substr($color, 0, 6), round($alpha * 255));
|
||||
}
|
||||
|
||||
return $c;
|
||||
|
502
library/vendor/dompdf/src/Css/Style.php
vendored
502
library/vendor/dompdf/src/Css/Style.php
vendored
File diff suppressed because it is too large
Load Diff
494
library/vendor/dompdf/src/Css/Stylesheet.php
vendored
494
library/vendor/dompdf/src/Css/Stylesheet.php
vendored
@ -9,6 +9,7 @@
|
||||
*/
|
||||
namespace Dompdf\Css;
|
||||
|
||||
use DOMElement;
|
||||
use DOMXPath;
|
||||
use Dompdf\Dompdf;
|
||||
use Dompdf\Helpers;
|
||||
@ -55,12 +56,29 @@ class Stylesheet
|
||||
*/
|
||||
const ORIG_AUTHOR = 3;
|
||||
|
||||
/*
|
||||
* The highest possible specificity is 0x01000000 (and that is only for author
|
||||
* stylesheets, as it is for inline styles). Origin precedence can be achieved by
|
||||
* adding multiples of 0x10000000 to the actual specificity. Important
|
||||
* declarations are handled in Style; though technically they should be handled
|
||||
* here so that user important declarations can be made to take precedence over
|
||||
* user important declarations, this doesn't matter in practice as Dompdf does
|
||||
* not support user stylesheets, and user agent stylesheets can not include
|
||||
* important declarations.
|
||||
*/
|
||||
private static $_stylesheet_origins = array(
|
||||
self::ORIG_UA => -0x0FFFFFFF, // user agent style sheets
|
||||
self::ORIG_USER => -0x0000FFFF, // user normal style sheets
|
||||
self::ORIG_AUTHOR => 0x00000000, // author normal style sheets
|
||||
self::ORIG_UA => 0x00000000, // user agent declarations
|
||||
self::ORIG_USER => 0x10000000, // user normal declarations
|
||||
self::ORIG_AUTHOR => 0x30000000, // author normal declarations
|
||||
);
|
||||
|
||||
/*
|
||||
* Non-CSS presentational hints (i.e. HTML 4 attributes) are handled as if added
|
||||
* to the beginning of an author stylesheet, i.e. anything in author stylesheets
|
||||
* should override them.
|
||||
*/
|
||||
const SPEC_NON_CSS = 0x20000000;
|
||||
|
||||
/**
|
||||
* Current dompdf instance
|
||||
*
|
||||
@ -135,6 +153,7 @@ class Stylesheet
|
||||
*/
|
||||
static $ACCEPTED_DEFAULT_MEDIA_TYPE = "print";
|
||||
static $ACCEPTED_GENERIC_MEDIA_TYPES = array("all", "static", "visual", "bitmap", "paged", "dompdf");
|
||||
static $VALID_MEDIA_TYPES = array("all", "aural", "bitmap", "braille", "dompdf", "embossed", "handheld", "paged", "print", "projection", "screen", "speech", "static", "tty", "tv", "visual");
|
||||
|
||||
/**
|
||||
* @var FontMetrics
|
||||
@ -253,23 +272,24 @@ class Stylesheet
|
||||
throw new Exception("CSS rule must be keyed by a string.");
|
||||
}
|
||||
|
||||
if (isset($this->_styles[$key])) {
|
||||
$this->_styles[$key]->merge($style);
|
||||
} else {
|
||||
$this->_styles[$key] = clone $style;
|
||||
if (!isset($this->_styles[$key])) {
|
||||
$this->_styles[$key] = array();
|
||||
}
|
||||
|
||||
$this->_styles[$key]->set_origin($this->_current_origin);
|
||||
$new_style = clone $style;
|
||||
$new_style->set_origin($this->_current_origin);
|
||||
$this->_styles[$key][] = $new_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* lookup a specifc Style object
|
||||
* lookup a specifc Style collection
|
||||
*
|
||||
* lookup() returns the Style specified by $key, or null if the Style is
|
||||
* lookup() returns the Style collection specified by $key, or null if the Style is
|
||||
* not found.
|
||||
*
|
||||
* @param string $key the selector of the requested Style
|
||||
* @return Style
|
||||
*
|
||||
* @Fixme _styles is a two dimensional array. It should produce wrong results
|
||||
*/
|
||||
function lookup($key)
|
||||
{
|
||||
@ -295,9 +315,13 @@ class Stylesheet
|
||||
* load and parse a CSS string
|
||||
*
|
||||
* @param string $css
|
||||
* @param int $origin
|
||||
*/
|
||||
function load_css(&$css)
|
||||
function load_css(&$css, $origin = self::ORIG_AUTHOR)
|
||||
{
|
||||
if ($origin) {
|
||||
$this->_current_origin = $origin;
|
||||
}
|
||||
$this->_parse_css($css);
|
||||
}
|
||||
|
||||
@ -336,14 +360,12 @@ class Stylesheet
|
||||
$file = Helpers::build_url($this->_protocol, $this->_base_host, $this->_base_path, $filename);
|
||||
}
|
||||
|
||||
set_error_handler(array("\\Dompdf\\Helpers", "record_warnings"));
|
||||
$css = file_get_contents($file, null, $this->_dompdf->get_http_context());
|
||||
restore_error_handler();
|
||||
list($css, $http_response_header) = Helpers::getFileContent($file, $this->_dompdf->getHttpContext());
|
||||
|
||||
$good_mime_type = true;
|
||||
|
||||
// See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/
|
||||
if (isset($http_response_header) && !$this->_dompdf->get_quirksmode()) {
|
||||
if (isset($http_response_header) && !$this->_dompdf->getQuirksmode()) {
|
||||
foreach ($http_response_header as $_header) {
|
||||
if (preg_match("@Content-Type:\s*([\w/]+)@i", $_header, $matches) &&
|
||||
($matches[1] !== "text/css")
|
||||
@ -367,11 +389,9 @@ class Stylesheet
|
||||
*
|
||||
* @param string $selector
|
||||
* @param int $origin :
|
||||
* - ua: user agent style sheets
|
||||
* - un: user normal style sheets
|
||||
* - an: author normal style sheets
|
||||
* - ai: author important style sheets
|
||||
* - ui: user important style sheets
|
||||
* - Stylesheet::ORIG_UA: user agent style sheet
|
||||
* - Stylesheet::ORIG_USER: user style sheet
|
||||
* - Stylesheet::ORIG_AUTHOR: author style sheet
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
@ -398,20 +418,20 @@ class Stylesheet
|
||||
//this can lead to a too small specificity
|
||||
//see _css_selector_to_xpath
|
||||
|
||||
if (!in_array($selector[0], array(" ", ">", ".", "#", "+", ":", "[")) /* && $selector !== "*"*/) {
|
||||
if (!in_array($selector[0], array(" ", ">", ".", "#", "+", ":", "[")) && $selector !== "*") {
|
||||
$d++;
|
||||
}
|
||||
|
||||
if ($this->_dompdf->get_option('debugCss')) {
|
||||
if ($this->_dompdf->getOptions()->getDebugCss()) {
|
||||
/*DEBUGCSS*/
|
||||
print "<pre>\n";
|
||||
/*DEBUGCSS*/
|
||||
printf("_specificity(): 0x%08x \"%s\"\n", ($a << 24) | ($b << 16) | ($c << 8) | ($d), $selector);
|
||||
printf("_specificity(): 0x%08x \"%s\"\n", self::$_stylesheet_origins[$origin] + (($a << 24) | ($b << 16) | ($c << 8) | ($d)), $selector);
|
||||
/*DEBUGCSS*/
|
||||
print "</pre>";
|
||||
}
|
||||
|
||||
return self::$_stylesheet_origins[$origin] + ($a << 24) | ($b << 16) | ($c << 8) | ($d);
|
||||
return self::$_stylesheet_origins[$origin] + (($a << 24) | ($b << 16) | ($c << 8) | ($d));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,16 +447,19 @@ class Stylesheet
|
||||
{
|
||||
|
||||
// Collapse white space and strip whitespace around delimiters
|
||||
// $search = array("/\\s+/", "/\\s+([.>#+:])\\s+/");
|
||||
// $replace = array(" ", "\\1");
|
||||
// $selector = preg_replace($search, $replace, trim($selector));
|
||||
//$search = array("/\\s+/", "/\\s+([.>#+:])\\s+/");
|
||||
//$replace = array(" ", "\\1");
|
||||
//$selector = preg_replace($search, $replace, trim($selector));
|
||||
|
||||
// Initial query (non-absolute)
|
||||
$query = "//";
|
||||
|
||||
// Will contain :before and :after if they must be created
|
||||
// Will contain :before and :after
|
||||
$pseudo_elements = array();
|
||||
|
||||
// Will contain :link, etc
|
||||
$pseudo_classes = array();
|
||||
|
||||
// Parse the selector
|
||||
//$s = preg_split("/([ :>.#+])/", $selector, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
|
||||
@ -466,18 +489,22 @@ class Stylesheet
|
||||
// Eat characters up to the next delimiter
|
||||
$tok = "";
|
||||
$in_attr = false;
|
||||
$in_func = false;
|
||||
|
||||
while ($i < $len) {
|
||||
$c = $selector[$i];
|
||||
$c_prev = $selector[$i - 1];
|
||||
|
||||
if (!$in_attr && in_array($c, $delimiters)) {
|
||||
if (!$in_func && !$in_attr && in_array($c, $delimiters) && !(($c == $c_prev) == ":")) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($c_prev === "[") {
|
||||
$in_attr = true;
|
||||
}
|
||||
if ($c_prev === "(") {
|
||||
$in_func = true;
|
||||
}
|
||||
|
||||
$tok .= $selector[$i++];
|
||||
|
||||
@ -485,6 +512,10 @@ class Stylesheet
|
||||
$in_attr = false;
|
||||
break;
|
||||
}
|
||||
if ($in_func && $c === ")") {
|
||||
$in_func = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($s) {
|
||||
@ -546,7 +577,7 @@ class Stylesheet
|
||||
|
||||
case ":":
|
||||
$i2 = $i - strlen($tok) - 2; // the char before ":"
|
||||
if (!isset($selector[$i2]) || in_array($selector[$i2], $delimiters)) {
|
||||
if (($i2 < 0 || !isset($selector[$i2]) || (in_array($selector[$i2], $delimiters) && $selector[$i2] != ":")) && substr($query, -1) != "*") {
|
||||
$query .= "*";
|
||||
}
|
||||
|
||||
@ -576,12 +607,17 @@ class Stylesheet
|
||||
break;
|
||||
|
||||
// an+b, n, odd, and even
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case "nth-last-of-type":
|
||||
case "nth-last-child":
|
||||
$last = true;
|
||||
|
||||
case "nth-of-type":
|
||||
case "nth-child":
|
||||
//FIXME: this fix-up is pretty ugly, would parsing the selector in reverse work better generally?
|
||||
$descendant_delimeter = strrpos($query, "::");
|
||||
$isChild = substr($query, $descendant_delimeter-5, 5) == "child";
|
||||
$el = substr($query, $descendant_delimeter+2);
|
||||
$query = substr($query, 0, strrpos($query, "/")) . ($isChild ? "/" : "//") . $el;
|
||||
|
||||
$pseudo_classes[$tok] = true;
|
||||
$p = $i + 1;
|
||||
$nth = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p));
|
||||
|
||||
@ -602,16 +638,73 @@ class Stylesheet
|
||||
$query .= "[$condition]";
|
||||
$tok = "";
|
||||
break;
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case "nth-last-child":
|
||||
$last = true;
|
||||
case "nth-child":
|
||||
//FIXME: this fix-up is pretty ugly, would parsing the selector in reverse work better generally?
|
||||
$descendant_delimeter = strrpos($query, "::");
|
||||
$isChild = substr($query, $descendant_delimeter-5, 5) == "child";
|
||||
$el = substr($query, $descendant_delimeter+2);
|
||||
$query = substr($query, 0, strrpos($query, "/")) . ($isChild ? "/" : "//") . "*";
|
||||
|
||||
$pseudo_classes[$tok] = true;
|
||||
$p = $i + 1;
|
||||
$nth = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p));
|
||||
|
||||
// 1
|
||||
if (preg_match("/^\d+$/", $nth)) {
|
||||
$condition = "position() = $nth";
|
||||
} // odd
|
||||
elseif ($nth === "odd") {
|
||||
$condition = "(position() mod 2) = 1";
|
||||
} // even
|
||||
elseif ($nth === "even") {
|
||||
$condition = "(position() mod 2) = 0";
|
||||
} // an+b
|
||||
else {
|
||||
$condition = $this->_selector_an_plus_b($nth, $last);
|
||||
}
|
||||
|
||||
$query .= "[$condition]";
|
||||
if ($el != "*") {
|
||||
$query .= "[name() = '$el']";
|
||||
}
|
||||
$tok = "";
|
||||
break;
|
||||
|
||||
//TODO: bit of a hack attempt at matches support, currently only matches against elements
|
||||
case "matches":
|
||||
$pseudo_classes[$tok] = true;
|
||||
$p = $i + 1;
|
||||
$matchList = trim(mb_substr($selector, $p, strpos($selector, ")", $i) - $p));
|
||||
|
||||
// Tag names are case-insensitive
|
||||
$elements = array_map("trim", explode(",", strtolower($matchList)));
|
||||
foreach ($elements as &$element) {
|
||||
$element = "name() = '$element'";
|
||||
}
|
||||
|
||||
$query .= "[" . implode(" or ", $elements) . "]";
|
||||
$tok = "";
|
||||
break;
|
||||
|
||||
case "link":
|
||||
$query .= "[@href]";
|
||||
$tok = "";
|
||||
break;
|
||||
|
||||
case "first-line": // TODO
|
||||
case "first-letter": // TODO
|
||||
case "first-line":
|
||||
case ":first-line":
|
||||
case "first-letter":
|
||||
case ":first-letter":
|
||||
// TODO
|
||||
$el = trim($tok, ":");
|
||||
$pseudo_elements[$el] = true;
|
||||
break;
|
||||
|
||||
// N/A
|
||||
case "focus":
|
||||
case "active":
|
||||
case "hover":
|
||||
case "visited":
|
||||
@ -621,11 +714,13 @@ class Stylesheet
|
||||
|
||||
/* Pseudo-elements */
|
||||
case "before":
|
||||
case ":before":
|
||||
case "after":
|
||||
if ($first_pass) {
|
||||
$pseudo_elements[$tok] = $tok;
|
||||
} else {
|
||||
$query .= "/*[@$tok]";
|
||||
case ":after":
|
||||
$pos = trim($tok, ":");
|
||||
$pseudo_elements[$pos] = true;
|
||||
if (!$first_pass) {
|
||||
$query .= "/*[@$pos]";
|
||||
}
|
||||
|
||||
$tok = "";
|
||||
@ -646,6 +741,12 @@ class Stylesheet
|
||||
$query .= "[not(@disabled)]";
|
||||
$tok = "";
|
||||
break;
|
||||
|
||||
// the selector is not handled, until we support all possible selectors force an empty set (silent failure)
|
||||
default:
|
||||
$query = "/../.."; // go up two levels because generated content starts on the body element
|
||||
$tok = "";
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -787,7 +888,13 @@ class Stylesheet
|
||||
return array("query" => $query, "pseudo_elements" => $pseudo_elements);
|
||||
}
|
||||
|
||||
// https://github.com/tenderlove/nokogiri/blob/master/lib/nokogiri/css/xpath_visitor.rb
|
||||
/**
|
||||
* https://github.com/tenderlove/nokogiri/blob/master/lib/nokogiri/css/xpath_visitor.rb
|
||||
*
|
||||
* @param $expr
|
||||
* @param bool $last
|
||||
* @return string
|
||||
*/
|
||||
protected function _selector_an_plus_b($expr, $last = false)
|
||||
{
|
||||
$expr = preg_replace("/\s/", "", $expr);
|
||||
@ -837,77 +944,103 @@ class Stylesheet
|
||||
|
||||
$styles = array();
|
||||
$xp = new DOMXPath($tree->get_dom());
|
||||
$DEBUGCSS = $this->_dompdf->getOptions()->getDebugCss();
|
||||
|
||||
// Add generated content
|
||||
foreach ($this->_styles as $selector => $style) {
|
||||
if (strpos($selector, ":before") === false && strpos($selector, ":after") === false) {
|
||||
continue;
|
||||
}
|
||||
foreach ($this->_styles as $selector => $selector_styles) {
|
||||
/** @var Style $style */
|
||||
foreach ($selector_styles as $style) {
|
||||
if (strpos($selector, ":before") === false && strpos($selector, ":after") === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$query = $this->_css_selector_to_xpath($selector, true);
|
||||
$query = $this->_css_selector_to_xpath($selector, true);
|
||||
|
||||
// Retrieve the nodes, limit to body for generated content
|
||||
$nodes = @$xp->query('.' . $query["query"]);
|
||||
if ($nodes == null) {
|
||||
Helpers::record_warnings(E_USER_WARNING, "The CSS selector '$selector' is not valid", __FILE__, __LINE__);
|
||||
continue;
|
||||
}
|
||||
// Retrieve the nodes, limit to body for generated content
|
||||
//TODO: If we use a context node can we remove the leading dot?
|
||||
$nodes = @$xp->query('.' . $query["query"]);
|
||||
if ($nodes == null) {
|
||||
Helpers::record_warnings(E_USER_WARNING, "The CSS selector '$selector' is not valid", __FILE__, __LINE__);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
foreach ($query["pseudo_elements"] as $pos) {
|
||||
// Do not add a new pseudo element if another one already matched
|
||||
if ($node->hasAttribute("dompdf_{$pos}_frame_id")) {
|
||||
/** @var \DOMElement $node */
|
||||
foreach ($nodes as $node) {
|
||||
// Only DOMElements get styles
|
||||
if ($node->nodeType != XML_ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (($src = $this->_image($style->content)) !== "none") {
|
||||
$new_node = $node->ownerDocument->createElement("img_generated");
|
||||
$new_node->setAttribute("src", $src);
|
||||
} else {
|
||||
$new_node = $node->ownerDocument->createElement("dompdf_generated");
|
||||
}
|
||||
foreach (array_keys($query["pseudo_elements"], true, true) as $pos) {
|
||||
// Do not add a new pseudo element if another one already matched
|
||||
if ($node->hasAttribute("dompdf_{$pos}_frame_id")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_node->setAttribute($pos, $pos);
|
||||
$new_frame_id = $tree->insert_node($node, $new_node, $pos);
|
||||
$node->setAttribute("dompdf_{$pos}_frame_id", $new_frame_id);
|
||||
if (($src = $this->_image($style->get_prop('content'))) !== "none") {
|
||||
$new_node = $node->ownerDocument->createElement("img_generated");
|
||||
$new_node->setAttribute("src", $src);
|
||||
} else {
|
||||
$new_node = $node->ownerDocument->createElement("dompdf_generated");
|
||||
}
|
||||
|
||||
$new_node->setAttribute($pos, $pos);
|
||||
$new_frame_id = $tree->insert_node($node, $new_node, $pos);
|
||||
$node->setAttribute("dompdf_{$pos}_frame_id", $new_frame_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply all styles in stylesheet
|
||||
foreach ($this->_styles as $selector => $style) {
|
||||
$query = $this->_css_selector_to_xpath($selector);
|
||||
foreach ($this->_styles as $selector => $selector_styles) {
|
||||
/** @var Style $style */
|
||||
foreach ($selector_styles as $style) {
|
||||
$query = $this->_css_selector_to_xpath($selector);
|
||||
|
||||
// Retrieve the nodes
|
||||
$nodes = @$xp->query($query["query"]);
|
||||
if ($nodes == null) {
|
||||
Helpers::record_warnings(E_USER_WARNING, "The CSS selector '$selector' is not valid", __FILE__, __LINE__);
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
// Retrieve the node id
|
||||
// Only DOMElements get styles
|
||||
if ($node->nodeType != XML_ELEMENT_NODE) {
|
||||
// Retrieve the nodes
|
||||
$nodes = @$xp->query($query["query"]);
|
||||
if ($nodes == null) {
|
||||
Helpers::record_warnings(E_USER_WARNING, "The CSS selector '$selector' is not valid", __FILE__, __LINE__);
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = $node->getAttribute("frame_id");
|
||||
$spec = $this->_specificity($selector, $style->get_origin());
|
||||
|
||||
// Assign the current style to the scratch array
|
||||
$spec = $this->_specificity($selector);
|
||||
$styles[$id][$spec][] = $style;
|
||||
foreach ($nodes as $node) {
|
||||
// Retrieve the node id
|
||||
// Only DOMElements get styles
|
||||
if ($node->nodeType != XML_ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = $node->getAttribute("frame_id");
|
||||
|
||||
// Assign the current style to the scratch array
|
||||
$styles[$id][$spec][] = $style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now create the styles and assign them to the appropriate frames. (We
|
||||
// Set the page width, height, and orientation based on the canvas paper size
|
||||
$canvas = $this->_dompdf->getCanvas();
|
||||
$paper_width = $canvas->get_width();
|
||||
$paper_height = $canvas->get_height();
|
||||
$paper_orientation = ($paper_width > $paper_height ? "landscape" : "portrait");
|
||||
|
||||
if ($this->_page_styles["base"] && is_array($this->_page_styles["base"]->size)) {
|
||||
$paper_width = $this->_page_styles['base']->size[0];
|
||||
$paper_height = $this->_page_styles['base']->size[1];
|
||||
$paper_orientation = ($paper_width > $paper_height ? "landscape" : "portrait");
|
||||
}
|
||||
|
||||
// Now create the styles and assign them to the appropriate frames. (We
|
||||
// iterate over the tree using an implicit FrameTree iterator.)
|
||||
$root_flg = false;
|
||||
foreach ($tree->get_frames() as $frame) {
|
||||
// Helpers::pre_r($frame->get_node()->nodeName . ":");
|
||||
if (!$root_flg && $this->_page_styles["base"]) {
|
||||
$style = $this->_page_styles["base"];
|
||||
$root_flg = true;
|
||||
} else {
|
||||
$style = $this->create_style();
|
||||
}
|
||||
@ -936,8 +1069,7 @@ class Stylesheet
|
||||
// Handle HTML 4.0 attributes
|
||||
AttributeTranslator::translate_attributes($frame);
|
||||
if (($str = $frame->get_node()->getAttribute(AttributeTranslator::$_style_attr)) !== "") {
|
||||
// Lowest specificity
|
||||
$styles[$id][1][] = $this->_parse_properties($str);
|
||||
$styles[$id][self::SPEC_NON_CSS][] = $this->_parse_properties($str);
|
||||
}
|
||||
|
||||
// Locate any additional style attributes
|
||||
@ -945,23 +1077,25 @@ class Stylesheet
|
||||
// Destroy CSS comments
|
||||
$str = preg_replace("'/\*.*?\*/'si", "", $str);
|
||||
|
||||
$spec = $this->_specificity("!attr");
|
||||
$spec = $this->_specificity("!attr", self::ORIG_AUTHOR);
|
||||
$styles[$id][$spec][] = $this->_parse_properties($str);
|
||||
}
|
||||
|
||||
// Grab the applicable styles
|
||||
if (isset($styles[$id])) {
|
||||
|
||||
/** @var array[][] $applied_styles */
|
||||
$applied_styles = $styles[$frame->get_id()];
|
||||
|
||||
// Sort by specificity
|
||||
ksort($applied_styles);
|
||||
|
||||
if ($this->_dompdf->get_option('debugCss')) {
|
||||
if ($DEBUGCSS) {
|
||||
$debug_nodename = $frame->get_node()->nodeName;
|
||||
print "<pre>\n[$debug_nodename\n";
|
||||
foreach ($applied_styles as $spec => $arr) {
|
||||
printf("specificity: 0x%08x\n", $spec);
|
||||
/** @var Style $s */
|
||||
foreach ($arr as $s) {
|
||||
print "[\n";
|
||||
$s->debug_print();
|
||||
@ -971,8 +1105,66 @@ class Stylesheet
|
||||
}
|
||||
|
||||
// Merge the new styles with the inherited styles
|
||||
$acceptedmedia = self::$ACCEPTED_GENERIC_MEDIA_TYPES;
|
||||
$acceptedmedia[] = $this->_dompdf->getOptions()->getDefaultMediaType();
|
||||
foreach ($applied_styles as $arr) {
|
||||
/** @var Style $s */
|
||||
foreach ($arr as $s) {
|
||||
$media_queries = $s->get_media_queries();
|
||||
foreach ($media_queries as $media_query) {
|
||||
list($media_query_feature, $media_query_value) = $media_query;
|
||||
// if any of the Style's media queries fail then do not apply the style
|
||||
//TODO: When the media query logic is fully developed we should not apply the Style when any of the media queries fail or are bad, per https://www.w3.org/TR/css3-mediaqueries/#error-handling
|
||||
if (in_array($media_query_feature, self::$VALID_MEDIA_TYPES)) {
|
||||
if ((strlen($media_query_feature) === 0 && !in_array($media_query, $acceptedmedia)) || (in_array($media_query, $acceptedmedia) && $media_query_value == "not")) {
|
||||
continue (3);
|
||||
}
|
||||
} else {
|
||||
switch ($media_query_feature) {
|
||||
case "height":
|
||||
if ($paper_height !== (float)$style->length_in_pt($media_query_value)) {
|
||||
continue (3);
|
||||
}
|
||||
break;
|
||||
case "min-height":
|
||||
if ($paper_height < (float)$style->length_in_pt($media_query_value)) {
|
||||
continue (3);
|
||||
}
|
||||
break;
|
||||
case "max-height":
|
||||
if ($paper_height > (float)$style->length_in_pt($media_query_value)) {
|
||||
continue (3);
|
||||
}
|
||||
break;
|
||||
case "width":
|
||||
if ($paper_width !== (float)$style->length_in_pt($media_query_value)) {
|
||||
continue (3);
|
||||
}
|
||||
break;
|
||||
case "min-width":
|
||||
//if (min($paper_width, $media_query_width) === $paper_width) {
|
||||
if ($paper_width < (float)$style->length_in_pt($media_query_value)) {
|
||||
continue (3);
|
||||
}
|
||||
break;
|
||||
case "max-width":
|
||||
//if (max($paper_width, $media_query_width) === $paper_width) {
|
||||
if ($paper_width > (float)$style->length_in_pt($media_query_value)) {
|
||||
continue (3);
|
||||
}
|
||||
break;
|
||||
case "orientation":
|
||||
if ($paper_orientation !== $media_query_value) {
|
||||
continue (3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Helpers::record_warnings(E_USER_WARNING, "Unknown media query: $media_query_feature", __FILE__, __LINE__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$style->merge($s);
|
||||
}
|
||||
}
|
||||
@ -981,7 +1173,7 @@ class Stylesheet
|
||||
// Inherit parent's styles if required
|
||||
if ($p) {
|
||||
|
||||
if ($this->_dompdf->get_option('debugCss')) {
|
||||
if ($DEBUGCSS) {
|
||||
print "inherit:\n";
|
||||
print "[\n";
|
||||
$p->get_style()->debug_print();
|
||||
@ -991,7 +1183,7 @@ class Stylesheet
|
||||
$style->inherit($p->get_style());
|
||||
}
|
||||
|
||||
if ($this->_dompdf->get_option('debugCss')) {
|
||||
if ($DEBUGCSS) {
|
||||
print "DomElementStyle:\n";
|
||||
print "[\n";
|
||||
$style->debug_print();
|
||||
@ -1006,6 +1198,17 @@ class Stylesheet
|
||||
echo "</pre>";*/
|
||||
$frame->set_style($style);
|
||||
|
||||
if (!$root_flg && $this->_page_styles["base"]) {
|
||||
$root_flg = true;
|
||||
|
||||
// set the page width, height, and orientation based on the parsed page style
|
||||
if ($style->size !== "auto") {
|
||||
list($paper_width, $paper_height) = $style->size;
|
||||
}
|
||||
$paper_width = $paper_width - (float)$style->length_in_pt($style->margin_left) - (float)$style->length_in_pt($style->margin_right);
|
||||
$paper_height = $paper_height - (float)$style->length_in_pt($style->margin_top) - (float)$style->length_in_pt($style->margin_bottom);
|
||||
$paper_orientation = ($paper_width > $paper_height ? "landscape" : "portrait");
|
||||
}
|
||||
}
|
||||
|
||||
// We're done! Clean out the registry of all styles since we
|
||||
@ -1049,8 +1252,8 @@ class Stylesheet
|
||||
" (?(6) (?>[^}]*) }) \s*)+? \n" .
|
||||
" ) \n" .
|
||||
" }) # Balancing '}' \n" .
|
||||
"| # Branch to match regular rules (not preceded by '@')\n" .
|
||||
"([^{]*{[^}]*})) # Parse normal rulesets\n" .
|
||||
"| # Branch to match regular rules (not preceded by '@') \n" .
|
||||
"([^{]*{[^}]*})) # Parse normal rulesets \n" .
|
||||
"/xs";
|
||||
|
||||
if (preg_match_all($re, $css, $matches, PREG_SET_ORDER) === false) {
|
||||
@ -1069,6 +1272,9 @@ class Stylesheet
|
||||
// [6] => '{', within media rules
|
||||
// [7] => individual rules, outside of media rules
|
||||
//
|
||||
|
||||
$media_query_regex = "/(?:((only|not)?\s*(" . implode("|", self::$VALID_MEDIA_TYPES) . "))|(\s*\(\s*((?:(min|max)-)?([\w\-]+))\s*(?:\:\s*(.*?)\s*)?\)))/isx";
|
||||
|
||||
//Helpers::pre_r($matches);
|
||||
foreach ($matches as $match) {
|
||||
$match[2] = trim($match[2]);
|
||||
@ -1083,12 +1289,33 @@ class Stylesheet
|
||||
|
||||
case "media":
|
||||
$acceptedmedia = self::$ACCEPTED_GENERIC_MEDIA_TYPES;
|
||||
$acceptedmedia[] = $this->_dompdf->get_option("default_media_type");
|
||||
$acceptedmedia[] = $this->_dompdf->getOptions()->getDefaultMediaType();
|
||||
|
||||
$media = preg_split("/\s*,\s*/", mb_strtolower(trim($match[3])));
|
||||
|
||||
if (count(array_intersect($acceptedmedia, $media))) {
|
||||
$this->_parse_sections($match[5]);
|
||||
$media_queries = preg_split("/\s*,\s*/", mb_strtolower(trim($match[3])));
|
||||
foreach ($media_queries as $media_query) {
|
||||
if (in_array($media_query, $acceptedmedia)) {
|
||||
//if we have a media type match go ahead and parse the stylesheet
|
||||
$this->_parse_sections($match[5]);
|
||||
break;
|
||||
} elseif (!in_array($media_query, self::$VALID_MEDIA_TYPES)) {
|
||||
// otherwise conditionally parse the stylesheet assuming there are parseable media queries
|
||||
if (preg_match_all($media_query_regex, $media_query, $media_query_matches, PREG_SET_ORDER) !== false) {
|
||||
$mq = array();
|
||||
foreach ($media_query_matches as $media_query_match) {
|
||||
if (empty($media_query_match[1]) === false) {
|
||||
$media_query_feature = strtolower($media_query_match[3]);
|
||||
$media_query_value = strtolower($media_query_match[2]);
|
||||
$mq[] = array($media_query_feature, $media_query_value);
|
||||
} else if (empty($media_query_match[4]) === false) {
|
||||
$media_query_feature = strtolower($media_query_match[5]);
|
||||
$media_query_value = (array_key_exists(8, $media_query_match) ? strtolower($media_query_match[8]) : null);
|
||||
$mq[] = array($media_query_feature, $media_query_value);
|
||||
}
|
||||
}
|
||||
$this->_parse_sections($match[5], $mq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1125,6 +1352,7 @@ class Stylesheet
|
||||
case ":right":
|
||||
case ":odd":
|
||||
case ":even":
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case ":first":
|
||||
$key = $page_selector;
|
||||
|
||||
@ -1159,16 +1387,21 @@ class Stylesheet
|
||||
}
|
||||
}
|
||||
|
||||
/* See also style.cls Style::_image(), refactoring?, works also for imported css files */
|
||||
/**
|
||||
* See also style.cls Style::_image(), refactoring?, works also for imported css files
|
||||
*
|
||||
* @param $val
|
||||
* @return string
|
||||
*/
|
||||
protected function _image($val)
|
||||
{
|
||||
$DEBUGCSS = $this->_dompdf->get_option('debugCss');
|
||||
$DEBUGCSS = $this->_dompdf->getOptions()->getDebugCss();
|
||||
$parsed_url = "none";
|
||||
|
||||
if (mb_strpos($val, "url") === false) {
|
||||
$path = "none"; //Don't resolve no image -> otherwise would prefix path and no longer recognize as none
|
||||
} else {
|
||||
$val = preg_replace("/url\(['\"]?([^'\")]+)['\"]?\)/", "\\1", trim($val));
|
||||
$val = preg_replace("/url\(\s*['\"]?([^'\")]+)['\"]?\s*\)/", "\\1", trim($val));
|
||||
|
||||
// Resolve the url now in the context of the current stylesheet
|
||||
$parsed_url = Helpers::explode_url($val);
|
||||
@ -1217,7 +1450,7 @@ class Stylesheet
|
||||
|
||||
if (count($arr) > 0) {
|
||||
$acceptedmedia = self::$ACCEPTED_GENERIC_MEDIA_TYPES;
|
||||
$acceptedmedia[] = $this->_dompdf->get_option("default_media_type");
|
||||
$acceptedmedia[] = $this->_dompdf->getOptions()->getDefaultMediaType();
|
||||
|
||||
// @import url media_type [media_type...]
|
||||
foreach ($arr as $type) {
|
||||
@ -1261,7 +1494,6 @@ class Stylesheet
|
||||
* http://www.w3.org/TR/css3-fonts/#the-font-face-rule
|
||||
*
|
||||
* @param string $str CSS @font-face rules
|
||||
* @return Style
|
||||
*/
|
||||
private function _parse_font_face($str)
|
||||
{
|
||||
@ -1276,7 +1508,7 @@ class Stylesheet
|
||||
$source = array(
|
||||
"local" => strtolower($src[1][$i]) === "local",
|
||||
"uri" => $src[2][$i],
|
||||
"format" => $src[4][$i],
|
||||
"format" => strtolower($src[4][$i]),
|
||||
"path" => Helpers::build_url($this->_protocol, $this->_base_host, $this->_base_path, $src[2][$i]),
|
||||
);
|
||||
|
||||
@ -1313,8 +1545,11 @@ class Stylesheet
|
||||
private function _parse_properties($str)
|
||||
{
|
||||
$properties = preg_split("/;(?=(?:[^\(]*\([^\)]*\))*(?![^\)]*\)))/", $str);
|
||||
$DEBUGCSS = $this->_dompdf->getOptions()->getDebugCss();
|
||||
|
||||
if ($this->_dompdf->get_option('debugCss')) print '[_parse_properties';
|
||||
if ($DEBUGCSS) {
|
||||
print '[_parse_properties';
|
||||
}
|
||||
|
||||
// Create the style
|
||||
$style = new Style($this, Stylesheet::ORIG_AUTHOR);
|
||||
@ -1342,7 +1577,7 @@ class Stylesheet
|
||||
}
|
||||
$prop = trim($prop);
|
||||
*/
|
||||
if ($this->_dompdf->get_option('debugCss')) print '(';
|
||||
if ($DEBUGCSS) print '(';
|
||||
|
||||
$important = false;
|
||||
$prop = trim($prop);
|
||||
@ -1357,19 +1592,19 @@ class Stylesheet
|
||||
}
|
||||
|
||||
if ($prop === "") {
|
||||
if ($this->_dompdf->get_option('debugCss')) print 'empty)';
|
||||
if ($DEBUGCSS) print 'empty)';
|
||||
continue;
|
||||
}
|
||||
|
||||
$i = mb_strpos($prop, ":");
|
||||
if ($i === false) {
|
||||
if ($this->_dompdf->get_option('debugCss')) print 'novalue' . $prop . ')';
|
||||
if ($DEBUGCSS) print 'novalue' . $prop . ')';
|
||||
continue;
|
||||
}
|
||||
|
||||
$prop_name = rtrim(mb_strtolower(mb_substr($prop, 0, $i)));
|
||||
$value = ltrim(mb_substr($prop, $i + 1));
|
||||
if ($this->_dompdf->get_option('debugCss')) print $prop_name . ':=' . $value . ($important ? '!IMPORTANT' : '') . ')';
|
||||
if ($DEBUGCSS) print $prop_name . ':=' . $value . ($important ? '!IMPORTANT' : '') . ')';
|
||||
//New style, anyway empty
|
||||
//if ($important || !$style->important_get($prop_name) ) {
|
||||
//$style->$prop_name = array($value,$important);
|
||||
@ -1383,7 +1618,7 @@ class Stylesheet
|
||||
$style->$prop_name = $value;
|
||||
//$style->props_set($prop_name, $value);
|
||||
}
|
||||
if ($this->_dompdf->get_option('debugCss')) print '_parse_properties]';
|
||||
if ($DEBUGCSS) print '_parse_properties]';
|
||||
|
||||
return $style;
|
||||
}
|
||||
@ -1392,8 +1627,9 @@ class Stylesheet
|
||||
* parse selector + rulesets
|
||||
*
|
||||
* @param string $str CSS selectors and rulesets
|
||||
* @param array $media_queries
|
||||
*/
|
||||
private function _parse_sections($str)
|
||||
private function _parse_sections($str, $media_queries = array())
|
||||
{
|
||||
// Pre-process: collapse all whitespace and strip whitespace around '>',
|
||||
// '.', ':', '+', '#'
|
||||
@ -1401,14 +1637,18 @@ class Stylesheet
|
||||
$patterns = array("/[\\s\n]+/", "/\\s+([>.:+#])\\s+/");
|
||||
$replacements = array(" ", "\\1");
|
||||
$str = preg_replace($patterns, $replacements, $str);
|
||||
$DEBUGCSS = $this->_dompdf->getOptions()->getDebugCss();
|
||||
|
||||
$sections = explode("}", $str);
|
||||
if ($this->_dompdf->get_option('debugCss')) print '[_parse_sections';
|
||||
if ($DEBUGCSS) print '[_parse_sections';
|
||||
foreach ($sections as $sect) {
|
||||
$i = mb_strpos($sect, "{");
|
||||
if ($i === false) { continue; }
|
||||
|
||||
//$selectors = explode(",", mb_substr($sect, 0, $i));
|
||||
$selectors = preg_split("/,(?![^\(]*\))/", mb_substr($sect, 0, $i),0, PREG_SPLIT_NO_EMPTY);
|
||||
if ($DEBUGCSS) print '[section';
|
||||
|
||||
$selectors = explode(",", mb_substr($sect, 0, $i));
|
||||
if ($this->_dompdf->get_option('debugCss')) print '[section';
|
||||
$style = $this->_parse_properties(trim(mb_substr($sect, $i + 1)));
|
||||
|
||||
// Assign it to the selected elements
|
||||
@ -1416,21 +1656,32 @@ class Stylesheet
|
||||
$selector = trim($selector);
|
||||
|
||||
if ($selector == "") {
|
||||
if ($this->_dompdf->get_option('debugCss')) print '#empty#';
|
||||
if ($DEBUGCSS) print '#empty#';
|
||||
continue;
|
||||
}
|
||||
if ($this->_dompdf->get_option('debugCss')) print '#' . $selector . '#';
|
||||
//if ($this->_dompdf->get_option('debugCss')) { if (strpos($selector,'p') !== false) print '!!!p!!!#'; }
|
||||
if ($DEBUGCSS) print '#' . $selector . '#';
|
||||
//if ($DEBUGCSS) { if (strpos($selector,'p') !== false) print '!!!p!!!#'; }
|
||||
|
||||
//FIXME: tag the selector with a hash of the media query to separate it from non-conditional styles (?), xpath comments are probably not what we want to do here
|
||||
if (count($media_queries) > 0) {
|
||||
$style->set_media_queries($media_queries);
|
||||
}
|
||||
$this->add_style($selector, $style);
|
||||
}
|
||||
|
||||
if ($this->_dompdf->get_option('debugCss')) print 'section]';
|
||||
if ($DEBUGCSS) {
|
||||
print 'section]';
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_dompdf->get_option('debugCss')) print '_parse_sections]';
|
||||
if ($DEBUGCSS) {
|
||||
print '_parse_sections]';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getDefaultStylesheet()
|
||||
{
|
||||
$dir = realpath(__DIR__ . "/../..");
|
||||
@ -1466,8 +1717,11 @@ class Stylesheet
|
||||
function __toString()
|
||||
{
|
||||
$str = "";
|
||||
foreach ($this->_styles as $selector => $style) {
|
||||
$str .= "$selector => " . $style->__toString() . "\n";
|
||||
foreach ($this->_styles as $selector => $selector_styles) {
|
||||
/** @var Style $style */
|
||||
foreach ($selector_styles as $style) {
|
||||
$str .= "$selector => " . $style->__toString() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
|
307
library/vendor/dompdf/src/Dompdf.php
vendored
307
library/vendor/dompdf/src/Dompdf.php
vendored
@ -12,14 +12,12 @@ use DOMDocument;
|
||||
use DOMNode;
|
||||
use Dompdf\Adapter\CPDF;
|
||||
use DOMXPath;
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\Frame\Factory;
|
||||
use Dompdf\Frame\FrameTree;
|
||||
use HTML5_Tokenizer;
|
||||
use HTML5_TreeBuilder;
|
||||
use Dompdf\Image\Cache;
|
||||
use Dompdf\Renderer\ListBullet;
|
||||
use Dompdf\Renderer;
|
||||
use Dompdf\Css\Stylesheet;
|
||||
|
||||
/**
|
||||
@ -77,7 +75,7 @@ class Dompdf
|
||||
* @var string
|
||||
*/
|
||||
private $version = 'dompdf';
|
||||
|
||||
|
||||
/**
|
||||
* DomDocument representing the HTML document
|
||||
*
|
||||
@ -99,12 +97,6 @@ class Dompdf
|
||||
*/
|
||||
private $css;
|
||||
|
||||
/**
|
||||
* @var Canvas
|
||||
* @deprecated
|
||||
*/
|
||||
private $pdf;
|
||||
|
||||
/**
|
||||
* Actual PDF renderer
|
||||
*
|
||||
@ -216,13 +208,13 @@ class Dompdf
|
||||
/**
|
||||
* Protocol whitelist
|
||||
*
|
||||
* Protocols and PHP wrappers allowed in URLs. Full support is not
|
||||
* Protocols and PHP wrappers allowed in URLs. Full support is not
|
||||
* guarantee for the protocols/wrappers contained in this array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $allowedProtocols = array(null, "", "file://", "http://", "https://");
|
||||
|
||||
|
||||
/**
|
||||
* Local file extension whitelist
|
||||
*
|
||||
@ -231,7 +223,7 @@ class Dompdf
|
||||
* @var array
|
||||
*/
|
||||
private $allowedLocalFileExtensions = array("htm", "html");
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
@ -280,7 +272,7 @@ class Dompdf
|
||||
public function __construct($options = null)
|
||||
{
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
|
||||
if (isset($options) && $options instanceof Options) {
|
||||
$this->setOptions($options);
|
||||
} elseif (is_array($options)) {
|
||||
@ -288,7 +280,7 @@ class Dompdf
|
||||
} else {
|
||||
$this->setOptions(new Options());
|
||||
}
|
||||
|
||||
|
||||
$versionFile = realpath(__DIR__ . '/../VERSION');
|
||||
if (file_exists($versionFile) && ($version = file_get_contents($versionFile)) !== false && $version !== '$Format:<%h>$') {
|
||||
$this->version = sprintf('dompdf %s', $version);
|
||||
@ -297,6 +289,7 @@ class Dompdf
|
||||
$this->localeStandard = sprintf('%.1f', 1.0) == '1.0';
|
||||
$this->saveLocale();
|
||||
$this->paperSize = $this->options->getDefaultPaperSize();
|
||||
$this->paperOrientation = $this->options->getDefaultPaperOrientation();
|
||||
|
||||
$this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
|
||||
$this->setFontMetrics(new FontMetrics($this->getCanvas(), $this->getOptions()));
|
||||
@ -355,30 +348,29 @@ class Dompdf
|
||||
if (!$this->protocol && !$this->baseHost && !$this->basePath) {
|
||||
list($this->protocol, $this->baseHost, $this->basePath) = Helpers::explode_url($file);
|
||||
}
|
||||
$protocol = strtolower($this->protocol);
|
||||
|
||||
if ( !in_array($this->protocol, $this->allowedProtocols) ) {
|
||||
if ( !in_array($protocol, $this->allowedProtocols) ) {
|
||||
throw new Exception("Permission denied on $file. The communication protocol is not supported.");
|
||||
}
|
||||
|
||||
if (!$this->options->isRemoteEnabled() && ($this->protocol != "" && $this->protocol !== "file://")) {
|
||||
|
||||
if (!$this->options->isRemoteEnabled() && ($protocol != "" && $protocol !== "file://")) {
|
||||
throw new Exception("Remote file requested, but remote file download is disabled.");
|
||||
}
|
||||
|
||||
if ($this->protocol == "" || $this->protocol === "file://") {
|
||||
|
||||
// Get the full path to $file, returns false if the file doesn't exist
|
||||
if ($protocol == "" || $protocol === "file://") {
|
||||
$realfile = realpath($file);
|
||||
|
||||
$chroot = $this->options->getChroot();
|
||||
if (strpos($realfile, $chroot) !== 0) {
|
||||
|
||||
$chroot = realpath($this->options->getChroot());
|
||||
if ($chroot && strpos($realfile, $chroot) !== 0) {
|
||||
throw new Exception("Permission denied on $file. The file could not be found under the directory specified by Options::chroot.");
|
||||
}
|
||||
|
||||
$ext = pathinfo($realfile, PATHINFO_EXTENSION);
|
||||
$ext = strtolower(pathinfo($realfile, PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, $this->allowedLocalFileExtensions)) {
|
||||
throw new Exception("Permission denied on $file.");
|
||||
}
|
||||
|
||||
|
||||
if (!$realfile) {
|
||||
throw new Exception("File '$file' not found.");
|
||||
}
|
||||
@ -386,8 +378,8 @@ class Dompdf
|
||||
$file = $realfile;
|
||||
}
|
||||
|
||||
$contents = file_get_contents($file, null, $this->httpContext);
|
||||
$encoding = null;
|
||||
list($contents, $http_response_header) = Helpers::getFileContent($file, $this->httpContext);
|
||||
$encoding = 'UTF-8';
|
||||
|
||||
// See http://the-stickman.com/web-development/php/getting-http-response-headers-when-using-file_get_contents/
|
||||
if (isset($http_response_header)) {
|
||||
@ -409,7 +401,7 @@ class Dompdf
|
||||
* @param null $encoding
|
||||
* @deprecated
|
||||
*/
|
||||
public function load_html($str, $encoding = null)
|
||||
public function load_html($str, $encoding = 'UTF-8')
|
||||
{
|
||||
$this->loadHtml($str, $encoding);
|
||||
}
|
||||
@ -422,50 +414,42 @@ class Dompdf
|
||||
* @param string $str HTML text to load
|
||||
* @param string $encoding Not used yet
|
||||
*/
|
||||
public function loadHtml($str, $encoding = null)
|
||||
public function loadHtml($str, $encoding = 'UTF-8')
|
||||
{
|
||||
$this->saveLocale();
|
||||
|
||||
// FIXME: Determine character encoding, switch to UTF8, update meta tag. Need better http/file stream encoding detection, currently relies on text or meta tag.
|
||||
$known_encodings = mb_list_encodings();
|
||||
mb_detect_order('auto');
|
||||
|
||||
if (mb_detect_encoding($str) !== 'UTF-8') {
|
||||
$metatags = array(
|
||||
'@<meta\s+http-equiv="Content-Type"\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))?@i',
|
||||
'@<meta\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))"?\s+http-equiv="Content-Type"@i',
|
||||
'@<meta [^>]*charset\s*=\s*["\']?\s*([^"\' ]+)@i',
|
||||
);
|
||||
|
||||
foreach ($metatags as $metatag) {
|
||||
if (preg_match($metatag, $str, $matches)) break;
|
||||
}
|
||||
|
||||
if (mb_detect_encoding($str) == '') {
|
||||
if (isset($matches[1])) {
|
||||
$encoding = strtoupper($matches[1]);
|
||||
} else {
|
||||
$encoding = 'UTF-8';
|
||||
}
|
||||
} else {
|
||||
if (isset($matches[1])) {
|
||||
$encoding = strtoupper($matches[1]);
|
||||
} else {
|
||||
$encoding = 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
if ($encoding !== 'UTF-8') {
|
||||
$str = mb_convert_encoding($str, 'UTF-8', $encoding);
|
||||
}
|
||||
|
||||
if (isset($matches[1])) {
|
||||
$str = preg_replace('/charset=([^\s"]+)/i', 'charset=UTF-8', $str);
|
||||
} else {
|
||||
$str = str_replace('<head>', '<head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">', $str);
|
||||
}
|
||||
} else {
|
||||
$encoding = 'UTF-8';
|
||||
if (($file_encoding = mb_detect_encoding($str, null, true)) === false) {
|
||||
$file_encoding = "auto";
|
||||
}
|
||||
if (in_array(strtoupper($file_encoding), array('UTF-8','UTF8')) === false) {
|
||||
$str = mb_convert_encoding($str, 'UTF-8', $file_encoding);
|
||||
}
|
||||
|
||||
$metatags = array(
|
||||
'@<meta\s+http-equiv="Content-Type"\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))?@i',
|
||||
'@<meta\s+content="(?:[\w/]+)(?:;\s*?charset=([^\s"]+))"?\s+http-equiv="Content-Type"@i',
|
||||
'@<meta [^>]*charset\s*=\s*["\']?\s*([^"\' ]+)@i',
|
||||
);
|
||||
foreach ($metatags as $metatag) {
|
||||
if (preg_match($metatag, $str, $matches)) {
|
||||
if (isset($matches[1]) && in_array($matches[1], $known_encodings)) {
|
||||
$document_encoding = $matches[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($document_encoding) && in_array(strtoupper($document_encoding), array('UTF-8','UTF8')) === false) {
|
||||
$str = preg_replace('/charset=([^\s"]+)/i', 'charset=UTF-8', $str);
|
||||
} elseif (isset($document_encoding) === false && strpos($str, '<head>') !== false) {
|
||||
$str = str_replace('<head>', '<head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">', $str);
|
||||
} elseif (isset($document_encoding) === false) {
|
||||
$str = '<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">' . $str;
|
||||
}
|
||||
//FIXME: since we're not using this just yet
|
||||
$encoding = 'UTF-8';
|
||||
|
||||
// remove BOM mark from UTF-8, it's treated as document text by DOMDocument
|
||||
// FIXME: roll this into the encoding detection using UTF-8/16/32 BOM (http://us2.php.net/manual/en/function.mb-detect-encoding.php#91051)?
|
||||
@ -473,14 +457,6 @@ class Dompdf
|
||||
$str = substr($str, 3);
|
||||
}
|
||||
|
||||
// if the document contains non utf-8 with a utf-8 meta tag chars and was
|
||||
// detected as utf-8 by mbstring, problems could happen.
|
||||
// http://devzone.zend.com/article/8855
|
||||
if ($encoding !== 'UTF-8') {
|
||||
$re = '/<meta ([^>]*)((?:charset=[^"\' ]+)([^>]*)|(?:charset=["\'][^"\' ]+["\']))([^>]*)>/i';
|
||||
$str = preg_replace($re, '<meta $1$3>', $str);
|
||||
}
|
||||
|
||||
// Store parsing warnings as messages
|
||||
set_error_handler(array("\\Dompdf\\Helpers", "record_warnings"));
|
||||
|
||||
@ -489,7 +465,7 @@ class Dompdf
|
||||
// https://developer.mozilla.org/en/mozilla's_quirks_mode
|
||||
$quirksmode = false;
|
||||
|
||||
if ($this->options->isHtml5ParserEnabled()) {
|
||||
if ($this->options->isHtml5ParserEnabled() && class_exists("HTML5_Tokenizer")) {
|
||||
$tokenizer = new HTML5_Tokenizer($str);
|
||||
$tokenizer->parse();
|
||||
$doc = $tokenizer->save();
|
||||
@ -500,20 +476,29 @@ class Dompdf
|
||||
$nodes = $doc->getElementsByTagName($tag_name);
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
self::remove_text_nodes($node);
|
||||
self::removeTextNodes($node);
|
||||
}
|
||||
}
|
||||
|
||||
$quirksmode = ($tokenizer->getTree()->getQuirksMode() > HTML5_TreeBuilder::NO_QUIRKS);
|
||||
} else {
|
||||
// loadHTML assumes ISO-8859-1 unless otherwise specified, but there are
|
||||
// bugs in how DOMDocument determines the actual encoding. Converting to
|
||||
// HTML-ENTITIES prior to import appears to resolve the issue.
|
||||
// loadHTML assumes ISO-8859-1 unless otherwise specified on the HTML document header.
|
||||
// http://devzone.zend.com/1538/php-dom-xml-extension-encoding-processing/ (see #4)
|
||||
// http://stackoverflow.com/a/11310258/264628
|
||||
$doc = new DOMDocument();
|
||||
$doc = new DOMDocument("1.0", $encoding);
|
||||
$doc->preserveWhiteSpace = true;
|
||||
$doc->loadHTML(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8'));
|
||||
$doc->loadHTML($str);
|
||||
$doc->encoding = $encoding;
|
||||
|
||||
// Remove #text children nodes in nodes that shouldn't have
|
||||
$tag_names = array("html", "table", "tbody", "thead", "tfoot", "tr");
|
||||
foreach ($tag_names as $tag_name) {
|
||||
$nodes = $doc->getElementsByTagName($tag_name);
|
||||
|
||||
foreach ($nodes as $node) {
|
||||
self::removeTextNodes($node);
|
||||
}
|
||||
}
|
||||
|
||||
// If some text is before the doctype, we are in quirksmode
|
||||
if (preg_match("/^(.+)<!doctype/i", ltrim($str), $matches)) {
|
||||
@ -599,6 +584,7 @@ class Dompdf
|
||||
$xpath = new DOMXPath($this->dom);
|
||||
$stylesheets = $xpath->query("//*[name() = 'link' or name() = 'style']");
|
||||
|
||||
/** @var \DOMElement $tag */
|
||||
foreach ($stylesheets as $tag) {
|
||||
switch (strtolower($tag->nodeName)) {
|
||||
// load <link rel="STYLESHEET" ... /> tags
|
||||
@ -656,7 +642,7 @@ class Dompdf
|
||||
$css = $tag->nodeValue;
|
||||
}
|
||||
|
||||
$this->css->load_css($css);
|
||||
$this->css->load_css($css, Stylesheet::ORIG_AUTHOR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -716,15 +702,18 @@ class Dompdf
|
||||
public function render()
|
||||
{
|
||||
$this->saveLocale();
|
||||
$options = $this->options;
|
||||
|
||||
$logOutputFile = $this->options->getLogOutputFile();
|
||||
$logOutputFile = $options->getLogOutputFile();
|
||||
if ($logOutputFile) {
|
||||
if (!file_exists($logOutputFile) && is_writable(dirname($logOutputFile))) {
|
||||
touch($logOutputFile);
|
||||
}
|
||||
|
||||
$this->startTime = microtime(true);
|
||||
ob_start();
|
||||
if (is_writable($logOutputFile)) {
|
||||
ob_start();
|
||||
}
|
||||
}
|
||||
|
||||
$this->processHtml();
|
||||
@ -733,7 +722,6 @@ class Dompdf
|
||||
|
||||
// @page style rules : size, margins
|
||||
$pageStyles = $this->css->get_page_styles();
|
||||
|
||||
$basePageStyle = $pageStyles["base"];
|
||||
unset($pageStyles["base"]);
|
||||
|
||||
@ -741,29 +729,43 @@ class Dompdf
|
||||
$pageStyle->inherit($basePageStyle);
|
||||
}
|
||||
|
||||
$defaultOptionPaperSize = $this->getPaperSize($options->getDefaultPaperSize());
|
||||
// If there is a CSS defined paper size compare to the paper size used to create the canvas to determine a
|
||||
// recreation need
|
||||
if (is_array($basePageStyle->size)) {
|
||||
$this->setPaper(array(0, 0, $basePageStyle->size[0], $basePageStyle->size[1]));
|
||||
$basePageStyleSize = $basePageStyle->size;
|
||||
$this->setPaper(array(0, 0, $basePageStyleSize[0], $basePageStyleSize[1]));
|
||||
}
|
||||
|
||||
//TODO: We really shouldn't be doing this; properties were already set in the constructor. We should add Canvas methods to set the page size and orientation after instantiaion (see #1059).
|
||||
$this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
|
||||
$this->setFontMetrics(new FontMetrics($this->pdf, $this->getOptions()));
|
||||
|
||||
if ($this->options->isFontSubsettingEnabled() && $this->pdf instanceof CPDF) {
|
||||
$paperSize = $this->getPaperSize();
|
||||
if (
|
||||
$defaultOptionPaperSize[2] !== $paperSize[2] ||
|
||||
$defaultOptionPaperSize[3] !== $paperSize[3] ||
|
||||
$options->getDefaultPaperOrientation() !== $this->paperOrientation
|
||||
) {
|
||||
$this->setCanvas(CanvasFactory::get_instance($this, $this->paperSize, $this->paperOrientation));
|
||||
$this->fontMetrics->setCanvas($this->getCanvas());
|
||||
}
|
||||
|
||||
$canvas = $this->getCanvas();
|
||||
|
||||
if ($options->isFontSubsettingEnabled() && $canvas instanceof CPDF) {
|
||||
foreach ($this->tree->get_frames() as $frame) {
|
||||
$style = $frame->get_style();
|
||||
$node = $frame->get_node();
|
||||
|
||||
// Handle text nodes
|
||||
if ($node->nodeName === "#text") {
|
||||
$this->getCanvas()->register_string_subset($style->font_family, $node->nodeValue);
|
||||
$chars = mb_strtoupper($node->nodeValue) . mb_strtolower($node->nodeValue);
|
||||
$canvas->register_string_subset($style->font_family, $chars);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle generated content (list items)
|
||||
if ($style->display === "list-item") {
|
||||
$chars = ListBullet::get_counter_chars($style->list_style_type);
|
||||
$this->getCanvas()->register_string_subset($style->font_family, $chars);
|
||||
$canvas->register_string_subset($style->font_family, $chars);
|
||||
$canvas->register_string_subset($style->font_family, '.');
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -772,17 +774,22 @@ class Dompdf
|
||||
// not the actual generated content, and forces all possible counter
|
||||
// values. See notes in issue #750.
|
||||
if ($frame->get_node()->nodeName == "dompdf_generated") {
|
||||
// all possible counter values
|
||||
// all possible counter values, just in case
|
||||
$chars = ListBullet::get_counter_chars('decimal');
|
||||
$this->getCanvas()->register_string_subset($style->font_family, $chars);
|
||||
$canvas->register_string_subset($style->font_family, $chars);
|
||||
$chars = ListBullet::get_counter_chars('upper-alpha');
|
||||
$this->getCanvas()->register_string_subset($style->font_family, $chars);
|
||||
$canvas->register_string_subset($style->font_family, $chars);
|
||||
$chars = ListBullet::get_counter_chars('lower-alpha');
|
||||
$this->getCanvas()->register_string_subset($style->font_family, $chars);
|
||||
$canvas->register_string_subset($style->font_family, $chars);
|
||||
$chars = ListBullet::get_counter_chars('lower-greek');
|
||||
$this->getCanvas()->register_string_subset($style->font_family, $chars);
|
||||
// the text of the stylesheet declaration
|
||||
$this->getCanvas()->register_string_subset($style->font_family, $style->content);
|
||||
$canvas->register_string_subset($style->font_family, $chars);
|
||||
|
||||
// the hex-decoded text of the content property, duplicated from AbstrctFrameReflower::_parse_string
|
||||
$decoded_string = preg_replace_callback("/\\\\([0-9a-fA-F]{0,6})/",
|
||||
function ($matches) { return \Dompdf\Helpers::unichr(hexdec($matches[1])); },
|
||||
$style->content);
|
||||
$chars = mb_strtoupper($style->content) . mb_strtolower($style->content) . mb_strtoupper($decoded_string) . mb_strtolower($decoded_string);
|
||||
$canvas->register_string_subset($style->font_family, $chars);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -804,7 +811,7 @@ class Dompdf
|
||||
// Add meta information
|
||||
$title = $this->dom->getElementsByTagName("title");
|
||||
if ($title->length) {
|
||||
$this->getCanvas()->add_info("Title", trim($title->item(0)->nodeValue));
|
||||
$canvas->add_info("Title", trim($title->item(0)->nodeValue));
|
||||
}
|
||||
|
||||
$metas = $this->dom->getElementsByTagName("meta");
|
||||
@ -813,21 +820,22 @@ class Dompdf
|
||||
"keywords" => "Keywords",
|
||||
"description" => "Subject",
|
||||
);
|
||||
/** @var \DOMElement $meta */
|
||||
foreach ($metas as $meta) {
|
||||
$name = mb_strtolower($meta->getAttribute("name"));
|
||||
$value = trim($meta->getAttribute("content"));
|
||||
|
||||
if (isset($labels[$name])) {
|
||||
$this->pdf->add_info($labels[$name], $value);
|
||||
$canvas->add_info($labels[$name], $value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($name === "dompdf.view" && $this->parseDefaultView($value)) {
|
||||
$this->getCanvas()->set_default_view($this->defaultView, $this->defaultViewOptions);
|
||||
$canvas->set_default_view($this->defaultView, $this->defaultViewOptions);
|
||||
}
|
||||
}
|
||||
|
||||
$root->set_containing_block(0, 0, $this->getCanvas()->get_width(), $this->getCanvas()->get_height());
|
||||
$root->set_containing_block(0, 0,$canvas->get_width(), $canvas->get_height());
|
||||
$root->set_renderer(new Renderer($this));
|
||||
|
||||
// This is where the magic happens:
|
||||
@ -842,11 +850,19 @@ class Dompdf
|
||||
foreach ($_dompdf_warnings as $msg) {
|
||||
echo $msg . "\n";
|
||||
}
|
||||
echo $this->getCanvas()->get_cpdf()->messages;
|
||||
|
||||
if ($canvas instanceof CPDF) {
|
||||
echo $canvas->get_cpdf()->messages;
|
||||
}
|
||||
echo '</pre>';
|
||||
flush();
|
||||
}
|
||||
|
||||
if ($logOutputFile && is_writable($logOutputFile)) {
|
||||
$this->write_log();
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
$this->restoreLocale();
|
||||
}
|
||||
|
||||
@ -855,8 +871,9 @@ class Dompdf
|
||||
*/
|
||||
public function add_info($label, $value)
|
||||
{
|
||||
if (!is_null($this->pdf)) {
|
||||
$this->pdf->add_info($label, $value);
|
||||
$canvas = $this->getCanvas();
|
||||
if (!is_null($canvas)) {
|
||||
$canvas->add_info($label, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -867,7 +884,7 @@ class Dompdf
|
||||
*/
|
||||
private function write_log()
|
||||
{
|
||||
$log_output_file = $this->get_option("log_output_file");
|
||||
$log_output_file = $this->getOptions()->getLogOutputFile();
|
||||
if (!$log_output_file || !is_writable($log_output_file)) {
|
||||
return;
|
||||
}
|
||||
@ -884,23 +901,18 @@ class Dompdf
|
||||
($this->quirksmode ? "<span style='color: #d00'> ON</span>" : "<span style='color: #0d0'>OFF</span>") .
|
||||
"</span><br />", $frames, $memory, $time);
|
||||
|
||||
$out .= ob_get_clean();
|
||||
$out .= ob_get_contents();
|
||||
ob_clean();
|
||||
|
||||
$log_output_file = $this->get_option("log_output_file");
|
||||
file_put_contents($log_output_file, $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams the PDF to the client
|
||||
* Streams the PDF to the client.
|
||||
*
|
||||
* The file will open a download dialog by default. The options
|
||||
* parameter controls the output. Accepted options (array keys) are:
|
||||
*
|
||||
* 'Accept-Ranges' => 1 or 0 (=default): Send an 'Accept-Ranges:'
|
||||
* HTTP header, see https://tools.ietf.org/html/rfc2616#section-14.5
|
||||
* This header seems to have caused some problems, despite the fact
|
||||
* that it is supposed to solve them, so I am leaving it off by default.
|
||||
*
|
||||
* 'compress' = > 1 (=default) or 0:
|
||||
* Apply content stream compression
|
||||
*
|
||||
@ -911,45 +923,40 @@ class Dompdf
|
||||
* @param string $filename the name of the streamed file
|
||||
* @param array $options header options (see above)
|
||||
*/
|
||||
public function stream($filename = 'document.pdf', $options = null)
|
||||
public function stream($filename = "document.pdf", $options = array())
|
||||
{
|
||||
$this->saveLocale();
|
||||
|
||||
$this->write_log();
|
||||
|
||||
if (!is_null($this->pdf)) {
|
||||
$this->pdf->stream($filename, $options);
|
||||
$canvas = $this->getCanvas();
|
||||
if (!is_null($canvas)) {
|
||||
$canvas->stream($filename, $options);
|
||||
}
|
||||
|
||||
$this->restoreLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PDF as a string
|
||||
*
|
||||
* The file will open a download dialog by default. The options
|
||||
* parameter controls the output. Accepted options are:
|
||||
* Returns the PDF as a string.
|
||||
*
|
||||
* The options parameter controls the output. Accepted options are:
|
||||
*
|
||||
* 'compress' = > 1 or 0 - apply content stream compression, this is
|
||||
* on (1) by default
|
||||
*
|
||||
*
|
||||
* @param array $options options (see above)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function output($options = null)
|
||||
public function output($options = array())
|
||||
{
|
||||
$this->saveLocale();
|
||||
|
||||
$this->write_log();
|
||||
|
||||
if (is_null($this->pdf)) {
|
||||
$canvas = $this->getCanvas();
|
||||
if (is_null($canvas)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$output = $this->pdf->output($options);
|
||||
$output = $canvas->output($options);
|
||||
|
||||
$this->restoreLocale();
|
||||
|
||||
@ -998,7 +1005,7 @@ class Dompdf
|
||||
$this->options->set($key, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @return $this
|
||||
@ -1034,6 +1041,34 @@ class Dompdf
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paper size
|
||||
*
|
||||
* @param null|string|array $paperSize
|
||||
* @return int[] A four-element integer array
|
||||
*/
|
||||
public function getPaperSize($paperSize = null)
|
||||
{
|
||||
$size = $paperSize !== null ? $paperSize : $this->paperSize;
|
||||
if (is_array($size)) {
|
||||
return $size;
|
||||
} else if (isset(Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)])) {
|
||||
return Adapter\CPDF::$PAPER_SIZES[mb_strtolower($size)];
|
||||
} else {
|
||||
return Adapter\CPDF::$PAPER_SIZES["letter"];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paper orientation
|
||||
*
|
||||
* @return string Either "portrait" or "landscape"
|
||||
*/
|
||||
public function getPaperOrientation()
|
||||
{
|
||||
return $this->paperOrientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FrameTree $tree
|
||||
* @return $this
|
||||
@ -1259,7 +1294,6 @@ class Dompdf
|
||||
*/
|
||||
public function setCanvas(Canvas $canvas)
|
||||
{
|
||||
$this->pdf = $canvas;
|
||||
$this->canvas = $canvas;
|
||||
return $this;
|
||||
}
|
||||
@ -1280,9 +1314,6 @@ class Dompdf
|
||||
*/
|
||||
public function getCanvas()
|
||||
{
|
||||
if (null === $this->canvas && null !== $this->pdf) {
|
||||
return $this->pdf;
|
||||
}
|
||||
return $this->canvas;
|
||||
}
|
||||
|
||||
@ -1455,10 +1486,10 @@ class Dompdf
|
||||
{
|
||||
return $this->fontMetrics;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PHP5 overloaded getter
|
||||
* Along with {@link Dompdf::__set()} __get() provides access to all
|
||||
* Along with {@link Dompdf::__set()} __get() provides access to all
|
||||
* properties directly. Typically __get() is not called directly outside
|
||||
* of this class.
|
||||
*
|
||||
|
3
library/vendor/dompdf/src/Exception.php
vendored
3
library/vendor/dompdf/src/Exception.php
vendored
@ -22,9 +22,8 @@ class Exception extends \Exception
|
||||
* @param string $message Error message
|
||||
* @param int $code Error code
|
||||
*/
|
||||
function __construct($message = null, $code = 0)
|
||||
public function __construct($message = null, $code = 0)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
}
|
||||
|
190
library/vendor/dompdf/src/FontMetrics.php
vendored
190
library/vendor/dompdf/src/FontMetrics.php
vendored
@ -84,10 +84,10 @@ class FontMetrics
|
||||
* Saves the stored font family cache
|
||||
*
|
||||
* The name and location of the cache file are determined by {@link
|
||||
* FontMetrics::CACHE_FILE}. This file should be writable by the
|
||||
* FontMetrics::CACHE_FILE}. This file should be writable by the
|
||||
* webserver process.
|
||||
*
|
||||
* @see Font_Metrics::load_font_families()
|
||||
* @see FontMetrics::loadFontFamilies()
|
||||
*/
|
||||
public function saveFontFamilies()
|
||||
{
|
||||
@ -118,84 +118,38 @@ class FontMetrics
|
||||
/**
|
||||
* Loads the stored font family cache
|
||||
*
|
||||
* @see save_font_families()
|
||||
* @see FontMetrics::saveFontFamilies()
|
||||
*/
|
||||
public function loadFontFamilies()
|
||||
{
|
||||
$fontDir = $this->getOptions()->getFontDir();
|
||||
$rootDir = $this->getOptions()->getRootDir();
|
||||
|
||||
|
||||
// FIXME: tempoarary define constants for cache files <= v0.6.2
|
||||
if (!defined("DOMPDF_DIR")) { define("DOMPDF_DIR", $rootDir); }
|
||||
if (!defined("DOMPDF_FONT_DIR")) { define("DOMPDF_FONT_DIR", $fontDir); }
|
||||
|
||||
|
||||
$file = $rootDir . "/lib/fonts/dompdf_font_family_cache.dist.php";
|
||||
$distFonts = require $file;
|
||||
|
||||
// FIXME: temporary step for font cache created before the font cache fix
|
||||
if (is_readable($fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache")) {
|
||||
$oldFonts = require $fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache";
|
||||
// If the font family cache is still in the old format
|
||||
if ($oldFonts === 1) {
|
||||
$cacheData = file_get_contents($fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache");
|
||||
file_put_contents($fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache", "<" . "?php return $cacheData ?" . ">");
|
||||
$oldFonts = require $fontDir . DIRECTORY_SEPARATOR . "dompdf_font_family_cache";
|
||||
}
|
||||
$distFonts += $oldFonts;
|
||||
}
|
||||
|
||||
|
||||
if (!is_readable($this->getCacheFile())) {
|
||||
$this->fontLookup = $distFonts;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$cacheData = require $this->getCacheFile();
|
||||
|
||||
// If the font family cache is still in the old format
|
||||
if ($cacheData === 1) {
|
||||
$cacheData = file_get_contents($this->getCacheFile());
|
||||
file_put_contents($this->getCacheFile(), "<" . "?php return $cacheData ?" . ">");
|
||||
$this->fontLookup = require $this->getCacheFile();
|
||||
}
|
||||
|
||||
|
||||
$this->fontLookup = array();
|
||||
foreach ($cacheData as $key => $value) {
|
||||
$this->fontLookup[stripslashes($key)] = $value;
|
||||
if (is_array($this->fontLookup)) {
|
||||
foreach ($cacheData as $key => $value) {
|
||||
$this->fontLookup[stripslashes($key)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Merge provided fonts
|
||||
$this->fontLookup += $distFonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return array
|
||||
* @deprecated
|
||||
*/
|
||||
public function install_fonts($files)
|
||||
{
|
||||
return $this->installFonts($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files
|
||||
* @return array
|
||||
*/
|
||||
public function installFonts(array $files)
|
||||
{
|
||||
$names = array();
|
||||
|
||||
foreach ($files as $file) {
|
||||
$font = Font::load($file);
|
||||
$records = $font->getData("name", "records");
|
||||
$type = $this->getType($records[2]);
|
||||
$names[mb_strtolower($records[1])][$type] = $file;
|
||||
$font->close();
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $style
|
||||
* @param string $remote_file
|
||||
@ -216,7 +170,6 @@ class FontMetrics
|
||||
*/
|
||||
public function registerFont($style, $remoteFile, $context = null)
|
||||
{
|
||||
$fontDir = $this->getOptions()->getFontDir();
|
||||
$fontname = mb_strtolower($style["family"]);
|
||||
$families = $this->getFontFamilies();
|
||||
|
||||
@ -225,52 +178,56 @@ class FontMetrics
|
||||
$entry = $families[$fontname];
|
||||
}
|
||||
|
||||
$localFile = $fontDir . DIRECTORY_SEPARATOR . md5($remoteFile);
|
||||
$localTempFile = $this->options->get('tempDir') . "/" . md5($remoteFile);
|
||||
$cacheEntry = $localFile;
|
||||
$localFile .= ".ttf";
|
||||
|
||||
$styleString = $this->getType("{$style['weight']} {$style['style']}");
|
||||
|
||||
if ( !isset($entry[$styleString]) ) {
|
||||
$entry[$styleString] = $cacheEntry;
|
||||
|
||||
// Download the remote file
|
||||
$remoteFileContent = @file_get_contents($remoteFile, null, $context);
|
||||
if (false === $remoteFileContent) {
|
||||
return false;
|
||||
}
|
||||
file_put_contents($localTempFile, $remoteFileContent);
|
||||
|
||||
$font = Font::load($localTempFile);
|
||||
|
||||
if (!$font) {
|
||||
unlink($localTempFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
$font->parse();
|
||||
$font->saveAdobeFontMetrics("$cacheEntry.ufm");
|
||||
$font->close();
|
||||
|
||||
unlink($localTempFile);
|
||||
|
||||
if ( !file_exists("$cacheEntry.ufm") ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the changes
|
||||
file_put_contents($localFile, file_get_contents($remoteFile, null, $context));
|
||||
|
||||
if ( !file_exists($localFile) ) {
|
||||
unlink("$cacheEntry.ufm");
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setFontFamily($fontname, $entry);
|
||||
$this->saveFontFamilies();
|
||||
if (isset($entry[$styleString])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$fontDir = $this->getOptions()->getFontDir();
|
||||
$remoteHash = md5($remoteFile);
|
||||
$localFile = $fontDir . DIRECTORY_SEPARATOR . $remoteHash;
|
||||
$localTempFile = tempnam($this->options->get("tempDir"), "dompdf-font-");
|
||||
|
||||
$cacheEntry = $localFile;
|
||||
$localFile .= ".".strtolower(pathinfo(parse_url($remoteFile, PHP_URL_PATH),PATHINFO_EXTENSION));
|
||||
|
||||
$entry[$styleString] = $cacheEntry;
|
||||
|
||||
// Download the remote file
|
||||
list($remoteFileContent, $http_response_header) = @Helpers::getFileContent($remoteFile, $context);
|
||||
if (false === $remoteFileContent) {
|
||||
return false;
|
||||
}
|
||||
file_put_contents($localTempFile, $remoteFileContent);
|
||||
|
||||
$font = Font::load($localTempFile);
|
||||
|
||||
if (!$font) {
|
||||
unlink($localTempFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
$font->parse();
|
||||
$font->saveAdobeFontMetrics("$cacheEntry.ufm");
|
||||
$font->close();
|
||||
|
||||
unlink($localTempFile);
|
||||
|
||||
if ( !file_exists("$cacheEntry.ufm") ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the changes
|
||||
file_put_contents($localFile, $remoteFileContent);
|
||||
|
||||
if ( !file_exists($localFile) ) {
|
||||
unlink("$cacheEntry.ufm");
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->setFontFamily($fontname, $entry);
|
||||
$this->saveFontFamilies();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -494,30 +451,6 @@ class FontMetrics
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @deprecated
|
||||
*/
|
||||
public function get_system_fonts()
|
||||
{
|
||||
return $this->getSystemFonts();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSystemFonts()
|
||||
{
|
||||
$files = glob("/usr/share/fonts/truetype/*.ttf") +
|
||||
glob("/usr/share/fonts/truetype/*/*.ttf") +
|
||||
glob("/usr/share/fonts/truetype/*/*/*.ttf") +
|
||||
glob("C:\\Windows\\fonts\\*.ttf") +
|
||||
glob("C:\\WinNT\\fonts\\*.ttf") +
|
||||
glob("/mnt/c_drive/WINDOWS/Fonts/");
|
||||
|
||||
return $this->installFonts($files);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @deprecated
|
||||
@ -588,8 +521,9 @@ class FontMetrics
|
||||
*/
|
||||
public function setCanvas(Canvas $canvas)
|
||||
{
|
||||
$this->pdf = $canvas;
|
||||
$this->canvas = $canvas;
|
||||
// Still write deprecated pdf for now. It might be used by a parent class.
|
||||
$this->pdf = $canvas;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
123
library/vendor/dompdf/src/Frame.php
vendored
123
library/vendor/dompdf/src/Frame.php
vendored
@ -325,6 +325,14 @@ class Frame
|
||||
$this->_style = null;
|
||||
unset($this->_style);
|
||||
$this->_style = clone $this->_original_style;
|
||||
|
||||
// If this represents a generated node then child nodes represent generated content.
|
||||
// Remove the children since the content will be generated next time this frame is reflowed.
|
||||
if ($this->_node->nodeName === "dompdf_generated" && $this->_style->content != "normal") {
|
||||
foreach ($this->get_children() as $child) {
|
||||
$this->remove_child($child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,7 +434,7 @@ class Frame
|
||||
/**
|
||||
* Containing block dimensions
|
||||
*
|
||||
* @param $i string The key of the wanted containing block's dimension (x, y, x, h)
|
||||
* @param $i string The key of the wanted containing block's dimension (x, y, w, h)
|
||||
*
|
||||
* @return float[]|float
|
||||
*/
|
||||
@ -467,7 +475,7 @@ class Frame
|
||||
{
|
||||
$style = $this->_style;
|
||||
|
||||
return $style->length_in_pt(array(
|
||||
return (float)$style->length_in_pt(array(
|
||||
$style->height,
|
||||
$style->margin_top,
|
||||
$style->margin_bottom,
|
||||
@ -488,7 +496,7 @@ class Frame
|
||||
{
|
||||
$style = $this->_style;
|
||||
|
||||
return $style->length_in_pt(array(
|
||||
return (float)$style->length_in_pt(array(
|
||||
$style->width,
|
||||
$style->margin_left,
|
||||
$style->margin_right,
|
||||
@ -506,7 +514,7 @@ class Frame
|
||||
{
|
||||
$style = $this->_style;
|
||||
|
||||
return $style->length_in_pt(array(
|
||||
return (float)$style->length_in_pt(array(
|
||||
//$style->height,
|
||||
$style->margin_top,
|
||||
$style->margin_bottom,
|
||||
@ -517,6 +525,38 @@ class Frame
|
||||
), $this->_containing_block["h"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content box (x,y,w,h) of the frame
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_content_box()
|
||||
{
|
||||
$style = $this->_style;
|
||||
$cb = $this->_containing_block;
|
||||
|
||||
$x = $this->_position["x"] +
|
||||
(float)$style->length_in_pt(array($style->margin_left,
|
||||
$style->border_left_width,
|
||||
$style->padding_left),
|
||||
$cb["w"]);
|
||||
|
||||
$y = $this->_position["y"] +
|
||||
(float)$style->length_in_pt(array($style->margin_top,
|
||||
$style->border_top_width,
|
||||
$style->padding_top),
|
||||
$cb["h"]);
|
||||
|
||||
$w = $style->length_in_pt($style->width, $cb["w"]);
|
||||
|
||||
$h = $style->length_in_pt($style->height, $cb["h"]);
|
||||
|
||||
return array(0 => $x, "x" => $x,
|
||||
1 => $y, "y" => $y,
|
||||
2 => $w, "w" => $w,
|
||||
3 => $h, "h" => $h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the padding box (x,y,w,h) of the frame
|
||||
*
|
||||
@ -528,12 +568,12 @@ class Frame
|
||||
$cb = $this->_containing_block;
|
||||
|
||||
$x = $this->_position["x"] +
|
||||
$style->length_in_pt(array($style->margin_left,
|
||||
(float)$style->length_in_pt(array($style->margin_left,
|
||||
$style->border_left_width),
|
||||
$cb["w"]);
|
||||
|
||||
$y = $this->_position["y"] +
|
||||
$style->length_in_pt(array($style->margin_top,
|
||||
(float)$style->length_in_pt(array($style->margin_top,
|
||||
$style->border_top_width),
|
||||
$cb["h"]);
|
||||
|
||||
@ -563,9 +603,9 @@ class Frame
|
||||
$style = $this->_style;
|
||||
$cb = $this->_containing_block;
|
||||
|
||||
$x = $this->_position["x"] + $style->length_in_pt($style->margin_left, $cb["w"]);
|
||||
$x = $this->_position["x"] + (float)$style->length_in_pt($style->margin_left, $cb["w"]);
|
||||
|
||||
$y = $this->_position["y"] + $style->length_in_pt($style->margin_top, $cb["h"]);
|
||||
$y = $this->_position["y"] + (float)$style->length_in_pt($style->margin_top, $cb["h"]);
|
||||
|
||||
$w = $style->length_in_pt(array($style->border_left_width,
|
||||
$style->padding_left,
|
||||
@ -716,6 +756,56 @@ class Frame
|
||||
$this->_containing_line = $line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the margin height is auto sized
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_auto_height()
|
||||
{
|
||||
$style = $this->_style;
|
||||
|
||||
return in_array(
|
||||
"auto",
|
||||
array(
|
||||
$style->height,
|
||||
$style->margin_top,
|
||||
$style->margin_bottom,
|
||||
$style->border_top_width,
|
||||
$style->border_bottom_width,
|
||||
$style->padding_top,
|
||||
$style->padding_bottom,
|
||||
$this->_containing_block["h"]
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the margin width is auto sized
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_auto_width()
|
||||
{
|
||||
$style = $this->_style;
|
||||
|
||||
return in_array(
|
||||
"auto",
|
||||
array(
|
||||
$style->width,
|
||||
$style->margin_left,
|
||||
$style->margin_right,
|
||||
$style->border_left_width,
|
||||
$style->border_right_width,
|
||||
$style->padding_left,
|
||||
$style->padding_right,
|
||||
$this->_containing_block["w"]
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the frame is a text node
|
||||
*
|
||||
@ -770,6 +860,18 @@ class Frame
|
||||
return $this->_is_cache["block"] = in_array($this->get_style()->display, Style::$BLOCK_TYPES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_inline_block()
|
||||
{
|
||||
if (isset($this->_is_cache["inline_block"])) {
|
||||
return $this->_is_cache["inline_block"];
|
||||
}
|
||||
|
||||
return $this->_is_cache["inline_block"] = ($this->get_style()->display === 'inline-block');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@ -860,6 +962,11 @@ class Frame
|
||||
}
|
||||
|
||||
$child->_parent = $this;
|
||||
$decorator = $child->get_decorator();
|
||||
// force an update to the cached parent
|
||||
if ($decorator !== null) {
|
||||
$decorator->get_parent(false);
|
||||
}
|
||||
$child->_next_sibling = null;
|
||||
|
||||
// Handle the first child
|
||||
|
35
library/vendor/dompdf/src/Frame/Factory.php
vendored
35
library/vendor/dompdf/src/Frame/Factory.php
vendored
@ -15,6 +15,7 @@ use Dompdf\FrameDecorator\AbstractFrameDecorator;
|
||||
use DOMXPath;
|
||||
use Dompdf\FrameDecorator\Page as PageFrameDecorator;
|
||||
use Dompdf\FrameReflower\Page as PageFrameReflower;
|
||||
use Dompdf\Positioner\AbstractPositioner;
|
||||
|
||||
/**
|
||||
* Contains frame decorating logic
|
||||
@ -30,6 +31,13 @@ use Dompdf\FrameReflower\Page as PageFrameReflower;
|
||||
class Factory
|
||||
{
|
||||
|
||||
/**
|
||||
* Array of positioners for specific frame types
|
||||
*
|
||||
* @var AbstractPositioner[]
|
||||
*/
|
||||
protected static $_positioners;
|
||||
|
||||
/**
|
||||
* Decorate the root Frame
|
||||
*
|
||||
@ -76,12 +84,15 @@ class Factory
|
||||
|
||||
switch ($display) {
|
||||
|
||||
case "flex": //FIXME: display type not yet supported
|
||||
case "table-caption": //FIXME: display type not yet supported
|
||||
case "block":
|
||||
$positioner = "Block";
|
||||
$decorator = "Block";
|
||||
$reflower = "Block";
|
||||
break;
|
||||
|
||||
case "inline-flex": //FIXME: display type not yet supported
|
||||
case "inline-block":
|
||||
$positioner = "Inline";
|
||||
$decorator = "Block";
|
||||
@ -205,14 +216,13 @@ class Factory
|
||||
$reflower = "Image";
|
||||
}
|
||||
|
||||
$positioner = "Dompdf\\Positioner\\$positioner";
|
||||
$decorator = "Dompdf\\FrameDecorator\\$decorator";
|
||||
$reflower = "Dompdf\\FrameReflower\\$reflower";
|
||||
|
||||
/** @var AbstractFrameDecorator $deco */
|
||||
$deco = new $decorator($frame, $dompdf);
|
||||
|
||||
$deco->set_positioner(new $positioner($deco));
|
||||
$deco->set_positioner(self::getPositionerInstance($positioner));
|
||||
$deco->set_reflower(new $reflower($deco, $dompdf->getFontMetrics()));
|
||||
|
||||
if ($root) {
|
||||
@ -221,7 +231,7 @@ class Factory
|
||||
|
||||
if ($display === "list-item") {
|
||||
// Insert a list-bullet frame
|
||||
$xml = $dompdf->get_dom();
|
||||
$xml = $dompdf->getDom();
|
||||
$bullet_node = $xml->createElement("bullet"); // arbitrary choice
|
||||
$b_f = new Frame($bullet_node);
|
||||
|
||||
@ -241,7 +251,7 @@ class Factory
|
||||
if (!$parent_node->hasAttribute("dompdf-counter")) {
|
||||
$index = ($parent_node->hasAttribute("start") ? $parent_node->getAttribute("start") : 1);
|
||||
} else {
|
||||
$index = $parent_node->getAttribute("dompdf-counter") + 1;
|
||||
$index = (int)$parent_node->getAttribute("dompdf-counter") + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,7 +259,7 @@ class Factory
|
||||
$bullet_node->setAttribute("dompdf-counter", $index);
|
||||
}
|
||||
|
||||
$new_style = $dompdf->get_css()->create_style();
|
||||
$new_style = $dompdf->getCss()->create_style();
|
||||
$new_style->display = "-dompdf-list-bullet";
|
||||
$new_style->inherit($style);
|
||||
$b_f->set_style($new_style);
|
||||
@ -259,4 +269,19 @@ class Factory
|
||||
|
||||
return $deco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Positioners
|
||||
*
|
||||
* @param string $type type of positioner to use
|
||||
* @return AbstractPositioner
|
||||
*/
|
||||
protected static function getPositionerInstance($type)
|
||||
{
|
||||
if (!isset(self::$_positioners[$type])) {
|
||||
$class = '\\Dompdf\\Positioner\\'.$type;
|
||||
self::$_positioners[$type] = new $class();
|
||||
}
|
||||
return self::$_positioners[$type];
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Dompdf\Frame;
|
||||
|
||||
use Dompdf\Frame;
|
||||
use IteratorAggregate;
|
||||
|
||||
/**
|
||||
@ -12,12 +13,12 @@ use IteratorAggregate;
|
||||
class FrameList implements IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var
|
||||
* @var Frame
|
||||
*/
|
||||
protected $_frame;
|
||||
|
||||
/**
|
||||
* @param $frame
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function __construct($frame)
|
||||
{
|
||||
|
57
library/vendor/dompdf/src/Frame/FrameTree.php
vendored
57
library/vendor/dompdf/src/Frame/FrameTree.php
vendored
@ -4,11 +4,11 @@ namespace Dompdf\Frame;
|
||||
|
||||
use DOMDocument;
|
||||
use DOMNode;
|
||||
use DOMElement;
|
||||
use DOMXPath;
|
||||
|
||||
use Dompdf\Exception;
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\FrameDecorator\Page;
|
||||
|
||||
/**
|
||||
* @package dompdf
|
||||
@ -44,7 +44,6 @@ class FrameTree
|
||||
"title",
|
||||
"colgroup",
|
||||
"noembed",
|
||||
"noscript",
|
||||
"param",
|
||||
"#comment"
|
||||
);
|
||||
@ -103,7 +102,7 @@ class FrameTree
|
||||
/**
|
||||
* Returns the root frame of the tree
|
||||
*
|
||||
* @return \Dompdf\FrameDecorator\Page
|
||||
* @return Frame
|
||||
*/
|
||||
public function get_root()
|
||||
{
|
||||
@ -115,7 +114,7 @@ class FrameTree
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return Frame
|
||||
* @return Frame|null
|
||||
*/
|
||||
public function get_frame($id)
|
||||
{
|
||||
@ -160,20 +159,37 @@ class FrameTree
|
||||
|
||||
// Move table caption before the table
|
||||
// FIXME find a better way to deal with it...
|
||||
$captions = $xp->query("//table/caption");
|
||||
$captions = $xp->query('//table/caption');
|
||||
foreach ($captions as $caption) {
|
||||
$table = $caption->parentNode;
|
||||
$table->parentNode->insertBefore($caption, $table);
|
||||
}
|
||||
|
||||
$rows = $xp->query("//table/tr");
|
||||
foreach ($rows as $row) {
|
||||
$tbody = $this->_dom->createElement("tbody");
|
||||
$tbody = $row->parentNode->insertBefore($tbody, $row);
|
||||
$tbody->appendChild($row);
|
||||
$firstRows = $xp->query('//table/tr[1]');
|
||||
/** @var DOMElement $tableChild */
|
||||
foreach ($firstRows as $tableChild) {
|
||||
$tbody = $this->_dom->createElement('tbody');
|
||||
$tableNode = $tableChild->parentNode;
|
||||
do {
|
||||
if ($tableChild->nodeName === 'tr') {
|
||||
$tmpNode = $tableChild;
|
||||
$tableChild = $tableChild->nextSibling;
|
||||
$tableNode->removeChild($tmpNode);
|
||||
$tbody->appendChild($tmpNode);
|
||||
} else {
|
||||
if ($tbody->hasChildNodes() === true) {
|
||||
$tableNode->insertBefore($tbody, $tableChild);
|
||||
$tbody = $this->_dom->createElement('tbody');
|
||||
}
|
||||
$tableChild = $tableChild->nextSibling;
|
||||
}
|
||||
} while ($tableChild);
|
||||
if ($tbody->hasChildNodes() === true) {
|
||||
$tableNode->appendChild($tbody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME: temporary hack, preferably we will improve rendering of sequential #text nodes
|
||||
/**
|
||||
* Remove a child from a node
|
||||
@ -181,9 +197,9 @@ class FrameTree
|
||||
* Remove a child from a node. If the removed node results in two
|
||||
* adjacent #text nodes then combine them.
|
||||
*
|
||||
* @param DONNode $node the current DOMNode being considered
|
||||
* @param DOMNode $node the current DOMNode being considered
|
||||
* @param array $children an array of nodes that are the children of $node
|
||||
* @param $index index from the $children array of the node to remove
|
||||
* @param int $index index from the $children array of the node to remove
|
||||
*/
|
||||
protected function _remove_node(DOMNode $node, array &$children, $index)
|
||||
{
|
||||
@ -192,8 +208,7 @@ class FrameTree
|
||||
$nextChild = $child->nextSibling;
|
||||
$node->removeChild($child);
|
||||
if (isset($previousChild, $nextChild)) {
|
||||
if ($previousChild->nodeName === "#text" && $nextChild->nodeName === "#text")
|
||||
{
|
||||
if ($previousChild->nodeName === "#text" && $nextChild->nodeName === "#text") {
|
||||
$previousChild->nodeValue .= $nextChild->nodeValue;
|
||||
$this->_remove_node($node, $children, $index+1);
|
||||
}
|
||||
@ -222,7 +237,7 @@ class FrameTree
|
||||
if (!$node->hasChildNodes()) {
|
||||
return $frame;
|
||||
}
|
||||
|
||||
|
||||
// Store the children in an array so that the tree can be modified
|
||||
$children = array();
|
||||
$length = $node->childNodes->length;
|
||||
@ -234,7 +249,7 @@ class FrameTree
|
||||
while ($index < count($children)) {
|
||||
$child = $children[$index];
|
||||
$nodeName = strtolower($child->nodeName);
|
||||
|
||||
|
||||
// Skip non-displaying nodes
|
||||
if (in_array($nodeName, self::$HIDDEN_TAGS)) {
|
||||
if ($nodeName !== "head" && $nodeName !== "style") {
|
||||
@ -254,7 +269,7 @@ class FrameTree
|
||||
$this->_remove_node($node, $children, $index);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (is_object($child)) {
|
||||
$frame->append_child($this->_build_tree_r($child), false);
|
||||
}
|
||||
@ -265,13 +280,13 @@ class FrameTree
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DOMNode $node
|
||||
* @param DOMNode $new_node
|
||||
* @param DOMElement $node
|
||||
* @param DOMElement $new_node
|
||||
* @param string $pos
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function insert_node(DOMNode $node, DOMNode $new_node, $pos)
|
||||
public function insert_node(DOMElement $node, DOMElement $new_node, $pos)
|
||||
{
|
||||
if ($pos === "after" || !$node->firstChild) {
|
||||
$node->appendChild($new_node);
|
||||
|
@ -82,6 +82,13 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
*/
|
||||
private $_positionned_parent;
|
||||
|
||||
/**
|
||||
* Cache for the get_parent wehile loop results
|
||||
*
|
||||
* @var Frame
|
||||
*/
|
||||
private $_cached_parent;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
@ -146,12 +153,12 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
function deep_copy()
|
||||
{
|
||||
$node = $this->_frame->get_node();
|
||||
|
||||
|
||||
if ($node instanceof DOMElement && $node->hasAttribute("id")) {
|
||||
$node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
|
||||
$node->removeAttribute("id");
|
||||
}
|
||||
|
||||
|
||||
$frame = new Frame($node->cloneNode());
|
||||
$frame->set_style(clone $this->_frame->get_original_style());
|
||||
|
||||
@ -173,6 +180,8 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
|
||||
$this->_counters = array();
|
||||
|
||||
$this->_cached_parent = null; //clear get_parent() cache
|
||||
|
||||
// Reset all children
|
||||
foreach ($this->get_children() as $child) {
|
||||
$child->reset();
|
||||
@ -180,6 +189,10 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
}
|
||||
|
||||
// Getters -----------
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function get_id()
|
||||
{
|
||||
return $this->_frame->get_id();
|
||||
@ -261,6 +274,14 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
return $this->_frame->get_margin_width();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function get_content_box()
|
||||
{
|
||||
return $this->_frame->get_content_box();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
@ -313,6 +334,22 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
$this->_frame->set_position($x, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function is_auto_height()
|
||||
{
|
||||
return $this->_frame->is_auto_height();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function is_auto_width()
|
||||
{
|
||||
return $this->_frame->is_auto_width();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -372,15 +409,17 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
*/
|
||||
function insert_child_after(Frame $new_child, Frame $ref, $update_node = true)
|
||||
{
|
||||
while ($new_child instanceof AbstractFrameDecorator) {
|
||||
$new_child = $new_child->_frame;
|
||||
$insert_frame = $new_child;
|
||||
while ($insert_frame instanceof AbstractFrameDecorator) {
|
||||
$insert_frame = $insert_frame->_frame;
|
||||
}
|
||||
|
||||
while ($ref instanceof AbstractFrameDecorator) {
|
||||
$ref = $ref->_frame;
|
||||
$reference_frame = $ref;
|
||||
while ($reference_frame instanceof AbstractFrameDecorator) {
|
||||
$reference_frame = $reference_frame->_frame;
|
||||
}
|
||||
|
||||
$this->_frame->insert_child_after($new_child, $ref, $update_node);
|
||||
$this->_frame->insert_child_after($insert_frame, $reference_frame, $update_node);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -401,22 +440,21 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
/**
|
||||
* @return AbstractFrameDecorator
|
||||
*/
|
||||
function get_parent()
|
||||
function get_parent($use_cache = true)
|
||||
{
|
||||
if ($use_cache && $this->_cached_parent) {
|
||||
return $this->_cached_parent;
|
||||
}
|
||||
$p = $this->_frame->get_parent();
|
||||
if ($p && $deco = $p->get_decorator()) {
|
||||
while ($tmp = $deco->get_decorator()) {
|
||||
$deco = $tmp;
|
||||
}
|
||||
|
||||
return $deco;
|
||||
return $this->_cached_parent = $deco;
|
||||
} else {
|
||||
if ($p) {
|
||||
return $p;
|
||||
}
|
||||
return $this->_cached_parent = $p;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -612,8 +650,10 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
{
|
||||
// decrement any counters that were incremented on the current node, unless that node is the body
|
||||
$style = $this->_frame->get_style();
|
||||
if ($this->_frame->get_node(
|
||||
)->nodeName !== "body" && $style->counter_increment && ($decrement = $style->counter_increment) !== "none"
|
||||
if (
|
||||
$this->_frame->get_node()->nodeName !== "body" &&
|
||||
$style->counter_increment &&
|
||||
($decrement = $style->counter_increment) !== "none"
|
||||
) {
|
||||
$this->decrement_counters($decrement);
|
||||
}
|
||||
@ -624,8 +664,9 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
// it's been rendered, thus the position check)
|
||||
if (!$this->is_text_node() && $this->get_node()->hasAttribute("dompdf_before_frame_id")) {
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
if ($this->get_node()->getAttribute("dompdf_before_frame_id") == $child->get_id(
|
||||
) && $child->get_position('x') !== null
|
||||
if (
|
||||
$this->get_node()->getAttribute("dompdf_before_frame_id") == $child->get_id() &&
|
||||
$child->get_position('x') !== null
|
||||
) {
|
||||
$style = $child->get_style();
|
||||
if ($style->counter_increment && ($decrement = $style->counter_increment) !== "none") {
|
||||
@ -644,7 +685,7 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
}
|
||||
|
||||
$node = $this->_frame->get_node();
|
||||
|
||||
|
||||
if ($node instanceof DOMElement && $node->hasAttribute("id")) {
|
||||
$node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
|
||||
$node->removeAttribute("id");
|
||||
@ -654,6 +695,7 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
$split->reset();
|
||||
$split->get_original_style()->text_indent = 0;
|
||||
$split->_splitted = true;
|
||||
$split->_already_pushed = true;
|
||||
|
||||
// The body's properties must be kept
|
||||
if ($node->nodeName !== "body") {
|
||||
@ -672,7 +714,13 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
$orig_style->page_break_before = "auto";
|
||||
}
|
||||
|
||||
// recalculate the float offsets after paging
|
||||
$this->get_parent()->insert_child_after($split, $this);
|
||||
if ($this instanceof Block) {
|
||||
foreach ($this->get_line_boxes() as $index => $line_box) {
|
||||
$line_box->get_float_offsets();
|
||||
}
|
||||
}
|
||||
|
||||
// Add $frame and all following siblings to the new split node
|
||||
$iter = $child;
|
||||
@ -680,7 +728,15 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
$frame = $iter;
|
||||
$iter = $iter->get_next_sibling();
|
||||
$frame->reset();
|
||||
$frame->_parent = $split;
|
||||
$split->append_child($frame);
|
||||
|
||||
// recalculate the float offsets
|
||||
if ($frame instanceof Block) {
|
||||
foreach ($frame->get_line_boxes() as $index => $line_box) {
|
||||
$line_box->get_float_offsets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->get_parent()->split($split, $force_pagebreak);
|
||||
@ -692,11 +748,18 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $value
|
||||
*/
|
||||
function reset_counter($id = self::DEFAULT_COUNTER, $value = 0)
|
||||
{
|
||||
$this->get_parent()->_counters[$id] = intval($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $counters
|
||||
*/
|
||||
function decrement_counters($counters)
|
||||
{
|
||||
foreach ($counters as $id => $increment) {
|
||||
@ -704,6 +767,9 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $counters
|
||||
*/
|
||||
function increment_counters($counters)
|
||||
{
|
||||
foreach ($counters as $id => $increment) {
|
||||
@ -711,6 +777,10 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param int $increment
|
||||
*/
|
||||
function increment_counter($id = self::DEFAULT_COUNTER, $increment = 1)
|
||||
{
|
||||
$counter_frame = $this->lookup_counter_frame($id);
|
||||
@ -724,6 +794,10 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @return AbstractFrameDecorator|null
|
||||
*/
|
||||
function lookup_counter_frame($id = self::DEFAULT_COUNTER)
|
||||
{
|
||||
$f = $this->get_parent();
|
||||
@ -740,9 +814,17 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
|
||||
$f = $fp;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: What version is the best : this one or the one in ListBullet ?
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $type
|
||||
* @return bool|string
|
||||
*
|
||||
* TODO: What version is the best : this one or the one in ListBullet ?
|
||||
*/
|
||||
function counter_value($id = self::DEFAULT_COUNTER, $type = "decimal")
|
||||
{
|
||||
$type = mb_strtolower($type);
|
||||
@ -783,16 +865,27 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
final function position()
|
||||
{
|
||||
$this->_positioner->position();
|
||||
$this->_positioner->position($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $offset_x
|
||||
* @param $offset_y
|
||||
* @param bool $ignore_self
|
||||
*/
|
||||
final function move($offset_x, $offset_y, $ignore_self = false)
|
||||
{
|
||||
$this->_positioner->move($offset_x, $offset_y, $ignore_self);
|
||||
$this->_positioner->move($this, $offset_x, $offset_y, $ignore_self);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Block|null $block
|
||||
*/
|
||||
final function reflow(Block $block = null)
|
||||
{
|
||||
// Uncomment this to see the frames before they're laid out, instead of
|
||||
@ -801,8 +894,21 @@ abstract class AbstractFrameDecorator extends Frame
|
||||
$this->_reflower->reflow($block);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
final function get_min_max_width()
|
||||
{
|
||||
return $this->_reflower->get_min_max_width();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine current frame width based on contents
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
final function calculate_auto_width()
|
||||
{
|
||||
return $this->_reflower->calculate_auto_width();
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,11 @@ class Block extends AbstractFrameDecorator
|
||||
*/
|
||||
protected $_line_boxes;
|
||||
|
||||
/**
|
||||
* Block constructor.
|
||||
* @param Frame $frame
|
||||
* @param Dompdf $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, Dompdf $dompdf)
|
||||
{
|
||||
parent::__construct($frame, $dompdf);
|
||||
@ -41,6 +46,9 @@ class Block extends AbstractFrameDecorator
|
||||
$this->_cl = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function reset()
|
||||
{
|
||||
parent::reset();
|
||||
@ -73,6 +81,17 @@ class Block extends AbstractFrameDecorator
|
||||
return $this->_line_boxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $line_number
|
||||
* @return integer
|
||||
*/
|
||||
function set_current_line_number($line_number)
|
||||
{
|
||||
$line_boxes_count = count($this->_line_boxes);
|
||||
$cl = max(min($line_number, $line_boxes_count), 0);
|
||||
return ($this->_cl = $cl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $i
|
||||
*/
|
||||
@ -114,7 +133,6 @@ class Block extends AbstractFrameDecorator
|
||||
|
||||
// Handle inline frames (which are effectively wrappers)
|
||||
if ($frame instanceof Inline) {
|
||||
|
||||
// Handle line breaks
|
||||
if ($frame->get_node()->nodeName === "br") {
|
||||
$this->maximize_line_height($style->length_in_pt($style->line_height), $frame);
|
||||
@ -130,14 +148,15 @@ class Block extends AbstractFrameDecorator
|
||||
$frame->is_text_node() &&
|
||||
!$frame->is_pre()
|
||||
) {
|
||||
|
||||
$frame->set_text(ltrim($frame->get_text()));
|
||||
$frame->recalculate_width();
|
||||
}
|
||||
|
||||
$w = $frame->get_margin_width();
|
||||
|
||||
if ($w == 0) {
|
||||
// FIXME: Why? Doesn't quite seem to be the correct thing to do,
|
||||
// but does appear to be necessary. Hack to handle wrapped white space?
|
||||
if ($w == 0 && $frame->get_node()->nodeName !== "hr") {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -177,6 +196,9 @@ class Block extends AbstractFrameDecorator
|
||||
$this->maximize_line_height($frame->get_margin_height(), $frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function remove_frames_from_line(Frame $frame)
|
||||
{
|
||||
// Search backwards through the lines for $frame
|
||||
@ -221,11 +243,18 @@ class Block extends AbstractFrameDecorator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param float $w
|
||||
*/
|
||||
function increase_line_width($w)
|
||||
{
|
||||
$this->_line_boxes[$this->_cl]->w += $w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $val
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function maximize_line_height($val, Frame $frame)
|
||||
{
|
||||
if ($val > $this->_line_boxes[$this->_cl]->h) {
|
||||
@ -234,6 +263,9 @@ class Block extends AbstractFrameDecorator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $br
|
||||
*/
|
||||
function add_line($br = false)
|
||||
{
|
||||
|
||||
|
@ -10,7 +10,6 @@ namespace Dompdf\FrameDecorator;
|
||||
|
||||
use Dompdf\Dompdf;
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\FontMetrics;
|
||||
use Dompdf\Image\Cache;
|
||||
|
||||
/**
|
||||
@ -47,14 +46,16 @@ class Image extends AbstractFrameDecorator
|
||||
parent::__construct($frame, $dompdf);
|
||||
$url = $frame->get_node()->getAttribute("src");
|
||||
|
||||
$debug_png = $dompdf->get_option("debug_png");
|
||||
if ($debug_png) print '[__construct ' . $url . ']';
|
||||
$debug_png = $dompdf->getOptions()->getDebugPng();
|
||||
if ($debug_png) {
|
||||
print '[__construct ' . $url . ']';
|
||||
}
|
||||
|
||||
list($this->_image_url, /*$type*/, $this->_image_msg) = Cache::resolve_url(
|
||||
$url,
|
||||
$dompdf->get_protocol(),
|
||||
$dompdf->get_host(),
|
||||
$dompdf->get_base_path(),
|
||||
$dompdf->getProtocol(),
|
||||
$dompdf->getBaseHost(),
|
||||
$dompdf->getBasePath(),
|
||||
$dompdf
|
||||
);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
namespace Dompdf\FrameDecorator;
|
||||
|
||||
use DOMElement;
|
||||
use Dompdf\Dompdf;
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\Exception;
|
||||
@ -21,11 +22,21 @@ use Dompdf\Exception;
|
||||
class Inline extends AbstractFrameDecorator
|
||||
{
|
||||
|
||||
/**
|
||||
* Inline constructor.
|
||||
* @param Frame $frame
|
||||
* @param Dompdf $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, Dompdf $dompdf)
|
||||
{
|
||||
parent::__construct($frame, $dompdf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame|null $frame
|
||||
* @param bool $force_pagebreak
|
||||
* @throws Exception
|
||||
*/
|
||||
function split(Frame $frame = null, $force_pagebreak = false)
|
||||
{
|
||||
if (is_null($frame)) {
|
||||
@ -38,13 +49,17 @@ class Inline extends AbstractFrameDecorator
|
||||
}
|
||||
|
||||
$node = $this->_frame->get_node();
|
||||
|
||||
|
||||
if ($node instanceof DOMElement && $node->hasAttribute("id")) {
|
||||
$node->setAttribute("data-dompdf-original-id", $node->getAttribute("id"));
|
||||
$node->removeAttribute("id");
|
||||
}
|
||||
|
||||
$split = $this->copy($node->cloneNode());
|
||||
// if this is a generated node don't propagate the content style
|
||||
if ($split->get_node()->nodeName == "dompdf_generated") {
|
||||
$split->get_style()->content = "normal";
|
||||
}
|
||||
$this->get_parent()->insert_child_after($split, $this);
|
||||
|
||||
// Unset the current node's right style properties
|
||||
@ -84,7 +99,6 @@ class Inline extends AbstractFrameDecorator
|
||||
in_array($frame_style->page_break_before, $page_breaks) ||
|
||||
in_array($frame_style->page_break_after, $page_breaks)
|
||||
) {
|
||||
|
||||
$this->get_parent()->split($split, true);
|
||||
}
|
||||
}
|
||||
|
@ -27,29 +27,35 @@ class ListBullet extends AbstractFrameDecorator
|
||||
|
||||
static $BULLET_TYPES = array("disc", "circle", "square");
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* ListBullet constructor.
|
||||
* @param Frame $frame
|
||||
* @param Dompdf $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, Dompdf $dompdf)
|
||||
{
|
||||
parent::__construct($frame, $dompdf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|int
|
||||
*/
|
||||
function get_margin_width()
|
||||
{
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
// Small hack to prevent extra indenting of list text on list_style_position === "inside"
|
||||
// and on suppressed bullet
|
||||
if ($style->list_style_position === "outside" ||
|
||||
$style->list_style_type === "none"
|
||||
) {
|
||||
if ($style->list_style_type === "none") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
|
||||
}
|
||||
|
||||
//hits only on "inset" lists items, to increase height of box
|
||||
/**
|
||||
* hits only on "inset" lists items, to increase height of box
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
function get_margin_height()
|
||||
{
|
||||
$style = $this->_frame->get_style();
|
||||
@ -61,11 +67,17 @@ class ListBullet extends AbstractFrameDecorator
|
||||
return $style->get_font_size() * self::BULLET_SIZE + 2 * self::BULLET_PADDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|int
|
||||
*/
|
||||
function get_width()
|
||||
{
|
||||
return $this->get_margin_height();
|
||||
return $this->get_margin_width();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float|int
|
||||
*/
|
||||
function get_height()
|
||||
{
|
||||
return $this->get_margin_height();
|
||||
|
@ -59,7 +59,7 @@ class ListBulletImage extends AbstractFrameDecorator
|
||||
// Resample the bullet image to be consistent with 'auto' sized images
|
||||
// See also Image::get_min_max_width
|
||||
// Tested php ver: value measured in px, suffix "px" not in value: rtrim unnecessary.
|
||||
$dpi = $this->_dompdf->get_option("dpi");
|
||||
$dpi = $this->_dompdf->getOptions()->getDpi();
|
||||
$this->_width = ((float)rtrim($width, "px") * 72) / $dpi;
|
||||
$this->_height = ((float)rtrim($height, "px") * 72) / $dpi;
|
||||
|
||||
@ -118,10 +118,9 @@ class ListBulletImage extends AbstractFrameDecorator
|
||||
|
||||
// Small hack to prevent indenting of list text
|
||||
// Image Might not exist, then position like on list_bullet_frame_decorator fallback to none.
|
||||
if ($this->_frame->get_style()->list_style_position === "outside" ||
|
||||
$this->_width == 0
|
||||
)
|
||||
if ($this->_frame->get_style()->list_style_position === "outside" || $this->_width == 0) {
|
||||
return 0;
|
||||
}
|
||||
//This aligns the "inside" image position with the text.
|
||||
//The text starts to the right of the image.
|
||||
//Between the image and the text there is an added margin of image width.
|
||||
|
@ -17,7 +17,11 @@ use Dompdf\Frame;
|
||||
*/
|
||||
class NullFrameDecorator extends AbstractFrameDecorator
|
||||
{
|
||||
|
||||
/**
|
||||
* NullFrameDecorator constructor.
|
||||
* @param Frame $frame
|
||||
* @param Dompdf $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, Dompdf $dompdf)
|
||||
{
|
||||
parent::__construct($frame, $dompdf);
|
||||
@ -27,5 +31,4 @@ class NullFrameDecorator extends AbstractFrameDecorator
|
||||
$style->margin = 0;
|
||||
$style->padding = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
128
library/vendor/dompdf/src/FrameDecorator/Page.php
vendored
128
library/vendor/dompdf/src/FrameDecorator/Page.php
vendored
@ -191,9 +191,7 @@ class Page extends AbstractFrameDecorator
|
||||
$prev = $prev->get_prev_sibling();
|
||||
}
|
||||
|
||||
|
||||
if (in_array($style->page_break_before, $page_breaks)) {
|
||||
|
||||
// Prevent cascading splits
|
||||
$frame->split(null, true);
|
||||
// We have to grab the style again here because split() resets
|
||||
@ -224,7 +222,6 @@ class Page extends AbstractFrameDecorator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -279,7 +276,6 @@ class Page extends AbstractFrameDecorator
|
||||
*/
|
||||
protected function _page_break_allowed(Frame $frame)
|
||||
{
|
||||
|
||||
$block_types = array("block", "list-item", "table", "-dompdf-image");
|
||||
Helpers::dompdf_debug("page-break", "_page_break_allowed(" . $frame->get_node()->nodeName . ")");
|
||||
$display = $frame->get_style()->display;
|
||||
@ -393,9 +389,7 @@ class Page extends AbstractFrameDecorator
|
||||
}
|
||||
|
||||
// Skip breaks on empty text nodes
|
||||
if ($frame->is_text_node() &&
|
||||
$frame->get_node()->nodeValue == ""
|
||||
) {
|
||||
if ($frame->is_text_node() && $frame->get_node()->nodeValue == "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -403,14 +397,14 @@ class Page extends AbstractFrameDecorator
|
||||
|
||||
return true;
|
||||
|
||||
// Table-rows
|
||||
// Table-rows
|
||||
} else {
|
||||
if ($display === "table-row") {
|
||||
|
||||
// Simply check if the parent table's page_break_inside property is
|
||||
// not 'avoid'
|
||||
$p = Table::find_parent_table($frame);
|
||||
$table = Table::find_parent_table($frame);
|
||||
|
||||
$p = $table;
|
||||
while ($p) {
|
||||
if ($p->get_style()->page_break_inside === "avoid") {
|
||||
Helpers::dompdf_debug("page-break", "parent->inside: avoid");
|
||||
@ -421,7 +415,7 @@ class Page extends AbstractFrameDecorator
|
||||
}
|
||||
|
||||
// Avoid breaking after the first row of a table
|
||||
if ($p && $p->get_first_child() === $frame) {
|
||||
if ($table && $table->get_first_child() === $frame || $table->get_first_child()->get_first_child() === $frame) {
|
||||
Helpers::dompdf_debug("page-break", "table: first-row");
|
||||
|
||||
return false;
|
||||
@ -437,7 +431,6 @@ class Page extends AbstractFrameDecorator
|
||||
Helpers::dompdf_debug("page-break", "table-row/row-groups: break allowed");
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
if (in_array($display, Table::$ROW_GROUPS)) {
|
||||
|
||||
@ -445,7 +438,6 @@ class Page extends AbstractFrameDecorator
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
Helpers::dompdf_debug("page-break", "? " . $frame->get_style()->display . "");
|
||||
|
||||
return false;
|
||||
@ -463,56 +455,76 @@ class Page extends AbstractFrameDecorator
|
||||
*
|
||||
* @param Frame $frame the frame to check
|
||||
*
|
||||
* @return Frame the frame following the page break
|
||||
* @return bool
|
||||
*/
|
||||
function check_page_break(Frame $frame)
|
||||
{
|
||||
//FIXME: should not need to do this since we're tracking table status in `$this->_in_table`
|
||||
$p = $frame;
|
||||
$in_table = false;
|
||||
while ($p) {
|
||||
if ($p->is_table()) { $in_table = true; break; }
|
||||
$p = $p->get_parent();
|
||||
}
|
||||
// Do not split if we have already or if the frame was already
|
||||
// pushed to the next page (prevents infinite loops)
|
||||
if ($this->_page_full || $frame->_already_pushed) {
|
||||
if ($in_table) {
|
||||
if ($this->_page_full && $frame->_already_pushed) {
|
||||
return false;
|
||||
}
|
||||
} elseif ($this->_page_full || $frame->_already_pushed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//FIXME: work-around for infinite loop due to tables
|
||||
if ($in_table && $frame->_already_pushed) {
|
||||
return false;
|
||||
}
|
||||
$p = $frame;
|
||||
do {
|
||||
$display = $p->get_style()->display;
|
||||
if ($display == "table-row") {
|
||||
if ($p->_already_pushed) { return false; }
|
||||
}
|
||||
} while ($p = $p->get_parent());
|
||||
|
||||
// If the frame is absolute of fixed it shouldn't break
|
||||
$p = $frame;
|
||||
do {
|
||||
if ($p->is_absolute())
|
||||
if ($p->is_absolute()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME If the row is taller than the page and
|
||||
// if it the first of the page, we don't break
|
||||
$display = $p->get_style()->display;
|
||||
if ($display === "table-row"
|
||||
&& !$p->get_prev_sibling()
|
||||
&& $p->get_margin_height() > $this->get_margin_height()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
} while ($p = $p->get_parent());
|
||||
|
||||
$margin_height = $frame->get_margin_height();
|
||||
|
||||
// FIXME If the row is taller than the page and
|
||||
// if it the first of the page, we don't break
|
||||
if ($frame->get_style()->display === "table-row" &&
|
||||
!$frame->get_prev_sibling() &&
|
||||
$margin_height > $this->get_margin_height()
|
||||
)
|
||||
return false;
|
||||
|
||||
// Determine the frame's maximum y value
|
||||
$max_y = $frame->get_position("y") + $margin_height;
|
||||
$max_y = (float)$frame->get_position("y") + $margin_height;
|
||||
|
||||
// If a split is to occur here, then the bottom margins & paddings of all
|
||||
// parents of $frame must fit on the page as well:
|
||||
$p = $frame->get_parent();
|
||||
while ($p) {
|
||||
$style = $p->get_style();
|
||||
$max_y += $style->length_in_pt(
|
||||
array(
|
||||
$style->margin_bottom,
|
||||
$style->padding_bottom,
|
||||
$style->border_bottom_width
|
||||
)
|
||||
);
|
||||
$max_y += $p->get_style()->computed_bottom_spacing();
|
||||
$p = $p->get_parent();
|
||||
}
|
||||
|
||||
|
||||
// Check if $frame flows off the page
|
||||
if ($max_y <= $this->_bottom_page_margin)
|
||||
if ($max_y <= $this->_bottom_page_margin) {
|
||||
// no: do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
Helpers::dompdf_debug("page-break", "check_page_break");
|
||||
Helpers::dompdf_debug("page-break", "in_table: " . $this->_in_table);
|
||||
@ -545,8 +557,9 @@ class Page extends AbstractFrameDecorator
|
||||
if (!$flg && $next = $iter->get_last_child()) {
|
||||
Helpers::dompdf_debug("page-break", "following last child.");
|
||||
|
||||
if ($next->is_table())
|
||||
if ($next->is_table()) {
|
||||
$this->_in_table++;
|
||||
}
|
||||
|
||||
$iter = $next;
|
||||
continue;
|
||||
@ -555,11 +568,11 @@ class Page extends AbstractFrameDecorator
|
||||
if ($next = $iter->get_prev_sibling()) {
|
||||
Helpers::dompdf_debug("page-break", "following prev sibling.");
|
||||
|
||||
if ($next->is_table() && !$iter->is_table())
|
||||
if ($next->is_table() && !$iter->is_table()) {
|
||||
$this->_in_table++;
|
||||
|
||||
else if (!$next->is_table() && $iter->is_table())
|
||||
} else if (!$next->is_table() && $iter->is_table()) {
|
||||
$this->_in_table--;
|
||||
}
|
||||
|
||||
$iter = $next;
|
||||
$flg = false;
|
||||
@ -569,8 +582,9 @@ class Page extends AbstractFrameDecorator
|
||||
if ($next = $iter->get_parent()) {
|
||||
Helpers::dompdf_debug("page-break", "following parent.");
|
||||
|
||||
if ($iter->is_table())
|
||||
if ($iter->is_table()) {
|
||||
$this->_in_table--;
|
||||
}
|
||||
|
||||
$iter = $next;
|
||||
$flg = true;
|
||||
@ -588,10 +602,15 @@ class Page extends AbstractFrameDecorator
|
||||
// If we are in a table, backtrack to the nearest top-level table row
|
||||
if ($this->_in_table) {
|
||||
$iter = $frame;
|
||||
while ($iter && $iter->get_style()->display !== "table-row" && $iter->get_style()->display !== 'table-row-group')
|
||||
while ($iter && $iter->get_style()->display !== "table-row" && $iter->get_style()->display !== 'table-row-group' && $iter->_already_pushed === false) {
|
||||
$iter = $iter->get_parent();
|
||||
}
|
||||
|
||||
$iter->split(null, true);
|
||||
if ($iter) {
|
||||
$iter->split(null, true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$frame->split(null, true);
|
||||
}
|
||||
@ -604,6 +623,10 @@ class Page extends AbstractFrameDecorator
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param Frame|null $frame
|
||||
* @param bool $force_pagebreak
|
||||
*/
|
||||
function split(Frame $frame = null, $force_pagebreak = false)
|
||||
{
|
||||
// Do nothing
|
||||
@ -629,11 +652,18 @@ class Page extends AbstractFrameDecorator
|
||||
return $this->_floating_frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*/
|
||||
public function remove_floating_frame($key)
|
||||
{
|
||||
unset($this->_floating_frames[$key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $child
|
||||
* @return int|mixed
|
||||
*/
|
||||
public function get_lowest_float_offset(Frame $child)
|
||||
{
|
||||
$style = $child->get_style();
|
||||
@ -642,17 +672,19 @@ class Page extends AbstractFrameDecorator
|
||||
|
||||
$y = 0;
|
||||
|
||||
foreach ($this->_floating_frames as $key => $frame) {
|
||||
if ($side === "both" || $frame->get_style()->float === $side) {
|
||||
$y = max($y, $frame->get_position("y") + $frame->get_margin_height());
|
||||
|
||||
if ($float !== "none") {
|
||||
$this->remove_floating_frame($key);
|
||||
if ($float === "none") {
|
||||
foreach ($this->_floating_frames as $key => $frame) {
|
||||
if ($side === "both" || $frame->get_style()->float === $side) {
|
||||
$y = max($y, $frame->get_position("y") + $frame->get_margin_height());
|
||||
}
|
||||
$this->remove_floating_frame($key);
|
||||
}
|
||||
}
|
||||
|
||||
if ($y > 0) {
|
||||
$y++; // add 1px buffer from float
|
||||
}
|
||||
|
||||
return $y;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,7 +96,6 @@ class Table extends AbstractFrameDecorator
|
||||
$this->_footers = array();
|
||||
}
|
||||
|
||||
|
||||
public function reset()
|
||||
{
|
||||
parent::reset();
|
||||
@ -133,7 +132,6 @@ class Table extends AbstractFrameDecorator
|
||||
if (count($this->_headers) && !in_array($child, $this->_headers, true) &&
|
||||
!in_array($child->get_prev_sibling(), $this->_headers, true)
|
||||
) {
|
||||
|
||||
$first_header = null;
|
||||
|
||||
// Insert copies of the table headers before $child
|
||||
@ -195,10 +193,11 @@ class Table extends AbstractFrameDecorator
|
||||
*/
|
||||
public static function find_parent_table(Frame $frame)
|
||||
{
|
||||
|
||||
while ($frame = $frame->get_parent())
|
||||
if ($frame->is_table())
|
||||
while ($frame = $frame->get_parent()) {
|
||||
if ($frame->is_table()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $frame;
|
||||
}
|
||||
@ -257,6 +256,9 @@ class Table extends AbstractFrameDecorator
|
||||
* Restructure tree so that the table has the correct structure.
|
||||
* Invalid children (i.e. all non-table-rows) are moved below the
|
||||
* table.
|
||||
*
|
||||
* @fixme #1363 Method has some bugs. $table_row has not been initialized and lookup most likely could return an
|
||||
* array of Style instead a Style Object
|
||||
*/
|
||||
public function normalise()
|
||||
{
|
||||
@ -278,6 +280,7 @@ class Table extends AbstractFrameDecorator
|
||||
|
||||
$table_row->normalise();
|
||||
$child->normalise();
|
||||
$this->_cellmap->add_row();
|
||||
$anon_row = false;
|
||||
continue;
|
||||
}
|
||||
@ -294,12 +297,34 @@ class Table extends AbstractFrameDecorator
|
||||
}
|
||||
|
||||
if ($display === "table-cell") {
|
||||
$css = $this->get_style()->get_stylesheet();
|
||||
|
||||
// Create an anonymous table row group
|
||||
$tbody = $this->get_node()->ownerDocument->createElement("tbody");
|
||||
|
||||
$frame = new Frame($tbody);
|
||||
|
||||
$style = $css->create_style();
|
||||
$style->inherit($this->get_style());
|
||||
|
||||
// Lookup styles for tbody tags. If the user wants styles to work
|
||||
// better, they should make the tbody explicit... I'm not going to
|
||||
// try to guess what they intended.
|
||||
if ($tbody_style = $css->lookup("tbody")) {
|
||||
$style->merge($tbody_style);
|
||||
}
|
||||
$style->display = 'table-row-group';
|
||||
|
||||
// Okay, I have absolutely no idea why I need this clone here, but
|
||||
// if it's omitted, php (as of 2004-07-28) segfaults.
|
||||
$frame->set_style($style);
|
||||
$table_row_group = Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
|
||||
|
||||
// Create an anonymous table row
|
||||
$tr = $this->get_node()->ownerDocument->createElement("tr");
|
||||
|
||||
$frame = new Frame($tr);
|
||||
|
||||
$css = $this->get_style()->get_stylesheet();
|
||||
$style = $css->create_style();
|
||||
$style->inherit($this->get_style());
|
||||
|
||||
@ -309,6 +334,7 @@ class Table extends AbstractFrameDecorator
|
||||
if ($tr_style = $css->lookup("tr")) {
|
||||
$style->merge($tr_style);
|
||||
}
|
||||
$style->display = 'table-row';
|
||||
|
||||
// Okay, I have absolutely no idea why I need this clone here, but
|
||||
// if it's omitted, php (as of 2004-07-28) segfaults.
|
||||
@ -316,7 +342,10 @@ class Table extends AbstractFrameDecorator
|
||||
$table_row = Factory::decorate_frame($frame, $this->_dompdf, $this->_root);
|
||||
|
||||
// Add the cell to the row
|
||||
$table_row->append_child($child);
|
||||
$table_row->append_child($child, true);
|
||||
|
||||
// Add the tr to the tbody
|
||||
$table_row_group->append_child($table_row, true);
|
||||
|
||||
$anon_row = true;
|
||||
continue;
|
||||
@ -343,11 +372,10 @@ class Table extends AbstractFrameDecorator
|
||||
}
|
||||
}
|
||||
|
||||
if ($anon_row && $table_row instanceof DOMNode) {
|
||||
if ($anon_row && $table_row_group instanceof AbstractFrameDecorator) {
|
||||
// Add the row to the table
|
||||
$this->_frame->append_child($table_row);
|
||||
$this->_frame->append_child($table_row_group->_frame);
|
||||
$table_row->normalise();
|
||||
$this->_cellmap->add_row();
|
||||
}
|
||||
|
||||
foreach ($erroneous_frames as $frame) {
|
||||
|
@ -24,6 +24,11 @@ class TableCell extends BlockFrameDecorator
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* TableCell constructor.
|
||||
* @param Frame $frame
|
||||
* @param Dompdf $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, Dompdf $dompdf)
|
||||
{
|
||||
parent::__construct($frame, $dompdf);
|
||||
@ -41,26 +46,39 @@ class TableCell extends BlockFrameDecorator
|
||||
$this->_frame->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
function get_content_height()
|
||||
{
|
||||
return $this->_content_height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $height
|
||||
*/
|
||||
function set_content_height($height)
|
||||
{
|
||||
$this->_content_height = $height;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $height
|
||||
*/
|
||||
function set_cell_height($height)
|
||||
{
|
||||
$style = $this->get_style();
|
||||
$v_space = $style->length_in_pt(array($style->margin_top,
|
||||
$v_space = (float)$style->length_in_pt(
|
||||
array(
|
||||
$style->margin_top,
|
||||
$style->padding_top,
|
||||
$style->border_top_width,
|
||||
$style->border_bottom_width,
|
||||
$style->padding_bottom,
|
||||
$style->margin_bottom),
|
||||
$style->width);
|
||||
$style->margin_bottom
|
||||
),
|
||||
(float)$style->length_in_pt($style->height)
|
||||
);
|
||||
|
||||
$new_height = $height - $v_space;
|
||||
$style->height = $new_height;
|
||||
@ -90,26 +108,35 @@ class TableCell extends BlockFrameDecorator
|
||||
if ($y_offset) {
|
||||
// Move our children
|
||||
foreach ($this->get_line_boxes() as $line) {
|
||||
foreach ($line->get_frames() as $frame)
|
||||
foreach ($line->get_frames() as $frame) {
|
||||
$frame->move(0, $y_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $side
|
||||
* @param $border_spec
|
||||
*/
|
||||
function set_resolved_border($side, $border_spec)
|
||||
{
|
||||
$this->_resolved_borders[$side] = $border_spec;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param $side
|
||||
* @return mixed
|
||||
*/
|
||||
function get_resolved_border($side)
|
||||
{
|
||||
return $this->_resolved_borders[$side];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function get_resolved_borders()
|
||||
{
|
||||
return $this->_resolved_borders;
|
||||
|
@ -18,6 +18,11 @@ use Dompdf\FrameDecorator\Table as TableFrameDecorator;
|
||||
*/
|
||||
class TableRow extends AbstractFrameDecorator
|
||||
{
|
||||
/**
|
||||
* TableRow constructor.
|
||||
* @param Frame $frame
|
||||
* @param Dompdf $dompdf
|
||||
*/
|
||||
function __construct(Frame $frame, Dompdf $dompdf)
|
||||
{
|
||||
parent::__construct($frame, $dompdf);
|
||||
@ -31,7 +36,6 @@ class TableRow extends AbstractFrameDecorator
|
||||
*/
|
||||
function normalise()
|
||||
{
|
||||
|
||||
// Find our table parent
|
||||
$p = TableFrameDecorator::find_parent_table($this);
|
||||
|
||||
@ -39,14 +43,26 @@ class TableRow extends AbstractFrameDecorator
|
||||
foreach ($this->get_children() as $child) {
|
||||
$display = $child->get_style()->display;
|
||||
|
||||
if ($display !== "table-cell")
|
||||
if ($display !== "table-cell") {
|
||||
$erroneous_frames[] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
// dump the extra nodes after the table.
|
||||
foreach ($erroneous_frames as $frame)
|
||||
foreach ($erroneous_frames as $frame) {
|
||||
$p->move_after($frame);
|
||||
}
|
||||
}
|
||||
|
||||
function split(Frame $child = null, $force_pagebreak = false)
|
||||
{
|
||||
$this->_already_pushed = true;
|
||||
|
||||
if (is_null($child)) {
|
||||
parent::split();
|
||||
return;
|
||||
}
|
||||
|
||||
parent::split($child, $force_pagebreak);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ class TableRowGroup extends AbstractFrameDecorator
|
||||
*/
|
||||
function split(Frame $child = null, $force_pagebreak = false)
|
||||
{
|
||||
|
||||
if (is_null($child)) {
|
||||
parent::split();
|
||||
return;
|
||||
@ -66,7 +65,6 @@ class TableRowGroup extends AbstractFrameDecorator
|
||||
|
||||
$cellmap->update_row_group($this, $child->get_prev_sibling());
|
||||
parent::split($child);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -12,8 +12,6 @@ namespace Dompdf\FrameDecorator;
|
||||
use Dompdf\Dompdf;
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\Exception;
|
||||
use DOMText;
|
||||
use Dompdf\FontMetrics;
|
||||
|
||||
/**
|
||||
* Decorates Frame objects for text layout
|
||||
@ -27,6 +25,12 @@ class Text extends AbstractFrameDecorator
|
||||
// protected members
|
||||
protected $_text_spacing;
|
||||
|
||||
/**
|
||||
* Text constructor.
|
||||
* @param Frame $frame
|
||||
* @param Dompdf $dompdf
|
||||
* @throws Exception
|
||||
*/
|
||||
function __construct(Frame $frame, Dompdf $dompdf)
|
||||
{
|
||||
if (!$frame->is_text_node()) {
|
||||
@ -37,22 +41,25 @@ class Text extends AbstractFrameDecorator
|
||||
$this->_text_spacing = null;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function reset()
|
||||
{
|
||||
parent::reset();
|
||||
$this->_text_spacing = null;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Accessor methods
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
function get_text_spacing()
|
||||
{
|
||||
return $this->_text_spacing;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
function get_text()
|
||||
{
|
||||
// FIXME: this should be in a child class (and is incorrect)
|
||||
@ -74,14 +81,18 @@ class Text extends AbstractFrameDecorator
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Vertical margins & padding do not apply to text frames
|
||||
|
||||
// http://www.w3.org/TR/CSS21/visudet.html#inline-non-replaced:
|
||||
//
|
||||
// The vertical padding, border and margin of an inline, non-replaced box
|
||||
// start at the top and bottom of the content area, not the
|
||||
// 'line-height'. But only the 'line-height' is used to calculate the
|
||||
// height of the line box.
|
||||
/**
|
||||
* Vertical margins & padding do not apply to text frames
|
||||
*
|
||||
* http://www.w3.org/TR/CSS21/visudet.html#inline-non-replaced:
|
||||
*
|
||||
* The vertical padding, border and margin of an inline, non-replaced box
|
||||
* start at the top and bottom of the content area, not the
|
||||
* 'line-height'. But only the 'line-height' is used to calculate the
|
||||
* height of the line box.
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
function get_margin_height()
|
||||
{
|
||||
// This function is called in add_frame_to_line() and is used to
|
||||
@ -100,9 +111,11 @@ class Text extends AbstractFrameDecorator
|
||||
*/
|
||||
|
||||
return ($style->line_height / ($size > 0 ? $size : 1)) * $this->_dompdf->getFontMetrics()->getFontHeight($font, $size);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function get_padding_box()
|
||||
{
|
||||
$pb = $this->_frame->get_padding_box();
|
||||
@ -110,41 +123,47 @@ class Text extends AbstractFrameDecorator
|
||||
|
||||
return $pb;
|
||||
}
|
||||
//........................................................................
|
||||
|
||||
// Set method
|
||||
/**
|
||||
* @param $spacing
|
||||
*/
|
||||
function set_text_spacing($spacing)
|
||||
{
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
$this->_text_spacing = $spacing;
|
||||
$char_spacing = $style->length_in_pt($style->letter_spacing);
|
||||
$char_spacing = (float)$style->length_in_pt($style->letter_spacing);
|
||||
|
||||
// Re-adjust our width to account for the change in spacing
|
||||
$style->width = $this->_dompdf->getFontMetrics()->getTextWidth($this->get_text(), $style->font_family, $style->font_size, $spacing, $char_spacing);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Recalculate the text width
|
||||
/**
|
||||
* Recalculate the text width
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
function recalculate_width()
|
||||
{
|
||||
$style = $this->get_style();
|
||||
$text = $this->get_text();
|
||||
$size = $style->font_size;
|
||||
$font = $style->font_family;
|
||||
$word_spacing = $style->length_in_pt($style->word_spacing);
|
||||
$char_spacing = $style->length_in_pt($style->letter_spacing);
|
||||
$word_spacing = (float)$style->length_in_pt($style->word_spacing);
|
||||
$char_spacing = (float)$style->length_in_pt($style->letter_spacing);
|
||||
|
||||
return $style->width = $this->_dompdf->getFontMetrics()->getTextWidth($text, $font, $size, $word_spacing, $char_spacing);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Text manipulation methods
|
||||
|
||||
// split the text in this frame at the offset specified. The remaining
|
||||
// text is added a sibling frame following this one and is returned.
|
||||
/**
|
||||
* split the text in this frame at the offset specified. The remaining
|
||||
* text is added a sibling frame following this one and is returned.
|
||||
*
|
||||
* @param $offset
|
||||
* @return Frame|null
|
||||
*/
|
||||
function split_text($offset)
|
||||
{
|
||||
if ($offset == 0) {
|
||||
@ -165,18 +184,20 @@ class Text extends AbstractFrameDecorator
|
||||
return $deco;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param $offset
|
||||
* @param $count
|
||||
*/
|
||||
function delete_text($offset, $count)
|
||||
{
|
||||
$this->_frame->get_node()->deleteData($offset, $count);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
*/
|
||||
function set_text($text)
|
||||
{
|
||||
$this->_frame->get_node()->data = $text;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ abstract class AbstractFrameReflower
|
||||
*/
|
||||
protected $_min_max_cache;
|
||||
|
||||
/**
|
||||
* AbstractFrameReflower constructor.
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function __construct(Frame $frame)
|
||||
{
|
||||
$this->_frame = $frame;
|
||||
@ -68,7 +72,8 @@ abstract class AbstractFrameReflower
|
||||
$cb = $frame->get_containing_block();
|
||||
$style = $frame->get_style();
|
||||
|
||||
if (!$frame->is_in_flow()) {
|
||||
// Margins of float/absolutely positioned/inline-block elements do not collapse.
|
||||
if (!$frame->is_in_flow() || $frame->is_inline_block()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -88,9 +93,9 @@ abstract class AbstractFrameReflower
|
||||
|
||||
// Collapse vertical margins:
|
||||
$n = $frame->get_next_sibling();
|
||||
if ($n && !$n->is_block()) {
|
||||
if ( $n && !$n->is_block() & !$n->is_table() ) {
|
||||
while ($n = $n->get_next_sibling()) {
|
||||
if ($n->is_block()) {
|
||||
if ($n->is_block() || $n->is_table()) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -103,45 +108,104 @@ abstract class AbstractFrameReflower
|
||||
|
||||
if ($n) {
|
||||
$n_style = $n->get_style();
|
||||
$b = max($b, $n_style->length_in_pt($n_style->margin_top, $cb["h"]));
|
||||
$n_style->margin_top = "0pt";
|
||||
$n_t = (float)$n_style->length_in_pt($n_style->margin_top, $cb["h"]);
|
||||
|
||||
$b = $this->_get_collapsed_margin_length($b, $n_t);
|
||||
$style->margin_bottom = $b . "pt";
|
||||
$n_style->margin_top = "0pt";
|
||||
}
|
||||
|
||||
// Collapse our first child's margin
|
||||
/*$f = $this->_frame->get_first_child();
|
||||
if ( $f && !$f->is_block() ) {
|
||||
while ( $f = $f->get_next_sibling() ) {
|
||||
if ( $f->is_block() ) {
|
||||
break;
|
||||
// Collapse our first child's margin, if there is no border or padding
|
||||
if ($style->get_border_top_width() == 0 && $style->length_in_pt($style->padding_top) == 0) {
|
||||
$f = $this->_frame->get_first_child();
|
||||
if ( $f && !$f->is_block() && !$f->is_table() ) {
|
||||
while ( $f = $f->get_next_sibling() ) {
|
||||
if ( $f->is_block() || $f->is_table() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !$f->get_first_child() ) {
|
||||
$f = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$f->get_first_child() ) {
|
||||
$f = null;
|
||||
break;
|
||||
// Margin are collapsed only between block-level boxes
|
||||
if ($f) {
|
||||
$f_style = $f->get_style();
|
||||
$f_t = (float)$f_style->length_in_pt($f_style->margin_top, $cb["h"]);
|
||||
|
||||
$t = $this->_get_collapsed_margin_length($t, $f_t);
|
||||
$style->margin_top = $t."pt";
|
||||
$f_style->margin_top = "0pt";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Margin are collapsed only between block elements
|
||||
if ( $f ) {
|
||||
$f_style = $f->get_style();
|
||||
$t = max($t, $f_style->length_in_pt($f_style->margin_top, $cb["h"]));
|
||||
$style->margin_top = $t."pt";
|
||||
$f_style->margin_bottom = "0pt";
|
||||
}*/
|
||||
// Collapse our last child's margin, if there is no border or padding
|
||||
if ($style->get_border_bottom_width() == 0 && $style->length_in_pt($style->padding_bottom) == 0) {
|
||||
$l = $this->_frame->get_last_child();
|
||||
if ( $l && !$l->is_block() && !$l->is_table() ) {
|
||||
while ( $l = $l->get_prev_sibling() ) {
|
||||
if ( $l->is_block() || $l->is_table() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !$l->get_last_child() ) {
|
||||
$l = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Margin are collapsed only between block-level boxes
|
||||
if ($l) {
|
||||
$l_style = $l->get_style();
|
||||
$l_b = (float)$l_style->length_in_pt($l_style->margin_bottom, $cb["h"]);
|
||||
|
||||
$b = $this->_get_collapsed_margin_length($b, $l_b);
|
||||
$style->margin_bottom = $b."pt";
|
||||
$l_style->margin_bottom = "0pt";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
/**
|
||||
* Get the combined (collapsed) length of two adjoining margins.
|
||||
*
|
||||
* See http://www.w3.org/TR/CSS2/box.html#collapsing-margins.
|
||||
*
|
||||
* @param number $length1
|
||||
* @param number $length2
|
||||
* @return number
|
||||
*/
|
||||
private function _get_collapsed_margin_length($length1, $length2)
|
||||
{
|
||||
if ($length1 < 0 && $length2 < 0) {
|
||||
return min($length1, $length2); // min(x, y) = - max(abs(x), abs(y)), if x < 0 && y < 0
|
||||
}
|
||||
|
||||
if ($length1 < 0 || $length2 < 0) {
|
||||
return $length1 + $length2; // x + y = x - abs(y), if y < 0
|
||||
}
|
||||
|
||||
return max($length1, $length2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Block|null $block
|
||||
* @return mixed
|
||||
*/
|
||||
abstract function reflow(Block $block = null);
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Required for table layout: Returns an array(0 => min, 1 => max, "min"
|
||||
// => min, "max" => max) of the minimum and maximum widths of this frame.
|
||||
// This provides a basic implementation. Child classes should override
|
||||
// this if necessary.
|
||||
/**
|
||||
* Required for table layout: Returns an array(0 => min, 1 => max, "min"
|
||||
* => min, "max" => max) of the minimum and maximum widths of this frame.
|
||||
* This provides a basic implementation. Child classes should override
|
||||
* this if necessary.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
function get_min_max_width()
|
||||
{
|
||||
if (!is_null($this->_min_max_cache)) {
|
||||
@ -159,7 +223,7 @@ abstract class AbstractFrameReflower
|
||||
$style->margin_right);
|
||||
|
||||
$cb_w = $this->_frame->get_containing_block("w");
|
||||
$delta = $style->length_in_pt($dims, $cb_w);
|
||||
$delta = (float)$style->length_in_pt($dims, $cb_w);
|
||||
|
||||
// Handle degenerate case
|
||||
if (!$this->_frame->get_first_child()) {
|
||||
@ -173,16 +237,12 @@ abstract class AbstractFrameReflower
|
||||
$low = array();
|
||||
$high = array();
|
||||
|
||||
for ($iter = $this->_frame->get_children()->getIterator();
|
||||
$iter->valid();
|
||||
$iter->next()) {
|
||||
|
||||
for ($iter = $this->_frame->get_children()->getIterator(); $iter->valid(); $iter->next()) {
|
||||
$inline_min = 0;
|
||||
$inline_max = 0;
|
||||
|
||||
// Add all adjacent inline widths together to calculate max width
|
||||
while ($iter->valid() && in_array($iter->current()->get_style()->display, Style::$INLINE_TYPES)) {
|
||||
|
||||
$child = $iter->current();
|
||||
|
||||
$minmax = $child->get_min_max_width();
|
||||
@ -195,17 +255,19 @@ abstract class AbstractFrameReflower
|
||||
|
||||
$inline_max += $minmax["max"];
|
||||
$iter->next();
|
||||
|
||||
}
|
||||
|
||||
if ($inline_max > 0) $high[] = $inline_max;
|
||||
if ($inline_min > 0) $low[] = $inline_min;
|
||||
if ($inline_max > 0) {
|
||||
$high[] = $inline_max;
|
||||
}
|
||||
if ($inline_min > 0) {
|
||||
$low[] = $inline_min;
|
||||
}
|
||||
|
||||
if ($iter->valid()) {
|
||||
list($low[], $high[]) = $iter->current()->get_min_max_width();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
$min = count($low) ? max($low) : 0;
|
||||
$max = count($high) ? max($high) : 0;
|
||||
@ -214,9 +276,13 @@ abstract class AbstractFrameReflower
|
||||
// content. If the width is a percentage ignore it for now.
|
||||
$width = $style->width;
|
||||
if ($width !== "auto" && !Helpers::is_percent($width)) {
|
||||
$width = $style->length_in_pt($width, $cb_w);
|
||||
if ($min < $width) $min = $width;
|
||||
if ($max < $width) $max = $width;
|
||||
$width = (float)$style->length_in_pt($width, $cb_w);
|
||||
if ($min < $width) {
|
||||
$min = $width;
|
||||
}
|
||||
if ($max < $width) {
|
||||
$max = $width;
|
||||
}
|
||||
}
|
||||
|
||||
$min += $delta;
|
||||
@ -257,7 +323,6 @@ abstract class AbstractFrameReflower
|
||||
*/
|
||||
protected function _parse_quotes()
|
||||
{
|
||||
|
||||
// Matches quote types
|
||||
$re = '/(\'[^\']*\')|(\"[^\"]*\")/';
|
||||
|
||||
@ -287,7 +352,6 @@ abstract class AbstractFrameReflower
|
||||
*/
|
||||
protected function _parse_content()
|
||||
{
|
||||
|
||||
// Matches generated content
|
||||
$re = "/\n" .
|
||||
"\s(counters?\\([^)]*\\))|\n" .
|
||||
@ -310,7 +374,6 @@ abstract class AbstractFrameReflower
|
||||
$text = "";
|
||||
|
||||
foreach ($matches as $match) {
|
||||
|
||||
if (isset($match[2]) && $match[2] !== "") {
|
||||
$match[1] = $match[2];
|
||||
}
|
||||
@ -324,7 +387,6 @@ abstract class AbstractFrameReflower
|
||||
}
|
||||
|
||||
if (isset($match[1]) && $match[1] !== "") {
|
||||
|
||||
// counters?(...)
|
||||
$match[1] = mb_strtolower(trim($match[1]));
|
||||
|
||||
@ -371,10 +433,8 @@ abstract class AbstractFrameReflower
|
||||
array_unshift($tmp, $p->counter_value($counter_id, $type));
|
||||
}
|
||||
$p = $p->lookup_counter_frame($counter_id);
|
||||
|
||||
}
|
||||
$text .= implode($string, $tmp);
|
||||
|
||||
} else {
|
||||
// countertops?
|
||||
continue;
|
||||
@ -397,7 +457,6 @@ abstract class AbstractFrameReflower
|
||||
} else if ($match[7] === "no-close-quote") {
|
||||
// FIXME:
|
||||
} else if (mb_strpos($match[7], "attr(") === 0) {
|
||||
|
||||
$i = mb_strpos($match[7], ")");
|
||||
if ($i === false) {
|
||||
continue;
|
||||
@ -436,12 +495,12 @@ abstract class AbstractFrameReflower
|
||||
$frame->increment_counters($increment);
|
||||
}
|
||||
|
||||
if ($style->content && !$frame->get_first_child() && $frame->get_node()->nodeName === "dompdf_generated") {
|
||||
if ($style->content && $frame->get_node()->nodeName === "dompdf_generated") {
|
||||
$content = $this->_parse_content();
|
||||
// add generated content to the font subset
|
||||
// FIXME: This is currently too late because the font subset has already been generated.
|
||||
// See notes in issue #750.
|
||||
if ($frame->get_dompdf()->get_option("enable_font_subsetting") && $frame->get_dompdf()->get_canvas() instanceof CPDF) {
|
||||
if ($frame->get_dompdf()->getOptions()->getIsFontSubsettingEnabled() && $frame->get_dompdf()->get_canvas() instanceof CPDF) {
|
||||
$frame->get_dompdf()->get_canvas()->register_string_subset($style->font_family, $content);
|
||||
}
|
||||
|
||||
@ -457,4 +516,14 @@ abstract class AbstractFrameReflower
|
||||
$frame->append_child($new_frame);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine current frame width based on contents
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function calculate_auto_width()
|
||||
{
|
||||
return $this->_frame->get_margin_width();
|
||||
}
|
||||
}
|
||||
|
395
library/vendor/dompdf/src/FrameReflower/Block.php
vendored
395
library/vendor/dompdf/src/FrameReflower/Block.php
vendored
@ -8,11 +8,12 @@
|
||||
*/
|
||||
namespace Dompdf\FrameReflower;
|
||||
|
||||
use Dompdf\FontMetrics;
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\FrameDecorator\Block as BlockFrameDecorator;
|
||||
use Dompdf\FrameDecorator\TableCell as TableCellFrameDecorator;
|
||||
use Dompdf\FrameDecorator\Text as TextFrameDecorator;
|
||||
use Dompdf\Exception;
|
||||
use Dompdf\Css\Style;
|
||||
|
||||
/**
|
||||
* Reflows block frames
|
||||
@ -76,22 +77,23 @@ class Block extends AbstractFrameReflower
|
||||
$absolute = false;
|
||||
}
|
||||
|
||||
$sum = $style->length_in_pt($dims, $w);
|
||||
$sum = (float)$style->length_in_pt($dims, $w);
|
||||
|
||||
// Compare to the containing block
|
||||
$diff = $w - $sum;
|
||||
|
||||
if ($diff > 0) {
|
||||
|
||||
if ($absolute) {
|
||||
|
||||
// resolve auto properties: see
|
||||
// http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
|
||||
|
||||
if ($width === "auto" && $left === "auto" && $right === "auto") {
|
||||
|
||||
if ($lm === "auto") $lm = 0;
|
||||
if ($rm === "auto") $rm = 0;
|
||||
if ($lm === "auto") {
|
||||
$lm = 0;
|
||||
}
|
||||
if ($rm === "auto") {
|
||||
$rm = 0;
|
||||
}
|
||||
|
||||
// Technically, the width should be "shrink-to-fit" i.e. based on the
|
||||
// preferred width of the content... a little too costly here as a
|
||||
@ -100,30 +102,44 @@ class Block extends AbstractFrameReflower
|
||||
$right = 0;
|
||||
$width = $diff;
|
||||
} else if ($width === "auto") {
|
||||
|
||||
if ($lm === "auto") $lm = 0;
|
||||
if ($rm === "auto") $rm = 0;
|
||||
if ($left === "auto") $left = 0;
|
||||
if ($right === "auto") $right = 0;
|
||||
if ($lm === "auto") {
|
||||
$lm = 0;
|
||||
}
|
||||
if ($rm === "auto") {
|
||||
$rm = 0;
|
||||
}
|
||||
if ($left === "auto") {
|
||||
$left = 0;
|
||||
}
|
||||
if ($right === "auto") {
|
||||
$right = 0;
|
||||
}
|
||||
|
||||
$width = $diff;
|
||||
} else if ($left === "auto") {
|
||||
|
||||
if ($lm === "auto") $lm = 0;
|
||||
if ($rm === "auto") $rm = 0;
|
||||
if ($right === "auto") $right = 0;
|
||||
if ($lm === "auto") {
|
||||
$lm = 0;
|
||||
}
|
||||
if ($rm === "auto") {
|
||||
$rm = 0;
|
||||
}
|
||||
if ($right === "auto") {
|
||||
$right = 0;
|
||||
}
|
||||
|
||||
$left = $diff;
|
||||
} else if ($right === "auto") {
|
||||
|
||||
if ($lm === "auto") $lm = 0;
|
||||
if ($rm === "auto") $rm = 0;
|
||||
if ($lm === "auto") {
|
||||
$lm = 0;
|
||||
}
|
||||
if ($rm === "auto") {
|
||||
$rm = 0;
|
||||
}
|
||||
|
||||
$right = $diff;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Find auto properties and get them to take up the slack
|
||||
if ($width === "auto") {
|
||||
$width = $diff;
|
||||
@ -135,12 +151,9 @@ class Block extends AbstractFrameReflower
|
||||
$rm = $diff;
|
||||
}
|
||||
}
|
||||
|
||||
} else if ($diff < 0) {
|
||||
|
||||
// We are over constrained--set margin-right to the difference
|
||||
$rm = $diff;
|
||||
|
||||
}
|
||||
|
||||
return array(
|
||||
@ -182,7 +195,12 @@ class Block extends AbstractFrameReflower
|
||||
$width = $style->length_in_pt($style->width, $cb["w"]);
|
||||
}
|
||||
|
||||
extract($this->_calculate_width($width));
|
||||
$calculate_width = $this->_calculate_width($width);
|
||||
$margin_left = $calculate_width['margin_left'];
|
||||
$margin_right = $calculate_width['margin_right'];
|
||||
$width = $calculate_width['width'];
|
||||
$left = $calculate_width['left'];
|
||||
$right = $calculate_width['right'];
|
||||
|
||||
// Handle min/max width
|
||||
$min_width = $style->length_in_pt($style->min_width, $cb["w"]);
|
||||
@ -197,7 +215,12 @@ class Block extends AbstractFrameReflower
|
||||
}
|
||||
|
||||
if ($width < $min_width) {
|
||||
extract($this->_calculate_width($min_width));
|
||||
$calculate_width = $this->_calculate_width($min_width);
|
||||
$margin_left = $calculate_width['margin_left'];
|
||||
$margin_right = $calculate_width['margin_right'];
|
||||
$width = $calculate_width['width'];
|
||||
$left = $calculate_width['left'];
|
||||
$right = $calculate_width['right'];
|
||||
}
|
||||
|
||||
return array($width, $margin_left, $margin_right, $left, $right);
|
||||
@ -212,19 +235,13 @@ class Block extends AbstractFrameReflower
|
||||
*/
|
||||
protected function _calculate_content_height()
|
||||
{
|
||||
$lines = $this->_frame->get_line_boxes();
|
||||
$height = 0;
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$height += $line->h;
|
||||
$lines = $this->_frame->get_line_boxes();
|
||||
if (count($lines) > 0) {
|
||||
$last_line = end($lines);
|
||||
$content_box = $this->_frame->get_content_box();
|
||||
$height = $last_line->y + $last_line->h - $content_box["y"];
|
||||
}
|
||||
|
||||
/*
|
||||
$first_line = reset($lines);
|
||||
$last_line = end($lines);
|
||||
$height2 = $last_line->y + $last_line->h - $first_line->y;
|
||||
*/
|
||||
|
||||
return $height;
|
||||
}
|
||||
|
||||
@ -262,74 +279,101 @@ class Block extends AbstractFrameReflower
|
||||
$style->margin_bottom !== "auto" ? $style->margin_bottom : 0,
|
||||
$bottom !== "auto" ? $bottom : 0);
|
||||
|
||||
$sum = $style->length_in_pt($dims, $cb["h"]);
|
||||
$sum = (float)$style->length_in_pt($dims, $cb["h"]);
|
||||
|
||||
$diff = $cb["h"] - $sum;
|
||||
|
||||
if ($diff > 0) {
|
||||
|
||||
if ($height === "auto" && $top === "auto" && $bottom === "auto") {
|
||||
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
|
||||
$height = $diff;
|
||||
} else if ($height === "auto" && $top === "auto") {
|
||||
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
|
||||
$height = $content_height;
|
||||
$top = $diff - $content_height;
|
||||
} else if ($height === "auto" && $bottom === "auto") {
|
||||
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
|
||||
$height = $content_height;
|
||||
$bottom = $diff - $content_height;
|
||||
} else if ($top === "auto" && $bottom === "auto") {
|
||||
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
|
||||
$bottom = $diff;
|
||||
} else if ($top === "auto") {
|
||||
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
|
||||
$top = $diff;
|
||||
} else if ($height === "auto") {
|
||||
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
|
||||
$height = $diff;
|
||||
} else if ($bottom === "auto") {
|
||||
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
|
||||
$bottom = $diff;
|
||||
} else {
|
||||
|
||||
if ($style->overflow === "visible") {
|
||||
// set all autos to zero
|
||||
if ($margin_top === "auto") $margin_top = 0;
|
||||
if ($margin_bottom === "auto") $margin_bottom = 0;
|
||||
if ($top === "auto") $top = 0;
|
||||
if ($bottom === "auto") $bottom = 0;
|
||||
if ($height === "auto") $height = $content_height;
|
||||
if ($margin_top === "auto") {
|
||||
$margin_top = 0;
|
||||
}
|
||||
if ($margin_bottom === "auto") {
|
||||
$margin_bottom = 0;
|
||||
}
|
||||
if ($top === "auto") {
|
||||
$top = 0;
|
||||
}
|
||||
if ($bottom === "auto") {
|
||||
$bottom = 0;
|
||||
}
|
||||
if ($height === "auto") {
|
||||
$height = $content_height;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: overflow hidden
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Expand the height if overflow is visible
|
||||
if ($height === "auto" && $content_height > $height /* && $style->overflow === "visible" */) {
|
||||
$height = $content_height;
|
||||
@ -339,19 +383,14 @@ class Block extends AbstractFrameReflower
|
||||
// _calculate_restricted_width
|
||||
|
||||
// Only handle min/max height if the height is independent of the frame's content
|
||||
if (!($style->overflow === "visible" ||
|
||||
($style->overflow === "hidden" && $height === "auto"))
|
||||
) {
|
||||
|
||||
if (!($style->overflow === "visible" || ($style->overflow === "hidden" && $height === "auto"))) {
|
||||
$min_height = $style->min_height;
|
||||
$max_height = $style->max_height;
|
||||
|
||||
if (isset($cb["h"])) {
|
||||
$min_height = $style->length_in_pt($min_height, $cb["h"]);
|
||||
$max_height = $style->length_in_pt($max_height, $cb["h"]);
|
||||
|
||||
} else if (isset($cb["w"])) {
|
||||
|
||||
if (mb_strpos($min_height, "%") !== false) {
|
||||
$min_height = 0;
|
||||
} else {
|
||||
@ -378,11 +417,9 @@ class Block extends AbstractFrameReflower
|
||||
$height = $min_height;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return array($height, $margin_top, $margin_bottom, $top, $bottom);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -393,7 +430,7 @@ class Block extends AbstractFrameReflower
|
||||
{
|
||||
$style = $this->_frame->get_style();
|
||||
$w = $this->_frame->get_containing_block("w");
|
||||
$width = $style->length_in_pt($style->width, $w);
|
||||
$width = (float)$style->length_in_pt($style->width, $w);
|
||||
|
||||
switch ($style->text_align) {
|
||||
default:
|
||||
@ -428,11 +465,10 @@ class Block extends AbstractFrameReflower
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case "justify":
|
||||
// We justify all lines except the last one
|
||||
$lines = $this->_frame->get_line_boxes(); // needs to be a variable (strict standards)
|
||||
array_pop($lines);
|
||||
$last_line = array_pop($lines);
|
||||
|
||||
foreach ($lines as $i => $line) {
|
||||
if ($line->br) {
|
||||
@ -454,10 +490,6 @@ class Block extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
|
||||
// Only set the spacing if the line is long enough. This is really
|
||||
// just an aesthetic choice ;)
|
||||
//if ( $line["left"] + $line["w"] + $line["right"] > self::MIN_JUSTIFY_WIDTH * $width ) {
|
||||
|
||||
// Set the spacing for each child
|
||||
if ($line->wc > 1) {
|
||||
$spacing = ($width - ($line->left + $line->w + $line->right) + $space_width) / ($line->wc - 1);
|
||||
@ -474,7 +506,7 @@ class Block extends AbstractFrameReflower
|
||||
$text = $frame->get_text();
|
||||
$spaces = mb_substr_count($text, " ");
|
||||
|
||||
$char_spacing = $style->length_in_pt($style->letter_spacing);
|
||||
$char_spacing = (float)$style->length_in_pt($style->letter_spacing);
|
||||
$_spacing = $spacing + $char_spacing;
|
||||
|
||||
$frame->set_position($frame->get_position("x") + $dx);
|
||||
@ -485,8 +517,16 @@ class Block extends AbstractFrameReflower
|
||||
|
||||
// The line (should) now occupy the entire width
|
||||
$line->w = $width;
|
||||
}
|
||||
|
||||
//}
|
||||
// Adjust the last line if necessary
|
||||
if ($last_line->left) {
|
||||
foreach ($last_line->get_frames() as $frame) {
|
||||
if ($frame instanceof BlockFrameDecorator) {
|
||||
continue;
|
||||
}
|
||||
$frame->set_position($frame->get_position("x") + $last_line->left);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -515,7 +555,6 @@ class Block extends AbstractFrameReflower
|
||||
*/
|
||||
function vertical_align()
|
||||
{
|
||||
|
||||
$canvas = null;
|
||||
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
@ -524,13 +563,15 @@ class Block extends AbstractFrameReflower
|
||||
|
||||
foreach ($line->get_frames() as $frame) {
|
||||
$style = $frame->get_style();
|
||||
|
||||
if ($style->display !== "inline") {
|
||||
$isInlineBlock = (
|
||||
'-dompdf-image' === $style->display
|
||||
|| 'inline-block' === $style->display
|
||||
|| 'inline-table' === $style->display
|
||||
);
|
||||
if (!$isInlineBlock && $style->display !== "inline") {
|
||||
continue;
|
||||
}
|
||||
|
||||
$align = $frame->get_parent()->get_style()->vertical_align;
|
||||
|
||||
if (!isset($canvas)) {
|
||||
$canvas = $frame->get_root()->get_dompdf()->get_canvas();
|
||||
}
|
||||
@ -538,34 +579,91 @@ class Block extends AbstractFrameReflower
|
||||
$baseline = $canvas->get_font_baseline($style->font_family, $style->font_size);
|
||||
$y_offset = 0;
|
||||
|
||||
switch ($align) {
|
||||
case "baseline":
|
||||
$y_offset = $height * 0.8 - $baseline; // The 0.8 ratio is arbitrary until we find it's meaning
|
||||
break;
|
||||
//FIXME: The 0.8 ratio applied to the height is arbitrary (used to accommodate descenders?)
|
||||
if($isInlineBlock) {
|
||||
$lineFrames = $line->get_frames();
|
||||
if (count($lineFrames) == 1) {
|
||||
continue;
|
||||
}
|
||||
$frameBox = $frame->get_frame()->get_border_box();
|
||||
$imageHeightDiff = $height * 0.8 - (float)$frameBox['h'];
|
||||
|
||||
case "middle":
|
||||
$y_offset = ($height * 0.8 - $baseline) / 2;
|
||||
break;
|
||||
$align = $frame->get_style()->vertical_align;
|
||||
if (in_array($align, Style::$vertical_align_keywords) === true) {
|
||||
switch ($align) {
|
||||
case "middle":
|
||||
$y_offset = $imageHeightDiff / 2;
|
||||
break;
|
||||
|
||||
case "sub":
|
||||
$y_offset = 0.3 * $height;
|
||||
break;
|
||||
case "sub":
|
||||
$y_offset = 0.3 * $height + $imageHeightDiff;
|
||||
break;
|
||||
|
||||
case "super":
|
||||
$y_offset = -0.2 * $height;
|
||||
break;
|
||||
case "super":
|
||||
$y_offset = -0.2 * $height + $imageHeightDiff;
|
||||
break;
|
||||
|
||||
case "text-top":
|
||||
case "top": // Not strictly accurate, but good enough for now
|
||||
break;
|
||||
case "text-top": // FIXME: this should be the height of the frame minus the height of the text
|
||||
$y_offset = $height - (float)$style->length_in_pt($style->get_line_height(), $style->font_size);
|
||||
break;
|
||||
|
||||
case "text-bottom":
|
||||
case "bottom":
|
||||
$y_offset = $height * 0.8 - $baseline;
|
||||
break;
|
||||
case "top":
|
||||
break;
|
||||
|
||||
case "text-bottom": // FIXME: align bottom of image with the descender?
|
||||
case "bottom":
|
||||
$y_offset = 0.3 * $height + $imageHeightDiff;
|
||||
break;
|
||||
|
||||
case "baseline":
|
||||
default:
|
||||
$y_offset = $imageHeightDiff;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$y_offset = $baseline - (float)$style->length_in_pt($align, $style->font_size) - (float)$frameBox['h'];
|
||||
}
|
||||
} else {
|
||||
$parent = $frame->get_parent();
|
||||
if ($parent instanceof TableCellFrameDecorator) {
|
||||
$align = "baseline";
|
||||
} else {
|
||||
$align = $parent->get_style()->vertical_align;
|
||||
}
|
||||
if (in_array($align, Style::$vertical_align_keywords) === true) {
|
||||
switch ($align) {
|
||||
case "middle":
|
||||
$y_offset = ($height * 0.8 - $baseline) / 2;
|
||||
break;
|
||||
|
||||
case "sub":
|
||||
$y_offset = $height * 0.8 - $baseline * 0.5;
|
||||
break;
|
||||
|
||||
case "super":
|
||||
$y_offset = $height * 0.8 - $baseline * 1.4;
|
||||
break;
|
||||
|
||||
case "text-top":
|
||||
case "top": // Not strictly accurate, but good enough for now
|
||||
break;
|
||||
|
||||
case "text-bottom":
|
||||
case "bottom":
|
||||
$y_offset = $height * 0.8 - $baseline;
|
||||
break;
|
||||
|
||||
case "baseline":
|
||||
default:
|
||||
$y_offset = $height * 0.8 - $baseline;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$y_offset = $height * 0.8 - $baseline - (float)$style->length_in_pt($align, $style->font_size);
|
||||
}
|
||||
}
|
||||
|
||||
if ($y_offset) {
|
||||
if ($y_offset !== 0) {
|
||||
$frame->move(0, $y_offset);
|
||||
}
|
||||
}
|
||||
@ -582,6 +680,14 @@ class Block extends AbstractFrameReflower
|
||||
|
||||
// Handle "clear"
|
||||
if ($child_style->clear !== "none") {
|
||||
//TODO: this is a WIP for handling clear/float frames that are in between inline frames
|
||||
if ($child->get_prev_sibling() !== null) {
|
||||
$this->_frame->add_line();
|
||||
}
|
||||
if ($child_style->float !== "none" && $child->get_next_sibling()) {
|
||||
$this->_frame->set_current_line_number($this->_frame->get_current_line_number() - 1);
|
||||
}
|
||||
|
||||
$lowest_y = $root->get_lowest_float_offset($child);
|
||||
|
||||
// If a float is still applying, we handle it
|
||||
@ -657,6 +763,7 @@ class Block extends AbstractFrameReflower
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator $block
|
||||
* @return mixed|void
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
@ -688,30 +795,30 @@ class Block extends AbstractFrameReflower
|
||||
list($w, $left_margin, $right_margin, $left, $right) = $this->_calculate_restricted_width();
|
||||
|
||||
// Store the calculated properties
|
||||
$style->width = $w . "pt";
|
||||
$style->margin_left = $left_margin . "pt";
|
||||
$style->margin_right = $right_margin . "pt";
|
||||
$style->left = $left . "pt";
|
||||
$style->right = $right . "pt";
|
||||
$style->width = $w;
|
||||
$style->margin_left = $left_margin;
|
||||
$style->margin_right = $right_margin;
|
||||
$style->left = $left;
|
||||
$style->right = $right;
|
||||
|
||||
// Update the position
|
||||
$this->_frame->position();
|
||||
list($x, $y) = $this->_frame->get_position();
|
||||
|
||||
// Adjust the first line based on the text-indent property
|
||||
$indent = $style->length_in_pt($style->text_indent, $cb["w"]);
|
||||
$indent = (float)$style->length_in_pt($style->text_indent, $cb["w"]);
|
||||
$this->_frame->increase_line_width($indent);
|
||||
|
||||
// Determine the content edge
|
||||
$top = $style->length_in_pt(array($style->margin_top,
|
||||
$top = (float)$style->length_in_pt(array($style->margin_top,
|
||||
$style->padding_top,
|
||||
$style->border_top_width), $cb["h"]);
|
||||
|
||||
$bottom = $style->length_in_pt(array($style->border_bottom_width,
|
||||
$bottom = (float)$style->length_in_pt(array($style->border_bottom_width,
|
||||
$style->margin_bottom,
|
||||
$style->padding_bottom), $cb["h"]);
|
||||
|
||||
$cb_x = $x + $left_margin + $style->length_in_pt(array($style->border_left_width,
|
||||
$cb_x = $x + (float)$left_margin + (float)$style->length_in_pt(array($style->border_left_width,
|
||||
$style->padding_left), $cb["w"]);
|
||||
|
||||
$cb_y = $y + $top;
|
||||
@ -753,11 +860,12 @@ class Block extends AbstractFrameReflower
|
||||
$style->top = $top;
|
||||
$style->bottom = $bottom;
|
||||
|
||||
$orig_style = $this->_frame->get_original_style();
|
||||
|
||||
$needs_reposition = ($style->position === "absolute" && ($style->right !== "auto" || $style->bottom !== "auto"));
|
||||
|
||||
// Absolute positioning measurement
|
||||
if ($needs_reposition) {
|
||||
$orig_style = $this->_frame->get_original_style();
|
||||
if ($orig_style->width === "auto" && ($orig_style->left === "auto" || $orig_style->right === "auto")) {
|
||||
$width = 0;
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
@ -770,6 +878,25 @@ class Block extends AbstractFrameReflower
|
||||
$style->right = $orig_style->right;
|
||||
}
|
||||
|
||||
// Calculate inline-block / float auto-widths
|
||||
if (($style->display === "inline-block" || $style->float !== 'none') && $orig_style->width === 'auto') {
|
||||
$width = 0;
|
||||
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
$line->recalculate_width();
|
||||
|
||||
$width = max($line->w, $width);
|
||||
}
|
||||
|
||||
if ($width === 0) {
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
$width += $child->calculate_auto_width();
|
||||
}
|
||||
}
|
||||
|
||||
$style->width = $width;
|
||||
}
|
||||
|
||||
$this->_text_align();
|
||||
$this->vertical_align();
|
||||
|
||||
@ -790,4 +917,32 @@ class Block extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine current frame width based on contents
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function calculate_auto_width()
|
||||
{
|
||||
$width = 0;
|
||||
|
||||
foreach ($this->_frame->get_line_boxes() as $line) {
|
||||
$line_width = 0;
|
||||
|
||||
foreach ($line->get_frames() as $frame) {
|
||||
if ($frame->get_original_style()->width == 'auto') {
|
||||
$line_width += $frame->calculate_auto_width();
|
||||
} else {
|
||||
$line_width += $frame->get_margin_width();
|
||||
}
|
||||
}
|
||||
|
||||
$width = max($line_width, $width);
|
||||
}
|
||||
|
||||
$this->_frame->get_style()->width = $width;
|
||||
|
||||
return $this->_frame->get_margin_width();
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,18 @@ use Dompdf\FrameDecorator\Image as ImageFrameDecorator;
|
||||
class Image extends AbstractFrameReflower
|
||||
{
|
||||
|
||||
/**
|
||||
* Image constructor.
|
||||
* @param ImageFrameDecorator $frame
|
||||
*/
|
||||
function __construct(ImageFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
$this->_frame->position();
|
||||
@ -36,7 +43,7 @@ class Image extends AbstractFrameReflower
|
||||
//if ($frame->get_style()->float !== "none" ) {
|
||||
// $page->add_floating_frame($this);
|
||||
//}
|
||||
|
||||
|
||||
// Set the frame's width
|
||||
$this->get_min_max_width();
|
||||
|
||||
@ -45,9 +52,12 @@ class Image extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function get_min_max_width()
|
||||
{
|
||||
if ($this->get_dompdf()->get_option("debugPng")) {
|
||||
if ($this->get_dompdf()->getOptions()->getDebugPng()) {
|
||||
// Determine the image's size. Time consuming. Only when really needed?
|
||||
list($img_width, $img_height) = Helpers::dompdf_getimagesize($this->_frame->get_image_url(), $this->get_dompdf()->getHttpContext());
|
||||
print "get_min_max_width() " .
|
||||
@ -83,7 +93,7 @@ class Image extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
$width = ((float)rtrim($width, "%") * $t) / 100; //maybe 0
|
||||
} elseif (!mb_strpos($width, 'pt')) {
|
||||
} else {
|
||||
// Don't set image original size if "%" branch was 0 or size not given.
|
||||
// Otherwise aspect changed on %/auto combination for width/height
|
||||
// Resample according to px per inch
|
||||
@ -96,13 +106,13 @@ class Image extends AbstractFrameReflower
|
||||
$t = 0.0;
|
||||
for ($f = $this->_frame->get_parent(); $f; $f = $f->get_parent()) {
|
||||
$f_style = $f->get_style();
|
||||
$t = $f_style->length_in_pt($f_style->height);
|
||||
$t = (float)$f_style->length_in_pt($f_style->height);
|
||||
if ($t != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$height = ((float)rtrim($height, "%") * $t) / 100; //maybe 0
|
||||
} elseif (!mb_strpos($height, 'pt')) {
|
||||
} else {
|
||||
// Don't set image original size if "%" branch was 0 or size not given.
|
||||
// Otherwise aspect changed on %/auto combination for width/height
|
||||
// Resample according to px per inch
|
||||
@ -118,7 +128,7 @@ class Image extends AbstractFrameReflower
|
||||
// Resample according to px per inch
|
||||
// See also ListBulletImage::__construct
|
||||
if ($width == 0 && $height == 0) {
|
||||
$dpi = $this->_frame->get_dompdf()->get_option("dpi");
|
||||
$dpi = $this->_frame->get_dompdf()->getOptions()->getDpi();
|
||||
$width = (float)($img_width * 72) / $dpi;
|
||||
$height = (float)($img_height * 72) / $dpi;
|
||||
$width_forced = false;
|
||||
@ -179,7 +189,9 @@ class Image extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->get_dompdf()->get_option("debugPng")) print $width . ' ' . $height . ';';
|
||||
if ($this->get_dompdf()->getOptions()->getDebugPng()) {
|
||||
print $width . ' ' . $height . ';';
|
||||
}
|
||||
|
||||
$style->width = $width . "pt";
|
||||
$style->height = $height . "pt";
|
||||
@ -190,6 +202,5 @@ class Image extends AbstractFrameReflower
|
||||
$style->max_height = "none";
|
||||
|
||||
return array($width, $width, "min" => $width, "max" => $width);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -19,13 +19,18 @@ use Dompdf\FrameDecorator\Text as TextFrameDecorator;
|
||||
class Inline extends AbstractFrameReflower
|
||||
{
|
||||
|
||||
/**
|
||||
* Inline constructor.
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function __construct(Frame $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
$frame = $this->_frame;
|
||||
@ -73,4 +78,26 @@ class Inline extends AbstractFrameReflower
|
||||
$child->reflow($block);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine current frame width based on contents
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function calculate_auto_width()
|
||||
{
|
||||
$width = 0;
|
||||
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
if ($child->get_original_style()->width == 'auto') {
|
||||
$width += $child->calculate_auto_width();
|
||||
} else {
|
||||
$width += $child->get_margin_width();
|
||||
}
|
||||
}
|
||||
|
||||
$this->_frame->get_style()->width = $width;
|
||||
|
||||
return $this->_frame->get_margin_width();
|
||||
}
|
||||
}
|
||||
|
@ -18,13 +18,18 @@ use Dompdf\FrameDecorator\AbstractFrameDecorator;
|
||||
class ListBullet extends AbstractFrameReflower
|
||||
{
|
||||
|
||||
/**
|
||||
* ListBullet constructor.
|
||||
* @param AbstractFrameDecorator $frame
|
||||
*/
|
||||
function __construct(AbstractFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
$style = $this->_frame->get_style();
|
||||
@ -36,6 +41,5 @@ class ListBullet extends AbstractFrameReflower
|
||||
$p = $this->_frame->find_block_parent();
|
||||
$p->add_frame_to_line($this->_frame);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,18 @@ use Dompdf\FrameDecorator\Block as BlockFrameDecorator;
|
||||
class NullFrameReflower extends AbstractFrameReflower
|
||||
{
|
||||
|
||||
/**
|
||||
* NullFrameReflower constructor.
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function __construct(Frame $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
return;
|
||||
|
22
library/vendor/dompdf/src/FrameReflower/Page.php
vendored
22
library/vendor/dompdf/src/FrameReflower/Page.php
vendored
@ -34,11 +34,19 @@ class Page extends AbstractFrameReflower
|
||||
*/
|
||||
private $_canvas;
|
||||
|
||||
/**
|
||||
* Page constructor.
|
||||
* @param PageFrameDecorator $frame
|
||||
*/
|
||||
function __construct(PageFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Frame $frame
|
||||
* @param $page_number
|
||||
*/
|
||||
function apply_page_style(Frame $frame, $page_number)
|
||||
{
|
||||
$style = $frame->get_style();
|
||||
@ -77,11 +85,11 @@ class Page extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Paged layout:
|
||||
* http://www.w3.org/TR/CSS21/page.html
|
||||
*
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
@ -97,10 +105,10 @@ class Page extends AbstractFrameReflower
|
||||
|
||||
// Pages are only concerned with margins
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
$left = $style->length_in_pt($style->margin_left, $cb["w"]);
|
||||
$right = $style->length_in_pt($style->margin_right, $cb["w"]);
|
||||
$top = $style->length_in_pt($style->margin_top, $cb["h"]);
|
||||
$bottom = $style->length_in_pt($style->margin_bottom, $cb["h"]);
|
||||
$left = (float)$style->length_in_pt($style->margin_left, $cb["w"]);
|
||||
$right = (float)$style->length_in_pt($style->margin_right, $cb["w"]);
|
||||
$top = (float)$style->length_in_pt($style->margin_top, $cb["h"]);
|
||||
$bottom = (float)$style->length_in_pt($style->margin_bottom, $cb["h"]);
|
||||
|
||||
$content_x = $cb["x"] + $left;
|
||||
$content_y = $cb["y"] + $top;
|
||||
@ -162,8 +170,6 @@ class Page extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* Check for callbacks that need to be performed when a given event
|
||||
* gets triggered on a page
|
||||
|
194
library/vendor/dompdf/src/FrameReflower/Table.php
vendored
194
library/vendor/dompdf/src/FrameReflower/Table.php
vendored
@ -32,6 +32,10 @@ class Table extends AbstractFrameReflower
|
||||
*/
|
||||
protected $_state;
|
||||
|
||||
/**
|
||||
* Table constructor.
|
||||
* @param TableFrameDecorator $frame
|
||||
*/
|
||||
function __construct(TableFrameDecorator $frame)
|
||||
{
|
||||
$this->_state = null;
|
||||
@ -47,8 +51,6 @@ class Table extends AbstractFrameReflower
|
||||
$this->_min_max_cache = null;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
protected function _assign_widths()
|
||||
{
|
||||
$style = $this->_frame->get_style();
|
||||
@ -77,13 +79,13 @@ class Table extends AbstractFrameReflower
|
||||
|
||||
$centered = ($left === "auto" && $right === "auto");
|
||||
|
||||
$left = $left === "auto" ? 0 : $style->length_in_pt($left, $cb["w"]);
|
||||
$right = $right === "auto" ? 0 : $style->length_in_pt($right, $cb["w"]);
|
||||
$left = (float)($left === "auto" ? 0 : $style->length_in_pt($left, $cb["w"]));
|
||||
$right = (float)($right === "auto" ? 0 : $style->length_in_pt($right, $cb["w"]));
|
||||
|
||||
$delta = $left + $right;
|
||||
|
||||
if (!$centered) {
|
||||
$delta += $style->length_in_pt(array(
|
||||
$delta += (float)$style->length_in_pt(array(
|
||||
$style->padding_left,
|
||||
$style->border_left_width,
|
||||
$style->border_right_width,
|
||||
@ -91,35 +93,37 @@ class Table extends AbstractFrameReflower
|
||||
$cb["w"]);
|
||||
}
|
||||
|
||||
$min_table_width = $style->length_in_pt($style->min_width, $cb["w"] - $delta);
|
||||
$min_table_width = (float)$style->length_in_pt($style->min_width, $cb["w"] - $delta);
|
||||
|
||||
// min & max widths already include borders & padding
|
||||
$min_width -= $delta;
|
||||
$max_width -= $delta;
|
||||
|
||||
if ($width !== "auto") {
|
||||
$preferred_width = (float)$style->length_in_pt($width, $cb["w"]) - $delta;
|
||||
|
||||
$preferred_width = $style->length_in_pt($width, $cb["w"]) - $delta;
|
||||
|
||||
if ($preferred_width < $min_table_width)
|
||||
if ($preferred_width < $min_table_width) {
|
||||
$preferred_width = $min_table_width;
|
||||
}
|
||||
|
||||
if ($preferred_width > $min_width)
|
||||
if ($preferred_width > $min_width) {
|
||||
$width = $preferred_width;
|
||||
else
|
||||
} else {
|
||||
$width = $min_width;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ($max_width + $delta < $cb["w"])
|
||||
if ($max_width + $delta < $cb["w"]) {
|
||||
$width = $max_width;
|
||||
else if ($cb["w"] - $delta > $min_width)
|
||||
} else if ($cb["w"] - $delta > $min_width) {
|
||||
$width = $cb["w"] - $delta;
|
||||
else
|
||||
} else {
|
||||
$width = $min_width;
|
||||
}
|
||||
|
||||
if ($width < $min_table_width)
|
||||
if ($width < $min_table_width) {
|
||||
$width = $min_table_width;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -134,16 +138,15 @@ class Table extends AbstractFrameReflower
|
||||
|
||||
// If the whole table fits on the page, then assign each column it's max width
|
||||
if ($width == $max_width) {
|
||||
|
||||
foreach (array_keys($columns) as $i)
|
||||
foreach (array_keys($columns) as $i) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["max-width"]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine leftover and assign it evenly to all columns
|
||||
if ($width > $min_width) {
|
||||
|
||||
// We have four cases to deal with:
|
||||
//
|
||||
// 1. All columns are auto--no widths have been specified. In this
|
||||
@ -172,21 +175,19 @@ class Table extends AbstractFrameReflower
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Case 2
|
||||
if ($absolute_used > 0 && $percent_used == 0) {
|
||||
|
||||
if (count($auto) > 0)
|
||||
if (count($auto) > 0) {
|
||||
$increment = ($width - $auto_min - $absolute_used) / count($auto);
|
||||
}
|
||||
|
||||
// Use the absolutely specified width or the increment
|
||||
foreach (array_keys($columns) as $i) {
|
||||
|
||||
if ($columns[$i]["absolute"] > 0 && count($auto))
|
||||
if ($columns[$i]["absolute"] > 0 && count($auto)) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"]);
|
||||
else if (count($auto))
|
||||
} else if (count($auto)) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
|
||||
else {
|
||||
} else {
|
||||
// All absolute columns
|
||||
$increment = ($width - $absolute_used) * $columns[$i]["absolute"] / $absolute_used;
|
||||
|
||||
@ -197,19 +198,18 @@ class Table extends AbstractFrameReflower
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Case 3:
|
||||
if ($absolute_used == 0 && $percent_used > 0) {
|
||||
|
||||
$scale = null;
|
||||
$remaining = null;
|
||||
|
||||
// Scale percent values if the total percentage is > 100, or if all
|
||||
// values are specified as percentages.
|
||||
if ($percent_used > 100 || count($auto) == 0)
|
||||
if ($percent_used > 100 || count($auto) == 0) {
|
||||
$scale = 100 / $percent_used;
|
||||
else
|
||||
} else {
|
||||
$scale = 1;
|
||||
}
|
||||
|
||||
// Account for the minimum space used by the unassigned auto columns
|
||||
$used_width = $auto_min;
|
||||
@ -221,8 +221,9 @@ class Table extends AbstractFrameReflower
|
||||
|
||||
$w = min($columns[$i]["percent"] * $width / 100, $slack);
|
||||
|
||||
if ($w < $columns[$i]["min-width"])
|
||||
if ($w < $columns[$i]["min-width"]) {
|
||||
$w = $columns[$i]["min-width"];
|
||||
}
|
||||
|
||||
$cellmap->set_column_width($i, $w);
|
||||
$used_width += $w;
|
||||
@ -234,8 +235,9 @@ class Table extends AbstractFrameReflower
|
||||
if (count($auto) > 0) {
|
||||
$increment = ($width - $used_width) / count($auto);
|
||||
|
||||
foreach ($auto as $i)
|
||||
foreach ($auto as $i) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
@ -245,7 +247,6 @@ class Table extends AbstractFrameReflower
|
||||
|
||||
// First-come, first served
|
||||
if ($absolute_used > 0 && $percent_used > 0) {
|
||||
|
||||
$used_width = $auto_min;
|
||||
|
||||
foreach ($absolute as $i) {
|
||||
@ -255,10 +256,11 @@ class Table extends AbstractFrameReflower
|
||||
|
||||
// Scale percent values if the total percentage is > 100 or there
|
||||
// are no auto values to take up slack
|
||||
if ($percent_used > 100 || count($auto) == 0)
|
||||
if ($percent_used > 100 || count($auto) == 0) {
|
||||
$scale = 100 / $percent_used;
|
||||
else
|
||||
} else {
|
||||
$scale = 1;
|
||||
}
|
||||
|
||||
$remaining_width = $width - $used_width;
|
||||
|
||||
@ -268,8 +270,9 @@ class Table extends AbstractFrameReflower
|
||||
$columns[$i]["percent"] *= $scale;
|
||||
$w = min($columns[$i]["percent"] * $remaining_width / 100, $slack);
|
||||
|
||||
if ($w < $columns[$i]["min-width"])
|
||||
if ($w < $columns[$i]["min-width"]) {
|
||||
$w = $columns[$i]["min-width"];
|
||||
}
|
||||
|
||||
$columns[$i]["used-width"] = $w;
|
||||
$used_width += $w;
|
||||
@ -278,30 +281,28 @@ class Table extends AbstractFrameReflower
|
||||
if (count($auto) > 0) {
|
||||
$increment = ($width - $used_width) / count($auto);
|
||||
|
||||
foreach ($auto as $i)
|
||||
foreach ($auto as $i) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"] + $increment);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
} else { // we are over constrained
|
||||
|
||||
// Each column gets its minimum width
|
||||
foreach (array_keys($columns) as $i)
|
||||
foreach (array_keys($columns) as $i) {
|
||||
$cellmap->set_column_width($i, $columns[$i]["min-width"]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
// Determine the frame's height based on min/max height
|
||||
/**
|
||||
* Determine the frame's height based on min/max height
|
||||
*
|
||||
* @return float|int|mixed|string
|
||||
*/
|
||||
protected function _calculate_height()
|
||||
{
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
$height = $style->height;
|
||||
|
||||
@ -311,15 +312,15 @@ class Table extends AbstractFrameReflower
|
||||
|
||||
// Determine our content height
|
||||
$content_height = 0;
|
||||
foreach ($rows as $r)
|
||||
foreach ($rows as $r) {
|
||||
$content_height += $r["height"];
|
||||
}
|
||||
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
|
||||
if (!($style->overflow === "visible" ||
|
||||
($style->overflow === "hidden" && $height === "auto"))
|
||||
) {
|
||||
|
||||
// Only handle min/max height if the height is independent of the frame's content
|
||||
|
||||
$min_height = $style->min_height;
|
||||
@ -330,48 +331,47 @@ class Table extends AbstractFrameReflower
|
||||
$max_height = $style->length_in_pt($max_height, $cb["h"]);
|
||||
|
||||
} else if (isset($cb["w"])) {
|
||||
|
||||
if (mb_strpos($min_height, "%") !== false)
|
||||
if (mb_strpos($min_height, "%") !== false) {
|
||||
$min_height = 0;
|
||||
else
|
||||
} else {
|
||||
$min_height = $style->length_in_pt($min_height, $cb["w"]);
|
||||
|
||||
if (mb_strpos($max_height, "%") !== false)
|
||||
}
|
||||
if (mb_strpos($max_height, "%") !== false) {
|
||||
$max_height = "none";
|
||||
else
|
||||
} else {
|
||||
$max_height = $style->length_in_pt($max_height, $cb["w"]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($max_height !== "none" && $min_height > $max_height)
|
||||
if ($max_height !== "none" && $min_height > $max_height) {
|
||||
// Swap 'em
|
||||
list($max_height, $min_height) = array($min_height, $max_height);
|
||||
}
|
||||
|
||||
if ($max_height !== "none" && $height > $max_height)
|
||||
if ($max_height !== "none" && $height > $max_height) {
|
||||
$height = $max_height;
|
||||
}
|
||||
|
||||
if ($height < $min_height)
|
||||
if ($height < $min_height) {
|
||||
$height = $min_height;
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
// Use the content height or the height value, whichever is greater
|
||||
if ($height !== "auto") {
|
||||
$height = $style->length_in_pt($height, $cb["h"]);
|
||||
|
||||
if ($height <= $content_height)
|
||||
if ($height <= $content_height) {
|
||||
$height = $content_height;
|
||||
else
|
||||
} else {
|
||||
$cellmap->set_frame_heights($height, $content_height);
|
||||
|
||||
} else
|
||||
}
|
||||
} else {
|
||||
$height = $content_height;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $height;
|
||||
|
||||
}
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator $block
|
||||
@ -386,8 +386,9 @@ class Table extends AbstractFrameReflower
|
||||
$page->check_forced_page_break($frame);
|
||||
|
||||
// Bail if the page is full
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the page know that we're reflowing a table so that splits
|
||||
// are suppressed (simply setting page-break-inside: avoid won't
|
||||
@ -403,8 +404,9 @@ class Table extends AbstractFrameReflower
|
||||
// Table layout algorithm:
|
||||
// http://www.w3.org/TR/CSS21/tables.html#auto-table-layout
|
||||
|
||||
if (is_null($this->_state))
|
||||
if (is_null($this->_state)) {
|
||||
$this->get_min_max_width();
|
||||
}
|
||||
|
||||
$cb = $frame->get_containing_block();
|
||||
$style = $frame->get_style();
|
||||
@ -415,14 +417,13 @@ class Table extends AbstractFrameReflower
|
||||
if ($style->border_collapse === "separate") {
|
||||
list($h, $v) = $style->border_spacing;
|
||||
|
||||
$v = $style->length_in_pt($v) / 2;
|
||||
$h = $style->length_in_pt($h) / 2;
|
||||
|
||||
$style->padding_left = $style->length_in_pt($style->padding_left, $cb["w"]) + $h;
|
||||
$style->padding_right = $style->length_in_pt($style->padding_right, $cb["w"]) + $h;
|
||||
$style->padding_top = $style->length_in_pt($style->padding_top, $cb["h"]) + $v;
|
||||
$style->padding_bottom = $style->length_in_pt($style->padding_bottom, $cb["h"]) + $v;
|
||||
$v = (float)$style->length_in_pt($v) / 2;
|
||||
$h = (float)$style->length_in_pt($h) / 2;
|
||||
|
||||
$style->padding_left = (float)$style->length_in_pt($style->padding_left, $cb["w"]) + $h;
|
||||
$style->padding_right = (float)$style->length_in_pt($style->padding_right, $cb["w"]) + $h;
|
||||
$style->padding_top = (float)$style->length_in_pt($style->padding_top, $cb["h"]) + $v;
|
||||
$style->padding_bottom = (float)$style->length_in_pt($style->padding_bottom, $cb["h"]) + $v;
|
||||
}
|
||||
|
||||
$this->_assign_widths();
|
||||
@ -442,31 +443,31 @@ class Table extends AbstractFrameReflower
|
||||
$left = $right = $diff / 2;
|
||||
}
|
||||
|
||||
$style->margin_left = "$left pt";
|
||||
$style->margin_right = "$right pt";
|
||||
|
||||
$style->margin_left = sprintf("%Fpt", $left);
|
||||
$style->margin_right = sprintf("%Fpt", $right);;
|
||||
} else {
|
||||
if ($left === "auto") {
|
||||
$left = $style->length_in_pt($cb["w"] - $right - $width, $cb["w"]);
|
||||
$left = (float)$style->length_in_pt($cb["w"] - $right - $width, $cb["w"]);
|
||||
}
|
||||
if ($right === "auto") {
|
||||
$left = $style->length_in_pt($left, $cb["w"]);
|
||||
$left = (float)$style->length_in_pt($left, $cb["w"]);
|
||||
}
|
||||
}
|
||||
|
||||
list($x, $y) = $frame->get_position();
|
||||
|
||||
// Determine the content edge
|
||||
$content_x = $x + $left + $style->length_in_pt(array($style->padding_left,
|
||||
$content_x = $x + (float)$left + (float)$style->length_in_pt(array($style->padding_left,
|
||||
$style->border_left_width), $cb["w"]);
|
||||
$content_y = $y + $style->length_in_pt(array($style->margin_top,
|
||||
$content_y = $y + (float)$style->length_in_pt(array($style->margin_top,
|
||||
$style->border_top_width,
|
||||
$style->padding_top), $cb["h"]);
|
||||
|
||||
if (isset($cb["h"]))
|
||||
if (isset($cb["h"])) {
|
||||
$h = $cb["h"];
|
||||
else
|
||||
} else {
|
||||
$h = null;
|
||||
}
|
||||
|
||||
$cellmap = $frame->get_cellmap();
|
||||
$col =& $cellmap->get_column(0);
|
||||
@ -479,17 +480,18 @@ class Table extends AbstractFrameReflower
|
||||
|
||||
// Set the containing block of each child & reflow
|
||||
foreach ($frame->get_children() as $child) {
|
||||
|
||||
// Bail if the page is full
|
||||
if (!$page->in_nested_table() && $page->is_full())
|
||||
if (!$page->in_nested_table() && $page->is_full()) {
|
||||
break;
|
||||
}
|
||||
|
||||
$child->set_containing_block($content_x, $content_y, $width, $h);
|
||||
$child->reflow();
|
||||
|
||||
if (!$page->in_nested_table())
|
||||
if (!$page->in_nested_table()) {
|
||||
// Check if a split has occured
|
||||
$page->check_page_break($child);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -512,13 +514,14 @@ class Table extends AbstractFrameReflower
|
||||
}
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
function get_min_max_width()
|
||||
{
|
||||
|
||||
if (!is_null($this->_min_max_cache))
|
||||
if (!is_null($this->_min_max_cache)) {
|
||||
return $this->_min_max_cache;
|
||||
}
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
@ -550,11 +553,9 @@ class Table extends AbstractFrameReflower
|
||||
if ($columns[$i]["absolute"] > 0) {
|
||||
$this->_state["absolute"][] = $i;
|
||||
$this->_state["absolute_used"] += $columns[$i]["absolute"];
|
||||
|
||||
} else if ($columns[$i]["percent"] > 0) {
|
||||
$this->_state["percent"][] = $i;
|
||||
$this->_state["percent_used"] += $columns[$i]["percent"];
|
||||
|
||||
} else {
|
||||
$this->_state["auto"][] = $i;
|
||||
$this->_state["auto_min"] += $columns[$i]["min-width"];
|
||||
@ -569,10 +570,11 @@ class Table extends AbstractFrameReflower
|
||||
$style->margin_left,
|
||||
$style->margin_right);
|
||||
|
||||
if ($style->border_collapse !== "collapse")
|
||||
if ($style->border_collapse !== "collapse") {
|
||||
list($dims[]) = $style->border_spacing;
|
||||
}
|
||||
|
||||
$delta = $style->length_in_pt($dims, $this->_frame->get_containing_block("w"));
|
||||
$delta = (float)$style->length_in_pt($dims, $this->_frame->get_containing_block("w"));
|
||||
|
||||
$this->_state["min_width"] += $delta;
|
||||
$this->_state["max_width"] += $delta;
|
||||
|
@ -17,14 +17,20 @@ use Dompdf\FrameDecorator\Table as TableFrameDecorator;
|
||||
*/
|
||||
class TableCell extends Block
|
||||
{
|
||||
/**
|
||||
* TableCell constructor.
|
||||
* @param BlockFrameDecorator $frame
|
||||
*/
|
||||
function __construct(BlockFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
|
||||
$style = $this->_frame->get_style();
|
||||
|
||||
$table = TableFrameDecorator::find_parent_table($this->_frame);
|
||||
@ -44,21 +50,21 @@ class TableCell extends Block
|
||||
//FIXME?
|
||||
$h = $this->_frame->get_containing_block("h");
|
||||
|
||||
$left_space = $style->length_in_pt(array($style->margin_left,
|
||||
$left_space = (float)$style->length_in_pt(array($style->margin_left,
|
||||
$style->padding_left,
|
||||
$style->border_left_width),
|
||||
$w);
|
||||
|
||||
$right_space = $style->length_in_pt(array($style->padding_right,
|
||||
$right_space = (float)$style->length_in_pt(array($style->padding_right,
|
||||
$style->margin_right,
|
||||
$style->border_right_width),
|
||||
$w);
|
||||
|
||||
$top_space = $style->length_in_pt(array($style->margin_top,
|
||||
$top_space = (float)$style->length_in_pt(array($style->margin_top,
|
||||
$style->padding_top,
|
||||
$style->border_top_width),
|
||||
$h);
|
||||
$bottom_space = $style->length_in_pt(array($style->margin_bottom,
|
||||
$bottom_space = (float)$style->length_in_pt(array($style->margin_bottom,
|
||||
$style->padding_bottom,
|
||||
$style->border_bottom_width),
|
||||
$h);
|
||||
@ -69,7 +75,7 @@ class TableCell extends Block
|
||||
$content_y = $line_y = $y + $top_space;
|
||||
|
||||
// Adjust the first line based on the text-indent property
|
||||
$indent = $style->length_in_pt($style->text_indent, $w);
|
||||
$indent = (float)$style->length_in_pt($style->text_indent, $w);
|
||||
$this->_frame->increase_line_width($indent);
|
||||
|
||||
$page = $this->_frame->get_root();
|
||||
@ -80,41 +86,36 @@ class TableCell extends Block
|
||||
|
||||
// Set the containing blocks and reflow each child
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
break;
|
||||
}
|
||||
|
||||
$child->set_containing_block($content_x, $content_y, $cb_w, $h);
|
||||
|
||||
$this->process_clear($child);
|
||||
|
||||
$child->reflow($this->_frame);
|
||||
|
||||
$this->process_float($child, $x + $left_space, $w - $right_space - $left_space);
|
||||
}
|
||||
|
||||
// Determine our height
|
||||
$style_height = $style->length_in_pt($style->height, $h);
|
||||
$style_height = (float)$style->length_in_pt($style->height, $h);
|
||||
|
||||
$this->_frame->set_content_height($this->_calculate_content_height());
|
||||
|
||||
$height = max($style_height, $this->_frame->get_content_height());
|
||||
$height = max($style_height, (float)$this->_frame->get_content_height());
|
||||
|
||||
// Let the cellmap know our height
|
||||
$cell_height = $height / count($cells["rows"]);
|
||||
|
||||
if ($style_height <= $height)
|
||||
if ($style_height <= $height) {
|
||||
$cell_height += $top_space + $bottom_space;
|
||||
}
|
||||
|
||||
foreach ($cells["rows"] as $i)
|
||||
foreach ($cells["rows"] as $i) {
|
||||
$cellmap->set_row_height($i, $cell_height);
|
||||
}
|
||||
|
||||
$style->height = $height;
|
||||
|
||||
$this->_text_align();
|
||||
|
||||
$this->vertical_align();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,36 +19,42 @@ use Dompdf\Exception;
|
||||
*/
|
||||
class TableRow extends AbstractFrameReflower
|
||||
{
|
||||
/**
|
||||
* TableRow constructor.
|
||||
* @param TableRowFrameDecorator $frame
|
||||
*/
|
||||
function __construct(TableRowFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
$page = $this->_frame->get_root();
|
||||
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_frame->position();
|
||||
$style = $this->_frame->get_style();
|
||||
$cb = $this->_frame->get_containing_block();
|
||||
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$child->set_containing_block($cb);
|
||||
$child->reflow();
|
||||
|
||||
}
|
||||
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table = TableFrameDecorator::find_parent_table($this->_frame);
|
||||
$cellmap = $table->get_cellmap();
|
||||
@ -56,11 +62,11 @@ class TableRow extends AbstractFrameReflower
|
||||
$style->height = $cellmap->get_frame_height($this->_frame);
|
||||
|
||||
$this->_frame->set_position($cellmap->get_frame_position($this->_frame));
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
function get_min_max_width()
|
||||
{
|
||||
throw new Exception("Min/max width is undefined for table rows");
|
||||
|
@ -18,11 +18,18 @@ use Dompdf\FrameDecorator\Table as TableFrameDecorator;
|
||||
class TableRowGroup extends AbstractFrameReflower
|
||||
{
|
||||
|
||||
/**
|
||||
* TableRowGroup constructor.
|
||||
* @param \Dompdf\Frame $frame
|
||||
*/
|
||||
function __construct($frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
$page = $this->_frame->get_root();
|
||||
@ -36,19 +43,20 @@ class TableRowGroup extends AbstractFrameReflower
|
||||
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
// Bail if the page is full
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$child->set_containing_block($cb["x"], $cb["y"], $cb["w"], $cb["h"]);
|
||||
$child->reflow();
|
||||
|
||||
// Check if a split has occured
|
||||
$page->check_page_break($child);
|
||||
|
||||
}
|
||||
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cellmap = $table->get_cellmap();
|
||||
$style->width = $cellmap->get_frame_width($this->_frame);
|
||||
@ -56,10 +64,9 @@ class TableRowGroup extends AbstractFrameReflower
|
||||
|
||||
$this->_frame->set_position($cellmap->get_frame_position($this->_frame));
|
||||
|
||||
if ($table->get_style()->border_collapse === "collapse")
|
||||
if ($table->get_style()->border_collapse === "collapse") {
|
||||
// Unset our borders because our cells are now using them
|
||||
$style->border_style = "none";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
115
library/vendor/dompdf/src/FrameReflower/Text.php
vendored
115
library/vendor/dompdf/src/FrameReflower/Text.php
vendored
@ -11,6 +11,7 @@ namespace Dompdf\FrameReflower;
|
||||
use Dompdf\FrameDecorator\Block as BlockFrameDecorator;
|
||||
use Dompdf\FrameDecorator\Text as TextFrameDecorator;
|
||||
use Dompdf\FontMetrics;
|
||||
use Dompdf\Helpers;
|
||||
|
||||
/**
|
||||
* Reflows text frames.
|
||||
@ -47,8 +48,10 @@ class Text extends AbstractFrameReflower
|
||||
$this->setFontMetrics($fontMetrics);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _collapse_white_space($text)
|
||||
{
|
||||
//$text = $this->_frame->get_text();
|
||||
@ -57,8 +60,10 @@ class Text extends AbstractFrameReflower
|
||||
return preg_replace(self::$_whitespace_pattern, " ", $text);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
* @return bool|int
|
||||
*/
|
||||
protected function _line_break($text)
|
||||
{
|
||||
$style = $this->_frame->get_style();
|
||||
@ -73,13 +78,13 @@ class Text extends AbstractFrameReflower
|
||||
$available_width = $line_width - $current_line_width;
|
||||
|
||||
// Account for word-spacing
|
||||
$word_spacing = $style->length_in_pt($style->word_spacing);
|
||||
$char_spacing = $style->length_in_pt($style->letter_spacing);
|
||||
$word_spacing = (float)$style->length_in_pt($style->word_spacing);
|
||||
$char_spacing = (float)$style->length_in_pt($style->letter_spacing);
|
||||
|
||||
// Determine the frame width including margin, padding & border
|
||||
$text_width = $this->getFontMetrics()->getTextWidth($text, $font, $size, $word_spacing, $char_spacing);
|
||||
$mbp_width =
|
||||
$style->length_in_pt(array($style->margin_left,
|
||||
(float)$style->length_in_pt(array($style->margin_left,
|
||||
$style->border_left_width,
|
||||
$style->padding_left,
|
||||
$style->padding_right,
|
||||
@ -99,8 +104,9 @@ class Text extends AbstractFrameReflower
|
||||
|
||||
// Helpers::pre_r($words);
|
||||
|
||||
if ($frame_width <= $available_width)
|
||||
if ($frame_width <= $available_width) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// split the text into words
|
||||
$words = preg_split('/([\s-]+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
@ -115,8 +121,9 @@ class Text extends AbstractFrameReflower
|
||||
for ($i = 0; $i < $wc; $i += 2) {
|
||||
$word = $words[$i] . (isset($words[$i + 1]) ? $words[$i + 1] : "");
|
||||
$word_width = $this->getFontMetrics()->getTextWidth($word, $font, $size, $word_spacing, $char_spacing);
|
||||
if ($width + $word_width + $mbp_width > $available_width)
|
||||
if ($width + $word_width + $mbp_width > $available_width) {
|
||||
break;
|
||||
}
|
||||
|
||||
$width += $word_width;
|
||||
$str .= $word;
|
||||
@ -126,7 +133,6 @@ class Text extends AbstractFrameReflower
|
||||
|
||||
// The first word has overflowed. Force it onto the line
|
||||
if ($current_line_width == 0 && $width == 0) {
|
||||
|
||||
$s = "";
|
||||
$last_width = 0;
|
||||
|
||||
@ -143,39 +149,42 @@ class Text extends AbstractFrameReflower
|
||||
}
|
||||
|
||||
if ($break_word && $last_width > 0) {
|
||||
$width += $last_width;
|
||||
//$width += $last_width;
|
||||
$str .= substr($s, 0, -1);
|
||||
} else {
|
||||
$width += $word_width;
|
||||
//$width += $word_width;
|
||||
$str .= $word;
|
||||
}
|
||||
}
|
||||
|
||||
$offset = mb_strlen($str);
|
||||
|
||||
// More debugging:
|
||||
// var_dump($str);
|
||||
// print_r("Width: ". $width);
|
||||
// print_r("Offset: " . $offset);
|
||||
// More debugging:
|
||||
// var_dump($str);
|
||||
// print_r("Width: ". $width);
|
||||
// print_r("Offset: " . $offset);
|
||||
|
||||
return $offset;
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
* @return bool|int
|
||||
*/
|
||||
protected function _newline_break($text)
|
||||
{
|
||||
|
||||
if (($i = mb_strpos($text, "\n")) === false)
|
||||
if (($i = mb_strpos($text, "\n")) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $i + 1;
|
||||
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function _layout_line()
|
||||
{
|
||||
$frame = $this->_frame;
|
||||
@ -196,7 +205,7 @@ class Text extends AbstractFrameReflower
|
||||
default:
|
||||
break;
|
||||
case "capitalize":
|
||||
$text = mb_convert_case($text, MB_CASE_TITLE);
|
||||
$text = Helpers::mb_ucwords($text);
|
||||
break;
|
||||
case "uppercase":
|
||||
$text = mb_convert_case($text, MB_CASE_UPPER);
|
||||
@ -209,12 +218,12 @@ class Text extends AbstractFrameReflower
|
||||
// Handle white-space property:
|
||||
// http://www.w3.org/TR/CSS21/text.html#propdef-white-space
|
||||
switch ($style->white_space) {
|
||||
|
||||
default:
|
||||
case "normal":
|
||||
$frame->set_text($text = $this->_collapse_white_space($text));
|
||||
if ($text == "")
|
||||
if ($text == "") {
|
||||
break;
|
||||
}
|
||||
|
||||
$split = $this->_line_break($text);
|
||||
break;
|
||||
@ -243,27 +252,29 @@ class Text extends AbstractFrameReflower
|
||||
// Collapse white-space except for \n
|
||||
$frame->set_text($text = preg_replace("/[ \t]+/u", " ", $text));
|
||||
|
||||
if ($text == "")
|
||||
if ($text == "") {
|
||||
break;
|
||||
}
|
||||
|
||||
$split = $this->_newline_break($text);
|
||||
|
||||
if (($tmp = $this->_line_break($text)) !== false) {
|
||||
$add_line = $split < $tmp;
|
||||
$split = min($tmp, $split);
|
||||
} else
|
||||
} else {
|
||||
$add_line = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Handle degenerate case
|
||||
if ($text === "")
|
||||
if ($text === "") {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($split !== false) {
|
||||
|
||||
// Handle edge cases
|
||||
if ($split == 0 && $text === " ") {
|
||||
$frame->set_text("");
|
||||
@ -271,16 +282,15 @@ class Text extends AbstractFrameReflower
|
||||
}
|
||||
|
||||
if ($split == 0) {
|
||||
|
||||
// Trim newlines from the beginning of the line
|
||||
//$this->_frame->set_text(ltrim($text, "\n\r"));
|
||||
|
||||
$this->_block_parent->maximize_line_height($style->height, $frame);
|
||||
$this->_block_parent->add_line();
|
||||
$frame->position();
|
||||
|
||||
// Layout the new line
|
||||
$this->_layout_line();
|
||||
|
||||
} else if ($split < mb_strlen($frame->get_text())) {
|
||||
// split the line if required
|
||||
$frame->split_text($split);
|
||||
@ -288,8 +298,9 @@ class Text extends AbstractFrameReflower
|
||||
$t = $frame->get_text();
|
||||
|
||||
// Remove any trailing newlines
|
||||
if ($split > 1 && $t[$split - 1] === "\n" && !$frame->is_pre())
|
||||
if ($split > 1 && $t[$split - 1] === "\n" && !$frame->is_pre()) {
|
||||
$frame->set_text(mb_substr($t, 0, -1));
|
||||
}
|
||||
|
||||
// Do we need to trim spaces on wrapped lines? This might be desired, however, we
|
||||
// can't trim the lines here or the layout will be affected if trimming the line
|
||||
@ -305,49 +316,48 @@ class Text extends AbstractFrameReflower
|
||||
$this->_block_parent->add_line();
|
||||
$frame->position();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Remove empty space from start and end of line, but only where there isn't an inline sibling
|
||||
// and the parent node isn't an inline element with siblings
|
||||
// FIXME: Include non-breaking spaces?
|
||||
$t = $frame->get_text();
|
||||
$parent = $frame->get_parent();
|
||||
$is_inline_frame = get_class($parent) === 'Inline_Frame_Decorator';
|
||||
$is_inline_frame = ($parent instanceof \Dompdf\FrameDecorator\Inline);
|
||||
|
||||
if ((!$is_inline_frame && !$frame->get_next_sibling()) /* ||
|
||||
( $is_inline_frame && !$parent->get_next_sibling())*/
|
||||
( $is_inline_frame && !$parent->get_next_sibling())*/
|
||||
) { // fails <b>BOLD <u>UNDERLINED</u></b> becomes <b>BOLD<u>UNDERLINED</u></b>
|
||||
$t = rtrim($t);
|
||||
}
|
||||
|
||||
if ((!$is_inline_frame && !$frame->get_prev_sibling()) /* ||
|
||||
( $is_inline_frame && !$parent->get_prev_sibling())*/
|
||||
( $is_inline_frame && !$parent->get_prev_sibling())*/
|
||||
) { // <span><span>A<span>B</span> C</span></span> fails (the whitespace is removed)
|
||||
$t = ltrim($t);
|
||||
}
|
||||
|
||||
$frame->set_text($t);
|
||||
|
||||
}
|
||||
|
||||
// Set our new width
|
||||
$width = $frame->recalculate_width();
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
/**
|
||||
* @param BlockFrameDecorator|null $block
|
||||
*/
|
||||
function reflow(BlockFrameDecorator $block = null)
|
||||
{
|
||||
$frame = $this->_frame;
|
||||
$page = $frame->get_root();
|
||||
$page->check_forced_page_break($this->_frame);
|
||||
|
||||
if ($page->is_full())
|
||||
if ($page->is_full()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_block_parent = /*isset($block) ? $block : */
|
||||
$frame->find_block_parent();
|
||||
$frame->find_block_parent();
|
||||
|
||||
// Left trim the text if this is the first text on the line and we're
|
||||
// collapsing white space
|
||||
@ -383,11 +393,10 @@ class Text extends AbstractFrameReflower
|
||||
$size = $style->font_size;
|
||||
$font = $style->font_family;
|
||||
|
||||
$word_spacing = $style->length_in_pt($style->word_spacing);
|
||||
$char_spacing = $style->length_in_pt($style->letter_spacing);
|
||||
$word_spacing = (float)$style->length_in_pt($style->word_spacing);
|
||||
$char_spacing = (float)$style->length_in_pt($style->letter_spacing);
|
||||
|
||||
switch ($style->white_space) {
|
||||
|
||||
default:
|
||||
case "normal":
|
||||
$str = preg_replace(self::$_whitespace_pattern, " ", $str);
|
||||
@ -423,11 +432,9 @@ class Text extends AbstractFrameReflower
|
||||
case "nowrap":
|
||||
$min = $this->getFontMetrics()->getTextWidth($this->_collapse_white_space($str), $font, $size, $word_spacing, $char_spacing);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
switch ($style->white_space) {
|
||||
|
||||
default:
|
||||
case "normal":
|
||||
case "nowrap":
|
||||
@ -449,12 +456,11 @@ class Text extends AbstractFrameReflower
|
||||
reset($lines);
|
||||
$str = key($lines);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$max = $this->getFontMetrics()->getTextWidth($str, $font, $size, $word_spacing, $char_spacing);
|
||||
|
||||
$delta = $style->length_in_pt(array($style->margin_left,
|
||||
$delta = (float)$style->length_in_pt(array($style->margin_left,
|
||||
$style->border_left_width,
|
||||
$style->padding_left,
|
||||
$style->padding_right,
|
||||
@ -464,7 +470,6 @@ class Text extends AbstractFrameReflower
|
||||
$max += $delta;
|
||||
|
||||
return $this->_min_max_cache = array($min, $max, "min" => $min, "max" => $max);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -484,4 +489,14 @@ class Text extends AbstractFrameReflower
|
||||
{
|
||||
return $this->fontMetrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine current frame width based on contents
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function calculate_auto_width()
|
||||
{
|
||||
return $this->_frame->recalculate_width();
|
||||
}
|
||||
}
|
||||
|
185
library/vendor/dompdf/src/Helpers.php
vendored
185
library/vendor/dompdf/src/Helpers.php
vendored
@ -12,7 +12,7 @@ class Helpers
|
||||
* @param mixed $mixed variable or expression to display
|
||||
* @param bool $return
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public static function pre_r($mixed, $return = false)
|
||||
{
|
||||
@ -33,6 +33,8 @@ class Helpers
|
||||
}
|
||||
|
||||
flush();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,7 +74,7 @@ class Helpers
|
||||
//drive: followed by a relative path would be a drive specific default folder.
|
||||
//not known in php app code, treat as abs path
|
||||
//($url[1] !== ':' || ($url[2]!=='\\' && $url[2]!=='/'))
|
||||
if ($url[0] !== '/' && (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' || ($url[0] !== '\\' && $url[1] !== ':'))) {
|
||||
if ($url[0] !== '/' && (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' || (mb_strlen($url) > 1 && $url[0] !== '\\' && $url[1] !== ':'))) {
|
||||
// For rel path and local acess we ignore the host, and run the path through realpath()
|
||||
$ret .= realpath($base_path) . '/';
|
||||
}
|
||||
@ -97,6 +99,33 @@ class Helpers
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a HTTP Content-Disposition header string using `$dispositionType`
|
||||
* and `$filename`.
|
||||
*
|
||||
* If the filename contains any characters not in the ISO-8859-1 character
|
||||
* set, a fallback filename will be included for clients not supporting the
|
||||
* `filename*` parameter.
|
||||
*
|
||||
* @param string $dispositionType
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
public static function buildContentDispositionHeader($dispositionType, $filename)
|
||||
{
|
||||
$encoding = mb_detect_encoding($filename);
|
||||
$fallbackfilename = mb_convert_encoding($filename, "ISO-8859-1", $encoding);
|
||||
$fallbackfilename = str_replace("\"", "", $fallbackfilename);
|
||||
$encodedfilename = rawurlencode($filename);
|
||||
|
||||
$contentDisposition = "Content-Disposition: $dispositionType; filename=\"$fallbackfilename\"";
|
||||
if ($fallbackfilename !== $filename) {
|
||||
$contentDisposition .= "; filename*=UTF-8''$encodedfilename";
|
||||
}
|
||||
|
||||
return $contentDisposition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts decimal numbers to roman numerals
|
||||
*
|
||||
@ -125,12 +154,16 @@ class Helpers
|
||||
|
||||
$ret = "";
|
||||
switch (mb_strlen($num)) {
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 4:
|
||||
$ret .= $thou[$num[3]];
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 3:
|
||||
$ret .= $hund[$num[2]];
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 2:
|
||||
$ret .= $tens[$num[1]];
|
||||
/** @noinspection PhpMissingBreakStatementInspection */
|
||||
case 1:
|
||||
$ret .= $ones[$num[0]];
|
||||
default:
|
||||
@ -158,7 +191,7 @@ class Helpers
|
||||
*
|
||||
* @param string $data_uri The data URI to parse
|
||||
*
|
||||
* @return array The result with charset, mime type and decoded data
|
||||
* @return array|bool The result with charset, mime type and decoded data
|
||||
*/
|
||||
public static function parse_data_uri($data_uri)
|
||||
{
|
||||
@ -176,6 +209,37 @@ class Helpers
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a Uniform Resource Identifier (URI) by replacing non-alphanumeric
|
||||
* characters with a percent (%) sign followed by two hex digits, excepting
|
||||
* characters in the URI reserved character set.
|
||||
*
|
||||
* Assumes that the URI is a complete URI, so does not encode reserved
|
||||
* characters that have special meaning in the URI.
|
||||
*
|
||||
* Simulates the encodeURI function available in JavaScript
|
||||
* https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURI
|
||||
*
|
||||
* Source: http://stackoverflow.com/q/4929584/264628
|
||||
*
|
||||
* @param string $uri The URI to encode
|
||||
* @return string The original URL with special characters encoded
|
||||
*/
|
||||
public static function encodeURI($uri) {
|
||||
$unescaped = array(
|
||||
'%2D'=>'-','%5F'=>'_','%2E'=>'.','%21'=>'!', '%7E'=>'~',
|
||||
'%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')'
|
||||
);
|
||||
$reserved = array(
|
||||
'%3B'=>';','%2C'=>',','%2F'=>'/','%3F'=>'?','%3A'=>':',
|
||||
'%40'=>'@','%26'=>'&','%3D'=>'=','%2B'=>'+','%24'=>'$'
|
||||
);
|
||||
$score = array(
|
||||
'%23'=>'#'
|
||||
);
|
||||
return strtr(rawurlencode(rawurldecode($uri)), array_merge($reserved,$unescaped,$score));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decoder for RLE8 compression in windows bitmaps
|
||||
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
|
||||
@ -199,20 +263,27 @@ class Helpers
|
||||
switch (ord($str[$i])) {
|
||||
case 0: # NEW LINE
|
||||
$padCnt = $lineWidth - strlen($out) % $lineWidth;
|
||||
if ($padCnt < $lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line
|
||||
if ($padCnt < $lineWidth) {
|
||||
$out .= str_repeat(chr(0), $padCnt); # pad line
|
||||
}
|
||||
break;
|
||||
case 1: # END OF FILE
|
||||
$padCnt = $lineWidth - strlen($out) % $lineWidth;
|
||||
if ($padCnt < $lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line
|
||||
if ($padCnt < $lineWidth) {
|
||||
$out .= str_repeat(chr(0), $padCnt); # pad line
|
||||
}
|
||||
break 3;
|
||||
case 2: # DELTA
|
||||
$i += 2;
|
||||
break;
|
||||
default: # ABSOLUTE MODE
|
||||
$num = ord($str[$i]);
|
||||
for ($j = 0; $j < $num; $j++)
|
||||
for ($j = 0; $j < $num; $j++) {
|
||||
$out .= $str[++$i];
|
||||
if ($num % 2) $i++;
|
||||
}
|
||||
if ($num % 2) {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -492,9 +563,15 @@ class Helpers
|
||||
$g = (1 - round(2.55 * ($m + $k)));
|
||||
$b = (1 - round(2.55 * ($y + $k)));
|
||||
|
||||
if ($r < 0) $r = 0;
|
||||
if ($g < 0) $g = 0;
|
||||
if ($b < 0) $b = 0;
|
||||
if ($r < 0) {
|
||||
$r = 0;
|
||||
}
|
||||
if ($g < 0) {
|
||||
$g = 0;
|
||||
}
|
||||
if ($b < 0) {
|
||||
$b = 0;
|
||||
}
|
||||
|
||||
return array(
|
||||
$r, $g, $b,
|
||||
@ -529,7 +606,7 @@ class Helpers
|
||||
$type = isset($types[$type]) ? $types[$type] : null;
|
||||
|
||||
if ($width == null || $height == null) {
|
||||
$data = file_get_contents($filename, null, $context, 0, 26);
|
||||
list($data, $headers) = Helpers::getFileContent($filename, $context);
|
||||
|
||||
if (substr($data, 0, 2) === "BM") {
|
||||
$meta = unpack('vtype/Vfilesize/Vreserved/Voffset/Vheadersize/Vwidth/Vheight', $data);
|
||||
@ -538,7 +615,7 @@ class Helpers
|
||||
$type = "bmp";
|
||||
}
|
||||
else {
|
||||
if (strpos(file_get_contents($filename), "<svg") !== false) {
|
||||
if (strpos($data, "<svg") !== false) {
|
||||
$doc = new \Svg\Document();
|
||||
$doc->loadFile($filename);
|
||||
|
||||
@ -730,4 +807,88 @@ class Helpers
|
||||
return $im;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content of the file at the specified path using one of
|
||||
* the following methods, in preferential order:
|
||||
* - file_get_contents: if allow_url_fopen is true or the file is local
|
||||
* - curl: if allow_url_fopen is false and curl is available
|
||||
*
|
||||
* @param string $uri
|
||||
* @param resource $context (ignored if curl is used)
|
||||
* @param int $offset
|
||||
* @param int $maxlen (ignored if curl is used)
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function getFileContent($uri, $context = null, $offset = 0, $maxlen = null)
|
||||
{
|
||||
$result = false;
|
||||
$headers = null;
|
||||
list($proto, $host, $path, $file) = Helpers::explode_url($uri);
|
||||
$is_local_path = ($proto == "" || $proto === "file://");
|
||||
|
||||
set_error_handler(array("\\Dompdf\\Helpers", "record_warnings"));
|
||||
|
||||
if ($is_local_path || ini_get("allow_url_fopen")) {
|
||||
if ($is_local_path === false) {
|
||||
$uri = Helpers::encodeURI($uri);
|
||||
}
|
||||
if (isset($maxlen)) {
|
||||
$result = file_get_contents($uri, null, $context, $offset, $maxlen);
|
||||
} else {
|
||||
$result = file_get_contents($uri, null, $context, $offset);
|
||||
}
|
||||
if (isset($http_response_header)) {
|
||||
$headers = $http_response_header;
|
||||
}
|
||||
|
||||
} elseif (function_exists("curl_exec")) {
|
||||
$curl = curl_init($uri);
|
||||
|
||||
//TODO: use $context to define additional curl options
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
if ($offset > 0) {
|
||||
curl_setopt($curl, CURLOPT_RESUME_FROM, $offset);
|
||||
}
|
||||
|
||||
$data = curl_exec($curl);
|
||||
$raw_headers = substr($data, 0, curl_getinfo($curl, CURLINFO_HEADER_SIZE));
|
||||
$headers = preg_split("/[\n\r]+/", trim($raw_headers));
|
||||
$result = substr($data, curl_getinfo($curl, CURLINFO_HEADER_SIZE));
|
||||
curl_close($curl);
|
||||
}
|
||||
|
||||
restore_error_handler();
|
||||
|
||||
return array($result, $headers);
|
||||
}
|
||||
|
||||
public static function mb_ucwords($str) {
|
||||
$max_len = mb_strlen($str);
|
||||
if ($max_len === 1) {
|
||||
return mb_strtoupper($str);
|
||||
}
|
||||
|
||||
$str = mb_strtoupper(mb_substr($str, 0, 1)) . mb_substr($str, 1);
|
||||
|
||||
foreach (array(' ', '.', ',', '!', '?', '-', '+') as $s) {
|
||||
$pos = 0;
|
||||
while (($pos = mb_strpos($str, $s, $pos)) !== false) {
|
||||
$pos++;
|
||||
// Nothing to do if the separator is the last char of the string
|
||||
if ($pos !== false && $pos < $max_len) {
|
||||
// If the char we want to upper is the last char there is nothing to append behind
|
||||
if ($pos + 1 < $max_len) {
|
||||
$str = mb_substr($str, 0, $pos) . mb_strtoupper(mb_substr($str, $pos, 1)) . mb_substr($str, $pos + 1);
|
||||
} else {
|
||||
$str = mb_substr($str, 0, $pos) . mb_strtoupper(mb_substr($str, $pos, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
16
library/vendor/dompdf/src/Image/Cache.php
vendored
16
library/vendor/dompdf/src/Image/Cache.php
vendored
@ -35,6 +35,8 @@ class Cache
|
||||
* @var string
|
||||
*/
|
||||
public static $broken_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAAAA3NCSVQICAjb4U/gAAAAHlBMVEWZmZn////g4OCkpKS1tbXv7++9vb2tra3m5ub5+fkFnN6oAAAACXBIWXMAAAsSAAALEgHS3X78AAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M0BrLToAAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNC8xMi8xMRPnI58AAAGZSURBVEiJhZbPasMwDMbTw2DHKhDQcbDQPsEge4BAjg0Mxh5gkBcY7Niwkpx32PvOjv9JspX60It/+fxJsqxW1b11gN11rA7N3v6vAd5nfR9fDYCTDiyzAeA6qgKd9QDNoAtsAKyKCxzAAfhdBuyHGwC3oovNvQOaxxJwnSNg3ZQFAlBy4ax7AG6ZBLrgA5Cn038SAPgREiaJHJASwXYEhEQQIACyikTTCWCBJJoANBfpPAKQdBLHFMBYkctcBKIE9lAGggt6gRjgA2GV44CL7m1WgS08fAAdsPHxyyMAIyHujgRwEldHArCKy5cBz90+gNOyf8TTyKOUQN2LPEmgnWWPcKD+sr+rnuqTK1avAcHfRSv3afTgVAbqmCPiggLtGM8aSkBNOidVjADrmIDYebT1PoGsWJEE8Oc0b96aZoe4iMBZPiADB6RAzEUA2vwRmyiAL3Lfv6MBSEmUEg7ALt/3LhxwLgj4QNw4UCbKEsaBNpPsyRbgVRASFig78BIGyJNIJQyQTwIi0RvgT98H+Mi6W67j3X8H/427u5bfpQGVAAAAAElFTkSuQmCC";
|
||||
|
||||
public static $error_message = "Image not found or type unknown";
|
||||
|
||||
/**
|
||||
* Current dompdf instance
|
||||
@ -67,7 +69,7 @@ class Cache
|
||||
|
||||
$data_uri = strpos($parsed_url['protocol'], "data:") === 0;
|
||||
$full_url = null;
|
||||
$enable_remote = $dompdf->get_option("enable_remote");
|
||||
$enable_remote = $dompdf->getOptions()->getIsRemoteEnabled();
|
||||
|
||||
try {
|
||||
|
||||
@ -85,7 +87,7 @@ class Cache
|
||||
$resolved_url = self::$_cache[$full_url];
|
||||
} // From remote
|
||||
else {
|
||||
$tmp_dir = $dompdf->get_option("temp_dir");
|
||||
$tmp_dir = $dompdf->getOptions()->getTempDir();
|
||||
$resolved_url = tempnam($tmp_dir, "ca_dompdf_img_");
|
||||
$image = "";
|
||||
|
||||
@ -94,9 +96,7 @@ class Cache
|
||||
$image = $parsed_data_uri['data'];
|
||||
}
|
||||
} else {
|
||||
set_error_handler(array("\\Dompdf\\Helpers", "record_warnings"));
|
||||
$image = file_get_contents($full_url, null, $dompdf->getHttpContext());
|
||||
restore_error_handler();
|
||||
list($image, $http_response_header) = Helpers::getFileContent($full_url, $dompdf->getHttpContext());
|
||||
}
|
||||
|
||||
// Image not found or invalid
|
||||
@ -141,7 +141,7 @@ class Cache
|
||||
} catch (ImageException $e) {
|
||||
$resolved_url = self::$broken_image;
|
||||
$type = "png";
|
||||
$message = "Image not found or type unknown";
|
||||
$message = self::$error_message;
|
||||
Helpers::record_warnings($e->getCode(), $e->getMessage() . " \n $url", $e->getFile(), $e->getLine());
|
||||
}
|
||||
|
||||
@ -154,12 +154,12 @@ class Cache
|
||||
*/
|
||||
static function clear()
|
||||
{
|
||||
if (empty(self::$_cache) || self::$_dompdf->get_option("debugKeepTemp")) {
|
||||
if (empty(self::$_cache) || self::$_dompdf->getOptions()->getDebugKeepTemp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (self::$_cache as $file) {
|
||||
if (self::$_dompdf->get_option("debugPng")) {
|
||||
if (self::$_dompdf->getOptions()->getDebugPng()) {
|
||||
print "[clear unlink $file]";
|
||||
}
|
||||
unlink($file);
|
||||
|
23
library/vendor/dompdf/src/JavascriptEmbedder.php
vendored
23
library/vendor/dompdf/src/JavascriptEmbedder.php
vendored
@ -7,8 +7,6 @@
|
||||
*/
|
||||
namespace Dompdf;
|
||||
|
||||
use Dompdf\Frame;
|
||||
|
||||
/**
|
||||
* Embeds Javascript into the PDF document
|
||||
*
|
||||
@ -22,19 +20,30 @@ class JavascriptEmbedder
|
||||
*/
|
||||
protected $_dompdf;
|
||||
|
||||
function __construct(Dompdf $dompdf)
|
||||
/**
|
||||
* JavascriptEmbedder constructor.
|
||||
*
|
||||
* @param Dompdf $dompdf
|
||||
*/
|
||||
public function __construct(Dompdf $dompdf)
|
||||
{
|
||||
$this->_dompdf = $dompdf;
|
||||
}
|
||||
|
||||
function insert($script)
|
||||
/**
|
||||
* @param $script
|
||||
*/
|
||||
public function insert($script)
|
||||
{
|
||||
$this->_dompdf->get_canvas()->javascript($script);
|
||||
$this->_dompdf->getCanvas()->javascript($script);
|
||||
}
|
||||
|
||||
function render(Frame $frame)
|
||||
/**
|
||||
* @param Frame $frame
|
||||
*/
|
||||
public function render(Frame $frame)
|
||||
{
|
||||
if (!$this->_dompdf->get_option("enable_javascript")) {
|
||||
if (!$this->_dompdf->getOptions()->getIsJavascriptEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
81
library/vendor/dompdf/src/LineBox.php
vendored
81
library/vendor/dompdf/src/LineBox.php
vendored
@ -7,7 +7,6 @@
|
||||
*/
|
||||
namespace Dompdf;
|
||||
|
||||
use Dompdf\Frame;
|
||||
use Dompdf\FrameDecorator\Block;
|
||||
use Dompdf\FrameDecorator\Page;
|
||||
|
||||
@ -81,8 +80,9 @@ class LineBox
|
||||
* Class constructor
|
||||
*
|
||||
* @param Block $frame the Block containing this line
|
||||
* @param int $y
|
||||
*/
|
||||
function __construct(Block $frame, $y = 0)
|
||||
public function __construct(Block $frame, $y = 0)
|
||||
{
|
||||
$this->_block_frame = $frame;
|
||||
$this->_frames = array();
|
||||
@ -98,7 +98,7 @@ class LineBox
|
||||
*
|
||||
* @return Frame[]
|
||||
*/
|
||||
function get_floats_inside(Page $root)
|
||||
public function get_floats_inside(Page $root)
|
||||
{
|
||||
$floating_frames = $root->get_floating_frames();
|
||||
|
||||
@ -129,7 +129,7 @@ class LineBox
|
||||
foreach ($floating_frames as $_floating) {
|
||||
$p = $_floating->get_parent();
|
||||
|
||||
while (($p = $p->get_parent()) && $p !== $parent) ;
|
||||
while (($p = $p->get_parent()) && $p !== $parent);
|
||||
|
||||
if ($p) {
|
||||
$childs[] = $p;
|
||||
@ -139,9 +139,12 @@ class LineBox
|
||||
return $childs;
|
||||
}
|
||||
|
||||
function get_float_offsets()
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function get_float_offsets()
|
||||
{
|
||||
static $anti_infinite_loop = 500; // FIXME smelly hack
|
||||
static $anti_infinite_loop = 10000; // FIXME smelly hack
|
||||
|
||||
$reflower = $this->_block_frame->get_reflower();
|
||||
|
||||
@ -158,18 +161,22 @@ class LineBox
|
||||
return;
|
||||
}
|
||||
|
||||
$style = $this->_block_frame->get_style();
|
||||
$floating_frames = $this->get_floats_inside($root);
|
||||
$inside_left_floating_width = 0;
|
||||
$inside_right_floating_width = 0;
|
||||
$outside_left_floating_width = 0;
|
||||
$outside_right_floating_width = 0;
|
||||
|
||||
foreach ($floating_frames as $child_key => $floating_frame) {
|
||||
$floating_frame_parent = $floating_frame->get_parent();
|
||||
$id = $floating_frame->get_id();
|
||||
|
||||
if (isset($this->floating_blocks[$id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$floating_style = $floating_frame->get_style();
|
||||
$float = $floating_style->float;
|
||||
|
||||
$float = $floating_frame->get_style()->float;
|
||||
$floating_width = $floating_frame->get_margin_width();
|
||||
|
||||
if (!$cb_w) {
|
||||
@ -185,13 +192,21 @@ class LineBox
|
||||
|
||||
// If the child is still shifted by the floating element
|
||||
if ($anti_infinite_loop-- > 0 &&
|
||||
$floating_frame->get_position("y") + $floating_frame->get_margin_height() > $this->y &&
|
||||
$block->get_position("x") + $block->get_margin_width() > $floating_frame->get_position("x")
|
||||
$floating_frame->get_position("y") + $floating_frame->get_margin_height() >= $this->y &&
|
||||
$block->get_position("x") + $block->get_margin_width() >= $floating_frame->get_position("x")
|
||||
) {
|
||||
if ($float === "left") {
|
||||
$this->left += $floating_width;
|
||||
} else {
|
||||
$this->right += $floating_width;
|
||||
if ($floating_frame_parent === $this->_block_frame) {
|
||||
$inside_left_floating_width += $floating_width;
|
||||
} else {
|
||||
$outside_left_floating_width += $floating_width;
|
||||
}
|
||||
} elseif ($float === "right") {
|
||||
if ($floating_frame_parent === $this->_block_frame) {
|
||||
$inside_right_floating_width += $floating_width;
|
||||
} else {
|
||||
$outside_right_floating_width += $floating_width;
|
||||
}
|
||||
}
|
||||
|
||||
$this->floating_blocks[$id] = true;
|
||||
@ -200,12 +215,21 @@ class LineBox
|
||||
$root->remove_floating_frame($child_key);
|
||||
}
|
||||
}
|
||||
|
||||
$this->left += $inside_left_floating_width;
|
||||
if ($outside_left_floating_width > 0 && $outside_left_floating_width > ((float)$style->length_in_pt($style->margin_left) + (float)$style->length_in_pt($style->padding_left))) {
|
||||
$this->left += $outside_left_floating_width - (float)$style->length_in_pt($style->margin_left) - (float)$style->length_in_pt($style->padding_left);
|
||||
}
|
||||
$this->right += $inside_right_floating_width;
|
||||
if ($outside_right_floating_width > 0 && $outside_right_floating_width > ((float)$style->length_in_pt($style->margin_left) + (float)$style->length_in_pt($style->padding_right))) {
|
||||
$this->right += $outside_right_floating_width - (float)$style->length_in_pt($style->margin_right) - (float)$style->length_in_pt($style->padding_right);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
function get_width()
|
||||
public function get_width()
|
||||
{
|
||||
return $this->left + $this->w + $this->right;
|
||||
}
|
||||
@ -213,7 +237,7 @@ class LineBox
|
||||
/**
|
||||
* @return Block
|
||||
*/
|
||||
function get_block_frame()
|
||||
public function get_block_frame()
|
||||
{
|
||||
return $this->_block_frame;
|
||||
}
|
||||
@ -229,12 +253,31 @@ class LineBox
|
||||
/**
|
||||
* @param Frame $frame
|
||||
*/
|
||||
function add_frame(Frame $frame)
|
||||
public function add_frame(Frame $frame)
|
||||
{
|
||||
$this->_frames[] = $frame;
|
||||
}
|
||||
|
||||
function __toString()
|
||||
/**
|
||||
* Recalculate LineBox width based on the contained frames total width.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function recalculate_width()
|
||||
{
|
||||
$width = 0;
|
||||
|
||||
foreach ($this->get_frames() as $frame) {
|
||||
$width += $frame->calculate_auto_width();
|
||||
}
|
||||
|
||||
return $this->w = $width;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$props = array("wc", "y", "w", "h", "left", "right", "br");
|
||||
$s = "";
|
||||
@ -255,6 +298,6 @@ class LineBox
|
||||
class LineBoxList implements Iterator {
|
||||
private $_p = 0;
|
||||
private $_lines = array();
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
|
57
library/vendor/dompdf/src/Options.php
vendored
57
library/vendor/dompdf/src/Options.php
vendored
@ -36,7 +36,7 @@ class Options
|
||||
*
|
||||
* This directory contains the cached font metrics for the fonts used by DOMPDF.
|
||||
* This directory can be the same as $fontDir
|
||||
*
|
||||
*
|
||||
* Note: This directory must exist and be writable by the webserver process.
|
||||
*
|
||||
* @var string
|
||||
@ -52,7 +52,7 @@ class Options
|
||||
* read any files on the server. This should be an absolute path.
|
||||
*
|
||||
* ==== IMPORTANT ====
|
||||
* This setting may increase the risk of system exploit. Do not change
|
||||
* This setting may increase the risk of system exploit. Do not change
|
||||
* this settings without understanding the consequences. Additional
|
||||
* documentation is available on the dompdf wiki at:
|
||||
* https://github.com/dompdf/dompdf/wiki
|
||||
@ -84,12 +84,21 @@ class Options
|
||||
* The default paper size.
|
||||
*
|
||||
* North America standard is "letter"; other countries generally "a4"
|
||||
* @see Dompdf\Adapter\CPDF::PAPER_SIZES for valid sizes
|
||||
* @see \Dompdf\Adapter\CPDF::PAPER_SIZES for valid sizes
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $defaultPaperSize = "letter";
|
||||
|
||||
/**
|
||||
* The default paper orientation.
|
||||
*
|
||||
* The orientation of the page (portrait or landscape).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $defaultPaperOrientation = "portrait";
|
||||
|
||||
/**
|
||||
* The default font family
|
||||
*
|
||||
@ -141,7 +150,7 @@ class Options
|
||||
* system access available to dompdf. Set this option to false (recommended)
|
||||
* if you wish to process untrusted documents.
|
||||
*
|
||||
* This setting may increase the risk of system exploit. Do not change
|
||||
* This setting may increase the risk of system exploit. Do not change
|
||||
* this settings without understanding the consequences. Additional
|
||||
* documentation is available on the dompdf wiki at:
|
||||
* https://github.com/dompdf/dompdf/wiki
|
||||
@ -163,7 +172,7 @@ class Options
|
||||
* tracing back appears to being downloaded by your server, or allows malicious php code
|
||||
* in remote html pages to be executed by your server with your account privileges.
|
||||
*
|
||||
* This setting may increase the risk of system exploit. Do not change
|
||||
* This setting may increase the risk of system exploit. Do not change
|
||||
* this settings without understanding the consequences. Additional
|
||||
* documentation is available on the dompdf wiki at:
|
||||
* https://github.com/dompdf/dompdf/wiki
|
||||
@ -192,7 +201,7 @@ class Options
|
||||
/**
|
||||
* Whether to enable font subsetting or not.
|
||||
*
|
||||
* @var is_bool
|
||||
* @var bool
|
||||
*/
|
||||
private $isFontSubsettingEnabled = false;
|
||||
|
||||
@ -239,16 +248,16 @@ class Options
|
||||
/**
|
||||
* The PDF rendering backend to use
|
||||
*
|
||||
* Valid settings are 'PDFLib', 'CPDF', 'GD', and 'auto'. 'auto' will
|
||||
* look for PDFLib and use it if found, or if not it will fall back on
|
||||
* CPDF. 'GD' renders PDFs to graphic files. {@link Dompdf\CanvasFactory}
|
||||
* Valid settings are 'PDFLib', 'CPDF', 'GD', and 'auto'. 'auto' will
|
||||
* look for PDFLib and use it if found, or if not it will fall back on
|
||||
* CPDF. 'GD' renders PDFs to graphic files. {@link Dompdf\CanvasFactory}
|
||||
* ultimately determines which rendering class to instantiate
|
||||
* based on this setting.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $pdfBackend = "CPDF";
|
||||
|
||||
|
||||
/**
|
||||
* PDFlib license key
|
||||
*
|
||||
@ -264,7 +273,7 @@ class Options
|
||||
* @var string
|
||||
*/
|
||||
private $pdflibLicense = "";
|
||||
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @deprecated
|
||||
@ -319,6 +328,8 @@ class Options
|
||||
$this->setDefaultMediaType($value);
|
||||
} elseif ($key === 'defaultPaperSize' || $key === 'default_paper_size') {
|
||||
$this->setDefaultPaperSize($value);
|
||||
} elseif ($key === 'defaultPaperOrientation' || $key === 'default_paper_orientation') {
|
||||
$this->setDefaultPaperOrientation($value);
|
||||
} elseif ($key === 'defaultFont' || $key === 'default_font') {
|
||||
$this->setDefaultFont($value);
|
||||
} elseif ($key === 'dpi') {
|
||||
@ -384,6 +395,8 @@ class Options
|
||||
return $this->getDefaultMediaType();
|
||||
} elseif ($key === 'defaultPaperSize' || $key === 'default_paper_size') {
|
||||
return $this->getDefaultPaperSize();
|
||||
} elseif ($key === 'defaultPaperOrientation' || $key === 'default_paper_orientation') {
|
||||
return $this->getDefaultPaperOrientation();
|
||||
} elseif ($key === 'defaultFont' || $key === 'default_font') {
|
||||
return $this->getDefaultFont();
|
||||
} elseif ($key === 'dpi') {
|
||||
@ -481,7 +494,7 @@ class Options
|
||||
{
|
||||
return $this->pdfBackend;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $pdflibLicense
|
||||
* @return $this
|
||||
@ -499,7 +512,7 @@ class Options
|
||||
{
|
||||
return $this->pdflibLicense;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $chroot
|
||||
* @return $this
|
||||
@ -708,6 +721,16 @@ class Options
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $defaultPaperOrientation
|
||||
* @return $this
|
||||
*/
|
||||
public function setDefaultPaperOrientation($defaultPaperOrientation)
|
||||
{
|
||||
$this->defaultPaperOrientation = $defaultPaperOrientation;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -716,6 +739,14 @@ class Options
|
||||
return $this->defaultPaperSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultPaperOrientation()
|
||||
{
|
||||
return $this->defaultPaperOrientation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dpi
|
||||
* @return $this
|
||||
|
22
library/vendor/dompdf/src/PhpEvaluator.php
vendored
22
library/vendor/dompdf/src/PhpEvaluator.php
vendored
@ -7,8 +7,6 @@
|
||||
*/
|
||||
namespace Dompdf;
|
||||
|
||||
use Dompdf\Frame;
|
||||
|
||||
/**
|
||||
* Executes inline PHP code during the rendering process
|
||||
*
|
||||
@ -22,14 +20,22 @@ class PhpEvaluator
|
||||
*/
|
||||
protected $_canvas;
|
||||
|
||||
function __construct(Canvas $canvas)
|
||||
/**
|
||||
* PhpEvaluator constructor.
|
||||
* @param Canvas $canvas
|
||||
*/
|
||||
public function __construct(Canvas $canvas)
|
||||
{
|
||||
$this->_canvas = $canvas;
|
||||
}
|
||||
|
||||
function evaluate($code, $vars = array())
|
||||
/**
|
||||
* @param $code
|
||||
* @param array $vars
|
||||
*/
|
||||
public function evaluate($code, $vars = array())
|
||||
{
|
||||
if (!$this->_canvas->get_dompdf()->get_option("enable_php")) {
|
||||
if (!$this->_canvas->get_dompdf()->getOptions()->getIsPhpEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -44,11 +50,13 @@ class PhpEvaluator
|
||||
$$k = $v;
|
||||
}
|
||||
|
||||
//$code = html_entity_decode($code); // @todo uncomment this when tested
|
||||
eval($code);
|
||||
}
|
||||
|
||||
function render(Frame $frame)
|
||||
/**
|
||||
* @param Frame $frame
|
||||
*/
|
||||
public function render(Frame $frame)
|
||||
{
|
||||
$this->evaluate($frame->get_node()->nodeValue);
|
||||
}
|
||||
|
@ -16,15 +16,11 @@ use Dompdf\FrameDecorator\AbstractFrameDecorator;
|
||||
class Absolute extends AbstractPositioner
|
||||
{
|
||||
|
||||
function __construct(AbstractFrameDecorator $frame)
|
||||
/**
|
||||
* @param AbstractFrameDecorator $frame
|
||||
*/
|
||||
function position(AbstractFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
function position()
|
||||
{
|
||||
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
|
||||
$p = $frame->find_positionned_parent();
|
||||
@ -43,7 +39,7 @@ class Absolute extends AbstractPositioner
|
||||
|
||||
list($width, $height) = array($frame->get_margin_width(), $frame->get_margin_height());
|
||||
|
||||
$orig_style = $this->_frame->get_original_style();
|
||||
$orig_style = $frame->get_original_style();
|
||||
$orig_width = $orig_style->width;
|
||||
$orig_height = $orig_style->height;
|
||||
|
||||
@ -76,14 +72,14 @@ class Absolute extends AbstractPositioner
|
||||
} else {
|
||||
if ($right === "auto") {
|
||||
// B or F
|
||||
$x += $left;
|
||||
$x += (float)$left;
|
||||
} else {
|
||||
if ($orig_width === "auto") {
|
||||
// D - TODO change width
|
||||
$x += $left;
|
||||
$x += (float)$left;
|
||||
} else {
|
||||
// H - Everything is fixed: left + width win
|
||||
$x += $left;
|
||||
$x += (float)$left;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,28 +92,27 @@ class Absolute extends AbstractPositioner
|
||||
} else {
|
||||
if ($orig_height === "auto") {
|
||||
// C
|
||||
$y += $h - $height - $bottom;
|
||||
$y += (float)$h - $height - (float)$bottom;
|
||||
} else {
|
||||
// G
|
||||
$y += $h - $height - $bottom;
|
||||
$y += (float)$h - $height - (float)$bottom;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($bottom === "auto") {
|
||||
// B or F
|
||||
$y += $top;
|
||||
$y += (float)$top;
|
||||
} else {
|
||||
if ($orig_height === "auto") {
|
||||
// D - TODO change height
|
||||
$y += $top;
|
||||
$y += (float)$top;
|
||||
} else {
|
||||
// H - Everything is fixed: top + height win
|
||||
$y += $top;
|
||||
$y += (float)$top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$frame->set_position($x, $y);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,30 +22,26 @@ abstract class AbstractPositioner
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \Dompdf\FrameDecorator\AbstractFrameDecorator
|
||||
* @param AbstractFrameDecorator $frame
|
||||
* @return mixed
|
||||
*/
|
||||
protected $_frame;
|
||||
abstract function position(AbstractFrameDecorator $frame);
|
||||
|
||||
//........................................................................
|
||||
|
||||
function __construct(AbstractFrameDecorator $frame)
|
||||
/**
|
||||
* @param AbstractFrameDecorator $frame
|
||||
* @param $offset_x
|
||||
* @param $offset_y
|
||||
* @param bool $ignore_self
|
||||
*/
|
||||
function move(AbstractFrameDecorator $frame, $offset_x, $offset_y, $ignore_self = false)
|
||||
{
|
||||
$this->_frame = $frame;
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
abstract function position();
|
||||
|
||||
function move($offset_x, $offset_y, $ignore_self = false)
|
||||
{
|
||||
list($x, $y) = $this->_frame->get_position();
|
||||
list($x, $y) = $frame->get_position();
|
||||
|
||||
if (!$ignore_self) {
|
||||
$this->_frame->set_position($x + $offset_x, $y + $offset_y);
|
||||
$frame->set_position($x + $offset_x, $y + $offset_y);
|
||||
}
|
||||
|
||||
foreach ($this->_frame->get_children() as $child) {
|
||||
foreach ($frame->get_children() as $child) {
|
||||
$child->move($offset_x, $offset_y);
|
||||
}
|
||||
}
|
||||
|
19
library/vendor/dompdf/src/Positioner/Block.php
vendored
19
library/vendor/dompdf/src/Positioner/Block.php
vendored
@ -18,17 +18,8 @@ use Dompdf\FrameDecorator\AbstractFrameDecorator;
|
||||
*/
|
||||
class Block extends AbstractPositioner {
|
||||
|
||||
|
||||
function __construct(AbstractFrameDecorator $frame)
|
||||
function position(AbstractFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function position()
|
||||
{
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_style();
|
||||
$cb = $frame->get_containing_block();
|
||||
$p = $frame->find_block_parent();
|
||||
@ -49,10 +40,10 @@ class Block extends AbstractPositioner {
|
||||
|
||||
// Relative positionning
|
||||
if ($style->position === "relative") {
|
||||
$top = $style->length_in_pt($style->top, $cb["h"]);
|
||||
//$right = $style->length_in_pt($style->right, $cb["w"]);
|
||||
//$bottom = $style->length_in_pt($style->bottom, $cb["h"]);
|
||||
$left = $style->length_in_pt($style->left, $cb["w"]);
|
||||
$top = (float)$style->length_in_pt($style->top, $cb["h"]);
|
||||
//$right = (float)$style->length_in_pt($style->right, $cb["w"]);
|
||||
//$bottom = (float)$style->length_in_pt($style->bottom, $cb["h"]);
|
||||
$left = (float)$style->length_in_pt($style->left, $cb["w"]);
|
||||
|
||||
$x += $left;
|
||||
$y += $top;
|
||||
|
42
library/vendor/dompdf/src/Positioner/Fixed.php
vendored
42
library/vendor/dompdf/src/Positioner/Fixed.php
vendored
@ -17,15 +17,11 @@ use Dompdf\FrameDecorator\AbstractFrameDecorator;
|
||||
class Fixed extends AbstractPositioner
|
||||
{
|
||||
|
||||
function __construct(AbstractFrameDecorator $frame)
|
||||
/**
|
||||
* @param AbstractFrameDecorator $frame
|
||||
*/
|
||||
function position(AbstractFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
function position()
|
||||
{
|
||||
|
||||
$frame = $this->_frame;
|
||||
$style = $frame->get_original_style();
|
||||
$root = $frame->get_root();
|
||||
$initialcb = $root->get_containing_block();
|
||||
@ -37,14 +33,14 @@ class Fixed extends AbstractPositioner
|
||||
}
|
||||
|
||||
// Compute the margins of the @page style
|
||||
$margin_top = $initialcb_style->length_in_pt($initialcb_style->margin_top, $initialcb["h"]);
|
||||
$margin_right = $initialcb_style->length_in_pt($initialcb_style->margin_right, $initialcb["w"]);
|
||||
$margin_bottom = $initialcb_style->length_in_pt($initialcb_style->margin_bottom, $initialcb["h"]);
|
||||
$margin_left = $initialcb_style->length_in_pt($initialcb_style->margin_left, $initialcb["w"]);
|
||||
$margin_top = (float)$initialcb_style->length_in_pt($initialcb_style->margin_top, $initialcb["h"]);
|
||||
$margin_right = (float)$initialcb_style->length_in_pt($initialcb_style->margin_right, $initialcb["w"]);
|
||||
$margin_bottom = (float)$initialcb_style->length_in_pt($initialcb_style->margin_bottom, $initialcb["h"]);
|
||||
$margin_left = (float)$initialcb_style->length_in_pt($initialcb_style->margin_left, $initialcb["w"]);
|
||||
|
||||
// The needed computed style of the element
|
||||
$height = $style->length_in_pt($style->height, $initialcb["h"]);
|
||||
$width = $style->length_in_pt($style->width, $initialcb["w"]);
|
||||
$height = (float)$style->length_in_pt($style->height, $initialcb["h"]);
|
||||
$width = (float)$style->length_in_pt($style->width, $initialcb["w"]);
|
||||
|
||||
$top = $style->length_in_pt($style->top, $initialcb["h"]);
|
||||
$right = $style->length_in_pt($style->right, $initialcb["w"]);
|
||||
@ -53,16 +49,15 @@ class Fixed extends AbstractPositioner
|
||||
|
||||
$y = $margin_top;
|
||||
if (isset($top)) {
|
||||
$y = $top + $margin_top;
|
||||
$y = (float)$top + $margin_top;
|
||||
if ($top === "auto") {
|
||||
$y = $margin_top;
|
||||
if (isset($bottom) && $bottom !== "auto") {
|
||||
$y = $initialcb["h"] - $bottom - $margin_bottom;
|
||||
$margin_height = $this->_frame->get_margin_height();
|
||||
if ($margin_height !== "auto") {
|
||||
$y -= $margin_height;
|
||||
} else {
|
||||
if ($frame->is_auto_height()) {
|
||||
$y -= $height;
|
||||
} else {
|
||||
$y -= $frame->get_margin_height();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,16 +65,15 @@ class Fixed extends AbstractPositioner
|
||||
|
||||
$x = $margin_left;
|
||||
if (isset($left)) {
|
||||
$x = $left + $margin_left;
|
||||
$x = (float)$left + $margin_left;
|
||||
if ($left === "auto") {
|
||||
$x = $margin_left;
|
||||
if (isset($right) && $right !== "auto") {
|
||||
$x = $initialcb["w"] - $right - $margin_right;
|
||||
$margin_width = $this->_frame->get_margin_width();
|
||||
if ($margin_width !== "auto") {
|
||||
$x -= $margin_width;
|
||||
} else {
|
||||
if ($frame->is_auto_width()) {
|
||||
$x -= $width;
|
||||
} else {
|
||||
$x -= $frame->get_margin_width();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
library/vendor/dompdf/src/Positioner/Inline.php
vendored
31
library/vendor/dompdf/src/Positioner/Inline.php
vendored
@ -10,7 +10,6 @@ namespace Dompdf\Positioner;
|
||||
|
||||
use Dompdf\FrameDecorator\AbstractFrameDecorator;
|
||||
use Dompdf\FrameDecorator\Inline as InlineFrameDecorator;
|
||||
use Dompdf\FrameDecorator\Block as BlockFrameDecorator;
|
||||
use Dompdf\Exception;
|
||||
|
||||
/**
|
||||
@ -21,33 +20,31 @@ use Dompdf\Exception;
|
||||
class Inline extends AbstractPositioner
|
||||
{
|
||||
|
||||
function __construct(AbstractFrameDecorator $frame)
|
||||
{
|
||||
parent::__construct($frame);
|
||||
}
|
||||
|
||||
//........................................................................
|
||||
|
||||
function position()
|
||||
/**
|
||||
* @param AbstractFrameDecorator $frame
|
||||
* @throws Exception
|
||||
*/
|
||||
function position(AbstractFrameDecorator $frame)
|
||||
{
|
||||
/**
|
||||
* Find our nearest block level parent and access its lines property.
|
||||
* @var BlockFrameDecorator
|
||||
*/
|
||||
$p = $this->_frame->find_block_parent();
|
||||
$p = $frame->find_block_parent();
|
||||
|
||||
// Debugging code:
|
||||
|
||||
// Helpers::pre_r("\nPositioning:");
|
||||
// Helpers::pre_r("Me: " . $this->_frame->get_node()->nodeName . " (" . spl_object_hash($this->_frame->get_node()) . ")");
|
||||
// Helpers::pre_r("Parent: " . $p->get_node()->nodeName . " (" . spl_object_hash($p->get_node()) . ")");
|
||||
// Helpers::pre_r("\nPositioning:");
|
||||
// Helpers::pre_r("Me: " . $frame->get_node()->nodeName . " (" . spl_object_hash($frame->get_node()) . ")");
|
||||
// Helpers::pre_r("Parent: " . $p->get_node()->nodeName . " (" . spl_object_hash($p->get_node()) . ")");
|
||||
|
||||
// End debugging
|
||||
|
||||
if (!$p)
|
||||
if (!$p) {
|
||||
throw new Exception("No block-level parent found. Not good.");
|
||||
}
|
||||
|
||||
$f = $this->_frame;
|
||||
$f = $frame;
|
||||
|
||||
$cb = $f->get_containing_block();
|
||||
$line = $p->get_current_line_box();
|
||||
@ -61,13 +58,12 @@ class Inline extends AbstractPositioner
|
||||
}
|
||||
}
|
||||
|
||||
$f = $this->_frame;
|
||||
$f = $frame;
|
||||
|
||||
if (!$is_fixed && $f->get_parent() &&
|
||||
$f->get_parent() instanceof InlineFrameDecorator &&
|
||||
$f->is_text_node()
|
||||
) {
|
||||
|
||||
$min_max = $f->get_reflower()->get_min_max_width();
|
||||
|
||||
// If the frame doesn't fit in the current line, a line break occurs
|
||||
@ -77,6 +73,5 @@ class Inline extends AbstractPositioner
|
||||
}
|
||||
|
||||
$f->set_position($cb["x"] + $line->w, $line->y);
|
||||
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user