Tweak the WasmImage implementation a little bit (PR 21225 follow-up)

This fixes two things that I overlooked in PR 21225, more specifically:

 - Use proper, rather than semi, private class fields in `WasmImage`.

 - Make tracking of `WasmImage` instances optional, to avoid keeping data alive permanently in the `IMAGE_DECODERS` build.
This commit is contained in:
Jonas Jenwald 2026-05-06 15:04:10 +02:00
parent cd1b5f57c7
commit 3f6a2feef6
3 changed files with 24 additions and 17 deletions

View File

@ -29,7 +29,11 @@ class JBig2CCITTFaxImage extends WasmImage {
_noWasmFilename = "jbig2_nowasm_fallback.js";
static get instance() {
return shadow(this, "instance", new JBig2CCITTFaxImage());
return shadow(
this,
"instance",
new JBig2CCITTFaxImage(/* trackInstance = */ true)
);
}
async decode(bytes, width, height, globals, CCITTOptions) {

View File

@ -30,7 +30,7 @@ class JpxImage extends WasmImage {
_noWasmFilename = "openjpeg_nowasm_fallback.js";
static get instance() {
return shadow(this, "instance", new JpxImage());
return shadow(this, "instance", new JpxImage(/* trackInstance = */ true));
}
async decode(

View File

@ -27,13 +27,13 @@ class WasmImage {
static #wasmUrl = null;
_buffer = null;
#buffer = null;
_filename = "";
#modulePromise = null;
_noWasmFilename = "";
_filename = null;
_modulePromise = null;
_noWasmFilename = null;
static setOptions({ handler, useWasm, useWorkerFetch, wasmUrl }) {
WasmImage.#useWasm = useWasm;
@ -52,19 +52,22 @@ class WasmImage {
static cleanup() {
for (const instance of WasmImage.#instances) {
instance._modulePromise = null;
instance.#modulePromise = null;
}
}
constructor() {
constructor(trackInstance = false) {
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
this.constructor === WasmImage
) {
unreachable("Cannot initialize WasmImage.");
}
// Keep track of the instances for `cleanup` purposes.
WasmImage.#instances.add(this);
if (trackInstance) {
// Keep track of the instances for `cleanup` purposes.
WasmImage.#instances.add(this);
}
}
async #getJsModule(fallbackCallback) {
@ -83,22 +86,22 @@ class WasmImage {
async #instantiateWasm(fallbackCallback, imports, successCallback) {
try {
if (!this._buffer) {
if (!this.#buffer) {
if (WasmImage.#useWorkerFetch) {
this._buffer = await fetchBinaryData(
this.#buffer = await fetchBinaryData(
`${WasmImage.#wasmUrl}${this._filename}`
);
} else {
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
throw new Error("Only worker-thread fetching supported.");
}
this._buffer = await WasmImage.#handler.sendWithPromise(
this.#buffer = await WasmImage.#handler.sendWithPromise(
"FetchBinaryData",
{ kind: "wasmUrl", filename: this._filename }
);
}
}
const results = await WebAssembly.instantiate(this._buffer, imports);
const results = await WebAssembly.instantiate(this.#buffer, imports);
return successCallback(results.instance);
} catch (ex) {
warn(`#instantiateWasm: ${ex}`);
@ -109,7 +112,7 @@ class WasmImage {
}
_getModule(ImageDecoder) {
if (!this._modulePromise) {
if (!this.#modulePromise) {
const { promise, resolve } = Promise.withResolvers();
const promises = [promise];
if (!WasmImage.#useWasm) {
@ -122,9 +125,9 @@ class WasmImage {
})
);
}
this._modulePromise = Promise.race(promises);
this.#modulePromise = Promise.race(promises);
}
return this._modulePromise;
return this.#modulePromise;
}
async decode(bytes, _params) {