async draw()

in web/pdf_page_view.js [928:1122]


  async draw() {
    if (this.renderingState !== RenderingStates.INITIAL) {
      console.error("Must be in new state before drawing");
      this.reset(); // Ensure that we reset all state to prevent issues.
    }
    const { div, l10n, pdfPage, viewport } = this;

    if (!pdfPage) {
      this.renderingState = RenderingStates.FINISHED;
      throw new Error("pdfPage is not loaded");
    }

    this.renderingState = RenderingStates.RUNNING;

    const canvasWrapper = this._ensureCanvasWrapper();

    if (
      !this.textLayer &&
      this.#textLayerMode !== TextLayerMode.DISABLE &&
      !pdfPage.isPureXfa
    ) {
      this._accessibilityManager ||= new TextAccessibilityManager();

      this.textLayer = new TextLayerBuilder({
        pdfPage,
        highlighter: this._textHighlighter,
        accessibilityManager: this._accessibilityManager,
        enablePermissions:
          this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS,
        onAppend: textLayerDiv => {
          // Pause translation when inserting the textLayer in the DOM.
          this.l10n.pause();
          this.#addLayer(textLayerDiv, "textLayer");
          this.l10n.resume();
        },
      });
    }

    if (
      !this.annotationLayer &&
      this.#annotationMode !== AnnotationMode.DISABLE
    ) {
      const {
        annotationStorage,
        annotationEditorUIManager,
        downloadManager,
        enableScripting,
        fieldObjectsPromise,
        hasJSActionsPromise,
        linkService,
      } = this.#layerProperties;

      this._annotationCanvasMap ||= new Map();
      this.annotationLayer = new AnnotationLayerBuilder({
        pdfPage,
        annotationStorage,
        imageResourcesPath: this.imageResourcesPath,
        renderForms: this.#annotationMode === AnnotationMode.ENABLE_FORMS,
        linkService,
        downloadManager,
        enableScripting,
        hasJSActionsPromise,
        fieldObjectsPromise,
        annotationCanvasMap: this._annotationCanvasMap,
        accessibilityManager: this._accessibilityManager,
        annotationEditorUIManager,
        onAppend: annotationLayerDiv => {
          this.#addLayer(annotationLayerDiv, "annotationLayer");
        },
      });
    }

    const { width, height } = viewport;
    this.#originalViewport = viewport;

    const { canvas, prevCanvas, ctx } = this._createCanvas(newCanvas => {
      // Always inject the canvas as the first element in the wrapper.
      canvasWrapper.prepend(newCanvas);
    });
    canvas.setAttribute("role", "presentation");

    if (!this.outputScale) {
      this.#computeScale();
    }
    const { outputScale } = this;
    this.#hasRestrictedScaling = this.#needsRestrictedScaling;

    const sfx = approximateFraction(outputScale.sx);
    const sfy = approximateFraction(outputScale.sy);

    const canvasWidth = (canvas.width = floorToDivide(
      calcRound(width * outputScale.sx),
      sfx[0]
    ));
    const canvasHeight = (canvas.height = floorToDivide(
      calcRound(height * outputScale.sy),
      sfy[0]
    ));
    const pageWidth = floorToDivide(calcRound(width), sfx[1]);
    const pageHeight = floorToDivide(calcRound(height), sfy[1]);
    outputScale.sx = canvasWidth / pageWidth;
    outputScale.sy = canvasHeight / pageHeight;

    if (this.#scaleRoundX !== sfx[1]) {
      div.style.setProperty("--scale-round-x", `${sfx[1]}px`);
      this.#scaleRoundX = sfx[1];
    }
    if (this.#scaleRoundY !== sfy[1]) {
      div.style.setProperty("--scale-round-y", `${sfy[1]}px`);
      this.#scaleRoundY = sfy[1];
    }

    // Rendering area
    const transform = outputScale.scaled
      ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0]
      : null;
    const resultPromise = this._drawCanvas(
      this._getRenderingContext(ctx, transform),
      () => {
        prevCanvas?.remove();
        this._resetCanvas();
      },
      renderTask => {
        // Ensure that the thumbnails won't become partially (or fully) blank,
        // for documents that contain interactive form elements.
        this.#useThumbnailCanvas.regularAnnotations =
          !renderTask.separateAnnots;

        this.dispatchPageRendered(
          /* cssTransform */ false,
          /* isDetailView */ false
        );
      }
    ).then(async () => {
      this.structTreeLayer ||= new StructTreeLayerBuilder(
        pdfPage,
        viewport.rawDims
      );

      const textLayerPromise = this.#renderTextLayer();

      if (this.annotationLayer) {
        await this.#renderAnnotationLayer();

        if (this.#enableAutoLinking && this.annotationLayer && this.textLayer) {
          await this.#injectLinkAnnotations(textLayerPromise);
        }
      }

      const { annotationEditorUIManager } = this.#layerProperties;

      if (!annotationEditorUIManager) {
        return;
      }
      this.drawLayer ||= new DrawLayerBuilder({
        pageIndex: this.id,
      });
      await this.#renderDrawLayer();
      this.drawLayer.setParent(canvasWrapper);

      this.annotationEditorLayer ||= new AnnotationEditorLayerBuilder({
        uiManager: annotationEditorUIManager,
        pdfPage,
        l10n,
        structTreeLayer: this.structTreeLayer,
        accessibilityManager: this._accessibilityManager,
        annotationLayer: this.annotationLayer?.annotationLayer,
        textLayer: this.textLayer,
        drawLayer: this.drawLayer.getDrawLayer(),
        onAppend: annotationEditorLayerDiv => {
          this.#addLayer(annotationEditorLayerDiv, "annotationEditorLayer");
        },
      });
      this.#renderAnnotationEditorLayer();
    });

    if (pdfPage.isPureXfa) {
      if (!this.xfaLayer) {
        const { annotationStorage, linkService } = this.#layerProperties;

        this.xfaLayer = new XfaLayerBuilder({
          pdfPage,
          annotationStorage,
          linkService,
        });
      }
      this.#renderXfaLayer();
    }

    div.setAttribute("data-loaded", true);

    this.dispatchPageRender();

    return resultPromise;
  }