diff --git a/src/core/evaluator.js b/src/core/evaluator.js index dd69ef65e..e81d9ac81 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -392,6 +392,14 @@ class PartialEvaluator { } else { bbox = null; } + let optionalContent = null; + if (dict.has("OC")) { + optionalContent = await this.parseMarkedContentProps( + dict.get("OC"), + resources + ); + operatorList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]); + } var group = dict.get("Group"); if (group) { var groupOptions = { @@ -449,6 +457,10 @@ class PartialEvaluator { if (group) { operatorList.addOp(OPS.endGroup, [groupOptions]); } + + if (optionalContent) { + operatorList.addOp(OPS.endMarkedContent, []); + } }); } @@ -1202,6 +1214,63 @@ class PartialEvaluator { throw new FormatError(`Unknown PatternName: ${patternName}`); } + async parseMarkedContentProps(contentProperties, resources) { + let optionalContent; + if (isName(contentProperties)) { + const properties = resources.get("Properties"); + optionalContent = properties.get(contentProperties.name); + } else if (isDict(contentProperties)) { + optionalContent = contentProperties; + } else { + throw new FormatError("Optional content properties malformed."); + } + + const optionalContentType = optionalContent.get("Type").name; + if (optionalContentType === "OCG") { + return { + type: optionalContentType, + id: optionalContent.objId, + }; + } else if (optionalContentType === "OCMD") { + const optionalContentGroups = optionalContent.get("OCGs"); + if ( + Array.isArray(optionalContentGroups) || + isDict(optionalContentGroups) + ) { + const groupIds = []; + if (Array.isArray(optionalContentGroups)) { + optionalContent.get("OCGs").forEach(ocg => { + groupIds.push(ocg.toString()); + }); + } else { + // Dictionary, just use the obj id. + groupIds.push(optionalContentGroups.objId); + } + + let expression = null; + if (optionalContent.get("VE")) { + // TODO support visibility expression. + expression = true; + } + + return { + type: optionalContentType, + ids: groupIds, + policy: isName(optionalContent.get("P")) + ? optionalContent.get("P").name + : null, + expression, + }; + } else if (isRef(optionalContentGroups)) { + return { + type: optionalContentType, + id: optionalContentGroups.toString(), + }; + } + } + return null; + } + getOperatorList({ stream, task, @@ -1704,9 +1773,6 @@ class PartialEvaluator { continue; case OPS.markPoint: case OPS.markPointProps: - case OPS.beginMarkedContent: - case OPS.beginMarkedContentProps: - case OPS.endMarkedContent: case OPS.beginCompat: case OPS.endCompat: // Ignore operators where the corresponding handlers are known to @@ -1716,6 +1782,45 @@ class PartialEvaluator { // e.g. as done in https://github.com/mozilla/pdf.js/pull/6266, // but doing so is meaningless without knowing the semantics. continue; + case OPS.beginMarkedContentProps: + if (!isName(args[0])) { + warn(`Expected name for beginMarkedContentProps arg0=${args[0]}`); + continue; + } + if (args[0].name === "OC") { + next( + self + .parseMarkedContentProps(args[1], resources) + .then(data => { + operatorList.addOp(OPS.beginMarkedContentProps, [ + "OC", + data, + ]); + }) + .catch(reason => { + if (reason instanceof AbortException) { + return; + } + if (self.options.ignoreErrors) { + self.handler.send("UnsupportedFeature", { + featureId: UNSUPPORTED_FEATURES.errorMarkedContent, + }); + warn( + `getOperatorList - ignoring beginMarkedContentProps: "${reason}".` + ); + return; + } + throw reason; + }) + ); + return; + } + // Other marked content types aren't supported yet. + args = [args[0].name]; + + break; + case OPS.beginMarkedContent: + case OPS.endMarkedContent: default: // Note: Ignore the operator if it has `Dict` arguments, since // those are non-serializable, otherwise postMessage will throw diff --git a/src/core/obj.js b/src/core/obj.js index fd1986e9d..9139a7bf6 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -254,6 +254,82 @@ class Catalog { return permissions; } + get optionalContentConfig() { + let config = null; + try { + const properties = this.catDict.get("OCProperties"); + if (!properties) { + return shadow(this, "optionalContentConfig", null); + } + const defaultConfig = properties.get("D"); + if (!defaultConfig) { + return shadow(this, "optionalContentConfig", null); + } + const groupsData = properties.get("OCGs"); + if (!Array.isArray(groupsData)) { + return shadow(this, "optionalContentConfig", null); + } + const groups = []; + const groupRefs = []; + // Ensure all the optional content groups are valid. + for (const groupRef of groupsData) { + if (!isRef(groupRef)) { + continue; + } + groupRefs.push(groupRef); + const group = this.xref.fetchIfRef(groupRef); + groups.push({ + id: groupRef.toString(), + name: isString(group.get("Name")) + ? stringToPDFString(group.get("Name")) + : null, + intent: isString(group.get("Intent")) + ? stringToPDFString(group.get("Intent")) + : null, + }); + } + config = this._readOptionalContentConfig(defaultConfig, groupRefs); + config.groups = groups; + } catch (ex) { + if (ex instanceof MissingDataException) { + throw ex; + } + warn(`Unable to read optional content config: ${ex}`); + } + return shadow(this, "optionalContentConfig", config); + } + + _readOptionalContentConfig(config, contentGroupRefs) { + function parseOnOff(refs) { + const onParsed = []; + if (Array.isArray(refs)) { + for (const value of refs) { + if (!isRef(value)) { + continue; + } + if (contentGroupRefs.includes(value)) { + onParsed.push(value.toString()); + } + } + } + return onParsed; + } + + return { + name: isString(config.get("Name")) + ? stringToPDFString(config.get("Name")) + : null, + creator: isString(config.get("Creator")) + ? stringToPDFString(config.get("Creator")) + : null, + baseState: isName(config.get("BaseState")) + ? config.get("BaseState").name + : null, + on: parseOnOff(config.get("ON")), + off: parseOnOff(config.get("OFF")), + }; + } + get numPages() { const obj = this.toplevelPagesDict.get("Count"); if (!Number.isInteger(obj)) { diff --git a/src/core/worker.js b/src/core/worker.js index 269bb6ab2..2eb282c33 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -481,6 +481,10 @@ class WorkerMessageHandler { return pdfManager.ensureCatalog("documentOutline"); }); + handler.on("GetOptionalContentConfig", function (data) { + return pdfManager.ensureCatalog("optionalContentConfig"); + }); + handler.on("GetPermissions", function (data) { return pdfManager.ensureCatalog("permissions"); }); diff --git a/src/display/api.js b/src/display/api.js index 0b0387bcf..6251d6946 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -55,6 +55,7 @@ import { GlobalWorkerOptions } from "./worker_options.js"; import { isNodeJS } from "../shared/is_node.js"; import { MessageHandler } from "../shared/message_handler.js"; import { Metadata } from "./metadata.js"; +import { OptionalContentConfig } from "./optional_content_config.js"; import { PDFDataTransportStream } from "./transport_stream.js"; import { WebGLContext } from "./webgl.js"; @@ -788,6 +789,15 @@ class PDFDocumentProxy { return this._transport.getOutline(); } + /** + * @returns {Promise} A promise that is resolved + * with an {@link OptionalContentConfig} that will have all the optional + * content groups (if the document has any). + */ + getOptionalContentConfig() { + return this._transport.getOptionalContentConfig(); + } + /** * @returns {Promise>} A promise that is resolved with * an {Array} that contains the permission flags for the PDF document, or @@ -965,6 +975,11 @@ class PDFDocumentProxy { * image). The default value is 'rgb(255,255,255)'. * @property {Object} [annotationStorage] - Storage for annotation data in * forms. + * @property {Promise} [optionalContentConfigPromise] - A promise that should + * resolve with an {OptionalContentConfig} created from + * PDFDocumentProxy.getOptionalContentConfig. If null, the + * config will be automatically fetched with the default + * visibility states set. */ /** @@ -1088,6 +1103,7 @@ class PDFPageProxy { canvasFactory = null, background = null, annotationStorage = null, + optionalContentConfigPromise = null, }) { if (this._stats) { this._stats.time("Overall"); @@ -1098,6 +1114,10 @@ class PDFPageProxy { // this call to render. this.pendingCleanup = false; + if (!optionalContentConfigPromise) { + optionalContentConfigPromise = this._transport.getOptionalContentConfig(); + } + let intentState = this._intentStates.get(renderingIntent); if (!intentState) { intentState = Object.create(null); @@ -1191,8 +1211,11 @@ class PDFPageProxy { intentState.renderTasks.push(internalRenderTask); const renderTask = internalRenderTask.task; - intentState.displayReadyCapability.promise - .then(transparency => { + Promise.all([ + intentState.displayReadyCapability.promise, + optionalContentConfigPromise, + ]) + .then(([transparency, optionalContentConfig]) => { if (this.pendingCleanup) { complete(); return; @@ -1200,7 +1223,10 @@ class PDFPageProxy { if (this._stats) { this._stats.time("Rendering"); } - internalRenderTask.initializeGraphics(transparency); + internalRenderTask.initializeGraphics({ + transparency, + optionalContentConfig, + }); internalRenderTask.operatorListChanged(); }) .catch(complete); @@ -2546,6 +2572,14 @@ class WorkerTransport { return this.messageHandler.sendWithPromise("GetOutline", null); } + getOptionalContentConfig() { + return this.messageHandler + .sendWithPromise("GetOptionalContentConfig", null) + .then(results => { + return new OptionalContentConfig(results); + }); + } + getPermissions() { return this.messageHandler.sendWithPromise("GetPermissions", null); } @@ -2759,7 +2793,7 @@ const InternalRenderTask = (function InternalRenderTaskClosure() { }); } - initializeGraphics(transparency = false) { + initializeGraphics({ transparency = false, optionalContentConfig }) { if (this.cancelled) { return; } @@ -2797,7 +2831,8 @@ const InternalRenderTask = (function InternalRenderTaskClosure() { this.objs, this.canvasFactory, this.webGLContext, - imageLayer + imageLayer, + optionalContentConfig ); this.gfx.beginDrawing({ transform, diff --git a/src/display/canvas.js b/src/display/canvas.js index d987bac4a..83d95edfc 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -447,7 +447,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { objs, canvasFactory, webGLContext, - imageLayer + imageLayer, + optionalContentConfig ) { this.ctx = canvasCtx; this.current = new CanvasExtraState(); @@ -471,6 +472,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.smaskStack = []; this.smaskCounter = 0; this.tempSMask = null; + this.contentVisible = true; + this.markedContentStack = []; + this.optionalContentConfig = optionalContentConfig; this.cachedCanvases = new CachedCanvases(this.canvasFactory); if (canvasCtx) { // NOTE: if mozCurrentTransform is polyfilled, then the current state of @@ -1262,34 +1266,36 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { // For stroke we want to temporarily change the global alpha to the // stroking alpha. ctx.globalAlpha = this.current.strokeAlpha; - if ( - strokeColor && - strokeColor.hasOwnProperty("type") && - strokeColor.type === "Pattern" - ) { - // for patterns, we transform to pattern space, calculate - // the pattern, call stroke, and restore to user space - ctx.save(); - // The current transform will be replaced while building the pattern, - // but the line width needs to be adjusted by the current transform, so - // we must scale it. To properly fix this we should be using a pattern - // transform instead (see #10955). - const transform = ctx.mozCurrentTransform; - const scale = Util.singularValueDecompose2dScale(transform)[0]; - ctx.strokeStyle = strokeColor.getPattern(ctx, this); - ctx.lineWidth = Math.max( - this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, - this.current.lineWidth * scale - ); - ctx.stroke(); - ctx.restore(); - } else { - // Prevent drawing too thin lines by enforcing a minimum line width. - ctx.lineWidth = Math.max( - this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, - this.current.lineWidth - ); - ctx.stroke(); + if (this.contentVisible) { + if ( + strokeColor && + strokeColor.hasOwnProperty("type") && + strokeColor.type === "Pattern" + ) { + // for patterns, we transform to pattern space, calculate + // the pattern, call stroke, and restore to user space + ctx.save(); + // The current transform will be replaced while building the pattern, + // but the line width needs to be adjusted by the current transform, + // so we must scale it. To properly fix this we should be using a + // pattern transform instead (see #10955). + const transform = ctx.mozCurrentTransform; + const scale = Util.singularValueDecompose2dScale(transform)[0]; + ctx.strokeStyle = strokeColor.getPattern(ctx, this); + ctx.lineWidth = Math.max( + this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, + this.current.lineWidth * scale + ); + ctx.stroke(); + ctx.restore(); + } else { + // Prevent drawing too thin lines by enforcing a minimum line width. + ctx.lineWidth = Math.max( + this.getSinglePixelWidth() * MIN_WIDTH_FACTOR, + this.current.lineWidth + ); + ctx.stroke(); + } } if (consumePath) { this.consumePath(); @@ -1317,11 +1323,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { needRestore = true; } - if (this.pendingEOFill) { - ctx.fill("evenodd"); - this.pendingEOFill = false; - } else { - ctx.fill(); + if (this.contentVisible) { + if (this.pendingEOFill) { + ctx.fill("evenodd"); + this.pendingEOFill = false; + } else { + ctx.fill(); + } } if (needRestore) { @@ -1700,7 +1708,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { // Only attempt to draw the glyph if it is actually in the embedded font // file or if there isn't a font file so the fallback font is shown. - if (glyph.isInFont || font.missingFile) { + if (this.contentVisible && (glyph.isInFont || font.missingFile)) { if (simpleFillText && !accent) { // common case ctx.fillText(character, scaledX, scaledY); @@ -1782,12 +1790,14 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { warn(`Type3 character "${glyph.operatorListId}" is not available.`); continue; } - this.processingType3 = glyph; - this.save(); - ctx.scale(fontSize, fontSize); - ctx.transform.apply(ctx, fontMatrix); - this.executeOperatorList(operatorList); - this.restore(); + if (this.contentVisible) { + this.processingType3 = glyph; + this.save(); + ctx.scale(fontSize, fontSize); + ctx.transform.apply(ctx, fontMatrix); + this.executeOperatorList(operatorList); + this.restore(); + } var transformed = Util.applyTransform([glyph.width, 0], fontMatrix); width = transformed[0] * fontSize + spacing; @@ -1869,6 +1879,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, shadingFill: function CanvasGraphics_shadingFill(patternIR) { + if (!this.contentVisible) { + return; + } var ctx = this.ctx; this.save(); @@ -1917,6 +1930,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { matrix, bbox ) { + if (!this.contentVisible) { + return; + } this.save(); this.baseTransformStack.push(this.baseTransform); @@ -1936,11 +1952,18 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() { + if (!this.contentVisible) { + return; + } this.restore(); this.baseTransform = this.baseTransformStack.pop(); }, beginGroup: function CanvasGraphics_beginGroup(group) { + if (!this.contentVisible) { + return; + } + this.save(); var currentCtx = this.ctx; // TODO non-isolated groups - according to Rik at adobe non-isolated @@ -2062,6 +2085,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, endGroup: function CanvasGraphics_endGroup(group) { + if (!this.contentVisible) { + return; + } this.groupLevel--; var groupCtx = this.ctx; this.ctx = this.groupStack.pop(); @@ -2117,6 +2143,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, paintImageMaskXObject: function CanvasGraphics_paintImageMaskXObject(img) { + if (!this.contentVisible) { + return; + } var ctx = this.ctx; var width = img.width, height = img.height; @@ -2168,6 +2197,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { scaleY, positions ) { + if (!this.contentVisible) { + return; + } var width = imgData.width; var height = imgData.height; var fillColor = this.current.fillColor; @@ -2212,6 +2244,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { paintImageMaskXObjectGroup: function CanvasGraphics_paintImageMaskXObjectGroup( images ) { + if (!this.contentVisible) { + return; + } var ctx = this.ctx; var fillColor = this.current.fillColor; @@ -2249,6 +2284,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, paintImageXObject: function CanvasGraphics_paintImageXObject(objId) { + if (!this.contentVisible) { + return; + } const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId); @@ -2266,6 +2304,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { scaleY, positions ) { + if (!this.contentVisible) { + return; + } const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId); @@ -2292,6 +2333,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { paintInlineImageXObject: function CanvasGraphics_paintInlineImageXObject( imgData ) { + if (!this.contentVisible) { + return; + } var width = imgData.width; var height = imgData.height; var ctx = this.ctx; @@ -2394,6 +2438,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { imgData, map ) { + if (!this.contentVisible) { + return; + } var ctx = this.ctx; var w = imgData.width; var h = imgData.height; @@ -2433,6 +2480,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, paintSolidColorImageMask: function CanvasGraphics_paintSolidColorImageMask() { + if (!this.contentVisible) { + return; + } this.ctx.fillRect(0, 0, 1, 1); }, @@ -2445,16 +2495,28 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { // TODO Marked content. }, beginMarkedContent: function CanvasGraphics_beginMarkedContent(tag) { - // TODO Marked content. + this.markedContentStack.push({ + visible: true, + }); }, beginMarkedContentProps: function CanvasGraphics_beginMarkedContentProps( tag, properties ) { - // TODO Marked content. + if (tag === "OC") { + this.markedContentStack.push({ + visible: this.optionalContentConfig.isVisible(properties), + }); + } else { + this.markedContentStack.push({ + visible: true, + }); + } + this.contentVisible = this.isContentVisible(); }, endMarkedContent: function CanvasGraphics_endMarkedContent() { - // TODO Marked content. + this.markedContentStack.pop(); + this.contentVisible = this.isContentVisible(); }, // Compatibility @@ -2500,6 +2562,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { transform[1] * x + transform[3] * y + transform[5], ]; }, + + isContentVisible: function CanvasGraphics_isContentVisible() { + for (let i = this.markedContentStack.length - 1; i >= 0; i--) { + if (!this.markedContentStack[i].visible) { + return false; + } + } + return true; + }, }; for (var op in OPS) { diff --git a/src/display/optional_content_config.js b/src/display/optional_content_config.js new file mode 100644 index 000000000..16308623d --- /dev/null +++ b/src/display/optional_content_config.js @@ -0,0 +1,125 @@ +/* Copyright 2020 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { warn } from "../shared/util.js"; + +class OptionalContentGroup { + constructor(name, intent) { + this.visible = true; + this.name = name; + this.intent = intent; + } +} + +class OptionalContentConfig { + constructor(data) { + this.name = null; + this.creator = null; + this.groups = new Map(); + + if (data === null) { + return; + } + this.name = data.name; + this.creator = data.creator; + for (const group of data.groups) { + this.groups.set( + group.id, + new OptionalContentGroup(group.name, group.intent) + ); + } + + if (data.baseState === "OFF") { + for (const group of this.groups) { + group.visible = false; + } + } + + for (const on of data.on) { + this.groups.get(on).visible = true; + } + + for (const off of data.off) { + this.groups.get(off).visible = false; + } + } + + isVisible(group) { + if (group.type === "OCG") { + if (!this.groups.has(group.id)) { + warn(`Optional content group not found: ${group.id}`); + return true; + } + return this.groups.get(group.id).visible; + } else if (group.type === "OCMD") { + // Per the spec, the expression should be preferred if available. Until + // we implement this, just fallback to using the group policy for now. + if (group.expression) { + warn("Visibility expression not supported yet."); + } + if (!group.policy || group.policy === "AnyOn") { + // Default + for (const id of group.ids) { + if (!this.groups.has(id)) { + warn(`Optional content group not found: ${id}`); + return true; + } + if (this.groups.get(id).visible) { + return true; + } + } + return false; + } else if (group.policy === "AllOn") { + for (const id of group.ids) { + if (!this.groups.has(id)) { + warn(`Optional content group not found: ${id}`); + return true; + } + if (!this.groups.get(id).visible) { + return false; + } + } + return true; + } else if (group.policy === "AnyOff") { + for (const id of group.ids) { + if (!this.groups.has(id)) { + warn(`Optional content group not found: ${id}`); + return true; + } + if (!this.groups.get(id).visible) { + return true; + } + } + return false; + } else if (group.policy === "AllOff") { + for (const id of group.ids) { + if (!this.groups.has(id)) { + warn(`Optional content group not found: ${id}`); + return true; + } + if (this.groups.get(id).visible) { + return false; + } + } + return true; + } + warn(`Unknown optional content policy ${group.policy}.`); + return true; + } + warn(`Unknown group type ${group.type}.`); + return true; + } +} + +export { OptionalContentConfig }; diff --git a/src/shared/util.js b/src/shared/util.js index 525f40461..159f43810 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -302,6 +302,7 @@ const UNSUPPORTED_FEATURES = { errorFontToUnicode: "errorFontToUnicode", errorFontLoadNative: "errorFontLoadNative", errorFontGetPath: "errorFontGetPath", + errorMarkedContent: "errorMarkedContent", }; const PasswordResponses = { diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 44c50058f..085de126c 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -52,6 +52,7 @@ !issue7835.pdf !issue11922_reduced.pdf !issue7855.pdf +!issue11144_reduced.pdf !issue7872.pdf !issue7901.pdf !issue8061.pdf @@ -296,6 +297,7 @@ !issue3371.pdf !issue2956.pdf !issue2537r.pdf +!issue269_1.pdf !bug946506.pdf !issue3885.pdf !issue11697_reduced.pdf @@ -331,6 +333,7 @@ !issue5481.pdf !issue5567.pdf !issue5701.pdf +!issue12007_reduced.pdf !issue5896.pdf !issue6010_1.pdf !issue6010_2.pdf @@ -352,6 +355,7 @@ !issue9278.pdf !annotation-text-without-popup.pdf !annotation-underline.pdf +!issue269_2.pdf !annotation-strikeout.pdf !annotation-squiggly.pdf !annotation-highlight.pdf diff --git a/test/pdfs/issue11144_reduced.pdf b/test/pdfs/issue11144_reduced.pdf new file mode 100644 index 000000000..190d8fb7b Binary files /dev/null and b/test/pdfs/issue11144_reduced.pdf differ diff --git a/test/pdfs/issue12007_reduced.pdf b/test/pdfs/issue12007_reduced.pdf new file mode 100644 index 000000000..30bec9eb8 Binary files /dev/null and b/test/pdfs/issue12007_reduced.pdf differ diff --git a/test/pdfs/issue269_1.pdf b/test/pdfs/issue269_1.pdf new file mode 100644 index 000000000..3e7e6bd8d --- /dev/null +++ b/test/pdfs/issue269_1.pdf @@ -0,0 +1,676 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[6 0 R 7 0 R 5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + layers + + + 2018-02-08T18:55:56+04:00 + 2018-02-08T18:55:56+04:00 + 2018-02-08T18:55:56+05:00 + Adobe Illustrator CC 2015 (Windows) + + + + 256 + 228 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA5AEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq+ dP8AnJr83tc0jUIfJ/l+6exdoRPql5CeMpEtfThRx8SfCOTEbmoFetVIfNMOoX8N4L6G5ljvVb1F ukdllD/zBweVfeuKX2b/AM46fmBqvnDyRJ+mJTcanpU/1WW6b7UsZQPG7nu25UnvSp64sS9UxV2K uxV2KuxV2KuxV2KuxV2KrZJI442kkYJGgLO7GgAG5JJ6AYqw/Vvzj/LDSpDHd+YrQuv2lty1yR7H 6usuXx0uSXKJRaT/APQxn5R/WPS/TD8KV9f6pdcOnSnp8/8Ahcs/I5e77QvEE10z86fyt1KRY7bz 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 96Kbf33qfv8A/g80mfxL9dswzLMdLsVdir//2Q== + + + + uuid:a7f1ebfc-5070-47c6-a747-619e6c3897e3 + xmp.did:53400e61-c1c0-9e4b-9d2c-6de0047fdca4 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + uuid:d1c078a0-2746-42b2-b0d1-25aedff8fb1e + xmp.did:1b6690ed-28a8-c141-9479-b6a9cf6be651 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:53400e61-c1c0-9e4b-9d2c-6de0047fdca4 + 2018-02-08T18:55:29+04:00 + Adobe Illustrator CC 2015 (Windows) + / + + + + Print + False + False + 1 + + 100.000000 + 100.000000 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 0.000000 + + + Black + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + CMYK Red + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + CMYK Yellow + CMYK + PROCESS + 0.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Green + CMYK + PROCESS + 100.000000 + 0.000000 + 100.000000 + 0.000000 + + + CMYK Cyan + CMYK + PROCESS + 100.000000 + 0.000000 + 0.000000 + 0.000000 + + + CMYK Blue + CMYK + PROCESS + 100.000000 + 100.000000 + 0.000000 + 0.000000 + + + CMYK Magenta + CMYK + PROCESS + 0.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=15 M=100 Y=90 K=10 + CMYK + PROCESS + 15.000000 + 100.000000 + 90.000000 + 10.000000 + + + C=0 M=90 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 90.000000 + 85.000000 + 0.000000 + + + C=0 M=80 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 80.000000 + 95.000000 + 0.000000 + + + C=0 M=50 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 50.000000 + 100.000000 + 0.000000 + + + C=0 M=35 Y=85 K=0 + CMYK + PROCESS + 0.000000 + 35.000000 + 85.000000 + 0.000000 + + + C=5 M=0 Y=90 K=0 + CMYK + PROCESS + 5.000000 + 0.000000 + 90.000000 + 0.000000 + + + C=20 M=0 Y=100 K=0 + CMYK + PROCESS + 20.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=50 M=0 Y=100 K=0 + CMYK + PROCESS + 50.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=75 M=0 Y=100 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 100.000000 + 0.000000 + + + C=85 M=10 Y=100 K=10 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 10.000000 + + + C=90 M=30 Y=95 K=30 + CMYK + PROCESS + 90.000000 + 30.000000 + 95.000000 + 30.000000 + + + C=75 M=0 Y=75 K=0 + CMYK + PROCESS + 75.000000 + 0.000000 + 75.000000 + 0.000000 + + + C=80 M=10 Y=45 K=0 + CMYK + PROCESS + 80.000000 + 10.000000 + 45.000000 + 0.000000 + + + C=70 M=15 Y=0 K=0 + CMYK + PROCESS + 70.000000 + 15.000000 + 0.000000 + 0.000000 + + + C=85 M=50 Y=0 K=0 + CMYK + PROCESS + 85.000000 + 50.000000 + 0.000000 + 0.000000 + + + C=100 M=95 Y=5 K=0 + CMYK + PROCESS + 100.000000 + 95.000000 + 5.000000 + 0.000000 + + + C=100 M=100 Y=25 K=25 + CMYK + PROCESS + 100.000000 + 100.000000 + 25.000000 + 25.000000 + + + C=75 M=100 Y=0 K=0 + CMYK + PROCESS + 75.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=50 M=100 Y=0 K=0 + CMYK + PROCESS + 50.000000 + 100.000000 + 0.000000 + 0.000000 + + + C=35 M=100 Y=35 K=10 + CMYK + PROCESS + 35.000000 + 100.000000 + 35.000000 + 10.000000 + + + C=10 M=100 Y=50 K=0 + CMYK + PROCESS + 10.000000 + 100.000000 + 50.000000 + 0.000000 + + + C=0 M=95 Y=20 K=0 + CMYK + PROCESS + 0.000000 + 95.000000 + 20.000000 + 0.000000 + + + C=25 M=25 Y=40 K=0 + CMYK + PROCESS + 25.000000 + 25.000000 + 40.000000 + 0.000000 + + + C=40 M=45 Y=50 K=5 + CMYK + PROCESS + 40.000000 + 45.000000 + 50.000000 + 5.000000 + + + C=50 M=50 Y=60 K=25 + CMYK + PROCESS + 50.000000 + 50.000000 + 60.000000 + 25.000000 + + + C=55 M=60 Y=65 K=40 + CMYK + PROCESS + 55.000000 + 60.000000 + 65.000000 + 40.000000 + + + C=25 M=40 Y=65 K=0 + CMYK + PROCESS + 25.000000 + 40.000000 + 65.000000 + 0.000000 + + + C=30 M=50 Y=75 K=10 + CMYK + PROCESS + 30.000000 + 50.000000 + 75.000000 + 10.000000 + + + C=35 M=60 Y=80 K=25 + CMYK + PROCESS + 35.000000 + 60.000000 + 80.000000 + 25.000000 + + + C=40 M=65 Y=90 K=35 + CMYK + PROCESS + 40.000000 + 65.000000 + 90.000000 + 35.000000 + + + C=40 M=70 Y=100 K=50 + CMYK + PROCESS + 40.000000 + 70.000000 + 100.000000 + 50.000000 + + + C=50 M=70 Y=80 K=70 + CMYK + PROCESS + 50.000000 + 70.000000 + 80.000000 + 70.000000 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + C=0 M=0 Y=0 K=90 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 89.999400 + + + C=0 M=0 Y=0 K=80 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 79.998800 + + + C=0 M=0 Y=0 K=70 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 69.999700 + + + C=0 M=0 Y=0 K=60 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 59.999100 + + + C=0 M=0 Y=0 K=50 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 50.000000 + + + C=0 M=0 Y=0 K=40 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 39.999400 + + + C=0 M=0 Y=0 K=30 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 29.998800 + + + C=0 M=0 Y=0 K=20 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 19.999700 + + + C=0 M=0 Y=0 K=10 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 9.999100 + + + C=0 M=0 Y=0 K=5 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 4.998800 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + C=0 M=75 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 75.000000 + 100.000000 + 0.000000 + + + C=0 M=10 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 10.000000 + 95.000000 + 0.000000 + + + C=85 M=10 Y=100 K=0 + CMYK + PROCESS + 85.000000 + 10.000000 + 100.000000 + 0.000000 + + + C=100 M=90 Y=0 K=0 + CMYK + PROCESS + 100.000000 + 90.000000 + 0.000000 + 0.000000 + + + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000000 + 90.000000 + 0.003100 + 0.003100 + + + + + + + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 3 0 obj <> endobj 9 0 obj <>/Properties<>>>/TrimBox[0.0 0.0 100.0 100.0]/Type/Page>> endobj 10 0 obj <>stream +HMn7s +^`(v9,r$W=zs 0,d觟~/GIV~kc_J vޭ4Vn->u$ϫd=cd#&Vf +t%:b59GKQ7幮jn2r8[1f\@-6j@y;~?^+{+("^֤HUUYiR{ZT!j{WSFـd ;WyqJK[C?~DBOJg6ZJw-M- XטbrV:@6~\ytܽ_99wCx{(r네ݑ‰R(9!` [$^2V5CMրyQ!XCCQ#sY*iYkS53Rܬ\ +p|8_a&Lֻrl McXTEj058*y y0X䔵-Rᲅ.)#զ:W6֫ȵ$L6)90Q8L׋5lUS%׮;b5BkFW-ȵ{kO= ΌIEm^9Ni'Pv'ȅ,WQkԲ )tP`q,Q @5 +ԨZZ :$.IHlel[Ÿ́V*ehy\[8pF~4L0 A5{3 r傑Byd@ W0:.8@eЃcL55"23Tӹ~&\s7E !;U0z͸ɼtYg<I-K/3TUCX0$4蝎&&h_@m+vHzz:8|(V.oGw,z`qV^NJ'x:|dA;r!ɋ0z + +חCBuX#)> endobj 7 0 obj <> endobj 5 0 obj <> endobj 16 0 obj [/View/Design] endobj 17 0 obj <>>> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 12 0 obj [/View/Design] endobj 13 0 obj <>>> endobj 11 0 obj <> endobj 8 0 obj [5 0 R 7 0 R 6 0 R] endobj 18 0 obj <> endobj xref +0 19 +0000000000 65535 f +0000000016 00000 n +0000000173 00000 n +0000052359 00000 n +0000000000 00000 f +0000054015 00000 n +0000053883 00000 n +0000053949 00000 n +0000054542 00000 n +0000052410 00000 n +0000052682 00000 n +0000054429 00000 n +0000054313 00000 n +0000054344 00000 n +0000054197 00000 n +0000054228 00000 n +0000054081 00000 n +0000054112 00000 n +0000054577 00000 n +trailer +<<44D9B13F946F9D4E9B270DC3856D9C92>]>> +startxref +54764 +%%EOF diff --git a/test/pdfs/issue269_2.pdf b/test/pdfs/issue269_2.pdf new file mode 100644 index 000000000..7f8751559 Binary files /dev/null and b/test/pdfs/issue269_2.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 65c1b19dc..c13f77c34 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -926,6 +926,34 @@ "link": false, "type": "eq" }, + { "id": "issue269_1", + "file": "pdfs/issue269_1.pdf", + "md5": "ab932f697b4d2e2bf700de15a8efea9c", + "rounds": 1, + "type": "eq", + "about": "Optional marked content." + }, + { "id": "issue269_2", + "file": "pdfs/issue269_2.pdf", + "md5": "0f553510850ee17c87fbab3fac564165", + "rounds": 1, + "type": "eq", + "about": "Optional marked content." + }, + { "id": "issue11144_reduced", + "file": "pdfs/issue11144_reduced.pdf", + "md5": "09e3e771ebd6867558074e900adb54b9", + "rounds": 1, + "type": "eq", + "about": "Optional marked content." + }, + { "id": "issue12007_reduced", + "file": "pdfs/issue12007_reduced.pdf", + "md5": "3aa9d8a0c5ff8594245149f9c7379613", + "rounds": 1, + "type": "eq", + "about": "Optional marked content." + }, { "id": "issue10438", "file": "pdfs/issue10438_reduced.pdf", "md5": "bb26f68493e33af17b256a6ffe777a24", diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index cb0dcf9fd..ee66e0c5c 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -1636,8 +1636,8 @@ describe("api", function () { const result1 = loadingTask1.promise.then(pdfDoc => { return pdfDoc.getPage(1).then(pdfPage => { return pdfPage.getOperatorList().then(opList => { - expect(opList.fnArray.length).toEqual(722); - expect(opList.argsArray.length).toEqual(722); + expect(opList.fnArray.length).toBeGreaterThan(100); + expect(opList.argsArray.length).toBeGreaterThan(100); expect(opList.lastChunk).toEqual(true); return loadingTask1.destroy();