|
@@ -30,9 +30,14 @@ var _util = require("../shared/util.js");
|
|
|
|
|
|
var _pattern_helper = require("./pattern_helper.js");
|
|
var _pattern_helper = require("./pattern_helper.js");
|
|
|
|
|
|
|
|
+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_STEPS = 10;
|
|
const COMPILE_TYPE3_GLYPHS = true;
|
|
const COMPILE_TYPE3_GLYPHS = true;
|
|
const MAX_SIZE_TO_COMPILE = 1000;
|
|
const MAX_SIZE_TO_COMPILE = 1000;
|
|
const FULL_CHUNK_HEIGHT = 16;
|
|
const FULL_CHUNK_HEIGHT = 16;
|
|
@@ -184,6 +189,46 @@ 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]);
|
|
@@ -397,1989 +442,2006 @@ class CanvasExtraState {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-const CanvasGraphics = function CanvasGraphicsClosure() {
|
|
|
|
- const EXECUTION_TIME = 15;
|
|
|
|
- const EXECUTION_STEPS = 10;
|
|
|
|
-
|
|
|
|
- function putBinaryImageData(ctx, imgData, transferMaps = null) {
|
|
|
|
- if (typeof ImageData !== "undefined" && imgData instanceof ImageData) {
|
|
|
|
- ctx.putImageData(imgData, 0, 0);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const height = imgData.height,
|
|
|
|
- width = imgData.width;
|
|
|
|
- const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
|
|
|
|
- const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
|
|
|
|
- const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
|
|
|
|
- const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
|
|
|
|
- let srcPos = 0,
|
|
|
|
- destPos;
|
|
|
|
- const src = imgData.data;
|
|
|
|
- const dest = chunkImgData.data;
|
|
|
|
- let i, j, thisChunkHeight, elemsInThisChunk;
|
|
|
|
- let transferMapRed, transferMapGreen, transferMapBlue, transferMapGray;
|
|
|
|
-
|
|
|
|
- if (transferMaps) {
|
|
|
|
- switch (transferMaps.length) {
|
|
|
|
- case 1:
|
|
|
|
- transferMapRed = transferMaps[0];
|
|
|
|
- transferMapGreen = transferMaps[0];
|
|
|
|
- transferMapBlue = transferMaps[0];
|
|
|
|
- transferMapGray = transferMaps[0];
|
|
|
|
- break;
|
|
|
|
|
|
+function putBinaryImageData(ctx, imgData, transferMaps = null) {
|
|
|
|
+ if (typeof ImageData !== "undefined" && imgData instanceof ImageData) {
|
|
|
|
+ ctx.putImageData(imgData, 0, 0);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- case 4:
|
|
|
|
- transferMapRed = transferMaps[0];
|
|
|
|
- transferMapGreen = transferMaps[1];
|
|
|
|
- transferMapBlue = transferMaps[2];
|
|
|
|
- transferMapGray = transferMaps[3];
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ const height = imgData.height,
|
|
|
|
+ width = imgData.width;
|
|
|
|
+ const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
|
|
|
|
+ const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
|
|
|
|
+ const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
|
|
|
|
+ const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
|
|
|
|
+ let srcPos = 0,
|
|
|
|
+ destPos;
|
|
|
|
+ const src = imgData.data;
|
|
|
|
+ const dest = chunkImgData.data;
|
|
|
|
+ let i, j, thisChunkHeight, elemsInThisChunk;
|
|
|
|
+ let transferMapRed, transferMapGreen, transferMapBlue, transferMapGray;
|
|
|
|
+
|
|
|
|
+ if (transferMaps) {
|
|
|
|
+ switch (transferMaps.length) {
|
|
|
|
+ case 1:
|
|
|
|
+ transferMapRed = transferMaps[0];
|
|
|
|
+ transferMapGreen = transferMaps[0];
|
|
|
|
+ transferMapBlue = transferMaps[0];
|
|
|
|
+ transferMapGray = transferMaps[0];
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 4:
|
|
|
|
+ transferMapRed = transferMaps[0];
|
|
|
|
+ transferMapGreen = transferMaps[1];
|
|
|
|
+ transferMapBlue = transferMaps[2];
|
|
|
|
+ transferMapGray = transferMaps[3];
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- if (imgData.kind === _util.ImageKind.GRAYSCALE_1BPP) {
|
|
|
|
- const srcLength = src.byteLength;
|
|
|
|
- const dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2);
|
|
|
|
- const dest32DataLength = dest32.length;
|
|
|
|
- const fullSrcDiff = width + 7 >> 3;
|
|
|
|
- let white = 0xffffffff;
|
|
|
|
- let black = _util.IsLittleEndianCached.value ? 0xff000000 : 0x000000ff;
|
|
|
|
-
|
|
|
|
- if (transferMapGray) {
|
|
|
|
- if (transferMapGray[0] === 0xff && transferMapGray[0xff] === 0) {
|
|
|
|
- [white, black] = [black, white];
|
|
|
|
|
|
+ if (imgData.kind === _util.ImageKind.GRAYSCALE_1BPP) {
|
|
|
|
+ const srcLength = src.byteLength;
|
|
|
|
+ const dest32 = new Uint32Array(dest.buffer, 0, dest.byteLength >> 2);
|
|
|
|
+ const dest32DataLength = dest32.length;
|
|
|
|
+ const fullSrcDiff = width + 7 >> 3;
|
|
|
|
+ let white = 0xffffffff;
|
|
|
|
+ let black = _util.IsLittleEndianCached.value ? 0xff000000 : 0x000000ff;
|
|
|
|
+
|
|
|
|
+ if (transferMapGray) {
|
|
|
|
+ if (transferMapGray[0] === 0xff && transferMapGray[0xff] === 0) {
|
|
|
|
+ [white, black] = [black, white];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < totalChunks; i++) {
|
|
|
|
+ thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
|
|
|
|
+ destPos = 0;
|
|
|
|
+
|
|
|
|
+ for (j = 0; j < thisChunkHeight; j++) {
|
|
|
|
+ const srcDiff = srcLength - srcPos;
|
|
|
|
+ let k = 0;
|
|
|
|
+ const kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7;
|
|
|
|
+ const kEndUnrolled = kEnd & ~7;
|
|
|
|
+ let mask = 0;
|
|
|
|
+ let srcByte = 0;
|
|
|
|
+
|
|
|
|
+ for (; k < kEndUnrolled; k += 8) {
|
|
|
|
+ srcByte = src[srcPos++];
|
|
|
|
+ dest32[destPos++] = srcByte & 128 ? white : black;
|
|
|
|
+ dest32[destPos++] = srcByte & 64 ? white : black;
|
|
|
|
+ dest32[destPos++] = srcByte & 32 ? white : black;
|
|
|
|
+ dest32[destPos++] = srcByte & 16 ? white : black;
|
|
|
|
+ dest32[destPos++] = srcByte & 8 ? white : black;
|
|
|
|
+ dest32[destPos++] = srcByte & 4 ? white : black;
|
|
|
|
+ dest32[destPos++] = srcByte & 2 ? white : black;
|
|
|
|
+ dest32[destPos++] = srcByte & 1 ? white : black;
|
|
}
|
|
}
|
|
- }
|
|
|
|
-
|
|
|
|
- for (i = 0; i < totalChunks; i++) {
|
|
|
|
- thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
|
|
|
|
- destPos = 0;
|
|
|
|
|
|
|
|
- for (j = 0; j < thisChunkHeight; j++) {
|
|
|
|
- const srcDiff = srcLength - srcPos;
|
|
|
|
- let k = 0;
|
|
|
|
- const kEnd = srcDiff > fullSrcDiff ? width : srcDiff * 8 - 7;
|
|
|
|
- const kEndUnrolled = kEnd & ~7;
|
|
|
|
- let mask = 0;
|
|
|
|
- let srcByte = 0;
|
|
|
|
-
|
|
|
|
- for (; k < kEndUnrolled; k += 8) {
|
|
|
|
|
|
+ for (; k < kEnd; k++) {
|
|
|
|
+ if (mask === 0) {
|
|
srcByte = src[srcPos++];
|
|
srcByte = src[srcPos++];
|
|
- dest32[destPos++] = srcByte & 128 ? white : black;
|
|
|
|
- dest32[destPos++] = srcByte & 64 ? white : black;
|
|
|
|
- dest32[destPos++] = srcByte & 32 ? white : black;
|
|
|
|
- dest32[destPos++] = srcByte & 16 ? white : black;
|
|
|
|
- dest32[destPos++] = srcByte & 8 ? white : black;
|
|
|
|
- dest32[destPos++] = srcByte & 4 ? white : black;
|
|
|
|
- dest32[destPos++] = srcByte & 2 ? white : black;
|
|
|
|
- dest32[destPos++] = srcByte & 1 ? white : black;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (; k < kEnd; k++) {
|
|
|
|
- if (mask === 0) {
|
|
|
|
- srcByte = src[srcPos++];
|
|
|
|
- mask = 128;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dest32[destPos++] = srcByte & mask ? white : black;
|
|
|
|
- mask >>= 1;
|
|
|
|
|
|
+ mask = 128;
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- while (destPos < dest32DataLength) {
|
|
|
|
- dest32[destPos++] = 0;
|
|
|
|
|
|
+ dest32[destPos++] = srcByte & mask ? white : black;
|
|
|
|
+ mask >>= 1;
|
|
}
|
|
}
|
|
-
|
|
|
|
- ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
|
|
|
|
}
|
|
}
|
|
- } else if (imgData.kind === _util.ImageKind.RGBA_32BPP) {
|
|
|
|
- const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue);
|
|
|
|
- j = 0;
|
|
|
|
- elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < fullChunks; i++) {
|
|
|
|
- dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
|
|
|
|
- srcPos += elemsInThisChunk;
|
|
|
|
-
|
|
|
|
- if (hasTransferMaps) {
|
|
|
|
- for (let k = 0; k < elemsInThisChunk; k += 4) {
|
|
|
|
- if (transferMapRed) {
|
|
|
|
- dest[k + 0] = transferMapRed[dest[k + 0]];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (transferMapGreen) {
|
|
|
|
- dest[k + 1] = transferMapGreen[dest[k + 1]];
|
|
|
|
- }
|
|
|
|
|
|
|
|
- if (transferMapBlue) {
|
|
|
|
- dest[k + 2] = transferMapBlue[dest[k + 2]];
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ctx.putImageData(chunkImgData, 0, j);
|
|
|
|
- j += FULL_CHUNK_HEIGHT;
|
|
|
|
|
|
+ while (destPos < dest32DataLength) {
|
|
|
|
+ dest32[destPos++] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
- if (i < totalChunks) {
|
|
|
|
- elemsInThisChunk = width * partialChunkHeight * 4;
|
|
|
|
- dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
|
|
|
|
|
|
+ ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
|
|
|
|
+ }
|
|
|
|
+ } else if (imgData.kind === _util.ImageKind.RGBA_32BPP) {
|
|
|
|
+ const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue);
|
|
|
|
+ j = 0;
|
|
|
|
+ elemsInThisChunk = width * FULL_CHUNK_HEIGHT * 4;
|
|
|
|
|
|
- if (hasTransferMaps) {
|
|
|
|
- for (let k = 0; k < elemsInThisChunk; k += 4) {
|
|
|
|
- if (transferMapRed) {
|
|
|
|
- dest[k + 0] = transferMapRed[dest[k + 0]];
|
|
|
|
- }
|
|
|
|
|
|
+ for (i = 0; i < fullChunks; i++) {
|
|
|
|
+ dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
|
|
|
|
+ srcPos += elemsInThisChunk;
|
|
|
|
|
|
- if (transferMapGreen) {
|
|
|
|
- dest[k + 1] = transferMapGreen[dest[k + 1]];
|
|
|
|
- }
|
|
|
|
|
|
+ if (hasTransferMaps) {
|
|
|
|
+ for (let k = 0; k < elemsInThisChunk; k += 4) {
|
|
|
|
+ if (transferMapRed) {
|
|
|
|
+ dest[k + 0] = transferMapRed[dest[k + 0]];
|
|
|
|
+ }
|
|
|
|
|
|
- if (transferMapBlue) {
|
|
|
|
- dest[k + 2] = transferMapBlue[dest[k + 2]];
|
|
|
|
- }
|
|
|
|
|
|
+ if (transferMapGreen) {
|
|
|
|
+ dest[k + 1] = transferMapGreen[dest[k + 1]];
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- ctx.putImageData(chunkImgData, 0, j);
|
|
|
|
- }
|
|
|
|
- } else if (imgData.kind === _util.ImageKind.RGB_24BPP) {
|
|
|
|
- const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue);
|
|
|
|
- thisChunkHeight = FULL_CHUNK_HEIGHT;
|
|
|
|
- elemsInThisChunk = width * thisChunkHeight;
|
|
|
|
-
|
|
|
|
- for (i = 0; i < totalChunks; i++) {
|
|
|
|
- if (i >= fullChunks) {
|
|
|
|
- thisChunkHeight = partialChunkHeight;
|
|
|
|
- elemsInThisChunk = width * thisChunkHeight;
|
|
|
|
|
|
+ if (transferMapBlue) {
|
|
|
|
+ dest[k + 2] = transferMapBlue[dest[k + 2]];
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- destPos = 0;
|
|
|
|
|
|
+ ctx.putImageData(chunkImgData, 0, j);
|
|
|
|
+ j += FULL_CHUNK_HEIGHT;
|
|
|
|
+ }
|
|
|
|
|
|
- for (j = elemsInThisChunk; j--;) {
|
|
|
|
- dest[destPos++] = src[srcPos++];
|
|
|
|
- dest[destPos++] = src[srcPos++];
|
|
|
|
- dest[destPos++] = src[srcPos++];
|
|
|
|
- dest[destPos++] = 255;
|
|
|
|
- }
|
|
|
|
|
|
+ if (i < totalChunks) {
|
|
|
|
+ elemsInThisChunk = width * partialChunkHeight * 4;
|
|
|
|
+ dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
|
|
|
|
|
|
- if (hasTransferMaps) {
|
|
|
|
- for (let k = 0; k < destPos; k += 4) {
|
|
|
|
- if (transferMapRed) {
|
|
|
|
- dest[k + 0] = transferMapRed[dest[k + 0]];
|
|
|
|
- }
|
|
|
|
|
|
+ if (hasTransferMaps) {
|
|
|
|
+ for (let k = 0; k < elemsInThisChunk; k += 4) {
|
|
|
|
+ if (transferMapRed) {
|
|
|
|
+ dest[k + 0] = transferMapRed[dest[k + 0]];
|
|
|
|
+ }
|
|
|
|
|
|
- if (transferMapGreen) {
|
|
|
|
- dest[k + 1] = transferMapGreen[dest[k + 1]];
|
|
|
|
- }
|
|
|
|
|
|
+ if (transferMapGreen) {
|
|
|
|
+ dest[k + 1] = transferMapGreen[dest[k + 1]];
|
|
|
|
+ }
|
|
|
|
|
|
- if (transferMapBlue) {
|
|
|
|
- dest[k + 2] = transferMapBlue[dest[k + 2]];
|
|
|
|
- }
|
|
|
|
|
|
+ if (transferMapBlue) {
|
|
|
|
+ dest[k + 2] = transferMapBlue[dest[k + 2]];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
|
|
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- throw new Error(`bad image kind: ${imgData.kind}`);
|
|
|
|
|
|
+
|
|
|
|
+ ctx.putImageData(chunkImgData, 0, j);
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
+ } else if (imgData.kind === _util.ImageKind.RGB_24BPP) {
|
|
|
|
+ const hasTransferMaps = !!(transferMapRed || transferMapGreen || transferMapBlue);
|
|
|
|
+ thisChunkHeight = FULL_CHUNK_HEIGHT;
|
|
|
|
+ elemsInThisChunk = width * thisChunkHeight;
|
|
|
|
|
|
- function putBinaryImageMask(ctx, imgData) {
|
|
|
|
- const height = imgData.height,
|
|
|
|
- width = imgData.width;
|
|
|
|
- const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
|
|
|
|
- const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
|
|
|
|
- const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
|
|
|
|
- const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
|
|
|
|
- let srcPos = 0;
|
|
|
|
- const src = imgData.data;
|
|
|
|
- const dest = chunkImgData.data;
|
|
|
|
|
|
+ for (i = 0; i < totalChunks; i++) {
|
|
|
|
+ if (i >= fullChunks) {
|
|
|
|
+ thisChunkHeight = partialChunkHeight;
|
|
|
|
+ elemsInThisChunk = width * thisChunkHeight;
|
|
|
|
+ }
|
|
|
|
|
|
- for (let i = 0; i < totalChunks; i++) {
|
|
|
|
- const thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
|
|
|
|
- let destPos = 3;
|
|
|
|
|
|
+ destPos = 0;
|
|
|
|
|
|
- for (let j = 0; j < thisChunkHeight; j++) {
|
|
|
|
- let elem,
|
|
|
|
- mask = 0;
|
|
|
|
|
|
+ for (j = elemsInThisChunk; j--;) {
|
|
|
|
+ dest[destPos++] = src[srcPos++];
|
|
|
|
+ dest[destPos++] = src[srcPos++];
|
|
|
|
+ dest[destPos++] = src[srcPos++];
|
|
|
|
+ dest[destPos++] = 255;
|
|
|
|
+ }
|
|
|
|
|
|
- for (let k = 0; k < width; k++) {
|
|
|
|
- if (!mask) {
|
|
|
|
- elem = src[srcPos++];
|
|
|
|
- mask = 128;
|
|
|
|
|
|
+ if (hasTransferMaps) {
|
|
|
|
+ for (let k = 0; k < destPos; k += 4) {
|
|
|
|
+ if (transferMapRed) {
|
|
|
|
+ dest[k + 0] = transferMapRed[dest[k + 0]];
|
|
}
|
|
}
|
|
|
|
|
|
- dest[destPos] = elem & mask ? 0 : 255;
|
|
|
|
- destPos += 4;
|
|
|
|
- mask >>= 1;
|
|
|
|
|
|
+ if (transferMapGreen) {
|
|
|
|
+ dest[k + 1] = transferMapGreen[dest[k + 1]];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (transferMapBlue) {
|
|
|
|
+ dest[k + 2] = transferMapBlue[dest[k + 2]];
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
|
|
ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
|
|
}
|
|
}
|
|
|
|
+ } else {
|
|
|
|
+ throw new Error(`bad image kind: ${imgData.kind}`);
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- function copyCtxState(sourceCtx, destCtx) {
|
|
|
|
- const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font"];
|
|
|
|
-
|
|
|
|
- for (let i = 0, ii = properties.length; i < ii; i++) {
|
|
|
|
- const property = properties[i];
|
|
|
|
|
|
+function putBinaryImageMask(ctx, imgData) {
|
|
|
|
+ const height = imgData.height,
|
|
|
|
+ width = imgData.width;
|
|
|
|
+ const partialChunkHeight = height % FULL_CHUNK_HEIGHT;
|
|
|
|
+ const fullChunks = (height - partialChunkHeight) / FULL_CHUNK_HEIGHT;
|
|
|
|
+ const totalChunks = partialChunkHeight === 0 ? fullChunks : fullChunks + 1;
|
|
|
|
+ const chunkImgData = ctx.createImageData(width, FULL_CHUNK_HEIGHT);
|
|
|
|
+ let srcPos = 0;
|
|
|
|
+ const src = imgData.data;
|
|
|
|
+ const dest = chunkImgData.data;
|
|
|
|
+
|
|
|
|
+ for (let i = 0; i < totalChunks; i++) {
|
|
|
|
+ const thisChunkHeight = i < fullChunks ? FULL_CHUNK_HEIGHT : partialChunkHeight;
|
|
|
|
+ let destPos = 3;
|
|
|
|
+
|
|
|
|
+ for (let j = 0; j < thisChunkHeight; j++) {
|
|
|
|
+ let elem,
|
|
|
|
+ mask = 0;
|
|
|
|
+
|
|
|
|
+ for (let k = 0; k < width; k++) {
|
|
|
|
+ if (!mask) {
|
|
|
|
+ elem = src[srcPos++];
|
|
|
|
+ mask = 128;
|
|
|
|
+ }
|
|
|
|
|
|
- if (sourceCtx[property] !== undefined) {
|
|
|
|
- destCtx[property] = sourceCtx[property];
|
|
|
|
|
|
+ dest[destPos] = elem & mask ? 0 : 255;
|
|
|
|
+ destPos += 4;
|
|
|
|
+ mask >>= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (sourceCtx.setLineDash !== undefined) {
|
|
|
|
- destCtx.setLineDash(sourceCtx.getLineDash());
|
|
|
|
- destCtx.lineDashOffset = sourceCtx.lineDashOffset;
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.putImageData(chunkImgData, 0, i * FULL_CHUNK_HEIGHT);
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- function resetCtxToDefault(ctx) {
|
|
|
|
- ctx.strokeStyle = "#000000";
|
|
|
|
- ctx.fillStyle = "#000000";
|
|
|
|
- ctx.fillRule = "nonzero";
|
|
|
|
- ctx.globalAlpha = 1;
|
|
|
|
- ctx.lineWidth = 1;
|
|
|
|
- ctx.lineCap = "butt";
|
|
|
|
- ctx.lineJoin = "miter";
|
|
|
|
- ctx.miterLimit = 10;
|
|
|
|
- ctx.globalCompositeOperation = "source-over";
|
|
|
|
- ctx.font = "10px sans-serif";
|
|
|
|
|
|
+function copyCtxState(sourceCtx, destCtx) {
|
|
|
|
+ const properties = ["strokeStyle", "fillStyle", "fillRule", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "globalCompositeOperation", "font"];
|
|
|
|
|
|
- if (ctx.setLineDash !== undefined) {
|
|
|
|
- ctx.setLineDash([]);
|
|
|
|
- ctx.lineDashOffset = 0;
|
|
|
|
|
|
+ for (let i = 0, ii = properties.length; i < ii; i++) {
|
|
|
|
+ const property = properties[i];
|
|
|
|
+
|
|
|
|
+ if (sourceCtx[property] !== undefined) {
|
|
|
|
+ destCtx[property] = sourceCtx[property];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- function composeSMaskBackdrop(bytes, r0, g0, b0) {
|
|
|
|
- const length = bytes.length;
|
|
|
|
-
|
|
|
|
- for (let i = 3; i < length; i += 4) {
|
|
|
|
- const alpha = bytes[i];
|
|
|
|
|
|
+ if (sourceCtx.setLineDash !== undefined) {
|
|
|
|
+ destCtx.setLineDash(sourceCtx.getLineDash());
|
|
|
|
+ destCtx.lineDashOffset = sourceCtx.lineDashOffset;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- if (alpha === 0) {
|
|
|
|
- bytes[i - 3] = r0;
|
|
|
|
- bytes[i - 2] = g0;
|
|
|
|
- bytes[i - 1] = b0;
|
|
|
|
- } else if (alpha < 255) {
|
|
|
|
- const alpha_ = 255 - alpha;
|
|
|
|
- bytes[i - 3] = bytes[i - 3] * alpha + r0 * alpha_ >> 8;
|
|
|
|
- bytes[i - 2] = bytes[i - 2] * alpha + g0 * alpha_ >> 8;
|
|
|
|
- bytes[i - 1] = bytes[i - 1] * alpha + b0 * alpha_ >> 8;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+function resetCtxToDefault(ctx) {
|
|
|
|
+ ctx.strokeStyle = "#000000";
|
|
|
|
+ ctx.fillStyle = "#000000";
|
|
|
|
+ ctx.fillRule = "nonzero";
|
|
|
|
+ ctx.globalAlpha = 1;
|
|
|
|
+ ctx.lineWidth = 1;
|
|
|
|
+ ctx.lineCap = "butt";
|
|
|
|
+ ctx.lineJoin = "miter";
|
|
|
|
+ ctx.miterLimit = 10;
|
|
|
|
+ ctx.globalCompositeOperation = "source-over";
|
|
|
|
+ ctx.font = "10px sans-serif";
|
|
|
|
+
|
|
|
|
+ if (ctx.setLineDash !== undefined) {
|
|
|
|
+ ctx.setLineDash([]);
|
|
|
|
+ ctx.lineDashOffset = 0;
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function composeSMaskBackdrop(bytes, r0, g0, b0) {
|
|
|
|
+ const length = bytes.length;
|
|
|
|
|
|
- function composeSMaskAlpha(maskData, layerData, transferMap) {
|
|
|
|
- const length = maskData.length;
|
|
|
|
- const scale = 1 / 255;
|
|
|
|
|
|
+ for (let i = 3; i < length; i += 4) {
|
|
|
|
+ const alpha = bytes[i];
|
|
|
|
|
|
- for (let i = 3; i < length; i += 4) {
|
|
|
|
- const alpha = transferMap ? transferMap[maskData[i]] : maskData[i];
|
|
|
|
- layerData[i] = layerData[i] * alpha * scale | 0;
|
|
|
|
|
|
+ if (alpha === 0) {
|
|
|
|
+ bytes[i - 3] = r0;
|
|
|
|
+ bytes[i - 2] = g0;
|
|
|
|
+ bytes[i - 1] = b0;
|
|
|
|
+ } else if (alpha < 255) {
|
|
|
|
+ const alpha_ = 255 - alpha;
|
|
|
|
+ bytes[i - 3] = bytes[i - 3] * alpha + r0 * alpha_ >> 8;
|
|
|
|
+ bytes[i - 2] = bytes[i - 2] * alpha + g0 * alpha_ >> 8;
|
|
|
|
+ bytes[i - 1] = bytes[i - 1] * alpha + b0 * alpha_ >> 8;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- function composeSMaskLuminosity(maskData, layerData, transferMap) {
|
|
|
|
- const length = maskData.length;
|
|
|
|
|
|
+function composeSMaskAlpha(maskData, layerData, transferMap) {
|
|
|
|
+ const length = maskData.length;
|
|
|
|
+ const scale = 1 / 255;
|
|
|
|
|
|
- for (let i = 3; i < length; i += 4) {
|
|
|
|
- const y = maskData[i - 3] * 77 + maskData[i - 2] * 152 + maskData[i - 1] * 28;
|
|
|
|
- layerData[i] = transferMap ? layerData[i] * transferMap[y >> 8] >> 8 : layerData[i] * y >> 16;
|
|
|
|
- }
|
|
|
|
|
|
+ for (let i = 3; i < length; i += 4) {
|
|
|
|
+ const alpha = transferMap ? transferMap[maskData[i]] : maskData[i];
|
|
|
|
+ layerData[i] = layerData[i] * alpha * scale | 0;
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap) {
|
|
|
|
- const hasBackdrop = !!backdrop;
|
|
|
|
- const r0 = hasBackdrop ? backdrop[0] : 0;
|
|
|
|
- const g0 = hasBackdrop ? backdrop[1] : 0;
|
|
|
|
- const b0 = hasBackdrop ? backdrop[2] : 0;
|
|
|
|
- let composeFn;
|
|
|
|
|
|
+function composeSMaskLuminosity(maskData, layerData, transferMap) {
|
|
|
|
+ const length = maskData.length;
|
|
|
|
|
|
- if (subtype === "Luminosity") {
|
|
|
|
- composeFn = composeSMaskLuminosity;
|
|
|
|
- } else {
|
|
|
|
- composeFn = composeSMaskAlpha;
|
|
|
|
- }
|
|
|
|
|
|
+ for (let i = 3; i < length; i += 4) {
|
|
|
|
+ const y = maskData[i - 3] * 77 + maskData[i - 2] * 152 + maskData[i - 1] * 28;
|
|
|
|
+ layerData[i] = transferMap ? layerData[i] * transferMap[y >> 8] >> 8 : layerData[i] * y >> 16;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- const PIXELS_TO_PROCESS = 1048576;
|
|
|
|
- const chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
|
|
|
|
|
|
+function genericComposeSMask(maskCtx, layerCtx, width, height, subtype, backdrop, transferMap) {
|
|
|
|
+ const hasBackdrop = !!backdrop;
|
|
|
|
+ const r0 = hasBackdrop ? backdrop[0] : 0;
|
|
|
|
+ const g0 = hasBackdrop ? backdrop[1] : 0;
|
|
|
|
+ const b0 = hasBackdrop ? backdrop[2] : 0;
|
|
|
|
+ let composeFn;
|
|
|
|
+
|
|
|
|
+ if (subtype === "Luminosity") {
|
|
|
|
+ composeFn = composeSMaskLuminosity;
|
|
|
|
+ } else {
|
|
|
|
+ composeFn = composeSMaskAlpha;
|
|
|
|
+ }
|
|
|
|
|
|
- for (let row = 0; row < height; row += chunkSize) {
|
|
|
|
- const chunkHeight = Math.min(chunkSize, height - row);
|
|
|
|
- const maskData = maskCtx.getImageData(0, row, width, chunkHeight);
|
|
|
|
- const layerData = layerCtx.getImageData(0, row, width, chunkHeight);
|
|
|
|
|
|
+ const PIXELS_TO_PROCESS = 1048576;
|
|
|
|
+ const chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
|
|
|
|
|
|
- if (hasBackdrop) {
|
|
|
|
- composeSMaskBackdrop(maskData.data, r0, g0, b0);
|
|
|
|
- }
|
|
|
|
|
|
+ for (let row = 0; row < height; row += chunkSize) {
|
|
|
|
+ const chunkHeight = Math.min(chunkSize, height - row);
|
|
|
|
+ const maskData = maskCtx.getImageData(0, row, width, chunkHeight);
|
|
|
|
+ const layerData = layerCtx.getImageData(0, row, width, chunkHeight);
|
|
|
|
|
|
- composeFn(maskData.data, layerData.data, transferMap);
|
|
|
|
- maskCtx.putImageData(layerData, 0, row);
|
|
|
|
|
|
+ if (hasBackdrop) {
|
|
|
|
+ composeSMaskBackdrop(maskData.data, r0, g0, b0);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ composeFn(maskData.data, layerData.data, transferMap);
|
|
|
|
+ maskCtx.putImageData(layerData, 0, row);
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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 getImageSmoothingEnabled(transform, interpolate) {
|
|
|
|
+ const scale = _util.Util.singularValueDecompose2dScale(transform);
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
+ scale[0] = Math.fround(scale[0]);
|
|
|
|
+ scale[1] = Math.fround(scale[1]);
|
|
|
|
+ const actualScale = Math.fround((globalThis.devicePixelRatio || 1) * _display_utils.PixelsPerInch.PDF_TO_CSS_UNITS);
|
|
|
|
+
|
|
|
|
+ if (interpolate !== undefined) {
|
|
|
|
+ return interpolate;
|
|
|
|
+ } else if (scale[0] <= actualScale || scale[1] <= actualScale) {
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
- const LINE_CAP_STYLES = ["butt", "round", "square"];
|
|
|
|
- const LINE_JOIN_STYLES = ["miter", "round", "bevel"];
|
|
|
|
- const NORMAL_CLIP = {};
|
|
|
|
- const EO_CLIP = {};
|
|
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
|
|
- class CanvasGraphics {
|
|
|
|
- constructor(canvasCtx, commonObjs, objs, canvasFactory, imageLayer, optionalContentConfig) {
|
|
|
|
- this.ctx = canvasCtx;
|
|
|
|
- this.current = new CanvasExtraState();
|
|
|
|
- this.stateStack = [];
|
|
|
|
- this.pendingClip = null;
|
|
|
|
- this.pendingEOFill = false;
|
|
|
|
- this.res = null;
|
|
|
|
- this.xobjs = null;
|
|
|
|
- this.commonObjs = commonObjs;
|
|
|
|
- this.objs = objs;
|
|
|
|
- this.canvasFactory = canvasFactory;
|
|
|
|
- this.imageLayer = imageLayer;
|
|
|
|
- this.groupStack = [];
|
|
|
|
- this.processingType3 = null;
|
|
|
|
- this.baseTransform = null;
|
|
|
|
- this.baseTransformStack = [];
|
|
|
|
- this.groupLevel = 0;
|
|
|
|
- this.smaskStack = [];
|
|
|
|
- this.smaskCounter = 0;
|
|
|
|
- this.tempSMask = null;
|
|
|
|
- this.contentVisible = true;
|
|
|
|
- this.markedContentStack = [];
|
|
|
|
- this.optionalContentConfig = optionalContentConfig;
|
|
|
|
- this.cachedCanvases = new CachedCanvases(this.canvasFactory);
|
|
|
|
- this.cachedPatterns = new Map();
|
|
|
|
-
|
|
|
|
- if (canvasCtx) {
|
|
|
|
- addContextCurrentTransform(canvasCtx);
|
|
|
|
- }
|
|
|
|
|
|
+const LINE_CAP_STYLES = ["butt", "round", "square"];
|
|
|
|
+const LINE_JOIN_STYLES = ["miter", "round", "bevel"];
|
|
|
|
+const NORMAL_CLIP = {};
|
|
|
|
+const EO_CLIP = {};
|
|
|
|
+
|
|
|
|
+class CanvasGraphics {
|
|
|
|
+ constructor(canvasCtx, commonObjs, objs, canvasFactory, imageLayer, optionalContentConfig) {
|
|
|
|
+ this.ctx = canvasCtx;
|
|
|
|
+ this.current = new CanvasExtraState();
|
|
|
|
+ this.stateStack = [];
|
|
|
|
+ this.pendingClip = null;
|
|
|
|
+ this.pendingEOFill = false;
|
|
|
|
+ this.res = null;
|
|
|
|
+ this.xobjs = null;
|
|
|
|
+ this.commonObjs = commonObjs;
|
|
|
|
+ this.objs = objs;
|
|
|
|
+ this.canvasFactory = canvasFactory;
|
|
|
|
+ this.imageLayer = imageLayer;
|
|
|
|
+ this.groupStack = [];
|
|
|
|
+ this.processingType3 = null;
|
|
|
|
+ this.baseTransform = null;
|
|
|
|
+ this.baseTransformStack = [];
|
|
|
|
+ this.groupLevel = 0;
|
|
|
|
+ this.smaskStack = [];
|
|
|
|
+ this.smaskCounter = 0;
|
|
|
|
+ this.tempSMask = null;
|
|
|
|
+ this.contentVisible = true;
|
|
|
|
+ this.markedContentStack = [];
|
|
|
|
+ this.optionalContentConfig = optionalContentConfig;
|
|
|
|
+ this.cachedCanvases = new CachedCanvases(this.canvasFactory);
|
|
|
|
+ this.cachedCanvasPatterns = new LRUCache(MAX_CACHED_CANVAS_PATTERNS);
|
|
|
|
+ this.cachedPatterns = new Map();
|
|
|
|
+
|
|
|
|
+ if (canvasCtx) {
|
|
|
|
+ addContextCurrentTransform(canvasCtx);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._cachedGetSinglePixelWidth = null;
|
|
|
|
+ }
|
|
|
|
|
|
- this._cachedGetSinglePixelWidth = null;
|
|
|
|
|
|
+ beginDrawing({
|
|
|
|
+ transform,
|
|
|
|
+ viewport,
|
|
|
|
+ transparency = false,
|
|
|
|
+ background = null
|
|
|
|
+ }) {
|
|
|
|
+ const width = this.ctx.canvas.width;
|
|
|
|
+ const height = this.ctx.canvas.height;
|
|
|
|
+ this.ctx.save();
|
|
|
|
+ this.ctx.fillStyle = background || "rgb(255, 255, 255)";
|
|
|
|
+ this.ctx.fillRect(0, 0, width, height);
|
|
|
|
+ this.ctx.restore();
|
|
|
|
+
|
|
|
|
+ if (transparency) {
|
|
|
|
+ const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height, true);
|
|
|
|
+ this.compositeCtx = this.ctx;
|
|
|
|
+ this.transparentCanvas = transparentCanvas.canvas;
|
|
|
|
+ this.ctx = transparentCanvas.context;
|
|
|
|
+ this.ctx.save();
|
|
|
|
+ this.ctx.transform.apply(this.ctx, this.compositeCtx.mozCurrentTransform);
|
|
}
|
|
}
|
|
|
|
|
|
- beginDrawing({
|
|
|
|
- transform,
|
|
|
|
- viewport,
|
|
|
|
- transparency = false,
|
|
|
|
- background = null
|
|
|
|
- }) {
|
|
|
|
- const width = this.ctx.canvas.width;
|
|
|
|
- const height = this.ctx.canvas.height;
|
|
|
|
- this.ctx.save();
|
|
|
|
- this.ctx.fillStyle = background || "rgb(255, 255, 255)";
|
|
|
|
- this.ctx.fillRect(0, 0, width, height);
|
|
|
|
- this.ctx.restore();
|
|
|
|
|
|
+ this.ctx.save();
|
|
|
|
+ resetCtxToDefault(this.ctx);
|
|
|
|
|
|
- if (transparency) {
|
|
|
|
- const transparentCanvas = this.cachedCanvases.getCanvas("transparent", width, height, true);
|
|
|
|
- this.compositeCtx = this.ctx;
|
|
|
|
- this.transparentCanvas = transparentCanvas.canvas;
|
|
|
|
- this.ctx = transparentCanvas.context;
|
|
|
|
- this.ctx.save();
|
|
|
|
- this.ctx.transform.apply(this.ctx, this.compositeCtx.mozCurrentTransform);
|
|
|
|
- }
|
|
|
|
|
|
+ if (transform) {
|
|
|
|
+ this.ctx.transform.apply(this.ctx, transform);
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.save();
|
|
|
|
- resetCtxToDefault(this.ctx);
|
|
|
|
|
|
+ this.ctx.transform.apply(this.ctx, viewport.transform);
|
|
|
|
+ this.baseTransform = this.ctx.mozCurrentTransform.slice();
|
|
|
|
+ this._combinedScaleFactor = Math.hypot(this.baseTransform[0], this.baseTransform[2]);
|
|
|
|
|
|
- if (transform) {
|
|
|
|
- this.ctx.transform.apply(this.ctx, transform);
|
|
|
|
- }
|
|
|
|
|
|
+ if (this.imageLayer) {
|
|
|
|
+ this.imageLayer.beginLayout();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.transform.apply(this.ctx, viewport.transform);
|
|
|
|
- this.baseTransform = this.ctx.mozCurrentTransform.slice();
|
|
|
|
- this._combinedScaleFactor = Math.hypot(this.baseTransform[0], this.baseTransform[2]);
|
|
|
|
|
|
+ executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) {
|
|
|
|
+ const argsArray = operatorList.argsArray;
|
|
|
|
+ const fnArray = operatorList.fnArray;
|
|
|
|
+ let i = executionStartIdx || 0;
|
|
|
|
+ const argsArrayLen = argsArray.length;
|
|
|
|
|
|
- if (this.imageLayer) {
|
|
|
|
- this.imageLayer.beginLayout();
|
|
|
|
- }
|
|
|
|
|
|
+ if (argsArrayLen === i) {
|
|
|
|
+ return i;
|
|
}
|
|
}
|
|
|
|
|
|
- executeOperatorList(operatorList, executionStartIdx, continueCallback, stepper) {
|
|
|
|
- const argsArray = operatorList.argsArray;
|
|
|
|
- const fnArray = operatorList.fnArray;
|
|
|
|
- let i = executionStartIdx || 0;
|
|
|
|
- const argsArrayLen = argsArray.length;
|
|
|
|
|
|
+ const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function";
|
|
|
|
+ const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
|
|
|
|
+ let steps = 0;
|
|
|
|
+ const commonObjs = this.commonObjs;
|
|
|
|
+ const objs = this.objs;
|
|
|
|
+ let fnId;
|
|
|
|
|
|
- if (argsArrayLen === i) {
|
|
|
|
|
|
+ while (true) {
|
|
|
|
+ if (stepper !== undefined && i === stepper.nextBreakPoint) {
|
|
|
|
+ stepper.breakIt(i, continueCallback);
|
|
return i;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
|
|
- const chunkOperations = argsArrayLen - i > EXECUTION_STEPS && typeof continueCallback === "function";
|
|
|
|
- const endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
|
|
|
|
- let steps = 0;
|
|
|
|
- const commonObjs = this.commonObjs;
|
|
|
|
- const objs = this.objs;
|
|
|
|
- let fnId;
|
|
|
|
-
|
|
|
|
- while (true) {
|
|
|
|
- if (stepper !== undefined && i === stepper.nextBreakPoint) {
|
|
|
|
- stepper.breakIt(i, continueCallback);
|
|
|
|
- return i;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fnId = fnArray[i];
|
|
|
|
|
|
+ fnId = fnArray[i];
|
|
|
|
|
|
- if (fnId !== _util.OPS.dependency) {
|
|
|
|
- this[fnId].apply(this, argsArray[i]);
|
|
|
|
- } else {
|
|
|
|
- for (const depObjId of argsArray[i]) {
|
|
|
|
- const objsPool = depObjId.startsWith("g_") ? commonObjs : objs;
|
|
|
|
|
|
+ if (fnId !== _util.OPS.dependency) {
|
|
|
|
+ this[fnId].apply(this, argsArray[i]);
|
|
|
|
+ } else {
|
|
|
|
+ for (const depObjId of argsArray[i]) {
|
|
|
|
+ const objsPool = depObjId.startsWith("g_") ? commonObjs : objs;
|
|
|
|
|
|
- if (!objsPool.has(depObjId)) {
|
|
|
|
- objsPool.get(depObjId, continueCallback);
|
|
|
|
- return i;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!objsPool.has(depObjId)) {
|
|
|
|
+ objsPool.get(depObjId, continueCallback);
|
|
|
|
+ return i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ i++;
|
|
|
|
|
|
- i++;
|
|
|
|
|
|
+ if (i === argsArrayLen) {
|
|
|
|
+ return i;
|
|
|
|
+ }
|
|
|
|
|
|
- if (i === argsArrayLen) {
|
|
|
|
|
|
+ if (chunkOperations && ++steps > EXECUTION_STEPS) {
|
|
|
|
+ if (Date.now() > endTime) {
|
|
|
|
+ continueCallback();
|
|
return i;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
|
|
- if (chunkOperations && ++steps > EXECUTION_STEPS) {
|
|
|
|
- if (Date.now() > endTime) {
|
|
|
|
- continueCallback();
|
|
|
|
- return i;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- steps = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ steps = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- endDrawing() {
|
|
|
|
- while (this.stateStack.length || this.current.activeSMask !== null) {
|
|
|
|
- this.restore();
|
|
|
|
- }
|
|
|
|
|
|
+ endDrawing() {
|
|
|
|
+ while (this.stateStack.length || this.current.activeSMask !== null) {
|
|
|
|
+ this.restore();
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.restore();
|
|
|
|
|
|
+ this.ctx.restore();
|
|
|
|
|
|
- if (this.transparentCanvas) {
|
|
|
|
- this.ctx = this.compositeCtx;
|
|
|
|
- this.ctx.save();
|
|
|
|
- this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
- this.ctx.drawImage(this.transparentCanvas, 0, 0);
|
|
|
|
- this.ctx.restore();
|
|
|
|
- this.transparentCanvas = null;
|
|
|
|
- }
|
|
|
|
|
|
+ if (this.transparentCanvas) {
|
|
|
|
+ this.ctx = this.compositeCtx;
|
|
|
|
+ this.ctx.save();
|
|
|
|
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
+ this.ctx.drawImage(this.transparentCanvas, 0, 0);
|
|
|
|
+ this.ctx.restore();
|
|
|
|
+ this.transparentCanvas = null;
|
|
|
|
+ }
|
|
|
|
|
|
- this.cachedCanvases.clear();
|
|
|
|
- this.cachedPatterns.clear();
|
|
|
|
|
|
+ this.cachedCanvases.clear();
|
|
|
|
+ this.cachedCanvasPatterns.clear();
|
|
|
|
+ this.cachedPatterns.clear();
|
|
|
|
|
|
- if (this.imageLayer) {
|
|
|
|
- this.imageLayer.endLayout();
|
|
|
|
- }
|
|
|
|
|
|
+ if (this.imageLayer) {
|
|
|
|
+ this.imageLayer.endLayout();
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- _scaleImage(img, inverseTransform) {
|
|
|
|
- const width = img.width;
|
|
|
|
- const height = img.height;
|
|
|
|
- let widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1);
|
|
|
|
- let heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1);
|
|
|
|
- let paintWidth = width,
|
|
|
|
- paintHeight = height;
|
|
|
|
- let tmpCanvasId = "prescale1";
|
|
|
|
- let tmpCanvas, tmpCtx;
|
|
|
|
|
|
+ _scaleImage(img, inverseTransform) {
|
|
|
|
+ const width = img.width;
|
|
|
|
+ const height = img.height;
|
|
|
|
+ let widthScale = Math.max(Math.hypot(inverseTransform[0], inverseTransform[1]), 1);
|
|
|
|
+ let heightScale = Math.max(Math.hypot(inverseTransform[2], inverseTransform[3]), 1);
|
|
|
|
+ let paintWidth = width,
|
|
|
|
+ paintHeight = height;
|
|
|
|
+ let tmpCanvasId = "prescale1";
|
|
|
|
+ let tmpCanvas, tmpCtx;
|
|
|
|
+
|
|
|
|
+ while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) {
|
|
|
|
+ let newWidth = paintWidth,
|
|
|
|
+ newHeight = paintHeight;
|
|
|
|
+
|
|
|
|
+ if (widthScale > 2 && paintWidth > 1) {
|
|
|
|
+ newWidth = Math.ceil(paintWidth / 2);
|
|
|
|
+ widthScale /= paintWidth / newWidth;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (heightScale > 2 && paintHeight > 1) {
|
|
|
|
+ newHeight = Math.ceil(paintHeight / 2);
|
|
|
|
+ heightScale /= paintHeight / newHeight;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
|
|
|
|
+ tmpCtx = tmpCanvas.context;
|
|
|
|
+ tmpCtx.clearRect(0, 0, newWidth, newHeight);
|
|
|
|
+ tmpCtx.drawImage(img, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight);
|
|
|
|
+ img = tmpCanvas.canvas;
|
|
|
|
+ paintWidth = newWidth;
|
|
|
|
+ paintHeight = newHeight;
|
|
|
|
+ tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ img,
|
|
|
|
+ paintWidth,
|
|
|
|
+ paintHeight
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
|
|
- while (widthScale > 2 && paintWidth > 1 || heightScale > 2 && paintHeight > 1) {
|
|
|
|
- let newWidth = paintWidth,
|
|
|
|
- newHeight = paintHeight;
|
|
|
|
|
|
+ _createMaskCanvas(img) {
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const width = img.width,
|
|
|
|
+ height = img.height;
|
|
|
|
+ const fillColor = this.current.fillColor;
|
|
|
|
+ const isPatternFill = this.current.patternFill;
|
|
|
|
+ const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
|
|
|
|
+ const maskCtx = maskCanvas.context;
|
|
|
|
+ putBinaryImageMask(maskCtx, img);
|
|
|
|
+ const objToCanvas = ctx.mozCurrentTransform;
|
|
|
|
|
|
- if (widthScale > 2 && paintWidth > 1) {
|
|
|
|
- newWidth = Math.ceil(paintWidth / 2);
|
|
|
|
- widthScale /= paintWidth / newWidth;
|
|
|
|
- }
|
|
|
|
|
|
+ let maskToCanvas = _util.Util.transform(objToCanvas, [1 / width, 0, 0, -1 / height, 0, 0]);
|
|
|
|
|
|
- if (heightScale > 2 && paintHeight > 1) {
|
|
|
|
- newHeight = Math.ceil(paintHeight / 2);
|
|
|
|
- heightScale /= paintHeight / newHeight;
|
|
|
|
- }
|
|
|
|
|
|
+ maskToCanvas = _util.Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]);
|
|
|
|
|
|
- tmpCanvas = this.cachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
|
|
|
|
- tmpCtx = tmpCanvas.context;
|
|
|
|
- tmpCtx.clearRect(0, 0, newWidth, newHeight);
|
|
|
|
- tmpCtx.drawImage(img, 0, 0, paintWidth, paintHeight, 0, 0, newWidth, newHeight);
|
|
|
|
- img = tmpCanvas.canvas;
|
|
|
|
- paintWidth = newWidth;
|
|
|
|
- paintHeight = newHeight;
|
|
|
|
- tmpCanvasId = tmpCanvasId === "prescale1" ? "prescale2" : "prescale1";
|
|
|
|
- }
|
|
|
|
|
|
+ const cord1 = _util.Util.applyTransform([0, 0], maskToCanvas);
|
|
|
|
|
|
- return {
|
|
|
|
- img,
|
|
|
|
- paintWidth,
|
|
|
|
- paintHeight
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
|
|
+ const cord2 = _util.Util.applyTransform([width, height], maskToCanvas);
|
|
|
|
|
|
- _createMaskCanvas(img) {
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const width = img.width,
|
|
|
|
- height = img.height;
|
|
|
|
- const fillColor = this.current.fillColor;
|
|
|
|
- const isPatternFill = this.current.patternFill;
|
|
|
|
- const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
|
|
|
|
- const maskCtx = maskCanvas.context;
|
|
|
|
- putBinaryImageMask(maskCtx, img);
|
|
|
|
- const objToCanvas = ctx.mozCurrentTransform;
|
|
|
|
|
|
+ const rect = _util.Util.normalizeRect([cord1[0], cord1[1], cord2[0], cord2[1]]);
|
|
|
|
|
|
- let maskToCanvas = _util.Util.transform(objToCanvas, [1 / width, 0, 0, -1 / height, 0, 0]);
|
|
|
|
|
|
+ const drawnWidth = Math.ceil(rect[2] - rect[0]);
|
|
|
|
+ const drawnHeight = Math.ceil(rect[3] - rect[1]);
|
|
|
|
+ const fillCanvas = this.cachedCanvases.getCanvas("fillCanvas", drawnWidth, drawnHeight, true);
|
|
|
|
+ const fillCtx = fillCanvas.context;
|
|
|
|
+ const offsetX = Math.min(cord1[0], cord2[0]);
|
|
|
|
+ const offsetY = Math.min(cord1[1], cord2[1]);
|
|
|
|
+ fillCtx.translate(-offsetX, -offsetY);
|
|
|
|
+ fillCtx.transform.apply(fillCtx, maskToCanvas);
|
|
|
|
|
|
- maskToCanvas = _util.Util.transform(maskToCanvas, [1, 0, 0, 1, 0, -height]);
|
|
|
|
|
|
+ const scaled = this._scaleImage(maskCanvas.canvas, fillCtx.mozCurrentTransformInverse);
|
|
|
|
|
|
- const cord1 = _util.Util.applyTransform([0, 0], maskToCanvas);
|
|
|
|
|
|
+ fillCtx.imageSmoothingEnabled = getImageSmoothingEnabled(fillCtx.mozCurrentTransform, img.interpolate);
|
|
|
|
+ fillCtx.drawImage(scaled.img, 0, 0, scaled.img.width, scaled.img.height, 0, 0, width, height);
|
|
|
|
+ fillCtx.globalCompositeOperation = "source-in";
|
|
|
|
|
|
- const cord2 = _util.Util.applyTransform([width, height], maskToCanvas);
|
|
|
|
|
|
+ const inverse = _util.Util.transform(fillCtx.mozCurrentTransformInverse, [1, 0, 0, 1, -offsetX, -offsetY]);
|
|
|
|
|
|
- const rect = _util.Util.normalizeRect([cord1[0], cord1[1], cord2[0], cord2[1]]);
|
|
|
|
|
|
+ fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, false) : fillColor;
|
|
|
|
+ fillCtx.fillRect(0, 0, width, height);
|
|
|
|
+ return {
|
|
|
|
+ canvas: fillCanvas.canvas,
|
|
|
|
+ offsetX: Math.round(offsetX),
|
|
|
|
+ offsetY: Math.round(offsetY)
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
|
|
- const drawnWidth = Math.ceil(rect[2] - rect[0]);
|
|
|
|
- const drawnHeight = Math.ceil(rect[3] - rect[1]);
|
|
|
|
- const fillCanvas = this.cachedCanvases.getCanvas("fillCanvas", drawnWidth, drawnHeight, true);
|
|
|
|
- const fillCtx = fillCanvas.context;
|
|
|
|
- const offsetX = Math.min(cord1[0], cord2[0]);
|
|
|
|
- const offsetY = Math.min(cord1[1], cord2[1]);
|
|
|
|
- fillCtx.translate(-offsetX, -offsetY);
|
|
|
|
- fillCtx.transform.apply(fillCtx, maskToCanvas);
|
|
|
|
|
|
+ setLineWidth(width) {
|
|
|
|
+ this.current.lineWidth = width;
|
|
|
|
+ this.ctx.lineWidth = width;
|
|
|
|
+ }
|
|
|
|
|
|
- const scaled = this._scaleImage(maskCanvas.canvas, fillCtx.mozCurrentTransformInverse);
|
|
|
|
|
|
+ setLineCap(style) {
|
|
|
|
+ this.ctx.lineCap = LINE_CAP_STYLES[style];
|
|
|
|
+ }
|
|
|
|
|
|
- fillCtx.drawImage(scaled.img, 0, 0, scaled.img.width, scaled.img.height, 0, 0, width, height);
|
|
|
|
- fillCtx.globalCompositeOperation = "source-in";
|
|
|
|
|
|
+ setLineJoin(style) {
|
|
|
|
+ this.ctx.lineJoin = LINE_JOIN_STYLES[style];
|
|
|
|
+ }
|
|
|
|
|
|
- const inverse = _util.Util.transform(fillCtx.mozCurrentTransformInverse, [1, 0, 0, 1, -offsetX, -offsetY]);
|
|
|
|
|
|
+ setMiterLimit(limit) {
|
|
|
|
+ this.ctx.miterLimit = limit;
|
|
|
|
+ }
|
|
|
|
|
|
- fillCtx.fillStyle = isPatternFill ? fillColor.getPattern(ctx, this, inverse, false) : fillColor;
|
|
|
|
- fillCtx.fillRect(0, 0, width, height);
|
|
|
|
- return {
|
|
|
|
- canvas: fillCanvas.canvas,
|
|
|
|
- offsetX: Math.round(offsetX),
|
|
|
|
- offsetY: Math.round(offsetY)
|
|
|
|
- };
|
|
|
|
- }
|
|
|
|
|
|
+ setDash(dashArray, dashPhase) {
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
|
|
- setLineWidth(width) {
|
|
|
|
- this.current.lineWidth = width;
|
|
|
|
- this.ctx.lineWidth = width;
|
|
|
|
|
|
+ if (ctx.setLineDash !== undefined) {
|
|
|
|
+ ctx.setLineDash(dashArray);
|
|
|
|
+ ctx.lineDashOffset = dashPhase;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- setLineCap(style) {
|
|
|
|
- this.ctx.lineCap = LINE_CAP_STYLES[style];
|
|
|
|
- }
|
|
|
|
|
|
+ setRenderingIntent(intent) {}
|
|
|
|
|
|
- setLineJoin(style) {
|
|
|
|
- this.ctx.lineJoin = LINE_JOIN_STYLES[style];
|
|
|
|
- }
|
|
|
|
|
|
+ setFlatness(flatness) {}
|
|
|
|
|
|
- setMiterLimit(limit) {
|
|
|
|
- this.ctx.miterLimit = limit;
|
|
|
|
- }
|
|
|
|
|
|
+ setGState(states) {
|
|
|
|
+ for (let i = 0, ii = states.length; i < ii; i++) {
|
|
|
|
+ const state = states[i];
|
|
|
|
+ const key = state[0];
|
|
|
|
+ const value = state[1];
|
|
|
|
|
|
- setDash(dashArray, dashPhase) {
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
|
|
+ switch (key) {
|
|
|
|
+ case "LW":
|
|
|
|
+ this.setLineWidth(value);
|
|
|
|
+ break;
|
|
|
|
|
|
- if (ctx.setLineDash !== undefined) {
|
|
|
|
- ctx.setLineDash(dashArray);
|
|
|
|
- ctx.lineDashOffset = dashPhase;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ case "LC":
|
|
|
|
+ this.setLineCap(value);
|
|
|
|
+ break;
|
|
|
|
|
|
- setRenderingIntent(intent) {}
|
|
|
|
|
|
+ case "LJ":
|
|
|
|
+ this.setLineJoin(value);
|
|
|
|
+ break;
|
|
|
|
|
|
- setFlatness(flatness) {}
|
|
|
|
|
|
+ case "ML":
|
|
|
|
+ this.setMiterLimit(value);
|
|
|
|
+ break;
|
|
|
|
|
|
- setGState(states) {
|
|
|
|
- for (let i = 0, ii = states.length; i < ii; i++) {
|
|
|
|
- const state = states[i];
|
|
|
|
- const key = state[0];
|
|
|
|
- const value = state[1];
|
|
|
|
|
|
+ case "D":
|
|
|
|
+ this.setDash(value[0], value[1]);
|
|
|
|
+ break;
|
|
|
|
|
|
- switch (key) {
|
|
|
|
- case "LW":
|
|
|
|
- this.setLineWidth(value);
|
|
|
|
- break;
|
|
|
|
|
|
+ case "RI":
|
|
|
|
+ this.setRenderingIntent(value);
|
|
|
|
+ break;
|
|
|
|
|
|
- case "LC":
|
|
|
|
- this.setLineCap(value);
|
|
|
|
- break;
|
|
|
|
|
|
+ case "FL":
|
|
|
|
+ this.setFlatness(value);
|
|
|
|
+ break;
|
|
|
|
|
|
- case "LJ":
|
|
|
|
- this.setLineJoin(value);
|
|
|
|
- break;
|
|
|
|
|
|
+ case "Font":
|
|
|
|
+ this.setFont(value[0], value[1]);
|
|
|
|
+ break;
|
|
|
|
|
|
- case "ML":
|
|
|
|
- this.setMiterLimit(value);
|
|
|
|
- break;
|
|
|
|
|
|
+ case "CA":
|
|
|
|
+ this.current.strokeAlpha = state[1];
|
|
|
|
+ break;
|
|
|
|
|
|
- case "D":
|
|
|
|
- this.setDash(value[0], value[1]);
|
|
|
|
- break;
|
|
|
|
|
|
+ case "ca":
|
|
|
|
+ this.current.fillAlpha = state[1];
|
|
|
|
+ this.ctx.globalAlpha = state[1];
|
|
|
|
+ break;
|
|
|
|
|
|
- case "RI":
|
|
|
|
- this.setRenderingIntent(value);
|
|
|
|
- break;
|
|
|
|
|
|
+ case "BM":
|
|
|
|
+ this.ctx.globalCompositeOperation = value;
|
|
|
|
+ break;
|
|
|
|
|
|
- case "FL":
|
|
|
|
- this.setFlatness(value);
|
|
|
|
- break;
|
|
|
|
|
|
+ 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();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- case "Font":
|
|
|
|
- this.setFont(value[0], value[1]);
|
|
|
|
- break;
|
|
|
|
|
|
+ this.current.activeSMask = value ? this.tempSMask : null;
|
|
|
|
|
|
- case "CA":
|
|
|
|
- this.current.strokeAlpha = state[1];
|
|
|
|
- break;
|
|
|
|
|
|
+ if (this.current.activeSMask) {
|
|
|
|
+ this.beginSMaskGroup();
|
|
|
|
+ }
|
|
|
|
|
|
- case "ca":
|
|
|
|
- this.current.fillAlpha = state[1];
|
|
|
|
- this.ctx.globalAlpha = state[1];
|
|
|
|
- break;
|
|
|
|
|
|
+ this.tempSMask = null;
|
|
|
|
+ break;
|
|
|
|
|
|
- case "BM":
|
|
|
|
- this.ctx.globalCompositeOperation = value;
|
|
|
|
- break;
|
|
|
|
|
|
+ case "TR":
|
|
|
|
+ this.current.transferMaps = value;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- 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();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ beginSMaskGroup() {
|
|
|
|
+ const activeSMask = this.current.activeSMask;
|
|
|
|
+ const drawnWidth = activeSMask.canvas.width;
|
|
|
|
+ const drawnHeight = activeSMask.canvas.height;
|
|
|
|
+ const cacheId = "smaskGroupAt" + this.groupLevel;
|
|
|
|
+ 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.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
|
|
|
|
+ this.groupStack.push(currentCtx);
|
|
|
|
+ this.groupLevel++;
|
|
|
|
+ }
|
|
|
|
|
|
- this.current.activeSMask = value ? this.tempSMask : null;
|
|
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ 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();
|
|
|
|
+ }
|
|
|
|
|
|
- if (this.current.activeSMask) {
|
|
|
|
- this.beginSMaskGroup();
|
|
|
|
- }
|
|
|
|
|
|
+ resumeSMaskGroup() {
|
|
|
|
+ const groupCtx = this.current.resumeSMaskCtx;
|
|
|
|
+ const currentCtx = this.ctx;
|
|
|
|
+ this.ctx = groupCtx;
|
|
|
|
+ this.groupStack.push(currentCtx);
|
|
|
|
+ this.groupLevel++;
|
|
|
|
+ }
|
|
|
|
|
|
- this.tempSMask = null;
|
|
|
|
- break;
|
|
|
|
|
|
+ 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);
|
|
|
|
|
|
- case "TR":
|
|
|
|
- this.current.transferMaps = value;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
|
|
|
|
|
|
- beginSMaskGroup() {
|
|
|
|
- const activeSMask = this.current.activeSMask;
|
|
|
|
- const drawnWidth = activeSMask.canvas.width;
|
|
|
|
- const drawnHeight = activeSMask.canvas.height;
|
|
|
|
- const cacheId = "smaskGroupAt" + this.groupLevel;
|
|
|
|
- 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.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;
|
|
|
|
|
|
+ this.ctx.transform.apply(this.ctx, deltaTransform);
|
|
|
|
+ }
|
|
|
|
|
|
- const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
|
|
|
|
|
|
+ save() {
|
|
|
|
+ this.ctx.save();
|
|
|
|
+ const old = this.current;
|
|
|
|
+ this.stateStack.push(old);
|
|
|
|
+ this.current = old.clone();
|
|
|
|
+ this.current.resumeSMaskCtx = null;
|
|
|
|
+ }
|
|
|
|
|
|
- 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();
|
|
|
|
|
|
+ restore() {
|
|
|
|
+ if (this.current.resumeSMaskCtx) {
|
|
|
|
+ this.resumeSMaskGroup();
|
|
}
|
|
}
|
|
|
|
|
|
- resumeSMaskGroup() {
|
|
|
|
- const groupCtx = this.current.resumeSMaskCtx;
|
|
|
|
- const currentCtx = this.ctx;
|
|
|
|
- this.ctx = groupCtx;
|
|
|
|
- this.groupStack.push(currentCtx);
|
|
|
|
- this.groupLevel++;
|
|
|
|
|
|
+ if (this.current.activeSMask !== null && (this.stateStack.length === 0 || this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask)) {
|
|
|
|
+ this.endSMaskGroup();
|
|
}
|
|
}
|
|
|
|
|
|
- endSMaskGroup() {
|
|
|
|
- const groupCtx = this.ctx;
|
|
|
|
- this.groupLevel--;
|
|
|
|
- this.ctx = this.groupStack.pop();
|
|
|
|
- composeSMask(this.ctx, this.current.activeSMask, groupCtx);
|
|
|
|
|
|
+ if (this.stateStack.length !== 0) {
|
|
|
|
+ this.current = this.stateStack.pop();
|
|
this.ctx.restore();
|
|
this.ctx.restore();
|
|
- copyCtxState(groupCtx, this.ctx);
|
|
|
|
|
|
+ this.pendingClip = null;
|
|
|
|
+ this._cachedGetSinglePixelWidth = null;
|
|
|
|
+ } else {
|
|
|
|
+ this.current.activeSMask = null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- const deltaTransform = _util.Util.transform(this.current.activeSMask.startTransformInverse, groupCtx.mozCurrentTransform);
|
|
|
|
|
|
+ transform(a, b, c, d, e, f) {
|
|
|
|
+ this.ctx.transform(a, b, c, d, e, f);
|
|
|
|
+ this._cachedGetSinglePixelWidth = null;
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.transform.apply(this.ctx, deltaTransform);
|
|
|
|
- }
|
|
|
|
|
|
+ constructPath(ops, args) {
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const current = this.current;
|
|
|
|
+ let x = current.x,
|
|
|
|
+ y = current.y;
|
|
|
|
+
|
|
|
|
+ for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
|
|
|
|
+ switch (ops[i] | 0) {
|
|
|
|
+ case _util.OPS.rectangle:
|
|
|
|
+ x = args[j++];
|
|
|
|
+ y = args[j++];
|
|
|
|
+ const width = args[j++];
|
|
|
|
+ const height = args[j++];
|
|
|
|
+ const xw = x + width;
|
|
|
|
+ const yh = y + height;
|
|
|
|
+ ctx.moveTo(x, y);
|
|
|
|
+
|
|
|
|
+ if (width === 0 || height === 0) {
|
|
|
|
+ ctx.lineTo(xw, yh);
|
|
|
|
+ } else {
|
|
|
|
+ ctx.lineTo(xw, y);
|
|
|
|
+ ctx.lineTo(xw, yh);
|
|
|
|
+ ctx.lineTo(x, yh);
|
|
|
|
+ }
|
|
|
|
|
|
- save() {
|
|
|
|
- this.ctx.save();
|
|
|
|
- const old = this.current;
|
|
|
|
- this.stateStack.push(old);
|
|
|
|
- this.current = old.clone();
|
|
|
|
- this.current.resumeSMaskCtx = null;
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.closePath();
|
|
|
|
+ break;
|
|
|
|
|
|
- restore() {
|
|
|
|
- if (this.current.resumeSMaskCtx) {
|
|
|
|
- this.resumeSMaskGroup();
|
|
|
|
- }
|
|
|
|
|
|
+ case _util.OPS.moveTo:
|
|
|
|
+ x = args[j++];
|
|
|
|
+ y = args[j++];
|
|
|
|
+ ctx.moveTo(x, y);
|
|
|
|
+ break;
|
|
|
|
|
|
- if (this.current.activeSMask !== null && (this.stateStack.length === 0 || this.stateStack[this.stateStack.length - 1].activeSMask !== this.current.activeSMask)) {
|
|
|
|
- this.endSMaskGroup();
|
|
|
|
- }
|
|
|
|
|
|
+ case _util.OPS.lineTo:
|
|
|
|
+ x = args[j++];
|
|
|
|
+ y = args[j++];
|
|
|
|
+ ctx.lineTo(x, y);
|
|
|
|
+ break;
|
|
|
|
|
|
- if (this.stateStack.length !== 0) {
|
|
|
|
- this.current = this.stateStack.pop();
|
|
|
|
- this.ctx.restore();
|
|
|
|
- this.pendingClip = null;
|
|
|
|
- this._cachedGetSinglePixelWidth = null;
|
|
|
|
- } else {
|
|
|
|
- this.current.activeSMask = null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ case _util.OPS.curveTo:
|
|
|
|
+ x = args[j + 4];
|
|
|
|
+ y = args[j + 5];
|
|
|
|
+ ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
|
|
|
|
+ j += 6;
|
|
|
|
+ break;
|
|
|
|
|
|
- transform(a, b, c, d, e, f) {
|
|
|
|
- this.ctx.transform(a, b, c, d, e, f);
|
|
|
|
- this._cachedGetSinglePixelWidth = null;
|
|
|
|
- }
|
|
|
|
|
|
+ case _util.OPS.curveTo2:
|
|
|
|
+ ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
|
|
|
|
+ x = args[j + 2];
|
|
|
|
+ y = args[j + 3];
|
|
|
|
+ j += 4;
|
|
|
|
+ break;
|
|
|
|
|
|
- constructPath(ops, args) {
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const current = this.current;
|
|
|
|
- let x = current.x,
|
|
|
|
- y = current.y;
|
|
|
|
-
|
|
|
|
- for (let i = 0, j = 0, ii = ops.length; i < ii; i++) {
|
|
|
|
- switch (ops[i] | 0) {
|
|
|
|
- case _util.OPS.rectangle:
|
|
|
|
- x = args[j++];
|
|
|
|
- y = args[j++];
|
|
|
|
- const width = args[j++];
|
|
|
|
- const height = args[j++];
|
|
|
|
- const xw = x + width;
|
|
|
|
- const yh = y + height;
|
|
|
|
- ctx.moveTo(x, y);
|
|
|
|
-
|
|
|
|
- if (width === 0 || height === 0) {
|
|
|
|
- ctx.lineTo(xw, yh);
|
|
|
|
- } else {
|
|
|
|
- ctx.lineTo(xw, y);
|
|
|
|
- ctx.lineTo(xw, yh);
|
|
|
|
- ctx.lineTo(x, yh);
|
|
|
|
- }
|
|
|
|
|
|
+ case _util.OPS.curveTo3:
|
|
|
|
+ x = args[j + 2];
|
|
|
|
+ y = args[j + 3];
|
|
|
|
+ ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
|
|
|
|
+ j += 4;
|
|
|
|
+ break;
|
|
|
|
|
|
- ctx.closePath();
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case _util.OPS.moveTo:
|
|
|
|
- x = args[j++];
|
|
|
|
- y = args[j++];
|
|
|
|
- ctx.moveTo(x, y);
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case _util.OPS.lineTo:
|
|
|
|
- x = args[j++];
|
|
|
|
- y = args[j++];
|
|
|
|
- ctx.lineTo(x, y);
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case _util.OPS.curveTo:
|
|
|
|
- x = args[j + 4];
|
|
|
|
- y = args[j + 5];
|
|
|
|
- ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3], x, y);
|
|
|
|
- j += 6;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case _util.OPS.curveTo2:
|
|
|
|
- ctx.bezierCurveTo(x, y, args[j], args[j + 1], args[j + 2], args[j + 3]);
|
|
|
|
- x = args[j + 2];
|
|
|
|
- y = args[j + 3];
|
|
|
|
- j += 4;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case _util.OPS.curveTo3:
|
|
|
|
- x = args[j + 2];
|
|
|
|
- y = args[j + 3];
|
|
|
|
- ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
|
|
|
|
- j += 4;
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case _util.OPS.closePath:
|
|
|
|
- ctx.closePath();
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ case _util.OPS.closePath:
|
|
|
|
+ ctx.closePath();
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
-
|
|
|
|
- current.setCurrentPoint(x, y);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- closePath() {
|
|
|
|
- this.ctx.closePath();
|
|
|
|
- }
|
|
|
|
|
|
+ current.setCurrentPoint(x, y);
|
|
|
|
+ }
|
|
|
|
|
|
- stroke(consumePath) {
|
|
|
|
- consumePath = typeof consumePath !== "undefined" ? consumePath : true;
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const strokeColor = this.current.strokeColor;
|
|
|
|
- ctx.globalAlpha = this.current.strokeAlpha;
|
|
|
|
|
|
+ closePath() {
|
|
|
|
+ this.ctx.closePath();
|
|
|
|
+ }
|
|
|
|
|
|
- if (this.contentVisible) {
|
|
|
|
- if (typeof strokeColor === "object" && strokeColor?.getPattern) {
|
|
|
|
- const lineWidth = this.getSinglePixelWidth();
|
|
|
|
|
|
+ stroke(consumePath) {
|
|
|
|
+ consumePath = typeof consumePath !== "undefined" ? consumePath : true;
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const strokeColor = this.current.strokeColor;
|
|
|
|
+ ctx.globalAlpha = this.current.strokeAlpha;
|
|
|
|
+
|
|
|
|
+ if (this.contentVisible) {
|
|
|
|
+ if (typeof strokeColor === "object" && strokeColor?.getPattern) {
|
|
|
|
+ const lineWidth = this.getSinglePixelWidth();
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.strokeStyle = strokeColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
+ ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
|
|
|
|
+ ctx.stroke();
|
|
|
|
+ ctx.restore();
|
|
|
|
+ } else {
|
|
|
|
+ const lineWidth = this.getSinglePixelWidth();
|
|
|
|
+
|
|
|
|
+ if (lineWidth < 0 && -lineWidth >= this.current.lineWidth) {
|
|
ctx.save();
|
|
ctx.save();
|
|
- ctx.strokeStyle = strokeColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
- ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
|
|
|
|
|
|
+ ctx.resetTransform();
|
|
|
|
+ ctx.lineWidth = Math.round(this._combinedScaleFactor);
|
|
ctx.stroke();
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
ctx.restore();
|
|
} else {
|
|
} else {
|
|
- const lineWidth = this.getSinglePixelWidth();
|
|
|
|
-
|
|
|
|
- if (lineWidth < 0 && -lineWidth >= this.current.lineWidth) {
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.resetTransform();
|
|
|
|
- ctx.lineWidth = Math.round(this._combinedScaleFactor);
|
|
|
|
- ctx.stroke();
|
|
|
|
- ctx.restore();
|
|
|
|
- } else {
|
|
|
|
- ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
|
|
|
|
- ctx.stroke();
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.lineWidth = Math.max(lineWidth, this.current.lineWidth);
|
|
|
|
+ ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- if (consumePath) {
|
|
|
|
- this.consumePath();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ctx.globalAlpha = this.current.fillAlpha;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- closeStroke() {
|
|
|
|
- this.closePath();
|
|
|
|
- this.stroke();
|
|
|
|
|
|
+ if (consumePath) {
|
|
|
|
+ this.consumePath();
|
|
}
|
|
}
|
|
|
|
|
|
- fill(consumePath) {
|
|
|
|
- consumePath = typeof consumePath !== "undefined" ? consumePath : true;
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const fillColor = this.current.fillColor;
|
|
|
|
- const isPatternFill = this.current.patternFill;
|
|
|
|
- let needRestore = false;
|
|
|
|
|
|
+ ctx.globalAlpha = this.current.fillAlpha;
|
|
|
|
+ }
|
|
|
|
|
|
- if (isPatternFill) {
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.fillStyle = fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
- needRestore = true;
|
|
|
|
- }
|
|
|
|
|
|
+ closeStroke() {
|
|
|
|
+ this.closePath();
|
|
|
|
+ this.stroke();
|
|
|
|
+ }
|
|
|
|
|
|
- if (this.contentVisible) {
|
|
|
|
- if (this.pendingEOFill) {
|
|
|
|
- ctx.fill("evenodd");
|
|
|
|
- this.pendingEOFill = false;
|
|
|
|
- } else {
|
|
|
|
- ctx.fill();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ fill(consumePath) {
|
|
|
|
+ consumePath = typeof consumePath !== "undefined" ? consumePath : true;
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const fillColor = this.current.fillColor;
|
|
|
|
+ const isPatternFill = this.current.patternFill;
|
|
|
|
+ let needRestore = false;
|
|
|
|
|
|
- if (needRestore) {
|
|
|
|
- ctx.restore();
|
|
|
|
- }
|
|
|
|
|
|
+ if (isPatternFill) {
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.fillStyle = fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
+ needRestore = true;
|
|
|
|
+ }
|
|
|
|
|
|
- if (consumePath) {
|
|
|
|
- this.consumePath();
|
|
|
|
|
|
+ if (this.contentVisible) {
|
|
|
|
+ if (this.pendingEOFill) {
|
|
|
|
+ ctx.fill("evenodd");
|
|
|
|
+ this.pendingEOFill = false;
|
|
|
|
+ } else {
|
|
|
|
+ ctx.fill();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- eoFill() {
|
|
|
|
- this.pendingEOFill = true;
|
|
|
|
- this.fill();
|
|
|
|
|
|
+ if (needRestore) {
|
|
|
|
+ ctx.restore();
|
|
}
|
|
}
|
|
|
|
|
|
- fillStroke() {
|
|
|
|
- this.fill(false);
|
|
|
|
- this.stroke(false);
|
|
|
|
|
|
+ if (consumePath) {
|
|
this.consumePath();
|
|
this.consumePath();
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- eoFillStroke() {
|
|
|
|
- this.pendingEOFill = true;
|
|
|
|
- this.fillStroke();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- closeFillStroke() {
|
|
|
|
- this.closePath();
|
|
|
|
- this.fillStroke();
|
|
|
|
- }
|
|
|
|
|
|
+ eoFill() {
|
|
|
|
+ this.pendingEOFill = true;
|
|
|
|
+ this.fill();
|
|
|
|
+ }
|
|
|
|
|
|
- closeEOFillStroke() {
|
|
|
|
- this.pendingEOFill = true;
|
|
|
|
- this.closePath();
|
|
|
|
- this.fillStroke();
|
|
|
|
- }
|
|
|
|
|
|
+ fillStroke() {
|
|
|
|
+ this.fill(false);
|
|
|
|
+ this.stroke(false);
|
|
|
|
+ this.consumePath();
|
|
|
|
+ }
|
|
|
|
|
|
- endPath() {
|
|
|
|
- this.consumePath();
|
|
|
|
- }
|
|
|
|
|
|
+ eoFillStroke() {
|
|
|
|
+ this.pendingEOFill = true;
|
|
|
|
+ this.fillStroke();
|
|
|
|
+ }
|
|
|
|
|
|
- clip() {
|
|
|
|
- this.pendingClip = NORMAL_CLIP;
|
|
|
|
- }
|
|
|
|
|
|
+ closeFillStroke() {
|
|
|
|
+ this.closePath();
|
|
|
|
+ this.fillStroke();
|
|
|
|
+ }
|
|
|
|
|
|
- eoClip() {
|
|
|
|
- this.pendingClip = EO_CLIP;
|
|
|
|
- }
|
|
|
|
|
|
+ closeEOFillStroke() {
|
|
|
|
+ this.pendingEOFill = true;
|
|
|
|
+ this.closePath();
|
|
|
|
+ this.fillStroke();
|
|
|
|
+ }
|
|
|
|
|
|
- beginText() {
|
|
|
|
- this.current.textMatrix = _util.IDENTITY_MATRIX;
|
|
|
|
- this.current.textMatrixScale = 1;
|
|
|
|
- this.current.x = this.current.lineX = 0;
|
|
|
|
- this.current.y = this.current.lineY = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ endPath() {
|
|
|
|
+ this.consumePath();
|
|
|
|
+ }
|
|
|
|
|
|
- endText() {
|
|
|
|
- const paths = this.pendingTextPaths;
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
|
|
+ clip() {
|
|
|
|
+ this.pendingClip = NORMAL_CLIP;
|
|
|
|
+ }
|
|
|
|
|
|
- if (paths === undefined) {
|
|
|
|
- ctx.beginPath();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ eoClip() {
|
|
|
|
+ this.pendingClip = EO_CLIP;
|
|
|
|
+ }
|
|
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.beginPath();
|
|
|
|
|
|
+ beginText() {
|
|
|
|
+ this.current.textMatrix = _util.IDENTITY_MATRIX;
|
|
|
|
+ this.current.textMatrixScale = 1;
|
|
|
|
+ this.current.x = this.current.lineX = 0;
|
|
|
|
+ this.current.y = this.current.lineY = 0;
|
|
|
|
+ }
|
|
|
|
|
|
- for (let i = 0; i < paths.length; i++) {
|
|
|
|
- const path = paths[i];
|
|
|
|
- ctx.setTransform.apply(ctx, path.transform);
|
|
|
|
- ctx.translate(path.x, path.y);
|
|
|
|
- path.addToPath(ctx, path.fontSize);
|
|
|
|
- }
|
|
|
|
|
|
+ endText() {
|
|
|
|
+ const paths = this.pendingTextPaths;
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
|
|
- ctx.restore();
|
|
|
|
- ctx.clip();
|
|
|
|
|
|
+ if (paths === undefined) {
|
|
ctx.beginPath();
|
|
ctx.beginPath();
|
|
- delete this.pendingTextPaths;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- setCharSpacing(spacing) {
|
|
|
|
- this.current.charSpacing = spacing;
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.beginPath();
|
|
|
|
|
|
- setWordSpacing(spacing) {
|
|
|
|
- this.current.wordSpacing = spacing;
|
|
|
|
|
|
+ for (let i = 0; i < paths.length; i++) {
|
|
|
|
+ const path = paths[i];
|
|
|
|
+ ctx.setTransform.apply(ctx, path.transform);
|
|
|
|
+ ctx.translate(path.x, path.y);
|
|
|
|
+ path.addToPath(ctx, path.fontSize);
|
|
}
|
|
}
|
|
|
|
|
|
- setHScale(scale) {
|
|
|
|
- this.current.textHScale = scale / 100;
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.restore();
|
|
|
|
+ ctx.clip();
|
|
|
|
+ ctx.beginPath();
|
|
|
|
+ delete this.pendingTextPaths;
|
|
|
|
+ }
|
|
|
|
|
|
- setLeading(leading) {
|
|
|
|
- this.current.leading = -leading;
|
|
|
|
- }
|
|
|
|
|
|
+ setCharSpacing(spacing) {
|
|
|
|
+ this.current.charSpacing = spacing;
|
|
|
|
+ }
|
|
|
|
|
|
- setFont(fontRefName, size) {
|
|
|
|
- const fontObj = this.commonObjs.get(fontRefName);
|
|
|
|
- const current = this.current;
|
|
|
|
|
|
+ setWordSpacing(spacing) {
|
|
|
|
+ this.current.wordSpacing = spacing;
|
|
|
|
+ }
|
|
|
|
|
|
- if (!fontObj) {
|
|
|
|
- throw new Error(`Can't find font for ${fontRefName}`);
|
|
|
|
- }
|
|
|
|
|
|
+ setHScale(scale) {
|
|
|
|
+ this.current.textHScale = scale / 100;
|
|
|
|
+ }
|
|
|
|
|
|
- current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX;
|
|
|
|
|
|
+ setLeading(leading) {
|
|
|
|
+ this.current.leading = -leading;
|
|
|
|
+ }
|
|
|
|
|
|
- if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) {
|
|
|
|
- (0, _util.warn)("Invalid font matrix for font " + fontRefName);
|
|
|
|
- }
|
|
|
|
|
|
+ setFont(fontRefName, size) {
|
|
|
|
+ const fontObj = this.commonObjs.get(fontRefName);
|
|
|
|
+ const current = this.current;
|
|
|
|
|
|
- if (size < 0) {
|
|
|
|
- size = -size;
|
|
|
|
- current.fontDirection = -1;
|
|
|
|
- } else {
|
|
|
|
- current.fontDirection = 1;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!fontObj) {
|
|
|
|
+ throw new Error(`Can't find font for ${fontRefName}`);
|
|
|
|
+ }
|
|
|
|
|
|
- this.current.font = fontObj;
|
|
|
|
- this.current.fontSize = size;
|
|
|
|
|
|
+ current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX;
|
|
|
|
|
|
- if (fontObj.isType3Font) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (current.fontMatrix[0] === 0 || current.fontMatrix[3] === 0) {
|
|
|
|
+ (0, _util.warn)("Invalid font matrix for font " + fontRefName);
|
|
|
|
+ }
|
|
|
|
|
|
- const name = fontObj.loadedName || "sans-serif";
|
|
|
|
- let bold = "normal";
|
|
|
|
|
|
+ if (size < 0) {
|
|
|
|
+ size = -size;
|
|
|
|
+ current.fontDirection = -1;
|
|
|
|
+ } else {
|
|
|
|
+ current.fontDirection = 1;
|
|
|
|
+ }
|
|
|
|
|
|
- if (fontObj.black) {
|
|
|
|
- bold = "900";
|
|
|
|
- } else if (fontObj.bold) {
|
|
|
|
- bold = "bold";
|
|
|
|
- }
|
|
|
|
|
|
+ this.current.font = fontObj;
|
|
|
|
+ this.current.fontSize = size;
|
|
|
|
|
|
- const italic = fontObj.italic ? "italic" : "normal";
|
|
|
|
- const typeface = `"${name}", ${fontObj.fallbackName}`;
|
|
|
|
- let browserFontSize = size;
|
|
|
|
|
|
+ if (fontObj.isType3Font) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- if (size < MIN_FONT_SIZE) {
|
|
|
|
- browserFontSize = MIN_FONT_SIZE;
|
|
|
|
- } else if (size > MAX_FONT_SIZE) {
|
|
|
|
- browserFontSize = MAX_FONT_SIZE;
|
|
|
|
- }
|
|
|
|
|
|
+ const name = fontObj.loadedName || "sans-serif";
|
|
|
|
+ let bold = "normal";
|
|
|
|
|
|
- this.current.fontSizeScale = size / browserFontSize;
|
|
|
|
- this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
|
|
|
|
|
|
+ if (fontObj.black) {
|
|
|
|
+ bold = "900";
|
|
|
|
+ } else if (fontObj.bold) {
|
|
|
|
+ bold = "bold";
|
|
}
|
|
}
|
|
|
|
|
|
- setTextRenderingMode(mode) {
|
|
|
|
- this.current.textRenderingMode = mode;
|
|
|
|
- }
|
|
|
|
|
|
+ const italic = fontObj.italic ? "italic" : "normal";
|
|
|
|
+ const typeface = `"${name}", ${fontObj.fallbackName}`;
|
|
|
|
+ let browserFontSize = size;
|
|
|
|
|
|
- setTextRise(rise) {
|
|
|
|
- this.current.textRise = rise;
|
|
|
|
|
|
+ if (size < MIN_FONT_SIZE) {
|
|
|
|
+ browserFontSize = MIN_FONT_SIZE;
|
|
|
|
+ } else if (size > MAX_FONT_SIZE) {
|
|
|
|
+ browserFontSize = MAX_FONT_SIZE;
|
|
}
|
|
}
|
|
|
|
|
|
- moveText(x, y) {
|
|
|
|
- this.current.x = this.current.lineX += x;
|
|
|
|
- this.current.y = this.current.lineY += y;
|
|
|
|
- }
|
|
|
|
|
|
+ this.current.fontSizeScale = size / browserFontSize;
|
|
|
|
+ this.ctx.font = `${italic} ${bold} ${browserFontSize}px ${typeface}`;
|
|
|
|
+ }
|
|
|
|
|
|
- setLeadingMoveText(x, y) {
|
|
|
|
- this.setLeading(-y);
|
|
|
|
- this.moveText(x, y);
|
|
|
|
- }
|
|
|
|
|
|
+ setTextRenderingMode(mode) {
|
|
|
|
+ this.current.textRenderingMode = mode;
|
|
|
|
+ }
|
|
|
|
|
|
- setTextMatrix(a, b, c, d, e, f) {
|
|
|
|
- this.current.textMatrix = [a, b, c, d, e, f];
|
|
|
|
- this.current.textMatrixScale = Math.hypot(a, b);
|
|
|
|
- this.current.x = this.current.lineX = 0;
|
|
|
|
- this.current.y = this.current.lineY = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ setTextRise(rise) {
|
|
|
|
+ this.current.textRise = rise;
|
|
|
|
+ }
|
|
|
|
|
|
- nextLine() {
|
|
|
|
- this.moveText(0, this.current.leading);
|
|
|
|
- }
|
|
|
|
|
|
+ moveText(x, y) {
|
|
|
|
+ this.current.x = this.current.lineX += x;
|
|
|
|
+ this.current.y = this.current.lineY += y;
|
|
|
|
+ }
|
|
|
|
|
|
- paintChar(character, x, y, patternTransform, resetLineWidthToOne) {
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const current = this.current;
|
|
|
|
- const font = current.font;
|
|
|
|
- const textRenderingMode = current.textRenderingMode;
|
|
|
|
- const fontSize = current.fontSize / current.fontSizeScale;
|
|
|
|
- const fillStrokeMode = textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
|
|
|
|
- const isAddToPathSet = !!(textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG);
|
|
|
|
- const patternFill = current.patternFill && !font.missingFile;
|
|
|
|
- let addToPath;
|
|
|
|
|
|
+ setLeadingMoveText(x, y) {
|
|
|
|
+ this.setLeading(-y);
|
|
|
|
+ this.moveText(x, y);
|
|
|
|
+ }
|
|
|
|
|
|
- if (font.disableFontFace || isAddToPathSet || patternFill) {
|
|
|
|
- addToPath = font.getPathGenerator(this.commonObjs, character);
|
|
|
|
- }
|
|
|
|
|
|
+ setTextMatrix(a, b, c, d, e, f) {
|
|
|
|
+ this.current.textMatrix = [a, b, c, d, e, f];
|
|
|
|
+ this.current.textMatrixScale = Math.hypot(a, b);
|
|
|
|
+ this.current.x = this.current.lineX = 0;
|
|
|
|
+ this.current.y = this.current.lineY = 0;
|
|
|
|
+ }
|
|
|
|
|
|
- if (font.disableFontFace || patternFill) {
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.translate(x, y);
|
|
|
|
- ctx.beginPath();
|
|
|
|
- addToPath(ctx, fontSize);
|
|
|
|
|
|
+ nextLine() {
|
|
|
|
+ this.moveText(0, this.current.leading);
|
|
|
|
+ }
|
|
|
|
|
|
- if (patternTransform) {
|
|
|
|
- ctx.setTransform.apply(ctx, patternTransform);
|
|
|
|
- }
|
|
|
|
|
|
+ paintChar(character, x, y, patternTransform, resetLineWidthToOne) {
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const current = this.current;
|
|
|
|
+ const font = current.font;
|
|
|
|
+ const textRenderingMode = current.textRenderingMode;
|
|
|
|
+ const fontSize = current.fontSize / current.fontSizeScale;
|
|
|
|
+ const fillStrokeMode = textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
|
|
|
|
+ const isAddToPathSet = !!(textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG);
|
|
|
|
+ const patternFill = current.patternFill && !font.missingFile;
|
|
|
|
+ let addToPath;
|
|
|
|
|
|
- if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
- ctx.fill();
|
|
|
|
- }
|
|
|
|
|
|
+ if (font.disableFontFace || isAddToPathSet || patternFill) {
|
|
|
|
+ addToPath = font.getPathGenerator(this.commonObjs, character);
|
|
|
|
+ }
|
|
|
|
|
|
- if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
- if (resetLineWidthToOne) {
|
|
|
|
- ctx.resetTransform();
|
|
|
|
- ctx.lineWidth = Math.round(this._combinedScaleFactor);
|
|
|
|
- }
|
|
|
|
|
|
+ if (font.disableFontFace || patternFill) {
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.translate(x, y);
|
|
|
|
+ ctx.beginPath();
|
|
|
|
+ addToPath(ctx, fontSize);
|
|
|
|
|
|
- ctx.stroke();
|
|
|
|
- }
|
|
|
|
|
|
+ if (patternTransform) {
|
|
|
|
+ ctx.setTransform.apply(ctx, patternTransform);
|
|
|
|
+ }
|
|
|
|
|
|
- ctx.restore();
|
|
|
|
- } else {
|
|
|
|
- if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
- ctx.fillText(character, x, y);
|
|
|
|
- }
|
|
|
|
|
|
+ if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
+ ctx.fill();
|
|
|
|
+ }
|
|
|
|
|
|
- if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
- if (resetLineWidthToOne) {
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.moveTo(x, y);
|
|
|
|
- ctx.resetTransform();
|
|
|
|
- ctx.lineWidth = Math.round(this._combinedScaleFactor);
|
|
|
|
- ctx.strokeText(character, 0, 0);
|
|
|
|
- ctx.restore();
|
|
|
|
- } else {
|
|
|
|
- ctx.strokeText(character, x, y);
|
|
|
|
- }
|
|
|
|
|
|
+ if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
+ if (resetLineWidthToOne) {
|
|
|
|
+ ctx.resetTransform();
|
|
|
|
+ ctx.lineWidth = Math.round(this._combinedScaleFactor);
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- if (isAddToPathSet) {
|
|
|
|
- const paths = this.pendingTextPaths || (this.pendingTextPaths = []);
|
|
|
|
- paths.push({
|
|
|
|
- transform: ctx.mozCurrentTransform,
|
|
|
|
- x,
|
|
|
|
- y,
|
|
|
|
- fontSize,
|
|
|
|
- addToPath
|
|
|
|
- });
|
|
|
|
|
|
+ ctx.stroke();
|
|
}
|
|
}
|
|
- }
|
|
|
|
|
|
|
|
- get isFontSubpixelAAEnabled() {
|
|
|
|
- const {
|
|
|
|
- context: ctx
|
|
|
|
- } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10);
|
|
|
|
- ctx.scale(1.5, 1);
|
|
|
|
- ctx.fillText("I", 0, 10);
|
|
|
|
- const data = ctx.getImageData(0, 0, 10, 10).data;
|
|
|
|
- let enabled = false;
|
|
|
|
|
|
+ ctx.restore();
|
|
|
|
+ } else {
|
|
|
|
+ if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
+ ctx.fillText(character, x, y);
|
|
|
|
+ }
|
|
|
|
|
|
- for (let i = 3; i < data.length; i += 4) {
|
|
|
|
- if (data[i] > 0 && data[i] < 255) {
|
|
|
|
- enabled = true;
|
|
|
|
- break;
|
|
|
|
|
|
+ if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
+ if (resetLineWidthToOne) {
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.moveTo(x, y);
|
|
|
|
+ ctx.resetTransform();
|
|
|
|
+ ctx.lineWidth = Math.round(this._combinedScaleFactor);
|
|
|
|
+ ctx.strokeText(character, 0, 0);
|
|
|
|
+ ctx.restore();
|
|
|
|
+ } else {
|
|
|
|
+ ctx.strokeText(character, x, y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- return (0, _util.shadow)(this, "isFontSubpixelAAEnabled", enabled);
|
|
|
|
|
|
+ if (isAddToPathSet) {
|
|
|
|
+ const paths = this.pendingTextPaths || (this.pendingTextPaths = []);
|
|
|
|
+ paths.push({
|
|
|
|
+ transform: ctx.mozCurrentTransform,
|
|
|
|
+ x,
|
|
|
|
+ y,
|
|
|
|
+ fontSize,
|
|
|
|
+ addToPath
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- showText(glyphs) {
|
|
|
|
- const current = this.current;
|
|
|
|
- const font = current.font;
|
|
|
|
|
|
+ get isFontSubpixelAAEnabled() {
|
|
|
|
+ const {
|
|
|
|
+ context: ctx
|
|
|
|
+ } = this.cachedCanvases.getCanvas("isFontSubpixelAAEnabled", 10, 10);
|
|
|
|
+ ctx.scale(1.5, 1);
|
|
|
|
+ ctx.fillText("I", 0, 10);
|
|
|
|
+ const data = ctx.getImageData(0, 0, 10, 10).data;
|
|
|
|
+ let enabled = false;
|
|
|
|
|
|
- if (font.isType3Font) {
|
|
|
|
- return this.showType3Text(glyphs);
|
|
|
|
|
|
+ for (let i = 3; i < data.length; i += 4) {
|
|
|
|
+ if (data[i] > 0 && data[i] < 255) {
|
|
|
|
+ enabled = true;
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (0, _util.shadow)(this, "isFontSubpixelAAEnabled", enabled);
|
|
|
|
+ }
|
|
|
|
|
|
- const fontSize = current.fontSize;
|
|
|
|
|
|
+ showText(glyphs) {
|
|
|
|
+ const current = this.current;
|
|
|
|
+ const font = current.font;
|
|
|
|
|
|
- if (fontSize === 0) {
|
|
|
|
- return undefined;
|
|
|
|
- }
|
|
|
|
|
|
+ if (font.isType3Font) {
|
|
|
|
+ return this.showType3Text(glyphs);
|
|
|
|
+ }
|
|
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const fontSizeScale = current.fontSizeScale;
|
|
|
|
- const charSpacing = current.charSpacing;
|
|
|
|
- const wordSpacing = current.wordSpacing;
|
|
|
|
- const fontDirection = current.fontDirection;
|
|
|
|
- const textHScale = current.textHScale * fontDirection;
|
|
|
|
- const glyphsLength = glyphs.length;
|
|
|
|
- const vertical = font.vertical;
|
|
|
|
- const spacingDir = vertical ? 1 : -1;
|
|
|
|
- const defaultVMetrics = font.defaultVMetrics;
|
|
|
|
- const widthAdvanceScale = fontSize * current.fontMatrix[0];
|
|
|
|
- const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
|
|
|
|
|
|
+ const fontSize = current.fontSize;
|
|
|
|
+
|
|
|
|
+ if (fontSize === 0) {
|
|
|
|
+ return undefined;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const fontSizeScale = current.fontSizeScale;
|
|
|
|
+ const charSpacing = current.charSpacing;
|
|
|
|
+ const wordSpacing = current.wordSpacing;
|
|
|
|
+ const fontDirection = current.fontDirection;
|
|
|
|
+ const textHScale = current.textHScale * fontDirection;
|
|
|
|
+ const glyphsLength = glyphs.length;
|
|
|
|
+ const vertical = font.vertical;
|
|
|
|
+ const spacingDir = vertical ? 1 : -1;
|
|
|
|
+ const defaultVMetrics = font.defaultVMetrics;
|
|
|
|
+ const widthAdvanceScale = fontSize * current.fontMatrix[0];
|
|
|
|
+ const simpleFillText = current.textRenderingMode === _util.TextRenderingMode.FILL && !font.disableFontFace && !current.patternFill;
|
|
|
|
+ ctx.save();
|
|
|
|
+ let patternTransform;
|
|
|
|
+
|
|
|
|
+ if (current.patternFill) {
|
|
ctx.save();
|
|
ctx.save();
|
|
- let patternTransform;
|
|
|
|
|
|
+ const pattern = current.fillColor.getPattern(ctx, this, ctx.mozCurrentTransformInverse);
|
|
|
|
+ patternTransform = ctx.mozCurrentTransform;
|
|
|
|
+ ctx.restore();
|
|
|
|
+ ctx.fillStyle = pattern;
|
|
|
|
+ }
|
|
|
|
|
|
- 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.translate(current.x, current.y + current.textRise);
|
|
|
|
|
|
- ctx.transform.apply(ctx, current.textMatrix);
|
|
|
|
- ctx.translate(current.x, current.y + current.textRise);
|
|
|
|
|
|
+ if (fontDirection > 0) {
|
|
|
|
+ ctx.scale(textHScale, -1);
|
|
|
|
+ } else {
|
|
|
|
+ ctx.scale(textHScale, 1);
|
|
|
|
+ }
|
|
|
|
|
|
- if (fontDirection > 0) {
|
|
|
|
- ctx.scale(textHScale, -1);
|
|
|
|
- } else {
|
|
|
|
- ctx.scale(textHScale, 1);
|
|
|
|
|
|
+ let lineWidth = current.lineWidth;
|
|
|
|
+ let resetLineWidthToOne = false;
|
|
|
|
+ const scale = current.textMatrixScale;
|
|
|
|
+
|
|
|
|
+ if (scale === 0 || lineWidth === 0) {
|
|
|
|
+ const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
|
|
|
|
+
|
|
|
|
+ if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
+ this._cachedGetSinglePixelWidth = null;
|
|
|
|
+ lineWidth = this.getSinglePixelWidth();
|
|
|
|
+ resetLineWidthToOne = lineWidth < 0;
|
|
}
|
|
}
|
|
|
|
+ } else {
|
|
|
|
+ lineWidth /= scale;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (fontSizeScale !== 1.0) {
|
|
|
|
+ ctx.scale(fontSizeScale, fontSizeScale);
|
|
|
|
+ lineWidth /= fontSizeScale;
|
|
|
|
+ }
|
|
|
|
|
|
- let lineWidth = current.lineWidth;
|
|
|
|
- let resetLineWidthToOne = false;
|
|
|
|
- const scale = current.textMatrixScale;
|
|
|
|
|
|
+ ctx.lineWidth = lineWidth;
|
|
|
|
+ let x = 0,
|
|
|
|
+ i;
|
|
|
|
|
|
- if (scale === 0 || lineWidth === 0) {
|
|
|
|
- const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
|
|
|
|
|
|
+ for (i = 0; i < glyphsLength; ++i) {
|
|
|
|
+ const glyph = glyphs[i];
|
|
|
|
|
|
- if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
|
|
|
|
- this._cachedGetSinglePixelWidth = null;
|
|
|
|
- lineWidth = this.getSinglePixelWidth();
|
|
|
|
- resetLineWidthToOne = lineWidth < 0;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- lineWidth /= scale;
|
|
|
|
|
|
+ if ((0, _util.isNum)(glyph)) {
|
|
|
|
+ x += spacingDir * glyph * fontSize / 1000;
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
|
|
|
|
- if (fontSizeScale !== 1.0) {
|
|
|
|
- ctx.scale(fontSizeScale, fontSizeScale);
|
|
|
|
- lineWidth /= fontSizeScale;
|
|
|
|
- }
|
|
|
|
|
|
+ let restoreNeeded = false;
|
|
|
|
+ const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
|
|
|
|
+ const character = glyph.fontChar;
|
|
|
|
+ const accent = glyph.accent;
|
|
|
|
+ let scaledX, scaledY;
|
|
|
|
+ let width = glyph.width;
|
|
|
|
|
|
- ctx.lineWidth = lineWidth;
|
|
|
|
- let x = 0,
|
|
|
|
- i;
|
|
|
|
|
|
+ if (vertical) {
|
|
|
|
+ const vmetric = glyph.vmetric || defaultVMetrics;
|
|
|
|
+ const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
|
|
|
|
+ const vy = vmetric[2] * widthAdvanceScale;
|
|
|
|
+ width = vmetric ? -vmetric[0] : width;
|
|
|
|
+ scaledX = vx / fontSizeScale;
|
|
|
|
+ scaledY = (x + vy) / fontSizeScale;
|
|
|
|
+ } else {
|
|
|
|
+ scaledX = x / fontSizeScale;
|
|
|
|
+ scaledY = 0;
|
|
|
|
+ }
|
|
|
|
|
|
- for (i = 0; i < glyphsLength; ++i) {
|
|
|
|
- const glyph = glyphs[i];
|
|
|
|
|
|
+ if (font.remeasure && width > 0) {
|
|
|
|
+ const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale;
|
|
|
|
|
|
- if ((0, _util.isNum)(glyph)) {
|
|
|
|
- x += spacingDir * glyph * fontSize / 1000;
|
|
|
|
- continue;
|
|
|
|
|
|
+ if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
|
|
|
|
+ const characterScaleX = width / measuredWidth;
|
|
|
|
+ restoreNeeded = true;
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.scale(characterScaleX, 1);
|
|
|
|
+ scaledX /= characterScaleX;
|
|
|
|
+ } else if (width !== measuredWidth) {
|
|
|
|
+ scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- let restoreNeeded = false;
|
|
|
|
- const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
|
|
|
|
- const character = glyph.fontChar;
|
|
|
|
- const accent = glyph.accent;
|
|
|
|
- let scaledX, scaledY;
|
|
|
|
- let width = glyph.width;
|
|
|
|
-
|
|
|
|
- if (vertical) {
|
|
|
|
- const vmetric = glyph.vmetric || defaultVMetrics;
|
|
|
|
- const vx = -(glyph.vmetric ? vmetric[1] : width * 0.5) * widthAdvanceScale;
|
|
|
|
- const vy = vmetric[2] * widthAdvanceScale;
|
|
|
|
- width = vmetric ? -vmetric[0] : width;
|
|
|
|
- scaledX = vx / fontSizeScale;
|
|
|
|
- scaledY = (x + vy) / fontSizeScale;
|
|
|
|
|
|
+ if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
|
|
|
|
+ if (simpleFillText && !accent) {
|
|
|
|
+ ctx.fillText(character, scaledX, scaledY);
|
|
} else {
|
|
} else {
|
|
- scaledX = x / fontSizeScale;
|
|
|
|
- scaledY = 0;
|
|
|
|
- }
|
|
|
|
|
|
+ this.paintChar(character, scaledX, scaledY, patternTransform, resetLineWidthToOne);
|
|
|
|
|
|
- if (font.remeasure && width > 0) {
|
|
|
|
- const measuredWidth = ctx.measureText(character).width * 1000 / fontSize * fontSizeScale;
|
|
|
|
-
|
|
|
|
- if (width < measuredWidth && this.isFontSubpixelAAEnabled) {
|
|
|
|
- const characterScaleX = width / measuredWidth;
|
|
|
|
- restoreNeeded = true;
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.scale(characterScaleX, 1);
|
|
|
|
- scaledX /= characterScaleX;
|
|
|
|
- } else if (width !== measuredWidth) {
|
|
|
|
- scaledX += (width - measuredWidth) / 2000 * fontSize / fontSizeScale;
|
|
|
|
|
|
+ if (accent) {
|
|
|
|
+ const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale;
|
|
|
|
+ const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale;
|
|
|
|
+ this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform, resetLineWidthToOne);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- if (this.contentVisible && (glyph.isInFont || font.missingFile)) {
|
|
|
|
- if (simpleFillText && !accent) {
|
|
|
|
- ctx.fillText(character, scaledX, scaledY);
|
|
|
|
- } else {
|
|
|
|
- this.paintChar(character, scaledX, scaledY, patternTransform, resetLineWidthToOne);
|
|
|
|
|
|
+ let charWidth;
|
|
|
|
|
|
- if (accent) {
|
|
|
|
- const scaledAccentX = scaledX + fontSize * accent.offset.x / fontSizeScale;
|
|
|
|
- const scaledAccentY = scaledY - fontSize * accent.offset.y / fontSizeScale;
|
|
|
|
- this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY, patternTransform, resetLineWidthToOne);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (vertical) {
|
|
|
|
+ charWidth = width * widthAdvanceScale - spacing * fontDirection;
|
|
|
|
+ } else {
|
|
|
|
+ charWidth = width * widthAdvanceScale + spacing * fontDirection;
|
|
|
|
+ }
|
|
|
|
|
|
- let charWidth;
|
|
|
|
|
|
+ x += charWidth;
|
|
|
|
|
|
- if (vertical) {
|
|
|
|
- charWidth = width * widthAdvanceScale - spacing * fontDirection;
|
|
|
|
- } else {
|
|
|
|
- charWidth = width * widthAdvanceScale + spacing * fontDirection;
|
|
|
|
- }
|
|
|
|
|
|
+ if (restoreNeeded) {
|
|
|
|
+ ctx.restore();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- x += charWidth;
|
|
|
|
|
|
+ if (vertical) {
|
|
|
|
+ current.y -= x;
|
|
|
|
+ } else {
|
|
|
|
+ current.x += x * textHScale;
|
|
|
|
+ }
|
|
|
|
|
|
- if (restoreNeeded) {
|
|
|
|
- ctx.restore();
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.restore();
|
|
|
|
+ return undefined;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ showType3Text(glyphs) {
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const current = this.current;
|
|
|
|
+ const font = current.font;
|
|
|
|
+ const fontSize = current.fontSize;
|
|
|
|
+ const fontDirection = current.fontDirection;
|
|
|
|
+ const spacingDir = font.vertical ? 1 : -1;
|
|
|
|
+ const charSpacing = current.charSpacing;
|
|
|
|
+ const wordSpacing = current.wordSpacing;
|
|
|
|
+ const textHScale = current.textHScale * fontDirection;
|
|
|
|
+ const fontMatrix = current.fontMatrix || _util.FONT_IDENTITY_MATRIX;
|
|
|
|
+ const glyphsLength = glyphs.length;
|
|
|
|
+ const isTextInvisible = current.textRenderingMode === _util.TextRenderingMode.INVISIBLE;
|
|
|
|
+ let i, glyph, width, spacingLength;
|
|
|
|
+
|
|
|
|
+ if (isTextInvisible || fontSize === 0) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this._cachedGetSinglePixelWidth = null;
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.transform.apply(ctx, current.textMatrix);
|
|
|
|
+ ctx.translate(current.x, current.y);
|
|
|
|
+ ctx.scale(textHScale, fontDirection);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < glyphsLength; ++i) {
|
|
|
|
+ glyph = glyphs[i];
|
|
|
|
+
|
|
|
|
+ if ((0, _util.isNum)(glyph)) {
|
|
|
|
+ spacingLength = spacingDir * glyph * fontSize / 1000;
|
|
|
|
+ this.ctx.translate(spacingLength, 0);
|
|
|
|
+ current.x += spacingLength * textHScale;
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
|
|
|
|
- if (vertical) {
|
|
|
|
- current.y -= x;
|
|
|
|
- } else {
|
|
|
|
- current.x += x * textHScale;
|
|
|
|
|
|
+ const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
|
|
|
|
+ const operatorList = font.charProcOperatorList[glyph.operatorListId];
|
|
|
|
+
|
|
|
|
+ if (!operatorList) {
|
|
|
|
+ (0, _util.warn)(`Type3 character "${glyph.operatorListId}" is not available.`);
|
|
|
|
+ continue;
|
|
}
|
|
}
|
|
|
|
|
|
- ctx.restore();
|
|
|
|
- return undefined;
|
|
|
|
|
|
+ if (this.contentVisible) {
|
|
|
|
+ this.processingType3 = glyph;
|
|
|
|
+ this.save();
|
|
|
|
+ ctx.scale(fontSize, fontSize);
|
|
|
|
+ ctx.transform.apply(ctx, fontMatrix);
|
|
|
|
+ this.executeOperatorList(operatorList);
|
|
|
|
+ this.restore();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const transformed = _util.Util.applyTransform([glyph.width, 0], fontMatrix);
|
|
|
|
+
|
|
|
|
+ width = transformed[0] * fontSize + spacing;
|
|
|
|
+ ctx.translate(width, 0);
|
|
|
|
+ current.x += width * textHScale;
|
|
}
|
|
}
|
|
|
|
|
|
- showType3Text(glyphs) {
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const current = this.current;
|
|
|
|
- const font = current.font;
|
|
|
|
- const fontSize = current.fontSize;
|
|
|
|
- const fontDirection = current.fontDirection;
|
|
|
|
- const spacingDir = font.vertical ? 1 : -1;
|
|
|
|
- const charSpacing = current.charSpacing;
|
|
|
|
- const wordSpacing = current.wordSpacing;
|
|
|
|
- const textHScale = current.textHScale * fontDirection;
|
|
|
|
- const fontMatrix = current.fontMatrix || _util.FONT_IDENTITY_MATRIX;
|
|
|
|
- const glyphsLength = glyphs.length;
|
|
|
|
- const isTextInvisible = current.textRenderingMode === _util.TextRenderingMode.INVISIBLE;
|
|
|
|
- let i, glyph, width, spacingLength;
|
|
|
|
-
|
|
|
|
- if (isTextInvisible || fontSize === 0) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.restore();
|
|
|
|
+ this.processingType3 = null;
|
|
|
|
+ }
|
|
|
|
|
|
- this._cachedGetSinglePixelWidth = null;
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.transform.apply(ctx, current.textMatrix);
|
|
|
|
- ctx.translate(current.x, current.y);
|
|
|
|
- ctx.scale(textHScale, fontDirection);
|
|
|
|
-
|
|
|
|
- for (i = 0; i < glyphsLength; ++i) {
|
|
|
|
- glyph = glyphs[i];
|
|
|
|
-
|
|
|
|
- if ((0, _util.isNum)(glyph)) {
|
|
|
|
- spacingLength = spacingDir * glyph * fontSize / 1000;
|
|
|
|
- this.ctx.translate(spacingLength, 0);
|
|
|
|
- current.x += spacingLength * textHScale;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
|
|
+ setCharWidth(xWidth, yWidth) {}
|
|
|
|
|
|
- const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
|
|
|
|
- const operatorList = font.charProcOperatorList[glyph.operatorListId];
|
|
|
|
|
|
+ setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) {
|
|
|
|
+ this.ctx.rect(llx, lly, urx - llx, ury - lly);
|
|
|
|
+ this.clip();
|
|
|
|
+ this.endPath();
|
|
|
|
+ }
|
|
|
|
|
|
- if (!operatorList) {
|
|
|
|
- (0, _util.warn)(`Type3 character "${glyph.operatorListId}" is not available.`);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
|
|
+ getColorN_Pattern(IR) {
|
|
|
|
+ let pattern;
|
|
|
|
|
|
- if (this.contentVisible) {
|
|
|
|
- this.processingType3 = glyph;
|
|
|
|
- this.save();
|
|
|
|
- ctx.scale(fontSize, fontSize);
|
|
|
|
- ctx.transform.apply(ctx, fontMatrix);
|
|
|
|
- this.executeOperatorList(operatorList);
|
|
|
|
- this.restore();
|
|
|
|
|
|
+ if (IR[0] === "TilingPattern") {
|
|
|
|
+ const color = IR[1];
|
|
|
|
+ const baseTransform = this.baseTransform || this.ctx.mozCurrentTransform.slice();
|
|
|
|
+ const canvasGraphicsFactory = {
|
|
|
|
+ createCanvasGraphics: ctx => {
|
|
|
|
+ return new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory);
|
|
}
|
|
}
|
|
|
|
+ };
|
|
|
|
+ pattern = new _pattern_helper.TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform);
|
|
|
|
+ } else {
|
|
|
|
+ pattern = this._getPattern(IR[1], IR[2]);
|
|
|
|
+ }
|
|
|
|
|
|
- const transformed = _util.Util.applyTransform([glyph.width, 0], fontMatrix);
|
|
|
|
|
|
+ return pattern;
|
|
|
|
+ }
|
|
|
|
|
|
- width = transformed[0] * fontSize + spacing;
|
|
|
|
- ctx.translate(width, 0);
|
|
|
|
- current.x += width * textHScale;
|
|
|
|
- }
|
|
|
|
|
|
+ setStrokeColorN() {
|
|
|
|
+ this.current.strokeColor = this.getColorN_Pattern(arguments);
|
|
|
|
+ }
|
|
|
|
|
|
- ctx.restore();
|
|
|
|
- this.processingType3 = null;
|
|
|
|
- }
|
|
|
|
|
|
+ setFillColorN() {
|
|
|
|
+ this.current.fillColor = this.getColorN_Pattern(arguments);
|
|
|
|
+ this.current.patternFill = true;
|
|
|
|
+ }
|
|
|
|
|
|
- setCharWidth(xWidth, yWidth) {}
|
|
|
|
|
|
+ setStrokeRGBColor(r, g, b) {
|
|
|
|
+ const color = _util.Util.makeHexColor(r, g, b);
|
|
|
|
|
|
- setCharWidthAndBounds(xWidth, yWidth, llx, lly, urx, ury) {
|
|
|
|
- this.ctx.rect(llx, lly, urx - llx, ury - lly);
|
|
|
|
- this.clip();
|
|
|
|
- this.endPath();
|
|
|
|
- }
|
|
|
|
|
|
+ this.ctx.strokeStyle = color;
|
|
|
|
+ this.current.strokeColor = color;
|
|
|
|
+ }
|
|
|
|
|
|
- getColorN_Pattern(IR) {
|
|
|
|
- let pattern;
|
|
|
|
|
|
+ setFillRGBColor(r, g, b) {
|
|
|
|
+ const color = _util.Util.makeHexColor(r, g, b);
|
|
|
|
|
|
- if (IR[0] === "TilingPattern") {
|
|
|
|
- const color = IR[1];
|
|
|
|
- const baseTransform = this.baseTransform || this.ctx.mozCurrentTransform.slice();
|
|
|
|
- const canvasGraphicsFactory = {
|
|
|
|
- createCanvasGraphics: ctx => {
|
|
|
|
- return new CanvasGraphics(ctx, this.commonObjs, this.objs, this.canvasFactory);
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
- pattern = new _pattern_helper.TilingPattern(IR, color, this.ctx, canvasGraphicsFactory, baseTransform);
|
|
|
|
- } else {
|
|
|
|
- pattern = this._getPattern(IR[1]);
|
|
|
|
- }
|
|
|
|
|
|
+ this.ctx.fillStyle = color;
|
|
|
|
+ this.current.fillColor = color;
|
|
|
|
+ this.current.patternFill = false;
|
|
|
|
+ }
|
|
|
|
|
|
- return pattern;
|
|
|
|
- }
|
|
|
|
|
|
+ _getPattern(objId, matrix = null) {
|
|
|
|
+ let pattern;
|
|
|
|
|
|
- setStrokeColorN() {
|
|
|
|
- this.current.strokeColor = this.getColorN_Pattern(arguments);
|
|
|
|
|
|
+ if (this.cachedPatterns.has(objId)) {
|
|
|
|
+ pattern = this.cachedPatterns.get(objId);
|
|
|
|
+ } else {
|
|
|
|
+ pattern = (0, _pattern_helper.getShadingPattern)(this.objs.get(objId), this.cachedCanvasPatterns);
|
|
|
|
+ this.cachedPatterns.set(objId, pattern);
|
|
}
|
|
}
|
|
|
|
|
|
- setFillColorN() {
|
|
|
|
- this.current.fillColor = this.getColorN_Pattern(arguments);
|
|
|
|
- this.current.patternFill = true;
|
|
|
|
|
|
+ if (matrix) {
|
|
|
|
+ pattern.matrix = matrix;
|
|
}
|
|
}
|
|
|
|
|
|
- setStrokeRGBColor(r, g, b) {
|
|
|
|
- const color = _util.Util.makeHexColor(r, g, b);
|
|
|
|
|
|
+ return pattern;
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.strokeStyle = color;
|
|
|
|
- this.current.strokeColor = color;
|
|
|
|
|
|
+ shadingFill(objId) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- setFillRGBColor(r, g, b) {
|
|
|
|
- const color = _util.Util.makeHexColor(r, g, b);
|
|
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ this.save();
|
|
|
|
|
|
- this.ctx.fillStyle = color;
|
|
|
|
- this.current.fillColor = color;
|
|
|
|
- this.current.patternFill = false;
|
|
|
|
- }
|
|
|
|
|
|
+ const pattern = this._getPattern(objId);
|
|
|
|
|
|
- _getPattern(objId) {
|
|
|
|
- if (this.cachedPatterns.has(objId)) {
|
|
|
|
- return this.cachedPatterns.get(objId);
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.fillStyle = pattern.getPattern(ctx, this, ctx.mozCurrentTransformInverse, true);
|
|
|
|
+ const inv = ctx.mozCurrentTransformInverse;
|
|
|
|
|
|
- const pattern = (0, _pattern_helper.getShadingPattern)(this.objs.get(objId));
|
|
|
|
- this.cachedPatterns.set(objId, pattern);
|
|
|
|
- return pattern;
|
|
|
|
- }
|
|
|
|
|
|
+ if (inv) {
|
|
|
|
+ const canvas = ctx.canvas;
|
|
|
|
+ const width = canvas.width;
|
|
|
|
+ const height = canvas.height;
|
|
|
|
|
|
- shadingFill(objId) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ const bl = _util.Util.applyTransform([0, 0], inv);
|
|
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- this.save();
|
|
|
|
|
|
+ const br = _util.Util.applyTransform([0, height], inv);
|
|
|
|
|
|
- const pattern = this._getPattern(objId);
|
|
|
|
|
|
+ const ul = _util.Util.applyTransform([width, 0], inv);
|
|
|
|
|
|
- ctx.fillStyle = pattern.getPattern(ctx, this, ctx.mozCurrentTransformInverse, true);
|
|
|
|
- const inv = ctx.mozCurrentTransformInverse;
|
|
|
|
|
|
+ const ur = _util.Util.applyTransform([width, height], inv);
|
|
|
|
|
|
- if (inv) {
|
|
|
|
- const canvas = ctx.canvas;
|
|
|
|
- const width = canvas.width;
|
|
|
|
- const height = canvas.height;
|
|
|
|
|
|
+ const x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
|
|
|
|
+ const y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
|
|
|
|
+ const x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
|
|
|
|
+ const y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
|
|
|
|
+ this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
|
|
|
|
+ } else {
|
|
|
|
+ this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
|
|
|
|
+ }
|
|
|
|
|
|
- const bl = _util.Util.applyTransform([0, 0], inv);
|
|
|
|
|
|
+ this.restore();
|
|
|
|
+ }
|
|
|
|
|
|
- const br = _util.Util.applyTransform([0, height], inv);
|
|
|
|
|
|
+ beginInlineImage() {
|
|
|
|
+ (0, _util.unreachable)("Should not call beginInlineImage");
|
|
|
|
+ }
|
|
|
|
|
|
- const ul = _util.Util.applyTransform([width, 0], inv);
|
|
|
|
|
|
+ beginImageData() {
|
|
|
|
+ (0, _util.unreachable)("Should not call beginImageData");
|
|
|
|
+ }
|
|
|
|
|
|
- const ur = _util.Util.applyTransform([width, height], inv);
|
|
|
|
|
|
+ paintFormXObjectBegin(matrix, bbox) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
|
|
|
|
- const y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
|
|
|
|
- const x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
|
|
|
|
- const y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
|
|
|
|
- this.ctx.fillRect(x0, y0, x1 - x0, y1 - y0);
|
|
|
|
- } else {
|
|
|
|
- this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10);
|
|
|
|
- }
|
|
|
|
|
|
+ this.save();
|
|
|
|
+ this.baseTransformStack.push(this.baseTransform);
|
|
|
|
|
|
- this.restore();
|
|
|
|
|
|
+ if (Array.isArray(matrix) && matrix.length === 6) {
|
|
|
|
+ this.transform.apply(this, matrix);
|
|
}
|
|
}
|
|
|
|
|
|
- beginInlineImage() {
|
|
|
|
- (0, _util.unreachable)("Should not call beginInlineImage");
|
|
|
|
|
|
+ this.baseTransform = this.ctx.mozCurrentTransform;
|
|
|
|
+
|
|
|
|
+ if (bbox) {
|
|
|
|
+ const width = bbox[2] - bbox[0];
|
|
|
|
+ const height = bbox[3] - bbox[1];
|
|
|
|
+ this.ctx.rect(bbox[0], bbox[1], width, height);
|
|
|
|
+ this.clip();
|
|
|
|
+ this.endPath();
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- beginImageData() {
|
|
|
|
- (0, _util.unreachable)("Should not call beginImageData");
|
|
|
|
|
|
+ paintFormXObjectEnd() {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- paintFormXObjectBegin(matrix, bbox) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ this.restore();
|
|
|
|
+ this.baseTransform = this.baseTransformStack.pop();
|
|
|
|
+ }
|
|
|
|
|
|
- this.save();
|
|
|
|
- this.baseTransformStack.push(this.baseTransform);
|
|
|
|
|
|
+ beginGroup(group) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- if (Array.isArray(matrix) && matrix.length === 6) {
|
|
|
|
- this.transform.apply(this, matrix);
|
|
|
|
- }
|
|
|
|
|
|
+ this.save();
|
|
|
|
+ const currentCtx = this.ctx;
|
|
|
|
|
|
- this.baseTransform = this.ctx.mozCurrentTransform;
|
|
|
|
|
|
+ if (!group.isolated) {
|
|
|
|
+ (0, _util.info)("TODO: Support non-isolated groups.");
|
|
|
|
+ }
|
|
|
|
|
|
- if (bbox) {
|
|
|
|
- const width = bbox[2] - bbox[0];
|
|
|
|
- const height = bbox[3] - bbox[1];
|
|
|
|
- this.ctx.rect(bbox[0], bbox[1], width, height);
|
|
|
|
- this.clip();
|
|
|
|
- this.endPath();
|
|
|
|
- }
|
|
|
|
|
|
+ if (group.knockout) {
|
|
|
|
+ (0, _util.warn)("Knockout groups not supported.");
|
|
}
|
|
}
|
|
|
|
|
|
- paintFormXObjectEnd() {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ const currentTransform = currentCtx.mozCurrentTransform;
|
|
|
|
|
|
- this.restore();
|
|
|
|
- this.baseTransform = this.baseTransformStack.pop();
|
|
|
|
|
|
+ if (group.matrix) {
|
|
|
|
+ currentCtx.transform.apply(currentCtx, group.matrix);
|
|
}
|
|
}
|
|
|
|
|
|
- beginGroup(group) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ if (!group.bbox) {
|
|
|
|
+ throw new Error("Bounding box is required.");
|
|
|
|
+ }
|
|
|
|
|
|
- this.save();
|
|
|
|
- const currentCtx = this.ctx;
|
|
|
|
|
|
+ let bounds = _util.Util.getAxialAlignedBoundingBox(group.bbox, currentCtx.mozCurrentTransform);
|
|
|
|
|
|
- if (!group.isolated) {
|
|
|
|
- (0, _util.info)("TODO: Support non-isolated groups.");
|
|
|
|
- }
|
|
|
|
|
|
+ const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height];
|
|
|
|
+ bounds = _util.Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
|
|
|
|
+ const offsetX = Math.floor(bounds[0]);
|
|
|
|
+ const offsetY = Math.floor(bounds[1]);
|
|
|
|
+ let drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
|
|
|
|
+ let drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
|
|
|
|
+ let scaleX = 1,
|
|
|
|
+ scaleY = 1;
|
|
|
|
|
|
- if (group.knockout) {
|
|
|
|
- (0, _util.warn)("Knockout groups not supported.");
|
|
|
|
- }
|
|
|
|
|
|
+ if (drawnWidth > MAX_GROUP_SIZE) {
|
|
|
|
+ scaleX = drawnWidth / MAX_GROUP_SIZE;
|
|
|
|
+ drawnWidth = MAX_GROUP_SIZE;
|
|
|
|
+ }
|
|
|
|
|
|
- const currentTransform = currentCtx.mozCurrentTransform;
|
|
|
|
|
|
+ if (drawnHeight > MAX_GROUP_SIZE) {
|
|
|
|
+ scaleY = drawnHeight / MAX_GROUP_SIZE;
|
|
|
|
+ drawnHeight = MAX_GROUP_SIZE;
|
|
|
|
+ }
|
|
|
|
|
|
- if (group.matrix) {
|
|
|
|
- currentCtx.transform.apply(currentCtx, group.matrix);
|
|
|
|
- }
|
|
|
|
|
|
+ let cacheId = "groupAt" + this.groupLevel;
|
|
|
|
|
|
- if (!group.bbox) {
|
|
|
|
- throw new Error("Bounding box is required.");
|
|
|
|
- }
|
|
|
|
|
|
+ if (group.smask) {
|
|
|
|
+ cacheId += "_smask_" + this.smaskCounter++ % 2;
|
|
|
|
+ }
|
|
|
|
|
|
- let bounds = _util.Util.getAxialAlignedBoundingBox(group.bbox, currentCtx.mozCurrentTransform);
|
|
|
|
|
|
+ const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
|
|
|
|
+ const groupCtx = scratchCanvas.context;
|
|
|
|
+ groupCtx.scale(1 / scaleX, 1 / scaleY);
|
|
|
|
+ groupCtx.translate(-offsetX, -offsetY);
|
|
|
|
+ groupCtx.transform.apply(groupCtx, currentTransform);
|
|
|
|
|
|
- const canvasBounds = [0, 0, currentCtx.canvas.width, currentCtx.canvas.height];
|
|
|
|
- bounds = _util.Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
|
|
|
|
- const offsetX = Math.floor(bounds[0]);
|
|
|
|
- const offsetY = Math.floor(bounds[1]);
|
|
|
|
- let drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
|
|
|
|
- let drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
|
|
|
|
- let scaleX = 1,
|
|
|
|
- scaleY = 1;
|
|
|
|
|
|
+ if (group.smask) {
|
|
|
|
+ this.smaskStack.push({
|
|
|
|
+ canvas: scratchCanvas.canvas,
|
|
|
|
+ context: groupCtx,
|
|
|
|
+ offsetX,
|
|
|
|
+ offsetY,
|
|
|
|
+ scaleX,
|
|
|
|
+ scaleY,
|
|
|
|
+ subtype: group.smask.subtype,
|
|
|
|
+ backdrop: group.smask.backdrop,
|
|
|
|
+ transferMap: group.smask.transferMap || null,
|
|
|
|
+ startTransformInverse: null
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ currentCtx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
+ currentCtx.translate(offsetX, offsetY);
|
|
|
|
+ currentCtx.scale(scaleX, scaleY);
|
|
|
|
+ }
|
|
|
|
|
|
- if (drawnWidth > MAX_GROUP_SIZE) {
|
|
|
|
- scaleX = drawnWidth / MAX_GROUP_SIZE;
|
|
|
|
- drawnWidth = MAX_GROUP_SIZE;
|
|
|
|
- }
|
|
|
|
|
|
+ copyCtxState(currentCtx, groupCtx);
|
|
|
|
+ this.ctx = groupCtx;
|
|
|
|
+ this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
|
|
|
|
+ this.groupStack.push(currentCtx);
|
|
|
|
+ this.groupLevel++;
|
|
|
|
+ this.current.activeSMask = null;
|
|
|
|
+ }
|
|
|
|
|
|
- if (drawnHeight > MAX_GROUP_SIZE) {
|
|
|
|
- scaleY = drawnHeight / MAX_GROUP_SIZE;
|
|
|
|
- drawnHeight = MAX_GROUP_SIZE;
|
|
|
|
- }
|
|
|
|
|
|
+ endGroup(group) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- let cacheId = "groupAt" + this.groupLevel;
|
|
|
|
|
|
+ this.groupLevel--;
|
|
|
|
+ const groupCtx = this.ctx;
|
|
|
|
+ this.ctx = this.groupStack.pop();
|
|
|
|
+ this.ctx.imageSmoothingEnabled = false;
|
|
|
|
|
|
- if (group.smask) {
|
|
|
|
- cacheId += "_smask_" + this.smaskCounter++ % 2;
|
|
|
|
- }
|
|
|
|
|
|
+ if (group.smask) {
|
|
|
|
+ this.tempSMask = this.smaskStack.pop();
|
|
|
|
+ } else {
|
|
|
|
+ this.ctx.drawImage(groupCtx.canvas, 0, 0);
|
|
|
|
+ }
|
|
|
|
|
|
- const scratchCanvas = this.cachedCanvases.getCanvas(cacheId, drawnWidth, drawnHeight, true);
|
|
|
|
- const groupCtx = scratchCanvas.context;
|
|
|
|
- groupCtx.scale(1 / scaleX, 1 / scaleY);
|
|
|
|
- groupCtx.translate(-offsetX, -offsetY);
|
|
|
|
- groupCtx.transform.apply(groupCtx, currentTransform);
|
|
|
|
-
|
|
|
|
- if (group.smask) {
|
|
|
|
- this.smaskStack.push({
|
|
|
|
- canvas: scratchCanvas.canvas,
|
|
|
|
- context: groupCtx,
|
|
|
|
- offsetX,
|
|
|
|
- offsetY,
|
|
|
|
- scaleX,
|
|
|
|
- scaleY,
|
|
|
|
- subtype: group.smask.subtype,
|
|
|
|
- backdrop: group.smask.backdrop,
|
|
|
|
- transferMap: group.smask.transferMap || null,
|
|
|
|
- startTransformInverse: null
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- currentCtx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
- currentCtx.translate(offsetX, offsetY);
|
|
|
|
- currentCtx.scale(scaleX, scaleY);
|
|
|
|
- }
|
|
|
|
|
|
+ this.restore();
|
|
|
|
+ }
|
|
|
|
|
|
- copyCtxState(currentCtx, groupCtx);
|
|
|
|
- this.ctx = groupCtx;
|
|
|
|
- this.setGState([["BM", "source-over"], ["ca", 1], ["CA", 1]]);
|
|
|
|
- this.groupStack.push(currentCtx);
|
|
|
|
- this.groupLevel++;
|
|
|
|
- this.current.activeSMask = null;
|
|
|
|
|
|
+ beginAnnotations() {
|
|
|
|
+ this.save();
|
|
|
|
+
|
|
|
|
+ if (this.baseTransform) {
|
|
|
|
+ this.ctx.setTransform.apply(this.ctx, this.baseTransform);
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- endGroup(group) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ endAnnotations() {
|
|
|
|
+ this.restore();
|
|
|
|
+ }
|
|
|
|
|
|
- this.groupLevel--;
|
|
|
|
- const groupCtx = this.ctx;
|
|
|
|
- this.ctx = this.groupStack.pop();
|
|
|
|
|
|
+ beginAnnotation(id, rect, transform, matrix) {
|
|
|
|
+ this.save();
|
|
|
|
+ resetCtxToDefault(this.ctx);
|
|
|
|
+ this.current = new CanvasExtraState();
|
|
|
|
|
|
- if (this.ctx.imageSmoothingEnabled !== undefined) {
|
|
|
|
- this.ctx.imageSmoothingEnabled = false;
|
|
|
|
- } else {
|
|
|
|
- this.ctx.mozImageSmoothingEnabled = false;
|
|
|
|
- }
|
|
|
|
|
|
+ if (Array.isArray(rect) && rect.length === 4) {
|
|
|
|
+ const width = rect[2] - rect[0];
|
|
|
|
+ const height = rect[3] - rect[1];
|
|
|
|
+ this.ctx.rect(rect[0], rect[1], width, height);
|
|
|
|
+ this.clip();
|
|
|
|
+ this.endPath();
|
|
|
|
+ }
|
|
|
|
|
|
- if (group.smask) {
|
|
|
|
- this.tempSMask = this.smaskStack.pop();
|
|
|
|
- } else {
|
|
|
|
- this.ctx.drawImage(groupCtx.canvas, 0, 0);
|
|
|
|
- }
|
|
|
|
|
|
+ this.transform.apply(this, transform);
|
|
|
|
+ this.transform.apply(this, matrix);
|
|
|
|
+ }
|
|
|
|
|
|
- this.restore();
|
|
|
|
|
|
+ endAnnotation() {
|
|
|
|
+ this.restore();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ paintImageMaskXObject(img) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- beginAnnotations() {
|
|
|
|
- this.save();
|
|
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const width = img.width,
|
|
|
|
+ height = img.height;
|
|
|
|
+ const glyph = this.processingType3;
|
|
|
|
|
|
- if (this.baseTransform) {
|
|
|
|
- this.ctx.setTransform.apply(this.ctx, this.baseTransform);
|
|
|
|
|
|
+ if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) {
|
|
|
|
+ if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {
|
|
|
|
+ glyph.compiled = compileType3Glyph({
|
|
|
|
+ data: img.data,
|
|
|
|
+ width,
|
|
|
|
+ height
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ glyph.compiled = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- endAnnotations() {
|
|
|
|
- this.restore();
|
|
|
|
|
|
+ if (glyph?.compiled) {
|
|
|
|
+ glyph.compiled(ctx);
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- beginAnnotation(id, rect, transform, matrix) {
|
|
|
|
- this.save();
|
|
|
|
- resetCtxToDefault(this.ctx);
|
|
|
|
- this.current = new CanvasExtraState();
|
|
|
|
|
|
+ const mask = this._createMaskCanvas(img);
|
|
|
|
|
|
- if (Array.isArray(rect) && rect.length === 4) {
|
|
|
|
- const width = rect[2] - rect[0];
|
|
|
|
- const height = rect[3] - rect[1];
|
|
|
|
- this.ctx.rect(rect[0], rect[1], width, height);
|
|
|
|
- this.clip();
|
|
|
|
- this.endPath();
|
|
|
|
- }
|
|
|
|
|
|
+ const maskCanvas = mask.canvas;
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
+ ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
|
|
|
|
+ ctx.restore();
|
|
|
|
+ }
|
|
|
|
|
|
- this.transform.apply(this, transform);
|
|
|
|
- this.transform.apply(this, matrix);
|
|
|
|
|
|
+ paintImageMaskXObjectRepeat(imgData, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- endAnnotation() {
|
|
|
|
- this.restore();
|
|
|
|
- }
|
|
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ ctx.save();
|
|
|
|
+ const currentTransform = ctx.mozCurrentTransform;
|
|
|
|
+ ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
|
|
|
|
|
|
- paintImageMaskXObject(img) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ const mask = this._createMaskCanvas(imgData);
|
|
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const width = img.width,
|
|
|
|
- height = img.height;
|
|
|
|
- const glyph = this.processingType3;
|
|
|
|
-
|
|
|
|
- if (COMPILE_TYPE3_GLYPHS && glyph && glyph.compiled === undefined) {
|
|
|
|
- if (width <= MAX_SIZE_TO_COMPILE && height <= MAX_SIZE_TO_COMPILE) {
|
|
|
|
- glyph.compiled = compileType3Glyph({
|
|
|
|
- data: img.data,
|
|
|
|
- width,
|
|
|
|
- height
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- glyph.compiled = null;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
|
|
- if (glyph?.compiled) {
|
|
|
|
- glyph.compiled(ctx);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ for (let i = 0, ii = positions.length; i < ii; i += 2) {
|
|
|
|
+ const trans = _util.Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]);
|
|
|
|
|
|
- const mask = this._createMaskCanvas(img);
|
|
|
|
|
|
+ const [x, y] = _util.Util.applyTransform([0, 0], trans);
|
|
|
|
|
|
- const maskCanvas = mask.canvas;
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
- ctx.drawImage(maskCanvas, mask.offsetX, mask.offsetY);
|
|
|
|
- ctx.restore();
|
|
|
|
|
|
+ ctx.drawImage(mask.canvas, x, y);
|
|
}
|
|
}
|
|
|
|
|
|
- paintImageMaskXObjectRepeat(imgData, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.restore();
|
|
|
|
+ }
|
|
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- ctx.save();
|
|
|
|
- const currentTransform = ctx.mozCurrentTransform;
|
|
|
|
- ctx.transform(scaleX, skewX, skewY, scaleY, 0, 0);
|
|
|
|
|
|
+ paintImageMaskXObjectGroup(images) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const mask = this._createMaskCanvas(imgData);
|
|
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const fillColor = this.current.fillColor;
|
|
|
|
+ const isPatternFill = this.current.patternFill;
|
|
|
|
|
|
- ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
|
|
|
|
+ for (let i = 0, ii = images.length; i < ii; i++) {
|
|
|
|
+ const image = images[i];
|
|
|
|
+ const width = image.width,
|
|
|
|
+ height = image.height;
|
|
|
|
+ const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
|
|
|
|
+ const maskCtx = maskCanvas.context;
|
|
|
|
+ maskCtx.save();
|
|
|
|
+ putBinaryImageMask(maskCtx, image);
|
|
|
|
+ maskCtx.globalCompositeOperation = "source-in";
|
|
|
|
+ maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, ctx.mozCurrentTransformInverse, false) : fillColor;
|
|
|
|
+ maskCtx.fillRect(0, 0, width, height);
|
|
|
|
+ maskCtx.restore();
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.transform.apply(ctx, image.transform);
|
|
|
|
+ ctx.scale(1, -1);
|
|
|
|
+ ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
|
|
|
|
+ ctx.restore();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- for (let i = 0, ii = positions.length; i < ii; i += 2) {
|
|
|
|
- const trans = _util.Util.transform(currentTransform, [scaleX, skewX, skewY, scaleY, positions[i], positions[i + 1]]);
|
|
|
|
|
|
+ paintImageXObject(objId) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const [x, y] = _util.Util.applyTransform([0, 0], trans);
|
|
|
|
|
|
+ const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
|
|
|
|
|
|
- ctx.drawImage(mask.canvas, x, y);
|
|
|
|
- }
|
|
|
|
|
|
+ if (!imgData) {
|
|
|
|
+ (0, _util.warn)("Dependent image isn't ready yet");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- ctx.restore();
|
|
|
|
|
|
+ this.paintInlineImageXObject(imgData);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ paintImageXObjectRepeat(objId, scaleX, scaleY, positions) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- paintImageMaskXObjectGroup(images) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
|
|
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const fillColor = this.current.fillColor;
|
|
|
|
- const isPatternFill = this.current.patternFill;
|
|
|
|
-
|
|
|
|
- for (let i = 0, ii = images.length; i < ii; i++) {
|
|
|
|
- const image = images[i];
|
|
|
|
- const width = image.width,
|
|
|
|
- height = image.height;
|
|
|
|
- const maskCanvas = this.cachedCanvases.getCanvas("maskCanvas", width, height);
|
|
|
|
- const maskCtx = maskCanvas.context;
|
|
|
|
- maskCtx.save();
|
|
|
|
- putBinaryImageMask(maskCtx, image);
|
|
|
|
- maskCtx.globalCompositeOperation = "source-in";
|
|
|
|
- maskCtx.fillStyle = isPatternFill ? fillColor.getPattern(maskCtx, this, ctx.mozCurrentTransformInverse, false) : fillColor;
|
|
|
|
- maskCtx.fillRect(0, 0, width, height);
|
|
|
|
- maskCtx.restore();
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.transform.apply(ctx, image.transform);
|
|
|
|
- ctx.scale(1, -1);
|
|
|
|
- ctx.drawImage(maskCanvas.canvas, 0, 0, width, height, 0, -1, 1, 1);
|
|
|
|
- ctx.restore();
|
|
|
|
- }
|
|
|
|
|
|
+ if (!imgData) {
|
|
|
|
+ (0, _util.warn)("Dependent image isn't ready yet");
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- paintImageXObject(objId) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ const width = imgData.width;
|
|
|
|
+ const height = imgData.height;
|
|
|
|
+ const map = [];
|
|
|
|
|
|
- const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
|
|
|
|
|
|
+ for (let i = 0, ii = positions.length; i < ii; i += 2) {
|
|
|
|
+ map.push({
|
|
|
|
+ transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]],
|
|
|
|
+ x: 0,
|
|
|
|
+ y: 0,
|
|
|
|
+ w: width,
|
|
|
|
+ h: height
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
|
|
- if (!imgData) {
|
|
|
|
- (0, _util.warn)("Dependent image isn't ready yet");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ this.paintInlineImageXObjectGroup(imgData, map);
|
|
|
|
+ }
|
|
|
|
|
|
- this.paintInlineImageXObject(imgData);
|
|
|
|
|
|
+ paintInlineImageXObject(imgData) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- paintImageXObjectRepeat(objId, scaleX, scaleY, positions) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ const width = imgData.width;
|
|
|
|
+ const height = imgData.height;
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ this.save();
|
|
|
|
+ ctx.scale(1 / width, -1 / height);
|
|
|
|
+ let imgToPaint;
|
|
|
|
|
|
- const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
|
|
|
|
|
|
+ if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) {
|
|
|
|
+ imgToPaint = imgData;
|
|
|
|
+ } else {
|
|
|
|
+ const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
|
|
|
|
+ const tmpCtx = tmpCanvas.context;
|
|
|
|
+ putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
|
|
|
|
+ imgToPaint = tmpCanvas.canvas;
|
|
|
|
+ }
|
|
|
|
|
|
- if (!imgData) {
|
|
|
|
- (0, _util.warn)("Dependent image isn't ready yet");
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ const scaled = this._scaleImage(imgToPaint, ctx.mozCurrentTransformInverse);
|
|
|
|
|
|
- const width = imgData.width;
|
|
|
|
- const height = imgData.height;
|
|
|
|
- const map = [];
|
|
|
|
-
|
|
|
|
- for (let i = 0, ii = positions.length; i < ii; i += 2) {
|
|
|
|
- map.push({
|
|
|
|
- transform: [scaleX, 0, 0, scaleY, positions[i], positions[i + 1]],
|
|
|
|
- x: 0,
|
|
|
|
- y: 0,
|
|
|
|
- w: width,
|
|
|
|
- h: height
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
|
|
+ ctx.imageSmoothingEnabled = getImageSmoothingEnabled(ctx.mozCurrentTransform, imgData.interpolate);
|
|
|
|
+ ctx.drawImage(scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
|
|
|
|
|
|
- this.paintInlineImageXObjectGroup(imgData, map);
|
|
|
|
|
|
+ if (this.imageLayer) {
|
|
|
|
+ const position = this.getCanvasPosition(0, -height);
|
|
|
|
+ this.imageLayer.appendImage({
|
|
|
|
+ imgData,
|
|
|
|
+ left: position[0],
|
|
|
|
+ top: position[1],
|
|
|
|
+ width: width / ctx.mozCurrentTransformInverse[0],
|
|
|
|
+ height: height / ctx.mozCurrentTransformInverse[3]
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
- paintInlineImageXObject(imgData) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const width = imgData.width;
|
|
|
|
- const height = imgData.height;
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- this.save();
|
|
|
|
- ctx.scale(1 / width, -1 / height);
|
|
|
|
- let imgToPaint;
|
|
|
|
|
|
+ this.restore();
|
|
|
|
+ }
|
|
|
|
|
|
- if (typeof HTMLElement === "function" && imgData instanceof HTMLElement || !imgData.data) {
|
|
|
|
- imgToPaint = imgData;
|
|
|
|
- } else {
|
|
|
|
- const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", width, height);
|
|
|
|
- const tmpCtx = tmpCanvas.context;
|
|
|
|
- putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
|
|
|
|
- imgToPaint = tmpCanvas.canvas;
|
|
|
|
- }
|
|
|
|
|
|
+ paintInlineImageXObjectGroup(imgData, map) {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- const scaled = this._scaleImage(imgToPaint, ctx.mozCurrentTransformInverse);
|
|
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
+ const w = imgData.width;
|
|
|
|
+ const h = imgData.height;
|
|
|
|
+ const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
|
|
|
|
+ const tmpCtx = tmpCanvas.context;
|
|
|
|
+ putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
|
|
|
|
|
|
- ctx.drawImage(scaled.img, 0, 0, scaled.paintWidth, scaled.paintHeight, 0, -height, width, height);
|
|
|
|
|
|
+ for (let i = 0, ii = map.length; i < ii; i++) {
|
|
|
|
+ const entry = map[i];
|
|
|
|
+ ctx.save();
|
|
|
|
+ ctx.transform.apply(ctx, entry.transform);
|
|
|
|
+ ctx.scale(1, -1);
|
|
|
|
+ ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
|
|
|
|
|
|
if (this.imageLayer) {
|
|
if (this.imageLayer) {
|
|
- const position = this.getCanvasPosition(0, -height);
|
|
|
|
|
|
+ const position = this.getCanvasPosition(entry.x, entry.y);
|
|
this.imageLayer.appendImage({
|
|
this.imageLayer.appendImage({
|
|
imgData,
|
|
imgData,
|
|
left: position[0],
|
|
left: position[0],
|
|
top: position[1],
|
|
top: position[1],
|
|
- width: width / ctx.mozCurrentTransformInverse[0],
|
|
|
|
- height: height / ctx.mozCurrentTransformInverse[3]
|
|
|
|
|
|
+ width: w,
|
|
|
|
+ height: h
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- this.restore();
|
|
|
|
|
|
+ ctx.restore();
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- paintInlineImageXObjectGroup(imgData, map) {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
- const w = imgData.width;
|
|
|
|
- const h = imgData.height;
|
|
|
|
- const tmpCanvas = this.cachedCanvases.getCanvas("inlineImage", w, h);
|
|
|
|
- const tmpCtx = tmpCanvas.context;
|
|
|
|
- putBinaryImageData(tmpCtx, imgData, this.current.transferMaps);
|
|
|
|
-
|
|
|
|
- for (let i = 0, ii = map.length; i < ii; i++) {
|
|
|
|
- const entry = map[i];
|
|
|
|
- ctx.save();
|
|
|
|
- ctx.transform.apply(ctx, entry.transform);
|
|
|
|
- ctx.scale(1, -1);
|
|
|
|
- ctx.drawImage(tmpCanvas.canvas, entry.x, entry.y, entry.w, entry.h, 0, -1, 1, 1);
|
|
|
|
-
|
|
|
|
- if (this.imageLayer) {
|
|
|
|
- const position = this.getCanvasPosition(entry.x, entry.y);
|
|
|
|
- this.imageLayer.appendImage({
|
|
|
|
- imgData,
|
|
|
|
- left: position[0],
|
|
|
|
- top: position[1],
|
|
|
|
- width: w,
|
|
|
|
- height: h
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ctx.restore();
|
|
|
|
- }
|
|
|
|
|
|
+ paintSolidColorImageMask() {
|
|
|
|
+ if (!this.contentVisible) {
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- paintSolidColorImageMask() {
|
|
|
|
- if (!this.contentVisible) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
+ this.ctx.fillRect(0, 0, 1, 1);
|
|
|
|
+ }
|
|
|
|
|
|
- this.ctx.fillRect(0, 0, 1, 1);
|
|
|
|
- }
|
|
|
|
|
|
+ markPoint(tag) {}
|
|
|
|
|
|
- markPoint(tag) {}
|
|
|
|
|
|
+ markPointProps(tag, properties) {}
|
|
|
|
|
|
- markPointProps(tag, properties) {}
|
|
|
|
|
|
+ beginMarkedContent(tag) {
|
|
|
|
+ this.markedContentStack.push({
|
|
|
|
+ visible: true
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
|
|
- beginMarkedContent(tag) {
|
|
|
|
|
|
+ beginMarkedContentProps(tag, properties) {
|
|
|
|
+ if (tag === "OC") {
|
|
|
|
+ this.markedContentStack.push({
|
|
|
|
+ visible: this.optionalContentConfig.isVisible(properties)
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
this.markedContentStack.push({
|
|
this.markedContentStack.push({
|
|
visible: true
|
|
visible: true
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- beginMarkedContentProps(tag, properties) {
|
|
|
|
- if (tag === "OC") {
|
|
|
|
- this.markedContentStack.push({
|
|
|
|
- visible: this.optionalContentConfig.isVisible(properties)
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- this.markedContentStack.push({
|
|
|
|
- visible: true
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.contentVisible = this.isContentVisible();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- endMarkedContent() {
|
|
|
|
- this.markedContentStack.pop();
|
|
|
|
- this.contentVisible = this.isContentVisible();
|
|
|
|
- }
|
|
|
|
|
|
+ this.contentVisible = this.isContentVisible();
|
|
|
|
+ }
|
|
|
|
|
|
- beginCompat() {}
|
|
|
|
|
|
+ endMarkedContent() {
|
|
|
|
+ this.markedContentStack.pop();
|
|
|
|
+ this.contentVisible = this.isContentVisible();
|
|
|
|
+ }
|
|
|
|
|
|
- endCompat() {}
|
|
|
|
|
|
+ beginCompat() {}
|
|
|
|
|
|
- consumePath() {
|
|
|
|
- const ctx = this.ctx;
|
|
|
|
|
|
+ endCompat() {}
|
|
|
|
|
|
- if (this.pendingClip) {
|
|
|
|
- if (this.pendingClip === EO_CLIP) {
|
|
|
|
- ctx.clip("evenodd");
|
|
|
|
- } else {
|
|
|
|
- ctx.clip();
|
|
|
|
- }
|
|
|
|
|
|
+ consumePath() {
|
|
|
|
+ const ctx = this.ctx;
|
|
|
|
|
|
- this.pendingClip = null;
|
|
|
|
|
|
+ if (this.pendingClip) {
|
|
|
|
+ if (this.pendingClip === EO_CLIP) {
|
|
|
|
+ ctx.clip("evenodd");
|
|
|
|
+ } else {
|
|
|
|
+ ctx.clip();
|
|
}
|
|
}
|
|
|
|
|
|
- ctx.beginPath();
|
|
|
|
|
|
+ this.pendingClip = null;
|
|
}
|
|
}
|
|
|
|
|
|
- getSinglePixelWidth() {
|
|
|
|
- if (this._cachedGetSinglePixelWidth === null) {
|
|
|
|
- const m = this.ctx.mozCurrentTransform;
|
|
|
|
- const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]);
|
|
|
|
- const sqNorm1 = m[0] ** 2 + m[2] ** 2;
|
|
|
|
- const sqNorm2 = m[1] ** 2 + m[3] ** 2;
|
|
|
|
- const pixelHeight = Math.sqrt(Math.max(sqNorm1, sqNorm2)) / absDet;
|
|
|
|
|
|
+ ctx.beginPath();
|
|
|
|
+ }
|
|
|
|
|
|
- if (sqNorm1 !== sqNorm2 && this._combinedScaleFactor * pixelHeight > 1) {
|
|
|
|
- this._cachedGetSinglePixelWidth = -(this._combinedScaleFactor * pixelHeight);
|
|
|
|
- } else if (absDet > Number.EPSILON) {
|
|
|
|
- this._cachedGetSinglePixelWidth = pixelHeight;
|
|
|
|
- } else {
|
|
|
|
- this._cachedGetSinglePixelWidth = 1;
|
|
|
|
- }
|
|
|
|
|
|
+ getSinglePixelWidth() {
|
|
|
|
+ if (this._cachedGetSinglePixelWidth === null) {
|
|
|
|
+ const m = this.ctx.mozCurrentTransform;
|
|
|
|
+ const absDet = Math.abs(m[0] * m[3] - m[2] * m[1]);
|
|
|
|
+ const sqNorm1 = m[0] ** 2 + m[2] ** 2;
|
|
|
|
+ const sqNorm2 = m[1] ** 2 + m[3] ** 2;
|
|
|
|
+ const pixelHeight = Math.sqrt(Math.max(sqNorm1, sqNorm2)) / absDet;
|
|
|
|
+
|
|
|
|
+ if (sqNorm1 !== sqNorm2 && this._combinedScaleFactor * pixelHeight > 1) {
|
|
|
|
+ this._cachedGetSinglePixelWidth = -(this._combinedScaleFactor * pixelHeight);
|
|
|
|
+ } else if (absDet > Number.EPSILON) {
|
|
|
|
+ this._cachedGetSinglePixelWidth = pixelHeight;
|
|
|
|
+ } else {
|
|
|
|
+ this._cachedGetSinglePixelWidth = 1;
|
|
}
|
|
}
|
|
-
|
|
|
|
- return this._cachedGetSinglePixelWidth;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- getCanvasPosition(x, y) {
|
|
|
|
- const transform = this.ctx.mozCurrentTransform;
|
|
|
|
- return [transform[0] * x + transform[2] * y + transform[4], transform[1] * x + transform[3] * y + transform[5]];
|
|
|
|
- }
|
|
|
|
|
|
+ return this._cachedGetSinglePixelWidth;
|
|
|
|
+ }
|
|
|
|
|
|
- isContentVisible() {
|
|
|
|
- for (let i = this.markedContentStack.length - 1; i >= 0; i--) {
|
|
|
|
- if (!this.markedContentStack[i].visible) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ getCanvasPosition(x, y) {
|
|
|
|
+ const transform = this.ctx.mozCurrentTransform;
|
|
|
|
+ return [transform[0] * x + transform[2] * y + transform[4], transform[1] * x + transform[3] * y + transform[5]];
|
|
|
|
+ }
|
|
|
|
|
|
- return true;
|
|
|
|
|
|
+ isContentVisible() {
|
|
|
|
+ for (let i = this.markedContentStack.length - 1; i >= 0; i--) {
|
|
|
|
+ if (!this.markedContentStack[i].visible) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ return true;
|
|
}
|
|
}
|
|
|
|
|
|
- for (const op in _util.OPS) {
|
|
|
|
- CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op];
|
|
|
|
- }
|
|
|
|
|
|
+}
|
|
|
|
|
|
- return CanvasGraphics;
|
|
|
|
-}();
|
|
|
|
|
|
+exports.CanvasGraphics = CanvasGraphics;
|
|
|
|
|
|
-exports.CanvasGraphics = CanvasGraphics;
|
|
|
|
|
|
+for (const op in _util.OPS) {
|
|
|
|
+ if (CanvasGraphics.prototype[op] !== undefined) {
|
|
|
|
+ CanvasGraphics.prototype[_util.OPS[op]] = CanvasGraphics.prototype[op];
|
|
|
|
+ }
|
|
|
|
+}
|