Use the native structuredClone implementation when it's available

With a recent addition to the HTML specification, the internal structured clone algorithm used in browsers is (or will be, once it's implemented) *directly* accessible to JavaScript; please see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/structuredClone

Hence we'll *eventually* not need to maintain our own structured clone functionality in the `LoopbackPort`-class in the API, however for the time being we'll feature detect `structuredClone` and fallback to the existing PDF.js implementation.

Given that https://bugzilla.mozilla.org/show_bug.cgi?id=1722576 has landed in Firefox 94, we should no longer need the manually implemented `cloneValue`-functionality in MOZCENTRAL builds. Note also that in the Firefox built-in PDF Viewer it's not possible for users to *easily* disable workers, which should further reduce the risk of these changes.
This commit is contained in:
Jonas Jenwald 2021-08-30 18:20:19 +02:00
parent a474d6c30f
commit d49b1bf2ee

View File

@ -1899,13 +1899,21 @@ class PDFPageProxy {
class LoopbackPort { class LoopbackPort {
constructor() { constructor() {
this._listeners = []; this._listeners = [];
this._deferred = Promise.resolve(undefined); this._deferred = Promise.resolve();
} }
postMessage(obj, transfers) { postMessage(obj, transfers) {
function cloneValue(value) { function cloneValue(object) {
if (
(typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) ||
globalThis.structuredClone
) {
return globalThis.structuredClone(object, transfers);
}
// Trying to perform a structured clone close to the spec, including // Trying to perform a structured clone close to the spec, including
// transfers. // transfers.
function fallbackCloneValue(value) {
if ( if (
typeof value === "function" || typeof value === "function" ||
typeof value === "symbol" || typeof value === "symbol" ||
@ -1942,7 +1950,7 @@ class LoopbackPort {
result = new Map(); result = new Map();
cloned.set(value, result); // Adding to cache now for cyclic references. cloned.set(value, result); // Adding to cache now for cyclic references.
for (const [key, val] of value) { for (const [key, val] of value) {
result.set(key, cloneValue(val)); result.set(key, fallbackCloneValue(val));
} }
return result; return result;
} }
@ -1950,7 +1958,7 @@ class LoopbackPort {
result = new Set(); result = new Set();
cloned.set(value, result); // Adding to cache now for cyclic references. cloned.set(value, result); // Adding to cache now for cyclic references.
for (const val of value) { for (const val of value) {
result.add(cloneValue(val)); result.add(fallbackCloneValue(val));
} }
return result; return result;
} }
@ -1970,12 +1978,15 @@ class LoopbackPort {
if (typeof desc.value === "function" && !value.hasOwnProperty?.(i)) { if (typeof desc.value === "function" && !value.hasOwnProperty?.(i)) {
continue; continue;
} }
result[i] = cloneValue(desc.value); result[i] = fallbackCloneValue(desc.value);
} }
return result; return result;
} }
const cloned = new WeakMap(); const cloned = new WeakMap();
return fallbackCloneValue(object);
}
const event = { data: cloneValue(obj) }; const event = { data: cloneValue(obj) };
this._deferred.then(() => { this._deferred.then(() => {