Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 37 additions & 17 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ const RENDERING_CANCELLED_TIMEOUT = 100; // ms
* The default value is {DOMFilterFactory}.
* @property {boolean} [enableHWA] - Enables hardware acceleration for
* rendering. The default value is `false`.
* @property {Object} [pagesMapper] - The pages mapper that will be used to map
* page ids and page numbers. It's used when the page order is changed or some
* pages are removed, cloned, etc.
*/

/**
Expand Down Expand Up @@ -342,6 +345,7 @@ function getDocument(src = {}) {
: DOMFilterFactory);
const enableHWA = src.enableHWA === true;
const useWasm = src.useWasm !== false;
const pagesMapper = src.pagesMapper || new PagesMapper();

// Parameters whose default values depend on other parameters.
const length = rangeTransport ? rangeTransport.length : (src.length ?? NaN);
Expand Down Expand Up @@ -511,7 +515,8 @@ function getDocument(src = {}) {
task,
networkStream,
transportParams,
transportFactory
transportFactory,
pagesMapper
);
task._transport = transport;
messageHandler.send("Ready", null);
Expand Down Expand Up @@ -761,6 +766,13 @@ class PDFDocumentProxy {
}
}

/**
* @type {PagesMapper} The pages mapper instance.
*/
get pagesMapper() {
return this._transport.pagesMapper;
}

