| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 | /** * @licstart The following is the entire license notice for the * Javascript code in this page * * Copyright 2020 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. * * @licend The above is the entire license notice for the * Javascript code in this page */"use strict";Object.defineProperty(exports, "__esModule", {  value: true});exports.PDFPageView = void 0;var _ui_utils = require("./ui_utils.js");var _pdf = require("../pdf");var _pdf_rendering_queue = require("./pdf_rendering_queue.js");var _viewer_compatibility = require("./viewer_compatibility.js");const MAX_CANVAS_PIXELS = _viewer_compatibility.viewerCompatibilityParams.maxCanvasPixels || 16777216;class PDFPageView {  constructor(options) {    const container = options.container;    const defaultViewport = options.defaultViewport;    this.id = options.id;    this.renderingId = "page" + this.id;    this.pdfPage = null;    this.pageLabel = null;    this.rotation = 0;    this.scale = options.scale || _ui_utils.DEFAULT_SCALE;    this.viewport = defaultViewport;    this.pdfPageRotate = defaultViewport.rotation;    this._annotationStorage = options.annotationStorage || null;    this._optionalContentConfigPromise = options.optionalContentConfigPromise || null;    this.hasRestrictedScaling = false;    this.textLayerMode = Number.isInteger(options.textLayerMode) ? options.textLayerMode : _ui_utils.TextLayerMode.ENABLE;    this.imageResourcesPath = options.imageResourcesPath || "";    this.renderInteractiveForms = typeof options.renderInteractiveForms === "boolean" ? options.renderInteractiveForms : true;    this.useOnlyCssZoom = options.useOnlyCssZoom || false;    this.maxCanvasPixels = options.maxCanvasPixels || MAX_CANVAS_PIXELS;    this.eventBus = options.eventBus;    this.renderingQueue = options.renderingQueue;    this.textLayerFactory = options.textLayerFactory;    this.annotationLayerFactory = options.annotationLayerFactory;    this.renderer = options.renderer || _ui_utils.RendererType.CANVAS;    this.enableWebGL = options.enableWebGL || false;    this.l10n = options.l10n || _ui_utils.NullL10n;    this.paintTask = null;    this.paintedViewportMap = new WeakMap();    this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL;    this.resume = null;    this.error = null;    this.annotationLayer = null;    this.textLayer = null;    this.zoomLayer = null;    const div = document.createElement("div");    div.className = "page";    div.style.width = Math.floor(this.viewport.width) + "px";    div.style.height = Math.floor(this.viewport.height) + "px";    div.setAttribute("data-page-number", this.id);    this.div = div;    container.appendChild(div);  }  setPdfPage(pdfPage) {    this.pdfPage = pdfPage;    this.pdfPageRotate = pdfPage.rotate;    const totalRotation = (this.rotation + this.pdfPageRotate) % 360;    this.viewport = pdfPage.getViewport({      scale: this.scale * _ui_utils.CSS_UNITS,      rotation: totalRotation    });    this.stats = pdfPage.stats;    this.reset();  }  destroy() {    this.reset();    if (this.pdfPage) {      this.pdfPage.cleanup();    }  }  async _renderAnnotationLayer() {    let error = null;    try {      await this.annotationLayer.render(this.viewport, "display");    } catch (ex) {      error = ex;    } finally {      this.eventBus.dispatch("annotationlayerrendered", {        source: this,        pageNumber: this.id,        error      });    }  }  _resetZoomLayer(removeFromDOM = false) {    if (!this.zoomLayer) {      return;    }    const zoomLayerCanvas = this.zoomLayer.firstChild;    this.paintedViewportMap.delete(zoomLayerCanvas);    zoomLayerCanvas.width = 0;    zoomLayerCanvas.height = 0;    if (removeFromDOM) {      this.zoomLayer.remove();    }    this.zoomLayer = null;  }  reset(keepZoomLayer = false, keepAnnotations = false) {    this.cancelRendering(keepAnnotations);    this.renderingState = _pdf_rendering_queue.RenderingStates.INITIAL;    const div = this.div;    div.style.width = Math.floor(this.viewport.width) + "px";    div.style.height = Math.floor(this.viewport.height) + "px";    const childNodes = div.childNodes;    const currentZoomLayerNode = keepZoomLayer && this.zoomLayer || null;    const currentAnnotationNode = keepAnnotations && this.annotationLayer && this.annotationLayer.div || null;    for (let i = childNodes.length - 1; i >= 0; i--) {      const node = childNodes[i];      if (currentZoomLayerNode === node || currentAnnotationNode === node) {        continue;      }      div.removeChild(node);    }    div.removeAttribute("data-loaded");    if (currentAnnotationNode) {      this.annotationLayer.hide();    } else if (this.annotationLayer) {      this.annotationLayer.cancel();      this.annotationLayer = null;    }    if (!currentZoomLayerNode) {      if (this.canvas) {        this.paintedViewportMap.delete(this.canvas);        this.canvas.width = 0;        this.canvas.height = 0;        delete this.canvas;      }      this._resetZoomLayer();    }    if (this.svg) {      this.paintedViewportMap.delete(this.svg);      delete this.svg;    }    this.loadingIconDiv = document.createElement("div");    this.loadingIconDiv.className = "loadingIcon";    div.appendChild(this.loadingIconDiv);  }  update(scale, rotation, optionalContentConfigPromise = null) {    this.scale = scale || this.scale;    if (typeof rotation !== "undefined") {      this.rotation = rotation;    }    if (optionalContentConfigPromise instanceof Promise) {      this._optionalContentConfigPromise = optionalContentConfigPromise;    }    const totalRotation = (this.rotation + this.pdfPageRotate) % 360;    this.viewport = this.viewport.clone({      scale: this.scale * _ui_utils.CSS_UNITS,      rotation: totalRotation    });    if (this.svg) {      this.cssTransform(this.svg, true);      this.eventBus.dispatch("pagerendered", {        source: this,        pageNumber: this.id,        cssTransform: true,        timestamp: performance.now()      });      return;    }    let isScalingRestricted = false;    if (this.canvas && this.maxCanvasPixels > 0) {      const outputScale = this.outputScale;      if ((Math.floor(this.viewport.width) * outputScale.sx | 0) * (Math.floor(this.viewport.height) * outputScale.sy | 0) > this.maxCanvasPixels) {        isScalingRestricted = true;      }    }    if (this.canvas) {      if (this.useOnlyCssZoom || this.hasRestrictedScaling && isScalingRestricted) {        this.cssTransform(this.canvas, true);        this.eventBus.dispatch("pagerendered", {          source: this,          pageNumber: this.id,          cssTransform: true,          timestamp: performance.now()        });        return;      }      if (!this.zoomLayer && !this.canvas.hasAttribute("hidden")) {        this.zoomLayer = this.canvas.parentNode;        this.zoomLayer.style.position = "absolute";      }    }    if (this.zoomLayer) {      this.cssTransform(this.zoomLayer.firstChild);    }    this.reset(true, true);  }  cancelRendering(keepAnnotations = false) {    if (this.paintTask) {      this.paintTask.cancel();      this.paintTask = null;    }    this.resume = null;    if (this.textLayer) {      this.textLayer.cancel();      this.textLayer = null;    }    if (!keepAnnotations && this.annotationLayer) {      this.annotationLayer.cancel();      this.annotationLayer = null;    }  }  cssTransform(target, redrawAnnotations = false) {    const width = this.viewport.width;    const height = this.viewport.height;    const div = this.div;    target.style.width = target.parentNode.style.width = div.style.width = Math.floor(width) + "px";    target.style.height = target.parentNode.style.height = div.style.height = Math.floor(height) + "px";    const relativeRotation = this.viewport.rotation - this.paintedViewportMap.get(target).rotation;    const absRotation = Math.abs(relativeRotation);    let scaleX = 1,        scaleY = 1;    if (absRotation === 90 || absRotation === 270) {      scaleX = height / width;      scaleY = width / height;    }    const cssTransform = "rotate(" + relativeRotation + "deg) " + "scale(" + scaleX + "," + scaleY + ")";    target.style.transform = cssTransform;    if (this.textLayer) {      const textLayerViewport = this.textLayer.viewport;      const textRelativeRotation = this.viewport.rotation - textLayerViewport.rotation;      const textAbsRotation = Math.abs(textRelativeRotation);      let scale = width / textLayerViewport.width;      if (textAbsRotation === 90 || textAbsRotation === 270) {        scale = width / textLayerViewport.height;      }      const textLayerDiv = this.textLayer.textLayerDiv;      let transX, transY;      switch (textAbsRotation) {        case 0:          transX = transY = 0;          break;        case 90:          transX = 0;          transY = "-" + textLayerDiv.style.height;          break;        case 180:          transX = "-" + textLayerDiv.style.width;          transY = "-" + textLayerDiv.style.height;          break;        case 270:          transX = "-" + textLayerDiv.style.width;          transY = 0;          break;        default:          console.error("Bad rotation value.");          break;      }      textLayerDiv.style.transform = "rotate(" + textAbsRotation + "deg) " + "scale(" + scale + ", " + scale + ") " + "translate(" + transX + ", " + transY + ")";      textLayerDiv.style.transformOrigin = "0% 0%";    }    if (redrawAnnotations && this.annotationLayer) {      this._renderAnnotationLayer();    }  }  get width() {    return this.viewport.width;  }  get height() {    return this.viewport.height;  }  getPagePoint(x, y) {    return this.viewport.convertToPdfPoint(x, y);  }  draw() {    if (this.renderingState !== _pdf_rendering_queue.RenderingStates.INITIAL) {      console.error("Must be in new state before drawing");      this.reset();    }    const {      div,      pdfPage    } = this;    if (!pdfPage) {      this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;      if (this.loadingIconDiv) {        div.removeChild(this.loadingIconDiv);        delete this.loadingIconDiv;      }      return Promise.reject(new Error("pdfPage is not loaded"));    }    this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING;    const canvasWrapper = document.createElement("div");    canvasWrapper.style.width = div.style.width;    canvasWrapper.style.height = div.style.height;    canvasWrapper.classList.add("canvasWrapper");    if (this.annotationLayer && this.annotationLayer.div) {      div.insertBefore(canvasWrapper, this.annotationLayer.div);    } else {      div.appendChild(canvasWrapper);    }    let textLayer = null;    if (this.textLayerMode !== _ui_utils.TextLayerMode.DISABLE && this.textLayerFactory) {      const textLayerDiv = document.createElement("div");      textLayerDiv.className = "textLayer";      textLayerDiv.style.width = canvasWrapper.style.width;      textLayerDiv.style.height = canvasWrapper.style.height;      if (this.annotationLayer && this.annotationLayer.div) {        div.insertBefore(textLayerDiv, this.annotationLayer.div);      } else {        div.appendChild(textLayerDiv);      }      textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.textLayerMode === _ui_utils.TextLayerMode.ENABLE_ENHANCE, this.eventBus);    }    this.textLayer = textLayer;    let renderContinueCallback = null;    if (this.renderingQueue) {      renderContinueCallback = cont => {        if (!this.renderingQueue.isHighestPriority(this)) {          this.renderingState = _pdf_rendering_queue.RenderingStates.PAUSED;          this.resume = () => {            this.renderingState = _pdf_rendering_queue.RenderingStates.RUNNING;            cont();          };          return;        }        cont();      };    }    const finishPaintTask = async error => {      if (paintTask === this.paintTask) {        this.paintTask = null;      }      if (error instanceof _pdf.RenderingCancelledException) {        this.error = null;        return;      }      this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;      if (this.loadingIconDiv) {        div.removeChild(this.loadingIconDiv);        delete this.loadingIconDiv;      }      this._resetZoomLayer(true);      this.error = error;      this.stats = pdfPage.stats;      this.eventBus.dispatch("pagerendered", {        source: this,        pageNumber: this.id,        cssTransform: false,        timestamp: performance.now()      });      if (error) {        throw error;      }    };    const paintTask = this.renderer === _ui_utils.RendererType.SVG ? this.paintOnSvg(canvasWrapper) : this.paintOnCanvas(canvasWrapper);    paintTask.onRenderContinue = renderContinueCallback;    this.paintTask = paintTask;    const resultPromise = paintTask.promise.then(function () {      return finishPaintTask(null).then(function () {        if (textLayer) {          const readableStream = pdfPage.streamTextContent({            normalizeWhitespace: true          });          textLayer.setTextContentStream(readableStream);          textLayer.render();        }      });    }, function (reason) {      return finishPaintTask(reason);    });    if (this.annotationLayerFactory) {      if (!this.annotationLayer) {        this.annotationLayer = this.annotationLayerFactory.createAnnotationLayerBuilder(div, pdfPage, this._annotationStorage, this.imageResourcesPath, this.renderInteractiveForms, this.l10n);      }      this._renderAnnotationLayer();    }    div.setAttribute("data-loaded", true);    this.eventBus.dispatch("pagerender", {      source: this,      pageNumber: this.id    });    return resultPromise;  }  paintOnCanvas(canvasWrapper) {    const renderCapability = (0, _pdf.createPromiseCapability)();    const result = {      promise: renderCapability.promise,      onRenderContinue(cont) {        cont();      },      cancel() {        renderTask.cancel();      }    };    const viewport = this.viewport;    const canvas = document.createElement("canvas");    this.l10n.get("page_canvas", {      page: this.id    }, "Page {{page}}").then(msg => {      canvas.setAttribute("aria-label", msg);    });    canvas.setAttribute("hidden", "hidden");    let isCanvasHidden = true;    const showCanvas = function () {      if (isCanvasHidden) {        canvas.removeAttribute("hidden");        isCanvasHidden = false;      }    };    canvasWrapper.appendChild(canvas);    this.canvas = canvas;    canvas.mozOpaque = true;    const ctx = canvas.getContext("2d", {      alpha: false    });    const outputScale = (0, _ui_utils.getOutputScale)(ctx);    this.outputScale = outputScale;    if (this.useOnlyCssZoom) {      const actualSizeViewport = viewport.clone({        scale: _ui_utils.CSS_UNITS      });      outputScale.sx *= actualSizeViewport.width / viewport.width;      outputScale.sy *= actualSizeViewport.height / viewport.height;      outputScale.scaled = true;    }    if (this.maxCanvasPixels > 0) {      const pixelsInViewport = viewport.width * viewport.height;      const maxScale = Math.sqrt(this.maxCanvasPixels / pixelsInViewport);      if (outputScale.sx > maxScale || outputScale.sy > maxScale) {        outputScale.sx = maxScale;        outputScale.sy = maxScale;        outputScale.scaled = true;        this.hasRestrictedScaling = true;      } else {        this.hasRestrictedScaling = false;      }    }    const sfx = (0, _ui_utils.approximateFraction)(outputScale.sx);    const sfy = (0, _ui_utils.approximateFraction)(outputScale.sy);    canvas.width = (0, _ui_utils.roundToDivide)(viewport.width * outputScale.sx, sfx[0]);    canvas.height = (0, _ui_utils.roundToDivide)(viewport.height * outputScale.sy, sfy[0]);    canvas.style.width = (0, _ui_utils.roundToDivide)(viewport.width, sfx[1]) + "px";    canvas.style.height = (0, _ui_utils.roundToDivide)(viewport.height, sfy[1]) + "px";    this.paintedViewportMap.set(canvas, viewport);    const transform = !outputScale.scaled ? null : [outputScale.sx, 0, 0, outputScale.sy, 0, 0];    const renderContext = {      canvasContext: ctx,      transform,      viewport: this.viewport,      enableWebGL: this.enableWebGL,      renderInteractiveForms: this.renderInteractiveForms,      optionalContentConfigPromise: this._optionalContentConfigPromise    };    const renderTask = this.pdfPage.render(renderContext);    renderTask.onContinue = function (cont) {      showCanvas();      if (result.onRenderContinue) {        result.onRenderContinue(cont);      } else {        cont();      }    };    renderTask.promise.then(function () {      showCanvas();      renderCapability.resolve(undefined);    }, function (error) {      showCanvas();      renderCapability.reject(error);    });    return result;  }  paintOnSvg(wrapper) {    let cancelled = false;    const ensureNotCancelled = () => {      if (cancelled) {        throw new _pdf.RenderingCancelledException(`Rendering cancelled, page ${this.id}`, "svg");      }    };    const pdfPage = this.pdfPage;    const actualSizeViewport = this.viewport.clone({      scale: _ui_utils.CSS_UNITS    });    const promise = pdfPage.getOperatorList().then(opList => {      ensureNotCancelled();      const svgGfx = new _pdf.SVGGraphics(pdfPage.commonObjs, pdfPage.objs);      return svgGfx.getSVG(opList, actualSizeViewport).then(svg => {        ensureNotCancelled();        this.svg = svg;        this.paintedViewportMap.set(svg, actualSizeViewport);        svg.style.width = wrapper.style.width;        svg.style.height = wrapper.style.height;        this.renderingState = _pdf_rendering_queue.RenderingStates.FINISHED;        wrapper.appendChild(svg);      });    });    return {      promise,      onRenderContinue(cont) {        cont();      },      cancel() {        cancelled = true;      }    };  }  setPageLabel(label) {    this.pageLabel = typeof label === "string" ? label : null;    if (this.pageLabel !== null) {      this.div.setAttribute("data-page-label", this.pageLabel);    } else {      this.div.removeAttribute("data-page-label");    }  }}exports.PDFPageView = PDFPageView;
 |