diff options
Diffstat (limited to 'toolkit/components/pdfjs/content/web')
7 files changed, 768 insertions, 455 deletions
diff --git a/toolkit/components/pdfjs/content/web/images/gv-toolbarButton-openinapp.svg b/toolkit/components/pdfjs/content/web/images/gv-toolbarButton-openinapp.svg deleted file mode 100644 index 80ec891aad..0000000000 --- a/toolkit/components/pdfjs/content/web/images/gv-toolbarButton-openinapp.svg +++ /dev/null @@ -1,11 +0,0 @@ -<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M4 4.5H6.5V7H4V4.5Z" fill="black"/> -<path d="M6.5 10.5H4V13H6.5V10.5Z" fill="black"/> -<path d="M13.25 10.5H10.75V13H13.25V10.5Z" fill="black"/> -<path d="M17.5 10.5H20V13H17.5V10.5Z" fill="black"/> -<path d="M6.5 16.5H4V19H6.5V16.5Z" fill="black"/> -<path d="M10.75 16.5H13.25V19H10.75V16.5Z" fill="black"/> -<path d="M20 16.5H17.5V19H20V16.5Z" fill="black"/> -<path d="M13.25 4.5H10.75V7H13.25V4.5Z" fill="black"/> -<path d="M17.5 4.5H20V7H17.5V4.5Z" fill="black"/> -</svg> diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.css b/toolkit/components/pdfjs/content/web/viewer-geckoview.css index 16e27e4eac..c336b4f7fc 100644 --- a/toolkit/components/pdfjs/content/web/viewer-geckoview.css +++ b/toolkit/components/pdfjs/content/web/viewer-geckoview.css @@ -23,7 +23,6 @@ text-size-adjust:none; forced-color-adjust:none; transform-origin:0 0; - z-index:2; caret-color:CanvasText; &.highlighting{ @@ -162,7 +161,6 @@ left:0; pointer-events:none; transform-origin:0 0; - z-index:3; &[data-main-rotation="90"] .norotate{ transform:rotate(270deg) translateX(-100%); @@ -817,7 +815,6 @@ overflow:hidden; width:100%; height:100%; - z-index:1; } .pdfViewer .page{ @@ -947,7 +944,6 @@ --toolbar-fg-color:#15141a; --toolbarButton-download-icon:url(images/gv-toolbarButton-download.svg); - --toolbarButton-openinapp-icon:url(images/gv-toolbarButton-openinapp.svg); } :root:dir(rtl){ @@ -1140,10 +1136,6 @@ body{ mask-image:var(--toolbarButton-download-icon); } -#openInApp::before{ - mask-image:var(--toolbarButton-openinapp-icon); -} - .dialogButton{ width:auto; margin:3px 4px 2px !important; diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.html b/toolkit/components/pdfjs/content/web/viewer-geckoview.html index 1c0296a481..ba52e298ed 100644 --- a/toolkit/components/pdfjs/content/web/viewer-geckoview.html +++ b/toolkit/components/pdfjs/content/web/viewer-geckoview.html @@ -45,9 +45,6 @@ See https://github.com/adobe-type-tools/cmap-resources <button id="download" class="toolbarButton" title="Download" tabindex="31" data-l10n-id="pdfjs-download-button"> <span data-l10n-id="pdfjs-download-button-label">Download</span> </button> - <button id="openInApp" class="toolbarButton" title="Open in app" tabindex="32" data-l10n-id="pdfjs-open-in-app-button"> - <span data-l10n-id="pdfjs-open-in-app-button-label">Open in app</span> - </button> </div> <div id="viewerContainer" tabindex="0"> diff --git a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs index 8ba8147a9f..866c4a405a 100644 --- a/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs +++ b/toolkit/components/pdfjs/content/web/viewer-geckoview.mjs @@ -606,6 +606,10 @@ const defaultOptions = { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, + enableHighlightFloatingButton: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, enableML: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE @@ -651,7 +655,7 @@ const defaultOptions = { kind: OptionKind.VIEWER }, maxCanvasPixels: { - value: 16777216, + value: 2 ** 25, kind: OptionKind.VIEWER }, forcePageColors: { @@ -768,28 +772,20 @@ class AppOptions { constructor() { throw new Error("Cannot initialize AppOptions."); } + static getCompat(name) { + return compatibilityParams[name] ?? undefined; + } static get(name) { - const userOption = userOptions[name]; - if (userOption !== undefined) { - return userOption; - } - const defaultOption = defaultOptions[name]; - if (defaultOption !== undefined) { - return compatibilityParams[name] ?? defaultOption.value; - } - return undefined; + return userOptions[name] ?? compatibilityParams[name] ?? defaultOptions[name]?.value ?? undefined; } - static getAll(kind = null) { + static getAll(kind = null, defaultOnly = false) { const options = Object.create(null); for (const name in defaultOptions) { const defaultOption = defaultOptions[name]; - if (kind) { - if (!(kind & defaultOption.kind)) { - continue; - } + if (kind && !(kind & defaultOption.kind)) { + continue; } - const userOption = userOptions[name]; - options[name] = userOption !== undefined ? userOption : compatibilityParams[name] ?? defaultOption.value; + options[name] = defaultOnly ? defaultOption.value : userOptions[name] ?? compatibilityParams[name] ?? defaultOption.value; } return options; } @@ -1112,30 +1108,7 @@ class PDFLinkService { if (pdfDocument !== this.pdfDocument) { return; } - let operator; - for (const elem of action.state) { - switch (elem) { - case "ON": - case "OFF": - case "Toggle": - operator = elem; - continue; - } - switch (operator) { - case "ON": - optionalContentConfig.setVisibility(elem, true); - break; - case "OFF": - optionalContentConfig.setVisibility(elem, false); - break; - case "Toggle": - const group = optionalContentConfig.getGroup(elem); - if (group) { - optionalContentConfig.setVisibility(elem, !group.visible); - } - break; - } - } + optionalContentConfig.setOCGState(action); this.pdfViewer.optionalContentConfigPromise = Promise.resolve(optionalContentConfig); } cachePageRef(pageNum, pageRef) { @@ -1423,7 +1396,7 @@ class BaseExternalServices { } updateFindControlState(data) {} updateFindMatchesCount(data) {} - initPassiveLoading(callbacks) {} + initPassiveLoading() {} reportTelemetry(data) {} async createL10n() { throw new Error("Not implemented: createL10n"); @@ -1440,6 +1413,16 @@ class BaseExternalServices { ;// CONCATENATED MODULE: ./web/preferences.js class BasePreferences { + #browserDefaults = Object.freeze({ + canvasMaxAreaInBytes: -1, + isInAutomation: false, + supportsCaretBrowsingMode: false, + supportsDocumentFonts: true, + supportsIntegratedFind: false, + supportsMouseWheelZoomCtrlKey: true, + supportsMouseWheelZoomMetaKey: true, + supportsPinchToZoom: true + }); #defaults = Object.freeze({ annotationEditorMode: 0, annotationMode: 2, @@ -1448,6 +1431,7 @@ class BasePreferences { defaultZoomValue: "", disablePageLabels: false, enableHighlightEditor: false, + enableHighlightFloatingButton: false, enableML: false, enablePermissions: false, enablePrintAutoRotate: true, @@ -1482,26 +1466,19 @@ class BasePreferences { browserPrefs, prefs }) => { - const BROWSER_PREFS = { - canvasMaxAreaInBytes: -1, - isInAutomation: false, - supportsCaretBrowsingMode: false, - supportsDocumentFonts: true, - supportsIntegratedFind: false, - supportsMouseWheelZoomCtrlKey: true, - supportsMouseWheelZoomMetaKey: true, - supportsPinchToZoom: true - }; const options = Object.create(null); - for (const [name, defaultVal] of Object.entries(BROWSER_PREFS)) { + for (const [name, val] of Object.entries(this.#browserDefaults)) { const prefVal = browserPrefs?.[name]; - options[name] = typeof prefVal === typeof defaultVal ? prefVal : defaultVal; + options[name] = typeof prefVal === typeof val ? prefVal : val; } - for (const [name, defaultVal] of Object.entries(this.#defaults)) { + for (const [name, val] of Object.entries(this.#defaults)) { const prefVal = prefs?.[name]; - options[name] = this.#prefs[name] = typeof prefVal === typeof defaultVal ? prefVal : defaultVal; + options[name] = this.#prefs[name] = typeof prefVal === typeof val ? prefVal : val; } AppOptions.setAll(options, true); + window.addEventListener("updatedPreference", evt => { + this.#updatePref(evt.detail); + }); }); } async _writeToStorage(prefObj) { @@ -1510,6 +1487,24 @@ class BasePreferences { async _readFromStorage(prefObj) { throw new Error("Not implemented: _readFromStorage"); } + #updatePref({ + name, + value + }) { + if (name in this.#browserDefaults) { + if (typeof value !== typeof this.#browserDefaults[name]) { + return; + } + } else if (name in this.#defaults) { + if (typeof value !== typeof this.#defaults[name]) { + return; + } + this.#prefs[name] = value; + } else { + return; + } + AppOptions.set(name, value); + } async reset() { throw new Error("Please use `about:config` to change preferences."); } @@ -1517,12 +1512,7 @@ class BasePreferences { throw new Error("Please use `about:config` to change preferences."); } async get(name) { - await this.#initializedPromise; - const defaultValue = this.#defaults[name]; - if (defaultValue === undefined) { - throw new Error(`Get preference: "${name}" is undefined.`); - } - return this.#prefs[name] ?? defaultValue; + throw new Error("Not implemented: get"); } get initializedPromise() { return this.#initializedPromise; @@ -1805,8 +1795,7 @@ class Preferences extends BasePreferences { try { const hasUnchangedAnnotations = pdfDocument.annotationStorage.size === 0; const hasWillPrint = pdfViewer.enableScripting && !!(await pdfDocument.getJSActions())?.WillPrint; - const hasUnchangedOptionalContent = (await pdfViewer.optionalContentConfigPromise).hasInitialVisibility; - result = hasUnchangedAnnotations && !hasWillPrint && hasUnchangedOptionalContent; + result = hasUnchangedAnnotations && !hasWillPrint; } catch { console.warn("Unable to check if the document can be downloaded."); } @@ -1860,7 +1849,7 @@ class ExternalServices extends BaseExternalServices { updateFindMatchesCount(data) { FirefoxCom.request("updateFindMatchesCount", data); } - initPassiveLoading(callbacks) { + initPassiveLoading() { let pdfDataRangeTransport; window.addEventListener("message", function windowMessage(e) { if (e.source !== null) { @@ -1874,11 +1863,13 @@ class ExternalServices extends BaseExternalServices { switch (args.pdfjsLoadAction) { case "supportsRangedLoading": if (args.done && !args.data) { - callbacks.onError(); + viewerApp._documentError(null); break; } pdfDataRangeTransport = new FirefoxComDataRangeTransport(args.length, args.data, args.done, args.filename); - callbacks.onOpenWithTransport(pdfDataRangeTransport); + viewerApp.open({ + range: pdfDataRangeTransport + }); break; case "range": pdfDataRangeTransport.onDataRange(args.begin, args.chunk); @@ -1894,21 +1885,26 @@ class ExternalServices extends BaseExternalServices { pdfDataRangeTransport?.onDataProgressiveDone(); break; case "progress": - callbacks.onProgress(args.loaded, args.total); + viewerApp.progress(args.loaded / args.total); break; case "complete": if (!args.data) { - callbacks.onError(args.errorCode); + viewerApp._documentError(null, { + message: args.errorCode + }); break; } - callbacks.onOpenWithData(args.data, args.filename); + viewerApp.open({ + data: args.data, + filename: args.filename + }); break; } }); FirefoxCom.request("initPassiveLoading", null); } reportTelemetry(data) { - FirefoxCom.request("reportTelemetry", JSON.stringify(data)); + FirefoxCom.request("reportTelemetry", data); } updateEditorStates(data) { FirefoxCom.request("updateEditorStates", data); @@ -3671,14 +3667,15 @@ class FirefoxPrintService { pagesOverview, printContainer, printResolution, - optionalContentConfigPromise = null, printAnnotationStoragePromise = null }) { this.pdfDocument = pdfDocument; this.pagesOverview = pagesOverview; this.printContainer = printContainer; this._printResolution = printResolution || 150; - this._optionalContentConfigPromise = optionalContentConfigPromise || pdfDocument.getOptionalContentConfig(); + this._optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ + intent: "print" + }); this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve(); } layout() { @@ -4206,10 +4203,10 @@ class PDFScriptingManager { class AnnotationEditorLayerBuilder { #annotationLayer = null; #drawLayer = null; + #onAppend = null; #textLayer = null; #uiManager; constructor(options) { - this.pageDiv = options.pageDiv; this.pdfPage = options.pdfPage; this.accessibilityManager = options.accessibilityManager; this.l10n = options.l10n; @@ -4220,6 +4217,7 @@ class AnnotationEditorLayerBuilder { this.#annotationLayer = options.annotationLayer || null; this.#textLayer = options.textLayer || null; this.#drawLayer = options.drawLayer || null; + this.#onAppend = options.onAppend || null; } async render(viewport, intent = "display") { if (intent !== "display") { @@ -4240,10 +4238,9 @@ class AnnotationEditorLayerBuilder { } const div = this.div = document.createElement("div"); div.className = "annotationEditorLayer"; - div.tabIndex = 0; div.hidden = true; div.dir = this.#uiManager.direction; - this.pageDiv.append(div); + this.#onAppend?.(div); this.annotationEditorLayer = new AnnotationEditorLayer({ uiManager: this.#uiManager, div, @@ -4269,9 +4266,7 @@ class AnnotationEditorLayerBuilder { if (!this.div) { return; } - this.pageDiv = null; this.annotationEditorLayer.destroy(); - this.div.remove(); } hide() { if (!this.div) { @@ -4280,7 +4275,7 @@ class AnnotationEditorLayerBuilder { this.div.hidden = true; } show() { - if (!this.div || this.annotationEditorLayer.isEmpty) { + if (!this.div || this.annotationEditorLayer.isInvisible) { return; } this.div.hidden = false; @@ -4291,9 +4286,9 @@ class AnnotationEditorLayerBuilder { class AnnotationLayerBuilder { + #onAppend = null; #onPresentationModeChanged = null; constructor({ - pageDiv, pdfPage, linkService, downloadManager, @@ -4304,9 +4299,9 @@ class AnnotationLayerBuilder { hasJSActionsPromise = null, fieldObjectsPromise = null, annotationCanvasMap = null, - accessibilityManager = null + accessibilityManager = null, + onAppend = null }) { - this.pageDiv = pageDiv; this.pdfPage = pdfPage; this.linkService = linkService; this.downloadManager = downloadManager; @@ -4318,6 +4313,7 @@ class AnnotationLayerBuilder { this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null); this._annotationCanvasMap = annotationCanvasMap; this._accessibilityManager = accessibilityManager; + this.#onAppend = onAppend; this.annotationLayer = null; this.div = null; this._cancelled = false; @@ -4343,7 +4339,7 @@ class AnnotationLayerBuilder { } const div = this.div = document.createElement("div"); div.className = "annotationLayer"; - this.pageDiv.append(div); + this.#onAppend?.(div); if (annotations.length === 0) { this.hide(); return; @@ -4937,13 +4933,15 @@ class TextHighlighter { class TextLayerBuilder { #enablePermissions = false; + #onAppend = null; #rotation = 0; #scale = 0; #textContentSource = null; constructor({ highlighter = null, accessibilityManager = null, - enablePermissions = false + enablePermissions = false, + onAppend = null }) { this.textContentItemsStr = []; this.renderingDone = false; @@ -4953,8 +4951,9 @@ class TextLayerBuilder { this.highlighter = highlighter; this.accessibilityManager = accessibilityManager; this.#enablePermissions = enablePermissions === true; - this.onAppend = null; + this.#onAppend = onAppend; this.div = document.createElement("div"); + this.div.tabIndex = 0; this.div.className = "textLayer"; } #finishRendering() { @@ -5009,7 +5008,7 @@ class TextLayerBuilder { this.#finishRendering(); this.#scale = scale; this.#rotation = rotation; - this.onAppend(this.div); + this.#onAppend?.(this.div); this.highlighter?.enable(); this.accessibilityManager?.enable(); } @@ -5083,8 +5082,8 @@ class TextLayerBuilder { -const MAX_CANVAS_PIXELS = compatibilityParams.maxCanvasPixels || 16777216; const DEFAULT_LAYER_PROPERTIES = null; +const LAYERS_ORDER = new Map([["canvasWrapper", 0], ["textLayer", 1], ["annotationLayer", 2], ["annotationEditorLayer", 3], ["xfaLayer", 3]]); class PDFPageView { #annotationMode = AnnotationMode.ENABLE_FORMS; #hasRestrictedScaling = false; @@ -5100,6 +5099,7 @@ class PDFPageView { regularAnnotations: true }; #viewportMap = new WeakMap(); + #layers = [null, null, null, null]; constructor(options) { const container = options.container; const defaultViewport = options.defaultViewport; @@ -5116,7 +5116,7 @@ class PDFPageView { this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE; this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS; this.imageResourcesPath = options.imageResourcesPath || ""; - this.maxCanvasPixels = options.maxCanvasPixels ?? MAX_CANVAS_PIXELS; + this.maxCanvasPixels = options.maxCanvasPixels ?? (AppOptions.getCompat("maxCanvasPixels") || 2 ** 25); this.pageColors = options.pageColors || null; this.eventBus = options.eventBus; this.renderingQueue = options.renderingQueue; @@ -5143,6 +5143,23 @@ class PDFPageView { this.#setDimensions(); container?.append(div); } + #addLayer(div, name) { + const pos = LAYERS_ORDER.get(name); + const oldDiv = this.#layers[pos]; + this.#layers[pos] = div; + if (oldDiv) { + oldDiv.replaceWith(div); + return; + } + for (let i = pos - 1; i >= 0; i--) { + const layer = this.#layers[i]; + if (layer) { + layer.after(div); + return; + } + } + this.div.prepend(div); + } get renderingState() { return this.#renderingState; } @@ -5256,7 +5273,7 @@ class PDFPageView { } finally { if (this.xfaLayer?.div) { this.l10n.pause(); - this.div.append(this.xfaLayer.div); + this.#addLayer(this.xfaLayer.div, "xfaLayer"); this.l10n.resume(); } this.eventBus.dispatch("xfalayerrendered", { @@ -5368,6 +5385,10 @@ class PDFPageView { continue; } node.remove(); + const layerIndex = this.#layers.indexOf(node); + if (layerIndex >= 0) { + this.#layers[layerIndex] = null; + } } div.removeAttribute("data-loaded"); if (annotationLayerNode) { @@ -5627,19 +5648,20 @@ class PDFPageView { this.renderingState = RenderingStates.RUNNING; const canvasWrapper = document.createElement("div"); canvasWrapper.classList.add("canvasWrapper"); - div.append(canvasWrapper); + canvasWrapper.setAttribute("aria-hidden", true); + this.#addLayer(canvasWrapper, "canvasWrapper"); if (!this.textLayer && this.#textLayerMode !== TextLayerMode.DISABLE && !pdfPage.isPureXfa) { this._accessibilityManager ||= new TextAccessibilityManager(); this.textLayer = new TextLayerBuilder({ highlighter: this._textHighlighter, accessibilityManager: this._accessibilityManager, - enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS + enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS, + onAppend: textLayerDiv => { + this.l10n.pause(); + this.#addLayer(textLayerDiv, "textLayer"); + this.l10n.resume(); + } }); - this.textLayer.onAppend = textLayerDiv => { - this.l10n.pause(); - this.div.append(textLayerDiv); - this.l10n.resume(); - }; } if (!this.annotationLayer && this.#annotationMode !== AnnotationMode.DISABLE) { const { @@ -5652,7 +5674,6 @@ class PDFPageView { } = this.#layerProperties; this._annotationCanvasMap ||= new Map(); this.annotationLayer = new AnnotationLayerBuilder({ - pageDiv: div, pdfPage, annotationStorage, imageResourcesPath: this.imageResourcesPath, @@ -5663,7 +5684,10 @@ class PDFPageView { hasJSActionsPromise, fieldObjectsPromise, annotationCanvasMap: this._annotationCanvasMap, - accessibilityManager: this._accessibilityManager + accessibilityManager: this._accessibilityManager, + onAppend: annotationLayerDiv => { + this.#addLayer(annotationLayerDiv, "annotationLayer"); + } }); } const renderContinueCallback = cont => { @@ -5752,13 +5776,15 @@ class PDFPageView { if (!this.annotationEditorLayer) { this.annotationEditorLayer = new AnnotationEditorLayerBuilder({ uiManager: annotationEditorUIManager, - pageDiv: div, pdfPage, l10n, accessibilityManager: this._accessibilityManager, annotationLayer: this.annotationLayer?.annotationLayer, textLayer: this.textLayer, - drawLayer: this.drawLayer.getDrawLayer() + drawLayer: this.drawLayer.getDrawLayer(), + onAppend: annotationEditorLayerDiv => { + this.#addLayer(annotationEditorLayerDiv, "annotationEditorLayer"); + } }); } this.#renderAnnotationEditorLayer(); @@ -5883,6 +5909,7 @@ class PDFViewer { #annotationMode = AnnotationMode.ENABLE_FORMS; #containerTopLeft = null; #copyCallbackBound = null; + #enableHighlightFloatingButton = false; #enablePermissions = false; #mlManager = null; #getAllTextInProgress = false; @@ -5895,7 +5922,7 @@ class PDFViewer { #scaleTimeoutId = null; #textLayerMode = TextLayerMode.ENABLE; constructor(options) { - const viewerVersion = "4.1.249"; + const viewerVersion = "4.1.342"; if (version !== viewerVersion) { throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); } @@ -5915,6 +5942,7 @@ class PDFViewer { this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS; this.#annotationEditorMode = options.annotationEditorMode ?? AnnotationEditorType.NONE; this.#annotationEditorHighlightColors = options.annotationEditorHighlightColors || null; + this.#enableHighlightFloatingButton = options.enableHighlightFloatingButton === true; this.imageResourcesPath = options.imageResourcesPath || ""; this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; this.maxCanvasPixels = options.maxCanvasPixels; @@ -6225,7 +6253,9 @@ class PDFViewer { } const pagesCount = pdfDocument.numPages; const firstPagePromise = pdfDocument.getPage(1); - const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ + intent: "display" + }); const permissionsPromise = this.#enablePermissions ? pdfDocument.getPermissions() : Promise.resolve(); if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document."); @@ -6281,7 +6311,7 @@ class PDFViewer { if (pdfDocument.isPureXfa) { console.warn("Warning: XFA-editing is not implemented."); } else if (isValidAnnotationEditorMode(mode)) { - this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, this.viewer, this.#altTextManager, this.eventBus, pdfDocument, this.pageColors, this.#annotationEditorHighlightColors, this.#mlManager); + this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, this.viewer, this.#altTextManager, this.eventBus, pdfDocument, this.pageColors, this.#annotationEditorHighlightColors, this.#enableHighlightFloatingButton, this.#mlManager); this.eventBus.dispatch("annotationeditoruimanager", { source: this, uiManager: this.#annotationEditorUIManager @@ -6942,7 +6972,9 @@ class PDFViewer { } if (!this._optionalContentConfigPromise) { console.error("optionalContentConfigPromise: Not initialized yet."); - return this.pdfDocument.getOptionalContentConfig(); + return this.pdfDocument.getOptionalContentConfig({ + intent: "display" + }); } return this._optionalContentConfigPromise; } @@ -7281,10 +7313,6 @@ class Toolbar { element: options.download, eventName: "download", nimbusName: "download-button" - }, { - element: options.openInApp, - eventName: "openinexternalapp", - nimbusName: "open-in-app-button" }]; if (nimbusData) { this.#buttons = []; @@ -7645,6 +7673,7 @@ const PDFViewerApplication = { annotationMode: AppOptions.get("annotationMode"), annotationEditorMode, annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"), + enableHighlightFloatingButton: AppOptions.get("enableHighlightFloatingButton"), imageResourcesPath: AppOptions.get("imageResourcesPath"), enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"), maxCanvasPixels: AppOptions.get("maxCanvasPixels"), @@ -7784,40 +7813,8 @@ const PDFViewerApplication = { if (this.supportsIntegratedFind) { appConfig.toolbar?.viewFind?.classList.add("hidden"); } - this.initPassiveLoading(file); - const { - mainContainer - } = appConfig; - ({ - scrollTop: this._lastScrollTop, - scrollLeft: this._lastScrollLeft - } = mainContainer); - const scroll = () => { - if (this._lastScrollTop === mainContainer.scrollTop && this._lastScrollLeft === mainContainer.scrollLeft) { - return; - } - mainContainer.removeEventListener("scroll", scroll, { - passive: true - }); - this._isScrolling = true; - const scrollend = () => { - ({ - scrollTop: this._lastScrollTop, - scrollLeft: this._lastScrollLeft - } = mainContainer); - this._isScrolling = false; - mainContainer.addEventListener("scroll", scroll, { - passive: true - }); - mainContainer.removeEventListener("scrollend", scrollend); - mainContainer.removeEventListener("blur", scrollend); - }; - mainContainer.addEventListener("scrollend", scrollend); - mainContainer.addEventListener("blur", scrollend); - }; - mainContainer.addEventListener("scroll", scroll, { - passive: true - }); + this.setTitleUsingUrl(file, file); + this.externalServices.initPassiveLoading(); }, get externalServices() { return shadow(this, "externalServices", new ExternalServices()); @@ -7890,45 +7887,12 @@ const PDFViewerApplication = { return shadow(this, "supportsMouseWheelZoomMetaKey", AppOptions.get("supportsMouseWheelZoomMetaKey")); }, get supportsCaretBrowsingMode() { - return shadow(this, "supportsCaretBrowsingMode", AppOptions.get("supportsCaretBrowsingMode")); + return AppOptions.get("supportsCaretBrowsingMode"); }, moveCaret(isUp, select) { this._caretBrowsing ||= new CaretBrowsingMode(this.appConfig.mainContainer, this.appConfig.viewerContainer, this.appConfig.toolbar?.container); this._caretBrowsing.moveCaret(isUp, select); }, - initPassiveLoading(file) { - this.setTitleUsingUrl(file, file); - this.externalServices.initPassiveLoading({ - onOpenWithTransport: range => { - this.open({ - range - }); - }, - onOpenWithData: (data, contentDispositionFilename) => { - if (isPdfFile(contentDispositionFilename)) { - this._contentDispositionFilename = contentDispositionFilename; - } - this.open({ - data - }); - }, - onOpenWithURL: (url, length, originalUrl) => { - this.open({ - url, - length, - originalUrl - }); - }, - onError: err => { - this.l10n.get("pdfjs-loading-error").then(msg => { - this._documentError(msg, err); - }); - }, - onProgress: (loaded, total) => { - this.progress(loaded / total); - } - }); - }, setTitleUsingUrl(url = "", downloadUrl = null) { this.url = url; this.baseUrl = url.split("#", 1)[0]; @@ -8016,6 +7980,9 @@ const PDFViewerApplication = { } const workerParams = AppOptions.getAll(OptionKind.WORKER); Object.assign(GlobalWorkerOptions, workerParams); + if (args.data && isPdfFile(args.filename)) { + this._contentDispositionFilename = args.filename; + } AppOptions.set("docBaseUrl", this.baseUrl); const apiParams = AppOptions.getAll(OptionKind.API); const loadingTask = getDocument({ @@ -8051,10 +8018,9 @@ const PDFViewerApplication = { } else if (reason instanceof UnexpectedResponseException) { key = "pdfjs-unexpected-response-error"; } - return this.l10n.get(key).then(msg => { - this._documentError(msg, { - message: reason?.message - }); + return this._documentError(key, { + message: reason.message + }).then(() => { throw reason; }); }); @@ -8118,21 +8084,17 @@ const PDFViewerApplication = { this.download(options); } }, - openInExternalApp() { - this.downloadOrSave({ - openInExternalApp: true - }); - }, - _documentError(message, moreInfo = null) { + async _documentError(key, moreInfo = null) { this._unblockDocumentLoadEvent(); - this._otherError(message, moreInfo); + const message = await this._otherError(key || "pdfjs-loading-error", moreInfo); this.eventBus.dispatch("documenterror", { source: this, message, reason: moreInfo?.message ?? null }); }, - _otherError(message, moreInfo = null) { + async _otherError(key, moreInfo = null) { + const message = await this.l10n.get(key); const moreInfoText = [`PDF.js v${version || "?"} (build: ${build || "?"})`]; if (moreInfo) { moreInfoText.push(`Message: ${moreInfo.message}`); @@ -8148,6 +8110,7 @@ const PDFViewerApplication = { } } console.error(`${message}\n\n${moreInfoText.join("\n")}`); + return message; }, progress(level) { if (!this.loadingBar || this.downloadComplete) { @@ -8272,10 +8235,8 @@ const PDFViewerApplication = { this._unblockDocumentLoadEvent(); this._initializeAutoPrint(pdfDocument, openActionPromise); }, reason => { - this.l10n.get("pdfjs-loading-error").then(msg => { - this._documentError(msg, { - message: reason?.message - }); + this._documentError("pdfjs-loading-error", { + message: reason.message }); }); onePageRendered.then(data => { @@ -8521,9 +8482,7 @@ const PDFViewerApplication = { return; } if (!this.supportsPrinting) { - this.l10n.get("pdfjs-printing-not-supported").then(msg => { - this._otherError(msg); - }); + this._otherError("pdfjs-printing-not-supported"); return; } if (!this.pdfViewer.pageViewsReady) { @@ -8537,7 +8496,6 @@ const PDFViewerApplication = { pagesOverview: this.pdfViewer.getPagesOverview(), printContainer: this.appConfig.printContainer, printResolution: AppOptions.get("printResolution"), - optionalContentConfigPromise: this.pdfViewer.optionalContentConfigPromise, printAnnotationStoragePromise: this._printAnnotationStoragePromise }); this.forceRendering(); @@ -8606,7 +8564,6 @@ const PDFViewerApplication = { eventBus._on("switchannotationeditorparams", webViewerSwitchAnnotationEditorParams); eventBus._on("print", webViewerPrint); eventBus._on("download", webViewerDownload); - eventBus._on("openinexternalapp", webViewerOpenInExternalApp); eventBus._on("firstpage", webViewerFirstPage); eventBus._on("lastpage", webViewerLastPage); eventBus._on("nextpage", webViewerNextPage); @@ -8638,7 +8595,10 @@ const PDFViewerApplication = { bindWindowEvents() { const { eventBus, - _boundEvents + _boundEvents, + appConfig: { + mainContainer + } } = this; function addWindowResolutionChange(evt = null) { if (evt) { @@ -8698,12 +8658,79 @@ const PDFViewerApplication = { window.addEventListener("beforeprint", _boundEvents.windowBeforePrint); window.addEventListener("afterprint", _boundEvents.windowAfterPrint); window.addEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + ({ + scrollTop: this._lastScrollTop, + scrollLeft: this._lastScrollLeft + } = mainContainer); + const scrollend = _boundEvents.mainContainerScrollend = () => { + ({ + scrollTop: this._lastScrollTop, + scrollLeft: this._lastScrollLeft + } = mainContainer); + this._isScrolling = false; + mainContainer.addEventListener("scroll", scroll, { + passive: true + }); + mainContainer.removeEventListener("scrollend", scrollend); + mainContainer.removeEventListener("blur", scrollend); + }; + const scroll = _boundEvents.mainContainerScroll = () => { + if (this._isCtrlKeyDown || this._lastScrollTop === mainContainer.scrollTop && this._lastScrollLeft === mainContainer.scrollLeft) { + return; + } + mainContainer.removeEventListener("scroll", scroll, { + passive: true + }); + this._isScrolling = true; + mainContainer.addEventListener("scrollend", scrollend); + mainContainer.addEventListener("blur", scrollend); + }; + mainContainer.addEventListener("scroll", scroll, { + passive: true + }); }, unbindEvents() { throw new Error("Not implemented: unbindEvents"); }, unbindWindowEvents() { - throw new Error("Not implemented: unbindWindowEvents"); + const { + _boundEvents, + appConfig: { + mainContainer + } + } = this; + window.removeEventListener("visibilitychange", webViewerVisibilityChange); + window.removeEventListener("wheel", webViewerWheel, { + passive: false + }); + window.removeEventListener("touchstart", webViewerTouchStart, { + passive: false + }); + window.removeEventListener("touchmove", webViewerTouchMove, { + passive: false + }); + window.removeEventListener("touchend", webViewerTouchEnd, { + passive: false + }); + window.removeEventListener("click", webViewerClick); + window.removeEventListener("keydown", webViewerKeyDown); + window.removeEventListener("keyup", webViewerKeyUp); + window.removeEventListener("resize", _boundEvents.windowResize); + window.removeEventListener("hashchange", _boundEvents.windowHashChange); + window.removeEventListener("beforeprint", _boundEvents.windowBeforePrint); + window.removeEventListener("afterprint", _boundEvents.windowAfterPrint); + window.removeEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + mainContainer.removeEventListener("scroll", _boundEvents.mainContainerScroll); + mainContainer.removeEventListener("scrollend", _boundEvents.mainContainerScrollend); + mainContainer.removeEventListener("blur", _boundEvents.mainContainerScrollend); + _boundEvents.removeWindowResolutionChange?.(); + _boundEvents.windowResize = null; + _boundEvents.windowHashChange = null; + _boundEvents.windowBeforePrint = null; + _boundEvents.windowAfterPrint = null; + _boundEvents.windowUpdateFromSandbox = null; + _boundEvents.mainContainerScroll = null; + _boundEvents.mainContainerScrollend = null; }, _accumulateTicks(ticks, prop) { if (this[prop] > 0 && ticks < 0 || this[prop] < 0 && ticks > 0) { @@ -8786,9 +8813,7 @@ function webViewerPageRendered({ } } if (error) { - PDFViewerApplication.l10n.get("pdfjs-rendering-error").then(msg => { - PDFViewerApplication._otherError(msg, error); - }); + PDFViewerApplication._otherError("pdfjs-rendering-error", error); } } function webViewerPageMode({ @@ -8918,9 +8943,6 @@ function webViewerPrint() { function webViewerDownload() { PDFViewerApplication.downloadOrSave(); } -function webViewerOpenInExternalApp() { - PDFViewerApplication.openInExternalApp(); -} function webViewerFirstPage() { PDFViewerApplication.page = 1; } @@ -9509,8 +9531,8 @@ function webViewerReportTelemetry({ -const pdfjsVersion = "4.1.249"; -const pdfjsBuild = "d07f37f44"; +const pdfjsVersion = "4.1.342"; +const pdfjsBuild = "e384df6f1"; const AppConstants = null; window.PDFViewerApplication = PDFViewerApplication; window.PDFViewerApplicationConstants = AppConstants; @@ -9524,8 +9546,7 @@ function getViewerConfiguration() { toolbar: { mainContainer, container: document.getElementById("floatingToolbar"), - download: document.getElementById("download"), - openInApp: document.getElementById("openInApp") + download: document.getElementById("download") }, passwordOverlay: { dialog: document.getElementById("passwordDialog"), diff --git a/toolkit/components/pdfjs/content/web/viewer.css b/toolkit/components/pdfjs/content/web/viewer.css index 238df7ce7f..2999c89f3a 100644 --- a/toolkit/components/pdfjs/content/web/viewer.css +++ b/toolkit/components/pdfjs/content/web/viewer.css @@ -23,7 +23,6 @@ text-size-adjust:none; forced-color-adjust:none; transform-origin:0 0; - z-index:2; caret-color:CanvasText; &.highlighting{ @@ -162,7 +161,6 @@ left:0; pointer-events:none; transform-origin:0 0; - z-index:3; &[data-main-rotation="90"] .norotate{ transform:rotate(270deg) translateX(-100%); @@ -853,6 +851,208 @@ } } +.toggle-button{ + --button-background-color:#f0f0f4; + --button-background-color-hover:#e0e0e6; + --button-background-color-active:#cfcfd8; + --color-accent-primary:#0060df; + --color-accent-primary-hover:#0250bb; + --color-accent-primary-active:#054096; + --border-interactive-color:#8f8f9d; + --border-radius-circle:9999px; + --border-width:1px; + --size-item-small:16px; + --size-item-large:32px; + --color-canvas:white; + + @media (prefers-color-scheme: dark){ + --button-background-color:color-mix(in srgb, currentColor 7%, transparent); + --button-background-color-hover:color-mix( + in srgb, + currentColor 14%, + transparent + ); + --button-background-color-active:color-mix( + in srgb, + currentColor 21%, + transparent + ); + --color-accent-primary:#0df; + --color-accent-primary-hover:#80ebff; + --color-accent-primary-active:#aaf2ff; + --border-interactive-color:#bfbfc9; + --color-canvas:#1c1b22; + } + + @media (forced-colors: active){ + --color-accent-primary:ButtonText; + --color-accent-primary-hover:SelectedItem; + --color-accent-primary-active:SelectedItem; + --border-interactive-color:ButtonText; + --button-background-color:ButtonFace; + --border-interactive-color-hover:SelectedItem; + --border-interactive-color-active:SelectedItem; + --border-interactive-color-disabled:GrayText; + --color-canvas:ButtonText; + } + + --toggle-background-color:var(--button-background-color); + --toggle-background-color-hover:var(--button-background-color-hover); + --toggle-background-color-active:var(--button-background-color-active); + --toggle-background-color-pressed:var(--color-accent-primary); + --toggle-background-color-pressed-hover:var(--color-accent-primary-hover); + --toggle-background-color-pressed-active:var(--color-accent-primary-active); + --toggle-border-color:var(--border-interactive-color); + --toggle-border-color-hover:var(--toggle-border-color); + --toggle-border-color-active:var(--toggle-border-color); + --toggle-border-radius:var(--border-radius-circle); + --toggle-border-width:var(--border-width); + --toggle-height:var(--size-item-small); + --toggle-width:var(--size-item-large); + --toggle-dot-background-color:var(--toggle-border-color); + --toggle-dot-background-color-hover:var(--toggle-dot-background-color); + --toggle-dot-background-color-active:var(--toggle-dot-background-color); + --toggle-dot-background-color-on-pressed:var(--color-canvas); + --toggle-dot-margin:1px; + --toggle-dot-height:calc( + var(--toggle-height) - 2 * var(--toggle-dot-margin) - 2 * + var(--toggle-border-width) + ); + --toggle-dot-width:var(--toggle-dot-height); + --toggle-dot-transform-x:calc( + var(--toggle-width) - 4 * var(--toggle-dot-margin) - var(--toggle-dot-width) + ); + + appearance:none; + padding:0; + margin:0; + border:var(--toggle-border-width) solid var(--toggle-border-color); + height:var(--toggle-height); + width:var(--toggle-width); + border-radius:var(--toggle-border-radius); + background:var(--toggle-background-color); + box-sizing:border-box; + flex-shrink:0; + + &:focus-visible{ + outline:var(--focus-outline); + outline-offset:var(--focus-outline-offset); + } + + &:enabled:hover{ + background:var(--toggle-background-color-hover); + border-color:var(--toggle-border-color); + } + + &:enabled:active{ + background:var(--toggle-background-color-active); + border-color:var(--toggle-border-color); + } + + &[aria-pressed="true"]{ + background:var(--toggle-background-color-pressed); + border-color:transparent; + } + + &[aria-pressed="true"]:enabled:hover{ + background:var(--toggle-background-color-pressed-hover); + border-color:transparent; + } + + &[aria-pressed="true"]:enabled:active{ + background:var(--toggle-background-color-pressed-active); + border-color:transparent; + } + + &::before{ + display:block; + content:""; + background-color:var(--toggle-dot-background-color); + height:var(--toggle-dot-height); + width:var(--toggle-dot-width); + margin:var(--toggle-dot-margin); + border-radius:var(--toggle-border-radius); + translate:0; + } + + &[aria-pressed="true"]::before{ + translate:var(--toggle-dot-transform-x); + background-color:var(--toggle-dot-background-color-on-pressed); + } + + &[aria-pressed="true"]:enabled:hover::before, + &[aria-pressed="true"]:enabled:active::before{ + background-color:var(--toggle-dot-background-color-on-pressed); + } + + &[aria-pressed="true"]:-moz-locale-dir(rtl)::before, + &[aria-pressed="true"]:dir(rtl)::before{ + translate:calc(-1 * var(--toggle-dot-transform-x)); + } + + @media (prefers-reduced-motion: no-preference){ + &::before{ + transition:translate 100ms; + } + } + + @media (prefers-contrast){ + &:enabled:hover{ + border-color:var(--toggle-border-color-hover); + } + + &:enabled:active{ + border-color:var(--toggle-border-color-active); + } + + &[aria-pressed="true"]:enabled{ + border-color:var(--toggle-border-color); + position:relative; + } + + &[aria-pressed="true"]:enabled:hover, + &[aria-pressed="true"]:enabled:hover:active{ + border-color:var(--toggle-border-color-hover); + } + + &[aria-pressed="true"]:enabled:active{ + background-color:var(--toggle-dot-background-color-active); + border-color:var(--toggle-dot-background-color-hover); + } + + &:hover::before, + &:active::before{ + background-color:var(--toggle-dot-background-color-hover); + } + } + + @media (forced-colors){ + --toggle-dot-background-color:var(--color-accent-primary); + --toggle-dot-background-color-hover:var(--color-accent-primary-hover); + --toggle-dot-background-color-active:var(--color-accent-primary-active); + --toggle-dot-background-color-on-pressed:var(--button-background-color); + --toggle-background-color-disabled:var(--button-background-color-disabled); + --toggle-border-color-hover:var(--border-interactive-color-hover); + --toggle-border-color-active:var(--border-interactive-color-active); + --toggle-border-color-disabled:var(--border-interactive-color-disabled); + + &[aria-pressed="true"]:enabled::after{ + border:1px solid var(--button-background-color); + content:""; + position:absolute; + height:var(--toggle-height); + width:var(--toggle-width); + display:block; + border-radius:var(--toggle-border-radius); + inset:-2px; + } + + &[aria-pressed="true"]:enabled:active::after{ + border-color:var(--toggle-border-color-active); + } + } +} + :root{ --outline-width:2px; --outline-color:#0060df; @@ -878,6 +1078,19 @@ --editorHighlight-editing-cursor:url(images/cursor-editorTextHighlight.svg) 24 24, text; --editorFreeHighlight-editing-cursor:url(images/cursor-editorFreeHighlight.svg) 1 18, pointer; } +.visuallyHidden{ + position:absolute; + top:0; + left:0; + border:0; + margin:0; + padding:0; + width:0; + height:0; + overflow:hidden; + white-space:nowrap; + font-size:0; +} .textLayer.highlighting{ cursor:var(--editorFreeHighlight-editing-cursor); @@ -926,7 +1139,6 @@ font-size:calc(100px * var(--scale-factor)); transform-origin:0 0; cursor:auto; - z-index:4; } .annotationEditorLayer.waiting{ @@ -995,10 +1207,12 @@ } .annotationEditorLayer - :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor){ + :is(.freeTextEditor, .inkEditor, .stampEditor, .highlightEditor), +.textLayer{ .editToolbar{ --editor-toolbar-delete-image:url(images/editor-toolbar-delete.svg); --editor-toolbar-bg-color:#f0f0f4; + --editor-toolbar-highlight-image:url(images/toolbarButton-editorHighlight.svg); --editor-toolbar-fg-color:#2e2e56; --editor-toolbar-border-color:#8f8f9d; --editor-toolbar-hover-border-color:var(--editor-toolbar-border-color); @@ -1084,6 +1298,25 @@ margin-inline:2px; } + .highlightButton{ + width:var(--editor-toolbar-height); + + &::before{ + content:""; + mask-image:var(--editor-toolbar-highlight-image); + mask-repeat:no-repeat; + mask-position:center; + display:inline-block; + background-color:var(--editor-toolbar-fg-color); + width:100%; + height:100%; + } + + &:hover::before{ + background-color:var(--editor-toolbar-hover-fg-color); + } + } + .delete{ width:var(--editor-toolbar-height); @@ -2003,7 +2236,12 @@ --example-color:CanvasText; } - &::before{ + :is(& > .editorParamsSlider[disabled]){ + opacity:0.4; + } + + &::before, + &::after{ content:""; width:8px; aspect-ratio:1; @@ -2011,20 +2249,46 @@ border-radius:100%; background-color:var(--example-color); } + &::after{ + width:24px; + } .editorParamsSlider{ width:unset; height:14px; } + } + } - &::after{ - content:""; - width:24px; - aspect-ratio:1; - display:block; - border-radius:100%; - background-color:var(--example-color); + #editorHighlightVisibility{ + display:flex; + flex-direction:column; + align-items:flex-start; + gap:8px; + align-self:stretch; + + .divider{ + --divider-color:#d7d7db; + + @media (prefers-color-scheme: dark){ + --divider-color:#8f8f9d; + } + + @media screen and (forced-colors: active){ + --divider-color:CanvasText; } + + margin-block:4px; + width:100%; + height:1px; + background-color:var(--divider-color); + } + + .toggler{ + display:flex; + justify-content:space-between; + align-items:center; + align-self:stretch; } } } @@ -2084,7 +2348,6 @@ overflow:hidden; width:100%; height:100%; - z-index:1; } .pdfViewer .page{ @@ -2655,6 +2918,7 @@ body{ font-style:normal; } .loadingInput:has(> &[data-status="pending"])::after{ + display:block; visibility:visible; } &[data-status="notFound"]{ @@ -3249,6 +3513,7 @@ a:is(.toolbarButton, .secondaryToolbarButton)[href="#"]{ transition-property:none; .loadingInput:has(> &.loading)::after{ + display: block; visibility:visible; transition-property:visibility; @@ -3260,6 +3525,7 @@ a:is(.toolbarButton, .secondaryToolbarButton)[href="#"]{ &::after{ position:absolute; visibility:hidden; + display: none; top:calc(50% - 8px); width:16px; height:16px; diff --git a/toolkit/components/pdfjs/content/web/viewer.html b/toolkit/components/pdfjs/content/web/viewer.html index 59438b64b4..941e17b58d 100644 --- a/toolkit/components/pdfjs/content/web/viewer.html +++ b/toolkit/components/pdfjs/content/web/viewer.html @@ -127,6 +127,13 @@ See https://github.com/adobe-type-tools/cmap-resources <input type="range" id="editorFreeHighlightThickness" class="editorParamsSlider" data-l10n-id="pdfjs-editor-free-highlight-thickness-title" value="12" min="8" max="24" step="1" tabindex="101"> </div> </div> + <div id="editorHighlightVisibility"> + <div class="divider"></div> + <div class="toggler"> + <label for="editorHighlightShowAll" class="editorParamsLabel" data-l10n-id="pdfjs-editor-highlight-show-all-button-label">Show all</label> + <button id="editorHighlightShowAll" class="toggle-button" data-l10n-id="pdfjs-editor-highlight-show-all-button" aria-pressed="true" tabindex="102"></button> + </div> + </div> </div> </div> @@ -134,11 +141,11 @@ See https://github.com/adobe-type-tools/cmap-resources <div class="editorParamsToolbarContainer"> <div class="editorParamsSetter"> <label for="editorFreeTextColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-color-input">Color</label> - <input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="102"> + <input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="103"> </div> <div class="editorParamsSetter"> <label for="editorFreeTextFontSize" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-size-input">Size</label> - <input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100" step="1" tabindex="103"> + <input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100" step="1" tabindex="104"> </div> </div> </div> @@ -147,22 +154,22 @@ See https://github.com/adobe-type-tools/cmap-resources <div class="editorParamsToolbarContainer"> <div class="editorParamsSetter"> <label for="editorInkColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-color-input">Color</label> - <input type="color" id="editorInkColor" class="editorParamsColor" tabindex="104"> + <input type="color" id="editorInkColor" class="editorParamsColor" tabindex="105"> </div> <div class="editorParamsSetter"> <label for="editorInkThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-thickness-input">Thickness</label> - <input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1" tabindex="105"> + <input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1" tabindex="106"> </div> <div class="editorParamsSetter"> <label for="editorInkOpacity" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-opacity-input">Opacity</label> - <input type="range" id="editorInkOpacity" class="editorParamsSlider" value="100" min="1" max="100" step="1" tabindex="106"> + <input type="range" id="editorInkOpacity" class="editorParamsSlider" value="100" min="1" max="100" step="1" tabindex="107"> </div> </div> </div> <div class="editorParamsToolbar hidden doorHangerRight" id="editorStampParamsToolbar"> <div class="editorParamsToolbarContainer"> - <button id="editorStampAddImage" class="secondaryToolbarButton" title="Add image" tabindex="107" data-l10n-id="pdfjs-editor-stamp-add-image-button"> + <button id="editorStampAddImage" class="secondaryToolbarButton" title="Add image" tabindex="108" data-l10n-id="pdfjs-editor-stamp-add-image-button"> <span class="editorParamsLabel" data-l10n-id="pdfjs-editor-stamp-add-image-button-label">Add image</span> </button> </div> diff --git a/toolkit/components/pdfjs/content/web/viewer.mjs b/toolkit/components/pdfjs/content/web/viewer.mjs index a047a9f7c1..778ce57e1a 100644 --- a/toolkit/components/pdfjs/content/web/viewer.mjs +++ b/toolkit/components/pdfjs/content/web/viewer.mjs @@ -606,6 +606,10 @@ const defaultOptions = { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE }, + enableHighlightFloatingButton: { + value: false, + kind: OptionKind.VIEWER + OptionKind.PREFERENCE + }, enableML: { value: false, kind: OptionKind.VIEWER + OptionKind.PREFERENCE @@ -651,7 +655,7 @@ const defaultOptions = { kind: OptionKind.VIEWER }, maxCanvasPixels: { - value: 16777216, + value: 2 ** 25, kind: OptionKind.VIEWER }, forcePageColors: { @@ -768,28 +772,20 @@ class AppOptions { constructor() { throw new Error("Cannot initialize AppOptions."); } + static getCompat(name) { + return compatibilityParams[name] ?? undefined; + } static get(name) { - const userOption = userOptions[name]; - if (userOption !== undefined) { - return userOption; - } - const defaultOption = defaultOptions[name]; - if (defaultOption !== undefined) { - return compatibilityParams[name] ?? defaultOption.value; - } - return undefined; + return userOptions[name] ?? compatibilityParams[name] ?? defaultOptions[name]?.value ?? undefined; } - static getAll(kind = null) { + static getAll(kind = null, defaultOnly = false) { const options = Object.create(null); for (const name in defaultOptions) { const defaultOption = defaultOptions[name]; - if (kind) { - if (!(kind & defaultOption.kind)) { - continue; - } + if (kind && !(kind & defaultOption.kind)) { + continue; } - const userOption = userOptions[name]; - options[name] = userOption !== undefined ? userOption : compatibilityParams[name] ?? defaultOption.value; + options[name] = defaultOnly ? defaultOption.value : userOptions[name] ?? compatibilityParams[name] ?? defaultOption.value; } return options; } @@ -1112,30 +1108,7 @@ class PDFLinkService { if (pdfDocument !== this.pdfDocument) { return; } - let operator; - for (const elem of action.state) { - switch (elem) { - case "ON": - case "OFF": - case "Toggle": - operator = elem; - continue; - } - switch (operator) { - case "ON": - optionalContentConfig.setVisibility(elem, true); - break; - case "OFF": - optionalContentConfig.setVisibility(elem, false); - break; - case "Toggle": - const group = optionalContentConfig.getGroup(elem); - if (group) { - optionalContentConfig.setVisibility(elem, !group.visible); - } - break; - } - } + optionalContentConfig.setOCGState(action); this.pdfViewer.optionalContentConfigPromise = Promise.resolve(optionalContentConfig); } cachePageRef(pageNum, pageRef) { @@ -1423,7 +1396,7 @@ class BaseExternalServices { } updateFindControlState(data) {} updateFindMatchesCount(data) {} - initPassiveLoading(callbacks) {} + initPassiveLoading() {} reportTelemetry(data) {} async createL10n() { throw new Error("Not implemented: createL10n"); @@ -1440,6 +1413,16 @@ class BaseExternalServices { ;// CONCATENATED MODULE: ./web/preferences.js class BasePreferences { + #browserDefaults = Object.freeze({ + canvasMaxAreaInBytes: -1, + isInAutomation: false, + supportsCaretBrowsingMode: false, + supportsDocumentFonts: true, + supportsIntegratedFind: false, + supportsMouseWheelZoomCtrlKey: true, + supportsMouseWheelZoomMetaKey: true, + supportsPinchToZoom: true + }); #defaults = Object.freeze({ annotationEditorMode: 0, annotationMode: 2, @@ -1448,6 +1431,7 @@ class BasePreferences { defaultZoomValue: "", disablePageLabels: false, enableHighlightEditor: false, + enableHighlightFloatingButton: false, enableML: false, enablePermissions: false, enablePrintAutoRotate: true, @@ -1482,26 +1466,19 @@ class BasePreferences { browserPrefs, prefs }) => { - const BROWSER_PREFS = { - canvasMaxAreaInBytes: -1, - isInAutomation: false, - supportsCaretBrowsingMode: false, - supportsDocumentFonts: true, - supportsIntegratedFind: false, - supportsMouseWheelZoomCtrlKey: true, - supportsMouseWheelZoomMetaKey: true, - supportsPinchToZoom: true - }; const options = Object.create(null); - for (const [name, defaultVal] of Object.entries(BROWSER_PREFS)) { + for (const [name, val] of Object.entries(this.#browserDefaults)) { const prefVal = browserPrefs?.[name]; - options[name] = typeof prefVal === typeof defaultVal ? prefVal : defaultVal; + options[name] = typeof prefVal === typeof val ? prefVal : val; } - for (const [name, defaultVal] of Object.entries(this.#defaults)) { + for (const [name, val] of Object.entries(this.#defaults)) { const prefVal = prefs?.[name]; - options[name] = this.#prefs[name] = typeof prefVal === typeof defaultVal ? prefVal : defaultVal; + options[name] = this.#prefs[name] = typeof prefVal === typeof val ? prefVal : val; } AppOptions.setAll(options, true); + window.addEventListener("updatedPreference", evt => { + this.#updatePref(evt.detail); + }); }); } async _writeToStorage(prefObj) { @@ -1510,6 +1487,24 @@ class BasePreferences { async _readFromStorage(prefObj) { throw new Error("Not implemented: _readFromStorage"); } + #updatePref({ + name, + value + }) { + if (name in this.#browserDefaults) { + if (typeof value !== typeof this.#browserDefaults[name]) { + return; + } + } else if (name in this.#defaults) { + if (typeof value !== typeof this.#defaults[name]) { + return; + } + this.#prefs[name] = value; + } else { + return; + } + AppOptions.set(name, value); + } async reset() { throw new Error("Please use `about:config` to change preferences."); } @@ -1517,12 +1512,7 @@ class BasePreferences { throw new Error("Please use `about:config` to change preferences."); } async get(name) { - await this.#initializedPromise; - const defaultValue = this.#defaults[name]; - if (defaultValue === undefined) { - throw new Error(`Get preference: "${name}" is undefined.`); - } - return this.#prefs[name] ?? defaultValue; + throw new Error("Not implemented: get"); } get initializedPromise() { return this.#initializedPromise; @@ -1824,7 +1814,7 @@ class ExternalServices extends BaseExternalServices { updateFindMatchesCount(data) { FirefoxCom.request("updateFindMatchesCount", data); } - initPassiveLoading(callbacks) { + initPassiveLoading() { let pdfDataRangeTransport; window.addEventListener("message", function windowMessage(e) { if (e.source !== null) { @@ -1838,11 +1828,13 @@ class ExternalServices extends BaseExternalServices { switch (args.pdfjsLoadAction) { case "supportsRangedLoading": if (args.done && !args.data) { - callbacks.onError(); + viewerApp._documentError(null); break; } pdfDataRangeTransport = new FirefoxComDataRangeTransport(args.length, args.data, args.done, args.filename); - callbacks.onOpenWithTransport(pdfDataRangeTransport); + viewerApp.open({ + range: pdfDataRangeTransport + }); break; case "range": pdfDataRangeTransport.onDataRange(args.begin, args.chunk); @@ -1858,21 +1850,26 @@ class ExternalServices extends BaseExternalServices { pdfDataRangeTransport?.onDataProgressiveDone(); break; case "progress": - callbacks.onProgress(args.loaded, args.total); + viewerApp.progress(args.loaded / args.total); break; case "complete": if (!args.data) { - callbacks.onError(args.errorCode); + viewerApp._documentError(null, { + message: args.errorCode + }); break; } - callbacks.onOpenWithData(args.data, args.filename); + viewerApp.open({ + data: args.data, + filename: args.filename + }); break; } }); FirefoxCom.request("initPassiveLoading", null); } reportTelemetry(data) { - FirefoxCom.request("reportTelemetry", JSON.stringify(data)); + FirefoxCom.request("reportTelemetry", data); } updateEditorStates(data) { FirefoxCom.request("updateEditorStates", data); @@ -2150,7 +2147,8 @@ class AnnotationEditorParams { editorInkThickness, editorInkOpacity, editorStampAddImage, - editorFreeHighlightThickness + editorFreeHighlightThickness, + editorHighlightShowAll }) { const dispatchEvent = (typeStr, value) => { this.eventBus.dispatch("switchannotationeditorparams", { @@ -2180,6 +2178,11 @@ class AnnotationEditorParams { editorFreeHighlightThickness.addEventListener("input", function () { dispatchEvent("HIGHLIGHT_THICKNESS", this.valueAsNumber); }); + editorHighlightShowAll.addEventListener("click", function () { + const checked = this.getAttribute("aria-pressed") === "true"; + this.setAttribute("aria-pressed", !checked); + dispatchEvent("HIGHLIGHT_SHOW_ALL", !checked); + }); this.eventBus._on("annotationeditorparamschanged", evt => { for (const [type, value] of evt.details) { switch (type) { @@ -2204,6 +2207,9 @@ class AnnotationEditorParams { case AnnotationEditorParamsType.HIGHLIGHT_FREE: editorFreeHighlightThickness.disabled = !value; break; + case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL: + editorHighlightShowAll.setAttribute("aria-pressed", value); + break; } } }); @@ -4690,7 +4696,9 @@ class PDFLayerViewer extends BaseTreeViewer { return; } const pdfDocument = this._pdfDocument; - const optionalContentConfig = await (promise || pdfDocument.getOptionalContentConfig()); + const optionalContentConfig = await (promise || pdfDocument.getOptionalContentConfig({ + intent: "display" + })); if (pdfDocument !== this._pdfDocument) { return; } @@ -5429,14 +5437,15 @@ class FirefoxPrintService { pagesOverview, printContainer, printResolution, - optionalContentConfigPromise = null, printAnnotationStoragePromise = null }) { this.pdfDocument = pdfDocument; this.pagesOverview = pagesOverview; this.printContainer = printContainer; this._printResolution = printResolution || 150; - this._optionalContentConfigPromise = optionalContentConfigPromise || pdfDocument.getOptionalContentConfig(); + this._optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ + intent: "print" + }); this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve(); } layout() { @@ -6680,7 +6689,9 @@ class PDFThumbnailViewer { return; } const firstPagePromise = pdfDocument.getPage(1); - const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ + intent: "display" + }); firstPagePromise.then(firstPdfPage => { const pagesCount = pdfDocument.numPages; const viewport = firstPdfPage.getViewport({ @@ -6770,10 +6781,10 @@ class PDFThumbnailViewer { class AnnotationEditorLayerBuilder { #annotationLayer = null; #drawLayer = null; + #onAppend = null; #textLayer = null; #uiManager; constructor(options) { - this.pageDiv = options.pageDiv; this.pdfPage = options.pdfPage; this.accessibilityManager = options.accessibilityManager; this.l10n = options.l10n; @@ -6784,6 +6795,7 @@ class AnnotationEditorLayerBuilder { this.#annotationLayer = options.annotationLayer || null; this.#textLayer = options.textLayer || null; this.#drawLayer = options.drawLayer || null; + this.#onAppend = options.onAppend || null; } async render(viewport, intent = "display") { if (intent !== "display") { @@ -6804,10 +6816,9 @@ class AnnotationEditorLayerBuilder { } const div = this.div = document.createElement("div"); div.className = "annotationEditorLayer"; - div.tabIndex = 0; div.hidden = true; div.dir = this.#uiManager.direction; - this.pageDiv.append(div); + this.#onAppend?.(div); this.annotationEditorLayer = new AnnotationEditorLayer({ uiManager: this.#uiManager, div, @@ -6833,9 +6844,7 @@ class AnnotationEditorLayerBuilder { if (!this.div) { return; } - this.pageDiv = null; this.annotationEditorLayer.destroy(); - this.div.remove(); } hide() { if (!this.div) { @@ -6844,7 +6853,7 @@ class AnnotationEditorLayerBuilder { this.div.hidden = true; } show() { - if (!this.div || this.annotationEditorLayer.isEmpty) { + if (!this.div || this.annotationEditorLayer.isInvisible) { return; } this.div.hidden = false; @@ -6855,9 +6864,9 @@ class AnnotationEditorLayerBuilder { class AnnotationLayerBuilder { + #onAppend = null; #onPresentationModeChanged = null; constructor({ - pageDiv, pdfPage, linkService, downloadManager, @@ -6868,9 +6877,9 @@ class AnnotationLayerBuilder { hasJSActionsPromise = null, fieldObjectsPromise = null, annotationCanvasMap = null, - accessibilityManager = null + accessibilityManager = null, + onAppend = null }) { - this.pageDiv = pageDiv; this.pdfPage = pdfPage; this.linkService = linkService; this.downloadManager = downloadManager; @@ -6882,6 +6891,7 @@ class AnnotationLayerBuilder { this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null); this._annotationCanvasMap = annotationCanvasMap; this._accessibilityManager = accessibilityManager; + this.#onAppend = onAppend; this.annotationLayer = null; this.div = null; this._cancelled = false; @@ -6907,7 +6917,7 @@ class AnnotationLayerBuilder { } const div = this.div = document.createElement("div"); div.className = "annotationLayer"; - this.pageDiv.append(div); + this.#onAppend?.(div); if (annotations.length === 0) { this.hide(); return; @@ -7501,13 +7511,15 @@ class TextHighlighter { class TextLayerBuilder { #enablePermissions = false; + #onAppend = null; #rotation = 0; #scale = 0; #textContentSource = null; constructor({ highlighter = null, accessibilityManager = null, - enablePermissions = false + enablePermissions = false, + onAppend = null }) { this.textContentItemsStr = []; this.renderingDone = false; @@ -7517,8 +7529,9 @@ class TextLayerBuilder { this.highlighter = highlighter; this.accessibilityManager = accessibilityManager; this.#enablePermissions = enablePermissions === true; - this.onAppend = null; + this.#onAppend = onAppend; this.div = document.createElement("div"); + this.div.tabIndex = 0; this.div.className = "textLayer"; } #finishRendering() { @@ -7573,7 +7586,7 @@ class TextLayerBuilder { this.#finishRendering(); this.#scale = scale; this.#rotation = rotation; - this.onAppend(this.div); + this.#onAppend?.(this.div); this.highlighter?.enable(); this.accessibilityManager?.enable(); } @@ -7647,8 +7660,8 @@ class TextLayerBuilder { -const MAX_CANVAS_PIXELS = compatibilityParams.maxCanvasPixels || 16777216; const DEFAULT_LAYER_PROPERTIES = null; +const LAYERS_ORDER = new Map([["canvasWrapper", 0], ["textLayer", 1], ["annotationLayer", 2], ["annotationEditorLayer", 3], ["xfaLayer", 3]]); class PDFPageView { #annotationMode = AnnotationMode.ENABLE_FORMS; #hasRestrictedScaling = false; @@ -7664,6 +7677,7 @@ class PDFPageView { regularAnnotations: true }; #viewportMap = new WeakMap(); + #layers = [null, null, null, null]; constructor(options) { const container = options.container; const defaultViewport = options.defaultViewport; @@ -7680,7 +7694,7 @@ class PDFPageView { this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE; this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS; this.imageResourcesPath = options.imageResourcesPath || ""; - this.maxCanvasPixels = options.maxCanvasPixels ?? MAX_CANVAS_PIXELS; + this.maxCanvasPixels = options.maxCanvasPixels ?? (AppOptions.getCompat("maxCanvasPixels") || 2 ** 25); this.pageColors = options.pageColors || null; this.eventBus = options.eventBus; this.renderingQueue = options.renderingQueue; @@ -7707,6 +7721,23 @@ class PDFPageView { this.#setDimensions(); container?.append(div); } + #addLayer(div, name) { + const pos = LAYERS_ORDER.get(name); + const oldDiv = this.#layers[pos]; + this.#layers[pos] = div; + if (oldDiv) { + oldDiv.replaceWith(div); + return; + } + for (let i = pos - 1; i >= 0; i--) { + const layer = this.#layers[i]; + if (layer) { + layer.after(div); + return; + } + } + this.div.prepend(div); + } get renderingState() { return this.#renderingState; } @@ -7820,7 +7851,7 @@ class PDFPageView { } finally { if (this.xfaLayer?.div) { this.l10n.pause(); - this.div.append(this.xfaLayer.div); + this.#addLayer(this.xfaLayer.div, "xfaLayer"); this.l10n.resume(); } this.eventBus.dispatch("xfalayerrendered", { @@ -7932,6 +7963,10 @@ class PDFPageView { continue; } node.remove(); + const layerIndex = this.#layers.indexOf(node); + if (layerIndex >= 0) { + this.#layers[layerIndex] = null; + } } div.removeAttribute("data-loaded"); if (annotationLayerNode) { @@ -8191,19 +8226,20 @@ class PDFPageView { this.renderingState = RenderingStates.RUNNING; const canvasWrapper = document.createElement("div"); canvasWrapper.classList.add("canvasWrapper"); - div.append(canvasWrapper); + canvasWrapper.setAttribute("aria-hidden", true); + this.#addLayer(canvasWrapper, "canvasWrapper"); if (!this.textLayer && this.#textLayerMode !== TextLayerMode.DISABLE && !pdfPage.isPureXfa) { this._accessibilityManager ||= new TextAccessibilityManager(); this.textLayer = new TextLayerBuilder({ highlighter: this._textHighlighter, accessibilityManager: this._accessibilityManager, - enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS + enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS, + onAppend: textLayerDiv => { + this.l10n.pause(); + this.#addLayer(textLayerDiv, "textLayer"); + this.l10n.resume(); + } }); - this.textLayer.onAppend = textLayerDiv => { - this.l10n.pause(); - this.div.append(textLayerDiv); - this.l10n.resume(); - }; } if (!this.annotationLayer && this.#annotationMode !== AnnotationMode.DISABLE) { const { @@ -8216,7 +8252,6 @@ class PDFPageView { } = this.#layerProperties; this._annotationCanvasMap ||= new Map(); this.annotationLayer = new AnnotationLayerBuilder({ - pageDiv: div, pdfPage, annotationStorage, imageResourcesPath: this.imageResourcesPath, @@ -8227,7 +8262,10 @@ class PDFPageView { hasJSActionsPromise, fieldObjectsPromise, annotationCanvasMap: this._annotationCanvasMap, - accessibilityManager: this._accessibilityManager + accessibilityManager: this._accessibilityManager, + onAppend: annotationLayerDiv => { + this.#addLayer(annotationLayerDiv, "annotationLayer"); + } }); } const renderContinueCallback = cont => { @@ -8316,13 +8354,15 @@ class PDFPageView { if (!this.annotationEditorLayer) { this.annotationEditorLayer = new AnnotationEditorLayerBuilder({ uiManager: annotationEditorUIManager, - pageDiv: div, pdfPage, l10n, accessibilityManager: this._accessibilityManager, annotationLayer: this.annotationLayer?.annotationLayer, textLayer: this.textLayer, - drawLayer: this.drawLayer.getDrawLayer() + drawLayer: this.drawLayer.getDrawLayer(), + onAppend: annotationEditorLayerDiv => { + this.#addLayer(annotationEditorLayerDiv, "annotationEditorLayer"); + } }); } this.#renderAnnotationEditorLayer(); @@ -8447,6 +8487,7 @@ class PDFViewer { #annotationMode = AnnotationMode.ENABLE_FORMS; #containerTopLeft = null; #copyCallbackBound = null; + #enableHighlightFloatingButton = false; #enablePermissions = false; #mlManager = null; #getAllTextInProgress = false; @@ -8459,7 +8500,7 @@ class PDFViewer { #scaleTimeoutId = null; #textLayerMode = TextLayerMode.ENABLE; constructor(options) { - const viewerVersion = "4.1.249"; + const viewerVersion = "4.1.342"; if (version !== viewerVersion) { throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`); } @@ -8479,6 +8520,7 @@ class PDFViewer { this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS; this.#annotationEditorMode = options.annotationEditorMode ?? AnnotationEditorType.NONE; this.#annotationEditorHighlightColors = options.annotationEditorHighlightColors || null; + this.#enableHighlightFloatingButton = options.enableHighlightFloatingButton === true; this.imageResourcesPath = options.imageResourcesPath || ""; this.enablePrintAutoRotate = options.enablePrintAutoRotate || false; this.maxCanvasPixels = options.maxCanvasPixels; @@ -8789,7 +8831,9 @@ class PDFViewer { } const pagesCount = pdfDocument.numPages; const firstPagePromise = pdfDocument.getPage(1); - const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({ + intent: "display" + }); const permissionsPromise = this.#enablePermissions ? pdfDocument.getPermissions() : Promise.resolve(); if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) { console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document."); @@ -8845,7 +8889,7 @@ class PDFViewer { if (pdfDocument.isPureXfa) { console.warn("Warning: XFA-editing is not implemented."); } else if (isValidAnnotationEditorMode(mode)) { - this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, this.viewer, this.#altTextManager, this.eventBus, pdfDocument, this.pageColors, this.#annotationEditorHighlightColors, this.#mlManager); + this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, this.viewer, this.#altTextManager, this.eventBus, pdfDocument, this.pageColors, this.#annotationEditorHighlightColors, this.#enableHighlightFloatingButton, this.#mlManager); this.eventBus.dispatch("annotationeditoruimanager", { source: this, uiManager: this.#annotationEditorUIManager @@ -9506,7 +9550,9 @@ class PDFViewer { } if (!this._optionalContentConfigPromise) { console.error("optionalContentConfigPromise: Not initialized yet."); - return this.pdfDocument.getOptionalContentConfig(); + return this.pdfDocument.getOptionalContentConfig({ + intent: "display" + }); } return this._optionalContentConfigPromise; } @@ -10694,6 +10740,7 @@ const PDFViewerApplication = { annotationMode: AppOptions.get("annotationMode"), annotationEditorMode, annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"), + enableHighlightFloatingButton: AppOptions.get("enableHighlightFloatingButton"), imageResourcesPath: AppOptions.get("imageResourcesPath"), enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"), maxCanvasPixels: AppOptions.get("maxCanvasPixels"), @@ -10833,40 +10880,8 @@ const PDFViewerApplication = { if (this.supportsIntegratedFind) { appConfig.toolbar?.viewFind?.classList.add("hidden"); } - this.initPassiveLoading(file); - const { - mainContainer - } = appConfig; - ({ - scrollTop: this._lastScrollTop, - scrollLeft: this._lastScrollLeft - } = mainContainer); - const scroll = () => { - if (this._lastScrollTop === mainContainer.scrollTop && this._lastScrollLeft === mainContainer.scrollLeft) { - return; - } - mainContainer.removeEventListener("scroll", scroll, { - passive: true - }); - this._isScrolling = true; - const scrollend = () => { - ({ - scrollTop: this._lastScrollTop, - scrollLeft: this._lastScrollLeft - } = mainContainer); - this._isScrolling = false; - mainContainer.addEventListener("scroll", scroll, { - passive: true - }); - mainContainer.removeEventListener("scrollend", scrollend); - mainContainer.removeEventListener("blur", scrollend); - }; - mainContainer.addEventListener("scrollend", scrollend); - mainContainer.addEventListener("blur", scrollend); - }; - mainContainer.addEventListener("scroll", scroll, { - passive: true - }); + this.setTitleUsingUrl(file, file); + this.externalServices.initPassiveLoading(); }, get externalServices() { return shadow(this, "externalServices", new ExternalServices()); @@ -10939,45 +10954,12 @@ const PDFViewerApplication = { return shadow(this, "supportsMouseWheelZoomMetaKey", AppOptions.get("supportsMouseWheelZoomMetaKey")); }, get supportsCaretBrowsingMode() { - return shadow(this, "supportsCaretBrowsingMode", AppOptions.get("supportsCaretBrowsingMode")); + return AppOptions.get("supportsCaretBrowsingMode"); }, moveCaret(isUp, select) { this._caretBrowsing ||= new CaretBrowsingMode(this.appConfig.mainContainer, this.appConfig.viewerContainer, this.appConfig.toolbar?.container); this._caretBrowsing.moveCaret(isUp, select); }, - initPassiveLoading(file) { - this.setTitleUsingUrl(file, file); - this.externalServices.initPassiveLoading({ - onOpenWithTransport: range => { - this.open({ - range - }); - }, - onOpenWithData: (data, contentDispositionFilename) => { - if (isPdfFile(contentDispositionFilename)) { - this._contentDispositionFilename = contentDispositionFilename; - } - this.open({ - data - }); - }, - onOpenWithURL: (url, length, originalUrl) => { - this.open({ - url, - length, - originalUrl - }); - }, - onError: err => { - this.l10n.get("pdfjs-loading-error").then(msg => { - this._documentError(msg, err); - }); - }, - onProgress: (loaded, total) => { - this.progress(loaded / total); - } - }); - }, setTitleUsingUrl(url = "", downloadUrl = null) { this.url = url; this.baseUrl = url.split("#", 1)[0]; @@ -11065,6 +11047,9 @@ const PDFViewerApplication = { } const workerParams = AppOptions.getAll(OptionKind.WORKER); Object.assign(GlobalWorkerOptions, workerParams); + if (args.data && isPdfFile(args.filename)) { + this._contentDispositionFilename = args.filename; + } AppOptions.set("docBaseUrl", this.baseUrl); const apiParams = AppOptions.getAll(OptionKind.API); const loadingTask = getDocument({ @@ -11100,10 +11085,9 @@ const PDFViewerApplication = { } else if (reason instanceof UnexpectedResponseException) { key = "pdfjs-unexpected-response-error"; } - return this.l10n.get(key).then(msg => { - this._documentError(msg, { - message: reason?.message - }); + return this._documentError(key, { + message: reason.message + }).then(() => { throw reason; }); }); @@ -11167,21 +11151,17 @@ const PDFViewerApplication = { this.download(options); } }, - openInExternalApp() { - this.downloadOrSave({ - openInExternalApp: true - }); - }, - _documentError(message, moreInfo = null) { + async _documentError(key, moreInfo = null) { this._unblockDocumentLoadEvent(); - this._otherError(message, moreInfo); + const message = await this._otherError(key || "pdfjs-loading-error", moreInfo); this.eventBus.dispatch("documenterror", { source: this, message, reason: moreInfo?.message ?? null }); }, - _otherError(message, moreInfo = null) { + async _otherError(key, moreInfo = null) { + const message = await this.l10n.get(key); const moreInfoText = [`PDF.js v${version || "?"} (build: ${build || "?"})`]; if (moreInfo) { moreInfoText.push(`Message: ${moreInfo.message}`); @@ -11197,6 +11177,7 @@ const PDFViewerApplication = { } } console.error(`${message}\n\n${moreInfoText.join("\n")}`); + return message; }, progress(level) { if (!this.loadingBar || this.downloadComplete) { @@ -11321,10 +11302,8 @@ const PDFViewerApplication = { this._unblockDocumentLoadEvent(); this._initializeAutoPrint(pdfDocument, openActionPromise); }, reason => { - this.l10n.get("pdfjs-loading-error").then(msg => { - this._documentError(msg, { - message: reason?.message - }); + this._documentError("pdfjs-loading-error", { + message: reason.message }); }); onePageRendered.then(data => { @@ -11603,9 +11582,7 @@ const PDFViewerApplication = { return; } if (!this.supportsPrinting) { - this.l10n.get("pdfjs-printing-not-supported").then(msg => { - this._otherError(msg); - }); + this._otherError("pdfjs-printing-not-supported"); return; } if (!this.pdfViewer.pageViewsReady) { @@ -11619,7 +11596,6 @@ const PDFViewerApplication = { pagesOverview: this.pdfViewer.getPagesOverview(), printContainer: this.appConfig.printContainer, printResolution: AppOptions.get("printResolution"), - optionalContentConfigPromise: this.pdfViewer.optionalContentConfigPromise, printAnnotationStoragePromise: this._printAnnotationStoragePromise }); this.forceRendering(); @@ -11688,7 +11664,6 @@ const PDFViewerApplication = { eventBus._on("switchannotationeditorparams", webViewerSwitchAnnotationEditorParams); eventBus._on("print", webViewerPrint); eventBus._on("download", webViewerDownload); - eventBus._on("openinexternalapp", webViewerOpenInExternalApp); eventBus._on("firstpage", webViewerFirstPage); eventBus._on("lastpage", webViewerLastPage); eventBus._on("nextpage", webViewerNextPage); @@ -11720,7 +11695,10 @@ const PDFViewerApplication = { bindWindowEvents() { const { eventBus, - _boundEvents + _boundEvents, + appConfig: { + mainContainer + } } = this; function addWindowResolutionChange(evt = null) { if (evt) { @@ -11780,12 +11758,79 @@ const PDFViewerApplication = { window.addEventListener("beforeprint", _boundEvents.windowBeforePrint); window.addEventListener("afterprint", _boundEvents.windowAfterPrint); window.addEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + ({ + scrollTop: this._lastScrollTop, + scrollLeft: this._lastScrollLeft + } = mainContainer); + const scrollend = _boundEvents.mainContainerScrollend = () => { + ({ + scrollTop: this._lastScrollTop, + scrollLeft: this._lastScrollLeft + } = mainContainer); + this._isScrolling = false; + mainContainer.addEventListener("scroll", scroll, { + passive: true + }); + mainContainer.removeEventListener("scrollend", scrollend); + mainContainer.removeEventListener("blur", scrollend); + }; + const scroll = _boundEvents.mainContainerScroll = () => { + if (this._isCtrlKeyDown || this._lastScrollTop === mainContainer.scrollTop && this._lastScrollLeft === mainContainer.scrollLeft) { + return; + } + mainContainer.removeEventListener("scroll", scroll, { + passive: true + }); + this._isScrolling = true; + mainContainer.addEventListener("scrollend", scrollend); + mainContainer.addEventListener("blur", scrollend); + }; + mainContainer.addEventListener("scroll", scroll, { + passive: true + }); }, unbindEvents() { throw new Error("Not implemented: unbindEvents"); }, unbindWindowEvents() { - throw new Error("Not implemented: unbindWindowEvents"); + const { + _boundEvents, + appConfig: { + mainContainer + } + } = this; + window.removeEventListener("visibilitychange", webViewerVisibilityChange); + window.removeEventListener("wheel", webViewerWheel, { + passive: false + }); + window.removeEventListener("touchstart", webViewerTouchStart, { + passive: false + }); + window.removeEventListener("touchmove", webViewerTouchMove, { + passive: false + }); + window.removeEventListener("touchend", webViewerTouchEnd, { + passive: false + }); + window.removeEventListener("click", webViewerClick); + window.removeEventListener("keydown", webViewerKeyDown); + window.removeEventListener("keyup", webViewerKeyUp); + window.removeEventListener("resize", _boundEvents.windowResize); + window.removeEventListener("hashchange", _boundEvents.windowHashChange); + window.removeEventListener("beforeprint", _boundEvents.windowBeforePrint); + window.removeEventListener("afterprint", _boundEvents.windowAfterPrint); + window.removeEventListener("updatefromsandbox", _boundEvents.windowUpdateFromSandbox); + mainContainer.removeEventListener("scroll", _boundEvents.mainContainerScroll); + mainContainer.removeEventListener("scrollend", _boundEvents.mainContainerScrollend); + mainContainer.removeEventListener("blur", _boundEvents.mainContainerScrollend); + _boundEvents.removeWindowResolutionChange?.(); + _boundEvents.windowResize = null; + _boundEvents.windowHashChange = null; + _boundEvents.windowBeforePrint = null; + _boundEvents.windowAfterPrint = null; + _boundEvents.windowUpdateFromSandbox = null; + _boundEvents.mainContainerScroll = null; + _boundEvents.mainContainerScrollend = null; }, _accumulateTicks(ticks, prop) { if (this[prop] > 0 && ticks < 0 || this[prop] < 0 && ticks > 0) { @@ -11868,9 +11913,7 @@ function webViewerPageRendered({ } } if (error) { - PDFViewerApplication.l10n.get("pdfjs-rendering-error").then(msg => { - PDFViewerApplication._otherError(msg, error); - }); + PDFViewerApplication._otherError("pdfjs-rendering-error", error); } } function webViewerPageMode({ @@ -12000,9 +12043,6 @@ function webViewerPrint() { function webViewerDownload() { PDFViewerApplication.downloadOrSave(); } -function webViewerOpenInExternalApp() { - PDFViewerApplication.openInExternalApp(); -} function webViewerFirstPage() { PDFViewerApplication.page = 1; } @@ -12591,8 +12631,8 @@ function webViewerReportTelemetry({ -const pdfjsVersion = "4.1.249"; -const pdfjsBuild = "d07f37f44"; +const pdfjsVersion = "4.1.342"; +const pdfjsBuild = "e384df6f1"; const AppConstants = null; window.PDFViewerApplication = PDFViewerApplication; window.PDFViewerApplicationConstants = AppConstants; @@ -12718,7 +12758,8 @@ function getViewerConfiguration() { editorInkThickness: document.getElementById("editorInkThickness"), editorInkOpacity: document.getElementById("editorInkOpacity"), editorStampAddImage: document.getElementById("editorStampAddImage"), - editorFreeHighlightThickness: document.getElementById("editorFreeHighlightThickness") + editorFreeHighlightThickness: document.getElementById("editorFreeHighlightThickness"), + editorHighlightShowAll: document.getElementById("editorHighlightShowAll") }, printContainer: document.getElementById("printContainer") }; |