|
@@ -1,6 +1,6 @@
|
|
|
/**
|
|
|
* @licstart The following is the entire license notice for the
|
|
|
- * Javascript code in this page
|
|
|
+ * JavaScript code in this page
|
|
|
*
|
|
|
* Copyright 2022 Mozilla Foundation
|
|
|
*
|
|
@@ -17,7 +17,7 @@
|
|
|
* limitations under the License.
|
|
|
*
|
|
|
* @licend The above is the entire license notice for the
|
|
|
- * Javascript code in this page
|
|
|
+ * JavaScript code in this page
|
|
|
*/
|
|
|
"use strict";
|
|
|
|
|
@@ -70,7 +70,7 @@ var _core_utils = require("./core_utils.js");
|
|
|
|
|
|
var _metrics = require("./metrics.js");
|
|
|
|
|
|
-var _murmurhash = require("./murmurhash3.js");
|
|
|
+var _murmurhash = require("../shared/murmurhash3.js");
|
|
|
|
|
|
var _operator_list = require("./operator_list.js");
|
|
|
|
|
@@ -174,6 +174,12 @@ function normalizeBlendMode(value, parsingArray = false) {
|
|
|
return "source-over";
|
|
|
}
|
|
|
|
|
|
+function incrementCachedImageMaskCount(data) {
|
|
|
+ if (data.fn === _util.OPS.paintImageMaskXObject && data.args[0] && data.args[0].count > 0) {
|
|
|
+ data.args[0].count++;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
class TimeSlotManager {
|
|
|
static get TIME_SLOT_DURATION_MS() {
|
|
|
return (0, _util.shadow)(this, "TIME_SLOT_DURATION_MS", 20);
|
|
@@ -355,9 +361,10 @@ class PartialEvaluator {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- processed.forEach(ref => {
|
|
|
+ for (const ref of processed) {
|
|
|
nonBlendModesSet.put(ref);
|
|
|
- });
|
|
|
+ }
|
|
|
+
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -522,7 +529,7 @@ class PartialEvaluator {
|
|
|
}
|
|
|
|
|
|
_sendImgData(objId, imgData, cacheGlobally = false) {
|
|
|
- const transfers = imgData ? [imgData.data.buffer] : null;
|
|
|
+ const transfers = imgData ? [imgData.bitmap || imgData.data.buffer] : null;
|
|
|
|
|
|
if (this.parsingType3Font || cacheGlobally) {
|
|
|
return this.handler.send("commonobj", [objId, "Image", imgData], transfers);
|
|
@@ -553,8 +560,14 @@ class PartialEvaluator {
|
|
|
const maxImageSize = this.options.maxImageSize;
|
|
|
|
|
|
if (maxImageSize !== -1 && w * h > maxImageSize) {
|
|
|
- (0, _util.warn)("Image exceeded maximum allowed size and was removed.");
|
|
|
- return;
|
|
|
+ const msg = "Image exceeded maximum allowed size and was removed.";
|
|
|
+
|
|
|
+ if (this.options.ignoreErrors) {
|
|
|
+ (0, _util.warn)(msg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new Error(msg);
|
|
|
}
|
|
|
|
|
|
let optionalContent;
|
|
@@ -563,18 +576,39 @@ class PartialEvaluator {
|
|
|
optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources);
|
|
|
}
|
|
|
|
|
|
- if (optionalContent !== undefined) {
|
|
|
- operatorList.addOp(_util.OPS.beginMarkedContentProps, ["OC", optionalContent]);
|
|
|
- }
|
|
|
-
|
|
|
const imageMask = dict.get("IM", "ImageMask") || false;
|
|
|
- const interpolate = dict.get("I", "Interpolate");
|
|
|
let imgData, args;
|
|
|
|
|
|
if (imageMask) {
|
|
|
+ const interpolate = dict.get("I", "Interpolate");
|
|
|
const bitStrideLength = w + 7 >> 3;
|
|
|
- const imgArray = image.getBytes(bitStrideLength * h, true);
|
|
|
+ const imgArray = image.getBytes(bitStrideLength * h);
|
|
|
const decode = dict.getArray("D", "Decode");
|
|
|
+
|
|
|
+ if (this.parsingType3Font) {
|
|
|
+ imgData = _image.PDFImage.createRawMask({
|
|
|
+ imgArray,
|
|
|
+ width: w,
|
|
|
+ height: h,
|
|
|
+ imageIsFromDecodeStream: image instanceof _decode_stream.DecodeStream,
|
|
|
+ inverseDecode: !!decode && decode[0] > 0,
|
|
|
+ interpolate
|
|
|
+ });
|
|
|
+ imgData.cached = !!cacheKey;
|
|
|
+ args = [imgData];
|
|
|
+ operatorList.addImageOps(_util.OPS.paintImageMaskXObject, args, optionalContent);
|
|
|
+
|
|
|
+ if (cacheKey) {
|
|
|
+ localImageCache.set(cacheKey, imageRef, {
|
|
|
+ fn: _util.OPS.paintImageMaskXObject,
|
|
|
+ args,
|
|
|
+ optionalContent
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
imgData = _image.PDFImage.createMask({
|
|
|
imgArray,
|
|
|
width: w,
|
|
@@ -583,21 +617,43 @@ class PartialEvaluator {
|
|
|
inverseDecode: !!decode && decode[0] > 0,
|
|
|
interpolate
|
|
|
});
|
|
|
- imgData.cached = !!cacheKey;
|
|
|
- args = [imgData];
|
|
|
- operatorList.addOp(_util.OPS.paintImageMaskXObject, args);
|
|
|
+
|
|
|
+ if (imgData.isSingleOpaquePixel) {
|
|
|
+ operatorList.addImageOps(_util.OPS.paintSolidColorImageMask, [], optionalContent);
|
|
|
+
|
|
|
+ if (cacheKey) {
|
|
|
+ localImageCache.set(cacheKey, imageRef, {
|
|
|
+ fn: _util.OPS.paintSolidColorImageMask,
|
|
|
+ args: [],
|
|
|
+ optionalContent
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const objId = `mask_${this.idFactory.createObjId()}`;
|
|
|
+ operatorList.addDependency(objId);
|
|
|
+
|
|
|
+ this._sendImgData(objId, imgData);
|
|
|
+
|
|
|
+ args = [{
|
|
|
+ data: objId,
|
|
|
+ width: imgData.width,
|
|
|
+ height: imgData.height,
|
|
|
+ interpolate: imgData.interpolate,
|
|
|
+ count: 1
|
|
|
+ }];
|
|
|
+ operatorList.addImageOps(_util.OPS.paintImageMaskXObject, args, optionalContent);
|
|
|
|
|
|
if (cacheKey) {
|
|
|
localImageCache.set(cacheKey, imageRef, {
|
|
|
fn: _util.OPS.paintImageMaskXObject,
|
|
|
- args
|
|
|
+ args,
|
|
|
+ optionalContent
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- if (optionalContent !== undefined) {
|
|
|
- operatorList.addOp(_util.OPS.endMarkedContent, []);
|
|
|
- }
|
|
|
-
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -615,12 +671,7 @@ class PartialEvaluator {
|
|
|
localColorSpaceCache
|
|
|
});
|
|
|
imgData = imageObj.createImageData(true);
|
|
|
- operatorList.addOp(_util.OPS.paintInlineImageXObject, [imgData]);
|
|
|
-
|
|
|
- if (optionalContent !== undefined) {
|
|
|
- operatorList.addOp(_util.OPS.endMarkedContent, []);
|
|
|
- }
|
|
|
-
|
|
|
+ operatorList.addImageOps(_util.OPS.paintInlineImageXObject, [imgData], optionalContent);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -660,12 +711,13 @@ class PartialEvaluator {
|
|
|
return this._sendImgData(objId, null, cacheGlobally);
|
|
|
});
|
|
|
|
|
|
- operatorList.addOp(_util.OPS.paintImageXObject, args);
|
|
|
+ operatorList.addImageOps(_util.OPS.paintImageXObject, args, optionalContent);
|
|
|
|
|
|
if (cacheKey) {
|
|
|
localImageCache.set(cacheKey, imageRef, {
|
|
|
fn: _util.OPS.paintImageXObject,
|
|
|
- args
|
|
|
+ args,
|
|
|
+ optionalContent
|
|
|
});
|
|
|
|
|
|
if (imageRef) {
|
|
@@ -677,15 +729,12 @@ class PartialEvaluator {
|
|
|
objId,
|
|
|
fn: _util.OPS.paintImageXObject,
|
|
|
args,
|
|
|
+ optionalContent,
|
|
|
byteSize: 0
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- if (optionalContent !== undefined) {
|
|
|
- operatorList.addOp(_util.OPS.endMarkedContent, []);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
handleSMask(smask, resources, operatorList, task, stateManager, localColorSpaceCache) {
|
|
@@ -1146,13 +1195,16 @@ class PartialEvaluator {
|
|
|
args = [];
|
|
|
}
|
|
|
|
|
|
+ let minMax;
|
|
|
+
|
|
|
if (lastIndex < 0 || operatorList.fnArray[lastIndex] !== _util.OPS.constructPath) {
|
|
|
if (parsingText) {
|
|
|
(0, _util.warn)(`Encountered path operator "${fn}" inside of a text object.`);
|
|
|
operatorList.addOp(_util.OPS.save, null);
|
|
|
}
|
|
|
|
|
|
- operatorList.addOp(_util.OPS.constructPath, [[fn], args]);
|
|
|
+ minMax = [Infinity, -Infinity, Infinity, -Infinity];
|
|
|
+ operatorList.addOp(_util.OPS.constructPath, [[fn], args, minMax]);
|
|
|
|
|
|
if (parsingText) {
|
|
|
operatorList.addOp(_util.OPS.restore, null);
|
|
@@ -1161,6 +1213,24 @@ class PartialEvaluator {
|
|
|
const opArgs = operatorList.argsArray[lastIndex];
|
|
|
opArgs[0].push(fn);
|
|
|
Array.prototype.push.apply(opArgs[1], args);
|
|
|
+ minMax = opArgs[2];
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (fn) {
|
|
|
+ case _util.OPS.rectangle:
|
|
|
+ minMax[0] = Math.min(minMax[0], args[0], args[0] + args[2]);
|
|
|
+ minMax[1] = Math.max(minMax[1], args[0], args[0] + args[2]);
|
|
|
+ minMax[2] = Math.min(minMax[2], args[1], args[1] + args[3]);
|
|
|
+ minMax[3] = Math.max(minMax[3], args[1], args[1] + args[3]);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case _util.OPS.moveTo:
|
|
|
+ case _util.OPS.lineTo:
|
|
|
+ minMax[0] = Math.min(minMax[0], args[0]);
|
|
|
+ minMax[1] = Math.max(minMax[1], args[0]);
|
|
|
+ minMax[2] = Math.min(minMax[2], args[1]);
|
|
|
+ minMax[3] = Math.max(minMax[3], args[1]);
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1438,7 +1508,8 @@ class PartialEvaluator {
|
|
|
const localImage = localImageCache.getByName(name);
|
|
|
|
|
|
if (localImage) {
|
|
|
- operatorList.addOp(localImage.fn, localImage.args);
|
|
|
+ operatorList.addImageOps(localImage.fn, localImage.args, localImage.optionalContent);
|
|
|
+ incrementCachedImageMaskCount(localImage);
|
|
|
args = null;
|
|
|
continue;
|
|
|
}
|
|
@@ -1455,7 +1526,8 @@ class PartialEvaluator {
|
|
|
const localImage = localImageCache.getByRef(xobj);
|
|
|
|
|
|
if (localImage) {
|
|
|
- operatorList.addOp(localImage.fn, localImage.args);
|
|
|
+ operatorList.addImageOps(localImage.fn, localImage.args, localImage.optionalContent);
|
|
|
+ incrementCachedImageMaskCount(localImage);
|
|
|
resolveXObject();
|
|
|
return;
|
|
|
}
|
|
@@ -1464,7 +1536,7 @@ class PartialEvaluator {
|
|
|
|
|
|
if (globalImage) {
|
|
|
operatorList.addDependency(globalImage.objId);
|
|
|
- operatorList.addOp(globalImage.fn, globalImage.args);
|
|
|
+ operatorList.addImageOps(globalImage.fn, globalImage.args, globalImage.optionalContent);
|
|
|
resolveXObject();
|
|
|
return;
|
|
|
}
|
|
@@ -1546,7 +1618,8 @@ class PartialEvaluator {
|
|
|
const localImage = localImageCache.getByName(cacheKey);
|
|
|
|
|
|
if (localImage) {
|
|
|
- operatorList.addOp(localImage.fn, localImage.args);
|
|
|
+ operatorList.addImageOps(localImage.fn, localImage.args, localImage.optionalContent);
|
|
|
+ incrementCachedImageMaskCount(localImage);
|
|
|
args = null;
|
|
|
continue;
|
|
|
}
|
|
@@ -1945,11 +2018,29 @@ class PartialEvaluator {
|
|
|
spaceInFlowMax: 0,
|
|
|
trackingSpaceMin: Infinity,
|
|
|
negativeSpaceMax: -Infinity,
|
|
|
+ notASpace: -Infinity,
|
|
|
transform: null,
|
|
|
fontName: null,
|
|
|
hasEOL: false
|
|
|
};
|
|
|
+ const twoLastChars = [" ", " "];
|
|
|
+ let twoLastCharsPos = 0;
|
|
|
+
|
|
|
+ function saveLastChar(char) {
|
|
|
+ const nextPos = (twoLastCharsPos + 1) % 2;
|
|
|
+ const ret = twoLastChars[twoLastCharsPos] !== " " && twoLastChars[nextPos] === " ";
|
|
|
+ twoLastChars[twoLastCharsPos] = char;
|
|
|
+ twoLastCharsPos = nextPos;
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ function resetLastChars() {
|
|
|
+ twoLastChars[0] = twoLastChars[1] = " ";
|
|
|
+ twoLastCharsPos = 0;
|
|
|
+ }
|
|
|
+
|
|
|
const TRACKING_SPACE_FACTOR = 0.1;
|
|
|
+ const NOT_A_SPACE_FACTOR = 0.03;
|
|
|
const NEGATIVE_SPACE_FACTOR = -0.2;
|
|
|
const SPACE_IN_FLOW_MIN_FACTOR = 0.1;
|
|
|
const SPACE_IN_FLOW_MAX_FACTOR = 0.6;
|
|
@@ -2012,6 +2103,7 @@ class PartialEvaluator {
|
|
|
const scaleCtmX = Math.hypot(textState.ctm[0], textState.ctm[1]);
|
|
|
textContentItem.textAdvanceScale = scaleCtmX * scaleLineX;
|
|
|
textContentItem.trackingSpaceMin = textState.fontSize * TRACKING_SPACE_FACTOR;
|
|
|
+ textContentItem.notASpace = textState.fontSize * NOT_A_SPACE_FACTOR;
|
|
|
textContentItem.negativeSpaceMax = textState.fontSize * NEGATIVE_SPACE_FACTOR;
|
|
|
textContentItem.spaceInFlowMin = textState.fontSize * SPACE_IN_FLOW_MIN_FACTOR;
|
|
|
textContentItem.spaceInFlowMax = textState.fontSize * SPACE_IN_FLOW_MAX_FACTOR;
|
|
@@ -2142,6 +2234,7 @@ class PartialEvaluator {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ resetLastChars();
|
|
|
flushTextContentItem();
|
|
|
return true;
|
|
|
}
|
|
@@ -2151,10 +2244,15 @@ class PartialEvaluator {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ if (advanceY <= textOrientation * textContentItem.notASpace) {
|
|
|
+ resetLastChars();
|
|
|
+ }
|
|
|
+
|
|
|
if (advanceY <= textOrientation * textContentItem.trackingSpaceMin) {
|
|
|
textContentItem.height += advanceY;
|
|
|
} else if (!addFakeSpaces(advanceY, textContentItem.prevTransform, textOrientation)) {
|
|
|
if (textContentItem.str.length === 0) {
|
|
|
+ resetLastChars();
|
|
|
textContent.items.push({
|
|
|
str: " ",
|
|
|
dir: "ltr",
|
|
@@ -2182,6 +2280,7 @@ class PartialEvaluator {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ resetLastChars();
|
|
|
flushTextContentItem();
|
|
|
return true;
|
|
|
}
|
|
@@ -2191,10 +2290,15 @@ class PartialEvaluator {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ if (advanceX <= textOrientation * textContentItem.notASpace) {
|
|
|
+ resetLastChars();
|
|
|
+ }
|
|
|
+
|
|
|
if (advanceX <= textOrientation * textContentItem.trackingSpaceMin) {
|
|
|
textContentItem.width += advanceX;
|
|
|
} else if (!addFakeSpaces(advanceX, textContentItem.prevTransform, textOrientation)) {
|
|
|
if (textContentItem.str.length === 0) {
|
|
|
+ resetLastChars();
|
|
|
textContent.items.push({
|
|
|
str: " ",
|
|
|
dir: "ltr",
|
|
@@ -2251,7 +2355,7 @@ class PartialEvaluator {
|
|
|
|
|
|
let scaledDim = glyphWidth * scale;
|
|
|
|
|
|
- if (glyph.isWhitespace && (i === 0 || i + 1 === ii || glyphs[i - 1].isWhitespace || glyphs[i + 1].isWhitespace || extraSpacing)) {
|
|
|
+ if (glyph.isWhitespace) {
|
|
|
if (!font.vertical) {
|
|
|
charSpacing += scaledDim + textState.wordSpacing;
|
|
|
textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
|
|
@@ -2260,6 +2364,7 @@ class PartialEvaluator {
|
|
|
textState.translateTextMatrix(0, -charSpacing);
|
|
|
}
|
|
|
|
|
|
+ saveLastChar(" ");
|
|
|
continue;
|
|
|
}
|
|
|
|
|
@@ -2287,15 +2392,16 @@ class PartialEvaluator {
|
|
|
textChunk.prevTransform = getCurrentTextTransform();
|
|
|
}
|
|
|
|
|
|
- if (glyph.isWhitespace) {
|
|
|
+ let glyphUnicode = glyph.unicode;
|
|
|
+ glyphUnicode = NormalizedUnicodes[glyphUnicode] || glyphUnicode;
|
|
|
+ glyphUnicode = (0, _unicode.reverseIfRtl)(glyphUnicode);
|
|
|
+
|
|
|
+ if (saveLastChar(glyphUnicode)) {
|
|
|
textChunk.str.push(" ");
|
|
|
- } else {
|
|
|
- let glyphUnicode = glyph.unicode;
|
|
|
- glyphUnicode = NormalizedUnicodes[glyphUnicode] || glyphUnicode;
|
|
|
- glyphUnicode = (0, _unicode.reverseIfRtl)(glyphUnicode);
|
|
|
- textChunk.str.push(glyphUnicode);
|
|
|
}
|
|
|
|
|
|
+ textChunk.str.push(glyphUnicode);
|
|
|
+
|
|
|
if (charSpacing) {
|
|
|
if (!font.vertical) {
|
|
|
textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
|
|
@@ -2307,6 +2413,8 @@ class PartialEvaluator {
|
|
|
}
|
|
|
|
|
|
function appendEOL() {
|
|
|
+ resetLastChars();
|
|
|
+
|
|
|
if (textContentItem.initialized) {
|
|
|
textContentItem.hasEOL = true;
|
|
|
flushTextContentItem();
|
|
@@ -2326,6 +2434,7 @@ class PartialEvaluator {
|
|
|
function addFakeSpaces(width, transf, textOrientation) {
|
|
|
if (textOrientation * textContentItem.spaceInFlowMin <= width && width <= textOrientation * textContentItem.spaceInFlowMax) {
|
|
|
if (textContentItem.initialized) {
|
|
|
+ resetLastChars();
|
|
|
textContentItem.str.push(" ");
|
|
|
}
|
|
|
|
|
@@ -2341,6 +2450,7 @@ class PartialEvaluator {
|
|
|
}
|
|
|
|
|
|
flushTextContentItem();
|
|
|
+ resetLastChars();
|
|
|
textContent.items.push({
|
|
|
str: " ",
|
|
|
dir: "ltr",
|
|
@@ -2841,7 +2951,13 @@ class PartialEvaluator {
|
|
|
} else if (encoding instanceof _primitives.Name) {
|
|
|
baseEncodingName = encoding.name;
|
|
|
} else {
|
|
|
- throw new _util.FormatError("Encoding is not a Name nor a Dict");
|
|
|
+ const msg = "Encoding is not a Name nor a Dict";
|
|
|
+
|
|
|
+ if (!this.options.ignoreErrors) {
|
|
|
+ throw new _util.FormatError(msg);
|
|
|
+ }
|
|
|
+
|
|
|
+ (0, _util.warn)(msg);
|
|
|
}
|
|
|
|
|
|
if (baseEncodingName !== "MacRomanEncoding" && baseEncodingName !== "MacExpertEncoding" && baseEncodingName !== "WinAnsiEncoding") {
|