Upgrade 1-11.38

This commit is contained in:
xesmyd
2026-03-30 14:10:30 +02:00
parent f2a7e6d1fc
commit ac648ef29d
24665 changed files with 69682 additions and 2205004 deletions
+1
View File
@@ -33,6 +33,7 @@ jobs:
- "8.2"
- "8.3"
- "8.4"
- "8.5"
operating-system: [ubuntu-latest, windows-latest]
steps:
+1
View File
@@ -1,2 +1,3 @@
vendor/*
tests/Mpdf/tmp/*
composer.lock
+5
View File
@@ -7,11 +7,16 @@ New features
* Added support for `psr/http-message` v2 without dropping v1. (@markdorison, @apotek, @greg-1-anderson, @NigelCunningham #1907)
* PHP 8.3 support in mPDF 8.2.1
* Add support for `page-break-before: avoid;` and `page-break-after: avoid;` for tr elements inside tables
* Add support for custom `AssetFetcher` via the service container (@splitbrain, #2165)
Bugfixes
--------
* Replace character entities with characters when processing the `code` attribute in the `<barcode />` tag
* Escape XML predefined entities in XMP metadata (Fix for #2090)
* Enable Font Subsetting by Default (Fix for #1315)
* Fix `TypeError` with non-numeric `rotate` values like `none` or `90deg` on tables (@derrabus, #2178)
* Small change to better support list-style-type on list items within tables
mPDF 8.1.x
===========================
+1
View File
@@ -26,6 +26,7 @@ PHP versions and extensions
- `PHP 8.2` is supported as of `mPDF v8.1.3`
- `PHP 8.3` is supported as of `mPDF v8.2.1`
- `PHP 8.4` is supported as of `mPDF v8.2.5`
- `PHP 8.5` is supported as of `mPDF v8.2.6`
PHP `mbstring` and `gd` extensions have to be loaded.
+10 -6
View File
@@ -21,7 +21,7 @@
"docs": "https://mpdf.github.io"
},
"require": {
"php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"ext-gd": "*",
"ext-mbstring": "*",
"mpdf/psr-http-message-shim": "^1.0 || ^2.0",
@@ -38,12 +38,13 @@
"squizlabs/php_codesniffer": "^3.5.0",
"tracy/tracy": "~2.5",
"yoast/phpunit-polyfills": "^1.0"
},
},
"suggest": {
"ext-bcmath": "Needed for generation of some types of barcodes",
"ext-zlib": "Needed for compression of embedded resources, such as fonts",
"ext-xml": "Needed mainly for SVG manipulation"
},
"ext-xml": "Needed mainly for SVG manipulation",
"ext-imagick": "Needed if developing the Mpdf library"
},
"autoload": {
"psr-4": {
"Mpdf\\": "src/"
@@ -54,7 +55,9 @@
},
"autoload-dev": {
"psr-4": {
"Mpdf\\": "tests/Mpdf"
"Mpdf\\": "tests/Mpdf",
"Snapshots\\": "tests/Snapshots",
"Issues\\": "tests/Issues"
},
"files": [
"src/functions-dev.php"
@@ -64,7 +67,8 @@
"post-install-cmd": [
"php -r \"chmod('./tmp', 0777);\""
],
"cs": "@php vendor/bin/phpcs -v --report-width=160 --standard=ruleset.xml --severity=1 --warning-severity=0 --extensions=php src utils tests",
"cs": "@php vendor/bin/phpcs --report-width=160 --standard=ruleset.xml --severity=1 --warning-severity=0 --extensions=php src utils tests",
"cs:fix": "@php vendor/bin/phpcbf --standard=ruleset.xml --extensions=php src utils tests",
"test": "@php vendor/bin/phpunit",
"coverage": "@php vendor/bin/phpunit --coverage-text"
},
+7 -151
View File
@@ -36,18 +36,6 @@ parameters:
count: 1
path: src/Color/ColorSpaceRestrictor.php
-
message: '#^Binary operation "\+" between non\-empty\-string and 0 results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: src/CssManager.php
-
message: '#^Variable \$tag might not be defined\.$#'
identifier: variable.undefined
count: 1
path: src/CssManager.php
-
message: '#^Method Mpdf\\Mpdf\:\:GetJspacing\(\) invoked with 4 parameters, 5 required\.$#'
identifier: arguments.count
@@ -60,12 +48,6 @@ parameters:
count: 1
path: src/DirectWrite.php
-
message: '#^Access to an undefined property Mpdf\\Mpdf\:\:\$ktForms\.$#'
identifier: property.notFound
count: 3
path: src/Form.php
-
message: '#^PHPDoc tag @throws has invalid value \(\\Kdyby\\StrictObjects\\\\Mpdf\\MpdfException\)\: Unexpected token "\\\\\\\\Mpdf\\\\MpdfException", expected TOKEN_HORIZONTAL_WS at offset 74 on line 3$#'
identifier: phpDoc.parseError
@@ -90,24 +72,12 @@ parameters:
count: 10
path: src/Form.php
-
message: '#^Variable \$dif might not be defined\.$#'
identifier: variable.undefined
count: 1
path: src/Gif/ColorTable.php
-
message: '#^Binary operation "\+" between non\-empty\-string and 0 results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: src/Gradient.php
-
message: '#^Comparison operation "\<" between \(array\|float\|int\) and 1 results in an error\.$#'
identifier: smaller.invalid
count: 1
path: src/Gradient.php
-
message: '#^Variable \$angle in isset\(\) always exists and is not nullable\.$#'
identifier: isset.variable
@@ -198,12 +168,6 @@ parameters:
count: 2
path: src/Image/ImageProcessor.php
-
message: '#^Binary operation "\*" between \(list\<string\>\|string\|null\) and \-1 results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: src/Image/Svg.php
-
message: '#^Binary operation "\*" between 0\.3333333333333333 and string results in an error\.$#'
identifier: binaryOp.invalid
@@ -225,13 +189,7 @@ parameters:
-
message: '#^Binary operation "\+" between string and \(float\|int\) results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: src/Image/Svg.php
-
message: '#^Binary operation "\+" between string and \(float\|int\|int\<1, max\>\) results in an error\.$#'
identifier: binaryOp.invalid
count: 2
count: 3
path: src/Image/Svg.php
-
@@ -360,30 +318,6 @@ parameters:
count: 1
path: src/Mpdf.php
-
message: '#^Comparison operation "\<" between \(float\|int\) and \(array\|float\|int\) results in an error\.$#'
identifier: smaller.invalid
count: 2
path: src/Mpdf.php
-
message: '#^Comparison operation "\>" between \(array\|float\|int\) and \(float\|int\) results in an error\.$#'
identifier: greater.invalid
count: 1
path: src/Mpdf.php
-
message: '#^Comparison operation "\>" between \(float\|int\) and \(array\|float\|int\) results in an error\.$#'
identifier: greater.invalid
count: 4
path: src/Mpdf.php
-
message: '#^Comparison operation "\>" between array\|float\|int and 0 results in an error\.$#'
identifier: greater.invalid
count: 2
path: src/Mpdf.php
-
message: '#^PHPDoc tag @throws has invalid value \(\\Kdyby\\StrictObjects\\\\Mpdf\\MpdfException\)\: Unexpected token "\\\\\\\\Mpdf\\\\MpdfException", expected TOKEN_HORIZONTAL_WS at offset 74 on line 3$#'
identifier: phpDoc.parseError
@@ -648,12 +582,6 @@ parameters:
count: 7
path: src/Mpdf.php
-
message: '#^Variable \$glyphIDtoUni might not be defined\.$#'
identifier: variable.undefined
count: 1
path: src/Mpdf.php
-
message: '#^Variable \$glyphYorigin might not be defined\.$#'
identifier: variable.undefined
@@ -759,7 +687,7 @@ parameters:
-
message: '#^Variable \$p might not be defined\.$#'
identifier: variable.undefined
count: 2
count: 1
path: src/Mpdf.php
-
@@ -942,34 +870,16 @@ parameters:
count: 1
path: src/Otl.php
-
message: '#^Comparison operation "\>" between array\|float\|int\|string\|false\|null and 0 results in an error\.$#'
identifier: greater.invalid
count: 5
path: src/Otl.php
-
message: '#^Comparison operation "\>\=" between int and \(array\|float\|int\) results in an error\.$#'
identifier: greaterOrEqual.invalid
count: 1
path: src/Otl.php
-
message: '#^Comparison operation "\>\=" between int\<0, max\> and \(array\|float\|int\) results in an error\.$#'
identifier: greaterOrEqual.invalid
count: 1
path: src/Otl.php
-
message: '#^Offset int on array\{\} in isset\(\) does not exist\.$#'
identifier: isset.offset
count: 2
count: 1
path: src/Otl.php
-
message: '#^Offset int\<0, max\> on array\{\} in isset\(\) does not exist\.$#'
identifier: isset.offset
count: 4
count: 1
path: src/Otl.php
-
@@ -1041,19 +951,19 @@ parameters:
-
message: '#^Variable \$PosLookupRecord might not be defined\.$#'
identifier: variable.undefined
count: 3
count: 1
path: src/Otl.php
-
message: '#^Variable \$SequenceIndex might not be defined\.$#'
identifier: variable.undefined
count: 8
count: 4
path: src/Otl.php
-
message: '#^Variable \$SubstLookupRecord might not be defined\.$#'
identifier: variable.undefined
count: 6
count: 2
path: src/Otl.php
-
@@ -1110,12 +1020,6 @@ parameters:
count: 1
path: src/Otl.php
-
message: '#^Comparison operation "\>\=" between \(float\|int\) and \(array\|float\|int\) results in an error\.$#'
identifier: greaterOrEqual.invalid
count: 1
path: src/OtlDump.php
-
message: '#^Undefined variable\: \$rtlPUAarr$#'
identifier: variable.undefined
@@ -1188,12 +1092,6 @@ parameters:
count: 2
path: src/Shaper/Indic.php
-
message: '#^Comparison operation "\>\=" between \(float\|int\) and \(array\|float\|int\) results in an error\.$#'
identifier: greaterOrEqual.invalid
count: 1
path: src/TTFontFile.php
-
message: '#^PHPDoc tag @throws has invalid value \(\\Kdyby\\StrictObjects\\\\Mpdf\\MpdfException\)\: Unexpected token "\\\\\\\\Mpdf\\\\MpdfException", expected TOKEN_HORIZONTAL_WS at offset 74 on line 3$#'
identifier: phpDoc.parseError
@@ -1296,12 +1194,6 @@ parameters:
count: 1
path: src/TTFontFileAnalysis.php
-
message: '#^Comparison operation "\>\=" between \(float\|int\) and \(non\-empty\-array\|float\|int\<min, \-1\>\|int\<1, max\>\) results in an error\.$#'
identifier: greaterOrEqual.invalid
count: 1
path: src/TTFontFileAnalysis.php
-
message: '#^Variable \$TOC_end might not be defined\.$#'
identifier: variable.undefined
@@ -1338,24 +1230,6 @@ parameters:
count: 1
path: src/Tag/BlockTag.php
-
message: '#^Offset ''bgcolor'' on array\{cells\: array, wc\: array, hr\: array, is_tfoot\: array\<int\<0, max\>, true\>, nestedpos\?\: array\{\(float\|int\)\}\} in isset\(\) does not exist\.$#'
identifier: isset.offset
count: 3
path: src/Tag/Table.php
-
message: '#^Offset ''trbackground\-images'' on array\{cells\: array, wc\: array, hr\: array, is_tfoot\: array\<int\<0, max\>, true\>, nestedpos\?\: array\{\(float\|int\)\}\} in isset\(\) does not exist\.$#'
identifier: isset.offset
count: 2
path: src/Tag/Table.php
-
message: '#^Offset ''trgradients'' on array\{cells\: array, wc\: array, hr\: array, is_tfoot\: array\<int\<0, max\>, true\>, nestedpos\?\: array\{\(float\|int\)\}\} in isset\(\) does not exist\.$#'
identifier: isset.offset
count: 2
path: src/Tag/Table.php
-
message: '#^Variable \$added_page might not be defined\.$#'
identifier: variable.undefined
@@ -1536,24 +1410,6 @@ parameters:
count: 2
path: src/Writer/MetadataWriter.php
-
message: '#^Access to an undefined property Mpdf\\Mpdf\:\:\$_obj_stack\.$#'
identifier: property.notFound
count: 5
path: src/Writer/ObjectWriter.php
-
message: '#^Access to an undefined property Mpdf\\Mpdf\:\:\$current_parser\.$#'
identifier: property.notFound
count: 1
path: src/Writer/ObjectWriter.php
-
message: '#^Access to an undefined property Mpdf\\Mpdf\:\:\$parsers\.$#'
identifier: property.notFound
count: 1
path: src/Writer/ObjectWriter.php
-
message: '#^Access to constant TYPE_STREAM on an unknown class pdf_parser\.$#'
identifier: class.notFound
+7
View File
@@ -1,5 +1,6 @@
<phpunit
bootstrap="tests/bootstrap.php"
cacheResultFile="tmp/.phpunit.result.cache"
colors="true"
backupGlobals="false"
beStrictAboutTestsThatDoNotTestAnything="false">
@@ -10,6 +11,12 @@
</testsuite>
</testsuites>
<groups>
<exclude>
<group>snapshot</group>
</exclude>
</groups>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
+1 -1
View File
@@ -10,7 +10,7 @@ use Mpdf\PsrHttpMessageShim\Request;
use Mpdf\PsrLogAwareTrait\PsrLogAwareTrait;
use Psr\Log\LoggerInterface;
class AssetFetcher implements \Psr\Log\LoggerAwareInterface
class AssetFetcher implements \Psr\Log\LoggerAwareInterface, \Mpdf\AssetFetcherInterface
{
use PsrLogAwareTrait;
+35 -7
View File
@@ -28,10 +28,6 @@ class Cache
protected function createBasePath($basePath)
{
if (!file_exists($basePath)) {
if (!$this->createBasePath(dirname($basePath))) {
return false;
}
if (!$this->createDirectory($basePath)) {
return false;
}
@@ -46,17 +42,49 @@ class Cache
protected function createDirectory($basePath)
{
if (!mkdir($basePath)) {
$parentPath = $this->getExistingParentDirectory($basePath);
$permissions = $this->getPermission($parentPath);
if (!mkdir($basePath, $permissions, true)) {
return false;
}
if (!chmod($basePath, 0777)) {
return false;
/* Check if umask modified the permissions and reset any created directories */
if (($permissions & ~umask()) !== $permissions) {
$basePath = realpath($basePath);
$folders = explode('/', substr($basePath, strlen($parentPath) + 1));
for ($i = 1, $total = count($folders); $i <= $total; $i++) {
$path = $parentPath . '/';
$path .= implode('/', array_slice($folders, 0, $i));
chmod($path, $permissions);
}
}
return true;
}
protected function getExistingParentDirectory($basePath)
{
$targetParent = dirname($basePath);
while ($targetParent !== '.' && ! is_dir($targetParent) && dirname($targetParent) !== $targetParent) {
$targetParent = dirname($targetParent);
}
return realpath($targetParent);
}
protected function getPermission($basePath, $fallbackPermission = 0777)
{
if (! is_dir($basePath)) {
return $fallbackPermission;
}
$result = fileperms($basePath);
return $result ? $result & 0007777 : $fallbackPermission;
}
public function tempFilename($filename)
{
return $this->getFilePath($filename);
+1
View File
@@ -152,6 +152,7 @@ class ConfigVariables
'PDFA' => false,
// Overrides warnings making changes when possible to force PDFA1-b compliance
'PDFAauto' => false,
'PDFAversion' => '1-B',
// Colour profile OutputIntent
// sRGB_IEC61966-2-1 (=default if blank and PDFA), or other added .icc profile
+1 -1
View File
@@ -198,7 +198,7 @@ class FontVariables
'useOTL' => 0xFF,
],
"eeyekunicode" => [/* Meetei Mayek */
'R' => "Eeyek.ttf",
'R' => "Eeyek-Regular.ttf",
],
"lannaalif" => [/* Tai Tham */
'R' => "lannaalif-v1-03.ttf",
+170 -2257
View File
File diff suppressed because it is too large Load Diff
+1 -5
View File
@@ -332,11 +332,7 @@ trait FpdiTrait
protected function _put($s, $newLine = true)
{
if ($newLine) {
$this->buffer .= $s . "\n";
} else {
$this->buffer .= $s;
}
$this->buffer->append($s, $newLine);
}
/**
+9 -3
View File
@@ -92,7 +92,7 @@ class CurlHttpClient implements \Mpdf\Http\ClientInterface, \Psr\Log\LoggerAware
throw new \Mpdf\MpdfException($message);
}
curl_close($ch);
$this->closeCurl($ch);
return $response;
}
@@ -106,16 +106,22 @@ class CurlHttpClient implements \Mpdf\Http\ClientInterface, \Psr\Log\LoggerAware
throw new \Mpdf\MpdfException($message);
}
curl_close($ch);
$this->closeCurl($ch);
return $response->withStatus($info['http_code']);
}
curl_close($ch);
$this->closeCurl($ch);
return $response
->withStatus($info['http_code'])
->withBody(Stream::create($data));
}
private function closeCurl($ch)
{
if (PHP_VERSION_ID < 80000) {
curl_close($ch);
}
}
}
+16 -9
View File
@@ -470,7 +470,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
$info['trns'] = $trns;
}
imagedestroy($im);
$this->destroyImage($im);
}
return $info;
}
@@ -654,7 +654,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
return $this->imageError($file, $firstTime, sprintf('Error parsing temporary file "%s" created with GD library to parse JPG (CMYK) image', $tempfile));
}
imagedestroy($im);
$this->destroyImage($im);
unlink($tempfile);
$info['type'] = 'jpg';
@@ -891,7 +891,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
$w = imagesx($im);
$h = imagesy($im);
$tempfile = $this->cache->tempFilename('_tempImgPNG' . md5($file) . random_int(1, 10000) . '.png');
$tempfile = $this->cache->tempFilename('_tempImgPNG' . md5($file) . bin2hex(random_bytes(6)) . '.png');
// Alpha channel set (including using tRNS for Paletted images)
if ($pngalpha) {
@@ -990,7 +990,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
return $this->imageError($file, $firstTime, 'Failed to create temporary image file (' . $tempfile_alpha . ') parsing PNG image with alpha channel (' . $errpng . ')');
}
imagedestroy($imgalpha);
$this->destroyImage($imgalpha);
// extract image without alpha channel
$imgplain = imagecreatetruecolor($w, $h);
imagealphablending($imgplain, false); // mPDF 5.7.2
@@ -1002,7 +1002,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
return $this->imageError($file, $firstTime, 'Failed to create temporary image file (' . $tempfile . ') parsing PNG image with alpha channel (' . $errpng . ')');
}
imagedestroy($imgplain);
$this->destroyImage($imgplain);
// embed mask image
//$minfo = $this->getImage($tempfile_alpha, false);
@@ -1089,7 +1089,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
return $this->imageError($file, $firstTime, 'Failed to create temporary image file (' . $tempfile . ') parsing PNG image (' . $errpng . ')');
}
imagedestroy($im);
$this->destroyImage($im);
// $info = $this->getImage($tempfile, false);
$data = file_get_contents($tempfile);
$info = $this->processPng($data, $tempfile, false, $interpolation);
@@ -1248,7 +1248,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
@imagejpeg($im, $tempfile);
$data = file_get_contents($tempfile);
imagedestroy($im);
$this->destroyImage($im);
unlink($tempfile);
unlink($checkfile);
@@ -1312,7 +1312,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
return $this->imageError($file, $firstTime, 'Error parsing temporary file (' . $tempfile . ') created with GD library to parse GIF image');
}
imagedestroy($im);
$this->destroyImage($im);
unlink($tempfile);
$info['type'] = 'gif';
@@ -1460,7 +1460,7 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
$data = file_get_contents($tempfile);
$info = $this->processPng($data, $tempfile, false, $interpolation);
imagedestroy($im);
$this->destroyImage($im);
unlink($tempfile);
if (!$info) {
@@ -1478,4 +1478,11 @@ class ImageProcessor implements \Psr\Log\LoggerAwareInterface
}
}
private function destroyImage($im)
{
if (PHP_VERSION_ID < 80000) {
imagedestroy($im);
}
}
}
+3 -3
View File
@@ -278,7 +278,7 @@ class Svg
$orig_srcpath = '';
if (trim($srcpath) != '' && substr($srcpath, 0, 4) == 'var:') {
$orig_srcpath = $srcpath;
$srcpath = $this->mpdf->GetFullPath($srcpath);
$this->mpdf->GetFullPath($srcpath);
}
// Image file (does not allow vector images i.e. WMF/SVG)
@@ -1479,11 +1479,11 @@ class Svg
for ($i = 0; $i < count($d); $i += 2) {
if ($d[$i] === 'none') {
if ($d[$i] === '' || $d[$i] === 'none') {
continue;
}
$arr .= sprintf('%.3F %.3F ', $d[$i] * $this->kp, $d[$i + 1] * $this->kp);
$arr .= sprintf('%.3F %.3F ', (float) $d[$i] * $this->kp, (float) $d[$i + 1] * $this->kp);
}
if (isset($critere_style['stroke-dashoffset'])) {
+58 -118
View File
@@ -15,6 +15,7 @@ use Mpdf\QrCode;
use Mpdf\Utils\Arrays;
use Mpdf\Utils\NumericString;
use Mpdf\Utils\UtfString;
use Mpdf\Utils\Path;
use Psr\Log\NullLogger;
/**
@@ -32,7 +33,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
use FpdiTrait;
use MpdfPsrLogAwareTrait;
const VERSION = '8.2.5';
const VERSION = '8.3.1';
const SCALE = 72 / 25.4;
@@ -76,7 +77,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
var $PDFXauto;
var $PDFA;
var $PDFAversion = '1-B';
var $PDFAversion;
var $PDFAauto;
var $ICCProfile;
@@ -332,10 +333,6 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
var $lastblocklevelchange;
var $nestedtablejustfinished;
var $linebreakjustfinished;
var $cell_border_dominance_L;
var $cell_border_dominance_R;
var $cell_border_dominance_T;
var $cell_border_dominance_B;
var $table_keep_together;
var $plainCell_properties;
var $shrin_k1;
@@ -851,6 +848,10 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
*/
private $cssManager;
/**
* @var ShadowParser
private $shadowParser;
/**
* @var \Mpdf\Gradient
*/
@@ -1109,7 +1110,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$this->BMPonly = [];
$this->page = 0;
$this->n = 2;
$this->buffer = '';
$this->buffer = new Buffer();
$this->objectbuffer = [];
$this->pages = [];
$this->OrientationChanges = [];
@@ -1913,6 +1914,11 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
}
}
/**
* @param mixed[] $parms
*
* @return int
*/
function AddExtGState($parms)
{
$n = count($this->extgstates);
@@ -1933,6 +1939,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
}
$n++;
$this->extgstates[$n]['parms'] = $parms;
return $n;
}
@@ -3912,6 +3919,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$regenerate = true;
} // mPDF 6
$glyphIDtoUni = null;
if (empty($font['name']) || $font['originalsize'] != $ttfstat['size'] || $regenerate) {
$generator = new MetricsGenerator($this->fontCache, $this->fontDescriptor);
@@ -9547,7 +9555,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$this->logger->debug(sprintf('Compiled in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);
$this->logger->debug(sprintf('Peak Memory usage %s MB', number_format(memory_get_peak_usage(true) / (1024 * 1024), 2)), ['context' => LogContext::STATISTICS]);
$this->logger->debug(sprintf('PDF file size %s kB', number_format(strlen($this->buffer) / 1024)), ['context' => LogContext::STATISTICS]);
$this->logger->debug(sprintf('PDF file size %s kB', number_format($this->buffer->getLength() / 1024)), ['context' => LogContext::STATISTICS]);
$this->logger->debug(sprintf('%d fonts used', count($this->fonts)), ['context' => LogContext::STATISTICS]);
if (is_bool($dest)) {
@@ -9584,7 +9592,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
// don't use length if server using compression
header('Content-Length: ' . strlen($this->buffer));
header('Content-Length: ' . $this->buffer->getLength());
}
header('Content-disposition: inline; filename="' . $name . '"');
@@ -9595,7 +9603,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
}
echo $this->buffer;
$this->buffer->writeToOutput();
break;
@@ -9616,12 +9624,12 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
// don't use length if server using compression
header('Content-Length: ' . strlen($this->buffer));
header('Content-Length: ' . $this->buffer->getLength());
}
header('Content-Disposition: attachment; filename="' . $name . '"');
echo $this->buffer;
$this->buffer->writeToOutput();
break;
@@ -9632,14 +9640,15 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
throw new \Mpdf\MpdfException(sprintf('Unable to create output file %s', $name));
}
fwrite($f, $this->buffer, strlen($this->buffer));
$this->buffer->writeToFile($f);
fclose($f);
break;
case Destination::STRING_RETURN:
$this->cache->clearOld();
return $this->buffer;
return $this->buffer->writeToString();
default:
throw new \Mpdf\MpdfException(sprintf('Incorrect output destination %s', $dest));
@@ -10036,9 +10045,10 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
for ($i = 0; $i < 4; $i++) {
$m[$i] = array_merge($m1[$i], $m2[$i], $m3[$i]);
}
if (count($m[0])) {
$mFirstLength = count($m[0]);
if ($mFirstLength) {
$sortarr = [];
for ($i = 0; $i < count($m[0]); $i++) {
for ($i = 0; $i < $mFirstLength; $i++) {
$key = $m[1][$i] * 2;
if ($m[3][$i] == 'EMCZ') {
$key +=2; // background first then gradient then normal
@@ -10102,7 +10112,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$this->writer->write('endobj');
// Cross-ref
$o = strlen($this->buffer);
$o = $this->buffer->getLength();
$this->writer->write('xref');
$this->writer->write('0 ' . ($this->n + 1));
$this->writer->write('0000000000 65535 f ');
@@ -10121,7 +10131,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$this->writer->write('startxref');
$this->writer->write($o);
$this->buffer .= '%%EOF';
$this->buffer->append('%%EOF');
$this->state = 3;
}
@@ -11527,84 +11537,8 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
public function GetFullPath(&$path, $basepath = '')
{
// @todo make return, remove reference
// When parsing CSS need to pass temporary basepath - so links are relative to current stylesheet
if (!$basepath) {
$basepath = $this->basepath;
}
// Fix path value
$path = str_replace("\\", '/', $path); // If on Windows
// mPDF 5.7.2
if (strpos($path, '//') === 0) {
$scheme = parse_url($basepath, PHP_URL_SCHEME);
$scheme = $scheme ?: 'http';
$path = $scheme . ':' . $path;
}
$path = preg_replace('|^./|', '', $path); // Inadvertently corrects "./path/etc" and "//www.domain.com/etc"
if (strpos($path, '#') === 0) {
return;
}
// Skip schemes not supported by installed stream wrappers
$wrappers = stream_get_wrappers();
$pattern = sprintf('@^(?!%s)[a-z0-9\.\-+]+:.*@i', implode('|', $wrappers));
if (preg_match($pattern, $path)) {
return;
}
if (strpos($path, '../') === 0) { // It is a relative link
$backtrackamount = substr_count($path, '../');
$maxbacktrack = substr_count($basepath, '/') - 3;
$filepath = str_replace('../', '', $path);
$path = $basepath;
// If it is an invalid relative link, then make it go to directory root
if ($backtrackamount > $maxbacktrack) {
$backtrackamount = $maxbacktrack;
}
// Backtrack some directories
for ($i = 0; $i < $backtrackamount + 1; $i++) {
$path = substr($path, 0, strrpos($path, "/"));
}
$path .= '/' . $filepath; // Make it an absolute path
return;
}
if ((strpos($path, ":/") === false || strpos($path, ":/") > 10) && !@is_file($path)) { // It is a local link. Ignore potential file errors
if (strpos($path, '/') === 0) {
$tr = parse_url($basepath);
// mPDF 5.7.2
$root = '';
if (!empty($tr['scheme'])) {
$root .= $tr['scheme'] . '://';
}
$root .= isset($tr['host']) ? $tr['host'] : '';
$root .= ((isset($tr['port']) && $tr['port']) ? (':' . $tr['port']) : ''); // mPDF 5.7.3
$path = $root . $path;
return;
}
$path = $basepath . $path;
}
// Do nothing if it is an Absolute Link
$basepath = !empty($basepath) ? $basepath : $this->basepath;
$path = Path::relativeToAbsolutePath($path, $basepath);
}
function docPageNum($num = 0, $extras = false)
@@ -13094,7 +13028,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$this->watermarkText = $txt->getText();
$this->watermarkTextAlpha = $txt->getAlpha();
$this->watermarkAngle = $txt->getAngle();
$this->watermark_font = $txt->getFont() === null ? $txt->getFont() : $this->watermark_font;
$this->watermark_font = $txt->getFont() !== null ? $txt->getFont() : $this->watermark_font;
$this->watermark_size = $txt->getSize();
return;
@@ -13339,7 +13273,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
}
$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
if ($zproperties) {
$properties = $this->cssManager->array_merge_recursive_unique($properties, $zproperties);
$properties = Arrays::uniqueRecursiveMerge($properties, $zproperties);
}
if (isset($properties['DIRECTION']) && $properties['DIRECTION']) {
@@ -22244,6 +22178,11 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
// pagebreak-after is mapped to pagebreak-before on i+1 in Tags/Tr.php
$pagebreaklookahead++;
}
// corner case: if the pagelookahead is bigger than the pagesize, we break anyway, so fill up the page
if ($pagebreaklookahead * $maxrowheight + $extra > $pagetrigger + 0.001) {
$pagebreaklookahead = 1;
}
// if we exceed page boundaries: restart table on next page before printing the line
if ($j == $startcol && ((($y + $pagebreaklookahead * $maxrowheight + $extra ) > ($pagetrigger + 0.001)) || (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && ($y + $maxrowheight + $tablefooterrowheight + $extra) > $pagetrigger) && ($this->tableLevel == 1 && $i < ($numrows - $table['headernrows']))) && ($y0 > 0 || $x0 > 0) && !$this->InFooter && $this->autoPageBreak) {
if (!$skippage) {
$finalSpread = true;
@@ -23888,26 +23827,27 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
if ($end_page < 1) {
$end_page = $start_page;
}
$n_tod = $end_page - $start_page + 1;
$last_page = count($this->pages);
$n_atend = $last_page - $end_page + 1;
$deletedPagesCount = $end_page - $start_page + 1;
$lastPageNumber = count($this->pages);
$remainingPagesFromEndPageCount = $lastPageNumber - $end_page;
// move pages
for ($i = 0; $i < $n_atend; $i++) {
for ($i = 0; $i < $remainingPagesFromEndPageCount; $i++) {
$this->pages[$start_page + $i] = $this->pages[$end_page + 1 + $i];
}
// delete pages
for ($i = 0; $i < $n_tod; $i++) {
unset($this->pages[$last_page - $i]);
}
// delete pages
for ($i = 0; $i < $deletedPagesCount; $i++) {
unset($this->pages[$lastPageNumber - $i]);
}
/* -- BOOKMARKS -- */
// Update Bookmarks
foreach ($this->BMoutlines as $i => $o) {
if ($o['p'] >= $end_page) {
$this->BMoutlines[$i]['p'] -= $n_tod;
} elseif ($p < $start_page) {
$this->BMoutlines[$i]['p'] -= $deletedPagesCount;
} elseif ($o['p'] < $start_page) {
unset($this->BMoutlines[$i]);
}
}
@@ -23921,14 +23861,14 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
if (strpos($pl[4], '@') === 0) {
$p = substr($pl[4], 1);
if ($p > $end_page) {
$this->PageLinks[$i][$key][4] = '@' . ($p - $n_tod);
$this->PageLinks[$i][$key][4] = '@' . ($p - $deletedPagesCount);
} elseif ($p < $start_page) {
unset($this->PageLinks[$i][$key]);
}
}
}
if ($i > $end_page) {
$newarr[($i - $n_tod)] = $this->PageLinks[$i];
$newarr[($i - $deletedPagesCount)] = $this->PageLinks[$i];
} elseif ($p < $start_page) {
$newarr[$i] = $this->PageLinks[$i];
}
@@ -23955,7 +23895,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$newarr = [];
foreach ($this->pageDim as $p => $v) {
if ($p > $end_page) {
$newarr[($p - $n_tod)] = $this->pageDim[$p];
$newarr[($p - $deletedPagesCount)] = $this->pageDim[$p];
} elseif ($p < $start_page) {
$newarr[$p] = $this->pageDim[$p];
}
@@ -23968,7 +23908,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
if (count($this->saveHTMLHeader)) {
foreach ($this->saveHTMLHeader as $p => $v) {
if ($p > $end_page) {
$newarr[($p - $n_tod)] = $this->saveHTMLHeader[$p];
$newarr[($p - $deletedPagesCount)] = $this->saveHTMLHeader[$p];
} // mPDF 5.7.3
elseif ($p < $start_page) {
$newarr[$p] = $this->saveHTMLHeader[$p];
@@ -23981,7 +23921,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
$newarr = [];
foreach ($this->saveHTMLFooter as $p => $v) {
if ($p > $end_page) {
$newarr[($p - $n_tod)] = $this->saveHTMLFooter[$p];
$newarr[($p - $deletedPagesCount)] = $this->saveHTMLFooter[$p];
} elseif ($p < $start_page) {
$newarr[$p] = $this->saveHTMLFooter[$p];
}
@@ -23993,7 +23933,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
// Update Internal Links
foreach ($this->internallink as $key => $o) {
if ($o['PAGE'] > $end_page) {
$this->internallink[$key]['PAGE'] -= $n_tod;
$this->internallink[$key]['PAGE'] -= $deletedPagesCount;
} elseif ($o['PAGE'] < $start_page) {
unset($this->internallink[$key]);
}
@@ -24002,7 +23942,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
// Update Links
foreach ($this->links as $key => $o) {
if ($o[0] > $end_page) {
$this->links[$key][0] -= $n_tod;
$this->links[$key][0] -= $deletedPagesCount;
} elseif ($o[0] < $start_page) {
unset($this->links[$key]);
}
@@ -24011,7 +23951,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
// Update Form fields
foreach ($this->form->forms as $key => $f) {
if ($f['page'] > $end_page) {
$this->form->forms[$key]['page'] -= $n_tod;
$this->form->forms[$key]['page'] -= $deletedPagesCount;
} elseif ($f['page'] < $start_page) {
unset($this->form->forms[$key]);
}
@@ -24024,7 +23964,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
foreach ($this->PageAnnots as $p => $anno) {
if ($p > $end_page) {
foreach ($anno as $o) {
$newarr[($p - $n_tod)][] = $o;
$newarr[($p - $deletedPagesCount)][] = $o;
}
} elseif ($p < $start_page) {
$newarr[$p] = $this->PageAnnots[$p];
@@ -24038,7 +23978,7 @@ class Mpdf implements \Psr\Log\LoggerAwareInterface
// Update PageNumSubstitutions
foreach ($this->PageNumSubstitutions as $k => $v) {
if ($this->PageNumSubstitutions[$k]['from'] > $end_page) {
$this->PageNumSubstitutions[$k]['from'] -= $n_tod;
$this->PageNumSubstitutions[$k]['from'] -= $deletedPagesCount;
} elseif ($this->PageNumSubstitutions[$k]['from'] < $start_page) {
unset($this->PageNumSubstitutions[$k]);
}
+12
View File
@@ -17,6 +17,9 @@ class PageBox implements \ArrayAccess
];
}
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
@@ -27,12 +30,18 @@ class PageBox implements \ArrayAccess
$this->container[$offset] = $value;
}
/**
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return array_key_exists($offset, $this->container);
}
/**
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
@@ -43,6 +52,9 @@ class PageBox implements \ArrayAccess
$this->container[$offset] = null;
}
/**
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
+30 -2
View File
@@ -5,6 +5,14 @@ namespace Mpdf;
use Mpdf\Color\ColorConverter;
use Mpdf\Color\ColorModeConverter;
use Mpdf\Color\ColorSpaceRestrictor;
use Mpdf\Css\BorderMerger;
use Mpdf\Css\CssMerger;
use Mpdf\Css\CssParser;
use Mpdf\Css\InlinePropertyConverter;
use Mpdf\Css\InlineStyleParser;
use Mpdf\Css\NormalizeProperties;
use Mpdf\Css\SelectorParser;
use Mpdf\Css\ShadowParser;
use Mpdf\File\LocalContentLoader;
use Mpdf\Fonts\FontCache;
use Mpdf\Fonts\FontFileFinder;
@@ -81,9 +89,29 @@ class ServiceFactory
? $this->container->get('localContentLoader')
: new LocalContentLoader();
$assetFetcher = new AssetFetcher($mpdf, $localContentLoader, $httpClient, $logger);
$assetFetcher = $this->container && $this->container->has('assetFetcher')
? $this->container->get('assetFetcher')
: new AssetFetcher($mpdf, $localContentLoader, $httpClient, $logger);
$cssManager = new CssManager($mpdf, $cache, $sizeConverter, $colorConverter, $assetFetcher);
$normalizeProperties = new NormalizeProperties($mpdf, $sizeConverter, $colorConverter);
$selectorParser = new SelectorParser($mpdf);
$inlineStyleParser = new InlineStyleParser($normalizeProperties);
$inlinePropertyConverter = new InlinePropertyConverter($colorConverter);
$borderMerger = new BorderMerger();
$cssParser = new CssParser($mpdf, $cache, $sizeConverter, $colorConverter, $assetFetcher);
$cssMerger = new CssMerger(
$mpdf,
$normalizeProperties,
$inlineStyleParser,
$selectorParser,
$inlinePropertyConverter,
$colorConverter,
$borderMerger
);
$cssManager = new CssManager($cssParser, $cssMerger);
$otl = new Otl($mpdf, $fontCache);
+2 -1
View File
@@ -42,7 +42,7 @@ class SizeConverter implements \Psr\Log\LoggerAwareInterface
*/
public function convert($size = 5, $maxsize = 0, $fontsize = false, $usefontsize = true)
{
$size = trim(strtolower($size));
$size = trim(strtolower((string) $size));
$res = preg_match('/^(?P<size>[-0-9.,]+([eE]\-?[0-9]+)?)?(?P<unit>[%a-z-]+)?$/', $size, $parts);
if (!$res) {
// ignore definition
@@ -70,6 +70,7 @@ class SizeConverter implements \Psr\Log\LoggerAwareInterface
break;
case '%':
case '%%': // Issue2051
if ($fontsize && $usefontsize) {
$size *= $fontsize / 100;
} else {
+160 -22
View File
@@ -3,6 +3,9 @@
namespace Mpdf\Tag;
use Mpdf\Conversion\DecToAlpha;
use Mpdf\Conversion\DecToCjk;
use Mpdf\Conversion\DecToHebrew;
use Mpdf\Conversion\DecToOther;
use Mpdf\Conversion\DecToRoman;
use Mpdf\Mpdf;
use Mpdf\Utils\Arrays;
@@ -155,6 +158,34 @@ abstract class BlockTag extends Tag
$this->mpdf->listtype[$this->mpdf->listlvl] = 'square';
}
}
// Override with HTML TYPE attribute (lower specificity than CSS)
if (!empty($attr['TYPE'])) {
$listtype = $attr['TYPE'];
switch ($listtype) {
case 'A':
$listtype = 'upper-latin';
break;
case 'a':
$listtype = 'lower-latin';
break;
case 'I':
$listtype = 'upper-roman';
break;
case 'i':
$listtype = 'lower-roman';
break;
case '1':
$listtype = 'decimal';
break;
}
$this->mpdf->listtype[$this->mpdf->listlvl] = $listtype;
}
// Override with CSS list-style-type if specified (highest specificity)
if (!empty($properties['LIST-STYLE-TYPE'])) {
$this->mpdf->listtype[$this->mpdf->listlvl] = strtolower($properties['LIST-STYLE-TYPE']);
}
}
// mPDF 6 Lists - in Tables
@@ -170,54 +201,161 @@ abstract class BlockTag extends Tag
//if in table - output here as a tabletextbuffer
//position:inside OR position:outside (always output in table as position:inside)
$currentListType = $this->mpdf->listtype[$this->mpdf->listlvl];
// Allow individual LI to override list type via HTML TYPE attribute
if (!empty($attr['TYPE'])) {
$liType = $attr['TYPE'];
switch ($liType) {
case 'A':
$liType = 'upper-latin';
break;
case 'a':
$liType = 'lower-latin';
break;
case 'I':
$liType = 'upper-roman';
break;
case 'i':
$liType = 'lower-roman';
break;
case '1':
$liType = 'decimal';
break;
}
$currentListType = $liType;
}
// Allow individual LI to override list type via CSS (highest specificity)
if (!empty($properties['LIST-STYLE-TYPE'])) {
$currentListType = strtolower($properties['LIST-STYLE-TYPE']);
}
$decToAlpha = new DecToAlpha();
$decToRoman = new DecToRoman();
$counter = $this->mpdf->listcounter[$this->mpdf->listlvl];
$list_item_color = '';
switch ($this->mpdf->listtype[$this->mpdf->listlvl]) {
switch ($currentListType) {
case 'upper-alpha':
case 'upper-latin':
case 'A':
$blt = $decToAlpha->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix;
$blt = $decToAlpha->convert($counter) . $this->mpdf->list_number_suffix;
break;
case 'lower-alpha':
case 'lower-latin':
case 'a':
$blt = $decToAlpha->convert($this->mpdf->listcounter[$this->mpdf->listlvl], false) . $this->mpdf->list_number_suffix;
$blt = $decToAlpha->convert($counter, false) . $this->mpdf->list_number_suffix;
break;
case 'upper-roman':
case 'I':
$blt = $decToRoman->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix;
$blt = $decToRoman->convert($counter) . $this->mpdf->list_number_suffix;
break;
case 'lower-roman':
case 'i':
$blt = $decToRoman->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix;
$blt = $decToRoman->convert($counter, false) . $this->mpdf->list_number_suffix;
break;
case 'decimal':
case '1':
$blt = $this->mpdf->listcounter[$this->mpdf->listlvl] . $this->mpdf->list_number_suffix;
$blt = $counter . $this->mpdf->list_number_suffix;
break;
case 'hebrew':
$decToHebrew = new DecToHebrew();
$blt = $decToHebrew->convert($counter) . $this->mpdf->list_number_suffix;
break;
case 'cjk-decimal':
$decToCjk = new DecToCjk();
$blt = $decToCjk->convert($counter) . $this->mpdf->list_number_suffix;
break;
case 'arabic-indic':
case 'bengali':
case 'cambodian':
case 'devanagari':
case 'gujarati':
case 'gurmukhi':
case 'kannada':
case 'khmer':
case 'lao':
case 'malayalam':
case 'myanmar':
case 'oriya':
case 'persian':
case 'tamil':
case 'telugu':
case 'thai':
case 'urdu':
$decToOther = new DecToOther($this->mpdf);
$cp = $decToOther->getCodePage($currentListType);
$blt = $decToOther->convert($counter, $cp, true) . $this->mpdf->list_number_suffix;
break;
case 'disc':
$blt = '-';
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 8226)) {
$blt = "\xe2\x80\xa2"; // U+2022 BULLET
}
break;
case 'circle':
$blt = '-';
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9900)) {
$blt = "\xe2\x9a\xac"; // U+26AC
}
break;
case 'square':
$blt = '-';
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9642)) {
$blt = "\xe2\x96\xaa"; // U+25AA
}
break;
case 'none':
$blt = '';
break;
default:
$blt = '-';
if ($this->mpdf->listlvl % 3 == 1 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 8226)) {
$blt = "\xe2\x80\xa2";
} // &#8226;
elseif ($this->mpdf->listlvl % 3 == 2 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9900)) {
$blt = "\xe2\x9a\xac";
} // &#9900;
elseif ($this->mpdf->listlvl % 3 == 0 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9642)) {
$blt = "\xe2\x96\xaa";
} // &#9642;
if (preg_match('/U\+([a-fA-F0-9]+)/i', $currentListType, $m)) {
$blt = '-';
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], hexdec($m[1]))) {
$blt = UtfString::codeHex2utf($m[1]);
}
if (preg_match('/rgb\(.*?\)/', $currentListType, $cm)) {
$list_item_color = $this->colorConverter->convert($cm[0], $this->mpdf->PDFAXwarnings);
}
} else {
$blt = '-';
if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 8226)) {
$blt = "\xe2\x80\xa2";
}
}
break;
}
// change to &nbsp; spaces
if ($this->mpdf->usingCoreFont) {
$ls = str_repeat(chr(160) . chr(160), ($this->mpdf->listlvl - 1) * 2) . $blt . ' ';
} else {
$ls = str_repeat("\xc2\xa0\xc2\xa0", ($this->mpdf->listlvl - 1) * 2) . $blt . ' ';
if ($currentListType !== 'none') {
if ($this->mpdf->usingCoreFont) {
$indent = str_repeat(chr(160) . chr(160), ($this->mpdf->listlvl - 1) * 2);
} else {
$indent = str_repeat("\xc2\xa0\xc2\xa0", ($this->mpdf->listlvl - 1) * 2);
}
if (!empty($list_item_color)) {
// Write indentation without color
if ($indent !== '') {
$this->mpdf->_saveCellTextBuffer($indent);
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($indent);
}
// Write marker with color
$save_colorarray = $this->mpdf->colorarray;
$this->mpdf->colorarray = $list_item_color;
$this->mpdf->_saveCellTextBuffer($blt);
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($blt);
$this->mpdf->colorarray = $save_colorarray;
// Write trailing space without color
$this->mpdf->_saveCellTextBuffer(' ');
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth(' ');
} else {
$ls = $indent . $blt . ' ';
$this->mpdf->_saveCellTextBuffer($ls);
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($ls);
}
}
$this->mpdf->_saveCellTextBuffer($ls);
$this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($ls);
}
return;
+26 -2
View File
@@ -212,7 +212,7 @@ class Table extends Tag
}
}
if (!empty($properties['ROTATE']) && $this->mpdf->tableLevel == 1) {
$this->mpdf->table_rotate = $properties['ROTATE'];
$this->mpdf->table_rotate = $this->parseTableRotate($properties['ROTATE']);
}
if (isset($properties['TOPNTAIL'])) {
$table['topntail'] = $properties['TOPNTAIL'];
@@ -496,7 +496,7 @@ class Table extends Tag
}
}
if (isset($attr['ROTATE']) && $this->mpdf->tableLevel == 1) {
$this->mpdf->table_rotate = $attr['ROTATE'];
$this->mpdf->table_rotate = $this->parseTableRotate($attr['ROTATE']);
}
//++++++++++++++++++++++++++++
@@ -1278,4 +1278,28 @@ class Table extends Tag
return $ret;
}
/**
* @param string $rotate
* @return int
*/
private function parseTableRotate($rotate)
{
if (1 !== preg_match('/^(-?[0-9]+)(?:deg)?$/', $rotate, $matches)) {
return 0;
}
$rotationDegrees = (int) $matches[1] % 360;
if ($rotationDegrees > 180) {
$rotationDegrees -= 360;
} elseif ($rotationDegrees < -180) {
$rotationDegrees += 360;
}
// Only 90 and -90 are supported
if ($rotationDegrees !== 90 && $rotationDegrees !== -90) {
$rotationDegrees = 0;
}
return $rotationDegrees;
}
}
+14 -13
View File
@@ -4,6 +4,7 @@ namespace Mpdf\Tag;
use Mpdf\Css\Border;
use Mpdf\Css\TextVars;
use Mpdf\Utils\Arrays;
use Mpdf\Utils\UtfString;
class Td extends Tag
@@ -167,14 +168,14 @@ class Td extends Tag
$c['R'] = $this->mpdf->trow_text_rotate;
}
$this->mpdf->cell_border_dominance_L = 0;
$this->mpdf->cell_border_dominance_R = 0;
$this->mpdf->cell_border_dominance_T = 0;
$this->mpdf->cell_border_dominance_B = 0;
$this->cssManager->setBorderDominance('L', 0);
$this->cssManager->setBorderDominance('R', 0);
$this->cssManager->setBorderDominance('T', 0);
$this->cssManager->setBorderDominance('B', 0);
$properties = $this->cssManager->MergeCSS('TABLE', $tag, $attr);
$properties = $this->cssManager->array_merge_recursive_unique($this->mpdf->base_table_properties, $properties);
$properties = Arrays::uniqueRecursiveMerge($this->mpdf->base_table_properties, $properties);
$this->mpdf->Reset(); // mPDF 6 ?????????????????????
@@ -282,10 +283,10 @@ class Td extends Tag
$c['border_details']['L'] = $bord;
$c['border_details']['T'] = $bord;
$c['border_details']['B'] = $bord;
$c['border_details']['L']['dom'] = $this->mpdf->cell_border_dominance_L;
$c['border_details']['R']['dom'] = $this->mpdf->cell_border_dominance_R;
$c['border_details']['T']['dom'] = $this->mpdf->cell_border_dominance_T;
$c['border_details']['B']['dom'] = $this->mpdf->cell_border_dominance_B;
$c['border_details']['L']['dom'] = $this->cssManager->getBorderDominance('L');
$c['border_details']['R']['dom'] = $this->cssManager->getBorderDominance('R');
$c['border_details']['T']['dom'] = $this->cssManager->getBorderDominance('T');
$c['border_details']['B']['dom'] = $this->cssManager->getBorderDominance('B');
} elseif ($this->mpdf->simpleTables && $this->mpdf->row == 0 && $this->mpdf->col == 0) {
$table['simple']['border'] = Border::ALL;
$table['simple']['border_details']['R'] = $bord;
@@ -299,22 +300,22 @@ class Td extends Tag
if (!empty($properties['BORDER-RIGHT'])) {
$c['border_details']['R'] = $this->mpdf->border_details($properties['BORDER-RIGHT']);
$this->mpdf->setBorder($c['border'], Border::RIGHT, $c['border_details']['R']['s']);
$c['border_details']['R']['dom'] = $this->mpdf->cell_border_dominance_R;
$c['border_details']['R']['dom'] = $this->cssManager->getBorderDominance('R');
}
if (!empty($properties['BORDER-LEFT'])) {
$c['border_details']['L'] = $this->mpdf->border_details($properties['BORDER-LEFT']);
$this->mpdf->setBorder($c['border'], Border::LEFT, $c['border_details']['L']['s']);
$c['border_details']['L']['dom'] = $this->mpdf->cell_border_dominance_L;
$c['border_details']['L']['dom'] = $this->cssManager->getBorderDominance('L');
}
if (!empty($properties['BORDER-BOTTOM'])) {
$c['border_details']['B'] = $this->mpdf->border_details($properties['BORDER-BOTTOM']);
$this->mpdf->setBorder($c['border'], Border::BOTTOM, $c['border_details']['B']['s']);
$c['border_details']['B']['dom'] = $this->mpdf->cell_border_dominance_B;
$c['border_details']['B']['dom'] = $this->cssManager->getBorderDominance('B');
}
if (!empty($properties['BORDER-TOP'])) {
$c['border_details']['T'] = $this->mpdf->border_details($properties['BORDER-TOP']);
$this->mpdf->setBorder($c['border'], Border::TOP, $c['border_details']['T']['s']);
$c['border_details']['T']['dom'] = $this->mpdf->cell_border_dominance_T;
$c['border_details']['T']['dom'] = $this->cssManager->getBorderDominance('T');
}
} elseif ($this->mpdf->simpleTables && $this->mpdf->row == 0 && $this->mpdf->col == 0) {
if (!empty($properties['BORDER-LEFT'])) {
+30 -1
View File
@@ -29,9 +29,10 @@ class Arrays
* [one, two]
* ]
* @param array $array
* @param int|null $maxSize Max depth of the combinations
* @return array
*/
public static function allUniqueSortedCombinations($array)
public static function allUniqueSortedCombinations($array, $maxSize = null)
{
$input = array_unique($array);
if (count($input) <= 1) {
@@ -46,6 +47,9 @@ class Arrays
$n = count($input);
for ($k = 2; $k <= $n; $k++) {
if ($maxSize && $k > $maxSize) {
break;
}
$combinations = array_merge($combinations, self::combinations($input, $k));
}
@@ -97,4 +101,29 @@ class Arrays
return $combinations;
}
/**
* Merge arrays recursively, appending integer-like keys and merge string keys.
*
* @param array ...$arrays Arrays to merge
* @return array Merged array
*/
public static function uniqueRecursiveMerge(...$arrays)
{
$results = array_shift($arrays);
foreach ($arrays as $array) {
foreach ($array as $key => $value) {
if ((string) $key === (string) ((int) $key)) {
$results[] = $value;
} elseif (is_array($value) && isset($results[$key]) && is_array($results[$key])) {
$results[$key] = self::uniqueRecursiveMerge($results[$key], $value);
} else {
$results[$key] = $value;
}
}
}
return $results;
}
}
+2 -2
View File
@@ -32,7 +32,7 @@ final class BaseWriter
if ($this->mpdf->state === 2) {
$this->endPage($s, $ln);
} else {
$this->mpdf->buffer .= $s . ($ln ? "\n" : '');
$this->mpdf->buffer->append($s, $ln);
}
}
@@ -53,7 +53,7 @@ final class BaseWriter
// Begin a new object
if (!$onlynewobj) {
$this->mpdf->offsets[$obj_id] = strlen($this->mpdf->buffer);
$this->mpdf->offsets[$obj_id] = $this->mpdf->buffer->getLength();
$this->write($obj_id . ' 0 obj');
$this->mpdf->currentObjectNumber = $obj_id; // for later use with encryption
}
+12 -6
View File
@@ -46,7 +46,7 @@ class FontWriter
// TrueType embedded
if (isset($info['type']) && $info['type'] === 'TTF' && !$info['sip'] && !$info['smp']) {
$used = true;
$asSubset = false;
$asSubset = true;
foreach ($this->mpdf->fonts as $k => $f) {
if (isset($f['fontkey']) && $f['fontkey'] === $fontkey && $f['type'] === 'TTF') {
$used = $f['used'];
@@ -61,9 +61,6 @@ class FontWriter
$asSubset = true;
}
}
if ($this->mpdf->PDFA || $this->mpdf->PDFX) {
$asSubset = false;
}
$this->mpdf->fonts[$k]['asSubset'] = $asSubset;
break;
}
@@ -165,10 +162,16 @@ class FontWriter
$ssfaid = 'AA';
$ttf = new TTFontFile($this->fontCache, $this->fontDescriptor);
$subsetCount = count($font['subsetfontids']);
for ($sfid = 0; $sfid < $subsetCount; $sfid++) {
$this->mpdf->fonts[$k]['n'][$sfid] = $this->mpdf->n + 1; // NB an array for subset
$subsetname = 'MPDF' . $ssfaid . '+' . $font['name'];
$ssfaid++;
if (function_exists('str_increment')) {
$ssfaid = str_increment($ssfaid);
} else {
$ssfaid++;
}
/* For some strange reason a subset ($sfid > 0) containing less than 97 characters causes an error
so fill up the array */
@@ -479,7 +482,10 @@ class FontWriter
continue;
}
$width = (ord($character1) << 8) + ord($character2);
$w1 = $character1 === '' ? 0 : ord($character1);
$w2 = $character2 === '' ? 0 : ord($character2);
$width = ($w1 << 8) + $w2;
if ($width === 65535) {
$width = 0;
+8 -8
View File
@@ -62,9 +62,9 @@ class MetadataWriter implements \Psr\Log\LoggerAwareInterface
$m .= ' <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="3.1-701">' . "\n";
$m .= ' <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">' . "\n";
$m .= ' <rdf:Description rdf:about="uuid:' . $uuid . '" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">' . "\n";
$m .= ' <pdf:Producer>' . $this->getProducerString() . '</pdf:Producer>' . "\n";
$m .= ' <pdf:Producer>' . htmlspecialchars($this->getProducerString(), ENT_QUOTES | ENT_XML1) . '</pdf:Producer>' . "\n";
if (!empty($this->mpdf->keywords)) {
$m .= ' <pdf:Keywords>' . $this->mpdf->keywords . '</pdf:Keywords>' . "\n";
$m .= ' <pdf:Keywords>' . htmlspecialchars($this->mpdf->keywords, ENT_QUOTES | ENT_XML1) . '</pdf:Keywords>' . "\n";
}
$m .= ' </rdf:Description>' . "\n";
@@ -73,7 +73,7 @@ class MetadataWriter implements \Psr\Log\LoggerAwareInterface
$m .= ' <xmp:ModifyDate>' . $CreationDate . '</xmp:ModifyDate>' . "\n";
$m .= ' <xmp:MetadataDate>' . $CreationDate . '</xmp:MetadataDate>' . "\n";
if (!empty($this->mpdf->creator)) {
$m .= ' <xmp:CreatorTool>' . $this->mpdf->creator . '</xmp:CreatorTool>' . "\n";
$m .= ' <xmp:CreatorTool>' . htmlspecialchars($this->mpdf->creator, ENT_QUOTES | ENT_XML1) . '</xmp:CreatorTool>' . "\n";
}
$m .= ' </rdf:Description>' . "\n";
@@ -83,28 +83,28 @@ class MetadataWriter implements \Psr\Log\LoggerAwareInterface
if (!empty($this->mpdf->title)) {
$m .= ' <dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">' . $this->mpdf->title . '</rdf:li>
<rdf:li xml:lang="x-default">' . htmlspecialchars($this->mpdf->title, ENT_QUOTES | ENT_XML1) . '</rdf:li>
</rdf:Alt>
</dc:title>' . "\n";
}
if (!empty($this->mpdf->keywords)) {
$m .= ' <dc:subject>
<rdf:Bag>
<rdf:li>' . $this->mpdf->keywords . '</rdf:li>
<rdf:li>' . htmlspecialchars($this->mpdf->keywords, ENT_QUOTES | ENT_XML1) . '</rdf:li>
</rdf:Bag>
</dc:subject>' . "\n";
}
if (!empty($this->mpdf->subject)) {
$m .= ' <dc:description>
<rdf:Alt>
<rdf:li xml:lang="x-default">' . $this->mpdf->subject . '</rdf:li>
<rdf:li xml:lang="x-default">' . htmlspecialchars($this->mpdf->subject, ENT_QUOTES | ENT_XML1) . '</rdf:li>
</rdf:Alt>
</dc:description>' . "\n";
}
if (!empty($this->mpdf->author)) {
$m .= ' <dc:creator>
<rdf:Seq>
<rdf:li>' . $this->mpdf->author . '</rdf:li>
<rdf:li>' . htmlspecialchars($this->mpdf->author, ENT_QUOTES | ENT_XML1) . '</rdf:li>
</rdf:Seq>
</dc:creator>' . "\n";
}
@@ -801,7 +801,7 @@ class MetadataWriter implements \Psr\Log\LoggerAwareInterface
$this->writer->write('/Encrypt ' . $this->mpdf->enc_obj_id . ' 0 R');
$this->writer->write('/ID [<' . $this->protection->getUniqid() . '> <' . $this->protection->getUniqid() . '>]');
} else {
$uniqid = md5(time() . $this->mpdf->buffer);
$uniqid = md5(time() . $this->mpdf->buffer->getHash());
$this->writer->write('/ID [<' . $uniqid . '> <' . $uniqid . '>]');
}
}
+1 -1
View File
@@ -265,7 +265,7 @@ final class PageWriter
$this->metadataWriter->writeAnnotations(); // mPDF 5.7.2
// Pages root
$this->mpdf->offsets[1] = strlen($this->mpdf->buffer);
$this->mpdf->offsets[1] = $this->mpdf->buffer->getLength();
$this->writer->write('1 0 obj');
$this->writer->write('<</Type /Pages');
+1 -1
View File
@@ -121,7 +121,7 @@ final class ResourceWriter implements \Psr\Log\LoggerAwareInterface
$this->backgroundWriter->writePatterns();
// Resource dictionary
$this->mpdf->offsets[2] = strlen($this->mpdf->buffer);
$this->mpdf->offsets[2] = $this->mpdf->buffer->getLength();
$this->writer->write('2 0 obj');
$this->writer->write('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');