From a8a381e120c434dccb55c166547003c4ad3089c5 Mon Sep 17 00:00:00 2001 From: Jake Jackson Date: Mon, 7 Sep 2026 12:00:24 +1000 Subject: [PATCH] Initialise the OTL Plus tag before font-variant-position appends to it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setCSS() clears OTLtags to [] between elements, so the first font-variant-position: super or sub in a document appends to an unset key: "Undefined array key" on PHP 8, "Undefined index" before that. Every sibling case — FONT-VARIANT-CAPS, -LIGATURES, -NUMERIC and -ALTERNATES — already opens by defaulting Plus to an empty string; FONT-VARIANT-POSITION guarded the str_replace() instead, which leaves the append below it unprotected. Use the same shape as its siblings. Mirrors mpdf/mpdf#2136. Co-Authored-By: Claude Opus 5 --- src/Mpdf.php | 5 ++-- tests/Mpdf/FontVariantPositionTest.php | 38 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/Mpdf/FontVariantPositionTest.php diff --git a/src/Mpdf.php b/src/Mpdf.php index 523b8b7d6..058ec598d 100644 --- a/src/Mpdf.php +++ b/src/Mpdf.php @@ -18830,9 +18830,10 @@ function setCSS($arrayaux, $type = '', $tag = '') case 'FONT-VARIANT-POSITION': - if (isset($this->OTLtags['Plus'])) { - $this->OTLtags['Plus'] = str_replace(['sups', 'subs'], '', $this->OTLtags['Plus']); + if (!isset($this->OTLtags['Plus'])) { + $this->OTLtags['Plus'] = ''; } + $this->OTLtags['Plus'] = str_replace(['sups', 'subs'], '', $this->OTLtags['Plus']); switch (strtoupper($v)) { case 'SUPER': $this->OTLtags['Plus'] .= ' sups'; diff --git a/tests/Mpdf/FontVariantPositionTest.php b/tests/Mpdf/FontVariantPositionTest.php new file mode 100644 index 000000000..9377f54e4 --- /dev/null +++ b/tests/Mpdf/FontVariantPositionTest.php @@ -0,0 +1,38 @@ + 'freeserif']); + $mpdf->compress = false; + + $mpdf->WriteHTML( + '1' + . '1' + . '1' + ); + + $output = $mpdf->OutputBinaryData(); + $mpdf->cleanup(); + + preg_match_all('/<([0-9a-fA-F]+)>\s*Tj/', $output, $matches); + + $this->assertCount(3, $matches[1], 'Expected one text-showing operator per span'); + + list($super, $sub, $normal) = $matches[1]; + + $this->assertSame('31', $normal, 'font-variant-position: normal must leave the digit alone'); + $this->assertNotSame($normal, $super, 'font-variant-position: super must substitute the glyph'); + $this->assertNotSame($normal, $sub, 'font-variant-position: sub must substitute the glyph'); + $this->assertNotSame($super, $sub, 'sups and subs must not resolve to the same glyph'); + } + +}