|
@@ -35,7 +35,6 @@ var _display_utils = require("./display_utils.js");
|
|
const MIN_FONT_SIZE = 16;
|
|
const MIN_FONT_SIZE = 16;
|
|
const MAX_FONT_SIZE = 100;
|
|
const MAX_FONT_SIZE = 100;
|
|
const MAX_GROUP_SIZE = 4096;
|
|
const MAX_GROUP_SIZE = 4096;
|
|
-const MAX_CACHED_CANVAS_PATTERNS = 2;
|
|
|
|
const EXECUTION_TIME = 15;
|
|
const EXECUTION_TIME = 15;
|
|
const EXECUTION_STEPS = 10;
|
|
const EXECUTION_STEPS = 10;
|
|
const COMPILE_TYPE3_GLYPHS = true;
|
|
const COMPILE_TYPE3_GLYPHS = true;
|
|
@@ -43,6 +42,137 @@ const MAX_SIZE_TO_COMPILE = 1000;
|
|
const FULL_CHUNK_HEIGHT = 16;
|
|
const FULL_CHUNK_HEIGHT = 16;
|
|
const LINEWIDTH_SCALE_FACTOR = 1.000001;
|
|
const LINEWIDTH_SCALE_FACTOR = 1.000001;
|
|
|
|
|
|
|
|
+function mirrorContextOperations(ctx, destCtx) {
|
|
|
|
+ if (ctx._removeMirroring) {
|
|
|
|
+ throw new Error("Context is already forwarding operations.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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.__originalClip = ctx.clip;
|
|
|
|
+ ctx.__originalMoveTo = ctx.moveTo;
|
|
|
|
+ ctx.__originalLineTo = ctx.lineTo;
|
|
|
|
+ ctx.__originalBezierCurveTo = ctx.bezierCurveTo;
|
|
|
|
+ ctx.__originalRect = ctx.rect;
|
|
|
|
+ ctx.__originalClosePath = ctx.closePath;
|
|
|
|
+ ctx.__originalBeginPath = ctx.beginPath;
|
|
|
|
+
|
|
|
|
+ ctx._removeMirroring = () => {
|
|
|
|
+ ctx.save = ctx.__originalSave;
|
|
|
|
+ ctx.restore = ctx.__originalRestore;
|
|
|
|
+ ctx.rotate = ctx.__originalRotate;
|
|
|
|
+ ctx.scale = ctx.__originalScale;
|
|
|
|
+ ctx.translate = ctx.__originalTranslate;
|
|
|
|
+ ctx.transform = ctx.__originalTransform;
|
|
|
|
+ ctx.setTransform = ctx.__originalSetTransform;
|
|
|
|
+ ctx.resetTransform = ctx.__originalResetTransform;
|
|
|
|
+ ctx.clip = ctx.__originalClip;
|
|
|
|
+ ctx.moveTo = ctx.__originalMoveTo;
|
|
|
|
+ ctx.lineTo = ctx.__originalLineTo;
|
|
|
|
+ ctx.bezierCurveTo = ctx.__originalBezierCurveTo;
|
|
|
|
+ ctx.rect = ctx.__originalRect;
|
|
|
|
+ ctx.closePath = ctx.__originalClosePath;
|
|
|
|
+ ctx.beginPath = ctx.__originalBeginPath;
|
|
|
|
+ delete ctx._removeMirroring;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.save = function ctxSave() {
|
|
|
|
+ destCtx.save();
|
|
|
|
+
|
|
|
|
+ this.__originalSave();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.restore = function ctxRestore() {
|
|
|
|
+ destCtx.restore();
|
|
|
|
+
|
|
|
|
+ this.__originalRestore();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.translate = function ctxTranslate(x, y) {
|
|
|
|
+ destCtx.translate(x, y);
|
|
|
|
+
|
|
|
|
+ this.__originalTranslate(x, y);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.scale = function ctxScale(x, y) {
|
|
|
|
+ destCtx.scale(x, y);
|
|
|
|
+
|
|
|
|
+ this.__originalScale(x, y);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.transform = function ctxTransform(a, b, c, d, e, f) {
|
|
|
|
+ destCtx.transform(a, b, c, d, e, f);
|
|
|
|
+
|
|
|
|
+ this.__originalTransform(a, b, c, d, e, f);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.setTransform = function ctxSetTransform(a, b, c, d, e, f) {
|
|
|
|
+ destCtx.setTransform(a, b, c, d, e, f);
|
|
|
|
+
|
|
|
|
+ this.__originalSetTransform(a, b, c, d, e, f);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.resetTransform = function ctxResetTransform() {
|
|
|
|
+ destCtx.resetTransform();
|
|
|
|
+
|
|
|
|
+ this.__originalResetTransform();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.rotate = function ctxRotate(angle) {
|
|
|
|
+ destCtx.rotate(angle);
|
|
|
|
+
|
|
|
|
+ this.__originalRotate(angle);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.clip = function ctxRotate(rule) {
|
|
|
|
+ destCtx.clip(rule);
|
|
|
|
+
|
|
|
|
+ this.__originalClip(rule);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.moveTo = function (x, y) {
|
|
|
|
+ destCtx.moveTo(x, y);
|
|
|
|
+
|
|
|
|
+ this.__originalMoveTo(x, y);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.lineTo = function (x, y) {
|
|
|
|
+ destCtx.lineTo(x, y);
|
|
|
|
+
|
|
|
|
+ this.__originalLineTo(x, y);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
|
|
+ destCtx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
|
|
|
+
|
|
|
|
+ this.__originalBezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.rect = function (x, y, width, height) {
|
|
|
|
+ destCtx.rect(x, y, width, height);
|
|
|
|
+
|
|
|
|
+ this.__originalRect(x, y, width, height);
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.closePath = function () {
|
|
|
|
+ destCtx.closePath();
|
|
|
|
+
|
|
|
|
+ this.__originalClosePath();
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ ctx.beginPath = function () {
|
|
|
|
+ destCtx.beginPath();
|
|
|
|
+
|
|
|
|
+ this.__originalBeginPath();
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
function addContextCurrentTransform(ctx) {
|
|
function addContextCurrentTransform(ctx) {
|
|
if (ctx.mozCurrentTransform) {
|
|
if (ctx.mozCurrentTransform) {
|
|
return;
|
|
return;
|
|
@@ -189,46 +319,6 @@ class CachedCanvases {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-class LRUCache {
|
|
|
|
- constructor(maxSize = 0) {
|
|
|
|
- this._cache = new Map();
|
|
|
|
- this._maxSize = maxSize;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- has(key) {
|
|
|
|
- return this._cache.has(key);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- get(key) {
|
|
|
|
- if (this._cache.has(key)) {
|
|
|
|
- const value = this._cache.get(key);
|
|
|
|
-
|
|
|
|
- this._cache.delete(key);
|
|
|
|
-
|
|
|
|
- this._cache.set(key, value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return this._cache.get(key);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- set(key, value) {
|
|
|
|
- if (this._maxSize <= 0) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (this._cache.size + 1 > this._maxSize) {
|
|
|
|
- this._cache.delete(this._cache.keys().next().value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this._cache.set(key, value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- clear() {
|
|
|
|
- this._cache.clear();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
function compileType3Glyph(imgData) {
|
|
function compileType3Glyph(imgData) {
|
|
const POINT_TO_PROCESS_LIMIT = 1000;
|
|
const POINT_TO_PROCESS_LIMIT = 1000;
|
|
const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
|
|
const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
|
|
@@ -403,7 +493,7 @@ function compileType3Glyph(imgData) {
|
|
}
|
|
}
|
|
|
|
|
|
class CanvasExtraState {
|
|
class CanvasExtraState {
|
|
- constructor() {
|
|
|
|
|
|
+ constructor(width, height) {
|
|
this.alphaIsShape = false;
|
|
this.alphaIsShape = false;
|
|
this.fontSize = 0;
|
|
this.fontSize = 0;
|
|
this.fontSizeScale = 1;
|
|
this.fontSizeScale = 1;
|
|
@@ -427,12 +517,14 @@ class CanvasExtraState {
|
|
this.strokeAlpha = 1;
|
|
this.strokeAlpha = 1;
|
|
this.lineWidth = 1;
|
|
this.lineWidth = 1;
|
|
this.activeSMask = null;
|
|
this.activeSMask = null;
|
|
- this.resumeSMaskCtx = null;
|
|
|
|
this.transferMaps = null;
|
|
this.transferMaps = null;
|
|
|
|
+ this.startNewPathAndClipBox([0, 0, width, height]);
|
|
}
|
|
}
|
|
|
|
|
|
clone() {
|
|
clone() {
|
|
- return Object.create(this);
|
|
|
|
|
|
+ const clone = Object.create(this);
|
|
|
|
+ clone.clipBox = this.clipBox.slice();
|
|
|
|
+ return clone;
|
|
}
|
|
}
|
|
|
|
|
|
setCurrentPoint(x, y) {
|
|
setCurrentPoint(x, y) {
|
|
@@ -440,6 +532,60 @@ class CanvasExtraState {
|
|
this.y = y;
|
|
this.y = y;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ updatePathMinMax(transform, x, y) {
|
|
|
|
+ [x, y] = _util.Util.applyTransform([x, y], transform);
|
|
|
|
+ this.minX = Math.min(this.minX, x);
|
|
|
|
+ this.minY = Math.min(this.minY, y);
|
|
|
|
+ this.maxX = Math.max(this.maxX, x);
|
|
|
|
+ this.maxY = Math.max(this.maxY, y);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ updateCurvePathMinMax(transform, x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
|
|
+ const box = _util.Util.bezierBoundingBox(x0, y0, x1, y1, x2, y2, x3, y3);
|
|
|
|
+
|
|
|
|
+ this.updatePathMinMax(transform, box[0], box[1]);
|
|
|
|
+ this.updatePathMinMax(transform, box[2], box[3]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getPathBoundingBox(pathType = _pattern_helper.PathType.FILL, transform = null) {
|
|
|
|
+ const box = [this.minX, this.minY, this.maxX, this.maxY];
|
|
|
|
+
|
|
|
|
+ if (pathType === _pattern_helper.PathType.STROKE) {
|
|
|
|
+ if (!transform) {
|
|
|
|
+ (0, _util.unreachable)("Stroke bounding box must include transform.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const scale = _util.Util.singularValueDecompose2dScale(transform);
|
|
|
|
+
|
|
|
|
+ const xStrokePad = scale[0] * this.lineWidth / 2;
|
|
|
|
+ const yStrokePad = scale[1] * this.lineWidth / 2;
|
|
|
|
+ box[0] -= xStrokePad;
|
|
|
|
+ box[1] -= yStrokePad;
|
|
|
|
+ box[2] += xStrokePad;
|
|
|
|
+ box[3] += yStrokePad;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return box;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ updateClipFromPath() {
|
|
|
|
+ const intersect = _util.Util.intersect(this.clipBox, this.getPathBoundingBox());
|
|
|
|
+
|
|
|
|
+ this.startNewPathAndClipBox(intersect || [0, 0, 0, 0]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ startNewPathAndClipBox(box) {
|
|
|
|
+ this.clipBox = box;
|
|
|
|
+ this.minX = Infinity;
|
|
|
|
+ this.minY = Infinity;
|
|
|
|
+ this.maxX = 0;
|
|
|
|
+ this.maxY = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ getClippedPathBoundingBox(pathType = _pattern_helper.PathType.FILL, transform = null) {
|
|
|
|
+ return _util.Util.intersect(this.clipBox, this.getPathBoundingBox(pathType, transform));
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
function putBinaryImageData(ctx, imgData, transferMaps = null) {
|
|
function putBinaryImageData(ctx, imgData, transferMaps = null) {
|
|
@@ -736,7 +882,7 @@ function composeSMaskLuminosity(maskData, layerData, transferMap) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap) {
|
|
|
|
|
|
+function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap, layerOffsetX, layerOffsetY, maskOffsetX, maskOffsetY) {
|
|
const hasBackdrop = !!backdrop;
|
|
const hasBackdrop = !!backdrop;
|
|
const r0 = hasBackdrop ? backdrop[0] : 0;
|
|
const r0 = hasBackdrop ? backdrop[0] : 0;
|
|
const g0 = hasBackdrop ? backdrop[1] : 0;
|
|
const g0 = hasBackdrop ? backdrop[1] : 0;
|
|
@@ -754,24 +900,35 @@ function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop
|
|
|
|
|
|
for (let row = 0; row < height; row += chunkSize) {
|
|
for (let row = 0; row < height; row += chunkSize) {
|
|
const chunkHeight = Math.min(chunkSize, height - row);
|
|
const chunkHeight = Math.min(chunkSize, height - row);
|
|
- const maskData = maskCtx.getImageData(0, row, width, chunkHeight);
|
|
|
|
- const layerData = layerCtx.getImageData(0, row, width, chunkHeight);
|
|
|
|
|
|
+ const maskData = maskCtx.getImageData(layerOffsetX - maskOffsetX, row + (layerOffsetY - maskOffsetY), width, chunkHeight);
|
|
|
|
+ const layerData = layerCtx.getImageData(layerOffsetX, row + layerOffsetY, width, chunkHeight);
|
|
|
|
|
|
if (hasBackdrop) {
|
|
if (hasBackdrop) {
|
|
composeSMaskBackdrop(maskData.data, r0, g0, b0);
|
|
composeSMaskBackdrop(maskData.data, r0, g0, b0);
|
|
}
|
|
}
|
|
|
|
|
|
composeFn(maskData.data, layerData.data, transferMap);
|
|
composeFn(maskData.data, layerData.data, transferMap);
|
|
- maskCtx.putImageData(layerData, 0, row);
|
|
|
|
|
|
+ layerCtx.putImageData(layerData, layerOffsetX, row + layerOffsetY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-function composeSMask(ctx, smask, layerCtx) {
|
|
|
|
- const mask = smask.canvas;
|
|
|
|
- const maskCtx = smask.context;
|
|
|
|
- ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY, smask.offsetX, smask.offsetY);
|
|
|
|
- genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height, smask.subtype, smask.backdrop, smask.transferMap);
|
|
|
|
- ctx.drawImage(mask, 0, 0);
|
|
|
|
|
|
+function composeSMask(ctx, smask, layerCtx, layerBox) {
|
|
|
|
+ const layerOffsetX = layerBox[0];
|
|
|
|
+ const layerOffsetY = layerBox[1];
|
|
|
|
+ const layerWidth = layerBox[2] - layerOffsetX;
|
|
|
|
+ const layerHeight = layerBox[3] - layerOffsetY;
|
|
|
|
+
|
|
|
|
+ if (layerWidth === 0 || layerHeight === 0) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ genericComposeSMask(smask.context, layerCtx, layerWidth, layerHeight, smask.subtype, smask.backdrop, smask.transferMap, layerOffsetX, layerOffsetY, smask.offsetX, smask.offsetY);
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.globalAlpha = 1;
|
|
|
|
+ ctx.globalCompositeOperation = "source-over";
|
|
|
|
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
+ ctx.drawImage(layerCtx.canvas, 0, 0);
|
|
|
|
+ ctx.restore();
|
|
}
|
|
}
|
|
|
|
|
|
function getImageSmoothingEnabled(transform, interpolate) {
|
|
function getImageSmoothingEnabled(transform, interpolate) {
|
|
@@ -796,9 +953,9 @@ const NORMAL_CLIP = {};
|
|
const EO_CLIP = {};
|
|
const EO_CLIP = {};
|
|
|
|
|
|
class CanvasGraphics {
|
|
class CanvasGraphics {
|
|
- constructor(canvasCtx, commonObjs, objs, canvasFactory, imageLayer, optionalContentConfig) {
|
|
|
|
|
|
+ constructor(canvasCtx, commonObjs, objs, canvasFactory, imageLayer, optionalContentConfig, annotationCanvasMap) {
|
|
this.ctx = canvasCtx;
|
|
this.ctx = canvasCtx;
|
|
- this.current = new CanvasExtraState();
|
|
|
|
|
|
+ this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
|
|
this.stateStack = [];
|
|
this.stateStack = [];
|
|
this.pendingClip = null;
|
|
this.pendingClip = null;
|
|
this.pendingEOFill = false;
|
|
this.pendingEOFill = false;
|
|
@@ -816,12 +973,16 @@ class CanvasGraphics {
|
|
this.smaskStack = [];
|
|
this.smaskStack = [];
|
|
this.smaskCounter = 0;
|
|
this.smaskCounter = 0;
|
|
this.tempSMask = null;
|
|
this.tempSMask = null;
|
|
|
|
+ this.suspendedCtx = null;
|
|
this.contentVisible = true;
|
|
this.contentVisible = true;
|
|
this.markedContentStack = [];
|
|
this.markedContentStack = [];
|
|
this.optionalContentConfig = optionalContentConfig;
|
|
this.optionalContentConfig = optionalContentConfig;
|
|
this.cachedCanvases = new CachedCanvases(this.canvasFactory);
|
|
this.cachedCanvases = new CachedCanvases(this.canvasFactory);
|
|
- this.cachedCanvasPatterns = new LRUCache(MAX_CACHED_CANVAS_PATTERNS);
|
|
|
|
this.cachedPatterns = new Map();
|
|
this.cachedPatterns = new Map();
|
|
|
|
+ this.annotationCanvasMap = annotationCanvasMap;
|
|
|
|
+ this.viewportScale = 1;
|
|
|
|
+ this.outputScaleX = 1;
|
|
|
|
+ this.outputScaleY = 1;
|
|
|
|
|
|
if (canvasCtx) {
|
|
if (canvasCtx) {
|
|
addContextCurrentTransform(canvasCtx);
|
|
addContextCurrentTransform(canvasCtx);
|
|
@@ -857,9 +1018,12 @@ class CanvasGraphics {
|
|
|
|
|
|
if (transform) {
|
|
if (transform) {
|
|
this.ctx.transform.apply(this.ctx, transform);
|
|
this.ctx.transform.apply(this.ctx, transform);
|
|
|
|
+ this.outputScaleX = transform[0];
|
|
|
|
+ this.outputScaleY = transform[0];
|
|
}
|
|
}
|
|
|
|
|
|
this.ctx.transform.apply(this.ctx, viewport.transform);
|
|
this.ctx.transform.apply(this.ctx, viewport.transform);
|
|
|
|
+ this.viewportScale = viewport.scale;
|
|
this.baseTransform = this.ctx.mozCurrentTransform.slice();
|
|
this.baseTransform = this.ctx.mozCurrentTransform.slice();
|
|
this._combinedScaleFactor = Math.hypot(this.baseTransform[0], this.baseTransform[2]);
|
|
this._combinedScaleFactor = Math.hypot(this.baseTransform[0], this.baseTransform[2]);
|
|
|
|
|
|
@@ -940,7 +1104,6 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
|
|
|
|
this.cachedCanvases.clear();
|
|
this.cachedCanvases.clear();
|
|
- this.cachedCanvasPatterns.clear();
|
|
|
|
this.cachedPatterns.clear();
|
|
this.cachedPatterns.clear();
|
|
|
|
|
|
if (this.imageLayer) {
|
|
if (this.imageLayer) {
|
|
@@ -1027,7 +1190,7 @@ class CanvasGraphics {
|
|
|
|
|
|
const inverse = _util.Util.transform(fillCtx.mozCurrentTransformInverse, [1, 0, 0, 1, -offsetX, -offsetY]);
|
|
const inverse = _util.Util.transform(fillCtx.mozCurrentTransformInverse, [1, 0, 0, 1, -offsetX, -offsetY]);
|
|
|
|
|
|
- fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, false) : fillColor;
|
|
|
|
|
|
+ fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, _pattern_helper.PathType.FILL) : fillColor;
|
|
fillCtx.fillRect(0, 0, width, height);
|
|
fillCtx.fillRect(0, 0, width, height);
|
|
return {
|
|
return {
|
|
canvas: fillCanvas.canvas,
|
|
canvas: fillCanvas.canvas,
|
|
@@ -1119,21 +1282,9 @@ class CanvasGraphics {
|
|
break;
|
|
break;
|
|
|
|
|
|
case "SMask":
|
|
case "SMask":
|
|
- if (this.current.activeSMask) {
|
|
|
|
- if (this.stateStack.length > 0 && this.stateStack[this.stateStack.length - 1].activeSMask === this.current.activeSMask) {
|
|
|
|
- this.suspendSMaskGroup();
|
|
|
|
- } else {
|
|
|
|
- this.endSMaskGroup();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
this.current.activeSMask = value ? this.tempSMask : null;
|
|
this.current.activeSMask = value ? this.tempSMask : null;
|
|
-
|
|
|
|
- if (this.current.activeSMask) {
|
|
|
|
- this.beginSMaskGroup();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
this.tempSMask = null;
|
|
this.tempSMask = null;
|
|
|
|
+ this.checkSMaskState();
|
|
break;
|
|
break;
|
|
|
|
|
|
case "TR":
|
|
case "TR":
|
|
@@ -1142,65 +1293,68 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- beginSMaskGroup() {
|
|
|
|
- const activeSMask = this.current.activeSMask;
|
|
|
|
- const drawnWidth = activeSMask.canvas.width;
|
|
|
|
- const drawnHeight = activeSMask.canvas.height;
|
|
|
|
|
|
+ checkSMaskState() {
|
|
|
|
+ const inSMaskMode = !!this.suspendedCtx;
|
|
|
|
+
|
|
|
|
+ if (this.current.activeSMask && !inSMaskMode) {
|
|
|
|
+ this.beginSMaskMode();
|
|
|
|
+ } else if (!this.current.activeSMask && inSMaskMode) {
|
|
|
|
+ this.endSMaskMode();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ beginSMaskMode() {
|
|
|
|
+ if (this.suspendedCtx) {
|
|
|
|
+ throw new Error("beginSMaskMode called while already in smask mode");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const drawnWidth = this.ctx.canvas.width;
|
|
|
|
+ const drawnHeight = this.ctx.canvas.height;
|
|
const cacheId = "smaskGroupAt" + this.groupLevel;
|
|
const cacheId = "smaskGroupAt" + this.groupLevel;
|
|
const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
|
|
const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
|
|
- const currentCtx = this.ctx;
|
|
|
|
- const currentTransform = currentCtx.mozCurrentTransform;
|
|
|
|
- this.ctx.save();
|
|
|
|
- const groupCtx = scratchCanvas.context;
|
|
|
|
- groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
|
|
|
|
- groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
|
|
|
|
- groupCtx.transform.apply(groupCtx, currentTransform);
|
|
|
|
- activeSMask.startTransformInverse = groupCtx.mozCurrentTransformInverse;
|
|
|
|
- copyCtxState(currentCtx, groupCtx);
|
|
|
|
- this.ctx = groupCtx;
|
|
|
|
|
|
+ this.suspendedCtx = this.ctx;
|
|
|
|
+ this.ctx = scratchCanvas.context;
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ ctx.setTransform.apply(ctx, this.suspendedCtx.mozCurrentTransform);
|
|
|
|
+ copyCtxState(this.suspendedCtx, ctx);
|
|
|
|
+ mirrorContextOperations(ctx, this.suspendedCtx);
|
|
this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
|
|
this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
|
|
- this.groupStack.push(currentCtx);
|
|
|
|
- this.groupLevel++;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- suspendSMaskGroup() {
|
|
|
|
- const groupCtx = this.ctx;
|
|
|
|
- this.groupLevel--;
|
|
|
|
- this.ctx = this.groupStack.pop();
|
|
|
|
- composeSMask(this.ctx, this.current.activeSMask, groupCtx);
|
|
|
|
- this.ctx.restore();
|
|
|
|
- this.ctx.save();
|
|
|
|
- copyCtxState(groupCtx, this.ctx);
|
|
|
|
- this.current.resumeSMaskCtx = groupCtx;
|
|
|
|
-
|
|
|
|
- const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
|
|
|
|
|
|
+ endSMaskMode() {
|
|
|
|
+ if (!this.suspendedCtx) {
|
|
|
|
+ throw new Error("endSMaskMode called while not in smask mode");
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.transform.apply(this.ctx, deltaTransform);
|
|
|
|
- groupCtx.save();
|
|
|
|
- groupCtx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
- groupCtx.clearRect(0, 0, groupCtx.canvas.width, groupCtx.canvas.height);
|
|
|
|
- groupCtx.restore();
|
|
|
|
- }
|
|
|
|
|
|
+ this.ctx._removeMirroring();
|
|
|
|
|
|
- resumeSMaskGroup() {
|
|
|
|
- const groupCtx = this.current.resumeSMaskCtx;
|
|
|
|
- const currentCtx = this.ctx;
|
|
|
|
- this.ctx = groupCtx;
|
|
|
|
- this.groupStack.push(currentCtx);
|
|
|
|
- this.groupLevel++;
|
|
|
|
|
|
+ copyCtxState(this.ctx, this.suspendedCtx);
|
|
|
|
+ this.ctx = this.suspendedCtx;
|
|
|
|
+ this.current.activeSMask = null;
|
|
|
|
+ this.suspendedCtx = null;
|
|
}
|
|
}
|
|
|
|
|
|
- endSMaskGroup() {
|
|
|
|
- const groupCtx = this.ctx;
|
|
|
|
- this.groupLevel--;
|
|
|
|
- this.ctx = this.groupStack.pop();
|
|
|
|
- composeSMask(this.ctx, this.current.activeSMask, groupCtx);
|
|
|
|
- this.ctx.restore();
|
|
|
|
- copyCtxState(groupCtx, this.ctx);
|
|
|
|
|
|
+ compose(dirtyBox) {
|
|
|
|
+ if (!this.current.activeSMask) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
|
|
|
|
|
|
+ if (!dirtyBox) {
|
|
|
|
+ dirtyBox = [0, 0, this.ctx.canvas.width, this.ctx.canvas.height];
|
|
|
|
+ } else {
|
|
|
|
+ dirtyBox[0] = Math.floor(dirtyBox[0]);
|
|
|
|
+ dirtyBox[1] = Math.floor(dirtyBox[1]);
|
|
|
|
+ dirtyBox[2] = Math.ceil(dirtyBox[2]);
|
|
|
|
+ dirtyBox[3] = Math.ceil(dirtyBox[3]);
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.transform.apply(this.ctx, deltaTransform);
|
|
|
|
|
|
+ const smask = this.current.activeSMask;
|
|
|
|
+ const suspendedCtx = this.suspendedCtx;
|
|
|
|
+ composeSMask(suspendedCtx, smask, this.ctx, dirtyBox);
|
|
|
|
+ this.ctx.save();
|
|
|
|
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
+ this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
|
|
|
|
+ this.ctx.restore();
|
|
}
|
|
}
|
|
|
|
|
|
save() {
|
|
save() {
|
|
@@ -1208,25 +1362,19 @@ class CanvasGraphics {
|
|
const old = this.current;
|
|
const old = this.current;
|
|
this.stateStack.push(old);
|
|
this.stateStack.push(old);
|
|
this.current = old.clone();
|
|
this.current = old.clone();
|
|
- this.current.resumeSMaskCtx = null;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
restore() {
|
|
restore() {
|
|
- if (this.current.resumeSMaskCtx) {
|
|
|
|
- this.resumeSMaskGroup();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (this.current.activeSMask !== null && (this.stateStack.length === 0 || this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask)) {
|
|
|
|
- this.endSMaskGroup();
|
|
|
|
|
|
+ if (this.stateStack.length === 0 && this.current.activeSMask) {
|
|
|
|
+ this.endSMaskMode();
|
|
}
|
|
}
|
|
|
|
|
|
if (this.stateStack.length !== 0) {
|
|
if (this.stateStack.length !== 0) {
|
|
this.current = this.stateStack.pop();
|
|
this.current = this.stateStack.pop();
|
|
this.ctx.restore();
|
|
this.ctx.restore();
|
|
|
|
+ this.checkSMaskState();
|
|
this.pendingClip = null;
|
|
this.pendingClip = null;
|
|
this._cachedGetSinglePixelWidth = null;
|
|
this._cachedGetSinglePixelWidth = null;
|
|
- } else {
|
|
|
|
- this.current.activeSMask = null;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1240,6 +1388,7 @@ class CanvasGraphics {
|
|
const current = this.current;
|
|
const current = this.current;
|
|
let x = current.x,
|
|
let x = current.x,
|
|
y = current.y;
|
|
y = current.y;
|
|
|
|
+ let startX, startY;
|
|
|
|
|
|
for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
|
|
for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
|
|
switch (ops[i] | 0) {
|
|
switch (ops[i] | 0) {
|
|
@@ -1260,6 +1409,8 @@ class CanvasGraphics {
|
|
ctx.lineTo(x, yh);
|
|
ctx.lineTo(x, yh);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ current.updatePathMinMax(ctx.mozCurrentTransform, x, y);
|
|
|
|
+ current.updatePathMinMax(ctx.mozCurrentTransform, xw, yh);
|
|
ctx.closePath();
|
|
ctx.closePath();
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -1267,32 +1418,43 @@ class CanvasGraphics {
|
|
x = args[j++];
|
|
x = args[j++];
|
|
y = args[j++];
|
|
y = args[j++];
|
|
ctx.moveTo(x, y);
|
|
ctx.moveTo(x, y);
|
|
|
|
+ current.updatePathMinMax(ctx.mozCurrentTransform, x, y);
|
|
break;
|
|
break;
|
|
|
|
|
|
case _util.OPS.lineTo:
|
|
case _util.OPS.lineTo:
|
|
x = args[j++];
|
|
x = args[j++];
|
|
y = args[j++];
|
|
y = args[j++];
|
|
ctx.lineTo(x, y);
|
|
ctx.lineTo(x, y);
|
|
|
|
+ current.updatePathMinMax(ctx.mozCurrentTransform, x, y);
|
|
break;
|
|
break;
|
|
|
|
|
|
case _util.OPS.curveTo:
|
|
case _util.OPS.curveTo:
|
|
|
|
+ startX = x;
|
|
|
|
+ startY = y;
|
|
x = args[j + 4];
|
|
x = args[j + 4];
|
|
y = args[j + 5];
|
|
y = args[j + 5];
|
|
ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
|
|
ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
|
|
|
|
+ current.updateCurvePathMinMax(ctx.mozCurrentTransform, startX, startY, args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
|
|
j += 6;
|
|
j += 6;
|
|
break;
|
|
break;
|
|
|
|
|
|
case _util.OPS.curveTo2:
|
|
case _util.OPS.curveTo2:
|
|
|
|
+ startX = x;
|
|
|
|
+ startY = y;
|
|
ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
|
|
ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
|
|
|
|
+ current.updateCurvePathMinMax(ctx.mozCurrentTransform, startX, startY, x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
|
|
x = args[j + 2];
|
|
x = args[j + 2];
|
|
y = args[j + 3];
|
|
y = args[j + 3];
|
|
j += 4;
|
|
j += 4;
|
|
break;
|
|
break;
|
|
|
|
|
|
case _util.OPS.curveTo3:
|
|
case _util.OPS.curveTo3:
|
|
|
|
+ startX = x;
|
|
|
|
+ startY = y;
|
|
x = args[j + 2];
|
|
x = args[j + 2];
|
|
y = args[j + 3];
|
|
y = args[j + 3];
|
|
ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
|
|
ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
|
|
|
|
+ current.updateCurvePathMinMax(ctx.mozCurrentTransform, startX, startY, args[j], args[j + 1], x, y, x, y);
|
|
j += 4;
|
|
j += 4;
|
|
break;
|
|
break;
|
|
|
|
|
|
@@ -1319,7 +1481,7 @@ class CanvasGraphics {
|
|
if (typeof strokeColor === "object" && strokeColor?.getPattern) {
|
|
if (typeof strokeColor === "object" && strokeColor?.getPattern) {
|
|
const lineWidth = this.getSinglePixelWidth();
|
|
const lineWidth = this.getSinglePixelWidth();
|
|
ctx.save();
|
|
ctx.save();
|
|
- ctx.strokeStyle = strokeColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
|
|
+ ctx.strokeStyle = strokeColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse, _pattern_helper.PathType.STROKE);
|
|
ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
|
|
ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
|
|
ctx.stroke();
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
ctx.restore();
|
|
@@ -1340,7 +1502,7 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
|
|
|
|
if (consumePath) {
|
|
if (consumePath) {
|
|
- this.consumePath();
|
|
|
|
|
|
+ this.consumePath(this.current.getClippedPathBoundingBox());
|
|
}
|
|
}
|
|
|
|
|
|
ctx.globalAlpha = this.current.fillAlpha;
|
|
ctx.globalAlpha = this.current.fillAlpha;
|
|
@@ -1360,11 +1522,13 @@ class CanvasGraphics {
|
|
|
|
|
|
if (isPatternFill) {
|
|
if (isPatternFill) {
|
|
ctx.save();
|
|
ctx.save();
|
|
- ctx.fillStyle = fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
|
|
+ ctx.fillStyle = fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse, _pattern_helper.PathType.FILL);
|
|
needRestore = true;
|
|
needRestore = true;
|
|
}
|
|
}
|
|
|
|
|
|
- if (this.contentVisible) {
|
|
|
|
|
|
+ const intersect = this.current.getClippedPathBoundingBox();
|
|
|
|
+
|
|
|
|
+ if (this.contentVisible && intersect !== null) {
|
|
if (this.pendingEOFill) {
|
|
if (this.pendingEOFill) {
|
|
ctx.fill("evenodd");
|
|
ctx.fill("evenodd");
|
|
this.pendingEOFill = false;
|
|
this.pendingEOFill = false;
|
|
@@ -1378,7 +1542,7 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
|
|
|
|
if (consumePath) {
|
|
if (consumePath) {
|
|
- this.consumePath();
|
|
|
|
|
|
+ this.consumePath(intersect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1665,16 +1829,6 @@ class CanvasGraphics {
|
|
const widthAdvanceScale = fontSize * current.fontMatrix[0];
|
|
const widthAdvanceScale = fontSize * current.fontMatrix[0];
|
|
const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
|
|
const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
|
|
ctx.save();
|
|
ctx.save();
|
|
- let patternTransform;
|
|
|
|
-
|
|
|
|
- if (current.patternFill) {
|
|
|
|
- ctx.save();
|
|
|
|
- const pattern = current.fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
- patternTransform = ctx.mozCurrentTransform;
|
|
|
|
- ctx.restore();
|
|
|
|
- ctx.fillStyle = pattern;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
ctx.transform.apply(ctx, current.textMatrix);
|
|
ctx.transform.apply(ctx, current.textMatrix);
|
|
ctx.translate(current.x, current.y + current.textRise);
|
|
ctx.translate(current.x, current.y + current.textRise);
|
|
|
|
|
|
@@ -1684,6 +1838,16 @@ class CanvasGraphics {
|
|
ctx.scale(textHScale, 1);
|
|
ctx.scale(textHScale, 1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ let patternTransform;
|
|
|
|
+
|
|
|
|
+ if (current.patternFill) {
|
|
|
|
+ ctx.save();
|
|
|
|
+ const pattern = current.fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse, _pattern_helper.PathType.FILL);
|
|
|
|
+ patternTransform = ctx.mozCurrentTransform;
|
|
|
|
+ ctx.restore();
|
|
|
|
+ ctx.fillStyle = pattern;
|
|
|
|
+ }
|
|
|
|
+
|
|
let lineWidth = current.lineWidth;
|
|
let lineWidth = current.lineWidth;
|
|
let resetLineWidthToOne = false;
|
|
let resetLineWidthToOne = false;
|
|
const scale = current.textMatrixScale;
|
|
const scale = current.textMatrixScale;
|
|
@@ -1786,6 +1950,7 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
|
|
|
|
ctx.restore();
|
|
ctx.restore();
|
|
|
|
+ this.compose();
|
|
return undefined;
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1909,7 +2074,7 @@ class CanvasGraphics {
|
|
if (this.cachedPatterns.has(objId)) {
|
|
if (this.cachedPatterns.has(objId)) {
|
|
pattern = this.cachedPatterns.get(objId);
|
|
pattern = this.cachedPatterns.get(objId);
|
|
} else {
|
|
} else {
|
|
- pattern = (0, _pattern_helper.getShadingPattern)(this.objs.get(objId), this.cachedCanvasPatterns);
|
|
|
|
|
|
+ pattern = (0, _pattern_helper.getShadingPattern)(this.objs.get(objId));
|
|
this.cachedPatterns.set(objId, pattern);
|
|
this.cachedPatterns.set(objId, pattern);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1930,7 +2095,7 @@ class CanvasGraphics {
|
|
|
|
|
|
const pattern = this._getPattern(objId);
|
|
const pattern = this._getPattern(objId);
|
|
|
|
|
|
- ctx.fillStyle = pattern.getPattern(ctx, this, ctx.mozCurrentTransformInverse, true);
|
|
|
|
|
|
+ ctx.fillStyle = pattern.getPattern(ctx, this, ctx.mozCurrentTransformInverse, _pattern_helper.PathType.SHADING);
|
|
const inv = ctx.mozCurrentTransformInverse;
|
|
const inv = ctx.mozCurrentTransformInverse;
|
|
|
|
|
|
if (inv) {
|
|
if (inv) {
|
|
@@ -1955,6 +2120,7 @@ class CanvasGraphics {
|
|
this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
|
|
this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ this.compose(this.current.getClippedPathBoundingBox());
|
|
this.restore();
|
|
this.restore();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1984,6 +2150,8 @@ class CanvasGraphics {
|
|
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.updatePathMinMax(this.ctx.mozCurrentTransform, bbox[0], bbox[1]);
|
|
|
|
+ this.current.updatePathMinMax(this.ctx.mozCurrentTransform, bbox[2], bbox[3]);
|
|
this.clip();
|
|
this.clip();
|
|
this.endPath();
|
|
this.endPath();
|
|
}
|
|
}
|
|
@@ -2004,6 +2172,13 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
|
|
|
|
this.save();
|
|
this.save();
|
|
|
|
+ const suspendedCtx = this.suspendedCtx;
|
|
|
|
+
|
|
|
|
+ if (this.current.activeSMask) {
|
|
|
|
+ this.suspendedCtx = null;
|
|
|
|
+ this.current.activeSMask = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
const currentCtx = this.ctx;
|
|
const currentCtx = this.ctx;
|
|
|
|
|
|
if (!group.isolated) {
|
|
if (!group.isolated) {
|
|
@@ -2045,6 +2220,7 @@ class CanvasGraphics {
|
|
drawnHeight = MAX_GROUP_SIZE;
|
|
drawnHeight = MAX_GROUP_SIZE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ this.current.startNewPathAndClipBox([0, 0, drawnWidth, drawnHeight]);
|
|
let cacheId = "groupAt" + this.groupLevel;
|
|
let cacheId = "groupAt" + this.groupLevel;
|
|
|
|
|
|
if (group.smask) {
|
|
if (group.smask) {
|
|
@@ -2074,14 +2250,17 @@ class CanvasGraphics {
|
|
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
|
|
currentCtx.setTransform(1, 0, 0, 1, 0, 0);
|
|
currentCtx.translate(offsetX, offsetY);
|
|
currentCtx.translate(offsetX, offsetY);
|
|
currentCtx.scale(scaleX, scaleY);
|
|
currentCtx.scale(scaleX, scaleY);
|
|
|
|
+ currentCtx.save();
|
|
}
|
|
}
|
|
|
|
|
|
copyCtxState(currentCtx, groupCtx);
|
|
copyCtxState(currentCtx, groupCtx);
|
|
this.ctx = groupCtx;
|
|
this.ctx = groupCtx;
|
|
this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
|
|
this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
|
|
- this.groupStack.push(currentCtx);
|
|
|
|
|
|
+ this.groupStack.push({
|
|
|
|
+ ctx: currentCtx,
|
|
|
|
+ suspendedCtx
|
|
|
|
+ });
|
|
this.groupLevel++;
|
|
this.groupLevel++;
|
|
- this.current.activeSMask = null;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
endGroup(group) {
|
|
endGroup(group) {
|
|
@@ -2091,16 +2270,33 @@ class CanvasGraphics {
|
|
|
|
|
|
this.groupLevel--;
|
|
this.groupLevel--;
|
|
const groupCtx = this.ctx;
|
|
const groupCtx = this.ctx;
|
|
- this.ctx = this.groupStack.pop();
|
|
|
|
|
|
+ const {
|
|
|
|
+ ctx,
|
|
|
|
+ suspendedCtx
|
|
|
|
+ } = this.groupStack.pop();
|
|
|
|
+ this.ctx = ctx;
|
|
this.ctx.imageSmoothingEnabled = false;
|
|
this.ctx.imageSmoothingEnabled = false;
|
|
|
|
|
|
|
|
+ if (suspendedCtx) {
|
|
|
|
+ this.suspendedCtx = suspendedCtx;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (group.smask) {
|
|
if (group.smask) {
|
|
this.tempSMask = this.smaskStack.pop();
|
|
this.tempSMask = this.smaskStack.pop();
|
|
|
|
+ this.restore();
|
|
} else {
|
|
} else {
|
|
|
|
+ this.ctx.restore();
|
|
|
|
+ const currentMtx = this.ctx.mozCurrentTransform;
|
|
|
|
+ this.restore();
|
|
|
|
+ this.ctx.save();
|
|
|
|
+ this.ctx.setTransform.apply(this.ctx, currentMtx);
|
|
|
|
+
|
|
|
|
+ const dirtyBox = _util.Util.getAxialAlignedBoundingBox([0, 0, groupCtx.canvas.width, groupCtx.canvas.height], currentMtx);
|
|
|
|
+
|
|
this.ctx.drawImage(groupCtx.canvas, 0, 0);
|
|
this.ctx.drawImage(groupCtx.canvas, 0, 0);
|
|
|
|
+ this.ctx.restore();
|
|
|
|
+ this.compose(dirtyBox);
|
|
}
|
|
}
|
|
-
|
|
|
|
- this.restore();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
beginAnnotations() {
|
|
beginAnnotations() {
|
|
@@ -2115,24 +2311,62 @@ class CanvasGraphics {
|
|
this.restore();
|
|
this.restore();
|
|
}
|
|
}
|
|
|
|
|
|
- beginAnnotation(id, rect, transform, matrix) {
|
|
|
|
|
|
+ beginAnnotation(id, rect, transform, matrix, hasOwnCanvas) {
|
|
this.save();
|
|
this.save();
|
|
- resetCtxToDefault(this.ctx);
|
|
|
|
- this.current = new CanvasExtraState();
|
|
|
|
|
|
|
|
if (Array.isArray(rect) && rect.length === 4) {
|
|
if (Array.isArray(rect) && rect.length === 4) {
|
|
const width = rect[2] - rect[0];
|
|
const width = rect[2] - rect[0];
|
|
const height = rect[3] - rect[1];
|
|
const height = rect[3] - rect[1];
|
|
- this.ctx.rect(rect[0], rect[1], width, height);
|
|
|
|
- this.clip();
|
|
|
|
- this.endPath();
|
|
|
|
|
|
+
|
|
|
|
+ if (hasOwnCanvas && this.annotationCanvasMap) {
|
|
|
|
+ transform = transform.slice();
|
|
|
|
+ transform[4] -= rect[0];
|
|
|
|
+ transform[5] -= rect[1];
|
|
|
|
+ rect = rect.slice();
|
|
|
|
+ rect[0] = rect[1] = 0;
|
|
|
|
+ rect[2] = width;
|
|
|
|
+ rect[3] = height;
|
|
|
|
+
|
|
|
|
+ const [scaleX, scaleY] = _util.Util.singularValueDecompose2dScale(this.ctx.mozCurrentTransform);
|
|
|
|
+
|
|
|
|
+ const {
|
|
|
|
+ viewportScale
|
|
|
|
+ } = this;
|
|
|
|
+ const canvasWidth = Math.ceil(width * this.outputScaleX * viewportScale);
|
|
|
|
+ const canvasHeight = Math.ceil(height * this.outputScaleY * viewportScale);
|
|
|
|
+ this.annotationCanvas = this.canvasFactory.create(canvasWidth, canvasHeight);
|
|
|
|
+ const {
|
|
|
|
+ canvas,
|
|
|
|
+ context
|
|
|
|
+ } = this.annotationCanvas;
|
|
|
|
+ canvas.style.width = `calc(${width}px * var(--viewport-scale-factor))`;
|
|
|
|
+ canvas.style.height = `calc(${height}px * var(--viewport-scale-factor))`;
|
|
|
|
+ this.annotationCanvasMap.set(id, canvas);
|
|
|
|
+ this.annotationCanvas.savedCtx = this.ctx;
|
|
|
|
+ this.ctx = context;
|
|
|
|
+ this.ctx.setTransform(scaleX, 0, 0, -scaleY, 0, height * scaleY);
|
|
|
|
+ addContextCurrentTransform(this.ctx);
|
|
|
|
+ resetCtxToDefault(this.ctx);
|
|
|
|
+ } else {
|
|
|
|
+ resetCtxToDefault(this.ctx);
|
|
|
|
+ this.ctx.rect(rect[0], rect[1], width, height);
|
|
|
|
+ this.clip();
|
|
|
|
+ this.endPath();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ this.current = new CanvasExtraState(this.ctx.canvas.width, this.ctx.canvas.height);
|
|
this.transform.apply(this, transform);
|
|
this.transform.apply(this, transform);
|
|
this.transform.apply(this, matrix);
|
|
this.transform.apply(this, matrix);
|
|
}
|
|
}
|
|
|
|
|
|
endAnnotation() {
|
|
endAnnotation() {
|
|
|
|
+ if (this.annotationCanvas) {
|
|
|
|
+ this.ctx = this.annotationCanvas.savedCtx;
|
|
|
|
+ delete this.annotationCanvas.savedCtx;
|
|
|
|
+ delete this.annotationCanvas;
|
|
|
|
+ }
|
|
|
|
+
|
|
this.restore();
|
|
this.restore();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2170,6 +2404,7 @@ class CanvasGraphics {
|
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
|
|
ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
|
|
ctx.restore();
|
|
ctx.restore();
|
|
|
|
+ this.compose();
|
|
}
|
|
}
|
|
|
|
|
|
paintImageMaskXObjectRepeat(imgData, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
|
|
paintImageMaskXObjectRepeat(imgData, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
|
|
@@ -2195,6 +2430,7 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
|
|
|
|
ctx.restore();
|
|
ctx.restore();
|
|
|
|
+ this.compose();
|
|
}
|
|
}
|
|
|
|
|
|
paintImageMaskXObjectGroup(images) {
|
|
paintImageMaskXObjectGroup(images) {
|
|
@@ -2215,7 +2451,7 @@ class CanvasGraphics {
|
|
maskCtx.save();
|
|
maskCtx.save();
|
|
putBinaryImageMask(maskCtx, image);
|
|
putBinaryImageMask(maskCtx, image);
|
|
maskCtx.globalCompositeOperation = "source-in";
|
|
maskCtx.globalCompositeOperation = "source-in";
|
|
- maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, ctx.mozCurrentTransformInverse, false) : fillColor;
|
|
|
|
|
|
+ maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, ctx.mozCurrentTransformInverse, _pattern_helper.PathType.FILL) : fillColor;
|
|
maskCtx.fillRect(0, 0, width, height);
|
|
maskCtx.fillRect(0, 0, width, height);
|
|
maskCtx.restore();
|
|
maskCtx.restore();
|
|
ctx.save();
|
|
ctx.save();
|
|
@@ -2224,6 +2460,8 @@ class CanvasGraphics {
|
|
ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
|
|
ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
|
|
ctx.restore();
|
|
ctx.restore();
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ this.compose();
|
|
}
|
|
}
|
|
|
|
|
|
paintImageXObject(objId) {
|
|
paintImageXObject(objId) {
|
|
@@ -2307,6 +2545,7 @@ class CanvasGraphics {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ this.compose();
|
|
this.restore();
|
|
this.restore();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2342,6 +2581,8 @@ class CanvasGraphics {
|
|
|
|
|
|
ctx.restore();
|
|
ctx.restore();
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ this.compose();
|
|
}
|
|
}
|
|
|
|
|
|
paintSolidColorImageMask() {
|
|
paintSolidColorImageMask() {
|
|
@@ -2350,6 +2591,7 @@ class CanvasGraphics {
|
|
}
|
|
}
|
|
|
|
|
|
this.ctx.fillRect(0, 0, 1, 1);
|
|
this.ctx.fillRect(0, 0, 1, 1);
|
|
|
|
+ this.compose();
|
|
}
|
|
}
|
|
|
|
|
|
markPoint(tag) {}
|
|
markPoint(tag) {}
|
|
@@ -2385,7 +2627,15 @@ class CanvasGraphics {
|
|
|
|
|
|
endCompat() {}
|
|
endCompat() {}
|
|
|
|
|
|
- consumePath() {
|
|
|
|
|
|
+ consumePath(clipBox) {
|
|
|
|
+ if (this.pendingClip) {
|
|
|
|
+ this.current.updateClipFromPath();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!this.pendingClip) {
|
|
|
|
+ this.compose(clipBox);
|
|
|
|
+ }
|
|
|
|
+
|
|
const ctx = this.ctx;
|
|
const ctx = this.ctx;
|
|
|
|
|
|
if (this.pendingClip) {
|
|
if (this.pendingClip) {
|
|
@@ -2398,6 +2648,7 @@ class CanvasGraphics {
|
|
this.pendingClip = null;
|
|
this.pendingClip = null;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ this.current.startNewPathAndClipBox(this.current.clipBox);
|
|
ctx.beginPath();
|
|
ctx.beginPath();
|
|
}
|
|
}
|
|
|
|
|