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 = '
'
+ . '';
+
+ $this->assertCount(1, $this->redRectangles($this->render($html)));
+ }
+
+ public function testEachTableWithNoBackgroundUsedToAddAnotherCopy()
+ {
+ $html = str_repeat('', 5)
+ . '';
+
+ $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 = '';
+
+ $alone = $this->render($table);
+ $preceded = $this->render('' . $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 = ''
+ . '';
+
+ $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