| 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 };
 |