Merge pull request #20016 from ryzokuken/move-getcontext

[api-minor] Move getContext call to InternalRenderTask
This commit is contained in:
calixteman 2025-07-08 22:20:19 +02:00 committed by GitHub
commit 1b427a3af5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 129 additions and 59 deletions

View File

@ -501,7 +501,8 @@ function getDocument(src = {}) {
task,
networkStream,
transportParams,
transportFactory
transportFactory,
enableHWA
);
task._transport = transport;
messageHandler.send("Ready", null);
@ -1181,8 +1182,12 @@ class PDFDocumentProxy {
* Page render parameters.
*
* @typedef {Object} RenderParameters
* @property {CanvasRenderingContext2D} canvasContext - A 2D context of a DOM
* Canvas object.
* @property {CanvasRenderingContext2D} canvasContext - Deprecated 2D context of
* a DOM Canvas object for backwards compatibility; it is recommended to use
* the `canvas` parameter instead.
* @property {HTMLCanvasElement} canvas - A DOM Canvas object. The default value
* is the canvas associated with the `canvasContext` parameter if no value is
* provided explicitly.
* @property {PageViewport} viewport - Rendering viewport obtained by calling
* the `PDFPageProxy.getViewport` method.
* @property {string} [intent] - Rendering intent, can be 'display', 'print',
@ -1405,6 +1410,7 @@ class PDFPageProxy {
*/
render({
canvasContext,
canvas = canvasContext.canvas,
viewport,
intent = "display",
annotationMode = AnnotationMode.ENABLE,
@ -1496,7 +1502,7 @@ class PDFPageProxy {
callback: complete,
// Only include the required properties, and *not* the entire object.
params: {
canvasContext,
canvas,
viewport,
transform,
background,
@ -1511,6 +1517,7 @@ class PDFPageProxy {
useRequestAnimationFrame: !intentPrint,
pdfBug: this._pdfBug,
pageColors,
enableHWA: this._transport.enableHWA,
});
(intentState.renderTasks ||= new Set()).add(internalRenderTask);
@ -2305,7 +2312,14 @@ class WorkerTransport {
#passwordCapability = null;
constructor(messageHandler, loadingTask, networkStream, params, factory) {
constructor(
messageHandler,
loadingTask,
networkStream,
params,
factory,
enableHWA
) {
this.messageHandler = messageHandler;
this.loadingTask = loadingTask;
this.commonObjs = new PDFObjects();
@ -2329,6 +2343,7 @@ class WorkerTransport {
this._fullReader = null;
this._lastProgress = null;
this.downloadInfoCapability = Promise.withResolvers();
this.enableHWA = enableHWA;
this.setupMessageHandler();
@ -3104,6 +3119,7 @@ class InternalRenderTask {
useRequestAnimationFrame = false,
pdfBug = false,
pageColors = null,
enableHWA = false,
}) {
this.callback = callback;
this.params = params;
@ -3131,7 +3147,8 @@ class InternalRenderTask {
this._continueBound = this._continue.bind(this);
this._scheduleNextBound = this._scheduleNext.bind(this);
this._nextBound = this._next.bind(this);
this._canvas = params.canvasContext.canvas;
this._canvas = params.canvas;
this._enableHWA = enableHWA;
}
get completed() {
@ -3161,7 +3178,12 @@ class InternalRenderTask {
this.stepper.init(this.operatorList);
this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
}
const { canvasContext, viewport, transform, background } = this.params;
const { viewport, transform, background } = this.params;
const canvasContext = this._canvas.getContext("2d", {
alpha: false,
willReadFrequently: !this._enableHWA,
});
this.gfx = new CanvasGraphics(
canvasContext,

View File

@ -1016,7 +1016,7 @@ class Driver {
}
}
const renderContext = {
canvasContext: ctx,
canvas: this.canvas,
viewport,
optionalContentConfigPromise: task.optionalContentConfigPromise,
annotationCanvasMap,

View File

@ -41,6 +41,7 @@ async function runTests(results) {
"stamp_editor_spec.mjs",
"text_field_spec.mjs",
"text_layer_spec.mjs",
"thumbnail_view_spec.mjs",
"viewer_spec.mjs",
],
});

View File

@ -0,0 +1,35 @@
import { closePages, loadAndWait } from "./test_utils.mjs";
describe("PDF Thumbnail View", () => {
describe("Works without errors", () => {
let pages;
beforeEach(async () => {
pages = await loadAndWait("tracemonkey.pdf", "#sidebarToggleButton");
});
afterEach(async () => {
await closePages(pages);
});
it("should render thumbnails without errors", async () => {
await Promise.all(
pages.map(async ([browserName, page]) => {
await page.click("#sidebarToggleButton");
const thumbSelector = "#thumbnailView .thumbnailImage";
await page.waitForSelector(thumbSelector, { visible: true });
await page.waitForSelector(
'#thumbnailView .thumbnail[data-loaded="true"]'
);
const src = await page.$eval(thumbSelector, el => el.src);
expect(src)
.withContext(`In ${browserName}`)
.toMatch(/^data:image\//);
})
);
});
});
});

View File

@ -4410,7 +4410,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
expect(renderTask instanceof RenderTask).toEqual(true);
@ -4446,7 +4446,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
expect(renderTask instanceof RenderTask).toEqual(true);
@ -4477,7 +4477,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
expect(renderTask instanceof RenderTask).toEqual(true);
@ -4494,7 +4494,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
}
const reRenderTask = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
expect(reRenderTask instanceof RenderTask).toEqual(true);
@ -4518,14 +4518,14 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask1 = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
optionalContentConfigPromise,
});
expect(renderTask1 instanceof RenderTask).toEqual(true);
const renderTask2 = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
optionalContentConfigPromise,
});
@ -4562,7 +4562,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
expect(renderTask instanceof RenderTask).toEqual(true);
@ -4591,7 +4591,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
background: "#FF0000", // See comment below.
});
@ -4651,7 +4651,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
@ -4755,7 +4755,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
@ -4802,7 +4802,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
@ -4852,7 +4852,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
intent: "print",
annotationMode: AnnotationMode.ENABLE_STORAGE,
@ -4911,6 +4911,34 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
await loadingTask.destroy();
});
it("should work with the legacy canvasContext parameter", async function () {
const loadingTask = getDocument(tracemonkeyGetDocumentParams);
const pdfDoc = await loadingTask.promise;
const pdfPage = await pdfDoc.getPage(1);
const viewport = pdfPage.getViewport({ scale: 1 });
const { canvasFactory } = pdfDoc;
const canvasAndCtx = canvasFactory.create(
viewport.width,
viewport.height
);
const renderTask = pdfPage.render({
canvasContext: canvasAndCtx.context,
viewport,
});
expect(renderTask instanceof RenderTask).toEqual(true);
await renderTask.promise;
expect(
canvasAndCtx.context
.getImageData(0, 0, viewport.width, viewport.height)
.data.some(channel => channel !== 0)
).toEqual(true);
canvasFactory.destroy(canvasAndCtx);
await loadingTask.destroy();
});
});
describe("Multiple `getDocument` instances", function () {
@ -4939,7 +4967,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport.height
);
const renderTask = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
await renderTask.promise;

View File

@ -50,7 +50,7 @@ describe("custom canvas rendering", function () {
const canvasAndCtx = canvasFactory.create(viewport.width, viewport.height);
const renderTask = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
});
await renderTask.promise;
@ -70,7 +70,7 @@ describe("custom canvas rendering", function () {
const canvasAndCtx = canvasFactory.create(viewport.width, viewport.height);
const renderTask = page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
background: "rgba(255,0,0,1.0)",
});
@ -160,7 +160,7 @@ describe("custom ownerDocument", function () {
const canvasAndCtx = canvasFactory.create(viewport.width, viewport.height);
await page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
}).promise;
@ -194,7 +194,7 @@ describe("custom ownerDocument", function () {
const canvasAndCtx = canvasFactory.create(viewport.width, viewport.height);
await page.render({
canvasContext: canvasAndCtx.context,
canvas: canvasAndCtx.canvas,
viewport,
}).promise;

View File

@ -17,8 +17,6 @@ import { RenderingCancelledException } from "pdfjs-lib";
import { RenderingStates } from "./ui_utils.js";
class BasePDFPageView {
#enableHWA = false;
#loadingId = null;
#minDurationToUpdateCanvas = 0;
@ -51,8 +49,6 @@ class BasePDFPageView {
resume = null;
constructor(options) {
this.#enableHWA =
#enableHWA in options ? options.#enableHWA : options.enableHWA || false;
this.eventBus = options.eventBus;
this.id = options.id;
this.pageColors = options.pageColors || null;
@ -166,12 +162,7 @@ class BasePDFPageView {
}
};
const ctx = canvas.getContext("2d", {
alpha: false,
willReadFrequently: !this.#enableHWA,
});
return { canvas, prevCanvas, ctx };
return { canvas, prevCanvas };
}
#renderContinueCallback = cont => {

View File

@ -72,7 +72,7 @@ function composePage(
currentRenderTask = null;
}
const renderContext = {
canvasContext: ctx,
canvas: ctx.canvas,
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
viewport: pdfPage.getViewport({ scale: 1, rotation: size.rotation }),
intent: "print",

View File

@ -214,7 +214,7 @@ class PDFPageDetailView extends BasePDFPageView {
const canvasWrapper = this.pageView._ensureCanvasWrapper();
const { canvas, prevCanvas, ctx } = this._createCanvas(newCanvas => {
const { canvas, prevCanvas } = this._createCanvas(newCanvas => {
// If there is already the background canvas, inject this new canvas
// after it. We cannot simply use .append because all canvases must
// be before the SVG elements used for drawings.
@ -249,7 +249,7 @@ class PDFPageDetailView extends BasePDFPageView {
style.left = `${(area.minX * 100) / width}%`;
const renderingPromise = this._drawCanvas(
this.pageView._getRenderingContext(ctx, transform),
this.pageView._getRenderingContext(canvas, transform),
() => {
// If the rendering is cancelled, keep the old canvas visible.
this.canvas?.remove();

View File

@ -95,8 +95,6 @@ import { XfaLayerBuilder } from "./xfa_layer_builder.js";
* @property {IL10n} [l10n] - Localization service.
* @property {Object} [layerProperties] - The object that is used to lookup
* the necessary layer-properties.
* @property {boolean} [enableHWA] - Enables hardware acceleration for
* rendering. The default value is `false`.
* @property {boolean} [enableAutoLinking] - Enable creation of hyperlinks from
* text that look like URLs. The default value is `true`.
*/
@ -912,9 +910,9 @@ class PDFPageView extends BasePDFPageView {
return canvasWrapper;
}
_getRenderingContext(canvasContext, transform) {
_getRenderingContext(canvas, transform) {
return {
canvasContext,
canvas,
transform,
viewport: this.viewport,
annotationMode: this.#annotationMode,
@ -1000,7 +998,7 @@ class PDFPageView extends BasePDFPageView {
const { width, height } = viewport;
this.#originalViewport = viewport;
const { canvas, prevCanvas, ctx } = this._createCanvas(newCanvas => {
const { canvas, prevCanvas } = this._createCanvas(newCanvas => {
// Always inject the canvas as the first element in the wrapper.
canvasWrapper.prepend(newCanvas);
});
@ -1042,7 +1040,7 @@ class PDFPageView extends BasePDFPageView {
? [outputScale.sx, 0, 0, outputScale.sy, 0, 0]
: null;
const resultPromise = this._drawCanvas(
this._getRenderingContext(ctx, transform),
this._getRenderingContext(canvas, transform),
() => {
prevCanvas?.remove();
this._resetCanvas();

View File

@ -58,7 +58,7 @@ function renderPage(
printAnnotationStoragePromise,
]).then(function ([pdfPage, printAnnotationStorage]) {
const renderContext = {
canvasContext: ctx,
canvas: scratchCanvas,
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
viewport: pdfPage.getViewport({ scale: 1, rotation: size.rotation }),
intent: "print",

View File

@ -58,8 +58,6 @@ function zeroCanvas(c) {
* @property {Object} [pageColors] - Overwrites background and foreground colors
* with user defined ones in order to improve readability in high contrast
* mode.
* @property {boolean} [enableHWA] - Enables hardware acceleration for
* rendering. The default value is `false`.
*/
class TempImageFactory {
@ -106,7 +104,6 @@ class PDFThumbnailView {
maxCanvasPixels,
maxCanvasDim,
pageColors,
enableHWA,
}) {
this.id = id;
this.renderingId = "thumbnail" + id;
@ -120,7 +117,6 @@ class PDFThumbnailView {
this.maxCanvasPixels = maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
this.maxCanvasDim = maxCanvasDim || AppOptions.get("maxCanvasDim");
this.pageColors = pageColors || null;
this.enableHWA = enableHWA || false;
this.eventBus = eventBus;
this.linkService = linkService;
@ -214,14 +210,10 @@ class PDFThumbnailView {
this.resume = null;
}
#getPageDrawContext(upscaleFactor = 1, enableHWA = this.enableHWA) {
#getPageDrawContext(upscaleFactor = 1) {
// Keep the no-thumbnail outline visible, i.e. `data-loaded === false`,
// until rendering/image conversion is complete, to avoid display issues.
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d", {
alpha: false,
willReadFrequently: !enableHWA,
});
const outputScale = new OutputScale();
const width = upscaleFactor * this.canvasWidth,
height = upscaleFactor * this.canvasHeight;
@ -239,7 +231,7 @@ class PDFThumbnailView {
? [outputScale.sx, 0, 0, outputScale.sy, 0, 0]
: null;
return { ctx, canvas, transform };
return { canvas, transform };
}
#convertCanvasToImage(canvas) {
@ -280,8 +272,7 @@ class PDFThumbnailView {
// the `draw` and `setImage` methods (fixes issue 8233).
// NOTE: To primarily avoid increasing memory usage too much, but also to
// reduce downsizing overhead, we purposely limit the up-scaling factor.
const { ctx, canvas, transform } =
this.#getPageDrawContext(DRAW_UPSCALE_FACTOR);
const { canvas, transform } = this.#getPageDrawContext(DRAW_UPSCALE_FACTOR);
const drawViewport = this.viewport.clone({
scale: DRAW_UPSCALE_FACTOR * this.scale,
});
@ -298,7 +289,7 @@ class PDFThumbnailView {
};
const renderContext = {
canvasContext: ctx,
canvas,
transform,
viewport: drawViewport,
optionalContentConfigPromise: this._optionalContentConfigPromise,
@ -378,7 +369,11 @@ class PDFThumbnailView {
}
#reduceImage(img) {
const { ctx, canvas } = this.#getPageDrawContext(1, true);
const { canvas } = this.#getPageDrawContext(1);
const ctx = canvas.getContext("2d", {
alpha: false,
willReadFrequently: false,
});
if (img.width <= 2 * canvas.width) {
ctx.drawImage(