Merge pull request #14362 from Snuffleupagus/issue-14356
Support disabling of form editing when `pdfjs.enablePermissions` is set (issue 14356)
This commit is contained in:
commit
6d8d37e93d
35
web/app.js
35
web/app.js
@ -51,7 +51,6 @@ import {
|
|||||||
MissingPDFException,
|
MissingPDFException,
|
||||||
OPS,
|
OPS,
|
||||||
PDFWorker,
|
PDFWorker,
|
||||||
PermissionFlag,
|
|
||||||
shadow,
|
shadow,
|
||||||
UnexpectedResponseException,
|
UnexpectedResponseException,
|
||||||
UNSUPPORTED_FEATURES,
|
UNSUPPORTED_FEATURES,
|
||||||
@ -82,7 +81,6 @@ import { ViewHistory } from "./view_history.js";
|
|||||||
const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; // ms
|
const DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000; // ms
|
||||||
const FORCE_PAGES_LOADED_TIMEOUT = 10000; // ms
|
const FORCE_PAGES_LOADED_TIMEOUT = 10000; // ms
|
||||||
const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; // ms
|
const WHEEL_ZOOM_DISABLED_TIMEOUT = 1000; // ms
|
||||||
const ENABLE_PERMISSIONS_CLASS = "enablePermissions";
|
|
||||||
|
|
||||||
const ViewOnLoad = {
|
const ViewOnLoad = {
|
||||||
UNKNOWN: -1,
|
UNKNOWN: -1,
|
||||||
@ -530,6 +528,7 @@ const PDFViewerApplication = {
|
|||||||
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
|
||||||
useOnlyCssZoom: AppOptions.get("useOnlyCssZoom"),
|
useOnlyCssZoom: AppOptions.get("useOnlyCssZoom"),
|
||||||
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
||||||
|
enablePermissions: AppOptions.get("enablePermissions"),
|
||||||
});
|
});
|
||||||
pdfRenderingQueue.setViewer(this.pdfViewer);
|
pdfRenderingQueue.setViewer(this.pdfViewer);
|
||||||
pdfLinkService.setViewer(this.pdfViewer);
|
pdfLinkService.setViewer(this.pdfViewer);
|
||||||
@ -841,7 +840,6 @@ const PDFViewerApplication = {
|
|||||||
this.pdfLinkService.setDocument(null);
|
this.pdfLinkService.setDocument(null);
|
||||||
this.pdfDocumentProperties.setDocument(null);
|
this.pdfDocumentProperties.setDocument(null);
|
||||||
}
|
}
|
||||||
webViewerResetPermissions();
|
|
||||||
this.pdfLinkService.externalLinkEnabled = true;
|
this.pdfLinkService.externalLinkEnabled = true;
|
||||||
this._fellback = false;
|
this._fellback = false;
|
||||||
this.store = null;
|
this.store = null;
|
||||||
@ -1326,10 +1324,6 @@ const PDFViewerApplication = {
|
|||||||
pdfViewer.focus();
|
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
|
// For documents with different page sizes, once all pages are
|
||||||
// resolved, ensure that the correct location becomes visible on load.
|
// resolved, ensure that the correct location becomes visible on load.
|
||||||
// (To reduce the risk, in very large and/or slow loading documents,
|
// (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
|
* @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 }) {
|
function webViewerPageRendered({ pageNumber, error }) {
|
||||||
// If the page is still visible when it has finished rendering,
|
// If the page is still visible when it has finished rendering,
|
||||||
// ensure that the page number input loading indicator is hidden.
|
// ensure that the page number input loading indicator is hidden.
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
import {
|
import {
|
||||||
AnnotationMode,
|
AnnotationMode,
|
||||||
createPromiseCapability,
|
createPromiseCapability,
|
||||||
|
PermissionFlag,
|
||||||
PixelsPerInch,
|
PixelsPerInch,
|
||||||
version,
|
version,
|
||||||
} from "pdfjs-lib";
|
} from "pdfjs-lib";
|
||||||
@ -53,6 +54,7 @@ import { TextLayerBuilder } from "./text_layer_builder.js";
|
|||||||
import { XfaLayerBuilder } from "./xfa_layer_builder.js";
|
import { XfaLayerBuilder } from "./xfa_layer_builder.js";
|
||||||
|
|
||||||
const DEFAULT_CACHE_SIZE = 10;
|
const DEFAULT_CACHE_SIZE = 10;
|
||||||
|
const ENABLE_PERMISSIONS_CLASS = "enablePermissions";
|
||||||
|
|
||||||
const PagesCountLimit = {
|
const PagesCountLimit = {
|
||||||
FORCE_SCROLL_MODE_PAGE: 15000,
|
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
|
* total pixels, i.e. width * height. Use -1 for no limit. The default value
|
||||||
* is 4096 * 4096 (16 mega-pixels).
|
* is 4096 * 4096 (16 mega-pixels).
|
||||||
* @property {IL10n} l10n - Localization service.
|
* @property {IL10n} l10n - Localization service.
|
||||||
|
* @property {boolean} [enablePermissions] - Enables PDF document permissions,
|
||||||
|
* when they exist. The default value is `false`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PDFPageViewBuffer {
|
class PDFPageViewBuffer {
|
||||||
@ -171,6 +175,12 @@ class PDFPageViewBuffer {
|
|||||||
class BaseViewer {
|
class BaseViewer {
|
||||||
#buffer = null;
|
#buffer = null;
|
||||||
|
|
||||||
|
#annotationMode = AnnotationMode.ENABLE_FORMS;
|
||||||
|
|
||||||
|
#previousAnnotationMode = null;
|
||||||
|
|
||||||
|
#enablePermissions = false;
|
||||||
|
|
||||||
#previousContainerHeight = 0;
|
#previousContainerHeight = 0;
|
||||||
|
|
||||||
#scrollModePageState = null;
|
#scrollModePageState = null;
|
||||||
@ -219,7 +229,7 @@ class BaseViewer {
|
|||||||
this._scriptingManager = options.scriptingManager || null;
|
this._scriptingManager = options.scriptingManager || null;
|
||||||
this.removePageBorders = options.removePageBorders || false;
|
this.removePageBorders = options.removePageBorders || false;
|
||||||
this.textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
|
this.textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
|
||||||
this._annotationMode =
|
this.#annotationMode =
|
||||||
options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
|
options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
|
||||||
this.imageResourcesPath = options.imageResourcesPath || "";
|
this.imageResourcesPath = options.imageResourcesPath || "";
|
||||||
this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
|
this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
|
||||||
@ -227,6 +237,7 @@ class BaseViewer {
|
|||||||
this.useOnlyCssZoom = options.useOnlyCssZoom || false;
|
this.useOnlyCssZoom = options.useOnlyCssZoom || false;
|
||||||
this.maxCanvasPixels = options.maxCanvasPixels;
|
this.maxCanvasPixels = options.maxCanvasPixels;
|
||||||
this.l10n = options.l10n || NullL10n;
|
this.l10n = options.l10n || NullL10n;
|
||||||
|
this.#enablePermissions = options.enablePermissions || false;
|
||||||
|
|
||||||
this.defaultRenderingQueue = !options.renderingQueue;
|
this.defaultRenderingQueue = !options.renderingQueue;
|
||||||
if (this.defaultRenderingQueue) {
|
if (this.defaultRenderingQueue) {
|
||||||
@ -279,7 +290,7 @@ class BaseViewer {
|
|||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get renderForms() {
|
get renderForms() {
|
||||||
return this._annotationMode === AnnotationMode.ENABLE_FORMS;
|
return this.#annotationMode === AnnotationMode.ENABLE_FORMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -473,9 +484,32 @@ class BaseViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* Currently only *some* permissions are supported.
|
||||||
*/
|
*/
|
||||||
_onePageRenderedOrForceFetch() {
|
#initializePermissions(permissions, pdfDocument) {
|
||||||
|
if (pdfDocument !== this.pdfDocument) {
|
||||||
|
return; // The document was closed while the permissions resolved.
|
||||||
|
}
|
||||||
|
if (!permissions || !this.#enablePermissions) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!permissions.includes(PermissionFlag.COPY)) {
|
||||||
|
this.viewer.classList.add(ENABLE_PERMISSIONS_CLASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!permissions.includes(PermissionFlag.MODIFY_ANNOTATIONS) &&
|
||||||
|
!permissions.includes(PermissionFlag.FILL_INTERACTIVE_FORMS)
|
||||||
|
) {
|
||||||
|
if (this.#annotationMode === AnnotationMode.ENABLE_FORMS) {
|
||||||
|
this.#previousAnnotationMode = this.#annotationMode; // Allow resetting.
|
||||||
|
this.#annotationMode = AnnotationMode.ENABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#onePageRenderedOrForceFetch() {
|
||||||
// Unless the viewer *and* its pages are visible, rendering won't start and
|
// Unless the viewer *and* its pages are visible, rendering won't start and
|
||||||
// `this._onePageRenderedCapability` thus won't be resolved.
|
// `this._onePageRenderedCapability` thus won't be resolved.
|
||||||
// To ensure that automatic printing, on document load, still works even in
|
// To ensure that automatic printing, on document load, still works even in
|
||||||
@ -520,6 +554,7 @@ class BaseViewer {
|
|||||||
const firstPagePromise = pdfDocument.getPage(1);
|
const firstPagePromise = pdfDocument.getPage(1);
|
||||||
// Rendering (potentially) depends on this, hence fetching it immediately.
|
// Rendering (potentially) depends on this, hence fetching it immediately.
|
||||||
const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig();
|
const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig();
|
||||||
|
const permissionsPromise = pdfDocument.getPermissions();
|
||||||
|
|
||||||
// Given that browsers don't handle huge amounts of DOM-elements very well,
|
// Given that browsers don't handle huge amounts of DOM-elements very well,
|
||||||
// enforce usage of PAGE-scrolling when loading *very* long/large documents.
|
// enforce usage of PAGE-scrolling when loading *very* long/large documents.
|
||||||
@ -564,10 +599,11 @@ class BaseViewer {
|
|||||||
|
|
||||||
// Fetch a single page so we can get a viewport that will be the default
|
// Fetch a single page so we can get a viewport that will be the default
|
||||||
// viewport for all pages
|
// viewport for all pages
|
||||||
firstPagePromise
|
Promise.all([firstPagePromise, permissionsPromise])
|
||||||
.then(firstPdfPage => {
|
.then(([firstPdfPage, permissions]) => {
|
||||||
this._firstPageCapability.resolve(firstPdfPage);
|
this._firstPageCapability.resolve(firstPdfPage);
|
||||||
this._optionalContentConfigPromise = optionalContentConfigPromise;
|
this._optionalContentConfigPromise = optionalContentConfigPromise;
|
||||||
|
this.#initializePermissions(permissions, pdfDocument);
|
||||||
|
|
||||||
const viewerElement =
|
const viewerElement =
|
||||||
this._scrollMode === ScrollMode.PAGE ? null : this.viewer;
|
this._scrollMode === ScrollMode.PAGE ? null : this.viewer;
|
||||||
@ -580,7 +616,7 @@ class BaseViewer {
|
|||||||
? this
|
? this
|
||||||
: null;
|
: null;
|
||||||
const annotationLayerFactory =
|
const annotationLayerFactory =
|
||||||
this._annotationMode !== AnnotationMode.DISABLE ? this : null;
|
this.#annotationMode !== AnnotationMode.DISABLE ? this : null;
|
||||||
const xfaLayerFactory = isPureXfa ? this : null;
|
const xfaLayerFactory = isPureXfa ? this : null;
|
||||||
|
|
||||||
for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
|
for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
|
||||||
@ -595,7 +631,7 @@ class BaseViewer {
|
|||||||
textLayerFactory,
|
textLayerFactory,
|
||||||
textLayerMode: this.textLayerMode,
|
textLayerMode: this.textLayerMode,
|
||||||
annotationLayerFactory,
|
annotationLayerFactory,
|
||||||
annotationMode: this._annotationMode,
|
annotationMode: this.#annotationMode,
|
||||||
xfaLayerFactory,
|
xfaLayerFactory,
|
||||||
textHighlighterFactory: this,
|
textHighlighterFactory: this,
|
||||||
structTreeLayerFactory: this,
|
structTreeLayerFactory: this,
|
||||||
@ -626,7 +662,7 @@ class BaseViewer {
|
|||||||
// Fetch all the pages since the viewport is needed before printing
|
// Fetch all the pages since the viewport is needed before printing
|
||||||
// starts to create the correct size canvas. Wait until one page is
|
// starts to create the correct size canvas. Wait until one page is
|
||||||
// rendered so we don't tie up too many resources early on.
|
// rendered so we don't tie up too many resources early on.
|
||||||
this._onePageRenderedOrForceFetch().then(async () => {
|
this.#onePageRenderedOrForceFetch().then(async () => {
|
||||||
if (this.findController) {
|
if (this.findController) {
|
||||||
this.findController.setDocument(pdfDocument); // Enable searching.
|
this.findController.setDocument(pdfDocument); // Enable searching.
|
||||||
}
|
}
|
||||||
@ -750,6 +786,14 @@ class BaseViewer {
|
|||||||
this.viewer.textContent = "";
|
this.viewer.textContent = "";
|
||||||
// ... and reset the Scroll mode CSS class(es) afterwards.
|
// ... and reset the Scroll mode CSS class(es) afterwards.
|
||||||
this._updateScrollMode();
|
this._updateScrollMode();
|
||||||
|
|
||||||
|
// Reset all PDF document permissions.
|
||||||
|
this.viewer.classList.remove(ENABLE_PERMISSIONS_CLASS);
|
||||||
|
|
||||||
|
if (this.#previousAnnotationMode !== null) {
|
||||||
|
this.#annotationMode = this.#previousAnnotationMode;
|
||||||
|
this.#previousAnnotationMode = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ensurePageViewVisible() {
|
#ensurePageViewVisible() {
|
||||||
|
@ -76,6 +76,8 @@ const MAX_CANVAS_PIXELS = compatibilityParams.maxCanvasPixels || 16777216;
|
|||||||
* @implements {IRenderableView}
|
* @implements {IRenderableView}
|
||||||
*/
|
*/
|
||||||
class PDFPageView {
|
class PDFPageView {
|
||||||
|
#annotationMode = AnnotationMode.ENABLE_FORMS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PDFPageViewOptions} options
|
* @param {PDFPageViewOptions} options
|
||||||
*/
|
*/
|
||||||
@ -96,7 +98,7 @@ class PDFPageView {
|
|||||||
options.optionalContentConfigPromise || null;
|
options.optionalContentConfigPromise || null;
|
||||||
this.hasRestrictedScaling = false;
|
this.hasRestrictedScaling = false;
|
||||||
this.textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
|
this.textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
|
||||||
this._annotationMode =
|
this.#annotationMode =
|
||||||
options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
|
options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
|
||||||
this.imageResourcesPath = options.imageResourcesPath || "";
|
this.imageResourcesPath = options.imageResourcesPath || "";
|
||||||
this.useOnlyCssZoom = options.useOnlyCssZoom || false;
|
this.useOnlyCssZoom = options.useOnlyCssZoom || false;
|
||||||
@ -597,7 +599,7 @@ class PDFPageView {
|
|||||||
this.textLayer = textLayer;
|
this.textLayer = textLayer;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this._annotationMode !== AnnotationMode.DISABLE &&
|
this.#annotationMode !== AnnotationMode.DISABLE &&
|
||||||
this.annotationLayerFactory
|
this.annotationLayerFactory
|
||||||
) {
|
) {
|
||||||
this._annotationCanvasMap ||= new Map();
|
this._annotationCanvasMap ||= new Map();
|
||||||
@ -607,7 +609,7 @@ class PDFPageView {
|
|||||||
pdfPage,
|
pdfPage,
|
||||||
/* annotationStorage = */ null,
|
/* annotationStorage = */ null,
|
||||||
this.imageResourcesPath,
|
this.imageResourcesPath,
|
||||||
this._annotationMode === AnnotationMode.ENABLE_FORMS,
|
this.#annotationMode === AnnotationMode.ENABLE_FORMS,
|
||||||
this.l10n,
|
this.l10n,
|
||||||
/* enableScripting = */ null,
|
/* enableScripting = */ null,
|
||||||
/* hasJSActionsPromise = */ null,
|
/* hasJSActionsPromise = */ null,
|
||||||
@ -835,7 +837,7 @@ class PDFPageView {
|
|||||||
canvasContext: ctx,
|
canvasContext: ctx,
|
||||||
transform,
|
transform,
|
||||||
viewport: this.viewport,
|
viewport: this.viewport,
|
||||||
annotationMode: this._annotationMode,
|
annotationMode: this.#annotationMode,
|
||||||
optionalContentConfigPromise: this._optionalContentConfigPromise,
|
optionalContentConfigPromise: this._optionalContentConfigPromise,
|
||||||
annotationCanvasMap: this._annotationCanvasMap,
|
annotationCanvasMap: this._annotationCanvasMap,
|
||||||
};
|
};
|
||||||
@ -892,7 +894,7 @@ class PDFPageView {
|
|||||||
});
|
});
|
||||||
const promise = pdfPage
|
const promise = pdfPage
|
||||||
.getOperatorList({
|
.getOperatorList({
|
||||||
annotationMode: this._annotationMode,
|
annotationMode: this.#annotationMode,
|
||||||
})
|
})
|
||||||
.then(opList => {
|
.then(opList => {
|
||||||
ensureNotCancelled();
|
ensureNotCancelled();
|
||||||
|
@ -141,6 +141,11 @@
|
|||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pdfViewer.enablePermissions .textLayer span {
|
||||||
|
user-select: none !important;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.pdfPresentationMode .pdfViewer {
|
.pdfPresentationMode .pdfViewer {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
@ -204,11 +204,6 @@ select {
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pdfViewer.enablePermissions .textLayer span {
|
|
||||||
user-select: none !important;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
#viewerContainer.pdfPresentationMode:fullscreen {
|
#viewerContainer.pdfPresentationMode:fullscreen {
|
||||||
top: 0;
|
top: 0;
|
||||||
background-color: rgba(0, 0, 0, 1);
|
background-color: rgba(0, 0, 0, 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user