mirror of
https://github.com/lexmount/moli.git
synced 2026-10-06 00:00:56 +00:00
fix(geometry): support structured cloning
This commit is contained in:
@@ -2467,7 +2467,6 @@ css/cssom/getComputedStyle-layout-dependent-replaced-into-ib-split.html
|
||||
css/cssom/idlharness.html
|
||||
css/cssom/style-sheet-interfaces-001.html
|
||||
css/geometry/DOMMatrix2DInit-validate-fixup.html
|
||||
css/geometry/structured-serialization.html
|
||||
css/mediaqueries/at-custom-media-cssom.html
|
||||
css/mediaqueries/at-custom-media-parsing.html
|
||||
css/mediaqueries/display-mode.html
|
||||
|
||||
@@ -3367,6 +3367,7 @@ css/geometry/DOMRectList.html
|
||||
css/geometry/WebKitCSSMatrix.html
|
||||
css/geometry/historical.html
|
||||
css/geometry/spec-examples.html
|
||||
css/geometry/structured-serialization.html
|
||||
css/mediaqueries/aspect-ratio-serialization.html
|
||||
css/mediaqueries/duplicate-media-stylesheet-crash.html
|
||||
css/mediaqueries/dynamic-range.html
|
||||
|
||||
@@ -24,6 +24,7 @@ mod events;
|
||||
pub(crate) mod exposed_interfaces;
|
||||
mod file_api;
|
||||
mod form_data_runtime;
|
||||
mod geometry_clone;
|
||||
mod geometry_runtime;
|
||||
mod history_mutation;
|
||||
mod history_runtime;
|
||||
@@ -273,6 +274,10 @@ pub(crate) use self::file_api::{
|
||||
flush_one_pending_file_reader, is_file_list_object, selected_file_from_object,
|
||||
};
|
||||
pub(crate) use self::form_data_runtime::form_data_request_body;
|
||||
pub(crate) use self::geometry_clone::{
|
||||
GeometryClonePayload, build_geometry_object_from_clone_payload,
|
||||
geometry_clone_payload_from_object,
|
||||
};
|
||||
use self::geometry_runtime::{build_dom_point_object, optional_dom_point_init_arg};
|
||||
pub(crate) use self::image_data::{
|
||||
ImageDataClonePayload, build_image_data_object_from_clone_payload,
|
||||
|
||||
@@ -24,8 +24,8 @@ use super::super::{
|
||||
},
|
||||
form_data_runtime::build_form_data_constructor_template,
|
||||
geometry_runtime::{
|
||||
dom_matrix_constructor_callback, dom_point_constructor_callback,
|
||||
dom_point_readonly_constructor_callback,
|
||||
dom_matrix_constructor_callback, dom_matrix_readonly_constructor_callback,
|
||||
dom_point_constructor_callback, dom_point_readonly_constructor_callback,
|
||||
},
|
||||
idle_detection::idle_detector_constructor_callback,
|
||||
image_data::image_data_constructor_callback,
|
||||
@@ -536,6 +536,14 @@ pub(in crate::context_bootstrap) fn build_constructor_template<'s>(
|
||||
.length(0)
|
||||
.build(scope)
|
||||
}
|
||||
ConstructorKind::DomMatrixReadOnly => {
|
||||
v8::FunctionTemplate::builder(moli_webapi_declare::web_api_constructor!(
|
||||
web_api_interfaces::DOMMatrixReadOnly,
|
||||
dom_matrix_readonly_constructor_callback
|
||||
))
|
||||
.length(0)
|
||||
.build(scope)
|
||||
}
|
||||
ConstructorKind::DomMatrix => {
|
||||
v8::FunctionTemplate::builder(dom_matrix_constructor_callback)
|
||||
.length(0)
|
||||
|
||||
@@ -322,6 +322,27 @@ fn dom_quad_points<'s>(
|
||||
])
|
||||
}
|
||||
|
||||
pub(super) fn dom_quad_clone_data<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
) -> Option<[[f64; 4]; 4]> {
|
||||
let points = dom_quad_points(scope, object)?;
|
||||
Some(points.map(|point| {
|
||||
let point = geometry_runtime::dom_point_init_from_object(scope, point);
|
||||
[point.x, point.y, point.z, point.w]
|
||||
}))
|
||||
}
|
||||
|
||||
pub(super) fn build_dom_quad_clone_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
points: [[f64; 4]; 4],
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
build_dom_quad(
|
||||
scope,
|
||||
points.map(|[x, y, z, w]| geometry_runtime::DomPointInit { x, y, z, w }),
|
||||
)
|
||||
}
|
||||
|
||||
fn dom_quad_receiver_branded<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
receiver: v8::Local<'s, v8::Object>,
|
||||
|
||||
@@ -561,6 +561,37 @@ fn dom_rect_receiver_branded<'s>(
|
||||
web_api_interfaces::DOMRectReadOnly::is_instance(scope, receiver)
|
||||
}
|
||||
|
||||
pub(super) fn dom_rect_clone_data<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
) -> Option<(bool, [f64; 4])> {
|
||||
if !dom_rect_receiver_branded(scope, object) {
|
||||
return None;
|
||||
}
|
||||
let mutable = web_api_interfaces::DOMRect::is_instance(scope, object);
|
||||
Some((
|
||||
mutable,
|
||||
[
|
||||
dom_rect_slot(object, scope, DOM_RECT_X_SLOT),
|
||||
dom_rect_slot(object, scope, DOM_RECT_Y_SLOT),
|
||||
dom_rect_slot(object, scope, DOM_RECT_WIDTH_SLOT),
|
||||
dom_rect_slot(object, scope, DOM_RECT_HEIGHT_SLOT),
|
||||
],
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn build_dom_rect_clone_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
mutable: bool,
|
||||
[x, y, width, height]: [f64; 4],
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
if mutable {
|
||||
build_dom_rect_object(scope, x, y, width, height)
|
||||
} else {
|
||||
build_dom_rect_readonly_object(scope, x, y, width, height)
|
||||
}
|
||||
}
|
||||
|
||||
const DOM_RECT_WRITABLE_ATTRIBUTE_SLOTS: &[&str] = &[
|
||||
DOM_RECT_X_SLOT,
|
||||
DOM_RECT_Y_SLOT,
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
use super::{dom_quad, dom_rect, geometry_runtime};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) enum GeometryClonePayload {
|
||||
Point {
|
||||
mutable: bool,
|
||||
values: [f64; 4],
|
||||
},
|
||||
Rect {
|
||||
mutable: bool,
|
||||
values: [f64; 4],
|
||||
},
|
||||
Quad {
|
||||
points: [[f64; 4]; 4],
|
||||
},
|
||||
Matrix {
|
||||
mutable: bool,
|
||||
is_2d: bool,
|
||||
values: [f64; 16],
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) fn geometry_clone_payload_from_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
) -> Option<GeometryClonePayload> {
|
||||
if let Some((mutable, values)) = geometry_runtime::dom_point_clone_data(scope, object) {
|
||||
return Some(GeometryClonePayload::Point { mutable, values });
|
||||
}
|
||||
if let Some((mutable, values)) = dom_rect::dom_rect_clone_data(scope, object) {
|
||||
return Some(GeometryClonePayload::Rect { mutable, values });
|
||||
}
|
||||
if let Some(points) = dom_quad::dom_quad_clone_data(scope, object) {
|
||||
return Some(GeometryClonePayload::Quad { points });
|
||||
}
|
||||
geometry_runtime::dom_matrix_clone_data(scope, object).map(|(mutable, is_2d, values)| {
|
||||
GeometryClonePayload::Matrix {
|
||||
mutable,
|
||||
is_2d,
|
||||
values,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn build_geometry_object_from_clone_payload<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
payload: GeometryClonePayload,
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
match payload {
|
||||
GeometryClonePayload::Point { mutable, values } => {
|
||||
geometry_runtime::build_dom_point_clone_object(scope, mutable, values)
|
||||
}
|
||||
GeometryClonePayload::Rect { mutable, values } => {
|
||||
dom_rect::build_dom_rect_clone_object(scope, mutable, values)
|
||||
}
|
||||
GeometryClonePayload::Quad { points } => {
|
||||
dom_quad::build_dom_quad_clone_object(scope, points)
|
||||
}
|
||||
GeometryClonePayload::Matrix {
|
||||
mutable,
|
||||
is_2d,
|
||||
values,
|
||||
} => geometry_runtime::build_dom_matrix_clone_object(scope, mutable, is_2d, values),
|
||||
}
|
||||
}
|
||||
@@ -657,6 +657,28 @@ pub(super) fn dom_matrix_constructor_callback<'s>(
|
||||
rv.set(args.this().into());
|
||||
}
|
||||
|
||||
pub(super) fn dom_matrix_readonly_constructor_callback<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
mut rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
if !args.is_construct_call() {
|
||||
throw_type_error(
|
||||
scope,
|
||||
"Failed to construct 'DOMMatrixReadOnly': Please use the 'new' operator.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
initialize_dom_matrix_readonly_identity_object(scope, args.this());
|
||||
if args.length() > 0
|
||||
&& !args.get(0).is_undefined()
|
||||
&& !apply_dom_matrix_init(scope, args.this(), args.get(0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
rv.set(args.this().into());
|
||||
}
|
||||
|
||||
pub(in crate::context_bootstrap) fn initialize_dom_point_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
@@ -1175,6 +1197,37 @@ fn dom_point_receiver_branded<'s>(
|
||||
web_api_interfaces::DOMPointReadOnly::is_instance(scope, receiver)
|
||||
}
|
||||
|
||||
pub(super) fn dom_point_clone_data<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
) -> Option<(bool, [f64; 4])> {
|
||||
if !dom_point_receiver_branded(scope, object) {
|
||||
return None;
|
||||
}
|
||||
let mutable = web_api_interfaces::DOMPoint::is_instance(scope, object);
|
||||
Some((
|
||||
mutable,
|
||||
[
|
||||
dom_point_slot(scope, object, DOM_POINT_X_SLOT, 0.0),
|
||||
dom_point_slot(scope, object, DOM_POINT_Y_SLOT, 0.0),
|
||||
dom_point_slot(scope, object, DOM_POINT_Z_SLOT, 0.0),
|
||||
dom_point_slot(scope, object, DOM_POINT_W_SLOT, 1.0),
|
||||
],
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn build_dom_point_clone_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
mutable: bool,
|
||||
[x, y, z, w]: [f64; 4],
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
if mutable {
|
||||
build_dom_point_object(scope, x, y, z, w)
|
||||
} else {
|
||||
build_dom_point_readonly_object(scope, x, y, z, w)
|
||||
}
|
||||
}
|
||||
|
||||
fn dom_matrix_require_readonly_receiver<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
receiver: v8::Local<'s, v8::Object>,
|
||||
@@ -1197,6 +1250,107 @@ fn dom_matrix_require_mutable_receiver<'s>(
|
||||
false
|
||||
}
|
||||
|
||||
pub(super) fn dom_matrix_clone_data<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
) -> Option<(bool, bool, [f64; DOM_MATRIX_COMPONENT_COUNT])> {
|
||||
if !web_api_interfaces::DOMMatrixReadOnly::is_instance(scope, object) {
|
||||
return None;
|
||||
}
|
||||
let mutable = web_api_interfaces::DOMMatrix::is_instance(scope, object);
|
||||
let is_2d = dom_matrix_is_2d(scope, object);
|
||||
let mut components = dom_matrix_components(scope, object);
|
||||
if is_2d {
|
||||
components = DomMatrixComponents {
|
||||
m11: components.m11,
|
||||
m12: components.m12,
|
||||
m21: components.m21,
|
||||
m22: components.m22,
|
||||
m41: components.m41,
|
||||
m42: components.m42,
|
||||
..DomMatrixComponents::identity()
|
||||
};
|
||||
}
|
||||
Some((
|
||||
mutable,
|
||||
is_2d,
|
||||
[
|
||||
components.m11,
|
||||
components.m12,
|
||||
components.m13,
|
||||
components.m14,
|
||||
components.m21,
|
||||
components.m22,
|
||||
components.m23,
|
||||
components.m24,
|
||||
components.m31,
|
||||
components.m32,
|
||||
components.m33,
|
||||
components.m34,
|
||||
components.m41,
|
||||
components.m42,
|
||||
components.m43,
|
||||
components.m44,
|
||||
],
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn build_dom_matrix_clone_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
mutable: bool,
|
||||
is_2d: bool,
|
||||
values: [f64; DOM_MATRIX_COMPONENT_COUNT],
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
let [
|
||||
m11,
|
||||
m12,
|
||||
m13,
|
||||
m14,
|
||||
m21,
|
||||
m22,
|
||||
m23,
|
||||
m24,
|
||||
m31,
|
||||
m32,
|
||||
m33,
|
||||
m34,
|
||||
m41,
|
||||
m42,
|
||||
m43,
|
||||
m44,
|
||||
] = values;
|
||||
let value = DomMatrixValue {
|
||||
components: DomMatrixComponents {
|
||||
m11,
|
||||
m12,
|
||||
m13,
|
||||
m14,
|
||||
m21,
|
||||
m22,
|
||||
m23,
|
||||
m24,
|
||||
m31,
|
||||
m32,
|
||||
m33,
|
||||
m34,
|
||||
m41,
|
||||
m42,
|
||||
m43,
|
||||
m44,
|
||||
},
|
||||
is_2d,
|
||||
};
|
||||
if mutable {
|
||||
DomMatrixObjectDeclaration::from_value(value)
|
||||
.bind(scope)
|
||||
.expect("DOMMatrix clone declaration should bind")
|
||||
} else {
|
||||
DomMatrixReadOnlyObjectDeclaration::from_value(value)
|
||||
.bind(scope)
|
||||
.expect("DOMMatrixReadOnly clone declaration should bind")
|
||||
}
|
||||
}
|
||||
|
||||
fn dom_matrix_to_json_callback<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
@@ -2331,6 +2485,15 @@ fn initialize_dom_matrix_identity_object<'s>(
|
||||
.expect("DOMMatrix declaration should initialize object");
|
||||
}
|
||||
|
||||
fn initialize_dom_matrix_readonly_identity_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
) {
|
||||
DomMatrixReadOnlyObjectDeclaration::identity()
|
||||
.initialize(scope, object)
|
||||
.expect("DOMMatrixReadOnly declaration should initialize object");
|
||||
}
|
||||
|
||||
fn dom_matrix_is_2d<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
|
||||
@@ -1105,7 +1105,7 @@ const CONSTRUCTOR_SPECS_AFTER_STREAMS: &[ConstructorSpec] = &[
|
||||
},
|
||||
ConstructorSpec {
|
||||
interface: web_api_interfaces::DOMMatrixReadOnly::DESCRIPTOR,
|
||||
kind: ConstructorKind::DomMatrix,
|
||||
kind: ConstructorKind::DomMatrixReadOnly,
|
||||
},
|
||||
ConstructorSpec {
|
||||
interface: web_api_interfaces::DOMMatrix::DESCRIPTOR,
|
||||
|
||||
@@ -116,6 +116,7 @@ pub(in crate::context_bootstrap) enum ConstructorKind {
|
||||
DomPointReadOnly,
|
||||
DomPoint,
|
||||
DomQuad,
|
||||
DomMatrixReadOnly,
|
||||
DomMatrix,
|
||||
ResizeObserver,
|
||||
PerformanceObserver,
|
||||
|
||||
@@ -323,6 +323,90 @@ fn structured_clone_preserves_dom_exception_fields_and_brand() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn structured_clone_preserves_geometry_interfaces_and_internal_values() {
|
||||
let mut vm = new_storage_test_vm("https://geometry-structured-clone.test/");
|
||||
|
||||
let result = vm
|
||||
.eval(
|
||||
r#"
|
||||
(() => {
|
||||
const same = (actual, expected) => Object.is(actual, expected);
|
||||
const check = (name, source, attrs, expected, nested = false) => {
|
||||
const originals = nested ? attrs.map(attr => source[attr]) : [];
|
||||
source.expando = "not serialized";
|
||||
for (const attr of attrs) {
|
||||
Object.defineProperty(source, attr, {
|
||||
get() { throw new Error(`unexpected ${name}.${attr} getter`); }
|
||||
});
|
||||
}
|
||||
const clone = structuredClone(source);
|
||||
const valuesMatch = attrs.every((attr, index) => {
|
||||
if (!nested) return same(clone[attr], expected[index]);
|
||||
return clone[attr] !== originals[index]
|
||||
&& expected[index].every((value, component) =>
|
||||
same(clone[attr][["x", "y", "z", "w"][component]], value));
|
||||
});
|
||||
return Object.prototype.toString.call(clone) === `[object ${name}]`
|
||||
&& Object.getPrototypeOf(clone) === self[name].prototype
|
||||
&& !("expando" in clone)
|
||||
&& valuesMatch;
|
||||
};
|
||||
|
||||
const pointAttrs = ["x", "y", "z", "w"];
|
||||
const rectAttrs = ["x", "y", "width", "height"];
|
||||
const quadAttrs = ["p1", "p2", "p3", "p4"];
|
||||
const pointValues = [1, -0, Infinity, NaN];
|
||||
const quadValues = [
|
||||
[1, 2, 3, 4],
|
||||
[-0, -0, -0, -0],
|
||||
[Infinity, Infinity, Infinity, Infinity],
|
||||
[NaN, NaN, NaN, NaN]
|
||||
];
|
||||
const matrixAttrs = [
|
||||
"a", "b", "c", "d", "e", "f",
|
||||
"m11", "m12", "m13", "m14",
|
||||
"m21", "m22", "m23", "m24",
|
||||
"m31", "m32", "m33", "m34",
|
||||
"m41", "m42", "m43", "m44", "is2D"
|
||||
];
|
||||
const normalized2DAttrs = new Set([
|
||||
"m13", "m14", "m23", "m24",
|
||||
"m31", "m32", "m34", "m43"
|
||||
]);
|
||||
const matrixCheck = (name, values) => {
|
||||
const source = new self[name](values);
|
||||
if (values.length === 6) {
|
||||
for (const attr of normalized2DAttrs) source[attr] = -0;
|
||||
}
|
||||
const expected = matrixAttrs.map(attr =>
|
||||
normalized2DAttrs.has(attr) && values.length === 6 ? 0 : source[attr]);
|
||||
return check(name, source, matrixAttrs, expected);
|
||||
};
|
||||
|
||||
return [
|
||||
check("DOMPointReadOnly", new DOMPointReadOnly(...pointValues),
|
||||
pointAttrs, pointValues),
|
||||
check("DOMPoint", new DOMPoint(...pointValues), pointAttrs, pointValues),
|
||||
check("DOMRectReadOnly", new DOMRectReadOnly(...pointValues),
|
||||
rectAttrs, pointValues),
|
||||
check("DOMRect", new DOMRect(...pointValues), rectAttrs, pointValues),
|
||||
check("DOMQuad", new DOMQuad(...quadValues.map(
|
||||
([x, y, z, w]) => ({x, y, z, w}))), quadAttrs, quadValues, true),
|
||||
matrixCheck("DOMMatrixReadOnly", [1, -0, Infinity, NaN, 5, 6]),
|
||||
matrixCheck("DOMMatrix", [
|
||||
11, -0, Infinity, NaN, 21, 22, 23, 24,
|
||||
31, 32, 33, 34, 41, 42, 43, 44
|
||||
])
|
||||
].join("|");
|
||||
})()
|
||||
"#,
|
||||
)
|
||||
.expect("Geometry structuredClone probe should evaluate");
|
||||
|
||||
assert_eq!(result, "true|true|true|true|true|true|true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn structured_clone_transfers_array_buffer_and_preserves_view_aliases() {
|
||||
let mut vm = new_storage_test_vm("https://array-buffer-transfer.test/");
|
||||
|
||||
@@ -9,8 +9,8 @@ use std::{
|
||||
use crate::{
|
||||
context_bootstrap::{
|
||||
CryptoKeyAlgorithmClonePayload, CryptoKeyClonePayload, FileSystemFileSnapshotClonePayload,
|
||||
FileSystemHandleClonePayload, ImageDataClonePayload, ReadableStreamClonePayload,
|
||||
TransformStreamClonePayload, WritableStreamClonePayload,
|
||||
FileSystemHandleClonePayload, GeometryClonePayload, ImageDataClonePayload,
|
||||
ReadableStreamClonePayload, TransformStreamClonePayload, WritableStreamClonePayload,
|
||||
attach_file_system_file_snapshot_clone_payload, build_file_object,
|
||||
build_file_system_handle_from_clone_payload, build_image_data_object_from_clone_payload,
|
||||
build_readable_stream_clone_shell, build_transform_stream_clone_shell,
|
||||
@@ -25,6 +25,7 @@ use crate::{
|
||||
prepare_transform_stream_transfer, prepare_writable_stream_transfer,
|
||||
quota_exceeded_error_clone_fields, require_internal_stream_value,
|
||||
selected_file_from_object,
|
||||
build_geometry_object_from_clone_payload, geometry_clone_payload_from_object,
|
||||
},
|
||||
dom::native::SelectedFile,
|
||||
types::MessagePortId,
|
||||
@@ -44,6 +45,15 @@ pub(crate) const HOST_OBJECT_TAG_FILE_SYSTEM_HANDLE: u32 = 7;
|
||||
const HOST_OBJECT_TAG_QUOTA_EXCEEDED_ERROR: u32 = 8;
|
||||
const HOST_OBJECT_TAG_WRITABLE_STREAM: u32 = 9;
|
||||
const HOST_OBJECT_TAG_TRANSFORM_STREAM: u32 = 10;
|
||||
const HOST_OBJECT_TAG_GEOMETRY: u32 = 11;
|
||||
|
||||
const GEOMETRY_KIND_DOM_POINT_READONLY: u32 = 0;
|
||||
const GEOMETRY_KIND_DOM_POINT: u32 = 1;
|
||||
const GEOMETRY_KIND_DOM_RECT_READONLY: u32 = 2;
|
||||
const GEOMETRY_KIND_DOM_RECT: u32 = 3;
|
||||
const GEOMETRY_KIND_DOM_QUAD: u32 = 4;
|
||||
const GEOMETRY_KIND_DOM_MATRIX_READONLY: u32 = 5;
|
||||
const GEOMETRY_KIND_DOM_MATRIX: u32 = 6;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct V8StructuredClonePayload {
|
||||
@@ -368,6 +378,12 @@ impl v8::ValueSerializerImpl for WireSerializer {
|
||||
return Some(true);
|
||||
}
|
||||
}
|
||||
Some("DOMPoint" | "DOMPointReadOnly" | "DOMRect" | "DOMRectReadOnly" | "DOMQuad" | "DOMMatrix" | "DOMMatrixReadOnly") => {
|
||||
if let Some(payload) = geometry_clone_payload_from_object(scope, object) {
|
||||
write_geometry_clone_payload(serializer, payload);
|
||||
return Some(true);
|
||||
}
|
||||
}
|
||||
Some("ImageData") => {
|
||||
if let Some(payload) = image_data_clone_payload_from_object(scope, object) {
|
||||
write_image_data_payload(serializer, payload);
|
||||
@@ -593,6 +609,15 @@ impl v8::ValueDeserializerImpl for WireDeserializer {
|
||||
None
|
||||
})
|
||||
}
|
||||
HOST_OBJECT_TAG_GEOMETRY => read_geometry_clone_payload(deserializer)
|
||||
.map(|payload| build_geometry_object_from_clone_payload(scope, payload))
|
||||
.or_else(|| {
|
||||
throw_data_clone_exception(
|
||||
scope,
|
||||
"Failed to deserialize structured clone Geometry object.",
|
||||
);
|
||||
None
|
||||
}),
|
||||
HOST_OBJECT_TAG_READABLE_STREAM => {
|
||||
let clone_id = read_u32(deserializer)?;
|
||||
let Some(payload) = self.readable_streams.get(&clone_id).cloned() else {
|
||||
@@ -824,6 +849,125 @@ pub(crate) fn read_image_data_payload<'s>(
|
||||
)
|
||||
}
|
||||
|
||||
fn write_geometry_clone_payload(
|
||||
serializer: &dyn v8::ValueSerializerHelper,
|
||||
payload: GeometryClonePayload,
|
||||
) {
|
||||
serializer.write_uint32(HOST_OBJECT_TAG_GEOMETRY);
|
||||
match payload {
|
||||
GeometryClonePayload::Point { mutable, values } => {
|
||||
serializer.write_uint32(if mutable {
|
||||
GEOMETRY_KIND_DOM_POINT
|
||||
} else {
|
||||
GEOMETRY_KIND_DOM_POINT_READONLY
|
||||
});
|
||||
write_doubles(serializer, &values);
|
||||
}
|
||||
GeometryClonePayload::Rect { mutable, values } => {
|
||||
serializer.write_uint32(if mutable {
|
||||
GEOMETRY_KIND_DOM_RECT
|
||||
} else {
|
||||
GEOMETRY_KIND_DOM_RECT_READONLY
|
||||
});
|
||||
write_doubles(serializer, &values);
|
||||
}
|
||||
GeometryClonePayload::Quad { points } => {
|
||||
serializer.write_uint32(GEOMETRY_KIND_DOM_QUAD);
|
||||
for point in points {
|
||||
write_doubles(serializer, &point);
|
||||
}
|
||||
}
|
||||
GeometryClonePayload::Matrix {
|
||||
mutable,
|
||||
is_2d,
|
||||
values,
|
||||
} => {
|
||||
serializer.write_uint32(if mutable {
|
||||
GEOMETRY_KIND_DOM_MATRIX
|
||||
} else {
|
||||
GEOMETRY_KIND_DOM_MATRIX_READONLY
|
||||
});
|
||||
serializer.write_uint32(u32::from(is_2d));
|
||||
if is_2d {
|
||||
write_doubles(
|
||||
serializer,
|
||||
&[
|
||||
values[0], values[1], values[4], values[5], values[12], values[13],
|
||||
],
|
||||
);
|
||||
} else {
|
||||
write_doubles(serializer, &values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_geometry_clone_payload(
|
||||
deserializer: &dyn v8::ValueDeserializerHelper,
|
||||
) -> Option<GeometryClonePayload> {
|
||||
let kind = read_u32(deserializer)?;
|
||||
match kind {
|
||||
GEOMETRY_KIND_DOM_POINT_READONLY | GEOMETRY_KIND_DOM_POINT => {
|
||||
Some(GeometryClonePayload::Point {
|
||||
mutable: kind == GEOMETRY_KIND_DOM_POINT,
|
||||
values: read_doubles(deserializer)?,
|
||||
})
|
||||
}
|
||||
GEOMETRY_KIND_DOM_RECT_READONLY | GEOMETRY_KIND_DOM_RECT => {
|
||||
Some(GeometryClonePayload::Rect {
|
||||
mutable: kind == GEOMETRY_KIND_DOM_RECT,
|
||||
values: read_doubles(deserializer)?,
|
||||
})
|
||||
}
|
||||
GEOMETRY_KIND_DOM_QUAD => {
|
||||
let mut points = [[0.0; 4]; 4];
|
||||
for point in &mut points {
|
||||
*point = read_doubles(deserializer)?;
|
||||
}
|
||||
Some(GeometryClonePayload::Quad { points })
|
||||
}
|
||||
GEOMETRY_KIND_DOM_MATRIX_READONLY | GEOMETRY_KIND_DOM_MATRIX => {
|
||||
let is_2d = match read_u32(deserializer)? {
|
||||
0 => false,
|
||||
1 => true,
|
||||
_ => return None,
|
||||
};
|
||||
let values = if is_2d {
|
||||
let [m11, m12, m21, m22, m41, m42] = read_doubles(deserializer)?;
|
||||
[
|
||||
m11, m12, 0.0, 0.0, m21, m22, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, m41, m42, 0.0, 1.0,
|
||||
]
|
||||
} else {
|
||||
read_doubles(deserializer)?
|
||||
};
|
||||
Some(GeometryClonePayload::Matrix {
|
||||
mutable: kind == GEOMETRY_KIND_DOM_MATRIX,
|
||||
is_2d,
|
||||
values,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn write_doubles(serializer: &dyn v8::ValueSerializerHelper, values: &[f64]) {
|
||||
for value in values {
|
||||
serializer.write_double(*value);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_doubles<const N: usize>(
|
||||
deserializer: &dyn v8::ValueDeserializerHelper,
|
||||
) -> Option<[f64; N]> {
|
||||
let mut values = [0.0; N];
|
||||
for value in &mut values {
|
||||
if !deserializer.read_double(value) {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(values)
|
||||
}
|
||||
|
||||
pub(crate) fn write_crypto_key_payload<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
object: v8::Local<'s, v8::Object>,
|
||||
|
||||
Reference in New Issue
Block a user