diff --git a/src/core/annotation.js b/src/core/annotation.js index d26ddeafb..ca5984576 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -21,11 +21,9 @@ import { AnnotationReplyType, AnnotationType, assert, - bytesToString, escapeString, getModificationDate, isString, - objectSize, OPS, shadow, stringToPDFString, @@ -34,17 +32,9 @@ import { warn, } from "../shared/util.js"; import { Catalog, FileSpec, ObjectLoader } from "./obj.js"; -import { - Dict, - isDict, - isName, - isRef, - isStream, - Name, - RefSet, -} from "./primitives.js"; +import { collectActions, getInheritableProperty } from "./core_utils.js"; +import { Dict, isDict, isName, isRef, isStream, Name } from "./primitives.js"; import { ColorSpace } from "./colorspace.js"; -import { getInheritableProperty } from "./core_utils.js"; import { OperatorList } from "./operator_list.js"; import { StringStream } from "./stream.js"; import { writeDict } from "./writer.js"; @@ -977,7 +967,7 @@ class WidgetAnnotation extends Annotation { data.annotationType = AnnotationType.WIDGET; data.fieldName = this._constructFieldName(dict); - data.actions = this._collectActions(params.xref, dict); + data.actions = collectActions(params.xref, dict, AnnotationActionEventType); const fieldValue = getInheritableProperty({ dict, @@ -1459,78 +1449,6 @@ class WidgetAnnotation extends Annotation { return localResources || Dict.empty; } - _collectJS(entry, xref, list, parents) { - if (!entry) { - return; - } - - let parent = null; - if (isRef(entry)) { - if (parents.has(entry)) { - // If we've already found entry then we've a cycle. - return; - } - parent = entry; - parents.put(parent); - entry = xref.fetch(entry); - } - if (Array.isArray(entry)) { - for (const element of entry) { - this._collectJS(element, xref, list, parents); - } - } else if (entry instanceof Dict) { - if (isName(entry.get("S"), "JavaScript") && entry.has("JS")) { - const js = entry.get("JS"); - let code; - if (isStream(js)) { - code = bytesToString(js.getBytes()); - } else { - code = js; - } - code = stringToPDFString(code); - if (code) { - list.push(code); - } - } - this._collectJS(entry.getRaw("Next"), xref, list, parents); - } - - if (parent) { - parents.remove(parent); - } - } - - _collectActions(xref, dict) { - const actions = Object.create(null); - if (dict.has("AA")) { - const additionalActions = dict.get("AA"); - for (const key of additionalActions.getKeys()) { - const action = AnnotationActionEventType[key]; - if (!action) { - continue; - } - const actionDict = additionalActions.getRaw(key); - const parents = new RefSet(); - const list = []; - this._collectJS(actionDict, xref, list, parents); - if (list.length > 0) { - actions[action] = list; - } - } - } - // Collect the Action if any (we may have one on pushbutton). - if (dict.has("A")) { - const actionDict = dict.get("A"); - const parents = new RefSet(); - const list = []; - this._collectJS(actionDict, xref, list, parents); - if (list.length > 0) { - actions.Action = list; - } - } - return objectSize(actions) > 0 ? actions : null; - } - getFieldObject() { if (this.data.fieldType === "Sig") { return { diff --git a/src/core/core_utils.js b/src/core/core_utils.js index 609ef9f6e..d9f8c050a 100644 --- a/src/core/core_utils.js +++ b/src/core/core_utils.js @@ -13,7 +13,15 @@ * limitations under the License. */ -import { assert, BaseException, warn } from "../shared/util.js"; +import { + assert, + BaseException, + bytesToString, + objectSize, + stringToPDFString, + warn, +} from "../shared/util.js"; +import { Dict, isName, isRef, isStream, RefSet } from "./primitives.js"; function getLookupTableFactory(initializer) { let lookup; @@ -240,7 +248,80 @@ function escapePDFName(str) { return buffer.join(""); } +function _collectJS(entry, xref, list, parents) { + if (!entry) { + return; + } + + let parent = null; + if (isRef(entry)) { + if (parents.has(entry)) { + // If we've already found entry then we've a cycle. + return; + } + parent = entry; + parents.put(parent); + entry = xref.fetch(entry); + } + if (Array.isArray(entry)) { + for (const element of entry) { + _collectJS(element, xref, list, parents); + } + } else if (entry instanceof Dict) { + if (isName(entry.get("S"), "JavaScript") && entry.has("JS")) { + const js = entry.get("JS"); + let code; + if (isStream(js)) { + code = bytesToString(js.getBytes()); + } else { + code = js; + } + code = stringToPDFString(code); + if (code) { + list.push(code); + } + } + _collectJS(entry.getRaw("Next"), xref, list, parents); + } + + if (parent) { + parents.remove(parent); + } +} + +function collectActions(xref, dict, eventType) { + const actions = Object.create(null); + if (dict.has("AA")) { + const additionalActions = dict.get("AA"); + for (const key of additionalActions.getKeys()) { + const action = eventType[key]; + if (!action) { + continue; + } + const actionDict = additionalActions.getRaw(key); + const parents = new RefSet(); + const list = []; + _collectJS(actionDict, xref, list, parents); + if (list.length > 0) { + actions[action] = list; + } + } + } + // Collect the Action if any (we may have one on pushbutton). + if (dict.has("A")) { + const actionDict = dict.get("A"); + const parents = new RefSet(); + const list = []; + _collectJS(actionDict, xref, list, parents); + if (list.length > 0) { + actions.Action = list; + } + } + return objectSize(actions) > 0 ? actions : null; +} + export { + collectActions, escapePDFName, getLookupTableFactory, getArrayLookupTableFactory, diff --git a/src/core/document.js b/src/core/document.js index e80a616ef..57167a894 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -24,6 +24,7 @@ import { isNum, isString, OPS, + PageActionEventType, shadow, stringToBytes, stringToPDFString, @@ -42,6 +43,7 @@ import { Ref, } from "./primitives.js"; import { + collectActions, getInheritableProperty, isWhiteSpace, MissingDataException, @@ -467,6 +469,16 @@ class Page { return shadow(this, "_parsedAnnotations", parsedAnnotations); } + + get jsActions() { + const actions = collectActions( + this.xref, + this.pageDict, + PageActionEventType + ); + + return shadow(this, "jsActions", actions); + } } const PDF_HEADER_SIGNATURE = new Uint8Array([0x25, 0x50, 0x44, 0x46, 0x2d]); diff --git a/src/core/obj.js b/src/core/obj.js index 66af45c95..9bb792501 100644 --- a/src/core/obj.js +++ b/src/core/obj.js @@ -19,6 +19,7 @@ import { bytesToString, createPromiseCapability, createValidAbsoluteUrl, + DocumentActionEventType, FormatError, info, InvalidPDFException, @@ -47,13 +48,14 @@ import { RefSet, RefSetCache, } from "./primitives.js"; -import { Lexer, Parser } from "./parser.js"; import { + collectActions, MissingDataException, toRomanNumerals, XRefEntryException, XRefParseException, } from "./core_utils.js"; +import { Lexer, Parser } from "./parser.js"; import { CipherTransformFactory } from "./crypto.js"; import { ColorSpace } from "./colorspace.js"; import { GlobalImageCache } from "./image_utils.js"; @@ -873,11 +875,11 @@ class Catalog { return shadow(this, "attachments", attachments); } - get javaScript() { + _collectJavaScript() { const obj = this._catDict.get("Names"); let javaScript = null; - function appendIfJavaScriptDict(jsDict) { + function appendIfJavaScriptDict(name, jsDict) { const type = jsDict.get("S"); if (!isName(type, "JavaScript")) { return; @@ -890,10 +892,10 @@ class Catalog { return; } - if (!javaScript) { - javaScript = []; + if (javaScript === null) { + javaScript = Object.create(null); } - javaScript.push(stringToPDFString(js)); + javaScript[name] = stringToPDFString(js); } if (obj && obj.has("JavaScript")) { @@ -904,7 +906,7 @@ class Catalog { // defensive so we don't cause errors on document load. const jsDict = names[name]; if (isDict(jsDict)) { - appendIfJavaScriptDict(jsDict); + appendIfJavaScriptDict(name, jsDict); } } } @@ -912,10 +914,43 @@ class Catalog { // Append OpenAction "JavaScript" actions to the JavaScript array. const openAction = this._catDict.get("OpenAction"); if (isDict(openAction) && isName(openAction.get("S"), "JavaScript")) { - appendIfJavaScriptDict(openAction); + appendIfJavaScriptDict("OpenAction", openAction); } - return shadow(this, "javaScript", javaScript); + return javaScript; + } + + get javaScript() { + const javaScript = this._collectJavaScript(); + return shadow( + this, + "javaScript", + javaScript ? Object.values(javaScript) : null + ); + } + + get jsActions() { + const js = this._collectJavaScript(); + let actions = collectActions( + this.xref, + this._catDict, + DocumentActionEventType + ); + + if (!actions && js) { + actions = Object.create(null); + } + if (actions && js) { + for (const [key, val] of Object.entries(js)) { + if (key in actions) { + actions[key].push(val); + } else { + actions[key] = [val]; + } + } + } + + return shadow(this, "jsActions", actions); } fontFallback(id, handler) { diff --git a/src/core/worker.js b/src/core/worker.js index a45c0d46b..9c8241f70 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -481,6 +481,16 @@ class WorkerMessageHandler { return pdfManager.ensureCatalog("javaScript"); }); + handler.on("GetDocJSActions", function wphSetupGetDocJSActions(data) { + return pdfManager.ensureCatalog("jsActions"); + }); + + handler.on("GetPageJSActions", function ({ pageIndex }) { + return pdfManager.getPage(pageIndex).then(function (page) { + return page.jsActions; + }); + }); + handler.on("GetOutline", function wphSetupGetOutline(data) { return pdfManager.ensureCatalog("documentOutline"); }); diff --git a/src/display/api.js b/src/display/api.js index bc914119d..ba5dd87cf 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -753,6 +753,17 @@ class PDFDocumentProxy { return this._transport.getJavaScript(); } + /** + * @returns {Promise} A promise that is resolved with + * an {Object} with the JavaScript actions: + * - from the name tree (like getJavaScript); + * - from A or AA entries in the catalog dictionary. + * , or `null` if no JavaScript exists. + */ + getJSActions() { + return this._transport.getDocJSActions(); + } + /** * @typedef {Object} OutlineNode * @property {string} title @@ -1124,6 +1135,20 @@ class PDFPageProxy { return this.annotationsPromise; } + /** + * @param {GetAnnotationsParameters} params - Annotation parameters. + * @returns {Promise>} A promise that is resolved with an + * {Array} of the annotation objects. + */ + getJSActions() { + if (!this._jsActionsPromise) { + this._jsActionsPromise = this._transport.getPageJSActions( + this._pageIndex + ); + } + return this._jsActionsPromise; + } + /** * Begins the process of rendering a page to the desired context. * @@ -1405,6 +1430,7 @@ class PDFPageProxy { } this.objs.clear(); this.annotationsPromise = null; + this._jsActionsPromise = null; this.pendingCleanup = false; return Promise.all(waitOn); } @@ -1438,6 +1464,7 @@ class PDFPageProxy { this._intentStates.clear(); this.objs.clear(); this.annotationsPromise = null; + this._jsActionsPromise = null; if (resetStats && this._stats) { this._stats = new StatTimer(); } @@ -2631,6 +2658,16 @@ class WorkerTransport { return this.messageHandler.sendWithPromise("GetJavaScript", null); } + getDocJSActions() { + return this.messageHandler.sendWithPromise("GetDocJSActions", null); + } + + getPageJSActions(pageIndex) { + return this.messageHandler.sendWithPromise("GetPageJSActions", { + pageIndex, + }); + } + getOutline() { return this.messageHandler.sendWithPromise("GetOutline", null); } diff --git a/src/scripting_api/common.js b/src/scripting_api/common.js new file mode 100644 index 000000000..901859f9e --- /dev/null +++ b/src/scripting_api/common.js @@ -0,0 +1,26 @@ +/* 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. + */ + +function createActionsMap(actions) { + const actionsMap = new Map(); + if (actions) { + for (const [eventType, actionsForEvent] of Object.entries(actions)) { + actionsMap.set(eventType, actionsForEvent); + } + } + return actionsMap; +} + +export { createActionsMap }; diff --git a/src/scripting_api/doc.js b/src/scripting_api/doc.js index 864295532..e7a10a13d 100644 --- a/src/scripting_api/doc.js +++ b/src/scripting_api/doc.js @@ -13,6 +13,7 @@ * limitations under the License. */ +import { createActionsMap } from "./common.js"; import { PDFObject } from "./pdf_object.js"; import { PrintParams } from "./print_params.js"; import { ZoomType } from "./constants.js"; @@ -88,6 +89,48 @@ class Doc extends PDFObject { this._zoomType = ZoomType.none; this._zoom = data.zoom || 100; + this._actions = createActionsMap(data.actions); + this._globalEval = data.globalEval; + } + + _dispatchDocEvent(name) { + if (name === "Open") { + const dontRun = new Set([ + "WillClose", + "WillSave", + "DidSave", + "WillPrint", + "DidPrint", + "OpenAction", + ]); + for (const actionName of this._actions.keys()) { + if (!dontRun.has(actionName)) { + this._runActions(actionName); + } + } + this._runActions("OpenAction"); + } else { + this._runActions(name); + } + } + + _dispatchPageEvent(name, action, pageNumber) { + if (name === "PageOpen") { + this._pageNum = pageNumber - 1; + } + + this._globalEval(action); + } + + _runActions(name) { + if (!this._actions.has(name)) { + return; + } + + const actions = this._actions.get(name); + for (const action of actions) { + this._globalEval(action); + } } _addField(name, field) { @@ -954,7 +997,7 @@ class Doc extends PDFObject { nEnd = -1; } - this._send({ id: "print", start: nStart, end: nEnd }); + this._send({ command: "print", start: nStart, end: nEnd }); } removeDataObject() { diff --git a/src/scripting_api/event.js b/src/scripting_api/event.js index 67ef096b8..92a248677 100644 --- a/src/scripting_api/event.js +++ b/src/scripting_api/event.js @@ -65,12 +65,28 @@ class EventDispatcher { dispatch(baseEvent) { const id = baseEvent.id; if (!(id in this._objects)) { + let event; + if (id === "doc" || id === "page") { + event = globalThis.event = new Event(baseEvent); + event.source = event.target = this._document.wrapped; + event.name = baseEvent.name; + } + if (id === "doc") { + this._document.obj._dispatchDocEvent(event.name); + } + if (id === "page") { + this._document.obj._dispatchPageEvent( + event.name, + baseEvent.action, + baseEvent.pageNumber + ); + } return; } const name = baseEvent.name.replace(" ", ""); const source = this._objects[id]; - globalThis.event = new Event(baseEvent); + const event = (globalThis.event = new Event(baseEvent)); let savedChange; if (source.obj._isButton()) { @@ -156,7 +172,7 @@ class EventDispatcher { const first = this._calculationOrder[0]; const source = this._objects[first]; globalThis.event = new Event({}); - this.runCalculate(source, event); + this.runCalculate(source, globalThis.event); } runCalculate(source, event) { diff --git a/src/scripting_api/field.js b/src/scripting_api/field.js index 46f100a2f..bd5a6e6bf 100644 --- a/src/scripting_api/field.js +++ b/src/scripting_api/field.js @@ -14,6 +14,7 @@ */ import { Color } from "./color.js"; +import { createActionsMap } from "./common.js"; import { PDFObject } from "./pdf_object.js"; class Field extends PDFObject { @@ -72,7 +73,7 @@ class Field extends PDFObject { // Private this._document = data.doc; - this._actions = this._createActionsMap(data.actions); + this._actions = createActionsMap(data.actions); this._fillColor = data.fillColor || ["T"]; this._strokeColor = data.strokeColor || ["G", 0]; @@ -133,16 +134,6 @@ class Field extends PDFObject { this._send({ id: this._id, focus: true }); } - _createActionsMap(actions) { - const actionsMap = new Map(); - if (actions) { - for (const [eventType, actionsForEvent] of Object.entries(actions)) { - actionsMap.set(eventType, actionsForEvent); - } - } - return actionsMap; - } - _isButton() { return false; } diff --git a/src/scripting_api/initialization.js b/src/scripting_api/initialization.js index 3be859a18..0ad80ab61 100644 --- a/src/scripting_api/initialization.js +++ b/src/scripting_api/initialization.js @@ -51,6 +51,7 @@ function initSandbox(params) { const { data } = params; const doc = new Doc({ send, + globalEval, ...data.docInfo, }); const _document = { obj: doc, wrapped: new Proxy(doc, proxyHandler) }; @@ -67,16 +68,17 @@ function initSandbox(params) { const util = new Util({ externalCall }); const aform = new AForm(doc, app, util); - for (const [name, objs] of Object.entries(data.objects)) { - const obj = objs[0]; - obj.send = send; - obj.globalEval = globalEval; - obj.doc = _document.wrapped; - obj.globalEval = globalEval; - const field = new Field(obj); - const wrapped = new Proxy(field, proxyHandler); - doc._addField(name, wrapped); - app._objects[obj.id] = { obj: field, wrapped }; + if (data.objects) { + for (const [name, objs] of Object.entries(data.objects)) { + const obj = objs[0]; + obj.send = send; + obj.globalEval = globalEval; + obj.doc = _document.wrapped; + const field = new Field(obj); + const wrapped = new Proxy(field, proxyHandler); + doc._addField(name, wrapped); + app._objects[obj.id] = { obj: field, wrapped }; + } } globalThis.event = null; diff --git a/src/shared/util.js b/src/shared/util.js index f5416e18f..77dddfb9c 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -159,6 +159,9 @@ const AnnotationActionEventType = { F: "Format", V: "Validate", C: "Calculate", +}; + +const DocumentActionEventType = { WC: "WillClose", WS: "WillSave", DS: "DidSave", @@ -166,6 +169,11 @@ const AnnotationActionEventType = { DP: "DidPrint", }; +const PageActionEventType = { + O: "PageOpen", + C: "PageClose", +}; + const StreamType = { UNKNOWN: "UNKNOWN", FLATE: "FLATE", @@ -1011,9 +1019,11 @@ export { FontType, ImageKind, CMapCompressionType, + DocumentActionEventType, AbortException, InvalidPDFException, MissingPDFException, + PageActionEventType, PasswordException, PasswordResponses, PermissionFlag, diff --git a/test/integration/scripting_spec.js b/test/integration/scripting_spec.js index 2760517ae..bde715249 100644 --- a/test/integration/scripting_spec.js +++ b/test/integration/scripting_spec.js @@ -27,6 +27,20 @@ describe("Interaction", () => { await closePages(pages); }); + it("must check that first text field has focus", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + // The document has an open action in order to give + // the focus to 401R. + await page.waitForTimeout(1000); + const id = await page.evaluate( + () => window.document.activeElement.id + ); + expect(id).withContext(`In ${browserName}`).toEqual("401R"); + }) + ); + }); + it("must show a text field and then make in invisible when content is removed", async () => { await Promise.all( pages.map(async ([browserName, page]) => { diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index e4fca428a..e85847cd2 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -178,6 +178,7 @@ !pattern_text_embedded_font.pdf !devicen.pdf !cmykjpeg.pdf +!docactions.pdf !issue840.pdf !160F-2019.pdf !issue4402_reduced.pdf diff --git a/test/pdfs/docactions.pdf b/test/pdfs/docactions.pdf new file mode 100644 index 000000000..56381f322 --- /dev/null +++ b/test/pdfs/docactions.pdf @@ -0,0 +1,426 @@ +%PDF-1.5 +% +1 0 obj +<< /Type /ObjStm /Length 9839 /N 70 /First 545 >> +stream +2 0 3 33 4 227 5 301 6 1602 7 1672 8 1755 9 1808 10 1936 11 1990 12 2115 13 2169 14 2464 15 2517 16 2561 17 2606 18 2730 19 2824 20 2877 21 3110 22 3155 23 3208 24 3441 25 3486 26 3539 27 3772 28 3817 29 3870 30 4103 31 4148 32 4201 33 4434 34 4479 35 4532 36 4765 37 4810 38 4905 39 4958 40 5191 41 5236 42 5289 43 5522 44 5567 45 5620 46 5855 47 5900 48 5953 49 6188 50 6233 51 6286 52 6521 53 6566 54 6599 55 6652 56 6887 57 6932 58 6992 59 7107 60 7703 61 7927 62 7935 63 8215 64 8430 65 8632 66 8692 67 8846 68 8989 69 9068 70 9138 71 9177 +<< /D [ 3 0 R /Fit ] /S /GoTo >> +<< /AA << /O << /JS (console.println\('Open the document'\); ) /S /JavaScript >> >> /Annots [ 13 0 R ] /Contents 73 0 R /MediaBox [ 0 0 612 792 ] /Parent 18 0 R /Resources 14 0 R /Type /Page >> +<< /JS (console.println('Open Action');) /S /JavaScript >> +<< /Differences [ 24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde 39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright /minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot /.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine 188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ] /Type /Encoding >> +<< /BaseFont /ZapfDingbats /Name /ZaDb /Subtype /Type1 /Type /Font >> +<< /BaseFont /Helvetica /Encoding 5 0 R /Name /Helv /Subtype /Type1 /Type /Font >> +<< /Font << /F30 9 0 R >> /ProcSet [ /PDF /Text ] >> +<< /BaseFont /GCRMMP+Dingbats /FirstChar 123 /FontDescriptor 64 0 R /LastChar 123 /Subtype /Type1 /Type /Font /Widths 61 0 R >> +<< /Font << /F31 11 0 R >> /ProcSet [ /PDF /Text ] >> +<< /BaseFont /XYLNGW+CMSS10 /FirstChar 80 /FontDescriptor 63 0 R /LastChar 117 /Subtype /Type1 /Type /Font /Widths 60 0 R >> +<< /Font << /F31 11 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /F << /JS (console.println\('text entered='+event.value\);) /S /JavaScript >> >> /BS << /S /S /W 1 >> /DA (/Helv 10 Tf 0 0 0 rg) /DV () /F 4 /FT /Tx /MK << /BC [ 1 0 0 ] /BG [ 1 1 1 ] >> /Q 0 /Rect [ 184.744 652.309 271.776 668.194 ] /Subtype /Widget /T (field1) /Type /Annot /V () >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /D [ 3 0 R /XYZ 105.869 705.06 null ] >> +<< /D [ 3 0 R /XYZ 106.869 667.198 null ] >> +<< /BaseFont /CFMZGO+CMR10 /FirstChar 12 /FontDescriptor 62 0 R /LastChar 121 /Subtype /Type1 /Type /Font /Widths 59 0 R >> +<< /Count 6 /Kids [ 3 0 R 20 0 R 23 0 R 26 0 R 29 0 R 32 0 R ] /Parent 65 0 R /Type /Pages >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 2'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 2'\);) /S /JavaScript >> >> /Contents 74 0 R /MediaBox [ 0 0 612 792 ] /Parent 18 0 R /Resources 19 0 R /Type /Page >> +<< /D [ 20 0 R /XYZ 159.667 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 3'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 3'\);) /S /JavaScript >> >> /Contents 75 0 R /MediaBox [ 0 0 612 792 ] /Parent 18 0 R /Resources 22 0 R /Type /Page >> +<< /D [ 23 0 R /XYZ 105.869 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 4'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 4'\);) /S /JavaScript >> >> /Contents 76 0 R /MediaBox [ 0 0 612 792 ] /Parent 18 0 R /Resources 25 0 R /Type /Page >> +<< /D [ 26 0 R /XYZ 159.667 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 5'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 5'\);) /S /JavaScript >> >> /Contents 77 0 R /MediaBox [ 0 0 612 792 ] /Parent 18 0 R /Resources 28 0 R /Type /Page >> +<< /D [ 29 0 R /XYZ 105.869 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 6'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 6'\);) /S /JavaScript >> >> /Contents 78 0 R /MediaBox [ 0 0 612 792 ] /Parent 18 0 R /Resources 31 0 R /Type /Page >> +<< /D [ 32 0 R /XYZ 159.667 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 7'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 7'\);) /S /JavaScript >> >> /Contents 79 0 R /MediaBox [ 0 0 612 792 ] /Parent 37 0 R /Resources 34 0 R /Type /Page >> +<< /D [ 35 0 R /XYZ 105.869 705.06 null ] >> +<< /Count 6 /Kids [ 35 0 R 39 0 R 42 0 R 45 0 R 48 0 R 51 0 R ] /Parent 65 0 R /Type /Pages >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 8'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 8'\);) /S /JavaScript >> >> /Contents 80 0 R /MediaBox [ 0 0 612 792 ] /Parent 37 0 R /Resources 38 0 R /Type /Page >> +<< /D [ 39 0 R /XYZ 159.667 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 9'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 9'\);) /S /JavaScript >> >> /Contents 81 0 R /MediaBox [ 0 0 612 792 ] /Parent 37 0 R /Resources 41 0 R /Type /Page >> +<< /D [ 42 0 R /XYZ 105.869 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 10'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 10'\);) /S /JavaScript >> >> /Contents 82 0 R /MediaBox [ 0 0 612 792 ] /Parent 37 0 R /Resources 44 0 R /Type /Page >> +<< /D [ 45 0 R /XYZ 159.667 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 11'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 11'\);) /S /JavaScript >> >> /Contents 83 0 R /MediaBox [ 0 0 612 792 ] /Parent 37 0 R /Resources 47 0 R /Type /Page >> +<< /D [ 48 0 R /XYZ 105.869 705.06 null ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 12'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 12'\);) /S /JavaScript >> >> /Contents 84 0 R /MediaBox [ 0 0 612 792 ] /Parent 37 0 R /Resources 50 0 R /Type /Page >> +<< /D [ 51 0 R /XYZ 159.667 705.06 null ] >> +<< /Names [ (Open) 4 0 R ] >> +<< /Font << /F8 17 0 R >> /ProcSet [ /PDF /Text ] >> +<< /AA << /C << /JS (console.println\('Close page 13'\);) /S /JavaScript >> /O << /JS (console.println\('Open page 13'\);) /S /JavaScript >> >> /Contents 85 0 R /MediaBox [ 0 0 612 792 ] /Parent 57 0 R /Resources 54 0 R /Type /Page >> +<< /D [ 55 0 R /XYZ 105.869 705.06 null ] >> +<< /Count 1 /Kids [ 55 0 R ] /Parent 65 0 R /Type /Pages >> +<< /DA (/Helv 10 Tf 0 g) /DR << /Font << /Helv 7 0 R /ZaDb 6 0 R >> >> /Fields [ 13 0 R ] /NeedAppearances true >> +[ 555.6 555.6 833.3 833.3 277.8 305.6 500 500 500 500 500 750 444.4 500 722.2 777.8 500 902.8 1013.9 777.8 277.8 277.8 500 833.3 500 833.3 777.8 277.8 388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 277.8 777.8 472.2 472.2 777.8 750 708.3 722.2 763.9 680.6 652.8 784.7 750 361.1 513.9 777.8 625 916.7 750 777.8 680.6 777.8 736.1 555.6 722.2 750 750 1027.8 750 750 611.1 277.8 500 277.8 500 277.8 277.8 500 555.6 444.4 555.6 444.4 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6 500 555.6 527.8 391.7 394.4 388.9 555.6 527.8 722.2 527.8 527.8 ] +[ 638.9 736.1 645.8 555.6 680.6 687.5 666.7 944.5 666.7 666.7 611.1 288.9 500 288.9 500 277.8 277.8 480.6 516.7 444.4 516.7 444.4 305.6 500 516.7 238.9 266.7 488.9 238.9 794.4 516.7 500 516.7 516.7 341.7 383.3 361.1 516.7 ] +[ 392 ] +<< /Ascent 694 /CapHeight 683 /CharSet (/M/a/colon/d/e/eight/fi/five/four/g/l/nine/one/p/seven/six/t/three/two/x/y/zero) /Descent -194 /Flags 4 /FontBBox [ -40 -250 1009 750 ] /FontFile 86 0 R /FontName /CFMZGO+CMR10 /ItalicAngle 0 /StemV 69 /Type /FontDescriptor /XHeight 431 >> +<< /Ascent 694 /CapHeight 694 /CharSet (/P/S/b/i/m/t/u) /Descent -194 /Flags 4 /FontBBox [ -61 -250 999 759 ] /FontFile 87 0 R /FontName /XYLNGW+CMSS10 /ItalicAngle 0 /StemV 78 /Type /FontDescriptor /XHeight 444 >> +<< /Ascent 708 /CapHeight 708 /CharSet (/a97) /Descent 0 /Flags 4 /FontBBox [ -1 -143 981 819 ] /FontFile 88 0 R /FontName /GCRMMP+Dingbats /ItalicAngle 0 /StemV 0 /Type /FontDescriptor /XHeight 400 >> +<< /Count 13 /Kids [ 18 0 R 37 0 R 57 0 R ] /Type /Pages >> +<< /Limits [ (Doc-Start) (page.13) ] /Names [ (Doc-Start) 16 0 R (page.1) 15 0 R (page.10) 46 0 R (page.11) 49 0 R (page.12) 52 0 R (page.13) 56 0 R ] >> +<< /Limits [ (page.2) (page.7) ] /Names [ (page.2) 21 0 R (page.3) 24 0 R (page.4) 27 0 R (page.5) 30 0 R (page.6) 33 0 R (page.7) 36 0 R ] >> +<< /Limits [ (page.8) (page.9) ] /Names [ (page.8) 40 0 R (page.9) 43 0 R ] >> +<< /Kids [ 66 0 R 67 0 R 68 0 R ] /Limits [ (Doc-Start) (page.9) ] >> +<< /Dests 69 0 R /JavaScript 53 0 R >> +<< /AA << >> /AcroForm 58 0 R /Names 70 0 R /OpenAction 2 0 R /PageMode /UseOutlines /Pages 65 0 R /Type /Catalog >> +endstream +endobj +72 0 obj +<< /Author () /CreationDate (D:20201207183605+01'00') /Creator (LaTeX with hyperref) /Keywords () /ModDate (D:20201207183605+01'00') /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.21 \(TeX Live 2020/Debian\) kpathsea version 6.3.2) /Producer (pdfTeX-1.40.21) /Subject () /Title () /Trapped /False >> +endobj +73 0 obj +<< /Length 100 >> +stream +BT +/F8 9.9626 Tf 121.813 655.243 Td [(My)-333(text)-334(\014eld:)]TJ 154.421 -565.878 Td [(1)]TJ +ET +endstream +endobj +74 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 175.611 657.235 Td [(page)-333(2)]TJ 154.421 -567.87 Td [(2)]TJ +ET +endstream +endobj +75 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 121.813 657.235 Td [(page)-333(3)]TJ 154.421 -567.87 Td [(3)]TJ +ET +endstream +endobj +76 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 175.611 657.235 Td [(page)-333(4)]TJ 154.421 -567.87 Td [(4)]TJ +ET +endstream +endobj +77 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 121.813 657.235 Td [(page)-333(5)]TJ 154.421 -567.87 Td [(5)]TJ +ET +endstream +endobj +78 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 175.611 657.235 Td [(page)-333(6)]TJ 154.421 -567.87 Td [(6)]TJ +ET +endstream +endobj +79 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 121.813 657.235 Td [(page)-333(7)]TJ 154.421 -567.87 Td [(7)]TJ +ET +endstream +endobj +80 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 175.611 657.235 Td [(page)-333(8)]TJ 154.421 -567.87 Td [(8)]TJ +ET +endstream +endobj +81 0 obj +<< /Length 84 >> +stream +BT +/F8 9.9626 Tf 121.813 657.235 Td [(page)-333(9)]TJ 154.421 -567.87 Td [(9)]TJ +ET +endstream +endobj +82 0 obj +<< /Length 86 >> +stream +BT +/F8 9.9626 Tf 175.611 657.235 Td [(page)-333(10)]TJ 151.931 -567.87 Td [(10)]TJ +ET +endstream +endobj +83 0 obj +<< /Length 85 >> +stream +BT +/F8 9.9626 Tf 121.813 657.235 Td [(page)-333(11)]TJ 151.93 -567.87 Td [(11)]TJ +ET +endstream +endobj +84 0 obj +<< /Length 86 >> +stream +BT +/F8 9.9626 Tf 175.611 657.235 Td [(page)-333(12)]TJ 151.931 -567.87 Td [(12)]TJ +ET +endstream +endobj +85 0 obj +<< /Length 85 >> +stream +BT +/F8 9.9626 Tf 121.813 657.235 Td [(page)-333(13)]TJ 151.93 -567.87 Td [(13)]TJ +ET +endstream +endobj +86 0 obj +<< /Length1 1700 /Length2 12121 /Length3 0 /Length 13821 >> +stream +%!PS-AdobeFont-1.0: CMR10 003.002 +%%Title: CMR10 +%Version: 003.002 +%%CreationDate: Mon Jul 13 16:17:00 2009 +%%Creator: David M. Jones +%Copyright: Copyright (c) 1997, 2009 American Mathematical Society +%Copyright: (), with Reserved Font Name CMR10. +% This Font Software is licensed under the SIL Open Font License, Version 1.1. +% This license is in the accompanying file OFL.txt, and is also +% available with a FAQ at: http://scripts.sil.org/OFL. +%%EndComments +FontDirectory/CMR10 known{/CMR10 findfont dup/UniqueID known{dup +/UniqueID get 5000793 eq exch/FontType get 1 eq and}{pop false}ifelse +{save true}{false}ifelse}{false}ifelse +11 dict begin +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def +/FontName /CFMZGO+CMR10 def +/FontBBox {-40 -250 1009 750 }readonly def +/PaintType 0 def +/FontInfo 9 dict dup begin +/version (003.002) readonly def +/Notice (Copyright \050c\051 1997, 2009 American Mathematical Society \050\051, with Reserved Font Name CMR10.) readonly def +/FullName (CMR10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 77 /M put +dup 97 /a put +dup 58 /colon put +dup 100 /d put +dup 101 /e put +dup 56 /eight put +dup 12 /fi put +dup 53 /five put +dup 52 /four put +dup 103 /g put +dup 108 /l put +dup 57 /nine put +dup 49 /one put +dup 112 /p put +dup 55 /seven put +dup 54 /six put +dup 116 /t put +dup 51 /three put +dup 50 /two put +dup 120 /x put +dup 121 /y put +dup 48 /zero put +readonly def +currentdict end +currentfile eexec +oc;jAw-=%W)-{ru)rAE(@{빴Q|_R +ϤA -T@|q|VkJ%qu8PwGxŪ̆Q6K -U\%b"t-*xJ+ +}3{Z2zݬT2s$Z&{BJ{x< ,-.2iRnñvپ1䠕 '䓱_r"O_t3kefBݼVfj9ҳ Yh뀸{q-ɷ}W??gw1*Eh[:tWeI,v8a<{B100Z85|}Nlw]6Nbh3E`(Eޏ'Q;eԃ/.DyL5$4IG׮Ɋ\yj9.VU5Q!-赁B9dB^oVwBɎT7RsOGA b#TBv!mWT=w,ID%'MK<|]D@2O( ݎ%#_ɷVBST#z!${l\4ĸ ;5l&!〚=(fUwAeB#30>H 'L+֓jz@=s\<=\Y$D?U 6xGQnǫi%֔! +L2[)!fXc<'ȲRP3E!-:'AJ.IJCJJt&{76 +#VH/Fgw"F5wS$|oQ<Η `~<10|;,zɴ% +oߠx0sW1Fx gmxVyѝ"]#z~pv Ũ.rB9$nYCC1td@#8kNԋK;ԓlF( ،N;d*<Ʀs9ZQ@It%[)7&hn Y'a¶T'Xrߙ/n_nJL (@ +К +N{KF^kbn~`L]aU{vLܺ41$rmAsnZ*=sob@{y !CC{c.WZ0n bpgsPd$-\ԛ&L27JBs/g(xQ,t>[8͓GsŸ:R$9]6&my)ivjWLRB^RBalx_Y:5M/j١!}`D&WȪQX$HߧtI .Y@nr_n܁ OtAN-L n?_^_g~Ə;`KB6eĶ +>lQp)/;S' ^:tJj@xE(0G;κQqǔkT'; ÃDHjsrxܖ +.>֯kl;&#<ښe)fFz`Ƿ?Ic@SH&<evn8F\V3aA!yy:+c!xbM։/f}3ߖ˦"G'fMsXWU}Yĵ^ %j!HOH͎_;臲Jv]# +$'Ch?5u-G:zHZ\%Uv z^By%NT⸶3=X?mJ-3iH@ܐfσkR.v'm.'SDly7 YCm^Gu5_G1t/ +41n_D>}p+fg9h$]@M`^ҹGK;5wIrqA3fAYiuYrD:dR At -,)aɺh9[ԧuS9KTKaX$wgɓO[xqǃyI(j5LIc}|h$zDUwY+Z:ϤŜ1le`u@|܈贚^6/y`a [Ί`ҾEwa ziLa}jʰ@}xWns0n*{l?Zz>8p-L&ȣK`> `%`ݿs?v˻^\*QNbf+ۼބo" ٧U zgga䎐uFљ<Xyݸ*g4?X2]4H͢^qLeoU~ 7>)ƤHnA7"{DRj)ע~eVDJ|X}ѧCrTA fP};"ӼK#ΑTF\^ԓ ; |R D\Ă Hu6QИ'Q3b;x#3S:jb%tJ/>ʡOrVށx]>)]l5o[F;,N&'i\NQIH?T:@FN SX0<)hW4fFDh.سT)^S-nw}, ZNEC Y Rez3\ +tY5`F~_xU|'XLJG@U6I \>:V_>զ9*I0}ӵ\"{3UzuFf٤Pߨ)E8Uw)gq:dj#hq so -@ +KG7"|QЇ Zzs|}LմS:fmA3S 2=[dؓJ\ܳc|tj1ƛArѮJv,K| ϕVސ +Q[5GnK;9za~%d-vy%i=iJhq=}LGP +*(0V(bDCܶ +HMnUmdm^>v!tx|ZiŽ3vL^ )B.L 4v?8I,.k0-~ )+]ݤ[aR6nҘd ɼγ%>HyHcz%{D||އU!@N +sxJb)(Zb-CYe^ECھx܃87I5ɸ^Lf  ß0Ǽz9v SvO,v@n:ŲC 86"y,u7Ͼ }Ty~.&-ĦI_ JQG[]O ] Γd l*=X$r"ər¸[`r#T;2=!}&SeCBW W+U+wb^ݖr*/do<؛MSRս_&= }gQNC C4 GH5 䏏fG2j ~l&gT [X;_ö/QqDp eeö+F9f)/~R."""/Wf# T+MڔYnޡ}maKN_сG(WQ+KS}~fTtTh@>ƪ;`#75+ӱ. cRn +loV +gQtLLh`i;n9s$<ݳlP%ƅ XjR0RQb+/+uNυ+Z.kAΖf*j}i/b 7_|6 ;^k az.4&+HaÝ+%2W׷޵g /z0RO_W,T_\BQJ$Fa8DNΒ+R2UiiKPN'J[e9bHrMSI=Gy5ZY9X'<ή/fvyZ +ƹ/6 :+uGnd>b+RX;}ھEw}fhm4WM䫄ϊx c7wg*zEL]…9DRMsjw!ƶ ]vHԨxB)jRe</=LaW#T7LrGJb.Mg fIgb[kCCycB:oYzT|Źr* '$R"l & `昇h +j +PgeU$GTVIj֜3~m!m%^zY;`(+*~όPia`_aˢst 4"͓V#Vl/cES3 Bl1WRQ( RWMEߢ/5j[^. \8 EIjMP`NY>@9zT %T:F|fbۜNpqORQc:0"M9~Zn>Xu2VaŭgBZ +?xlcۛ%1\DQx{EGWνmG&^v.׊Hsl, +'hAm;npk&V:z5ǥ (H9ًQ_]CLς/"+n CϣkSfa sVlt«@GJya`mx_1U6T}b2B[|2@ԣ +퐮@˯_ yoLRF( KTO@kH~v`{᲌T*_%ݑ>dx)vȖLϙĪw>Y/1?,.5+[F sBӻh~-)RgC[*fLм&Z;pf^_gxFo!Bu!XW"]ktے_ +b?ݕ^E0|eٙeiz}Jܶ:" PP+}:fN`H٭P +rA~rhhDJV{#"B=b;N}!OT<>Ѩ=M`\uGׁfvjƴ\ }3-U䘤Ai˘;q ;mL5c$\KF8K'u &1i3 c_pJ M&$baTf${&d +p{RQ.ȉM:? S#b [μF*n! r$;:|Dta_IҕŠFܯׄ-g]ιo4aXmwtg>^Q&)FzxRݮe{fcY%DWHf)x5.ψl +a7Vfuwz n hӉ_Y\9}2Z~Iq<藇HA|7.dc z-=53S!ɂidj@4LYm +ͯGLxXUkKu6e.o9 CƅADמRAB>s 1HZQ2+T Ɗ>[$YMSV7iuv@^:,YZյJf!9dSjQu:}^4/鴴XJt u$VE \Ό$%Я +n'C86U}) Jy> +stream +%!PS-AdobeFont-1.0: CMSS10 003.002 +%%Title: CMSS10 +%Version: 003.002 +%%CreationDate: Mon Jul 13 16:17:00 2009 +%%Creator: David M. Jones +%Copyright: Copyright (c) 1997, 2009 American Mathematical Society +%Copyright: (), with Reserved Font Name CMSS10. +% This Font Software is licensed under the SIL Open Font License, Version 1.1. +% This license is in the accompanying file OFL.txt, and is also +% available with a FAQ at: http://scripts.sil.org/OFL. +%%EndComments +FontDirectory/CMSS10 known{/CMSS10 findfont dup/UniqueID known{dup +/UniqueID get 5000803 eq exch/FontType get 1 eq and}{pop false}ifelse +{save true}{false}ifelse}{false}ifelse +11 dict begin +/FontType 1 def +/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def +/FontName /XYLNGW+CMSS10 def +/FontBBox {-61 -250 999 759 }readonly def +/PaintType 0 def +/FontInfo 9 dict dup begin +/version (003.002) readonly def +/Notice (Copyright \050c\051 1997, 2009 American Mathematical Society \050\051, with Reserved Font Name CMSS10.) readonly def +/FullName (CMSS10) readonly def +/FamilyName (Computer Modern) readonly def +/Weight (Medium) readonly def +/ItalicAngle 0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 80 /P put +dup 83 /S put +dup 98 /b put +dup 105 /i put +dup 109 /m put +dup 116 /t put +dup 117 /u put +readonly def +currentdict end +currentfile eexec +oc;jAw-ᾉYň5t&נ{hLGqB`d˗Pة|*x\ޖHtEB-gedog7Q`[['W73sZ9 m !tAY!$tY\r[uTIUiBy[Ȝŗ3Kï6zJ!˒Js&B5C3 }bQQvcXVL8:oF)w=b.0ٺ;4'Sb|2FZ0f瑆*5"{ Eޗ|&z{7j俶CCm$CfWM&9WEC7 鶐5Qs A0WX a4f36 D8ꩡx9Et{ +u|p:1cz5^Hɀ2bx@_@z gނ]0&, bܼR" a["+)騰% &8| 4O'ؘͣч)9$gꡉginkvRc-gj +x4cVԈ}pA)%`+e;1wXlfcL!9LO_ceph\CLjO)hyr+q-Ei|DcYv -+wud[!}QnMu9;jJk*d:4SklsҞ}4 nvF&VY8jzw?0}%tT%;p2QAWKq76jf?D*6zem>;LjI]f`^:Q&>NS\GYV,8a$l0 +L{8gX[rt=@|sv\a 伟bWMVSvn^hUC<-ެHO?OtRpDo^bh;O}M_Ɵz6XF_J}:Y!f,S%9oZKSp /88OO:?*\UV/vy0Ogƺj +AERpޫkJc~S㢕A_.!qk:2P g' +`eҞwkqjCY?^iĊXA*s)kc9ځ;Kq9g5>?Ӗt^g72xr ?n2<5(_ ]w.Js @e'if<_70Ai b۳n]9>PdBJk,~[#A3n \hyYS:/#a8'<>0FgKJ|2lig>:`~p޳>qCyl7`zN~]}lT!I\Eq +0!B)B߮ox!‹+,% mƖ"NYeh6^.̨~A 4h6+ҹξvL0ޠ9n#Z6)D<.uRN+oONy4W[6‡isGrɎBVem`r>8VS̀8{7}V-̠ ^vr$8[y5sSP@VI[m*R胙d\?X獈sZDY A$Ųʤ؋ ޷8 =*-)_NO'jEfN\}3̮ԧTw`du{rW^1+A*(/)W nXbL>Qy+]JZE8VoYÎ1kX~ 'C6zxpyFd7ghz +&L#*,6Kpg?N:BeF +&yuX5Pc'n޻{^lgHv +"XlfAE5i +_n𛎳%e}M6Ӕ3Yv;ĺ#WXHI,>(b2'ę_};7JF +;s5ڥbvqc8NQHhek,^2lSye.Ė YRD4o:ֹXfYqjE}; +`B7||oD& e#7=M}}Nϓ6}kjۻuU t ,XQIڝ`jPzݰCPi$ܟo~O/  885~*fx 9v&$GF볝ɗS[ˍL BmlC׮$/`^" Z6\&F$/՗?=o³\7\Rfmz`pnT$"nV>De{1~7W V>Ѓ3^tL<"qp|ҳ[ж:A?Io]JǔMb|tMPX")ž6a !`S]CVǔE3VibeJe =52joB&){S1eiH8a#E ha39a? !R~bal!J8kI$`."Ǧ[.!>ClKB\5;$7Zq0WZ<}^ hk/toD:fi>F-|O`#[+]b|>憍Hbo|I4;1[sDL]!3[T0S*H),yiJlt5ـHCV! .aswEx5?0֕"Ra<7119۩(ka nu{qgrew'(vot~ +@1VI,0c.bzwpa Cr<]9 P} +L` 4ԟp*mŌ~x.Eà]MwQA*Jb퇺)ϖQ Ϝ9?{?7 %4"㱥TG:jnCLLi-ޝ;Ŭ.p!2>=+0IOztYדH.]UᤸIuK;0j>7UT%k׵Zl_{(WiW ?ZYE>BD]?92Lg_ l(8V>Lm?Y FQ>ɑN=D{n;C0#W>A/_ycHo+*y=iQ3%*3: hryU0NiH}-vk~Rğw` <j]P/()Kp#snwIm-ps5<#hr'QVKPM=Q5d-wv!? 5UWg;ᅧ,[.ջ>뗬gI,F/*V2e;jZC%x^Mp nUC5,) [C½w- ޾B+V.AuJ<ƾBSxkf7~R&^wډڻ3Eݭ26|v>Rѓ|4թocw~Hr JO:2[r~}3qGb'CjNEqh9E*)m(s,!ۯڬ!DF +UF+ f^q/뛍.6o6y[w]"DDx(aDjhO0ə9XA%N%"7' -Q)ة1aە>Dr1mJM#0(D-10SH'LJ;K +Y2"6կadοB\Un8'yH{Dg Yi$B,.*i_ۆLR8޴FȝE +A/ +\ƍ儸aDU,B3sEÏ4ueKIގݞLV,yP3$_v*A絛js#ɺ%u΁%&cXKuΦ8 򑰪N^0E%EW3i<:O0NI ["BBmIC/|!G!,y +D Cq>(iR4&lu^')S?O\Rsy1;X9tP2Xh sbAPy=,#mn-AJlsF1N? Kx|g=gS̄4_@/{h\~wբh}~̬_S]7Z^I&G7 kk4$b#tLkwYXtIo=qgMLCgG %X%8٬=#+!׿el[(]^2q1T~ yz87mȽtS҅Fk6,8uljϦPvwSTov]_6l^ZxU H$6 `f[ MDA8W/UyV`DXg0EuVois%K>`]ϫ_fp+ U \Ѥܳ[nc`!E1&G[yƒRAz{,rH:)ϵȅzx@ooޅ^U^w޻/1˴,40BYun[nMgϝ+"Ogt0H8K8`9 |Z~ fvLZzb=?o8A @#DZP_ {&.ſ)w.3n՟E#2M>'[$1:_-sֺtT=«mwlj2IIx^ߍ ', d :,d~6CI_1^0 }&|eePJވ:QHMy23۝yhbM#H[=8QZD.yqbrkzjhL<Y Z&7"$(: !:lO]= h/eck7Q!ϵTuUܢZ_u,*@R_N38I+~K*p~vjnҩ92 zKq +wOfD Ag-Q/oJ,7j.yէ9!slE' <]:6l<07:l-0`n F;O %r:tNQD:Zf2v?(|~AYt%(BV_SenElCjfoz /xzL/W]@|CpOu|)Hտ{Qݪ6I~DQ!ڜ n)f㉪ b; +.&R|U/}L#&,ò,E(%[ADQdc墚Ʋ0a&VYxW7i^|F6㽢Ok-e}˒Ȫl(%⬪#A+ +Qx)6p)JB endstream +endobj +88 0 obj +<< /Length1 1568 /Length2 967 /Length3 0 /Length 2535 >> +stream +%!PS-AdobeFont-1.0: Dingbats 001.005 +%%CreationDate: Tue Oct 19 1999 +% Copyright URW Software, Copyright 1997 by URW +% URW Software, Copyright 1997 by URW +% See the file COPYING (GNU General Public License) for license conditions. +% As a special exception, permission is granted to include this font +% program in a Postscript or PDF file that consists of a document that +% contains text to be displayed or printed using this font, regardless +% of the conditions or license applying to the document itself. +12 dict begin +/FontInfo 10 dict dup begin +/version (001.005) readonly def +/Notice (URW Software, Copyright 1997 by URW. See the file COPYING (GNU General Public License) for license conditions. As a special exception, permission is granted to include this font program in a Postscript or PDF file that consists of a document that contains text to be displayed or printed using this font, regardless of the conditions or license applying to the document itself.) readonly def +/Copyright (Copyright URW Software, Copyright 1997 by URW) readonly def +/FullName (Dingbats ) readonly def +/FamilyName (Dingbats) readonly def +/Weight (Regular) readonly def +/ItalicAngle 0.0 def +/isFixedPitch false def +/UnderlinePosition -72 def +/UnderlineThickness 36 def +end readonly def +/FontName /GCRMMP+Dingbats def +/PaintType 0 def +/WMode 0 def +/FontBBox {-1 -143 981 819} readonly def +/FontType 1 def +/FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 123 /a97 put +readonly def +currentdict end +currentfile eexec +oc;jtD[1ƅpTo9`.:ypJ*l'e}#)&7+/^ W{LZ60VQR^λ3r)#v$p~c&'ſ+ %;a~!ty`r|v0Q>(Ŧ^bW69u ߈PuJ{{<\C>LC6ojL~c'YWU XMkA.cE}+:dkGvH8rSOp,<jy52|7Ile7d5+xMT),ҍ:ރsź'(tUU(j)^&pN +ޚraQjnHQ%d.Ȑ"8՚ϸa};{&;֖42- jxg;R:;*鮐߾jF 1Y;[IqkcCtpSL~r~U`Lz}y@^6df!pN %{Ȁ*f4c궻dB#~\55x!C5u_k1(qފ`;2j+{4K ~:@rCn`sH[دP:I#aH^u#<.}ʬ< mlQbB +*=(bCʻMku^ӁK n`f.߶0? D5\њSN6?Yy 0<8b{kihkĭ636]чFK=t_e?AR%ӐE֧\˸*?2]G +tendstream +endobj +89 0 obj +<< /Type /XRef /Length 360 /W [ 1 2 1 ] /Info 72 0 R /Root 71 0 R /Size 90 /ID [<4ebbbcf81067ebcf0d2f90a6d284c12c>] >> +stream +  +    !"#$%&'()*+,-./0123456789:;<=>?@ABCDE&(()8)*D*+P+,\,-j-.y/eZ3t +endstream +endobj +startxref +36980 +%%EOF diff --git a/test/test_manifest.json b/test/test_manifest.json index 1fd7bfa1d..a97953e92 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -894,6 +894,12 @@ "link": false, "type": "eq" }, + { "id": "docactions", + "file": "pdfs/docactions.pdf", + "md5": "28ea940349cf7cb793cfe167d04b097c", + "rounds": 1, + "type": "eq" + }, { "id": "issue9084", "file": "pdfs/issue9084.pdf", "md5": "5570ec01cc869d299fec1b2f68926a08", diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 5cbbcc773..82e3b1034 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -995,6 +995,44 @@ describe("api", function () { .catch(done.fail); }); + it("gets JSActions (none)", function (done) { + const promise = pdfDocument.getJSActions(); + promise + .then(function (data) { + expect(data).toEqual(null); + done(); + }) + .catch(done.fail); + }); + it("gets JSActions", function (done) { + // PDF document with "JavaScript" action in the OpenAction dictionary. + const loadingTask = getDocument(buildGetDocumentParams("docactions.pdf")); + const promise = loadingTask.promise.then(async pdfDoc => { + const docActions = await pdfDoc.getJSActions(); + const page5 = await pdfDoc.getPage(5); + const page12 = await pdfDoc.getPage(12); + const page5Actions = await page5.getJSActions(); + const page12Actions = await page12.getJSActions(); + return [docActions, page5Actions, page12Actions]; + }); + promise + .then(async ([docActions, page5Actions, page12Actions]) => { + expect(docActions).toEqual({ + Open: ["console.println('Open Action');"], + }); + expect(page5Actions).toEqual({ + PageOpen: ["console.println('Open page 5');"], + PageClose: ["console.println('Close page 5');"], + }); + expect(page12Actions).toEqual({ + PageOpen: ["console.println('Open page 12');"], + PageClose: ["console.println('Close page 12');"], + }); + loadingTask.destroy().then(done); + }) + .catch(done.fail); + }); + it("gets non-existent outline", function (done) { const loadingTask = getDocument( buildGetDocumentParams("tracemonkey.pdf") diff --git a/web/app.js b/web/app.js index 79a47aca9..731c24afa 100644 --- a/web/app.js +++ b/web/app.js @@ -1031,12 +1031,26 @@ const PDFViewerApplication = { return; } + if (this._scriptingInstance) { + this._scriptingInstance.scripting.dispatchEventInSandbox({ + id: "doc", + name: "WillSave", + }); + } + this._saveInProgress = true; this.pdfDocument .saveDocument(this.pdfDocument.annotationStorage) .then(data => { const blob = new Blob([data], { type: "application/pdf" }); downloadManager.download(blob, url, filename, sourceEventType); + + if (this._scriptingInstance) { + this._scriptingInstance.scripting.dispatchEventInSandbox({ + id: "doc", + name: "DidSave", + }); + } }) .catch(() => { this.download({ sourceEventType }); @@ -1447,16 +1461,18 @@ const PDFViewerApplication = { if (!AppOptions.get("enableScripting")) { return; } - const [objects, calculationOrder] = await Promise.all([ + const [objects, calculationOrder, docActions] = await Promise.all([ pdfDocument.getFieldObjects(), pdfDocument.getCalculationOrderIds(), + pdfDocument.getJSActions(), ]); - if (!objects || pdfDocument !== this.pdfDocument) { - // No FieldObjects were found in the document, + if ((!objects && !docActions) || pdfDocument !== this.pdfDocument) { + // No FieldObjects were found in the document, no JS Actions at doc level // or the document was closed while the data resolved. return; } + const scripting = this.externalServices.createScripting(); // Store a reference to the current scripting-instance, to allow destruction // of the sandbox and removal of the event listeners at document closing. @@ -1495,8 +1511,10 @@ const PDFViewerApplication = { this.pdfViewer.currentPageNumber = value + 1; return; case "print": - this.triggerPrinting(); - break; + this.pdfViewer.pagesPromise.then(() => { + this.triggerPrinting(); + }); + return; case "println": console.log(value); break; @@ -1578,12 +1596,18 @@ const PDFViewerApplication = { metadata: this.metadata, numPages: pdfDocument.numPages, URL: this.url, + actions: docActions, }, }); } catch (error) { console.error(error); this._destroyScriptingInstance(); } + + scripting.dispatchEventInSandbox({ + id: "doc", + name: "Open", + }); }, /** @@ -1620,7 +1644,7 @@ const PDFViewerApplication = { if (openAction && openAction.action === "Print") { triggerAutoPrint = true; } - if (javaScript) { + if (javaScript && !AppOptions.get("enableScripting")) { javaScript.some(js => { if (!js) { // Don't warn/fallback for empty JavaScript actions. @@ -2002,7 +2026,21 @@ const PDFViewerApplication = { if (!this.supportsPrinting) { return; } + if (this._scriptingInstance) { + this._scriptingInstance.scripting.dispatchEventInSandbox({ + id: "doc", + name: "WillPrint", + }); + } + window.print(); + + if (this._scriptingInstance) { + this._scriptingInstance.scripting.dispatchEventInSandbox({ + id: "doc", + name: "DidPrint", + }); + } }, bindEvents() {