diff --git a/src/Mpdf.php b/src/Mpdf.php index 7a5ab7632..5abec91b4 100644 --- a/src/Mpdf.php +++ b/src/Mpdf.php @@ -23469,29 +23469,27 @@ function _tableWrite(&$table, $split = false, $startrow = 0, $startcol = 0, $spl /* -- END BACKGROUNDS -- */ } - if ($this->tableBackgrounds && $level == 1) { + if ($level == 1) { // Nothing else paints while a page-break-inside:avoid block is being measured - see // PaintDivBB() and BaseWriter::write() - and what is drawn on the page it starts on // stays there when the block moves if (!$this->keep_block_together) { - $s = $this->PrintTableBackgrounds(); + $s = $this->tableBackgrounds ? "\n" . $this->PrintTableBackgrounds() . "\n" : ''; + + // The placeholder this table wrote is spent whether or not anything was put behind + // it. One left in place takes a copy of the next table's backgrounds as well, so a + // table with no background of its own used to leave the one after it painted twice + $placeholder = '___TABLE___BACKGROUNDS' . $this->uniqstr; + if ($this->table_rotate && !$this->processingHeader && !$this->processingFooter) { - $this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->tablebuffer); - if ($level == 1) { - $this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->tablebuffer); - } + $this->tablebuffer = str_replace($placeholder, ' ' . $s, $this->tablebuffer); } elseif ($this->bufferoutput) { - $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer); - if ($level == 1) { - $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer); - } + $this->headerbuffer = str_replace($placeholder, ' ' . $s, $this->headerbuffer); } else { - $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]); - if ($level == 1) { - $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]); - } + $this->pages[$this->page] = str_replace($placeholder, ' ' . $s, $this->pages[$this->page]); } } + $this->tableBackgrounds = []; } diff --git a/tests/Mpdf/TableBackgroundTest.php b/tests/Mpdf/TableBackgroundTest.php index b2c8d8796..1fd82df18 100644 --- a/tests/Mpdf/TableBackgroundTest.php +++ b/tests/Mpdf/TableBackgroundTest.php @@ -28,15 +28,14 @@ private function pages($pdf) } /** - * The rectangles filled red, without the duplicates that come of the same background being - * spliced in behind more than one placeholder + * Every rectangle filled red, in order, including any drawn more than once */ private function redRectangles($pdf) { $matches = []; preg_match_all('/' . preg_quote(self::RED_FILL, '/') . '\n([\d.\- ]+) re f/', $pdf, $matches); - return array_values(array_unique($matches[1])); + return $matches[1]; } private function document($before, $after) @@ -87,4 +86,54 @@ public function testATableBackgroundOutsideAnyAvoidBlockIsUnaffected() $this->assertCount(1, $this->redRectangles($this->render($html))); } + /** + * Each table writes a placeholder for its backgrounds to be spliced in behind. A table with no + * background of its own left the placeholder in the page, and the next table's backgrounds went + * behind that one as well as its own. + */ + public function testATableWithNoBackgroundDoesNotLeaveTheNextOnePaintedTwice() + { + $html = '
Plain table cell
' + . '
Red table cell
'; + + $this->assertCount(1, $this->redRectangles($this->render($html))); + } + + public function testEachTableWithNoBackgroundUsedToAddAnotherCopy() + { + $html = str_repeat('
Plain table cell
', 5) + . '
Red table cell
'; + + $this->assertCount(1, $this->redRectangles($this->render($html))); + } + + /** + * Painting the same rectangle twice is invisible while it is opaque; a translucent one comes out + * darker than it was asked to be + */ + public function testATranslucentBackgroundIsNotDarkenedByBeingPaintedTwice() + { + $table = '
Translucent table cell
'; + + $alone = $this->render($table); + $preceded = $this->render('
Plain table cell
' . $table); + + $this->assertSame( + preg_match_all('/ re f/', $alone), + preg_match_all('/ re f/', $preceded) + ); + } + + /** + * The table with the background comes first here, so its placeholder was always taken out before + * the plain table wrote one - this way round has never been wrong + */ + public function testATableWithNoBackgroundAfterAColouredOneIsStillUnaffected() + { + $html = '
Red table cell
' + . '
Plain table cell
'; + + $this->assertCount(1, $this->redRectangles($this->render($html))); + } + } diff --git a/tests/Snapshots/TableBackgroundSnapshotTest.php b/tests/Snapshots/TableBackgroundSnapshotTest.php new file mode 100644 index 000000000..50b79b6f7 --- /dev/null +++ b/tests/Snapshots/TableBackgroundSnapshotTest.php @@ -0,0 +1,72 @@ + + + +

mPDF

+

Table backgrounds

+ +

Each pair below is the same colour written twice. The second of each pair has a + table with no background of its own in front of it, which used to leave the pair's second + half painted on top of itself and so darker than the first.

+ + + +
Translucent red, with nothing in front of it
+ + + +
A table with no background of its own
+ + + +
Translucent red again, and the same shade as the first
+ + + +
Another table with no background of its own
+ + + +
Translucent blue, one table with no background behind it
+ + + +
A third table with no background of its own
+ + + +
A translucent cell rather than a translucent table
+ mpdf = new \Mpdf\Mpdf(); + $this->mpdf->WriteHTML($html); + } +} diff --git a/tests/data/snapshots/table-background.pdf b/tests/data/snapshots/table-background.pdf new file mode 100644 index 000000000..64ca7fac1 Binary files /dev/null and b/tests/data/snapshots/table-background.pdf differ diff --git a/tests/data/snapshots/table.pdf b/tests/data/snapshots/table.pdf index 9a14e7e07..bd4fb1596 100644 Binary files a/tests/data/snapshots/table.pdf and b/tests/data/snapshots/table.pdf differ