Respect maxCanvasPixels when computing canvas dimensions

Ensure that we never round the canvas dimensions above `maxCanvasPixels`
by rounding them to the preceeding multiple of the display ratio rather
than the succeeding one.
This commit is contained in:
Nicolò Ribaudo 2024-06-07 14:08:43 +02:00
parent 12692d2e39
commit de23bb9b82
No known key found for this signature in database
GPG key ID: AAFDA9101C58F338
3 changed files with 20 additions and 15 deletions

View file

@ -279,12 +279,13 @@ describe("PDF viewer", () => {
.withContext(`In ${browserName}`) .withContext(`In ${browserName}`)
.toBeLessThan(originalCanvasSize * factor ** 2); .toBeLessThan(originalCanvasSize * factor ** 2);
// Disabled because `canvasSize` is `4_012_800`, which is expect(canvasSize)
// close to the limit but somehow a bit more. .withContext(`In ${browserName}, <= MAX_CANVAS_PIXELS`)
// .toBeLessThanOrEqual(MAX_CANVAS_PIXELS.get(browserName));
// expect(canvasSize)
// .withContext(`In ${browserName}, MAX_CANVAS_PIXELS`) expect(canvasSize)
// .toBeLessThan(MAX_CANVAS_PIXELS.get(browserName)); .withContext(`In ${browserName}, > MAX_CANVAS_PIXELS * 0.99`)
.toBeGreaterThan(MAX_CANVAS_PIXELS.get(browserName) * 0.99);
}) })
); );
}); });

View file

@ -34,9 +34,9 @@ import {
import { import {
approximateFraction, approximateFraction,
DEFAULT_SCALE, DEFAULT_SCALE,
floorToDivide,
OutputScale, OutputScale,
RenderingStates, RenderingStates,
roundToDivide,
TextLayerMode, TextLayerMode,
} from "./ui_utils.js"; } from "./ui_utils.js";
import { AnnotationEditorLayerBuilder } from "./annotation_editor_layer_builder.js"; import { AnnotationEditorLayerBuilder } from "./annotation_editor_layer_builder.js";
@ -1025,11 +1025,11 @@ class PDFPageView {
const sfx = approximateFraction(outputScale.sx); const sfx = approximateFraction(outputScale.sx);
const sfy = approximateFraction(outputScale.sy); const sfy = approximateFraction(outputScale.sy);
canvas.width = roundToDivide(width * outputScale.sx, sfx[0]); canvas.width = floorToDivide(width * outputScale.sx, sfx[0]);
canvas.height = roundToDivide(height * outputScale.sy, sfy[0]); canvas.height = floorToDivide(height * outputScale.sy, sfy[0]);
const { style } = canvas; const { style } = canvas;
style.width = roundToDivide(width, sfx[1]) + "px"; style.width = floorToDivide(width, sfx[1]) + "px";
style.height = roundToDivide(height, sfy[1]) + "px"; style.height = floorToDivide(height, sfy[1]) + "px";
// Add the viewport so it's known what it was originally drawn with. // Add the viewport so it's known what it was originally drawn with.
this.#viewportMap.set(canvas, viewport); this.#viewportMap.set(canvas, viewport);

View file

@ -260,6 +260,7 @@ function binarySearchFirstItem(items, condition, start = 0) {
* @param {number} x - Positive float number. * @param {number} x - Positive float number.
* @returns {Array} Estimated fraction: the first array item is a numerator, * @returns {Array} Estimated fraction: the first array item is a numerator,
* the second one is a denominator. * the second one is a denominator.
* They are both natural numbers.
*/ */
function approximateFraction(x) { function approximateFraction(x) {
// Fast paths for int numbers or their inversions. // Fast paths for int numbers or their inversions.
@ -306,9 +307,12 @@ function approximateFraction(x) {
return result; return result;
} }
function roundToDivide(x, div) { /**
const r = x % div; * @param {number} x - A positive number to round to a multiple of `div`.
return r === 0 ? x : Math.round(x - r + div); * @param {number} div - A natural number.
*/
function floorToDivide(x, div) {
return x - (x % div);
} }
/** /**
@ -863,6 +867,7 @@ export {
DEFAULT_SCALE_DELTA, DEFAULT_SCALE_DELTA,
DEFAULT_SCALE_VALUE, DEFAULT_SCALE_VALUE,
docStyle, docStyle,
floorToDivide,
getActiveOrFocusedElement, getActiveOrFocusedElement,
getPageSizeInches, getPageSizeInches,
getVisibleElements, getVisibleElements,
@ -881,7 +886,6 @@ export {
ProgressBar, ProgressBar,
removeNullCharacters, removeNullCharacters,
RenderingStates, RenderingStates,
roundToDivide,
SCROLLBAR_PADDING, SCROLLBAR_PADDING,
scrollIntoView, scrollIntoView,
ScrollMode, ScrollMode,