| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 | 
							- /* Copyright 2012 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.
 
-  */
 
- // eslint-disable-next-line max-len
 
- /** @typedef {import("../src/display/display_utils").PageViewport} PageViewport */
 
- /** @typedef {import("../src/display/api").TextContent} TextContent */
 
- /** @typedef {import("./text_highlighter").TextHighlighter} TextHighlighter */
 
- // eslint-disable-next-line max-len
 
- /** @typedef {import("./text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */
 
- import { renderTextLayer, updateTextLayer } from "pdfjs-lib";
 
- /**
 
-  * @typedef {Object} TextLayerBuilderOptions
 
-  * @property {TextHighlighter} highlighter - Optional object that will handle
 
-  *   highlighting text from the find controller.
 
-  * @property {TextAccessibilityManager} [accessibilityManager]
 
-  * @property {boolean} [isOffscreenCanvasSupported] - Allows to use an
 
-  *   OffscreenCanvas if needed.
 
-  */
 
- /**
 
-  * The text layer builder provides text selection functionality for the PDF.
 
-  * It does this by creating overlay divs over the PDF's text. These divs
 
-  * contain text that matches the PDF text they are overlaying.
 
-  */
 
- class TextLayerBuilder {
 
-   #rotation = 0;
 
-   #scale = 0;
 
-   #textContentSource = null;
 
-   constructor({
 
-     highlighter = null,
 
-     accessibilityManager = null,
 
-     isOffscreenCanvasSupported = true,
 
-   }) {
 
-     this.textContentItemsStr = [];
 
-     this.renderingDone = false;
 
-     this.textDivs = [];
 
-     this.textDivProperties = new WeakMap();
 
-     this.textLayerRenderTask = null;
 
-     this.highlighter = highlighter;
 
-     this.accessibilityManager = accessibilityManager;
 
-     this.isOffscreenCanvasSupported = isOffscreenCanvasSupported;
 
-     this.div = document.createElement("div");
 
-     this.div.className = "textLayer";
 
-     this.hide();
 
-   }
 
-   #finishRendering() {
 
-     this.renderingDone = true;
 
-     const endOfContent = document.createElement("div");
 
-     endOfContent.className = "endOfContent";
 
-     this.div.append(endOfContent);
 
-     this.#bindMouse();
 
-   }
 
-   get numTextDivs() {
 
-     return this.textDivs.length;
 
-   }
 
-   /**
 
-    * Renders the text layer.
 
-    * @param {PageViewport} viewport
 
-    */
 
-   async render(viewport) {
 
-     if (!this.#textContentSource) {
 
-       throw new Error('No "textContentSource" parameter specified.');
 
-     }
 
-     const scale = viewport.scale * (globalThis.devicePixelRatio || 1);
 
-     const { rotation } = viewport;
 
-     if (this.renderingDone) {
 
-       const mustRotate = rotation !== this.#rotation;
 
-       const mustRescale = scale !== this.#scale;
 
-       if (mustRotate || mustRescale) {
 
-         this.hide();
 
-         updateTextLayer({
 
-           container: this.div,
 
-           viewport,
 
-           textDivs: this.textDivs,
 
-           textDivProperties: this.textDivProperties,
 
-           isOffscreenCanvasSupported: this.isOffscreenCanvasSupported,
 
-           mustRescale,
 
-           mustRotate,
 
-         });
 
-         this.#scale = scale;
 
-         this.#rotation = rotation;
 
-       }
 
-       this.show();
 
-       return;
 
-     }
 
-     this.cancel();
 
-     this.highlighter?.setTextMapping(this.textDivs, this.textContentItemsStr);
 
-     this.accessibilityManager?.setTextMapping(this.textDivs);
 
-     this.textLayerRenderTask = renderTextLayer({
 
-       textContentSource: this.#textContentSource,
 
-       container: this.div,
 
-       viewport,
 
-       textDivs: this.textDivs,
 
-       textDivProperties: this.textDivProperties,
 
-       textContentItemsStr: this.textContentItemsStr,
 
-       isOffscreenCanvasSupported: this.isOffscreenCanvasSupported,
 
-     });
 
-     await this.textLayerRenderTask.promise;
 
-     this.#finishRendering();
 
-     this.#scale = scale;
 
-     this.#rotation = rotation;
 
-     this.show();
 
-     this.accessibilityManager?.enable();
 
-   }
 
-   hide() {
 
-     if (!this.div.hidden) {
 
-       // We turn off the highlighter in order to avoid to scroll into view an
 
-       // element of the text layer which could be hidden.
 
-       this.highlighter?.disable();
 
-       this.div.hidden = true;
 
-     }
 
-   }
 
-   show() {
 
-     if (this.div.hidden && this.renderingDone) {
 
-       this.div.hidden = false;
 
-       this.highlighter?.enable();
 
-     }
 
-   }
 
-   /**
 
-    * Cancel rendering of the text layer.
 
-    */
 
-   cancel() {
 
-     if (this.textLayerRenderTask) {
 
-       this.textLayerRenderTask.cancel();
 
-       this.textLayerRenderTask = null;
 
-     }
 
-     this.highlighter?.disable();
 
-     this.accessibilityManager?.disable();
 
-     this.textContentItemsStr.length = 0;
 
-     this.textDivs.length = 0;
 
-     this.textDivProperties = new WeakMap();
 
-   }
 
-   /**
 
-    * @param {ReadableStream | TextContent} source
 
-    */
 
-   setTextContentSource(source) {
 
-     this.cancel();
 
-     this.#textContentSource = source;
 
-   }
 
-   /**
 
-    * Improves text selection by adding an additional div where the mouse was
 
-    * clicked. This reduces flickering of the content if the mouse is slowly
 
-    * dragged up or down.
 
-    */
 
-   #bindMouse() {
 
-     const { div } = this;
 
-     div.addEventListener("mousedown", evt => {
 
-       const end = div.querySelector(".endOfContent");
 
-       if (!end) {
 
-         return;
 
-       }
 
-       if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
 
-         // On non-Firefox browsers, the selection will feel better if the height
 
-         // of the `endOfContent` div is adjusted to start at mouse click
 
-         // location. This avoids flickering when the selection moves up.
 
-         // However it does not work when selection is started on empty space.
 
-         let adjustTop = evt.target !== div;
 
-         if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
 
-           adjustTop &&=
 
-             getComputedStyle(end).getPropertyValue("-moz-user-select") !==
 
-             "none";
 
-         }
 
-         if (adjustTop) {
 
-           const divBounds = div.getBoundingClientRect();
 
-           const r = Math.max(0, (evt.pageY - divBounds.top) / divBounds.height);
 
-           end.style.top = (r * 100).toFixed(2) + "%";
 
-         }
 
-       }
 
-       end.classList.add("active");
 
-     });
 
-     div.addEventListener("mouseup", () => {
 
-       const end = div.querySelector(".endOfContent");
 
-       if (!end) {
 
-         return;
 
-       }
 
-       if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
 
-         end.style.top = "";
 
-       }
 
-       end.classList.remove("active");
 
-     });
 
-   }
 
- }
 
- export { TextLayerBuilder };
 
 
  |