diff --git a/web/app.js b/web/app.js index 704ac1b95..451151b86 100644 --- a/web/app.js +++ b/web/app.js @@ -51,7 +51,6 @@ import { MissingPDFException, OPS, PDFWorker, - PermissionFlag, shadow, UnexpectedResponseException, UNSUPPORTED_FEATURES, @@ -82,7 +81,6 @@ import { ViewHistory } from "./view_history.js"; const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; // ms const FORCE_PAGES_LOADED_TIMEOUT = 10000; // ms const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; // ms -const ENABLE_PERMISSIONS_CLASS = "enablePermissions"; const ViewOnLoad = { UNKNOWN: -1, @@ -530,6 +528,7 @@ const PDFViewerApplication = { enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"), useOnlyCssZoom: AppOptions.get("useOnlyCssZoom"), maxCanvasPixels: AppOptions.get("maxCanvasPixels"), + enablePermissions: AppOptions.get("enablePermissions"), }); pdfRenderingQueue.setViewer(this.pdfViewer); pdfLinkService.setViewer(this.pdfViewer); @@ -841,7 +840,6 @@ const PDFViewerApplication = { this.pdfLinkService.setDocument(null); this.pdfDocumentProperties.setDocument(null); } - webViewerResetPermissions(); this.pdfLinkService.externalLinkEnabled = true; this._fellback = false; this.store = null; @@ -1326,10 +1324,6 @@ const PDFViewerApplication = { pdfViewer.focus(); } - // Currently only the "copy"-permission is supported, hence we delay - // the `getPermissions` API call until *after* rendering has started. - this._initializePermissions(pdfDocument); - // For documents with different page sizes, once all pages are // resolved, ensure that the correct location becomes visible on load. // (To reduce the risk, in very large and/or slow loading documents, @@ -1709,24 +1703,6 @@ const PDFViewerApplication = { } }, - /** - * @private - */ - async _initializePermissions(pdfDocument) { - const permissions = await pdfDocument.getPermissions(); - - if (pdfDocument !== this.pdfDocument) { - return; // The document was closed while the permissions resolved. - } - if (!permissions || !AppOptions.get("enablePermissions")) { - return; - } - // Currently only the "copy"-permission is supported. - if (!permissions.includes(PermissionFlag.COPY)) { - this.appConfig.viewerContainer.classList.add(ENABLE_PERMISSIONS_CLASS); - } - }, - /** * @private */ @@ -2335,15 +2311,6 @@ function webViewerOpenFileViaURL(file) { } } -function webViewerResetPermissions() { - const { appConfig } = PDFViewerApplication; - if (!appConfig) { - return; - } - // Currently only the "copy"-permission is supported. - appConfig.viewerContainer.classList.remove(ENABLE_PERMISSIONS_CLASS); -} - function webViewerPageRendered({ pageNumber, error }) { // If the page is still visible when it has finished rendering, // ensure that the page number input loading indicator is hidden. diff --git a/web/base_viewer.js b/web/base_viewer.js index 8fac5d0ce..2546edca5 100644 --- a/web/base_viewer.js +++ b/web/base_viewer.js @@ -16,6 +16,7 @@ import { AnnotationMode, createPromiseCapability, + PermissionFlag, PixelsPerInch, version, } from "pdfjs-lib"; @@ -53,6 +54,7 @@ import { TextLayerBuilder } from "./text_layer_builder.js"; import { XfaLayerBuilder } from "./xfa_layer_builder.js"; const DEFAULT_CACHE_SIZE = 10; +const ENABLE_PERMISSIONS_CLASS = "enablePermissions"; const PagesCountLimit = { FORCE_SCROLL_MODE_PAGE: 15000, @@ -95,6 +97,8 @@ const PagesCountLimit = { * total pixels, i.e. width * height. Use -1 for no limit. The default value * is 4096 * 4096 (16 mega-pixels). * @property {IL10n} l10n - Localization service. + * @property {boolean} [enablePermissions] - Enables PDF document permissions, + * when they exist. The default value is `false`. */ class PDFPageViewBuffer { @@ -171,6 +175,8 @@ class PDFPageViewBuffer { class BaseViewer { #buffer = null; + #enablePermissions = false; + #previousContainerHeight = 0; #scrollModePageState = null; @@ -227,6 +233,7 @@ class BaseViewer { this.useOnlyCssZoom = options.useOnlyCssZoom || false; this.maxCanvasPixels = options.maxCanvasPixels; this.l10n = options.l10n || NullL10n; + this.#enablePermissions = options.enablePermissions || false; this.defaultRenderingQueue = !options.renderingQueue; if (this.defaultRenderingQueue) { @@ -472,10 +479,20 @@ class BaseViewer { return this.pdfDocument ? this._pagesCapability.promise : null; } - /** - * @private - */ - _onePageRenderedOrForceFetch() { + #initializePermissions(permissions, pdfDocument) { + if (pdfDocument !== this.pdfDocument) { + return; // The document was closed while the permissions resolved. + } + if (!permissions || !this.#enablePermissions) { + return; + } + // Currently only the "copy"-permission is supported. + if (!permissions.includes(PermissionFlag.COPY)) { + this.viewer.classList.add(ENABLE_PERMISSIONS_CLASS); + } + } + + #onePageRenderedOrForceFetch() { // Unless the viewer *and* its pages are visible, rendering won't start and // `this._onePageRenderedCapability` thus won't be resolved. // To ensure that automatic printing, on document load, still works even in @@ -520,6 +537,7 @@ class BaseViewer { const firstPagePromise = pdfDocument.getPage(1); // Rendering (potentially) depends on this, hence fetching it immediately. const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig(); + const permissionsPromise = pdfDocument.getPermissions(); // Given that browsers don't handle huge amounts of DOM-elements very well, // enforce usage of PAGE-scrolling when loading *very* long/large documents. @@ -564,10 +582,11 @@ class BaseViewer { // Fetch a single page so we can get a viewport that will be the default // viewport for all pages - firstPagePromise - .then(firstPdfPage => { + Promise.all([firstPagePromise, permissionsPromise]) + .then(([firstPdfPage, permissions]) => { this._firstPageCapability.resolve(firstPdfPage); this._optionalContentConfigPromise = optionalContentConfigPromise; + this.#initializePermissions(permissions, pdfDocument); const viewerElement = this._scrollMode === ScrollMode.PAGE ? null : this.viewer; @@ -626,7 +645,7 @@ class BaseViewer { // Fetch all the pages since the viewport is needed before printing // starts to create the correct size canvas. Wait until one page is // rendered so we don't tie up too many resources early on. - this._onePageRenderedOrForceFetch().then(async () => { + this.#onePageRenderedOrForceFetch().then(async () => { if (this.findController) { this.findController.setDocument(pdfDocument); // Enable searching. } @@ -750,6 +769,9 @@ class BaseViewer { this.viewer.textContent = ""; // ... and reset the Scroll mode CSS class(es) afterwards. this._updateScrollMode(); + + // Reset all PDF document permissions. + this.viewer.classList.remove(ENABLE_PERMISSIONS_CLASS); } #ensurePageViewVisible() { diff --git a/web/pdf_viewer.css b/web/pdf_viewer.css index d98a17969..01c9cfa2d 100644 --- a/web/pdf_viewer.css +++ b/web/pdf_viewer.css @@ -141,6 +141,11 @@ background: none; } +.pdfViewer.enablePermissions .textLayer span { + user-select: none !important; + cursor: not-allowed; +} + .pdfPresentationMode .pdfViewer { padding-bottom: 0; } diff --git a/web/viewer.css b/web/viewer.css index a8810c528..0541efd3b 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -204,11 +204,6 @@ select { display: none !important; } -.pdfViewer.enablePermissions .textLayer span { - user-select: none !important; - cursor: not-allowed; -} - #viewerContainer.pdfPresentationMode:fullscreen { top: 0; background-color: rgba(0, 0, 0, 1);