Repository: mozilla/pdf.js
File: web/pdf_page_detail_view.js (JavaScript)

Code before:
  }

  update({ visibleArea = null, underlyingViewUpdated = false } = {}) {
    if (underlyingViewUpdated) {
      this.cancelRendering();
      this.renderingState = RenderingStates.INITIAL;
      return;
    }

    if (!this.#shouldRenderDifferentArea(visibleArea)) {
      return;
    }

    const { viewport } = this.pageView;

    const visibleWidth = visibleArea.maxX - visibleArea.minX;
    const visibleHeight = visibleArea.maxY - visibleArea.minY;
    let { maxCanvasPixels } = this.pageView;

    if (this.capCanvasAreaFactor >= 0) {
      const capFactor = 1 + this.capCanvasAreaFactor / 100;
      const cappedWindowArea =
        window.innerWidth *
        window.innerHeight *
        OutputScale.pixelRatio ** 2 *
        capFactor;
      maxCanvasPixels = Math.min(maxCanvasPixels, cappedWindowArea);
    }

    // "overflowScale" represents which percentage of the width and of the
    // height the detail area extends outside of the visible area. We want to
    // draw a larger area so that we don't have to constantly re-draw while
    // scrolling. The detail area's dimensions thus become
    // visibleLength * (2 * overflowScale + 1).
    // We default to adding a whole height/length of detail area on each side,
    // but we can reduce it to make sure that we stay within the maxCanvasPixels
    // limit.
    const visiblePixels =
      visibleWidth * visibleHeight * OutputScale.pixelRatio ** 2;
    const maxDetailToVisibleLinearRatio = Math.sqrt(
      maxCanvasPixels / visiblePixels
    );
    const maxOverflowScale = (maxDetailToVisibleLinearRatio - 1) / 2;
    let overflowScale = Math.min(1, maxOverflowScale);
    if (overflowScale < 0) {
      overflowScale = 0;
      // In this case, we render a detail view that is exactly as big as the
      // visible area, but we ignore the .maxCanvasPixels limit.
      // TODO: We should probably instead give up and not render the detail view
      // in this case. It's quite rare to hit it though, because usually
      // .maxCanvasPixels will at least have enough pixels to cover the visible

Review comment (refactor):
It seems unfortunate, from a maintainability perspective, to essentially duplicate this both here and in the `OutputScale` class.
Can't we add e.g. a static helper method, for computing the cap-value, on that class and use that everywhere instead?

Code after:

  update({ visibleArea = null, underlyingViewUpdated = false } = {}) {
    if (underlyingViewUpdated) {
      this.cancelRendering();
      this.renderingState = RenderingStates.INITIAL;
      return;
    }

    if (!this.#shouldRenderDifferentArea(visibleArea)) {
      return;
    }

    const { viewport, capCanvasAreaFactor } = this.pageView;

    const visibleWidth = visibleArea.maxX - visibleArea.minX;
    const visibleHeight = visibleArea.maxY - visibleArea.minY;
    let { maxCanvasPixels } = this.pageView;

    if (capCanvasAreaFactor >= 0) {
      maxCanvasPixels = Math.min(
        maxCanvasPixels,
        OutputScale.getCappedWindowArea(capCanvasAreaFactor)
      );
    }

    // "overflowScale" represents which percentage of the width and of the
    // height the detail area extends outside of the visible area. We want to
    // draw a larger area so that we don't have to constantly re-draw while
    // scrolling. The detail area's dimensions thus become
    // visibleLength * (2 * overflowScale + 1).
    // We default to adding a whole height/length of detail area on each side,
    // but we can reduce it to make sure that we stay within the maxCanvasPixels
    // limit.
    const visiblePixels =
      visibleWidth * visibleHeight * OutputScale.pixelRatio ** 2;
    const maxDetailToVisibleLinearRatio = Math.sqrt(
      maxCanvasPixels / visiblePixels
    );
    const maxOverflowScale = (maxDetailToVisibleLinearRatio - 1) / 2;
    let overflowScale = Math.min(1, maxOverflowScale);
    if (overflowScale < 0) {
      overflowScale = 0;
      // In this case, we render a detail view that is exactly as big as the
      // visible area, but we ignore the .maxCanvasPixels limit.
      // TODO: We should probably instead give up and not render the detail view
      // in this case. It's quite rare to hit it though, because usually
      // .maxCanvasPixels will at least have enough pixels to cover the visible
      // screen.
    }

    const overflowWidth = visibleWidth * overflowScale;