From ba1d68df134797231d038c449cfe4c7416041011 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Wed, 12 Jun 2024 12:51:51 +0200 Subject: [PATCH] Add an option to enable/disable hardware acceleration (bug 1902012) --- extensions/chromium/preferences_schema.json | 5 +++++ src/core/default_appearance.js | 2 +- src/display/api.js | 6 +++++- src/display/base_factory.js | 9 +++++++-- src/display/display_utils.js | 7 +++++-- src/display/editor/tools.js | 2 +- src/display/node_utils.js | 4 ++++ src/display/text_layer.js | 5 ++++- web/app.js | 1 + web/app_options.js | 5 +++++ web/pdf_page_view.js | 10 +++++++++- web/pdf_viewer.js | 7 +++++++ 12 files changed, 54 insertions(+), 9 deletions(-) diff --git a/extensions/chromium/preferences_schema.json b/extensions/chromium/preferences_schema.json index 19bb7d7c642eed..7affa43f7e1f9a 100644 --- a/extensions/chromium/preferences_schema.json +++ b/extensions/chromium/preferences_schema.json @@ -45,6 +45,11 @@ "type": "boolean", "default": false }, + "enableHardwareAcceleration": { + "description": "Whether to enable hardware acceleration.", + "type": "boolean", + "default": false + }, "enableML": { "type": "boolean", "default": false diff --git a/src/core/default_appearance.js b/src/core/default_appearance.js index cb84b1a7e7ac21..740a037c645db5 100644 --- a/src/core/default_appearance.js +++ b/src/core/default_appearance.js @@ -242,7 +242,7 @@ class FakeUnicodeFont { this.fontFamily = fontFamily; const canvas = new OffscreenCanvas(1, 1); - this.ctxMeasure = canvas.getContext("2d"); + this.ctxMeasure = canvas.getContext("2d", { willReadFrequently: true }); if (!FakeUnicodeFont._fontNameId) { FakeUnicodeFont._fontNameId = 1; diff --git a/src/display/api.js b/src/display/api.js index fd7ba98cc9f813..50f76340f16f1b 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -213,6 +213,8 @@ const DefaultStandardFontDataFactory = * when creating canvases. The default value is {new DOMCanvasFactory()}. * @property {Object} [filterFactory] - A factory instance that will be used * to create SVG filters when rendering some images on the main canvas. + * @property {boolean} [enableHardwareAcceleration] - Enables hardware + * acceleration for rendering. The default value is `false`. */ /** @@ -314,8 +316,10 @@ function getDocument(src) { standardFontDataUrl && isValidFetchUrl(cMapUrl, document.baseURI) && isValidFetchUrl(standardFontDataUrl, document.baseURI)); + const enableHardwareAcceleration = src.enableHardwareAcceleration === true; const canvasFactory = - src.canvasFactory || new DefaultCanvasFactory({ ownerDocument }); + src.canvasFactory || + new DefaultCanvasFactory({ ownerDocument, enableHardwareAcceleration }); const filterFactory = src.filterFactory || new DefaultFilterFactory({ docId, ownerDocument }); diff --git a/src/display/base_factory.js b/src/display/base_factory.js index 09280cf903e3ad..02f220fa0fb076 100644 --- a/src/display/base_factory.js +++ b/src/display/base_factory.js @@ -46,10 +46,13 @@ class BaseFilterFactory { } class BaseCanvasFactory { - constructor() { + #enableHardwareAcceleration = false; + + constructor(enableHardwareAcceleration = false) { if (this.constructor === BaseCanvasFactory) { unreachable("Cannot initialize BaseCanvasFactory."); } + this.#enableHardwareAcceleration = enableHardwareAcceleration; } create(width, height) { @@ -59,7 +62,9 @@ class BaseCanvasFactory { const canvas = this._createCanvas(width, height); return { canvas, - context: canvas.getContext("2d"), + context: canvas.getContext("2d", { + willReadFrequently: !this.#enableHardwareAcceleration, + }), }; } diff --git a/src/display/display_utils.js b/src/display/display_utils.js index adf9cbdea9d729..0d10c8abae8067 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -477,8 +477,11 @@ class DOMFilterFactory extends BaseFilterFactory { } class DOMCanvasFactory extends BaseCanvasFactory { - constructor({ ownerDocument = globalThis.document } = {}) { - super(); + constructor({ + ownerDocument = globalThis.document, + enableHardwareAcceleration = false, + } = {}) { + super(enableHardwareAcceleration); this._document = ownerDocument; } diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index dd277b7c3f523c..14444cf9461fa4 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -98,7 +98,7 @@ class ImageManager { // behavior in Safari. const svg = `data:image/svg+xml;charset=UTF-8,`; const canvas = new OffscreenCanvas(1, 3); - const ctx = canvas.getContext("2d"); + const ctx = canvas.getContext("2d", { willReadFrequently: true }); const image = new Image(); image.src = svg; const promise = image.decode().then(() => { diff --git a/src/display/node_utils.js b/src/display/node_utils.js index aca4ad750fad7d..eb6e3b08af5134 100644 --- a/src/display/node_utils.js +++ b/src/display/node_utils.js @@ -117,6 +117,10 @@ const fetchData = function (url) { class NodeFilterFactory extends BaseFilterFactory {} class NodeCanvasFactory extends BaseCanvasFactory { + constructor({ enableHardwareAcceleration = false } = {}) { + super(enableHardwareAcceleration); + } + /** * @ignore */ diff --git a/src/display/text_layer.js b/src/display/text_layer.js index 1ff8ac26b5e6ef..df35dfb4e5b739 100644 --- a/src/display/text_layer.js +++ b/src/display/text_layer.js @@ -447,7 +447,10 @@ class TextLayer { canvas.className = "hiddenCanvasElement"; canvas.lang = lang; document.body.append(canvas); - canvasContext = canvas.getContext("2d", { alpha: false }); + canvasContext = canvas.getContext("2d", { + alpha: false, + willReadFrequently: true, + }); this.#canvasContexts.set(lang, canvasContext); } return canvasContext; diff --git a/web/app.js b/web/app.js index d75800ae38766f..bbed886773e886 100644 --- a/web/app.js +++ b/web/app.js @@ -465,6 +465,7 @@ const PDFViewerApplication = { pageColors, mlManager: this.mlManager, abortSignal: this._globalAbortController.signal, + enableHardwareAcceleration: AppOptions.get("enableHardwareAcceleration"), }); this.pdfViewer = pdfViewer; diff --git a/web/app_options.js b/web/app_options.js index 61311172cf5cba..2b48a5ee1748b1 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -310,6 +310,11 @@ const defaultOptions = { value: "", kind: OptionKind.API, }, + enableHardwareAcceleration: { + /** @type {boolean} */ + value: false, + kind: OptionKind.API + OptionKind.PREFERENCE + OptionKind.VIEWER, + }, enableXfa: { /** @type {boolean} */ value: true, diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index b40f2dcc507c54..2d16983a1513c2 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -81,6 +81,8 @@ import { XfaLayerBuilder } from "./xfa_layer_builder.js"; * @property {IL10n} [l10n] - Localization service. * @property {Object} [layerProperties] - The object that is used to lookup * the necessary layer-properties. + * @property {boolean} [enableHardwareAcceleration] - Enables hardware + * acceleration for rendering. The default value is `false`. */ const DEFAULT_LAYER_PROPERTIES = @@ -113,6 +115,8 @@ const LAYERS_ORDER = new Map([ class PDFPageView { #annotationMode = AnnotationMode.ENABLE_FORMS; + #enableHardwareAcceleration = false; + #hasRestrictedScaling = false; #layerProperties = null; @@ -163,6 +167,7 @@ class PDFPageView { this.maxCanvasPixels = options.maxCanvasPixels ?? AppOptions.get("maxCanvasPixels"); this.pageColors = options.pageColors || null; + this.#enableHardwareAcceleration = !!options.enableHardwareAcceleration; this.eventBus = options.eventBus; this.renderingQueue = options.renderingQueue; @@ -981,7 +986,10 @@ class PDFPageView { canvasWrapper.append(canvas); this.canvas = canvas; - const ctx = canvas.getContext("2d", { alpha: false }); + const ctx = canvas.getContext("2d", { + alpha: false, + willReadFrequently: !this.#enableHardwareAcceleration, + }); const outputScale = (this.outputScale = new OutputScale()); if ( diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 3d373c804bb339..eaaa46686a10dd 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -123,6 +123,8 @@ function isValidAnnotationEditorMode(mode) { * @property {Object} [pageColors] - Overwrites background and foreground colors * with user defined ones in order to improve readability in high contrast * mode. + * @property {boolean} [enableHardwareAcceleration] - Enables hardware + * acceleration for rendering. The default value is `false`. */ class PDFPageViewBuffer { @@ -211,6 +213,8 @@ class PDFViewer { #containerTopLeft = null; + #enableHardwareAcceleration = false; + #enableHighlightFloatingButton = false; #enablePermissions = false; @@ -296,6 +300,8 @@ class PDFViewer { this.#enablePermissions = options.enablePermissions || false; this.pageColors = options.pageColors || null; this.#mlManager = options.mlManager || null; + this.#enableHardwareAcceleration = + options.enableHardwareAcceleration || false; this.defaultRenderingQueue = !options.renderingQueue; if ( @@ -943,6 +949,7 @@ class PDFViewer { pageColors, l10n: this.l10n, layerProperties: this._layerProperties, + enableHardwareAcceleration: this.#enableHardwareAcceleration, }); this._pages.push(pageView); }