mirror of
https://github.com/zen-browser/pdf.js.git
synced 2025-07-07 17:05:38 +02:00
Add an option to enable/disable hardware acceleration (bug 1902012)
This commit is contained in:
parent
341ff40e74
commit
ff6180a4c9
13 changed files with 62 additions and 12 deletions
|
@ -45,6 +45,11 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"enableHWA": {
|
||||||
|
"description": "Whether to enable hardware acceleration.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"enableML": {
|
"enableML": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
|
|
@ -242,7 +242,7 @@ class FakeUnicodeFont {
|
||||||
this.fontFamily = fontFamily;
|
this.fontFamily = fontFamily;
|
||||||
|
|
||||||
const canvas = new OffscreenCanvas(1, 1);
|
const canvas = new OffscreenCanvas(1, 1);
|
||||||
this.ctxMeasure = canvas.getContext("2d");
|
this.ctxMeasure = canvas.getContext("2d", { willReadFrequently: true });
|
||||||
|
|
||||||
if (!FakeUnicodeFont._fontNameId) {
|
if (!FakeUnicodeFont._fontNameId) {
|
||||||
FakeUnicodeFont._fontNameId = 1;
|
FakeUnicodeFont._fontNameId = 1;
|
||||||
|
|
|
@ -213,6 +213,8 @@ const DefaultStandardFontDataFactory =
|
||||||
* when creating canvases. The default value is {new DOMCanvasFactory()}.
|
* when creating canvases. The default value is {new DOMCanvasFactory()}.
|
||||||
* @property {Object} [filterFactory] - A factory instance that will be used
|
* @property {Object} [filterFactory] - A factory instance that will be used
|
||||||
* to create SVG filters when rendering some images on the main canvas.
|
* to create SVG filters when rendering some images on the main canvas.
|
||||||
|
* @property {boolean} [enableHWA] - Enables hardware acceleration for
|
||||||
|
* rendering. The default value is `false`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -297,6 +299,7 @@ function getDocument(src) {
|
||||||
const disableStream = src.disableStream === true;
|
const disableStream = src.disableStream === true;
|
||||||
const disableAutoFetch = src.disableAutoFetch === true;
|
const disableAutoFetch = src.disableAutoFetch === true;
|
||||||
const pdfBug = src.pdfBug === true;
|
const pdfBug = src.pdfBug === true;
|
||||||
|
const enableHWA = src.enableHWA === true;
|
||||||
|
|
||||||
// Parameters whose default values depend on other parameters.
|
// Parameters whose default values depend on other parameters.
|
||||||
const length = rangeTransport ? rangeTransport.length : src.length ?? NaN;
|
const length = rangeTransport ? rangeTransport.length : src.length ?? NaN;
|
||||||
|
@ -315,7 +318,7 @@ function getDocument(src) {
|
||||||
isValidFetchUrl(cMapUrl, document.baseURI) &&
|
isValidFetchUrl(cMapUrl, document.baseURI) &&
|
||||||
isValidFetchUrl(standardFontDataUrl, document.baseURI));
|
isValidFetchUrl(standardFontDataUrl, document.baseURI));
|
||||||
const canvasFactory =
|
const canvasFactory =
|
||||||
src.canvasFactory || new DefaultCanvasFactory({ ownerDocument });
|
src.canvasFactory || new DefaultCanvasFactory({ ownerDocument, enableHWA });
|
||||||
const filterFactory =
|
const filterFactory =
|
||||||
src.filterFactory || new DefaultFilterFactory({ docId, ownerDocument });
|
src.filterFactory || new DefaultFilterFactory({ docId, ownerDocument });
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,13 @@ class BaseFilterFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseCanvasFactory {
|
class BaseCanvasFactory {
|
||||||
constructor() {
|
#enableHWA = false;
|
||||||
|
|
||||||
|
constructor({ enableHWA = false } = {}) {
|
||||||
if (this.constructor === BaseCanvasFactory) {
|
if (this.constructor === BaseCanvasFactory) {
|
||||||
unreachable("Cannot initialize BaseCanvasFactory.");
|
unreachable("Cannot initialize BaseCanvasFactory.");
|
||||||
}
|
}
|
||||||
|
this.#enableHWA = enableHWA;
|
||||||
}
|
}
|
||||||
|
|
||||||
create(width, height) {
|
create(width, height) {
|
||||||
|
@ -59,7 +62,9 @@ class BaseCanvasFactory {
|
||||||
const canvas = this._createCanvas(width, height);
|
const canvas = this._createCanvas(width, height);
|
||||||
return {
|
return {
|
||||||
canvas,
|
canvas,
|
||||||
context: canvas.getContext("2d"),
|
context: canvas.getContext("2d", {
|
||||||
|
willReadFrequently: !this.#enableHWA,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -477,8 +477,8 @@ class DOMFilterFactory extends BaseFilterFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DOMCanvasFactory extends BaseCanvasFactory {
|
class DOMCanvasFactory extends BaseCanvasFactory {
|
||||||
constructor({ ownerDocument = globalThis.document } = {}) {
|
constructor({ ownerDocument = globalThis.document, enableHWA = false } = {}) {
|
||||||
super();
|
super({ enableHWA });
|
||||||
this._document = ownerDocument;
|
this._document = ownerDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,7 @@ class ImageManager {
|
||||||
// behavior in Safari.
|
// behavior in Safari.
|
||||||
const svg = `data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 1 1" width="1" height="1" xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1" style="fill:red;"/></svg>`;
|
const svg = `data:image/svg+xml;charset=UTF-8,<svg viewBox="0 0 1 1" width="1" height="1" xmlns="http://www.w3.org/2000/svg"><rect width="1" height="1" style="fill:red;"/></svg>`;
|
||||||
const canvas = new OffscreenCanvas(1, 3);
|
const canvas = new OffscreenCanvas(1, 3);
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
||||||
const image = new Image();
|
const image = new Image();
|
||||||
image.src = svg;
|
image.src = svg;
|
||||||
const promise = image.decode().then(() => {
|
const promise = image.decode().then(() => {
|
||||||
|
|
|
@ -447,7 +447,10 @@ class TextLayer {
|
||||||
canvas.className = "hiddenCanvasElement";
|
canvas.className = "hiddenCanvasElement";
|
||||||
canvas.lang = lang;
|
canvas.lang = lang;
|
||||||
document.body.append(canvas);
|
document.body.append(canvas);
|
||||||
canvasContext = canvas.getContext("2d", { alpha: false });
|
canvasContext = canvas.getContext("2d", {
|
||||||
|
alpha: false,
|
||||||
|
willReadFrequently: true,
|
||||||
|
});
|
||||||
this.#canvasContexts.set(lang, canvasContext);
|
this.#canvasContexts.set(lang, canvasContext);
|
||||||
}
|
}
|
||||||
return canvasContext;
|
return canvasContext;
|
||||||
|
|
|
@ -439,6 +439,7 @@ const PDFViewerApplication = {
|
||||||
)
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const enableHWA = AppOptions.get("enableHWA");
|
||||||
const pdfViewer = new PDFViewer({
|
const pdfViewer = new PDFViewer({
|
||||||
container,
|
container,
|
||||||
viewer,
|
viewer,
|
||||||
|
@ -465,6 +466,7 @@ const PDFViewerApplication = {
|
||||||
pageColors,
|
pageColors,
|
||||||
mlManager: this.mlManager,
|
mlManager: this.mlManager,
|
||||||
abortSignal: this._globalAbortController.signal,
|
abortSignal: this._globalAbortController.signal,
|
||||||
|
enableHWA,
|
||||||
});
|
});
|
||||||
this.pdfViewer = pdfViewer;
|
this.pdfViewer = pdfViewer;
|
||||||
|
|
||||||
|
@ -480,6 +482,7 @@ const PDFViewerApplication = {
|
||||||
linkService: pdfLinkService,
|
linkService: pdfLinkService,
|
||||||
pageColors,
|
pageColors,
|
||||||
abortSignal: this._globalAbortController.signal,
|
abortSignal: this._globalAbortController.signal,
|
||||||
|
enableHWA,
|
||||||
});
|
});
|
||||||
pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
|
pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,6 +310,11 @@ const defaultOptions = {
|
||||||
value: "",
|
value: "",
|
||||||
kind: OptionKind.API,
|
kind: OptionKind.API,
|
||||||
},
|
},
|
||||||
|
enableHWA: {
|
||||||
|
/** @type {boolean} */
|
||||||
|
value: false,
|
||||||
|
kind: OptionKind.API + OptionKind.VIEWER + OptionKind.PREFERENCE,
|
||||||
|
},
|
||||||
enableXfa: {
|
enableXfa: {
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
value: true,
|
value: true,
|
||||||
|
|
|
@ -81,6 +81,8 @@ import { XfaLayerBuilder } from "./xfa_layer_builder.js";
|
||||||
* @property {IL10n} [l10n] - Localization service.
|
* @property {IL10n} [l10n] - Localization service.
|
||||||
* @property {Object} [layerProperties] - The object that is used to lookup
|
* @property {Object} [layerProperties] - The object that is used to lookup
|
||||||
* the necessary layer-properties.
|
* the necessary layer-properties.
|
||||||
|
* @property {boolean} [enableHWA] - Enables hardware acceleration for
|
||||||
|
* rendering. The default value is `false`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const DEFAULT_LAYER_PROPERTIES =
|
const DEFAULT_LAYER_PROPERTIES =
|
||||||
|
@ -113,6 +115,8 @@ const LAYERS_ORDER = new Map([
|
||||||
class PDFPageView {
|
class PDFPageView {
|
||||||
#annotationMode = AnnotationMode.ENABLE_FORMS;
|
#annotationMode = AnnotationMode.ENABLE_FORMS;
|
||||||
|
|
||||||
|
#enableHWA = false;
|
||||||
|
|
||||||
#hasRestrictedScaling = false;
|
#hasRestrictedScaling = false;
|
||||||
|
|
||||||
#layerProperties = null;
|
#layerProperties = null;
|
||||||
|
@ -163,6 +167,7 @@ class PDFPageView {
|
||||||
this.maxCanvasPixels =
|
this.maxCanvasPixels =
|
||||||
options.maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
|
options.maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
|
||||||
this.pageColors = options.pageColors || null;
|
this.pageColors = options.pageColors || null;
|
||||||
|
this.#enableHWA = options.enableHWA || false;
|
||||||
|
|
||||||
this.eventBus = options.eventBus;
|
this.eventBus = options.eventBus;
|
||||||
this.renderingQueue = options.renderingQueue;
|
this.renderingQueue = options.renderingQueue;
|
||||||
|
@ -981,7 +986,10 @@ class PDFPageView {
|
||||||
canvasWrapper.append(canvas);
|
canvasWrapper.append(canvas);
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d", { alpha: false });
|
const ctx = canvas.getContext("2d", {
|
||||||
|
alpha: false,
|
||||||
|
willReadFrequently: !this.#enableHWA,
|
||||||
|
});
|
||||||
const outputScale = (this.outputScale = new OutputScale());
|
const outputScale = (this.outputScale = new OutputScale());
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -44,6 +44,8 @@ const THUMBNAIL_WIDTH = 98; // px
|
||||||
* @property {Object} [pageColors] - Overwrites background and foreground colors
|
* @property {Object} [pageColors] - Overwrites background and foreground colors
|
||||||
* with user defined ones in order to improve readability in high contrast
|
* with user defined ones in order to improve readability in high contrast
|
||||||
* mode.
|
* mode.
|
||||||
|
* @property {boolean} [enableHWA] - Enables hardware acceleration for
|
||||||
|
* rendering. The default value is `false`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class TempImageFactory {
|
class TempImageFactory {
|
||||||
|
@ -92,6 +94,7 @@ class PDFThumbnailView {
|
||||||
linkService,
|
linkService,
|
||||||
renderingQueue,
|
renderingQueue,
|
||||||
pageColors,
|
pageColors,
|
||||||
|
enableHWA,
|
||||||
}) {
|
}) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.renderingId = "thumbnail" + id;
|
this.renderingId = "thumbnail" + id;
|
||||||
|
@ -103,6 +106,7 @@ class PDFThumbnailView {
|
||||||
this.pdfPageRotate = defaultViewport.rotation;
|
this.pdfPageRotate = defaultViewport.rotation;
|
||||||
this._optionalContentConfigPromise = optionalContentConfigPromise || null;
|
this._optionalContentConfigPromise = optionalContentConfigPromise || null;
|
||||||
this.pageColors = pageColors || null;
|
this.pageColors = pageColors || null;
|
||||||
|
this.enableHWA = enableHWA || false;
|
||||||
|
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.linkService = linkService;
|
this.linkService = linkService;
|
||||||
|
@ -196,11 +200,14 @@ class PDFThumbnailView {
|
||||||
this.resume = null;
|
this.resume = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#getPageDrawContext(upscaleFactor = 1) {
|
#getPageDrawContext(upscaleFactor = 1, enableHWA = this.enableHWA) {
|
||||||
// Keep the no-thumbnail outline visible, i.e. `data-loaded === false`,
|
// Keep the no-thumbnail outline visible, i.e. `data-loaded === false`,
|
||||||
// until rendering/image conversion is complete, to avoid display issues.
|
// until rendering/image conversion is complete, to avoid display issues.
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
const ctx = canvas.getContext("2d", { alpha: false });
|
const ctx = canvas.getContext("2d", {
|
||||||
|
alpha: false,
|
||||||
|
willReadFrequently: !enableHWA,
|
||||||
|
});
|
||||||
const outputScale = new OutputScale();
|
const outputScale = new OutputScale();
|
||||||
|
|
||||||
canvas.width = (upscaleFactor * this.canvasWidth * outputScale.sx) | 0;
|
canvas.width = (upscaleFactor * this.canvasWidth * outputScale.sx) | 0;
|
||||||
|
@ -340,7 +347,7 @@ class PDFThumbnailView {
|
||||||
}
|
}
|
||||||
|
|
||||||
#reduceImage(img) {
|
#reduceImage(img) {
|
||||||
const { ctx, canvas } = this.#getPageDrawContext();
|
const { ctx, canvas } = this.#getPageDrawContext(1, true);
|
||||||
|
|
||||||
if (img.width <= 2 * canvas.width) {
|
if (img.width <= 2 * canvas.width) {
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
|
|
|
@ -44,6 +44,8 @@ const THUMBNAIL_SELECTED_CLASS = "selected";
|
||||||
* mode.
|
* mode.
|
||||||
* @property {AbortSignal} [abortSignal] - The AbortSignal for the window
|
* @property {AbortSignal} [abortSignal] - The AbortSignal for the window
|
||||||
* events.
|
* events.
|
||||||
|
* @property {boolean} [enableHWA] - Enables hardware acceleration for
|
||||||
|
* rendering. The default value is `false`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,12 +62,14 @@ class PDFThumbnailViewer {
|
||||||
renderingQueue,
|
renderingQueue,
|
||||||
pageColors,
|
pageColors,
|
||||||
abortSignal,
|
abortSignal,
|
||||||
|
enableHWA,
|
||||||
}) {
|
}) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
this.linkService = linkService;
|
this.linkService = linkService;
|
||||||
this.renderingQueue = renderingQueue;
|
this.renderingQueue = renderingQueue;
|
||||||
this.pageColors = pageColors || null;
|
this.pageColors = pageColors || null;
|
||||||
|
this.enableHWA = enableHWA || false;
|
||||||
|
|
||||||
this.scroll = watchScroll(
|
this.scroll = watchScroll(
|
||||||
this.container,
|
this.container,
|
||||||
|
@ -206,6 +210,7 @@ class PDFThumbnailViewer {
|
||||||
linkService: this.linkService,
|
linkService: this.linkService,
|
||||||
renderingQueue: this.renderingQueue,
|
renderingQueue: this.renderingQueue,
|
||||||
pageColors: this.pageColors,
|
pageColors: this.pageColors,
|
||||||
|
enableHWA: this.enableHWA,
|
||||||
});
|
});
|
||||||
this._thumbnails.push(thumbnail);
|
this._thumbnails.push(thumbnail);
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,8 @@ function isValidAnnotationEditorMode(mode) {
|
||||||
* @property {Object} [pageColors] - Overwrites background and foreground colors
|
* @property {Object} [pageColors] - Overwrites background and foreground colors
|
||||||
* with user defined ones in order to improve readability in high contrast
|
* with user defined ones in order to improve readability in high contrast
|
||||||
* mode.
|
* mode.
|
||||||
|
* @property {boolean} [enableHWA] - Enables hardware acceleration for
|
||||||
|
* rendering. The default value is `false`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PDFPageViewBuffer {
|
class PDFPageViewBuffer {
|
||||||
|
@ -211,6 +213,8 @@ class PDFViewer {
|
||||||
|
|
||||||
#containerTopLeft = null;
|
#containerTopLeft = null;
|
||||||
|
|
||||||
|
#enableHWA = false;
|
||||||
|
|
||||||
#enableHighlightFloatingButton = false;
|
#enableHighlightFloatingButton = false;
|
||||||
|
|
||||||
#enablePermissions = false;
|
#enablePermissions = false;
|
||||||
|
@ -296,6 +300,7 @@ class PDFViewer {
|
||||||
this.#enablePermissions = options.enablePermissions || false;
|
this.#enablePermissions = options.enablePermissions || false;
|
||||||
this.pageColors = options.pageColors || null;
|
this.pageColors = options.pageColors || null;
|
||||||
this.#mlManager = options.mlManager || null;
|
this.#mlManager = options.mlManager || null;
|
||||||
|
this.#enableHWA = options.enableHWA || false;
|
||||||
|
|
||||||
this.defaultRenderingQueue = !options.renderingQueue;
|
this.defaultRenderingQueue = !options.renderingQueue;
|
||||||
if (
|
if (
|
||||||
|
@ -943,6 +948,7 @@ class PDFViewer {
|
||||||
pageColors,
|
pageColors,
|
||||||
l10n: this.l10n,
|
l10n: this.l10n,
|
||||||
layerProperties: this._layerProperties,
|
layerProperties: this._layerProperties,
|
||||||
|
enableHWA: this.#enableHWA,
|
||||||
});
|
});
|
||||||
this._pages.push(pageView);
|
this._pages.push(pageView);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue