From 5e18cfd8f0294c210fd0f68c03a7cbdbf6599663 Mon Sep 17 00:00:00 2001 From: calixteman Date: Thu, 14 May 2026 22:59:21 +0200 Subject: [PATCH] Clear the full SMask scratch canvas in compose() PR #21101 narrowed `compose()`'s `clearRect` from full canvas to the caller-supplied dirty box. That leaves pixels outside the current dirty box on the SMask scratch canvas between `compose()` calls; subsequent draws into scratch are then source-over-blended on top of those leftovers, so the output depends on the cumulative draw history rather than just the current draw. --- src/display/canvas.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/display/canvas.js b/src/display/canvas.js index 2781c1929..e104c9fba 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -1850,17 +1850,13 @@ class CanvasGraphics { return; } - // Whatever was drawn has been moved to the suspended canvas, now clear it - // out of the current canvas. Only the dirty box region needs clearing; - // everything outside it is already transparent. + // Clear the full scratch canvas, not just the dirty box. Pixels left + // outside dirtyBox can leak into a later compose() whose destination-in + // pass doesn't overwrite them, producing stale output -- this is what + // breaks `firefox-issue17779-partial` (issue #21276). this.ctx.save(); this.ctx.setTransform(1, 0, 0, 1, 0, 0); - this.ctx.clearRect( - dirtyBox[0], - dirtyBox[1], - dirtyBox[2] - dirtyBox[0], - dirtyBox[3] - dirtyBox[1] - ); + this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); this.ctx.restore(); }