/**
* @type {AnnotationStorage} Storage for annotation data in forms.
*/
Expand Down Expand Up @@ -1324,9 +1336,9 @@ class PDFDocumentProxy {
class PDFPageProxy {
#pendingCleanup = false;

#pagesMapper = PagesMapper.instance;
#pagesMapper = null;

constructor(pageIndex, pageInfo, transport, pdfBug = false) {
constructor(pageIndex, pageInfo, transport, pagesMapper, pdfBug = false) {
this._pageIndex = pageIndex;
this._pageInfo = pageInfo;
this._transport = transport;
Expand All @@ -1339,6 +1351,7 @@ class PDFPageProxy {
this._intentStates = new Map();
this.destroyed = false;
this.recordedBBoxes = null;
this.#pagesMapper = pagesMapper;
}

/**
Expand Down Expand Up @@ -2402,9 +2415,14 @@ class WorkerTransport {

#passwordCapability = null;

#pagesMapper = PagesMapper.instance;

constructor(messageHandler, loadingTask, networkStream, params, factory) {
constructor(
messageHandler,
loadingTask,
networkStream,
params,
factory,
pagesMapper
) {
this.messageHandler = messageHandler;
this.loadingTask = loadingTask;
this.#networkStream = networkStream;
Expand All @@ -2429,7 +2447,8 @@ class WorkerTransport {

this.setupMessageHandler();

this.#pagesMapper.addListener(this.#updateCaches.bind(this));
this.pagesMapper = pagesMapper;
this.pagesMapper.addListener(this.#updateCaches.bind(this));

if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
// For testing purposes.
Expand Down Expand Up @@ -2458,8 +2477,8 @@ class WorkerTransport {
#updateCaches() {
const newPageCache = new Map();
const newPromiseCache = new Map();
for (let i = 0, ii = this.#pagesMapper.pagesNumber; i < ii; i++) {
const prevPageIndex = this.#pagesMapper.getPrevPageNumber(i + 1) - 1;
for (let i = 0, ii = this.pagesMapper.pagesNumber; i < ii; i++) {
const prevPageIndex = this.pagesMapper.getPrevPageNumber(i + 1) - 1;
const page = this.#pageCache.get(prevPageIndex);
if (page) {
newPageCache.set(i, page);
Expand Down Expand Up @@ -2730,7 +2749,7 @@ class WorkerTransport {
});

messageHandler.on("GetDoc", ({ pdfInfo }) => {
this.#pagesMapper.pagesNumber = pdfInfo.numPages;
this.pagesMapper.pagesNumber = pdfInfo.numPages;
this._numPages = pdfInfo.numPages;
this._htmlForXfa = pdfInfo.htmlForXfa;
delete pdfInfo.htmlForXfa;
Expand Down Expand Up @@ -2947,12 +2966,12 @@ class WorkerTransport {
if (
!Number.isInteger(pageNumber) ||
pageNumber <= 0 ||
pageNumber > this.#pagesMapper.pagesNumber
pageNumber > this.pagesMapper.pagesNumber
) {
return Promise.reject(new Error("Invalid page request."));
}
const pageIndex = pageNumber - 1;
const newPageIndex = this.#pagesMapper.getPageId(pageNumber) - 1;
const newPageIndex = this.pagesMapper.getPageId(pageNumber) - 1;

const cachedPromise = this.#pagePromises.get(pageIndex);
if (cachedPromise) {
Expand All @@ -2974,6 +2993,7 @@ class WorkerTransport {
pageIndex,
pageInfo,
this,
this.pagesMapper,
this._params.pdfBug
);
this.#pageCache.set(pageIndex, page);
Expand All @@ -2991,12 +3011,12 @@ class WorkerTransport {
num: ref.num,
gen: ref.gen,
});
return this.#pagesMapper.getPageNumber(index + 1) - 1;
return this.pagesMapper.getPageNumber(index + 1) - 1;
}

getAnnotations(pageIndex, intent) {
return this.messageHandler.sendWithPromise("GetAnnotations", {
pageIndex: this.#pagesMapper.getPageId(pageIndex + 1) - 1,
pageIndex: this.pagesMapper.getPageId(pageIndex + 1) - 1,
intent,
});
}
Expand Down Expand Up @@ -3063,13 +3083,13 @@ class WorkerTransport {

getPageJSActions(pageIndex) {
return this.messageHandler.sendWithPromise("GetPageJSActions", {
pageIndex: this.#pagesMapper.getPageId(pageIndex + 1) - 1,
pageIndex: this.pagesMapper.getPageId(pageIndex + 1) - 1,
});
}

getStructTree(pageIndex) {
return this.messageHandler.sendWithPromise("GetStructTree", {
pageIndex: this.#pagesMapper.getPageId(pageIndex + 1) - 1,
pageIndex: this.pagesMapper.getPageId(pageIndex + 1) - 1,
});
}

Expand Down Expand Up @@ -3141,7 +3161,7 @@ class WorkerTransport {
const refStr = ref.gen === 0 ? `${ref.num}R` : `${ref.num}R${ref.gen}`;
const pageIndex = this.#pageRefCache.get(refStr);
return pageIndex >= 0
? this.#pagesMapper.getPageNumber(pageIndex + 1)
? this.pagesMapper.getPageNumber(pageIndex + 1)
: null;
}
}
Expand Down
73 changes: 30 additions & 43 deletions src/display/display_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1045,38 +1045,38 @@ class PagesMapper {
* Maps page IDs to their corresponding page numbers.
* @type {Uint32Array|null}
*/
static #idToPageNumber = null;
#idToPageNumber = null;

/**
* Maps page numbers to their corresponding page IDs.
* @type {Uint32Array|null}
*/
static #pageNumberToId = null;
#pageNumberToId = null;

/**
* Previous mapping of page IDs to page numbers.
* @type {Uint32Array|null}
*/
static #prevIdToPageNumber = null;
#prevIdToPageNumber = null;

/**
* The total number of pages.
* @type {number}
*/
static #pagesNumber = 0;
#pagesNumber = 0;

/**
* Listeners for page changes.
* @type {Array<function>}
*/
static #listeners = [];
#listeners = [];

/**
* Gets the total number of pages.
* @returns {number} The number of pages.
*/
get pagesNumber() {
return PagesMapper.#pagesNumber;
return this.#pagesNumber;
}

/**
Expand All @@ -1085,52 +1085,49 @@ class PagesMapper {
* @param {number} n - The total number of pages.
*/
set pagesNumber(n) {
if (PagesMapper.#pagesNumber === n) {
if (this.#pagesNumber === n) {
return;
}
PagesMapper.#pagesNumber = n;
this.#pagesNumber = n;
if (n === 0) {
PagesMapper.#pageNumberToId = null;
PagesMapper.#idToPageNumber = null;
this.#pageNumberToId = null;
this.#idToPageNumber = null;
}
}

addListener(listener) {
PagesMapper.#listeners.push(listener);
this.#listeners.push(listener);
}

removeListener(listener) {
const index = PagesMapper.#listeners.indexOf(listener);
const index = this.#listeners.indexOf(listener);
if (index >= 0) {
PagesMapper.#listeners.splice(index, 1);
this.#listeners.splice(index, 1);
}
}

#updateListeners() {
for (const listener of PagesMapper.#listeners) {
for (const listener of this.#listeners) {
listener();
}
}

#init(mustInit) {
if (PagesMapper.#pageNumberToId) {
if (this.#pageNumberToId) {
return;
}
const n = PagesMapper.#pagesNumber;
const n = this.#pagesNumber;

// Allocate a single array for better memory locality.
const array = new Uint32Array(3 * n);
const pageNumberToId = (PagesMapper.#pageNumberToId = array.subarray(0, n));
const idToPageNumber = (PagesMapper.#idToPageNumber = array.subarray(
n,
2 * n
));
const pageNumberToId = (this.#pageNumberToId = array.subarray(0, n));
const idToPageNumber = (this.#idToPageNumber = array.subarray(n, 2 * n));
if (mustInit) {
for (let i = 0; i < n; i++) {
pageNumberToId[i] = idToPageNumber[i] = i + 1;
}
}
PagesMapper.#prevIdToPageNumber = array.subarray(2 * n);
this.#prevIdToPageNumber = array.subarray(2 * n);
}

/**
Expand All @@ -1143,9 +1140,9 @@ class PagesMapper {
*/
movePages(selectedPages, pagesToMove, index) {
this.#init(true);
const pageNumberToId = PagesMapper.#pageNumberToId;
const idToPageNumber = PagesMapper.#idToPageNumber;
PagesMapper.#prevIdToPageNumber.set(idToPageNumber);
const pageNumberToId = this.#pageNumberToId;
const idToPageNumber = this.#idToPageNumber;
this.#prevIdToPageNumber.set(idToPageNumber);
const movedCount = pagesToMove.length;
const mappedPagesToMove = new Uint32Array(movedCount);
let removedBeforeTarget = 0;
Expand All @@ -1158,7 +1155,7 @@ class PagesMapper {
}
}

const pagesNumber = PagesMapper.#pagesNumber;
const pagesNumber = this.#pagesNumber;
// target index after removing elements that were before it
let adjustedTarget = index - removedBeforeTarget;
const remainingLen = pagesNumber - movedCount;
Expand Down Expand Up @@ -1201,7 +1198,7 @@ class PagesMapper {
* @returns {boolean} True if the mappings have been altered, false otherwise.
*/
hasBeenAltered() {
return PagesMapper.#pageNumberToId !== null;
return this.#pageNumberToId !== null;
}

/**
Expand All @@ -1211,16 +1208,14 @@ class PagesMapper {
getPageMappingForSaving() {
// Saving is index-based.
return {
pageIndices: PagesMapper.#idToPageNumber
? PagesMapper.#idToPageNumber.map(x => x - 1)
pageIndices: this.#idToPageNumber
? this.#idToPageNumber.map(x => x - 1)
: null,
};
}

getPrevPageNumber(pageNumber) {
return PagesMapper.#prevIdToPageNumber[
PagesMapper.#pageNumberToId[pageNumber - 1] - 1
];
return this.#prevIdToPageNumber[this.#pageNumberToId[pageNumber - 1] - 1];
}

/**
Expand All @@ -1229,7 +1224,7 @@ class PagesMapper {
* @returns {number} The page number, or the ID itself if no mapping exists.
*/
getPageNumber(id) {
return PagesMapper.#idToPageNumber?.[id - 1] ?? id;
return this.#idToPageNumber?.[id - 1] ?? id;
}

/**
Expand All @@ -1239,19 +1234,11 @@ class PagesMapper {
* exists.
*/
getPageId(pageNumber) {
return PagesMapper.#pageNumberToId?.[pageNumber - 1] ?? pageNumber;
}

/**
* Gets or creates a singleton instance of PagesMapper.
* @returns {PagesMapper} The singleton instance.
*/
static get instance() {
return shadow(this, "instance", new PagesMapper());
return this.#pageNumberToId?.[pageNumber - 1] ?? pageNumber;
}

getMapping() {
return PagesMapper.#pageNumberToId.subarray(0, this.pagesNumber);
return this.#pageNumberToId.subarray(0, this.pagesNumber);
}
}

Expand Down
3 changes: 0 additions & 3 deletions src/pdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ import {
isPdfFile,
noContextMenu,
OutputScale,
PagesMapper,
PDFDateString,
PixelsPerInch,
RenderingCancelledException,
Expand Down Expand Up @@ -129,7 +128,6 @@ globalThis.pdfjsLib = {
normalizeUnicode,
OPS,
OutputScale,
PagesMapper,
PasswordResponses,
PDFDataRangeTransport,
PDFDateString,
Expand Down Expand Up @@ -189,7 +187,6 @@ export {
normalizeUnicode,
OPS,
OutputScale,
PagesMapper,
PasswordResponses,
PDFDataRangeTransport,
PDFDateString,
Expand Down
Loading