setDocument()

in web/pdf_viewer.js [828:1122]


  setDocument(pdfDocument) {
    if (this.pdfDocument) {
      this.eventBus.dispatch("pagesdestroy", { source: this });

      this._cancelRendering();
      this._resetView();

      this.findController?.setDocument(null);
      this._scriptingManager?.setDocument(null);

      this.#annotationEditorUIManager?.destroy();
      this.#annotationEditorUIManager = null;
    }

    this.pdfDocument = pdfDocument;
    if (!pdfDocument) {
      return;
    }
    const pagesCount = pdfDocument.numPages;
    const firstPagePromise = pdfDocument.getPage(1);
    // Rendering (potentially) depends on this, hence fetching it immediately.
    const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
      intent: "display",
    });
    const permissionsPromise = this.#enablePermissions
      ? pdfDocument.getPermissions()
      : Promise.resolve();

    const { eventBus, pageColors, viewer } = this;

    this.#eventAbortController = new AbortController();
    const { signal } = this.#eventAbortController;

    // Given that browsers don't handle huge amounts of DOM-elements very well,
    // enforce usage of PAGE-scrolling when loading *very* long/large documents.
    if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) {
      console.warn(
        "Forcing PAGE-scrolling for performance reasons, given the length of the document."
      );
      const mode = (this._scrollMode = ScrollMode.PAGE);
      eventBus.dispatch("scrollmodechanged", { source: this, mode });
    }

    this._pagesCapability.promise.then(
      () => {
        eventBus.dispatch("pagesloaded", { source: this, pagesCount });
      },
      () => {
        /* Prevent "Uncaught (in promise)"-messages in the console. */
      }
    );

    const onBeforeDraw = evt => {
      const pageView = this._pages[evt.pageNumber - 1];
      if (!pageView) {
        return;
      }
      // Add the page to the buffer at the start of drawing. That way it can be
      // evicted from the buffer and destroyed even if we pause its rendering.
      this.#buffer.push(pageView);
    };
    eventBus._on("pagerender", onBeforeDraw, { signal });

    const onAfterDraw = evt => {
      if (evt.cssTransform || evt.isDetailView) {
        return;
      }
      this._onePageRenderedCapability.resolve({ timestamp: evt.timestamp });

      eventBus._off("pagerendered", onAfterDraw); // Remove immediately.
    };
    eventBus._on("pagerendered", onAfterDraw, { signal });

    // Fetch a single page so we can get a viewport that will be the default
    // viewport for all pages
    Promise.all([firstPagePromise, permissionsPromise])
      .then(([firstPdfPage, permissions]) => {
        if (pdfDocument !== this.pdfDocument) {
          return; // The document was closed while the first page resolved.
        }
        this._firstPageCapability.resolve(firstPdfPage);
        this._optionalContentConfigPromise = optionalContentConfigPromise;

        const { annotationEditorMode, annotationMode, textLayerMode } =
          this.#initializePermissions(permissions);

        if (textLayerMode !== TextLayerMode.DISABLE) {
          const element = (this.#hiddenCopyElement =
            document.createElement("div"));
          element.id = "hiddenCopyElement";
          viewer.before(element);
        }

        if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
          const mode = annotationEditorMode;

          if (pdfDocument.isPureXfa) {
            console.warn("Warning: XFA-editing is not implemented.");
          } else if (isValidAnnotationEditorMode(mode)) {
            this.#annotationEditorUIManager = new AnnotationEditorUIManager(
              this.container,
              viewer,
              this.#altTextManager,
              this.#signatureManager,
              eventBus,
              pdfDocument,
              pageColors,
              this.#annotationEditorHighlightColors,
              this.#enableHighlightFloatingButton,
              this.#enableUpdatedAddImage,
              this.#enableNewAltTextWhenAddingImage,
              this.#mlManager,
              this.#editorUndoBar,
              this.#supportsPinchToZoom
            );
            eventBus.dispatch("annotationeditoruimanager", {
              source: this,
              uiManager: this.#annotationEditorUIManager,
            });
            if (mode !== AnnotationEditorType.NONE) {
              this.#preloadEditingData(mode);
              this.#annotationEditorUIManager.updateMode(mode);
            }
          } else {
            console.error(`Invalid AnnotationEditor mode: ${mode}`);
          }
        }

        const viewerElement =
          this._scrollMode === ScrollMode.PAGE ? null : viewer;
        const scale = this.currentScale;
        const viewport = firstPdfPage.getViewport({
          scale: scale * PixelsPerInch.PDF_TO_CSS_UNITS,
        });
        // Ensure that the various layers always get the correct initial size,
        // see issue 15795.
        viewer.style.setProperty("--scale-factor", viewport.scale);

        if (pageColors?.background) {
          viewer.style.setProperty("--page-bg-color", pageColors.background);
        }
        if (
          pageColors?.foreground === "CanvasText" ||
          pageColors?.background === "Canvas"
        ) {
          viewer.style.setProperty(
            "--hcm-highlight-filter",
            pdfDocument.filterFactory.addHighlightHCMFilter(
              "highlight",
              "CanvasText",
              "Canvas",
              "HighlightText",
              "Highlight"
            )
          );
          viewer.style.setProperty(
            "--hcm-highlight-selected-filter",
            pdfDocument.filterFactory.addHighlightHCMFilter(
              "highlight_selected",
              "CanvasText",
              "Canvas",
              "HighlightText",
              "ButtonText"
            )
          );
        }

        for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
          const pageView = new PDFPageView({
            container: viewerElement,
            eventBus,
            id: pageNum,
            scale,
            defaultViewport: viewport.clone(),
            optionalContentConfigPromise,
            renderingQueue: this.renderingQueue,
            textLayerMode,
            annotationMode,
            imageResourcesPath: this.imageResourcesPath,
            maxCanvasPixels: this.maxCanvasPixels,
            maxCanvasDim: this.maxCanvasDim,
            capCanvasAreaFactor: this.capCanvasAreaFactor,
            enableDetailCanvas: this.enableDetailCanvas,
            pageColors,
            l10n: this.l10n,
            layerProperties: this._layerProperties,
            enableHWA: this.#enableHWA,
            enableAutoLinking: this.#enableAutoLinking,
            minDurationToUpdateCanvas: this.#minDurationToUpdateCanvas,
          });
          this._pages.push(pageView);
        }
        // Set the first `pdfPage` immediately, since it's already loaded,
        // rather than having to repeat the `PDFDocumentProxy.getPage` call in
        // the `this.#ensurePdfPageLoaded` method before rendering can start.
        this._pages[0]?.setPdfPage(firstPdfPage);

        if (this._scrollMode === ScrollMode.PAGE) {
          // Ensure that the current page becomes visible on document load.
          this.#ensurePageViewVisible();
        } else if (this._spreadMode !== SpreadMode.NONE) {
          this._updateSpreadMode();
        }

        // Fetch all the pages since the viewport is needed before printing
        // starts to create the correct size canvas. Wait until one page is
        // rendered so we don't tie up too many resources early on.
        this.#onePageRenderedOrForceFetch(signal).then(async () => {
          if (pdfDocument !== this.pdfDocument) {
            return; // The document was closed while the first page rendered.
          }
          this.findController?.setDocument(pdfDocument); // Enable searching.
          this._scriptingManager?.setDocument(pdfDocument); // Enable scripting.

          if (this.#hiddenCopyElement) {
            document.addEventListener(
              "copy",
              this.#copyCallback.bind(this, textLayerMode),
              { signal }
            );
          }

          if (this.#annotationEditorUIManager) {
            // Ensure that the Editor buttons, in the toolbar, are updated.
            eventBus.dispatch("annotationeditormodechanged", {
              source: this,
              mode: this.#annotationEditorMode,
            });
          }

          // In addition to 'disableAutoFetch' being set, also attempt to reduce
          // resource usage when loading *very* long/large documents.
          if (
            pdfDocument.loadingParams.disableAutoFetch ||
            pagesCount > PagesCountLimit.FORCE_LAZY_PAGE_INIT
          ) {
            // XXX: Printing is semi-broken with auto fetch disabled.
            this._pagesCapability.resolve();
            return;
          }
          let getPagesLeft = pagesCount - 1; // The first page was already loaded.

          if (getPagesLeft <= 0) {
            this._pagesCapability.resolve();
            return;
          }
          for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) {
            const promise = pdfDocument.getPage(pageNum).then(
              pdfPage => {
                const pageView = this._pages[pageNum - 1];
                if (!pageView.pdfPage) {
                  pageView.setPdfPage(pdfPage);
                }
                if (--getPagesLeft === 0) {
                  this._pagesCapability.resolve();
                }
              },
              reason => {
                console.error(
                  `Unable to get page ${pageNum} to initialize viewer`,
                  reason
                );
                if (--getPagesLeft === 0) {
                  this._pagesCapability.resolve();
                }
              }
            );

            if (pageNum % PagesCountLimit.PAUSE_EAGER_PAGE_INIT === 0) {
              await promise;
            }
          }
        });

        eventBus.dispatch("pagesinit", { source: this });

        pdfDocument.getMetadata().then(({ info }) => {
          if (pdfDocument !== this.pdfDocument) {
            return; // The document was closed while the metadata resolved.
          }
          if (info.Language) {
            viewer.lang = info.Language;
          }
        });

        if (this.defaultRenderingQueue) {
          this.update();
        }
      })
      .catch(reason => {
        console.error("Unable to initialize viewer", reason);

        this._pagesCapability.reject(reason);
      });
  }