Skip to content

Commit 49b3881

Browse files
Merge pull request #18001 from Snuffleupagus/api-pageRefCache
[api-minor] Move the page reference/number caching into the API
2 parents 3052e99 + 150964d commit 49b3881

File tree

6 files changed

+75
-124
lines changed

6 files changed

+75
-124
lines changed

src/core/worker.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ class WorkerMessageHandler {
419419
return {
420420
rotate,
421421
ref,
422+
refStr: ref?.toString() ?? null,
422423
userUnit,
423424
view,
424425
};

src/display/api.js

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,16 @@ function getDataProp(val) {
560560
);
561561
}
562562

563+
function isRefProxy(ref) {
564+
return (
565+
typeof ref === "object" &&
566+
Number.isInteger(ref?.num) &&
567+
ref.num >= 0 &&
568+
Number.isInteger(ref?.gen) &&
569+
ref.gen >= 0
570+
);
571+
}
572+
563573
/**
564574
* @typedef {Object} OnProgressParameters
565575
* @property {number} loaded - Currently loaded number of bytes.
@@ -1066,6 +1076,14 @@ class PDFDocumentProxy {
10661076
return this.loadingTask.destroy();
10671077
}
10681078

1079+
/**
1080+
* @param {RefProxy} ref - The page reference.
1081+
* @returns {number | null} The page number, if it's cached.
1082+
*/
1083+
cachedPageNumber(ref) {
1084+
return this._transport.cachedPageNumber(ref);
1085+
}
1086+
10691087
/**
10701088
* @type {DocumentInitParameters} A subset of the current
10711089
* {DocumentInitParameters}, which are needed in the viewer.
@@ -2340,6 +2358,8 @@ class WorkerTransport {
23402358

23412359
#pagePromises = new Map();
23422360

2361+
#pageRefCache = new Map();
2362+
23432363
#passwordCapability = null;
23442364

23452365
constructor(messageHandler, loadingTask, networkStream, params, factory) {
@@ -2483,6 +2503,7 @@ class WorkerTransport {
24832503
}
24842504
this.#pageCache.clear();
24852505
this.#pagePromises.clear();
2506+
this.#pageRefCache.clear();
24862507
// Allow `AnnotationStorage`-related clean-up when destroying the document.
24872508
if (this.hasOwnProperty("annotationStorage")) {
24882509
this.annotationStorage.resetModified();
@@ -2915,6 +2936,10 @@ class WorkerTransport {
29152936
if (this.destroyed) {
29162937
throw new Error("Transport destroyed");
29172938
}
2939+
if (pageInfo.refStr) {
2940+
this.#pageRefCache.set(pageInfo.refStr, pageNumber);
2941+
}
2942+
29182943
const page = new PDFPageProxy(
29192944
pageIndex,
29202945
pageInfo,
@@ -2929,13 +2954,7 @@ class WorkerTransport {
29292954
}
29302955

29312956
getPageIndex(ref) {
2932-
if (
2933-
typeof ref !== "object" ||
2934-
!Number.isInteger(ref?.num) ||
2935-
ref.num < 0 ||
2936-
!Number.isInteger(ref?.gen) ||
2937-
ref.gen < 0
2938-
) {
2957+
if (!isRefProxy(ref)) {
29392958
return Promise.reject(new Error("Invalid pageIndex request."));
29402959
}
29412960
return this.messageHandler.sendWithPromise("GetPageIndex", {
@@ -3076,6 +3095,14 @@ class WorkerTransport {
30763095
cleanupTextLayer();
30773096
}
30783097

3098+
cachedPageNumber(ref) {
3099+
if (!isRefProxy(ref)) {
3100+
return null;
3101+
}
3102+
const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`;
3103+
return this.#pageRefCache.get(refStr) ?? null;
3104+
}
3105+
30793106
get loadingParams() {
30803107
const { disableAutoFetch, enableXfa } = this._params;
30813108
return shadow(this, "loadingParams", {

web/interfaces.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,6 @@ class IPDFLinkService {
106106
* @param {Object} action
107107
*/
108108
executeSetOCGState(action) {}
109-
110-
/**
111-
* @param {number} pageNum - page number.
112-
* @param {Object} pageRef - reference to the page.
113-
*/
114-
cachePageRef(pageNum, pageRef) {}
115109
}
116110

