Merge pull request #13948 from Snuffleupagus/structuredClone
Use the native `structuredClone` implementation when it's available
This commit is contained in:
commit
f5b79be0b7
@ -1899,83 +1899,94 @@ 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.
|
||||||
if (
|
function fallbackCloneValue(value) {
|
||||||
typeof value === "function" ||
|
if (
|
||||||
typeof value === "symbol" ||
|
typeof value === "function" ||
|
||||||
value instanceof URL
|
typeof value === "symbol" ||
|
||||||
) {
|
value instanceof URL
|
||||||
throw new Error(
|
) {
|
||||||
`LoopbackPort.postMessage - cannot clone: ${value?.toString()}`
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof value !== "object" || value === null) {
|
const cloned = new WeakMap();
|
||||||
return value;
|
return fallbackCloneValue(object);
|
||||||
}
|
|
||||||
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, cloneValue(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(cloneValue(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] = cloneValue(desc.value);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const cloned = new WeakMap();
|
|
||||||
const event = { data: cloneValue(obj) };
|
const event = { data: cloneValue(obj) };
|
||||||
|
|
||||||
this._deferred.then(() => {
|
this._deferred.then(() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user