Skip to content

Render knockout transparency groups#21242

Merged
calixteman merged 1 commit into
mozilla:masterfrom
calixteman:knockout
May 12, 2026
Merged

Render knockout transparency groups#21242
calixteman merged 1 commit into
mozilla:masterfrom
calixteman:knockout

Conversation

@calixteman
Copy link
Copy Markdown
Contributor

In a knockout (KO) group each painting operator ("element") composites against the group's initial backdrop instead of accumulating onto prior elements of the same group. The backend renders each element to a per-group pooled temp canvas (keyed off #groupStackMeta), builds a binary alpha mask via a new feFuncA filter (addKnockoutFilter), destination-outs the group canvas through that mask, restores the initial backdrop into the cleared footprint for non-isolated groups (cropped to the same mask so sparse groups don't bleed the whole rectangle), and finally paints the element on top with the parent's blend mode. Path / clip / transform ops are mirrored back to the group canvas via mirrorContextOperations so graphics state stays in sync between elements; only the raster pixels land on the temp canvas.

The temp canvas is forced to source-over for the element raster (multiply on a transparent backdrop would zero the color) and the original GCO is restored before copyCtxState writes back, so the parent's blend mode survives for the final composite.

Also handled:

  • Nested KO groups (the level is incremented for KO, reset to 0 for non-KO subgroups so an ancestor KO doesn't leak in).
  • Non-isolated non-KO subgroups inside a KO parent (hasInnerBackdrop path: blend the elements against the subgroup's running backdrop for color, mask with the elements-only canvas).
  • Soft masks installed inside a KO element (applySMaskInPlace in compose, which runs the SMask destination-in directly on the temp canvas; the existing blit-to-suspended step is gated by if (!ctx)).
  • Type-3 text, shading fills, image-mask groups, inline images and the solid-color mask path: each is wrapped in #begin/#endKnockoutElement.
  • endDrawing cleanup so cancelled rendering doesn't leak pooled canvases or stale knockout state.

@calixteman calixteman requested a review from timvandermeij May 8, 2026 17:26
@calixteman calixteman linked an issue May 8, 2026 that may be closed by this pull request
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 8, 2026

Codecov Report

❌ Patch coverage is 56.98113% with 114 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.17%. Comparing base (6bbcb46) to head (d1e9194).

Files with missing lines Patch % Lines
src/display/canvas.js 60.74% 95 Missing ⚠️
src/display/filter_factory.js 0.00% 18 Missing ⚠️
src/shared/util.js 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #21242      +/-   ##
==========================================
+ Coverage   56.05%   56.17%   +0.11%     
==========================================
  Files         220      220              
  Lines       58971    59230     +259     
==========================================
+ Hits        33057    33271     +214     
- Misses      25914    25959      +45     
Flag Coverage Δ
fonttest 8.65% <0.00%> (-0.01%) ⬇️
unittest 55.43% <56.60%> (+0.10%) ⬆️
unittestcli 54.71% <55.84%> (+0.12%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread src/shared/util.js Outdated
Copy link
Copy Markdown
Contributor

@timvandermeij timvandermeij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, with passing browser tests. Good to see this long-standing issue resolved; thanks!

@timvandermeij
Copy link
Copy Markdown
Contributor

/botio browsertest

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Windows)


Received

Command cmd_browsertest from @timvandermeij received. Current queue size: 0

Live output at: http://54.193.163.58:8877/fb1406cdbfb7580/output.txt

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Linux m4)


Received

Command cmd_browsertest from @timvandermeij received. Current queue size: 0

Live output at: http://54.241.84.105:8877/45e27f34470de69/output.txt

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Linux m4)


Failed

Full output at http://54.241.84.105:8877/45e27f34470de69/output.txt

Total script time: 19.04 mins

  • Regression tests: FAILED
  different ref/snapshot: 5

Image differences available at: http://54.241.84.105:8877/45e27f34470de69/reftest-analyzer.html#web=eq.log

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Windows)


Failed

Full output at http://54.193.163.58:8877/fb1406cdbfb7580/output.txt

Total script time: 24.82 mins

  • Regression tests: FAILED
  different ref/snapshot: 5