117111
/**

web/pdf_link_service.js

Lines changed: 35 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ const LinkTarget = {
4949
class PDFLinkService {
5050
externalLinkEnabled = true;
5151

52-
#pagesRefCache = new Map();
53-
5452
/**
5553
* @param {PDFLinkServiceOptions} options
5654
*/
@@ -74,7 +72,6 @@ class PDFLinkService {
7472
setDocument(pdfDocument, baseUrl = null) {
7573
this.baseUrl = baseUrl;
7674
this.pdfDocument = pdfDocument;
77-
this.#pagesRefCache.clear();
7875
}
7976

8077
setViewer(pdfViewer) {
@@ -131,44 +128,53 @@ class PDFLinkService {
131128
return this.pdfDocument ? this.pdfViewer.isInPresentationMode : false;
132129
}
133130

134-
#goToDestinationHelper(rawDest, namedDest = null, explicitDest) {
131+
/**
132+
* This method will, when available, also update the browser history.
133+
*
134+
* @param {string|Array} dest - The named, or explicit, PDF destination.
135+
*/
136+
async goToDestination(dest) {
137+
if (!this.pdfDocument) {
138+
return;
139+
}
140+
let namedDest, explicitDest, pageNumber;
141+
if (typeof dest === "string") {
142+
namedDest = dest;
143+
explicitDest = await this.pdfDocument.getDestination(dest);
144+
} else {
145+
namedDest = null;
146+
explicitDest = await dest;
147+
}
148+
if (!Array.isArray(explicitDest)) {
149+
console.error(
150+
`goToDestination: "${explicitDest}" is not a valid destination array, for dest="${dest}".`
151+
);
152+
return;
153+
}
135154
// Dest array looks like that: <page-ref> </XYZ|/FitXXX> <args..>
136-
const destRef = explicitDest[0];
137-
let pageNumber;
155+
const [destRef] = explicitDest;
138156

139-
if (typeof destRef === "object" && destRef !== null) {
140-
pageNumber = this._cachedPageNumber(destRef);
157+
if (destRef && typeof destRef === "object") {
158+
pageNumber = this.pdfDocument.cachedPageNumber(destRef);
141159

142160
if (!pageNumber) {
143161
// Fetch the page reference if it's not yet available. This could
144162
// only occur during loading, before all pages have been resolved.
145-
this.pdfDocument
146-
.getPageIndex(destRef)
147-
.then(pageIndex => {
148-
this.cachePageRef(pageIndex + 1, destRef);
149-
this.#goToDestinationHelper(rawDest, namedDest, explicitDest);
150-
})
151-
.catch(() => {
152-
console.error(
153-
`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` +
154-
`a valid page reference, for dest="${rawDest}".`
155-
);
156-
});
157-
return;
163+
try {
164+
pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1;
165+
} catch {
166+
console.error(
167+
`goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".`
168+
);
169+
return;
170+
}
158171
}
159172
} else if (Number.isInteger(destRef)) {
160173
pageNumber = destRef + 1;
161-
} else {
162-
console.error(
163-
`PDFLinkService.#goToDestinationHelper: "${destRef}" is not ` +
164-
`a valid destination reference, for dest="${rawDest}".`
165-
);
166-
return;
167174
}
168175
if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
169176
console.error(
170-
`PDFLinkService.#goToDestinationHelper: "${pageNumber}" is not ` +
171-
`a valid page number, for dest="${rawDest}".`
177+
`goToDestination: "${pageNumber}" is not a valid page number, for dest="${dest}".`
172178
);
173179
return;
174180
}
@@ -187,33 +193,6 @@ class PDFLinkService {
187193
});
188194
}
189195

190-
/**
191-
* This method will, when available, also update the browser history.
192-
*
193-
* @param {string|Array} dest - The named, or explicit, PDF destination.
194-
*/
195-
async goToDestination(dest) {
196-
if (!this.pdfDocument) {
197-
return;
198-
}
199-
let namedDest, explicitDest;
200-
if (typeof dest === "string") {
201-
namedDest = dest;
202-
explicitDest = await this.pdfDocument.getDestination(dest);
203-
} else {
204-
namedDest = null;
205-
explicitDest = await dest;
206-
}
207-
if (!Array.isArray(explicitDest)) {
208-
console.error(
209-
`PDFLinkService.goToDestination: "${explicitDest}" is not ` +
210-
`a valid destination array, for dest="${dest}".`
211-
);
212-
return;
213-
}
214-
this.#goToDestinationHelper(dest, namedDest, explicitDest);
215-
}
216-
217196
/**
218197
* This method will, when available, also update the browser history.
219198
*
@@ -508,31 +487,6 @@ class PDFLinkService {
508487
);
509488
}
510489

511-
/**
512-
* @param {number} pageNum - page number.
513-
* @param {Object} pageRef - reference to the page.
514-
*/
515-
cachePageRef(pageNum, pageRef) {
516-
if (!pageRef) {
517-
return;
518-
}
519-
const refStr =
520-
pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`;
521-
this.#pagesRefCache.set(refStr, pageNum);
522-
}
523-
524-
/**
525-
* @ignore
526-
*/
527-
_cachedPageNumber(pageRef) {
528-
if (!pageRef) {
529-
return null;
530-
}
531-
const refStr =
532-
pageRef.gen === 0 ? `${pageRef.num}R` : `${pageRef.num}R${pageRef.gen}`;
533-
return this.#pagesRefCache.get(refStr) || null;
534-
}
535-
536490
static #isValidExplicitDest(dest) {
537491
if (!Array.isArray(dest) || dest.length < 2) {
538492
return false;
@@ -592,12 +546,6 @@ class PDFLinkService {
592546
*/
593547
class SimpleLinkService extends PDFLinkService {
594548
setDocument(pdfDocument, baseUrl = null) {}
595-
596-
/**
597-
* @param {number} pageNum - page number.
598-
* @param {Object} pageRef - reference to the page.
599-
*/
600-
cachePageRef(pageNum, pageRef) {}
601549
}
602550

603551
export { LinkTarget, PDFLinkService, SimpleLinkService };

web/pdf_outline_viewer.js

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -325,21 +325,10 @@ class PDFOutlineViewer extends BaseTreeViewer {
325325
if (Array.isArray(explicitDest)) {
326326
const [destRef] = explicitDest;
327327

328-
if (typeof destRef === "object" && destRef !== null) {
329-
pageNumber = this.linkService._cachedPageNumber(destRef);
330-
331-
if (!pageNumber) {
332-
try {
333-
pageNumber = (await pdfDocument.getPageIndex(destRef)) + 1;
334-
335-
if (pdfDocument !== this._pdfDocument) {
336-
return null; // The document was closed while the data resolved.
337-
}
338-
this.linkService.cachePageRef(pageNumber, destRef);
339-
} catch {
340-
// Invalid page reference, ignore it and continue parsing.
341-
}
342-
}
328+
if (destRef && typeof destRef === "object") {
329+
// The page reference must be available, since the current method
330+
// won't be invoked until all pages have been loaded.
331+
pageNumber = pdfDocument.cachedPageNumber(destRef);
343332
} else if (Number.isInteger(destRef)) {
344333
pageNumber = destRef + 1;
345334
}

web/pdf_viewer.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -935,11 +935,7 @@ class PDFViewer {
935935
// Set the first `pdfPage` immediately, since it's already loaded,
936936
// rather than having to repeat the `PDFDocumentProxy.getPage` call in
937937
// the `this.#ensurePdfPageLoaded` method before rendering can start.
938-
const firstPageView = this._pages[0];
939-
if (firstPageView) {
940-
firstPageView.setPdfPage(firstPdfPage);
941-
this.linkService.cachePageRef(1, firstPdfPage.ref);
942-
}
938+
this._pages[0]?.setPdfPage(firstPdfPage);
943939

944940
if (this._scrollMode === ScrollMode.PAGE) {
945941
// Ensure that the current page becomes visible on document load.
@@ -994,7 +990,6 @@ class PDFViewer {
994990
if (!pageView.pdfPage) {
995991
pageView.setPdfPage(pdfPage);
996992
}
997-
this.linkService.cachePageRef(pageNum, pdfPage.ref);
998993
if (--getPagesLeft === 0) {
999994
this._pagesCapability.resolve();
1000995
}
@@ -1718,9 +1713,6 @@ class PDFViewer {
17181713
if (!pageView.pdfPage) {
17191714
pageView.setPdfPage(pdfPage);
17201715
}
1721-
if (!this.linkService._cachedPageNumber?.(pdfPage.ref)) {
1722-
this.linkService.cachePageRef(pageView.id, pdfPage.ref);
1723-
}
17241716
return pdfPage;
17251717
} catch (reason) {
17261718
console.error("Unable to get page for page view", reason);

0 commit comments

Comments
 (0)