From c275c729778f2cc169a4d9a92fd9d0f87a78cd05 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 22 Mar 2025 23:26:47 +0100 Subject: [PATCH] Fix save/restore while in smask mode The rendering bug with issue17779.pdf is due to the fact that we call save on the suspended ctx but not on the the current ctx. So each time we've something like save/transform/restore then the transform not "removed" when restoring. So this patch just apply the save/restore operations to ctx which are mirrored on the suspended one. --- src/display/canvas.js | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/display/canvas.js b/src/display/canvas.js index b8e56fec9..4d99b7cb3 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -1545,39 +1545,35 @@ class CanvasGraphics { // Copy the temporary canvas state to the main(suspended) canvas to keep // it in sync. copyCtxState(this.ctx, this.suspendedCtx); - // Don't bother calling save on the temporary canvas since state is not - // saved there. - this.suspendedCtx.save(); - } else { - this.ctx.save(); } + this.ctx.save(); const old = this.current; this.stateStack.push(old); this.current = old.clone(); } restore() { - if (this.stateStack.length === 0 && this.inSMaskMode) { - this.endSMaskMode(); - } - if (this.stateStack.length !== 0) { - this.current = this.stateStack.pop(); + if (this.stateStack.length === 0) { if (this.inSMaskMode) { - // Graphics state is stored on the main(suspended) canvas. Restore its - // state then copy it over to the temporary canvas. - this.suspendedCtx.restore(); - copyCtxState(this.suspendedCtx, this.ctx); - } else { - this.ctx.restore(); + this.endSMaskMode(); } - this.checkSMaskState(); - - // Ensure that the clipping path is reset (fixes issue6413.pdf). - this.pendingClip = null; - - this._cachedScaleForStroking[0] = -1; - this._cachedGetSinglePixelWidth = null; + return; } + + this.current = this.stateStack.pop(); + this.ctx.restore(); + if (this.inSMaskMode) { + // Graphics state is stored on the main(suspended) canvas. Restore its + // state then copy it over to the temporary canvas. + copyCtxState(this.suspendedCtx, this.ctx); + } + this.checkSMaskState(); + + // Ensure that the clipping path is reset (fixes issue6413.pdf). + this.pendingClip = null; + + this._cachedScaleForStroking[0] = -1; + this._cachedGetSinglePixelWidth = null; } transform(a, b, c, d, e, f) {