Image differences available at: http://54.193.163.58:8877/fb1406cdbfb7580/reftest-analyzer.html#web=eq.log

In a knockout (KO) group each painting operator ("element") composites against
the group's initial backdrop instead of accumulating onto prior elements
of the same group. The backend renders each element to a per-group pooled
temp canvas (keyed off `#groupStackMeta`), builds a binary alpha mask via
a new `feFuncA` filter (`addKnockoutFilter`), `destination-out`s the
group canvas through that mask, restores the initial backdrop into the
cleared footprint for non-isolated groups (cropped to the same mask so
sparse groups don't bleed the whole rectangle), and finally paints the
element on top with the parent's blend mode. Path / clip / transform ops
are mirrored back to the group canvas via `mirrorContextOperations` so
graphics state stays in sync between elements; only the raster pixels
land on the temp canvas.

The temp canvas is forced to source-over for the element raster (`multiply`
on a transparent backdrop would zero the color) and the original GCO is
restored before `copyCtxState` writes back, so the parent's blend mode
survives for the final composite.

Also handled:
  - Nested KO groups (the level is incremented for KO, reset to 0 for
    non-KO subgroups so an ancestor KO doesn't leak in).
  - Non-isolated non-KO subgroups inside a KO parent (`hasInnerBackdrop`
    path: blend the elements against the subgroup's running backdrop for
    color, mask with the elements-only canvas).
  - Soft masks installed inside a KO element (`applySMaskInPlace` in
    `compose`, which runs the SMask destination-in directly on the temp
    canvas; the existing blit-to-suspended step is gated by `if (!ctx)`).
  - Type-3 text, shading fills, image-mask groups, inline images and the
    solid-color mask path: each is wrapped in `#begin/#endKnockoutElement`.
  - `endDrawing` cleanup so cancelled rendering doesn't leak pooled
    canvases or stale knockout state.
@calixteman
Copy link
Copy Markdown
Contributor Author

/botio browsertest

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Linux m4)


Received

Command cmd_browsertest from @calixteman received. Current queue size: 0

Live output at: http://54.241.84.105:8877/0595d9ad17b56ee/output.txt

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Windows)


Received

Command cmd_browsertest from @calixteman received. Current queue size: 0

Live output at: http://54.193.163.58:8877/f4cd921513af0e5/output.txt

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Linux m4)


Failed

Full output at http://54.241.84.105:8877/0595d9ad17b56ee/output.txt

Total script time: 18.52 mins

  • Regression tests: FAILED
  different ref/snapshot: 5

Image differences available at: http://54.241.84.105:8877/0595d9ad17b56ee/reftest-analyzer.html#web=eq.log

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Windows)


Failed

Full output at http://54.193.163.58:8877/f4cd921513af0e5/output.txt

Total script time: 24.57 mins

  • Regression tests: FAILED
  different ref/snapshot: 5

Image differences available at: http://54.193.163.58:8877/f4cd921513af0e5/reftest-analyzer.html#web=eq.log

@calixteman calixteman merged commit 0c66063 into mozilla:master May 12, 2026
22 checks passed
@calixteman
Copy link
Copy Markdown
Contributor Author

/botio makeref

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Linux m4)


Received

Command cmd_makeref from @calixteman received. Current queue size: 0

Live output at: http://54.241.84.105:8877/5a3a3d452929aa1/output.txt

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Windows)


Received

Command cmd_makeref from @calixteman received. Current queue size: 0

Live output at: http://54.193.163.58:8877/e1b8d4ae2bfc5a8/output.txt

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Linux m4)


Success

Full output at http://54.241.84.105:8877/5a3a3d452929aa1/output.txt

Total script time: 18.46 mins

  • Make references: Passed
  • Check references: Passed

@moz-tools-bot
Copy link
Copy Markdown
Collaborator

From: Bot.io (Windows)


Success

Full output at http://54.193.163.58:8877/e1b8d4ae2bfc5a8/output.txt

Total script time: 24.33 mins

  • Make references: Passed
  • Check references: Passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue about knockout groups.

5 participants