From ea8ffa803b81862347920fa7d2c352449744ebca Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 24 Apr 2024 21:55:50 +0200 Subject: [PATCH] [api-minor] Move the page reference/number caching into the API Rather than having to handle this *manually* throughout the viewer, this functionality can instead be moved into the API which simplifies the code slightly. --- src/core/worker.js | 1 + src/display/api.js | 42 ++++++++++++++++++++++++++++++++------- web/interfaces.js | 6 ------ web/pdf_link_service.js | 39 ++---------------------------------- web/pdf_outline_viewer.js | 19 ++++-------------- web/pdf_viewer.js | 5 ----- 6 files changed, 42 insertions(+), 70 deletions(-) diff --git a/src/core/worker.js b/src/core/worker.js index 631bb52df9f269..804936229bcc93 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -419,6 +419,7 @@ class WorkerMessageHandler { return { rotate, ref, + refStr: ref?.toString() ?? null, userUnit, view, }; diff --git a/src/display/api.js b/src/display/api.js index 70dcf67fb213b9..6ff1a2481029ae 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -561,6 +561,17 @@ function getDataProp(val) { ); } +function isRefProxy(ref) { + return ( + ref && + typeof ref === "object" && + Number.isInteger(ref.num) && + ref.num >= 0 && + Number.isInteger(ref.gen) && + ref.gen >= 0 + ); +} + /** * @typedef {Object} OnProgressParameters * @property {number} loaded - Currently loaded number of bytes. @@ -1067,6 +1078,14 @@ class PDFDocumentProxy { return this.loadingTask.destroy(); } + /** + * @param {RefProxy} ref - The page reference. + * @returns {number | null} The page number, if it's cached. + */ + cachedPageNumber(ref) { + return this._transport.cachedPageNumber(ref); + } + /** * @type {DocumentInitParameters} A subset of the current * {DocumentInitParameters}, which are needed in the viewer. @@ -2341,6 +2360,8 @@ class WorkerTransport { #pagePromises = new Map(); + #pageRefCache = new Map(); + #passwordCapability = null; constructor(messageHandler, loadingTask, networkStream, params, factory) { @@ -2484,6 +2505,7 @@ class WorkerTransport { } this.#pageCache.clear(); this.#pagePromises.clear(); + this.#pageRefCache.clear(); // Allow `AnnotationStorage`-related clean-up when destroying the document. if (this.hasOwnProperty("annotationStorage")) { this.annotationStorage.resetModified(); @@ -2917,6 +2939,10 @@ class WorkerTransport { if (this.destroyed) { throw new Error("Transport destroyed"); } + if (pageInfo.refStr) { + this.#pageRefCache.set(pageInfo.refStr, pageNumber); + } + const page = new PDFPageProxy( pageIndex, pageInfo, @@ -2931,13 +2957,7 @@ class WorkerTransport { } getPageIndex(ref) { - if ( - typeof ref !== "object" || - !Number.isInteger(ref?.num) || - ref.num < 0 || - !Number.isInteger(ref?.gen) || - ref.gen < 0 - ) { + if (!isRefProxy(ref)) { return Promise.reject(new Error("Invalid pageIndex request.")); } return this.messageHandler.sendWithPromise("GetPageIndex", { @@ -3078,6 +3098,14 @@ class WorkerTransport { cleanupTextLayer(); } + cachedPageNumber(ref) { + if (!isRefProxy(ref)) { + return null; + } + const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`; + return this.#pageRefCache.get(refStr) ?? null; + } + get loadingParams() { const { disableAutoFetch, enableXfa } = this._params; return shadow(this, "loadingParams", { diff --git a/web/interfaces.js b/web/interfaces.js index 4c440312858449..31976c40f92f60 100644 --- a/web/interfaces.js +++ b/web/interfaces.js @@ -106,12 +106,6 @@ class IPDFLinkService { * @param {Object} action */ executeSetOCGState(action) {} - - /** - * @param {number} pageNum - page number. - * @param {Object} pageRef - reference to the page. - */ - cachePageRef(pageNum, pageRef) {} } /** diff --git a/web/pdf_link_service.js b/web/pdf_link_service.js index 62d3e0c44c58e5..b7b6670b0acaf7 100644 --- a/web/pdf_link_service.js +++ b/web/pdf_link_service.js @@ -98,8 +98,6 @@ function addLinkAttributes(link, { url, target, rel, enabled = true } = {}) { * @implements {IPDFLinkService} */ class PDFLinkService { - #pagesRefCache = new Map(); - /** * @param {PDFLinkServiceOptions} options */ @@ -124,7 +122,6 @@ class PDFLinkService { setDocument(pdfDocument, baseUrl = null) { this.baseUrl = baseUrl; this.pdfDocument = pdfDocument; - this.#pagesRefCache.clear(); } setViewer(pdfViewer) { @@ -203,15 +200,14 @@ class PDFLinkService { // Dest array looks like that: const [destRef] = explicitDest; - if (typeof destRef === "object" && destRef !== null) { - pageNumber = this._cachedPageNumber(destRef); + if (destRef && typeof destRef === "object") { + pageNumber = this.pdfDocument.cachedPageNumber(destRef); if (!pageNumber) { // Fetch the page reference if it's not yet available. This could // only occur during loading, before all pages have been resolved. try { pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1; - this.cachePageRef(pageNumber, destRef); } catch { console.error( `goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".` @@ -509,31 +505,6 @@ class PDFLinkService { ); } - /** - * @param {number} pageNum - page number. - * @param {Object} pageRef - reference to the page. - */ - cachePageRef(pageNum, pageRef) { - if (!pageRef) { - return; - } - const refStr = - pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; - this.#pagesRefCache.set(refStr, pageNum); - } - - /** - * @ignore - */ - _cachedPageNumber(pageRef) { - if (!pageRef) { - return null; - } - const refStr = - pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`; - return this.#pagesRefCache.get(refStr) || null; - } - static #isValidExplicitDest(dest) { if (!Array.isArray(dest) || dest.length < 2) { return false; @@ -683,12 +654,6 @@ class SimpleLinkService { * @param {Object} action */ executeSetOCGState(action) {} - - /** - * @param {number} pageNum - page number. - * @param {Object} pageRef - reference to the page. - */ - cachePageRef(pageNum, pageRef) {} } export { LinkTarget, PDFLinkService, SimpleLinkService }; diff --git a/web/pdf_outline_viewer.js b/web/pdf_outline_viewer.js index a198767b4e8719..efb7e5ec134243 100644 --- a/web/pdf_outline_viewer.js +++ b/web/pdf_outline_viewer.js @@ -325,21 +325,10 @@ class PDFOutlineViewer extends BaseTreeViewer { if (Array.isArray(explicitDest)) { const [destRef] = explicitDest; - if (typeof destRef === "object" && destRef !== null) { - pageNumber = this.linkService._cachedPageNumber(destRef); - - if (!pageNumber) { - try { - pageNumber = (await pdfDocument.getPageIndex(destRef)) + 1; - - if (pdfDocument !== this._pdfDocument) { - return null; // The document was closed while the data resolved. - } - this.linkService.cachePageRef(pageNumber, destRef); - } catch { - // Invalid page reference, ignore it and continue parsing. - } - } + if (destRef && typeof destRef === "object") { + // The page reference must be available, since the current method + // won't be invoked until all pages have been loaded. + pageNumber = pdfDocument.cachedPageNumber(destRef); } else if (Number.isInteger(destRef)) { pageNumber = destRef + 1; } diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index fd9ff4d8f49133..bfce351a02678b 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -938,7 +938,6 @@ class PDFViewer { const firstPageView = this._pages[0]; if (firstPageView) { firstPageView.setPdfPage(firstPdfPage); - this.linkService.cachePageRef(1, firstPdfPage.ref); } if (this._scrollMode === ScrollMode.PAGE) { @@ -994,7 +993,6 @@ class PDFViewer { if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } - this.linkService.cachePageRef(pageNum, pdfPage.ref); if (--getPagesLeft === 0) { this._pagesCapability.resolve(); } @@ -1718,9 +1716,6 @@ class PDFViewer { if (!pageView.pdfPage) { pageView.setPdfPage(pdfPage); } - if (!this.linkService._cachedPageNumber?.(pdfPage.ref)) { - this.linkService.cachePageRef(pageView.id, pdfPage.ref); - } return pdfPage; } catch (reason) { console.error("Unable to get page for page view", reason);