123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- /* Copyright 2014 Mozilla Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /** @typedef {import("../src/display/api").PDFPageProxy} PDFPageProxy */
- // eslint-disable-next-line max-len
- /** @typedef {import("../src/display/display_utils").PageViewport} PageViewport */
- /** @typedef {import("./interfaces").IDownloadManager} IDownloadManager */
- /** @typedef {import("./interfaces").IL10n} IL10n */
- /** @typedef {import("./interfaces").IPDFLinkService} IPDFLinkService */
- // eslint-disable-next-line max-len
- /** @typedef {import("./textaccessibility.js").TextAccessibilityManager} TextAccessibilityManager */
- import { AnnotationLayer } from "pdfjs-lib";
- import { NullL10n } from "./l10n_utils.js";
- import { PresentationModeState } from "./ui_utils.js";
- /**
- * @typedef {Object} AnnotationLayerBuilderOptions
- * @property {HTMLDivElement} pageDiv
- * @property {PDFPageProxy} pdfPage
- * @property {AnnotationStorage} [annotationStorage]
- * @property {string} [imageResourcesPath] - Path for image resources, mainly
- * for annotation icons. Include trailing slash.
- * @property {boolean} renderForms
- * @property {IPDFLinkService} linkService
- * @property {IDownloadManager} downloadManager
- * @property {IL10n} l10n - Localization service.
- * @property {boolean} [enableScripting]
- * @property {Promise<boolean>} [hasJSActionsPromise]
- * @property {Promise<Object<string, Array<Object>> | null>}
- * [fieldObjectsPromise]
- * @property {Map<string, HTMLCanvasElement>} [annotationCanvasMap]
- * @property {TextAccessibilityManager} [accessibilityManager]
- */
- class AnnotationLayerBuilder {
- #numAnnotations = 0;
- #onPresentationModeChanged = null;
- /**
- * @param {AnnotationLayerBuilderOptions} options
- */
- constructor({
- pageDiv,
- pdfPage,
- linkService,
- downloadManager,
- annotationStorage = null,
- imageResourcesPath = "",
- renderForms = true,
- l10n = NullL10n,
- enableScripting = false,
- hasJSActionsPromise = null,
- fieldObjectsPromise = null,
- annotationCanvasMap = null,
- accessibilityManager = null,
- }) {
- this.pageDiv = pageDiv;
- this.pdfPage = pdfPage;
- this.linkService = linkService;
- this.downloadManager = downloadManager;
- this.imageResourcesPath = imageResourcesPath;
- this.renderForms = renderForms;
- this.l10n = l10n;
- this.annotationStorage = annotationStorage;
- this.enableScripting = enableScripting;
- this._hasJSActionsPromise = hasJSActionsPromise || Promise.resolve(false);
- this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null);
- this._annotationCanvasMap = annotationCanvasMap;
- this._accessibilityManager = accessibilityManager;
- this.div = null;
- this._cancelled = false;
- this._eventBus = linkService.eventBus;
- }
- /**
- * @param {PageViewport} viewport
- * @param {string} intent (default value is 'display')
- * @returns {Promise<void>} A promise that is resolved when rendering of the
- * annotations is complete.
- */
- async render(viewport, intent = "display") {
- if (this.div) {
- if (this._cancelled || this.#numAnnotations === 0) {
- return;
- }
- // If an annotationLayer already exists, refresh its children's
- // transformation matrices.
- AnnotationLayer.update({
- viewport: viewport.clone({ dontFlip: true }),
- div: this.div,
- annotationCanvasMap: this._annotationCanvasMap,
- });
- return;
- }
- const [annotations, hasJSActions, fieldObjects] = await Promise.all([
- this.pdfPage.getAnnotations({ intent }),
- this._hasJSActionsPromise,
- this._fieldObjectsPromise,
- ]);
- if (this._cancelled) {
- return;
- }
- this.#numAnnotations = annotations.length;
- // Create an annotation layer div and render the annotations
- // if there is at least one annotation.
- this.div = document.createElement("div");
- this.div.className = "annotationLayer";
- this.pageDiv.append(this.div);
- if (this.#numAnnotations === 0) {
- this.hide();
- return;
- }
- AnnotationLayer.render({
- viewport: viewport.clone({ dontFlip: true }),
- div: this.div,
- annotations,
- page: this.pdfPage,
- imageResourcesPath: this.imageResourcesPath,
- renderForms: this.renderForms,
- linkService: this.linkService,
- downloadManager: this.downloadManager,
- annotationStorage: this.annotationStorage,
- enableScripting: this.enableScripting,
- hasJSActions,
- fieldObjects,
- annotationCanvasMap: this._annotationCanvasMap,
- accessibilityManager: this._accessibilityManager,
- });
- this.l10n.translate(this.div);
- // Ensure that interactive form elements in the annotationLayer are
- // disabled while PresentationMode is active (see issue 12232).
- if (this.linkService.isInPresentationMode) {
- this.#updatePresentationModeState(PresentationModeState.FULLSCREEN);
- }
- if (!this.#onPresentationModeChanged) {
- this.#onPresentationModeChanged = evt => {
- this.#updatePresentationModeState(evt.state);
- };
- this._eventBus?._on(
- "presentationmodechanged",
- this.#onPresentationModeChanged
- );
- }
- }
- cancel() {
- this._cancelled = true;
- if (this.#onPresentationModeChanged) {
- this._eventBus?._off(
- "presentationmodechanged",
- this.#onPresentationModeChanged
- );
- this.#onPresentationModeChanged = null;
- }
- }
- hide() {
- if (!this.div) {
- return;
- }
- this.div.hidden = true;
- }
- #updatePresentationModeState(state) {
- if (!this.div) {
- return;
- }
- let disableFormElements = false;
- switch (state) {
- case PresentationModeState.FULLSCREEN:
- disableFormElements = true;
- break;
- case PresentationModeState.NORMAL:
- break;
- default:
- return;
- }
- for (const section of this.div.childNodes) {
- if (section.hasAttribute("data-internal-link")) {
- continue;
- }
- section.inert = disableFormElements;
- }
- }
- }
- export { AnnotationLayerBuilder };
|