Skip to content

Commit

Permalink
Polyfill structuredClone with core-js (PR 13948 follow-up)
Browse files Browse the repository at this point in the history
This allows us to remove the manually implemented `structuredClone` polyfill, thus reducing the maintenance burden for the `LoopbackPort` class; refer to https://github.com/zloirock/core-js#structuredclone

*Please note:* This patch can't/shouldn't land until `structuredClone` becomes available in *at least* the release versions of both Mozilla Firefox and Google Chrome; see https://developer.mozilla.org/en-US/docs/Web/API/structuredClone#browser_compatibility
  • Loading branch information
Snuffleupagus committed Jan 9, 2022
1 parent 236c8d4 commit 5160659
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 85 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"globals": {
"PDFJSDev": false,
"exports": false,
"structuredClone": false,
"SystemJS": false,
},

Expand Down
88 changes: 3 additions & 85 deletions src/display/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1913,91 +1913,9 @@ class LoopbackPort {
}

postMessage(obj, transfers) {
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
// transfers.
function fallbackCloneValue(value) {
if (
typeof value === "function" ||
typeof value === "symbol" ||
value instanceof URL
) {
throw new Error(
`LoopbackPort.postMessage - cannot clone: ${value?.toString()}`
);
}

if (typeof value !== "object" || value === null) {
return value;
}
if (cloned.has(value)) {
// already cloned the object
return cloned.get(value);
}
let buffer, result;
if ((buffer = value.buffer) && isArrayBuffer(buffer)) {
// We found object with ArrayBuffer (typed array).
if (transfers?.includes(buffer)) {
result = new value.constructor(
buffer,
value.byteOffset,
value.byteLength
);
} else {
result = new value.constructor(value);
}
cloned.set(value, result);
return result;
}
if (value instanceof Map) {
result = new Map();
cloned.set(value, result); // Adding to cache now for cyclic references.
for (const [key, val] of value) {
result.set(key, fallbackCloneValue(val));
}
return result;
}
if (value instanceof Set) {
result = new Set();
cloned.set(value, result); // Adding to cache now for cyclic references.
for (const val of value) {
result.add(fallbackCloneValue(val));
}
return result;
}
result = Array.isArray(value) ? [] : Object.create(null);
cloned.set(value, result); // Adding to cache now for cyclic references.
// Cloning all value and object properties, however ignoring properties
// defined via getter.
for (const i in value) {
let desc,
p = value;
while (!(desc = Object.getOwnPropertyDescriptor(p, i))) {
p = Object.getPrototypeOf(p);
}
if (typeof desc.value === "undefined") {
continue;
}
if (typeof desc.value === "function" && !value.hasOwnProperty?.(i)) {
continue;
}
result[i] = fallbackCloneValue(desc.value);
}
return result;
}

const cloned = new WeakMap();
return fallbackCloneValue(object);
}

const event = { data: cloneValue(obj) };
const event = {
data: transfers ? structuredClone(obj, transfers) : structuredClone(obj),
};

this._deferred.then(() => {
for (const listener of this._listeners) {
Expand Down
13 changes: 13 additions & 0 deletions src/shared/compatibility.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,17 @@ if (
globalThis.ReadableStream =
require("web-streams-polyfill/dist/ponyfill.js").ReadableStream;
})();

// Support: Firefox<94, Chrome<xx, Safari<yy, Node.js<17.0.0
(function checkStructuredClone() {
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("IMAGE_DECODERS")) {
// The current image decoders are synchronous, hence `structuredClone`
// shouldn't need to be polyfilled for the IMAGE_DECODERS build target.
return;
}
if (globalThis.structuredClone) {
return;
}
require("core-js/web/structured-clone.js");
})();
}

0 comments on commit 5160659

Please sign in to comment.