Merge pull request #15281 from Snuffleupagus/getTransform

Remove `mozCurrentTransform`/`mozCurrentTransformInverse` usage
This commit is contained in:
Tim van der Meij 2022-08-06 14:34:03 +02:00 committed by GitHub
commit d55903764e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 235 deletions

View File

@ -26,7 +26,12 @@ import {
Util, Util,
warn, warn,
} from "../shared/util.js"; } from "../shared/util.js";
import { getRGB, PixelsPerInch } from "./display_utils.js"; import {
getCurrentTransform,
getCurrentTransformInverse,
getRGB,
PixelsPerInch,
} from "./display_utils.js";
import { import {
getShadingPattern, getShadingPattern,
PathType, PathType,
@ -54,13 +59,6 @@ const MAX_SIZE_TO_COMPILE = 1000;
const FULL_CHUNK_HEIGHT = 16; const FULL_CHUNK_HEIGHT = 16;
// Because of https://bugs.chromium.org/p/chromium/issues/detail?id=1170396
// some curves aren't rendered correctly.
// Multiplying lineWidth by this factor should help to have "correct"
// rendering with no artifacts.
// Once the bug is fixed upstream, we can remove this constant and its use.
const LINEWIDTH_SCALE_FACTOR = 1.000001;
/** /**
* Overrides certain methods on a 2d ctx so that when they are called they * Overrides certain methods on a 2d ctx so that when they are called they
* will also call the same method on the destCtx. The methods that are * will also call the same method on the destCtx. The methods that are
@ -191,177 +189,21 @@ function mirrorContextOperations(ctx, destCtx) {
}; };
} }
function addContextCurrentTransform(ctx) {
if (ctx._transformStack) {
// Reset the transform stack.
ctx._transformStack = [];
}
// If the context doesn't expose a `mozCurrentTransform`, add a JS based one.
if (ctx.mozCurrentTransform) {
return;
}
ctx._originalSave = ctx.save;
ctx._originalRestore = ctx.restore;
ctx._originalRotate = ctx.rotate;
ctx._originalScale = ctx.scale;
ctx._originalTranslate = ctx.translate;
ctx._originalTransform = ctx.transform;
ctx._originalSetTransform = ctx.setTransform;
ctx._originalResetTransform = ctx.resetTransform;
ctx._transformMatrix = ctx._transformMatrix || [1, 0, 0, 1, 0, 0];
ctx._transformStack = [];
try {
// The call to getOwnPropertyDescriptor throws an exception in Node.js:
// "TypeError: Method lineWidth called on incompatible receiver
// #<CanvasRenderingContext2D>".
const desc = Object.getOwnPropertyDescriptor(
Object.getPrototypeOf(ctx),
"lineWidth"
);
ctx._setLineWidth = desc.set;
ctx._getLineWidth = desc.get;
Object.defineProperty(ctx, "lineWidth", {
set: function setLineWidth(width) {
this._setLineWidth(width * LINEWIDTH_SCALE_FACTOR);
},
get: function getLineWidth() {
return this._getLineWidth();
},
});
} catch (_) {}
Object.defineProperty(ctx, "mozCurrentTransform", {
get: function getCurrentTransform() {
return this._transformMatrix;
},
});
Object.defineProperty(ctx, "mozCurrentTransformInverse", {
get: function getCurrentTransformInverse() {
// Calculation done using WolframAlpha:
// http://www.wolframalpha.com/input/?
// i=Inverse+{{a%2C+c%2C+e}%2C+{b%2C+d%2C+f}%2C+{0%2C+0%2C+1}}
const [a, b, c, d, e, f] = this._transformMatrix;
const ad_bc = a * d - b * c;
const bc_ad = b * c - a * d;
return [
d / ad_bc,
b / bc_ad,
c / bc_ad,
a / ad_bc,
(d * e - c * f) / bc_ad,
(b * e - a * f) / ad_bc,
];
},
});
ctx.save = function ctxSave() {
const old = this._transformMatrix;
this._transformStack.push(old);
this._transformMatrix = old.slice(0, 6);
this._originalSave();
};
ctx.restore = function ctxRestore() {
if (this._transformStack.length === 0) {
warn("Tried to restore a ctx when the stack was already empty.");
}
const prev = this._transformStack.pop();
if (prev) {
this._transformMatrix = prev;
this._originalRestore();
}
};
ctx.translate = function ctxTranslate(x, y) {
const m = this._transformMatrix;
m[4] = m[0] * x + m[2] * y + m[4];
m[5] = m[1] * x + m[3] * y + m[5];
this._originalTranslate(x, y);
};
ctx.scale = function ctxScale(x, y) {
const m = this._transformMatrix;
m[0] *= x;
m[1] *= x;
m[2] *= y;
m[3] *= y;
this._originalScale(x, y);
};
ctx.transform = function ctxTransform(a, b, c, d, e, f) {
const m = this._transformMatrix;
this._transformMatrix = [
m[0] * a + m[2] * b,
m[1] * a + m[3] * b,
m[0] * c + m[2] * d,
m[1] * c + m[3] * d,
m[0] * e + m[2] * f + m[4],
m[1] * e + m[3] * f + m[5],
];
ctx._originalTransform(a, b, c, d, e, f);
};
ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
this._transformMatrix = [a, b, c, d, e, f];
ctx._originalSetTransform(a, b, c, d, e, f);
};
ctx.resetTransform = function ctxResetTransform() {
this._transformMatrix = [1, 0, 0, 1, 0, 0];
ctx._originalResetTransform();
};
ctx.rotate = function ctxRotate(angle) {
const cosValue = Math.cos(angle);
const sinValue = Math.sin(angle);
const m = this._transformMatrix;
this._transformMatrix = [
m[0] * cosValue + m[2] * sinValue,
m[1] * cosValue + m[3] * sinValue,
m[0] * -sinValue + m[2] * cosValue,
m[1] * -sinValue + m[3] * cosValue,
m[4],
m[5],
];
this._originalRotate(angle);
};
}
class CachedCanvases { class CachedCanvases {
constructor(canvasFactory) { constructor(canvasFactory) {
this.canvasFactory = canvasFactory; this.canvasFactory = canvasFactory;
this.cache = Object.create(null); this.cache = Object.create(null);
} }
getCanvas(id, width, height, trackTransform) { getCanvas(id, width, height) {
let canvasEntry; let canvasEntry;
if (this.cache[id] !== undefined) { if (this.cache[id] !== undefined) {
canvasEntry = this.cache[id]; canvasEntry = this.cache[id];
this.canvasFactory.reset(canvasEntry, width, height); this.canvasFactory.reset(canvasEntry, width, height);
// reset canvas transform for emulated mozCurrentTransform, if needed
canvasEntry.context.setTransform(1, 0, 0, 1, 0, 0);
} else { } else {
canvasEntry = this.canvasFactory.create(width, height); canvasEntry = this.canvasFactory.create(width, height);
this.cache[id] = canvasEntry; this.cache[id] = canvasEntry;
} }
if (trackTransform) {
addContextCurrentTransform(canvasEntry.context);
}
return canvasEntry; return canvasEntry;
} }
@ -390,7 +232,7 @@ function drawImageAtIntegerCoords(
destW, destW,
destH destH
) { ) {
const [a, b, c, d, tx, ty] = ctx.mozCurrentTransform; const [a, b, c, d, tx, ty] = getCurrentTransform(ctx);
if (b === 0 && c === 0) { if (b === 0 && c === 0) {
// top-left corner is at (X, Y) and // top-left corner is at (X, Y) and
// bottom-right one is at (X + width, Y + height). // bottom-right one is at (X + width, Y + height).
@ -1250,11 +1092,7 @@ class CanvasGraphics {
this.outputScaleY = 1; this.outputScaleY = 1;
this.backgroundColor = pageColors?.background || null; this.backgroundColor = pageColors?.background || null;
this.foregroundColor = pageColors?.foreground || null; this.foregroundColor = pageColors?.foreground || null;
if (canvasCtx) {
// NOTE: if mozCurrentTransform is polyfilled, then the current state of
// the transformation must already be set in canvasCtx._transformMatrix.
addContextCurrentTransform(canvasCtx);
}
this._cachedScaleForStroking = null; this._cachedScaleForStroking = null;
this._cachedGetSinglePixelWidth = null; this._cachedGetSinglePixelWidth = null;
this._cachedBitmapsMap = new Map(); this._cachedBitmapsMap = new Map();
@ -1350,8 +1188,7 @@ class CanvasGraphics {
const transparentCanvas = this.cachedCanvases.getCanvas( const transparentCanvas = this.cachedCanvases.getCanvas(
"transparent", "transparent",
width, width,
height, height
/* trackTransform */ true
); );
this.compositeCtx = this.ctx; this.compositeCtx = this.ctx;
this.transparentCanvas = transparentCanvas.canvas; this.transparentCanvas = transparentCanvas.canvas;
@ -1359,7 +1196,7 @@ class CanvasGraphics {
this.ctx.save(); this.ctx.save();
// The transform can be applied before rendering, transferring it to // The transform can be applied before rendering, transferring it to
// the new canvas. // the new canvas.
this.ctx.transform(...this.compositeCtx.mozCurrentTransform); this.ctx.transform(...getCurrentTransform(this.compositeCtx));
} }
this.ctx.save(); this.ctx.save();
@ -1372,7 +1209,7 @@ class CanvasGraphics {
this.ctx.transform(...viewport.transform); this.ctx.transform(...viewport.transform);
this.viewportScale = viewport.scale; this.viewportScale = viewport.scale;
this.baseTransform = this.ctx.mozCurrentTransform.slice(); this.baseTransform = getCurrentTransform(this.ctx);
if (this.imageLayer) { if (this.imageLayer) {
this.imageLayer.beginLayout(); this.imageLayer.beginLayout();
@ -1529,8 +1366,7 @@ class CanvasGraphics {
tmpCanvas = this.cachedCanvases.getCanvas( tmpCanvas = this.cachedCanvases.getCanvas(
tmpCanvasId, tmpCanvasId,
newWidth, newWidth,
newHeight, newHeight
/* trackTransform */ false
); );
tmpCtx = tmpCanvas.context; tmpCtx = tmpCanvas.context;
tmpCtx.clearRect(0, 0, newWidth, newHeight); tmpCtx.clearRect(0, 0, newWidth, newHeight);
@ -1562,7 +1398,7 @@ class CanvasGraphics {
const { width, height } = img; const { width, height } = img;
const fillColor = this.current.fillColor; const fillColor = this.current.fillColor;
const isPatternFill = this.current.patternFill; const isPatternFill = this.current.patternFill;
const currentTransform = ctx.mozCurrentTransform; const currentTransform = getCurrentTransform(ctx);
let cache, cacheKey, scaled, maskCanvas; let cache, cacheKey, scaled, maskCanvas;
if ((img.bitmap || img.data) && img.count > 1) { if ((img.bitmap || img.data) && img.count > 1) {
@ -1603,12 +1439,7 @@ class CanvasGraphics {
} }
if (!scaled) { if (!scaled) {
maskCanvas = this.cachedCanvases.getCanvas( maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
"maskCanvas",
width,
height,
/* trackTransform */ false
);
putBinaryImageMask(maskCanvas.context, img); putBinaryImageMask(maskCanvas.context, img);
} }
@ -1634,8 +1465,7 @@ class CanvasGraphics {
const fillCanvas = this.cachedCanvases.getCanvas( const fillCanvas = this.cachedCanvases.getCanvas(
"fillCanvas", "fillCanvas",
drawnWidth, drawnWidth,
drawnHeight, drawnHeight
/* trackTransform */ true
); );
const fillCtx = fillCanvas.context; const fillCtx = fillCanvas.context;
@ -1652,7 +1482,7 @@ class CanvasGraphics {
// Pre-scale if needed to improve image smoothing. // Pre-scale if needed to improve image smoothing.
scaled = this._scaleImage( scaled = this._scaleImage(
maskCanvas.canvas, maskCanvas.canvas,
fillCtx.mozCurrentTransformInverse getCurrentTransformInverse(fillCtx)
); );
scaled = scaled.img; scaled = scaled.img;
if (cache && isPatternFill) { if (cache && isPatternFill) {
@ -1661,7 +1491,7 @@ class CanvasGraphics {
} }
fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled( fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled(
fillCtx.mozCurrentTransform, getCurrentTransform(fillCtx),
img.interpolate img.interpolate
); );
@ -1679,7 +1509,7 @@ class CanvasGraphics {
); );
fillCtx.globalCompositeOperation = "source-in"; fillCtx.globalCompositeOperation = "source-in";
const inverse = Util.transform(fillCtx.mozCurrentTransformInverse, [ const inverse = Util.transform(getCurrentTransformInverse(fillCtx), [
1, 1,
0, 0,
0, 0,
@ -1830,13 +1660,12 @@ class CanvasGraphics {
const scratchCanvas = this.cachedCanvases.getCanvas( const scratchCanvas = this.cachedCanvases.getCanvas(
cacheId, cacheId,
drawnWidth, drawnWidth,
drawnHeight, drawnHeight
/* trackTransform */ true
); );
this.suspendedCtx = this.ctx; this.suspendedCtx = this.ctx;
this.ctx = scratchCanvas.context; this.ctx = scratchCanvas.context;
const ctx = this.ctx; const ctx = this.ctx;
ctx.setTransform(...this.suspendedCtx.mozCurrentTransform); ctx.setTransform(...getCurrentTransform(this.suspendedCtx));
copyCtxState(this.suspendedCtx, ctx); copyCtxState(this.suspendedCtx, ctx);
mirrorContextOperations(ctx, this.suspendedCtx); mirrorContextOperations(ctx, this.suspendedCtx);
@ -1940,7 +1769,7 @@ class CanvasGraphics {
let x = current.x, let x = current.x,
y = current.y; y = current.y;
let startX, startY; let startX, startY;
const currentTransform = ctx.mozCurrentTransform; const currentTransform = getCurrentTransform(ctx);
// Most of the time the current transform is a scaling matrix // Most of the time the current transform is a scaling matrix
// so we don't need to transform points before computing min/max: // so we don't need to transform points before computing min/max:
@ -2096,7 +1925,7 @@ class CanvasGraphics {
ctx.strokeStyle = strokeColor.getPattern( ctx.strokeStyle = strokeColor.getPattern(
ctx, ctx,
this, this,
ctx.mozCurrentTransformInverse, getCurrentTransformInverse(ctx),
PathType.STROKE PathType.STROKE
); );
this.rescaleAndStroke(/* saveRestore */ false); this.rescaleAndStroke(/* saveRestore */ false);
@ -2129,7 +1958,7 @@ class CanvasGraphics {
ctx.fillStyle = fillColor.getPattern( ctx.fillStyle = fillColor.getPattern(
ctx, ctx,
this, this,
ctx.mozCurrentTransformInverse, getCurrentTransformInverse(ctx),
PathType.FILL PathType.FILL
); );
needRestore = true; needRestore = true;
@ -2383,7 +2212,7 @@ class CanvasGraphics {
if (isAddToPathSet) { if (isAddToPathSet) {
const paths = this.pendingTextPaths || (this.pendingTextPaths = []); const paths = this.pendingTextPaths || (this.pendingTextPaths = []);
paths.push({ paths.push({
transform: ctx.mozCurrentTransform, transform: getCurrentTransform(ctx),
x, x,
y, y,
fontSize, fontSize,
@ -2398,8 +2227,7 @@ class CanvasGraphics {
const { context: ctx } = this.cachedCanvases.getCanvas( const { context: ctx } = this.cachedCanvases.getCanvas(
"isFontSubpixelAAEnabled", "isFontSubpixelAAEnabled",
10, 10,
10, 10
/* trackTransform */ false
); );
ctx.scale(1.5, 1); ctx.scale(1.5, 1);
ctx.fillText("I", 0, 10); ctx.fillText("I", 0, 10);
@ -2459,10 +2287,10 @@ class CanvasGraphics {
const pattern = current.fillColor.getPattern( const pattern = current.fillColor.getPattern(
ctx, ctx,
this, this,
ctx.mozCurrentTransformInverse, getCurrentTransformInverse(ctx),
PathType.FILL PathType.FILL
); );
patternTransform = ctx.mozCurrentTransform; patternTransform = getCurrentTransform(ctx);
ctx.restore(); ctx.restore();
ctx.fillStyle = pattern; ctx.fillStyle = pattern;
} }
@ -2663,8 +2491,7 @@ class CanvasGraphics {
let pattern; let pattern;
if (IR[0] === "TilingPattern") { if (IR[0] === "TilingPattern") {
const color = IR[1]; const color = IR[1];
const baseTransform = const baseTransform = this.baseTransform || getCurrentTransform(this.ctx);
this.baseTransform || this.ctx.mozCurrentTransform.slice();
const canvasGraphicsFactory = { const canvasGraphicsFactory = {
createCanvasGraphics: ctx => { createCanvasGraphics: ctx => {
return new CanvasGraphics( return new CanvasGraphics(
@ -2735,11 +2562,11 @@ class CanvasGraphics {
ctx.fillStyle = pattern.getPattern( ctx.fillStyle = pattern.getPattern(
ctx, ctx,
this, this,
ctx.mozCurrentTransformInverse, getCurrentTransformInverse(ctx),
PathType.SHADING PathType.SHADING
); );
const inv = ctx.mozCurrentTransformInverse; const inv = getCurrentTransformInverse(ctx);
if (inv) { if (inv) {
const canvas = ctx.canvas; const canvas = ctx.canvas;
const width = canvas.width; const width = canvas.width;
@ -2790,13 +2617,13 @@ class CanvasGraphics {
this.transform(...matrix); this.transform(...matrix);
} }
this.baseTransform = this.ctx.mozCurrentTransform; this.baseTransform = getCurrentTransform(this.ctx);
if (bbox) { if (bbox) {
const width = bbox[2] - bbox[0]; const width = bbox[2] - bbox[0];
const height = bbox[3] - bbox[1]; const height = bbox[3] - bbox[1];
this.ctx.rect(bbox[0], bbox[1], width, height); this.ctx.rect(bbox[0], bbox[1], width, height);
this.current.updateRectMinMax(this.ctx.mozCurrentTransform, bbox); this.current.updateRectMinMax(getCurrentTransform(this.ctx), bbox);
this.clip(); this.clip();
this.endPath(); this.endPath();
} }
@ -2847,7 +2674,7 @@ class CanvasGraphics {
warn("Knockout groups not supported."); warn("Knockout groups not supported.");
} }
const currentTransform = currentCtx.mozCurrentTransform; const currentTransform = getCurrentTransform(currentCtx);
if (group.matrix) { if (group.matrix) {
currentCtx.transform(...group.matrix); currentCtx.transform(...group.matrix);
} }
@ -2859,7 +2686,7 @@ class CanvasGraphics {
// will actually be. // will actually be.
let bounds = Util.getAxialAlignedBoundingBox( let bounds = Util.getAxialAlignedBoundingBox(
group.bbox, group.bbox,
currentCtx.mozCurrentTransform getCurrentTransform(currentCtx)
); );
// Clip the bounding box to the current canvas. // Clip the bounding box to the current canvas.
const canvasBounds = [ const canvasBounds = [
@ -2896,8 +2723,7 @@ class CanvasGraphics {
const scratchCanvas = this.cachedCanvases.getCanvas( const scratchCanvas = this.cachedCanvases.getCanvas(
cacheId, cacheId,
drawnWidth, drawnWidth,
drawnHeight, drawnHeight
/* trackTransform */ true
); );
const groupCtx = scratchCanvas.context; const groupCtx = scratchCanvas.context;
@ -2959,7 +2785,7 @@ class CanvasGraphics {
this.restore(); this.restore();
} else { } else {
this.ctx.restore(); this.ctx.restore();
const currentMtx = this.ctx.mozCurrentTransform; const currentMtx = getCurrentTransform(this.ctx);
this.restore(); this.restore();
this.ctx.save(); this.ctx.save();
this.ctx.setTransform(...currentMtx); this.ctx.setTransform(...currentMtx);
@ -3003,7 +2829,7 @@ class CanvasGraphics {
rect[3] = height; rect[3] = height;
const [scaleX, scaleY] = Util.singularValueDecompose2dScale( const [scaleX, scaleY] = Util.singularValueDecompose2dScale(
this.ctx.mozCurrentTransform getCurrentTransform(this.ctx)
); );
const { viewportScale } = this; const { viewportScale } = this;
const canvasWidth = Math.ceil( const canvasWidth = Math.ceil(
@ -3021,7 +2847,6 @@ class CanvasGraphics {
this.annotationCanvasMap.set(id, canvas); this.annotationCanvasMap.set(id, canvas);
this.annotationCanvas.savedCtx = this.ctx; this.annotationCanvas.savedCtx = this.ctx;
this.ctx = context; this.ctx = context;
addContextCurrentTransform(this.ctx);
this.ctx.setTransform(scaleX, 0, 0, -scaleY, 0, height * scaleY); this.ctx.setTransform(scaleX, 0, 0, -scaleY, 0, height * scaleY);
resetCtxToDefault(this.ctx, this.foregroundColor); resetCtxToDefault(this.ctx, this.foregroundColor);
@ -3100,7 +2925,7 @@ class CanvasGraphics {
const ctx = this.ctx; const ctx = this.ctx;
ctx.save(); ctx.save();
const currentTransform = ctx.mozCurrentTransform; const currentTransform = getCurrentTransform(ctx);
ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0); ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
const mask = this._createMaskCanvas(img); const mask = this._createMaskCanvas(img);
@ -3137,8 +2962,7 @@ class CanvasGraphics {
const maskCanvas = this.cachedCanvases.getCanvas( const maskCanvas = this.cachedCanvases.getCanvas(
"maskCanvas", "maskCanvas",
width, width,
height, height
/* trackTransform */ false
); );
const maskCtx = maskCanvas.context; const maskCtx = maskCanvas.context;
maskCtx.save(); maskCtx.save();
@ -3152,7 +2976,7 @@ class CanvasGraphics {
? fillColor.getPattern( ? fillColor.getPattern(
maskCtx, maskCtx,
this, this,
ctx.mozCurrentTransformInverse, getCurrentTransformInverse(ctx),
PathType.FILL PathType.FILL
) )
: fillColor; : fillColor;
@ -3241,17 +3065,19 @@ class CanvasGraphics {
const tmpCanvas = this.cachedCanvases.getCanvas( const tmpCanvas = this.cachedCanvases.getCanvas(
"inlineImage", "inlineImage",
width, width,
height, height
/* trackTransform */ false
); );
const tmpCtx = tmpCanvas.context; const tmpCtx = tmpCanvas.context;
putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
imgToPaint = tmpCanvas.canvas; imgToPaint = tmpCanvas.canvas;
} }
const scaled = this._scaleImage(imgToPaint, ctx.mozCurrentTransformInverse); const scaled = this._scaleImage(
imgToPaint,
getCurrentTransformInverse(ctx)
);
ctx.imageSmoothingEnabled = getImageSmoothingEnabled( ctx.imageSmoothingEnabled = getImageSmoothingEnabled(
ctx.mozCurrentTransform, getCurrentTransform(ctx),
imgData.interpolate imgData.interpolate
); );
@ -3290,12 +3116,7 @@ class CanvasGraphics {
const w = imgData.width; const w = imgData.width;
const h = imgData.height; const h = imgData.height;
const tmpCanvas = this.cachedCanvases.getCanvas( const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
"inlineImage",
w,
h,
/* trackTransform */ false
);
const tmpCtx = tmpCanvas.context; const tmpCtx = tmpCanvas.context;
putBinaryImageData(tmpCtx, imgData, this.current.transferMaps); putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
@ -3409,7 +3230,7 @@ class CanvasGraphics {
getSinglePixelWidth() { getSinglePixelWidth() {
if (!this._cachedGetSinglePixelWidth) { if (!this._cachedGetSinglePixelWidth) {
const m = this.ctx.mozCurrentTransform; const m = getCurrentTransform(this.ctx);
if (m[1] === 0 && m[2] === 0) { if (m[1] === 0 && m[2] === 0) {
// Fast path // Fast path
this._cachedGetSinglePixelWidth = this._cachedGetSinglePixelWidth =
@ -3433,7 +3254,7 @@ class CanvasGraphics {
// to 1 after transform. // to 1 after transform.
if (!this._cachedScaleForStroking) { if (!this._cachedScaleForStroking) {
const { lineWidth } = this.current; const { lineWidth } = this.current;
const m = this.ctx.mozCurrentTransform; const m = getCurrentTransform(this.ctx);
let scaleX, scaleY; let scaleX, scaleY;
if (m[1] === 0 && m[2] === 0) { if (m[1] === 0 && m[2] === 0) {
@ -3489,7 +3310,7 @@ class CanvasGraphics {
let savedMatrix, savedDashes, savedDashOffset; let savedMatrix, savedDashes, savedDashOffset;
if (saveRestore) { if (saveRestore) {
savedMatrix = ctx.mozCurrentTransform.slice(); savedMatrix = getCurrentTransform(ctx);
savedDashes = ctx.getLineDash().slice(); savedDashes = ctx.getLineDash().slice();
savedDashOffset = ctx.lineDashOffset; savedDashOffset = ctx.lineDashOffset;
} }
@ -3517,7 +3338,7 @@ class CanvasGraphics {
} }
getCanvasPosition(x, y) { getCanvasPosition(x, y) {
const transform = this.ctx.mozCurrentTransform; const transform = getCurrentTransform(this.ctx);
return [ return [
transform[0] * x + transform[2] * y + transform[4], transform[0] * x + transform[2] * y + transform[4],
transform[1] * x + transform[3] * y + transform[5], transform[1] * x + transform[3] * y + transform[5],

View File

@ -641,6 +641,16 @@ function binarySearchFirstItem(items, condition, start = 0) {
return minIndex; /* === maxIndex */ return minIndex; /* === maxIndex */
} }
function getCurrentTransform(ctx) {
const { a, b, c, d, e, f } = ctx.getTransform();
return [a, b, c, d, e, f];
}
function getCurrentTransformInverse(ctx) {
const { a, b, c, d, e, f } = ctx.getTransform().invertSelf();
return [a, b, c, d, e, f];
}
export { export {
binarySearchFirstItem, binarySearchFirstItem,
deprecated, deprecated,
@ -649,6 +659,8 @@ export {
DOMStandardFontDataFactory, DOMStandardFontDataFactory,
DOMSVGFactory, DOMSVGFactory,
getColorValues, getColorValues,
getCurrentTransform,
getCurrentTransformInverse,
getFilenameFromUrl, getFilenameFromUrl,
getPdfFilenameFromUrl, getPdfFilenameFromUrl,
getRGB, getRGB,

View File

@ -21,6 +21,7 @@ import {
Util, Util,
warn, warn,
} from "../shared/util.js"; } from "../shared/util.js";
import { getCurrentTransform } from "./display_utils.js";
import { isNodeJS } from "../shared/is_node.js"; import { isNodeJS } from "../shared/is_node.js";
const PathType = { const PathType = {
@ -96,7 +97,7 @@ class RadialAxialShadingPattern extends BaseShadingPattern {
if (pathType === PathType.STROKE || pathType === PathType.FILL) { if (pathType === PathType.STROKE || pathType === PathType.FILL) {
const ownerBBox = owner.current.getClippedPathBoundingBox( const ownerBBox = owner.current.getClippedPathBoundingBox(
pathType, pathType,
ctx.mozCurrentTransform getCurrentTransform(ctx)
) || [0, 0, 0, 0]; ) || [0, 0, 0, 0];
// Create a canvas that is only as big as the current path. This doesn't // Create a canvas that is only as big as the current path. This doesn't
// allow us to cache the pattern, but it generally creates much smaller // allow us to cache the pattern, but it generally creates much smaller
@ -409,7 +410,7 @@ class MeshShadingPattern extends BaseShadingPattern {
applyBoundingBox(ctx, this._bbox); applyBoundingBox(ctx, this._bbox);
let scale; let scale;
if (pathType === PathType.SHADING) { if (pathType === PathType.SHADING) {
scale = Util.singularValueDecompose2dScale(ctx.mozCurrentTransform); scale = Util.singularValueDecompose2dScale(getCurrentTransform(ctx));
} else { } else {
// Obtain scale from matrix and current transformation matrix. // Obtain scale from matrix and current transformation matrix.
scale = Util.singularValueDecompose2dScale(owner.baseTransform); scale = Util.singularValueDecompose2dScale(owner.baseTransform);
@ -584,7 +585,7 @@ class TilingPattern {
this.clipBbox(graphics, adjustedX0, adjustedY0, adjustedX1, adjustedY1); this.clipBbox(graphics, adjustedX0, adjustedY0, adjustedX1, adjustedY1);
graphics.baseTransform = graphics.ctx.mozCurrentTransform.slice(); graphics.baseTransform = getCurrentTransform(graphics.ctx);
graphics.executeOperatorList(operatorList); graphics.executeOperatorList(operatorList);
@ -620,7 +621,7 @@ class TilingPattern {
const bboxWidth = x1 - x0; const bboxWidth = x1 - x0;
const bboxHeight = y1 - y0; const bboxHeight = y1 - y0;
graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight); graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight);
graphics.current.updateRectMinMax(graphics.ctx.mozCurrentTransform, [ graphics.current.updateRectMinMax(getCurrentTransform(graphics.ctx), [
x0, x0,
y0, y0,
x1, x1,