diff --git a/src/display/canvas.js b/src/display/canvas.js index aa151def2..8bf1a2de1 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -986,7 +986,7 @@ class CanvasGraphics { this.outputScaleY = 1; this.pageColors = pageColors; - this._cachedScaleForStroking = null; + this._cachedScaleForStroking = [-1, 0]; this._cachedGetSinglePixelWidth = null; this._cachedBitmapsMap = new Map(); } @@ -1395,7 +1395,7 @@ class CanvasGraphics { // Graphics state setLineWidth(width) { if (width !== this.current.lineWidth) { - this._cachedScaleForStroking = null; + this._cachedScaleForStroking[0] = -1; } this.current.lineWidth = width; this.ctx.lineWidth = width; @@ -1602,7 +1602,7 @@ class CanvasGraphics { // Ensure that the clipping path is reset (fixes issue6413.pdf). this.pendingClip = null; - this._cachedScaleForStroking = null; + this._cachedScaleForStroking[0] = -1; this._cachedGetSinglePixelWidth = null; } } @@ -1610,7 +1610,7 @@ class CanvasGraphics { transform(a, b, c, d, e, f) { this.ctx.transform(a, b, c, d, e, f); - this._cachedScaleForStroking = null; + this._cachedScaleForStroking[0] = -1; this._cachedGetSinglePixelWidth = null; } @@ -2297,7 +2297,7 @@ class CanvasGraphics { if (isTextInvisible || fontSize === 0) { return; } - this._cachedScaleForStroking = null; + this._cachedScaleForStroking[0] = -1; this._cachedGetSinglePixelWidth = null; ctx.save(); @@ -3160,16 +3160,23 @@ class CanvasGraphics { // The goal of this function is to rescale before setting the // lineWidth in order to have both thicknesses greater or equal // to 1 after transform. - if (!this._cachedScaleForStroking) { + if (this._cachedScaleForStroking[0] === -1) { const { lineWidth } = this.current; - const m = getCurrentTransform(this.ctx); + const { a, b, c, d } = this.ctx.getTransform(); let scaleX, scaleY; - if (m[1] === 0 && m[2] === 0) { + if (b === 0 && c === 0) { // Fast path - const normX = Math.abs(m[0]); - const normY = Math.abs(m[3]); - if (lineWidth === 0) { + const normX = Math.abs(a); + const normY = Math.abs(d); + if (normX === normY) { + if (lineWidth === 0) { + scaleX = scaleY = 1 / normX; + } else { + const scaledLineWidth = normX * lineWidth; + scaleX = scaleY = scaledLineWidth < 1 ? 1 / scaledLineWidth : 1; + } + } else if (lineWidth === 0) { scaleX = 1 / normX; scaleY = 1 / normY; } else { @@ -3185,9 +3192,9 @@ class CanvasGraphics { // - heightX (orthogonal to My) has a length: |det(M)| / norm(My). // heightX and heightY are the thicknesses of the transformed pixel // and they must be both greater or equal to 1. - const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]); - const normX = Math.hypot(m[0], m[1]); - const normY = Math.hypot(m[2], m[3]); + const absDet = Math.abs(a * d - b * c); + const normX = Math.hypot(a, b); + const normY = Math.hypot(c, d); if (lineWidth === 0) { scaleX = normY / absDet; scaleY = normX / absDet; @@ -3197,7 +3204,8 @@ class CanvasGraphics { scaleY = normX > baseArea ? normX / baseArea : 1; } } - this._cachedScaleForStroking = [scaleX, scaleY]; + this._cachedScaleForStroking[0] = scaleX; + this._cachedScaleForStroking[1] = scaleY; } return this._cachedScaleForStroking; } @@ -3216,11 +3224,9 @@ class CanvasGraphics { return; } - let savedMatrix, savedDashes, savedDashOffset; + const dashes = ctx.getLineDash(); if (saveRestore) { - savedMatrix = getCurrentTransform(ctx); - savedDashes = ctx.getLineDash().slice(); - savedDashOffset = ctx.lineDashOffset; + ctx.save(); } ctx.scale(scaleX, scaleY); @@ -3232,16 +3238,16 @@ class CanvasGraphics { // else we'll have some bugs (but only with too thin lines). // Here we take the max... why not taking the min... or something else. // Anyway, as said it's buggy when scaleX !== scaleY. - const scale = Math.max(scaleX, scaleY); - ctx.setLineDash(ctx.getLineDash().map(x => x / scale)); - ctx.lineDashOffset /= scale; + if (dashes.length > 0) { + const scale = Math.max(scaleX, scaleY); + ctx.setLineDash(dashes.map(x => x / scale)); + ctx.lineDashOffset /= scale; + } ctx.stroke(); if (saveRestore) { - ctx.setTransform(...savedMatrix); - ctx.setLineDash(savedDashes); - ctx.lineDashOffset = savedDashOffset; + ctx.restore(); } }