From 45c3f00a27e980b1d0cd85eef982a3e99159e1ad Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Tue, 25 May 2021 15:50:12 +0200 Subject: [PATCH] XFA - Move the fake HTML representation of XFA from the worker to the main thread - the only goal of this patch is to be able to get synchronously the fake html when printing from firefox: - in order to print we need to inject some html in beforeprint callback but we cannot block in waiting for all the pages. - from a memory point of view: it doesn't change anything since the fake HTML is deleted in the worker; - this way we don't break any assumptions. --- src/core/document.js | 14 +++++++++----- src/core/worker.js | 14 ++++---------- src/core/xfa/factory.js | 25 +++++++++++++++++++++---- src/display/api.js | 24 +++++++++++++----------- test/unit/xfa_tohtml_spec.js | 5 +++-- 5 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/core/document.js b/src/core/document.js index d5cec7c94..38f6a0404 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -146,8 +146,7 @@ class Page { _getBoundingBox(name) { if (this.xfaData) { - const { width, height } = this.xfaData.attributes.style; - return [0, 0, parseInt(width), parseInt(height)]; + return this.xfaData.bbox; } const box = this._getInheritableProperty(name, /* getArray = */ true); @@ -241,7 +240,9 @@ class Page { get xfaData() { if (this.xfaFactory) { - return shadow(this, "xfaData", this.xfaFactory.getPage(this.pageIndex)); + return shadow(this, "xfaData", { + bbox: this.xfaFactory.getBoundingBox(this.pageIndex), + }); } return shadow(this, "xfaData", null); } @@ -851,8 +852,11 @@ class PDFDocument { return shadow(this, "xfaFaxtory", null); } - get isPureXfa() { - return this.xfaFactory !== null; + get htmlForXfa() { + if (this.xfaFactory) { + return this.xfaFactory.getPages(); + } + return null; } async loadXfaFonts(handler, task) { diff --git a/src/core/worker.js b/src/core/worker.js index f88691622..4c121485c 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -187,13 +187,13 @@ class WorkerMessageHandler { await pdfManager.ensureDoc("checkFirstPage"); } - const [numPages, fingerprint, isPureXfa] = await Promise.all([ + const [numPages, fingerprint, htmlForXfa] = await Promise.all([ pdfManager.ensureDoc("numPages"), pdfManager.ensureDoc("fingerprint"), - pdfManager.ensureDoc("isPureXfa"), + pdfManager.ensureDoc("htmlForXfa"), ]); - if (isPureXfa) { + if (htmlForXfa) { const task = new WorkerTask("loadXfaFonts"); startWorkerTask(task); await pdfManager @@ -203,7 +203,7 @@ class WorkerMessageHandler { }) .then(() => finishWorkerTask(task)); } - return { numPages, fingerprint, isPureXfa }; + return { numPages, fingerprint, htmlForXfa }; } function getPdfManager(data, evaluatorOptions, enableXfa) { @@ -501,12 +501,6 @@ class WorkerMessageHandler { }); }); - handler.on("GetPageXfa", function wphSetupGetXfa({ pageIndex }) { - return pdfManager.getPage(pageIndex).then(function (page) { - return pdfManager.ensure(page, "xfaData"); - }); - }); - handler.on("GetOutline", function wphSetupGetOutline(data) { return pdfManager.ensureCatalog("documentOutline"); }); diff --git a/src/core/xfa/factory.js b/src/core/xfa/factory.js index 27e7c19c4..cea1a9110 100644 --- a/src/core/xfa/factory.js +++ b/src/core/xfa/factory.js @@ -22,18 +22,35 @@ class XFAFactory { try { this.root = new XFAParser().parse(XFAFactory._createDocument(data)); this.form = new Binder(this.root).bind(); - this.pages = this.form[$toHTML](); + this._createPages(); } catch (e) { console.log(e); } } - getPage(pageIndex) { - return this.pages.children[pageIndex]; + _createPages() { + this.pages = this.form[$toHTML](); + this.dims = this.pages.children.map(c => { + const { width, height } = c.attributes.style; + return [0, 0, parseInt(width), parseInt(height)]; + }); + } + + getBoundingBox(pageIndex) { + return this.dims[pageIndex]; } get numberPages() { - return this.pages.children.length; + return this.dims.length; + } + + getPages() { + if (!this.pages) { + this._createPages(); + } + const pages = this.pages; + this.pages = null; + return pages; } static _createDocument(data) { diff --git a/src/display/api.js b/src/display/api.js index ce7bac9d1..5cd2229c8 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -695,7 +695,15 @@ class PDFDocumentProxy { * @type {boolean} True if only XFA form. */ get isPureXfa() { - return this._pdfInfo.isPureXfa; + return !!this._transport._htmlForXfa; + } + + /** + * @type {Object | null} An object representing a HTML tree structure + * to render the XFA, or `null` when no XFA form exists. + */ + get allXfaHtml() { + return this._transport._htmlForXfa; } /** @@ -1255,8 +1263,8 @@ class PDFPageProxy { * are {Object} with a name, attributes (class, style, ...), value and * children, very similar to a HTML DOM tree), or `null` if no XFA exists. */ - getXfa() { - return (this._xfaPromise ||= this._transport.getPageXfa(this._pageIndex)); + async getXfa() { + return this._transport._htmlForXfa?.children[this._pageIndex] || null; } /** @@ -1552,7 +1560,6 @@ class PDFPageProxy { this.objs.clear(); this._annotationsPromise = null; this._jsActionsPromise = null; - this._xfaPromise = null; this._structTreePromise = null; this.pendingCleanup = false; return Promise.all(waitOn); @@ -1588,7 +1595,6 @@ class PDFPageProxy { this.objs.clear(); this._annotationsPromise = null; this._jsActionsPromise = null; - this._xfaPromise = null; this._structTreePromise = null; if (resetStats && this._stats) { this._stats = new StatTimer(); @@ -2456,6 +2462,8 @@ class WorkerTransport { messageHandler.on("GetDoc", ({ pdfInfo }) => { this._numPages = pdfInfo.numPages; + this._htmlForXfa = pdfInfo.htmlForXfa; + delete pdfInfo.htmlForXfa; loadingTask._capability.resolve(new PDFDocumentProxy(pdfInfo, this)); }); @@ -2812,12 +2820,6 @@ class WorkerTransport { }); } - getPageXfa(pageIndex) { - return this.messageHandler.sendWithPromise("GetPageXfa", { - pageIndex, - }); - } - getStructTree(pageIndex) { return this.messageHandler.sendWithPromise("GetStructTree", { pageIndex, diff --git a/test/unit/xfa_tohtml_spec.js b/test/unit/xfa_tohtml_spec.js index 7176fe0df..c116c4440 100644 --- a/test/unit/xfa_tohtml_spec.js +++ b/test/unit/xfa_tohtml_spec.js @@ -57,7 +57,8 @@ describe("XFAFactory", function () { expect(factory.numberPages).toEqual(2); - const page1 = factory.getPage(0); + const pages = factory.getPages(); + const page1 = pages.children[0]; expect(page1.attributes.style).toEqual({ height: "789px", width: "456px", @@ -99,7 +100,7 @@ describe("XFAFactory", function () { // draw element must be on each page. expect(draw.attributes.style).toEqual( - factory.getPage(1).children[1].children[0].attributes.style + pages.children[1].children[1].children[0].attributes.style ); }); });