Skip to content

Draw a text outline with no colour in the colour of its text - #681

Merged
jakejackson1 merged 1 commit into
gravitypdffrom
fix/650-text-outline-default-colour
Oct 6, 2026
Merged

jakejackson1 merged 1 commit into
gravitypdffrom
fix/650-text-outline-default-colour

Conversation

@gravitypdf-bot

Copy link
Copy Markdown

Fixes #650
Part of #552, part of #520

Problem

text-outline-width with no text-outline-color raised a warning when the document was written:

$mpdf = new \Mpdf\Mpdf(['mode' => 'c']);
$mpdf->WriteHTML('<p style="text-outline-width: 0.2mm">x</p>');
$mpdf->Output('', 'S');
// Undefined array key "outline-COLOR" in SetTextOutline()

The outline was stroked in black, whatever the colour of the text. In a browser, -webkit-text-stroke-color, the nearest CSS equivalent, defaults to currentColor, the colour of the text.

Two related cases, measured on gravitypdf:

Rule Before, standard mode After, standard mode Legacy, before and after
p { color: #0a0; text-outline-width: 0.2mm } black outline, warning green outline black outline (no warning after)
p { color: #0a0; text-outline: 0.2mm } no outline green outline no outline
p { color: #0a0; text-outline: 0.2mm currentColor } with <span style="color: #00f"> inside span outlined green span outlined blue span outlined green

Cause

SetTextOutline() read $params['outline-COLOR'] unconditionally. Only a text-outline-color declaration sets that key, so an outline given a width alone read a key that was never set, and SetDColor(null) left the stroke colour as it was. In practice that was the black that resets at the start of each block.

Fix

  • Mpdf::SetTextOutline() takes the colour of the text run as a second argument. printbuffer() passes the run's colour ($vetor[3]). With no outline colour, standard mode strokes in that colour, or black when the text has none. Legacy mode leaves the stroke colour as it was, so its output stays byte-identical, without the warning. The colour is resolved at draw time, not at merge time, because text-outline-color is inherited and mPDF passes it to inline content through textparam. Each piece of text then gets its own colour.
  • text-outline-color: currentColor is no longer resolved to a fixed colour in CssMerger under standard mode. It moved from CURRENT_COLOR_PROPERTIES to a new LEGACY_CURRENT_COLOR_PROPERTIES. setCSS() reads the keyword as "no outline colour", which clears any colour inherited from an ancestor, and the draw-time default then applies. A written currentColor therefore behaves the same as the default, and a descendant of another colour is outlined in its own colour, as CSS inherits currentColor as the keyword. Legacy mode resolves it at merge as Draw currentColor, and a border or shadow with no colour, in the element's colour #651 does.
  • The text-outline shorthand with a width alone (text-outline: 0.2mm) sets the width and resets the colour to currentColor in standard mode, as a shorthand resets the parts it does not name (resetsOmittedParts()). Legacy mode ignores it, as before.

Legacy mode

Legacy output does not change. The warning is gone, the outline keeps the stroke colour already set (black), the one-value shorthand is still ignored, and a written currentColor is still resolved at the element. No snapshot fixture changed.

Tests

In CurrentColorTest, through its uncompressed() helper, which fails on any warning or notice:

  • The document from the issue draws a black outline with no warning, in both modes.
  • A width with no colour under a green parent, in each of the 11 contexts (block, inline, table cell, collapsed and nested table cells, list item, header, footer, positioned block, kept block, forced page break). Standard mode strokes it green and legacy black.
  • A green paragraph with a blue <span> outlines the span in blue and the rest in green. This holds for a width with no colour, the one-value shorthand, the shorthand after a colour, and a written currentColor.
  • Legacy mode ignores the one-value shorthand.
  • An outline colour inherited from a parent is kept by a child that sets only a width, in both modes.
  • testEveryColourPropertyResolvesCurrentColor now expects standard mode to keep currentcolor in TEXT-OUTLINE-COLOR.

With the src/ changes reverted, 29 of these cases fail.

Checks

  • vendor/bin/phpunit --exclude-group snapshot: OK, 11948 tests, 31 skipped
  • vendor/bin/phpunit --group snapshot: OK, 208 tests, no fixture changed
  • composer cs: clean
  • PHPStan (--memory-limit=2G): no errors
  • php -l on PHP 5.6 (docker) for each changed file: no syntax errors

🤖 Generated with Claude Code

text-outline-width without a text-outline-color read a colour that was
never set and raised an undefined-key warning. In standard mode the
outline now takes the colour of each piece of text, as
text-outline-color is currentColor by default; the text-outline
shorthand with a width alone draws it too, and currentColor written in
text-outline-color is passed on as the keyword. Legacy mode keeps the
stroke colour it drew in before, without the warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jakejackson1
jakejackson1 force-pushed the fix/650-text-outline-default-colour branch from ceacdaf to 577de55 Compare October 6, 2026 04:12
@jakejackson1
jakejackson1 merged commit 11d2575 into gravitypdf Oct 6, 2026
@jakejackson1
jakejackson1 deleted the fix/650-text-outline-default-colour branch October 6, 2026 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working create-upstream-pr

Projects

None yet

Development

Successfully merging this pull request may close these issues.

text-outline-width without a colour raises Undefined array key "outline-COLOR"

2 participants