diff --git a/gulpfile.mjs b/gulpfile.mjs index 6d064481e..6cd23af63 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -188,6 +188,9 @@ function createWebpackConfig( BUNDLE_VERSION: versionInfo.version, BUNDLE_BUILD: versionInfo.commit, TESTING: defines.TESTING ?? process.env.TESTING === "true", + BROWSER_PREFERENCES: defaultPreferencesDir + ? getBrowserPreferences(defaultPreferencesDir) + : {}, DEFAULT_PREFERENCES: defaultPreferencesDir ? getDefaultPreferences(defaultPreferencesDir) : {}, @@ -811,17 +814,32 @@ async function parseDefaultPreferences(dir) { "./" + DEFAULT_PREFERENCES_DIR + dir + "app_options.mjs" ); + const browserPrefs = AppOptions.getAll(OptionKind.BROWSER); + if (Object.keys(browserPrefs).length === 0) { + throw new Error("No browser preferences found."); + } const prefs = AppOptions.getAll(OptionKind.PREFERENCE); if (Object.keys(prefs).length === 0) { throw new Error("No default preferences found."); } + fs.writeFileSync( + DEFAULT_PREFERENCES_DIR + dir + "browser_preferences.json", + JSON.stringify(browserPrefs) + ); fs.writeFileSync( DEFAULT_PREFERENCES_DIR + dir + "default_preferences.json", JSON.stringify(prefs) ); } +function getBrowserPreferences(dir) { + const str = fs + .readFileSync(DEFAULT_PREFERENCES_DIR + dir + "browser_preferences.json") + .toString(); + return JSON.parse(str); +} + function getDefaultPreferences(dir) { const str = fs .readFileSync(DEFAULT_PREFERENCES_DIR + dir + "default_preferences.json") @@ -1581,6 +1599,9 @@ function buildLib(defines, dir) { BUNDLE_VERSION: versionInfo.version, BUNDLE_BUILD: versionInfo.commit, TESTING: defines.TESTING ?? process.env.TESTING === "true", + BROWSER_PREFERENCES: getBrowserPreferences( + defines.SKIP_BABEL ? "lib/" : "lib-legacy/" + ), DEFAULT_PREFERENCES: getDefaultPreferences( defines.SKIP_BABEL ? "lib/" : "lib-legacy/" ), diff --git a/web/app.js b/web/app.js index 7c7d4cc34..36ef5d47a 100644 --- a/web/app.js +++ b/web/app.js @@ -120,37 +120,10 @@ class DefaultExternalServices { throw new Error("Not implemented: createScripting"); } - static get supportsPinchToZoom() { - return shadow(this, "supportsPinchToZoom", true); - } - - static get supportsIntegratedFind() { - return shadow(this, "supportsIntegratedFind", false); - } - - static get supportsDocumentFonts() { - return shadow(this, "supportsDocumentFonts", true); - } - - static get supportedMouseWheelZoomModifierKeys() { - return shadow(this, "supportedMouseWheelZoomModifierKeys", { - ctrlKey: true, - metaKey: true, - }); - } - - static get isInAutomation() { - return shadow(this, "isInAutomation", false); - } - static updateEditorStates(data) { throw new Error("Not implemented: updateEditorStates"); } - static get canvasMaxAreaInBytes() { - return shadow(this, "canvasMaxAreaInBytes", -1); - } - static getNimbusExperimentData() { return shadow(this, "getNimbusExperimentData", Promise.resolve(null)); } @@ -421,7 +394,7 @@ const PDFViewerApplication = { async _initializeViewerComponents() { const { appConfig, externalServices, l10n } = this; - const eventBus = externalServices.isInAutomation + const eventBus = AppOptions.get("isInAutomation") ? new AutomationEventBus() : new EventBus(); this.eventBus = eventBus; @@ -722,7 +695,7 @@ const PDFViewerApplication = { }); } - if (!this.supportsDocumentFonts) { + if (!AppOptions.get("supportsDocumentFonts")) { AppOptions.set("disableFontFace", true); this.l10n.get("pdfjs-web-fonts-disabled").then(msg => { console.warn(msg); @@ -825,15 +798,19 @@ const PDFViewerApplication = { }, get supportsPinchToZoom() { - return this.externalServices.supportsPinchToZoom; + return shadow( + this, + "supportsPinchToZoom", + AppOptions.get("supportsPinchToZoom") + ); }, get supportsIntegratedFind() { - return this.externalServices.supportsIntegratedFind; - }, - - get supportsDocumentFonts() { - return this.externalServices.supportsDocumentFonts; + return shadow( + this, + "supportsIntegratedFind", + AppOptions.get("supportsIntegratedFind") + ); }, get loadingBar() { @@ -842,8 +819,20 @@ const PDFViewerApplication = { return shadow(this, "loadingBar", bar); }, - get supportedMouseWheelZoomModifierKeys() { - return this.externalServices.supportedMouseWheelZoomModifierKeys; + get supportsMouseWheelZoomCtrlKey() { + return shadow( + this, + "supportsMouseWheelZoomCtrlKey", + AppOptions.get("supportsMouseWheelZoomCtrlKey") + ); + }, + + get supportsMouseWheelZoomMetaKey() { + return shadow( + this, + "supportsMouseWheelZoomMetaKey", + AppOptions.get("supportsMouseWheelZoomMetaKey") + ); }, initPassiveLoading(file) { @@ -1034,7 +1023,7 @@ const PDFViewerApplication = { // Set the necessary API parameters, using all the available options. const apiParams = AppOptions.getAll(OptionKind.API); const params = { - canvasMaxAreaInBytes: this.externalServices.canvasMaxAreaInBytes, + canvasMaxAreaInBytes: AppOptions.get("canvasMaxAreaInBytes"), ...apiParams, ...args, }; @@ -2648,7 +2637,8 @@ function setZoomDisabledTimeout() { function webViewerWheel(evt) { const { pdfViewer, - supportedMouseWheelZoomModifierKeys, + supportsMouseWheelZoomCtrlKey, + supportsMouseWheelZoomMetaKey, supportsPinchToZoom, } = PDFViewerApplication; @@ -2687,8 +2677,8 @@ function webViewerWheel(evt) { if ( isPinchToZoom || - (evt.ctrlKey && supportedMouseWheelZoomModifierKeys.ctrlKey) || - (evt.metaKey && supportedMouseWheelZoomModifierKeys.metaKey) + (evt.ctrlKey && supportsMouseWheelZoomCtrlKey) || + (evt.metaKey && supportsMouseWheelZoomMetaKey) ) { // Only zoom the pages, not the entire viewer. evt.preventDefault(); diff --git a/web/app_options.js b/web/app_options.js index 65be25b86..b8b592177 100644 --- a/web/app_options.js +++ b/web/app_options.js @@ -41,6 +41,7 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) { } const OptionKind = { + BROWSER: 0x01, VIEWER: 0x02, API: 0x04, WORKER: 0x08, @@ -53,6 +54,42 @@ const OptionKind = { * primitive types and cannot rely on any imported types. */ const defaultOptions = { + canvasMaxAreaInBytes: { + /** @type {number} */ + value: -1, + kind: OptionKind.BROWSER, + }, + isInAutomation: { + /** @type {boolean} */ + value: false, + kind: OptionKind.BROWSER, + }, + supportsDocumentFonts: { + /** @type {boolean} */ + value: true, + kind: OptionKind.BROWSER, + }, + supportsIntegratedFind: { + /** @type {boolean} */ + value: false, + kind: OptionKind.BROWSER, + }, + supportsMouseWheelZoomCtrlKey: { + /** @type {boolean} */ + value: true, + kind: OptionKind.BROWSER, + }, + supportsMouseWheelZoomMetaKey: { + /** @type {boolean} */ + value: true, + kind: OptionKind.BROWSER, + }, + supportsPinchToZoom: { + /** @type {boolean} */ + value: true, + kind: OptionKind.BROWSER, + }, + annotationEditorMode: { /** @type {number} */ value: 0, @@ -367,6 +404,9 @@ class AppOptions { continue; } if (kind === OptionKind.PREFERENCE) { + if (defaultOption.kind & OptionKind.BROWSER) { + throw new Error(`Invalid kind for preference: ${name}`); + } const value = defaultOption.value, valueType = typeof value; diff --git a/web/chromecom.js b/web/chromecom.js index 4d19823fc..74110a0cc 100644 --- a/web/chromecom.js +++ b/web/chromecom.js @@ -352,7 +352,7 @@ class ChromePreferences extends BasePreferences { defaultPrefs = this.defaults; } storageArea.get(defaultPrefs, function (readPrefs) { - resolve(readPrefs); + resolve({ prefs: readPrefs }); }); }; diff --git a/web/firefoxcom.js b/web/firefoxcom.js index 9628f929a..12687a231 100644 --- a/web/firefoxcom.js +++ b/web/firefoxcom.js @@ -14,7 +14,7 @@ */ import { DefaultExternalServices, PDFViewerApplication } from "./app.js"; -import { isPdfFile, PDFDataRangeTransport, shadow } from "pdfjs-lib"; +import { isPdfFile, PDFDataRangeTransport } from "pdfjs-lib"; import { BasePreferences } from "./preferences.js"; import { DEFAULT_SCALE_VALUE } from "./ui_utils.js"; import { L10n } from "./l10n.js"; @@ -434,40 +434,6 @@ class FirefoxExternalServices extends DefaultExternalServices { return FirefoxScripting; } - static get supportsPinchToZoom() { - const support = FirefoxCom.requestSync("supportsPinchToZoom"); - return shadow(this, "supportsPinchToZoom", support); - } - - static get supportsIntegratedFind() { - const support = FirefoxCom.requestSync("supportsIntegratedFind"); - return shadow(this, "supportsIntegratedFind", support); - } - - static get supportsDocumentFonts() { - const support = FirefoxCom.requestSync("supportsDocumentFonts"); - return shadow(this, "supportsDocumentFonts", support); - } - - static get supportedMouseWheelZoomModifierKeys() { - const support = FirefoxCom.requestSync( - "supportedMouseWheelZoomModifierKeys" - ); - return shadow(this, "supportedMouseWheelZoomModifierKeys", support); - } - - static get isInAutomation() { - // Returns the value of `Cu.isInAutomation`, which is only `true` when e.g. - // various test-suites are running in mozilla-central. - const isInAutomation = FirefoxCom.requestSync("isInAutomation"); - return shadow(this, "isInAutomation", isInAutomation); - } - - static get canvasMaxAreaInBytes() { - const maxArea = FirefoxCom.requestSync("getCanvasMaxArea"); - return shadow(this, "canvasMaxAreaInBytes", maxArea); - } - static async getNimbusExperimentData() { const nimbusData = await FirefoxCom.requestAsync( "getNimbusExperimentData", diff --git a/web/genericcom.js b/web/genericcom.js index 384f2f22d..f0ec79712 100644 --- a/web/genericcom.js +++ b/web/genericcom.js @@ -34,7 +34,7 @@ class GenericPreferences extends BasePreferences { } async _readFromStorage(prefObj) { - return JSON.parse(localStorage.getItem("pdfjs.preferences")); + return { prefs: JSON.parse(localStorage.getItem("pdfjs.preferences")) }; } } diff --git a/web/preferences.js b/web/preferences.js index faa64a51a..b669f3742 100644 --- a/web/preferences.js +++ b/web/preferences.js @@ -45,14 +45,25 @@ class BasePreferences { } this.#initializedPromise = this._readFromStorage(this.#defaults).then( - prefs => { + ({ browserPrefs, prefs }) => { + const BROWSER_PREFS = + typeof PDFJSDev === "undefined" + ? AppOptions.getAll(OptionKind.BROWSER) + : PDFJSDev.eval("BROWSER_PREFERENCES"); + const options = Object.create(null); + + for (const [name, defaultVal] of Object.entries(BROWSER_PREFS)) { + const prefVal = browserPrefs?.[name]; + options[name] = + typeof prefVal === typeof defaultVal ? prefVal : defaultVal; + } for (const [name, defaultVal] of Object.entries(this.#defaults)) { const prefVal = prefs?.[name]; // Ignore preferences whose types don't match the default values. - this.#prefs[name] = + options[name] = this.#prefs[name] = typeof prefVal === typeof defaultVal ? prefVal : defaultVal; } - AppOptions.setAll(this.#prefs, /* init = */ true); + AppOptions.setAll(options, /* init = */ true); } ); }