Merge pull request #14245 from Snuffleupagus/PDFPageViewBuffer-class
Convert `PDFPageViewBuffer` to a standard class, and use a `Set` internally
This commit is contained in:
commit
891f21fba6
@ -136,12 +136,12 @@ describe("BaseViewer", function () {
|
|||||||
|
|
||||||
// Ensure that decreasing the size will evict the correct views,
|
// Ensure that decreasing the size will evict the correct views,
|
||||||
// while re-ordering the remaining ones correctly.
|
// while re-ordering the remaining ones correctly.
|
||||||
buffer.resize(3, new Set([1, 2, 3]));
|
buffer.resize(3, new Set([1, 2, 5]));
|
||||||
|
|
||||||
expect(buffer._buffer).toEqual([
|
expect(buffer._buffer).toEqual([
|
||||||
viewsMap.get(1),
|
viewsMap.get(1),
|
||||||
viewsMap.get(2),
|
viewsMap.get(2),
|
||||||
viewsMap.get(3),
|
viewsMap.get(5),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ import {
|
|||||||
getVisibleElements,
|
getVisibleElements,
|
||||||
isPortraitOrientation,
|
isPortraitOrientation,
|
||||||
isValidRotation,
|
isValidRotation,
|
||||||
moveToEndOfArray,
|
|
||||||
parseQueryString,
|
parseQueryString,
|
||||||
waitOnEventOrTimeout,
|
waitOnEventOrTimeout,
|
||||||
WaitOnType,
|
WaitOnType,
|
||||||
@ -864,44 +863,4 @@ describe("ui_utils", function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("moveToEndOfArray", function () {
|
|
||||||
it("works on empty arrays", function () {
|
|
||||||
const data = [];
|
|
||||||
moveToEndOfArray(data, function () {});
|
|
||||||
expect(data).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("works when moving everything", function () {
|
|
||||||
const data = [1, 2, 3, 4, 5];
|
|
||||||
moveToEndOfArray(data, function () {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
expect(data).toEqual([1, 2, 3, 4, 5]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("works when moving some things", function () {
|
|
||||||
const data = [1, 2, 3, 4, 5];
|
|
||||||
moveToEndOfArray(data, function (x) {
|
|
||||||
return x % 2 === 0;
|
|
||||||
});
|
|
||||||
expect(data).toEqual([1, 3, 5, 2, 4]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("works when moving one thing", function () {
|
|
||||||
const data = [1, 2, 3, 4, 5];
|
|
||||||
moveToEndOfArray(data, function (x) {
|
|
||||||
return x === 1;
|
|
||||||
});
|
|
||||||
expect(data).toEqual([2, 3, 4, 5, 1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("works when moving nothing", function () {
|
|
||||||
const data = [1, 2, 3, 4, 5];
|
|
||||||
moveToEndOfArray(data, function (x) {
|
|
||||||
return x === 0;
|
|
||||||
});
|
|
||||||
expect(data).toEqual([1, 2, 3, 4, 5]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,6 @@ import {
|
|||||||
MAX_AUTO_SCALE,
|
MAX_AUTO_SCALE,
|
||||||
MAX_SCALE,
|
MAX_SCALE,
|
||||||
MIN_SCALE,
|
MIN_SCALE,
|
||||||
moveToEndOfArray,
|
|
||||||
PresentationModeState,
|
PresentationModeState,
|
||||||
RendererType,
|
RendererType,
|
||||||
SCROLLBAR_PADDING,
|
SCROLLBAR_PADDING,
|
||||||
@ -92,18 +91,38 @@ const DEFAULT_CACHE_SIZE = 10;
|
|||||||
* @property {IL10n} l10n - Localization service.
|
* @property {IL10n} l10n - Localization service.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function PDFPageViewBuffer(size) {
|
class PDFPageViewBuffer {
|
||||||
const data = [];
|
// Here we rely on the fact that `Set`s preserve the insertion order.
|
||||||
this.push = function (view) {
|
#buf = new Set();
|
||||||
const i = data.indexOf(view);
|
|
||||||
if (i >= 0) {
|
#size = 0;
|
||||||
data.splice(i, 1);
|
|
||||||
|
constructor(size) {
|
||||||
|
this.#size = size;
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof PDFJSDev === "undefined" ||
|
||||||
|
PDFJSDev.test("!PRODUCTION || TESTING")
|
||||||
|
) {
|
||||||
|
Object.defineProperty(this, "_buffer", {
|
||||||
|
get() {
|
||||||
|
return [...this.#buf];
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
data.push(view);
|
}
|
||||||
if (data.length > size) {
|
|
||||||
data.shift().destroy();
|
push(view) {
|
||||||
|
const buf = this.#buf;
|
||||||
|
if (buf.has(view)) {
|
||||||
|
buf.delete(view); // Move the view to the "end" of the buffer.
|
||||||
}
|
}
|
||||||
};
|
buf.add(view);
|
||||||
|
|
||||||
|
if (buf.size > this.#size) {
|
||||||
|
this.#destroyFirstView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After calling resize, the size of the buffer will be `newSize`.
|
* After calling resize, the size of the buffer will be `newSize`.
|
||||||
@ -112,31 +131,38 @@ function PDFPageViewBuffer(size) {
|
|||||||
* `idsToKeep` has no impact on the final size of the buffer; if `idsToKeep`
|
* `idsToKeep` has no impact on the final size of the buffer; if `idsToKeep`
|
||||||
* is larger than `newSize`, some of those pages will be destroyed anyway.
|
* is larger than `newSize`, some of those pages will be destroyed anyway.
|
||||||
*/
|
*/
|
||||||
this.resize = function (newSize, idsToKeep = null) {
|
resize(newSize, idsToKeep = null) {
|
||||||
size = newSize;
|
this.#size = newSize;
|
||||||
|
|
||||||
|
const buf = this.#buf;
|
||||||
if (idsToKeep) {
|
if (idsToKeep) {
|
||||||
moveToEndOfArray(data, function (page) {
|
const ii = buf.size;
|
||||||
return idsToKeep.has(page.id);
|
let i = 1;
|
||||||
});
|
for (const view of buf) {
|
||||||
|
if (idsToKeep.has(view.id)) {
|
||||||
|
buf.delete(view); // Move the view to the "end" of the buffer.
|
||||||
|
buf.add(view);
|
||||||
|
}
|
||||||
|
if (++i > ii) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (data.length > size) {
|
|
||||||
data.shift().destroy();
|
while (buf.size > this.#size) {
|
||||||
|
this.#destroyFirstView();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
this.has = function (view) {
|
has(view) {
|
||||||
return data.includes(view);
|
return this.#buf.has(view);
|
||||||
};
|
}
|
||||||
|
|
||||||
if (
|
#destroyFirstView() {
|
||||||
typeof PDFJSDev === "undefined" ||
|
const firstView = this.#buf.keys().next().value;
|
||||||
PDFJSDev.test("!PRODUCTION || TESTING")
|
|
||||||
) {
|
firstView?.destroy();
|
||||||
Object.defineProperty(this, "_buffer", {
|
this.#buf.delete(firstView);
|
||||||
get() {
|
|
||||||
return data.slice();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +182,8 @@ function isSameScale(oldScale, newScale) {
|
|||||||
* Simple viewer control to display PDF content/pages.
|
* Simple viewer control to display PDF content/pages.
|
||||||
*/
|
*/
|
||||||
class BaseViewer {
|
class BaseViewer {
|
||||||
|
#buffer = null;
|
||||||
|
|
||||||
#scrollModePageState = null;
|
#scrollModePageState = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -518,7 +546,7 @@ class BaseViewer {
|
|||||||
}
|
}
|
||||||
// Add the page to the buffer at the start of drawing. That way it can be
|
// Add the page to the buffer at the start of drawing. That way it can be
|
||||||
// evicted from the buffer and destroyed even if we pause its rendering.
|
// evicted from the buffer and destroyed even if we pause its rendering.
|
||||||
this._buffer.push(pageView);
|
this.#buffer.push(pageView);
|
||||||
};
|
};
|
||||||
this.eventBus._on("pagerender", this._onBeforeDraw);
|
this.eventBus._on("pagerender", this._onBeforeDraw);
|
||||||
|
|
||||||
@ -684,7 +712,7 @@ class BaseViewer {
|
|||||||
this._currentScale = UNKNOWN_SCALE;
|
this._currentScale = UNKNOWN_SCALE;
|
||||||
this._currentScaleValue = null;
|
this._currentScaleValue = null;
|
||||||
this._pageLabels = null;
|
this._pageLabels = null;
|
||||||
this._buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);
|
this.#buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);
|
||||||
this._location = null;
|
this._location = null;
|
||||||
this._pagesRotation = 0;
|
this._pagesRotation = 0;
|
||||||
this._optionalContentConfigPromise = null;
|
this._optionalContentConfigPromise = null;
|
||||||
@ -1153,7 +1181,7 @@ class BaseViewer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
|
const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
|
||||||
this._buffer.resize(newCacheSize, visible.ids);
|
this.#buffer.resize(newCacheSize, visible.ids);
|
||||||
|
|
||||||
this.renderingQueue.renderHighestPriority(visible);
|
this.renderingQueue.renderHighestPriority(visible);
|
||||||
|
|
||||||
@ -1304,7 +1332,7 @@ class BaseViewer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const pageView = this._pages[pageNumber - 1];
|
const pageView = this._pages[pageNumber - 1];
|
||||||
return this._buffer.has(pageView);
|
return this.#buffer.has(pageView);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
|
@ -906,27 +906,6 @@ class ProgressBar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves all elements of an array that satisfy condition to the end of the
|
|
||||||
* array, preserving the order of the rest.
|
|
||||||
*/
|
|
||||||
function moveToEndOfArray(arr, condition) {
|
|
||||||
const moved = [],
|
|
||||||
len = arr.length;
|
|
||||||
let write = 0;
|
|
||||||
for (let read = 0; read < len; ++read) {
|
|
||||||
if (condition(arr[read])) {
|
|
||||||
moved.push(arr[read]);
|
|
||||||
} else {
|
|
||||||
arr[write] = arr[read];
|
|
||||||
++write;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let read = 0; write < len; ++read, ++write) {
|
|
||||||
arr[write] = moved[read];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the active or focused element in current DOM.
|
* Get the active or focused element in current DOM.
|
||||||
*
|
*
|
||||||
@ -1031,7 +1010,6 @@ export {
|
|||||||
MAX_AUTO_SCALE,
|
MAX_AUTO_SCALE,
|
||||||
MAX_SCALE,
|
MAX_SCALE,
|
||||||
MIN_SCALE,
|
MIN_SCALE,
|
||||||
moveToEndOfArray,
|
|
||||||
noContextMenuHandler,
|
noContextMenuHandler,
|
||||||
normalizeWheelEventDelta,
|
normalizeWheelEventDelta,
|
||||||
normalizeWheelEventDirection,
|
normalizeWheelEventDirection,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user