From 682605cd32ef0a7a80f55e6af8edea2add529f84 Mon Sep 17 00:00:00 2001 From: gravitypdf-bot Date: Tue, 13 Oct 2026 10:38:02 +1100 Subject: [PATCH 1/2] Draw a split table's background image on its later pages without warnings (#742) _tableWrite() read the gradient of each layer of a table's own background-image, drawn again on every later page of a table split across pages, without checking it was there. A layer read from a URL has no gradient key, so each later page raised an "Undefined array key" warning, which a strict error handler turns into a failed document. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG-GRAVITYPDF.md | 2 ++ src/Mpdf.php | 2 +- tests/Mpdf/SplitTableBackgroundTest.php | 47 +++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/Mpdf/SplitTableBackgroundTest.php diff --git a/CHANGELOG-GRAVITYPDF.md b/CHANGELOG-GRAVITYPDF.md index 35468e8cb..987888c95 100644 --- a/CHANGELOG-GRAVITYPDF.md +++ b/CHANGELOG-GRAVITYPDF.md @@ -271,6 +271,7 @@ Bugfixes * Styling a table row or row group, such as `tr.total { font-weight: bold }` or ``, did not change the text of its cells, only their background. A `tr`, `thead`, `tbody` or `tfoot` now hands every inherited property to its cells, over the table's and under the cell's own, and a `tbody` rule reaches the rows written straight into a table. A row's `font-size: 80%` is taken of its row group's size, and a cell's of its row's. A row's `currentColor` is its row group's colour, and a cell's is its row's. A `th` stays bold, and is centred only when it inherits no `text-align` from its row, row group or table, as HTML's rendering rules have it. Under the standard `cssMode` only; set `'cssMode' => \Mpdf\CssMode::LEGACY` to keep the old output. [#542] [#655] * `text-outline-width` with no `text-outline-color` raised an undefined-key warning (`outline-COLOR`) and drew the outline black. The warning is gone in either `cssMode`. In standard mode the outline is now drawn in the colour of the text, as `text-outline-color` is `currentColor` by default, and `text-outline` with a width alone, such as `text-outline: 0.2mm`, which was ignored, outlines the text in its colour too. A text outline in `currentColor`, written or by default, is passed on as the keyword, so a `` of another colour inside the outlined text is outlined in its own colour. Set `'cssMode' => \Mpdf\CssMode::LEGACY` to keep black outlines and to ignore that shorthand. [#552] [#650] [#681] * A percentage `border-radius` on a block, such as `border-radius: 50%` on a box 40 mm by 12 mm, drew a pill instead of an ellipse. Both radii were taken of the width of the block around it, and then shrunk to fit. A percentage is now of the block's own border box, as in CSS: a horizontal radius of its width and a vertical one of its height, so `50%` draws an ellipse and `10%` a corner a tenth of each side. A block split across pages resolves a vertical percentage against the height of the part on each page. With `autoPadding` on, a percentage radius no longer adds padding, since the box is not known when the padding is set. In both `cssMode`s. [#552] [#586] +* A table split across pages raised `Undefined array key "gradient"` warnings on each later page when the table had a `background-image` from a URL. The image was drawn; the warnings are gone in either `cssMode`. [#552] [#742] ### Images and SVG @@ -969,3 +970,4 @@ These changes do not change output. [#584]: https://github.com/GravityPDF/mpdf/issues/584 [#689]: https://github.com/GravityPDF/mpdf/pull/689 [#609]: https://github.com/GravityPDF/mpdf/issues/609 +[#742]: https://github.com/GravityPDF/mpdf/issues/742 diff --git a/src/Mpdf.php b/src/Mpdf.php index 52fb36958..5f3a032fa 100644 --- a/src/Mpdf.php +++ b/src/Mpdf.php @@ -23537,7 +23537,7 @@ function _tableWrite(&$table, $split = false, $startrow = 0, $startcol = 0, $spl // The layers of a list are drawn in their order, so its gradients go in with its images $gradientSlot = isset($table['background-image']['layers']) ? 2 : 1; foreach ($this->backgroundLayers($table['background-image']) as $bg) { - if ($bg['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $bg['gradient'])) { + if (!empty($bg['gradient']) && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $bg['gradient'])) { $g = $this->gradient->parseMozGradient($bg['gradient']); if ($g) { $this->tableBackgrounds[$level * 9 + $gradientSlot][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => '']; diff --git a/tests/Mpdf/SplitTableBackgroundTest.php b/tests/Mpdf/SplitTableBackgroundTest.php new file mode 100644 index 000000000..19bf1f103 --- /dev/null +++ b/tests/Mpdf/SplitTableBackgroundTest.php @@ -0,0 +1,47 @@ +backgroundImage() . ')">' + . str_repeat('RowRow', 80) + . ''; + + $pdf = $this->assertDrawsSilently(function (Mpdf $mpdf) use ($html) { + $mpdf->WriteHTML($html); + }, ['cssMode' => $cssMode]); + + $pages = $this->pageContents($pdf); + $this->assertGreaterThan(1, count($pages)); + foreach ($pages as $page) { + $this->assertStringContainsString('/Pattern cs', $page); + } + } + + /** + * Each CSS mode + * + * @return array[] + */ + public function cssModes() + { + return [ + CssMode::STANDARD => [CssMode::STANDARD], + CssMode::LEGACY => [CssMode::LEGACY], + ]; + } + +} From fa6d49b7998e9c0a0ac4c2604d0c1a903611bbdb Mon Sep 17 00:00:00 2001 From: gravitypdf-bot Date: Tue, 13 Oct 2026 10:46:34 +1100 Subject: [PATCH 2/2] Test the split table background beside the other table background tests (#742) Co-Authored-By: Claude Opus 5.5 --- tests/Mpdf/SplitTableBackgroundTest.php | 47 ------------------------- tests/Mpdf/TableBackgroundTest.php | 26 ++++++++++++++ 2 files changed, 26 insertions(+), 47 deletions(-) delete mode 100644 tests/Mpdf/SplitTableBackgroundTest.php diff --git a/tests/Mpdf/SplitTableBackgroundTest.php b/tests/Mpdf/SplitTableBackgroundTest.php deleted file mode 100644 index 19bf1f103..000000000 --- a/tests/Mpdf/SplitTableBackgroundTest.php +++ /dev/null @@ -1,47 +0,0 @@ -backgroundImage() . ')">' - . str_repeat('RowRow', 80) - . ''; - - $pdf = $this->assertDrawsSilently(function (Mpdf $mpdf) use ($html) { - $mpdf->WriteHTML($html); - }, ['cssMode' => $cssMode]); - - $pages = $this->pageContents($pdf); - $this->assertGreaterThan(1, count($pages)); - foreach ($pages as $page) { - $this->assertStringContainsString('/Pattern cs', $page); - } - } - - /** - * Each CSS mode - * - * @return array[] - */ - public function cssModes() - { - return [ - CssMode::STANDARD => [CssMode::STANDARD], - CssMode::LEGACY => [CssMode::LEGACY], - ]; - } - -} diff --git a/tests/Mpdf/TableBackgroundTest.php b/tests/Mpdf/TableBackgroundTest.php index 536902906..21da2c4cf 100644 --- a/tests/Mpdf/TableBackgroundTest.php +++ b/tests/Mpdf/TableBackgroundTest.php @@ -5,6 +5,7 @@ class TableBackgroundTest extends \Yoast\PHPUnitPolyfills\TestCases\TestCase { use PageStreams; + use DrawnStyles; const RED = '1.000 0.000 0.000 rg'; @@ -103,4 +104,29 @@ public function testATableWithNoBackgroundAfterAColouredOneIsStillUnaffected() $this->assertCount(1, $this->redRectangles($this->render($html))); } + /** + * A table's background image from a URL has no gradient, and the background drawn again on each later page of a + * table split across pages must not expect one: the image is tiled on every page and nothing is raised. + * + * @dataProvider modes + * + * @param string $cssMode + */ + public function testASplitTableWithABackgroundImageDrawsItOnEveryPageWithoutWarnings($cssMode) + { + $html = '' + . str_repeat('', 80) + . '
RowRow
'; + + $pdf = $this->assertDrawsSilently(function (Mpdf $mpdf) use ($html) { + $mpdf->WriteHTML($html); + }, ['cssMode' => $cssMode]); + + $pages = $this->pageContents($pdf); + $this->assertGreaterThan(1, count($pages)); + foreach ($pages as $page) { + $this->assertStringContainsString('/Pattern cs', $page); + } + } + }