Merge pull request #16448 from calixteman/improve_rescaleandstroke

Improve performance of canvas::rescaleAndStroke by around 30% (bug 1135277)
This commit is contained in:
calixteman 2023-05-20 21:06:40 +02:00 committed by GitHub
commit 65e23432cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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();
}
}