Merge pull request #16108 from Snuffleupagus/delay-cleanup
Slightly delay cleanup, after rendering, in documents with large images
This commit is contained in:
commit
9819f1cc6b
@ -13,7 +13,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert, shadow, unreachable, warn } from "../shared/util.js";
|
import {
|
||||||
|
assert,
|
||||||
|
MAX_IMAGE_SIZE_TO_CACHE,
|
||||||
|
shadow,
|
||||||
|
unreachable,
|
||||||
|
warn,
|
||||||
|
} from "../shared/util.js";
|
||||||
import { RefSetCache } from "./primitives.js";
|
import { RefSetCache } from "./primitives.js";
|
||||||
|
|
||||||
class BaseLocalCache {
|
class BaseLocalCache {
|
||||||
@ -160,7 +166,7 @@ class GlobalImageCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get MAX_BYTE_SIZE() {
|
static get MAX_BYTE_SIZE() {
|
||||||
return shadow(this, "MAX_BYTE_SIZE", /* Forty megabytes = */ 40e6);
|
return shadow(this, "MAX_BYTE_SIZE", 5 * MAX_IMAGE_SIZE_TO_CACHE);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -26,6 +26,7 @@ import {
|
|||||||
info,
|
info,
|
||||||
InvalidPDFException,
|
InvalidPDFException,
|
||||||
isArrayBuffer,
|
isArrayBuffer,
|
||||||
|
MAX_IMAGE_SIZE_TO_CACHE,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
PasswordException,
|
PasswordException,
|
||||||
RenderingIntentFlag,
|
RenderingIntentFlag,
|
||||||
@ -66,6 +67,7 @@ import { XfaText } from "./xfa_text.js";
|
|||||||
|
|
||||||
const DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536
|
const DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536
|
||||||
const RENDERING_CANCELLED_TIMEOUT = 100; // ms
|
const RENDERING_CANCELLED_TIMEOUT = 100; // ms
|
||||||
|
const DELAYED_CLEANUP_TIMEOUT = 5000; // ms
|
||||||
|
|
||||||
let DefaultCanvasFactory = DOMCanvasFactory;
|
let DefaultCanvasFactory = DOMCanvasFactory;
|
||||||
let DefaultCMapReaderFactory = DOMCMapReaderFactory;
|
let DefaultCMapReaderFactory = DOMCMapReaderFactory;
|
||||||
@ -1262,6 +1264,10 @@ class PDFDocumentProxy {
|
|||||||
* Proxy to a `PDFPage` in the worker thread.
|
* Proxy to a `PDFPage` in the worker thread.
|
||||||
*/
|
*/
|
||||||
class PDFPageProxy {
|
class PDFPageProxy {
|
||||||
|
#delayedCleanupTimeout = null;
|
||||||
|
|
||||||
|
#pendingCleanup = false;
|
||||||
|
|
||||||
constructor(pageIndex, pageInfo, transport, pdfBug = false) {
|
constructor(pageIndex, pageInfo, transport, pdfBug = false) {
|
||||||
this._pageIndex = pageIndex;
|
this._pageIndex = pageIndex;
|
||||||
this._pageInfo = pageInfo;
|
this._pageInfo = pageInfo;
|
||||||
@ -1272,8 +1278,7 @@ class PDFPageProxy {
|
|||||||
this.commonObjs = transport.commonObjs;
|
this.commonObjs = transport.commonObjs;
|
||||||
this.objs = new PDFObjects();
|
this.objs = new PDFObjects();
|
||||||
|
|
||||||
this.cleanupAfterRender = false;
|
this._maybeCleanupAfterRender = false;
|
||||||
this.pendingCleanup = false;
|
|
||||||
this._intentStates = new Map();
|
this._intentStates = new Map();
|
||||||
this.destroyed = false;
|
this.destroyed = false;
|
||||||
}
|
}
|
||||||
@ -1413,8 +1418,10 @@ class PDFPageProxy {
|
|||||||
printAnnotationStorage
|
printAnnotationStorage
|
||||||
);
|
);
|
||||||
// If there was a pending destroy, cancel it so no cleanup happens during
|
// If there was a pending destroy, cancel it so no cleanup happens during
|
||||||
// this call to render.
|
// this call to render...
|
||||||
this.pendingCleanup = false;
|
this.#pendingCleanup = false;
|
||||||
|
// ... and ensure that a delayed cleanup is always aborted.
|
||||||
|
this.#abortDelayedCleanup();
|
||||||
|
|
||||||
if (!optionalContentConfigPromise) {
|
if (!optionalContentConfigPromise) {
|
||||||
optionalContentConfigPromise = this._transport.getOptionalContentConfig();
|
optionalContentConfigPromise = this._transport.getOptionalContentConfig();
|
||||||
@ -1455,11 +1462,11 @@ class PDFPageProxy {
|
|||||||
intentState.renderTasks.delete(internalRenderTask);
|
intentState.renderTasks.delete(internalRenderTask);
|
||||||
|
|
||||||
// Attempt to reduce memory usage during *printing*, by always running
|
// Attempt to reduce memory usage during *printing*, by always running
|
||||||
// cleanup once rendering has finished (regardless of cleanupAfterRender).
|
// cleanup immediately once rendering has finished.
|
||||||
if (this.cleanupAfterRender || intentPrint) {
|
if (this._maybeCleanupAfterRender || intentPrint) {
|
||||||
this.pendingCleanup = true;
|
this.#pendingCleanup = true;
|
||||||
}
|
}
|
||||||
this._tryCleanup();
|
this.#tryCleanup(/* delayed = */ !intentPrint);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
internalRenderTask.capability.reject(error);
|
internalRenderTask.capability.reject(error);
|
||||||
@ -1509,7 +1516,7 @@ class PDFPageProxy {
|
|||||||
{ transparency, isOffscreenCanvasSupported },
|
{ transparency, isOffscreenCanvasSupported },
|
||||||
optionalContentConfig,
|
optionalContentConfig,
|
||||||
]) => {
|
]) => {
|
||||||
if (this.pendingCleanup) {
|
if (this.#pendingCleanup) {
|
||||||
complete();
|
complete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1681,7 +1688,9 @@ class PDFPageProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.objs.clear();
|
this.objs.clear();
|
||||||
this.pendingCleanup = false;
|
this.#pendingCleanup = false;
|
||||||
|
this.#abortDelayedCleanup();
|
||||||
|
|
||||||
return Promise.all(waitOn);
|
return Promise.all(waitOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1693,16 +1702,34 @@ class PDFPageProxy {
|
|||||||
* @returns {boolean} Indicates if clean-up was successfully run.
|
* @returns {boolean} Indicates if clean-up was successfully run.
|
||||||
*/
|
*/
|
||||||
cleanup(resetStats = false) {
|
cleanup(resetStats = false) {
|
||||||
this.pendingCleanup = true;
|
this.#pendingCleanup = true;
|
||||||
return this._tryCleanup(resetStats);
|
const success = this.#tryCleanup(/* delayed = */ false);
|
||||||
|
|
||||||
|
if (resetStats && success) {
|
||||||
|
this._stats &&= new StatTimer();
|
||||||
|
}
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to clean up if rendering is in a state where that's possible.
|
* Attempts to clean up if rendering is in a state where that's possible.
|
||||||
* @private
|
* @param {boolean} [delayed] - Delay the cleanup, to e.g. improve zooming
|
||||||
|
* performance in documents with large images.
|
||||||
|
* The default value is `false`.
|
||||||
|
* @returns {boolean} Indicates if clean-up was successfully run.
|
||||||
*/
|
*/
|
||||||
_tryCleanup(resetStats = false) {
|
#tryCleanup(delayed = false) {
|
||||||
if (!this.pendingCleanup) {
|
this.#abortDelayedCleanup();
|
||||||
|
|
||||||
|
if (!this.#pendingCleanup) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (delayed) {
|
||||||
|
this.#delayedCleanupTimeout = setTimeout(() => {
|
||||||
|
this.#delayedCleanupTimeout = null;
|
||||||
|
this.#tryCleanup(/* delayed = */ false);
|
||||||
|
}, DELAYED_CLEANUP_TIMEOUT);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (const { renderTasks, operatorList } of this._intentStates.values()) {
|
for (const { renderTasks, operatorList } of this._intentStates.values()) {
|
||||||
@ -1710,16 +1737,19 @@ class PDFPageProxy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._intentStates.clear();
|
this._intentStates.clear();
|
||||||
this.objs.clear();
|
this.objs.clear();
|
||||||
if (resetStats && this._stats) {
|
this.#pendingCleanup = false;
|
||||||
this._stats = new StatTimer();
|
|
||||||
}
|
|
||||||
this.pendingCleanup = false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#abortDelayedCleanup() {
|
||||||
|
if (this.#delayedCleanupTimeout) {
|
||||||
|
clearTimeout(this.#delayedCleanupTimeout);
|
||||||
|
this.#delayedCleanupTimeout = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@ -1756,7 +1786,7 @@ class PDFPageProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (operatorListChunk.lastChunk) {
|
if (operatorListChunk.lastChunk) {
|
||||||
this._tryCleanup();
|
this.#tryCleanup(/* delayed = */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1814,7 +1844,7 @@ class PDFPageProxy {
|
|||||||
for (const internalRenderTask of intentState.renderTasks) {
|
for (const internalRenderTask of intentState.renderTasks) {
|
||||||
internalRenderTask.operatorListChanged();
|
internalRenderTask.operatorListChanged();
|
||||||
}
|
}
|
||||||
this._tryCleanup();
|
this.#tryCleanup(/* delayed = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intentState.displayReadyCapability) {
|
if (intentState.displayReadyCapability) {
|
||||||
@ -2782,7 +2812,6 @@ class WorkerTransport {
|
|||||||
pageProxy.objs.resolve(id, imageData);
|
pageProxy.objs.resolve(id, imageData);
|
||||||
|
|
||||||
// Heuristic that will allow us not to store large data.
|
// Heuristic that will allow us not to store large data.
|
||||||
const MAX_IMAGE_SIZE_TO_STORE = 8000000;
|
|
||||||
if (imageData) {
|
if (imageData) {
|
||||||
let length;
|
let length;
|
||||||
if (imageData.bitmap) {
|
if (imageData.bitmap) {
|
||||||
@ -2792,8 +2821,8 @@ class WorkerTransport {
|
|||||||
length = imageData.data?.length || 0;
|
length = imageData.data?.length || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length > MAX_IMAGE_SIZE_TO_STORE) {
|
if (length > MAX_IMAGE_SIZE_TO_CACHE) {
|
||||||
pageProxy.cleanupAfterRender = true;
|
pageProxy._maybeCleanupAfterRender = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -26,6 +26,8 @@ if (
|
|||||||
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
const IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
||||||
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
const FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
||||||
|
|
||||||
|
const MAX_IMAGE_SIZE_TO_CACHE = 10e6; // Ten megabytes.
|
||||||
|
|
||||||
// Represent the percentage of the height of a single-line field over
|
// Represent the percentage of the height of a single-line field over
|
||||||
// the font size. Acrobat seems to use this value.
|
// the font size. Acrobat seems to use this value.
|
||||||
const LINE_FACTOR = 1.35;
|
const LINE_FACTOR = 1.35;
|
||||||
@ -1060,6 +1062,7 @@ export {
|
|||||||
isArrayEqual,
|
isArrayEqual,
|
||||||
LINE_DESCENT_FACTOR,
|
LINE_DESCENT_FACTOR,
|
||||||
LINE_FACTOR,
|
LINE_FACTOR,
|
||||||
|
MAX_IMAGE_SIZE_TO_CACHE,
|
||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
objectFromMap,
|
objectFromMap,
|
||||||
objectSize,
|
objectSize,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user