fix(svg): reflect animated length attributes

This commit is contained in:
ldm0
2026-09-23 00:11:53 +08:00
parent d2bba6560a
commit 1df5279884
4 changed files with 473 additions and 47 deletions
@@ -1298,6 +1298,18 @@ struct SvgTextPositioningElementPrototypeAccessorsDeclaration {
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGPatternElement, enumerable)]
struct SvgPatternElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "x", getter = svg_pattern_animated_length_getter, data = callback_data_index_value(scope, 0))]
x: (),
#[webapi(accessor_property = "y", getter = svg_pattern_animated_length_getter, data = callback_data_index_value(scope, 1))]
y: (),
#[webapi(accessor_property = "width", getter = svg_pattern_animated_length_getter, data = callback_data_index_value(scope, 2))]
width: (),
#[webapi(accessor_property = "height", getter = svg_pattern_animated_length_getter, data = callback_data_index_value(scope, 3))]
height: (),
#[webapi(
accessor_property = "patternUnits",
getter = svg_element_animated_enumeration_getter,
@@ -1337,6 +1349,60 @@ struct SvgGradientElementPrototypeAccessorsDeclaration {
gradient_transform: (),
}
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGLinearGradientElement, enumerable)]
struct SvgLinearGradientElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "x1", getter = svg_linear_gradient_animated_length_getter, data = callback_data_index_value(scope, 0))]
x1: (),
#[webapi(accessor_property = "y1", getter = svg_linear_gradient_animated_length_getter, data = callback_data_index_value(scope, 1))]
y1: (),
#[webapi(accessor_property = "x2", getter = svg_linear_gradient_animated_length_getter, data = callback_data_index_value(scope, 2))]
x2: (),
#[webapi(accessor_property = "y2", getter = svg_linear_gradient_animated_length_getter, data = callback_data_index_value(scope, 3))]
y2: (),
}
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGRadialGradientElement, enumerable)]
struct SvgRadialGradientElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "cx", getter = svg_radial_gradient_animated_length_getter, data = callback_data_index_value(scope, 0))]
cx: (),
#[webapi(accessor_property = "cy", getter = svg_radial_gradient_animated_length_getter, data = callback_data_index_value(scope, 1))]
cy: (),
#[webapi(accessor_property = "r", getter = svg_radial_gradient_animated_length_getter, data = callback_data_index_value(scope, 2))]
r: (),
#[webapi(accessor_property = "fx", getter = svg_radial_gradient_animated_length_getter, data = callback_data_index_value(scope, 3))]
fx: (),
#[webapi(accessor_property = "fy", getter = svg_radial_gradient_animated_length_getter, data = callback_data_index_value(scope, 4))]
fy: (),
#[webapi(accessor_property = "fr", getter = svg_radial_gradient_animated_length_getter, data = callback_data_index_value(scope, 5))]
fr: (),
}
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGSVGElement, enumerable)]
struct SvgSvgElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "x", getter = svg_svg_animated_length_getter, data = callback_data_index_value(scope, 0))]
x: (),
#[webapi(accessor_property = "y", getter = svg_svg_animated_length_getter, data = callback_data_index_value(scope, 1))]
y: (),
#[webapi(accessor_property = "width", getter = svg_svg_animated_length_getter, data = callback_data_index_value(scope, 2))]
width: (),
#[webapi(accessor_property = "height", getter = svg_svg_animated_length_getter, data = callback_data_index_value(scope, 3))]
height: (),
}
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGClipPathElement, enumerable)]
struct SvgClipPathElementPrototypeAccessorsDeclaration {
@@ -1351,6 +1417,18 @@ struct SvgClipPathElementPrototypeAccessorsDeclaration {
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGFilterElement, enumerable)]
struct SvgFilterElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "x", getter = svg_filter_animated_length_getter, data = callback_data_index_value(scope, 0))]
x: (),
#[webapi(accessor_property = "y", getter = svg_filter_animated_length_getter, data = callback_data_index_value(scope, 1))]
y: (),
#[webapi(accessor_property = "width", getter = svg_filter_animated_length_getter, data = callback_data_index_value(scope, 2))]
width: (),
#[webapi(accessor_property = "height", getter = svg_filter_animated_length_getter, data = callback_data_index_value(scope, 3))]
height: (),
#[webapi(
accessor_property = "filterUnits",
getter = svg_element_animated_enumeration_getter,
@@ -1366,6 +1444,22 @@ struct SvgFilterElementPrototypeAccessorsDeclaration {
primitive_units: (),
}
#[derive(WebApiFunctionTemplate)]
#[webapi(name = "SVGFilterPrimitiveStandardAttributes", enumerable)]
struct SvgFilterPrimitiveStandardAttributesPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "x", getter = svg_filter_primitive_animated_length_getter, data = callback_data_index_value(scope, 0))]
x: (),
#[webapi(accessor_property = "y", getter = svg_filter_primitive_animated_length_getter, data = callback_data_index_value(scope, 1))]
y: (),
#[webapi(accessor_property = "width", getter = svg_filter_primitive_animated_length_getter, data = callback_data_index_value(scope, 2))]
width: (),
#[webapi(accessor_property = "height", getter = svg_filter_primitive_animated_length_getter, data = callback_data_index_value(scope, 3))]
height: (),
}
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGComponentTransferFunctionElement, enumerable)]
struct SvgComponentTransferFunctionElementPrototypeAccessorsDeclaration {
@@ -1512,6 +1606,9 @@ struct SvgFeTurbulenceElementPrototypeAccessorsDeclaration {
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGTextPathElement, enumerable)]
struct SvgTextPathElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "startOffset", getter = svg_text_path_animated_length_getter, data = callback_data_index_value(scope, 0))]
start_offset: (),
#[webapi(
accessor_property = "method",
getter = svg_element_animated_enumeration_getter,
@@ -1537,6 +1634,18 @@ struct SvgTextPathElementPrototypeAccessorsDeclaration {
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGMaskElement, enumerable)]
struct SvgMaskElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "x", getter = svg_mask_animated_length_getter, data = callback_data_index_value(scope, 0))]
x: (),
#[webapi(accessor_property = "y", getter = svg_mask_animated_length_getter, data = callback_data_index_value(scope, 1))]
y: (),
#[webapi(accessor_property = "width", getter = svg_mask_animated_length_getter, data = callback_data_index_value(scope, 2))]
width: (),
#[webapi(accessor_property = "height", getter = svg_mask_animated_length_getter, data = callback_data_index_value(scope, 3))]
height: (),
#[webapi(
accessor_property = "maskUnits",
getter = svg_element_animated_enumeration_getter,
@@ -1638,6 +1747,18 @@ struct SvgGraphicsBoxElementPrototypeAccessorsDeclaration {
#[derive(WebApiFunctionTemplate)]
#[webapi(interface = web_api_interfaces::SVGMarkerElement, enumerable)]
struct SvgMarkerElementPrototypeAccessorsDeclaration {
#[webapi(accessor_property = "refX", getter = svg_marker_animated_length_getter, data = callback_data_index_value(scope, 0))]
ref_x: (),
#[webapi(accessor_property = "refY", getter = svg_marker_animated_length_getter, data = callback_data_index_value(scope, 1))]
ref_y: (),
#[webapi(accessor_property = "markerWidth", getter = svg_marker_animated_length_getter, data = callback_data_index_value(scope, 2))]
marker_width: (),
#[webapi(accessor_property = "markerHeight", getter = svg_marker_animated_length_getter, data = callback_data_index_value(scope, 3))]
marker_height: (),
#[webapi(
accessor_property = "markerUnits",
getter = svg_element_animated_enumeration_getter,
@@ -1971,6 +2092,20 @@ pub(super) fn install_svg_element_accessor_bindings<'s>(
interface_name: &str,
) {
let prototype = template.prototype_template(scope);
if matches!(
interface_name,
"SVGFEBlendElement"
| "SVGFEColorMatrixElement"
| "SVGFECompositeElement"
| "SVGFEConvolveMatrixElement"
| "SVGFEDisplacementMapElement"
| "SVGFEMorphologyElement"
| "SVGFETurbulenceElement"
) {
SvgFilterPrimitiveStandardAttributesPrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
);
}
match interface_name {
"SVGElement" => {
SvgElementPrototypeAccessorsDeclaration::initialize_prototype_template(
@@ -2073,6 +2208,27 @@ pub(super) fn install_svg_element_accessor_bindings<'s>(
scope, prototype,
);
}
"SVGLinearGradientElement" => {
SvgLinearGradientElementPrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
);
SvgUriReferencePrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
);
}
"SVGRadialGradientElement" => {
SvgRadialGradientElementPrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
);
SvgUriReferencePrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
);
}
"SVGSVGElement" => {
SvgSvgElementPrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
);
}
"SVGRectElement" => {
SvgRectElementPrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
@@ -2103,10 +2259,7 @@ pub(super) fn install_svg_element_accessor_bindings<'s>(
scope, prototype,
);
}
"SVGAElement"
| "SVGLinearGradientElement"
| "SVGRadialGradientElement"
| "SVGScriptElement" => {
"SVGAElement" | "SVGScriptElement" => {
SvgUriReferencePrototypeAccessorsDeclaration::initialize_prototype_template(
scope, prototype,
);
@@ -1095,26 +1095,13 @@ pub(super) fn build_svg_matrix<'s>(
.expect("SVGMatrix declaration should bind")
}
pub(super) fn build_svg_animated_length<'s>(
scope: &mut v8::PinScope<'s, '_>,
value: f64,
) -> v8::Local<'s, v8::Object> {
let base_val = build_svg_length(scope, value);
let anim_val = build_svg_length(scope, value);
SvgAnimatedLengthObjectDeclaration::new(base_val, anim_val)
.bind(scope)
.expect("SVGAnimatedLength declaration should bind")
}
pub(super) fn build_svg_animated_length_for_attribute<'s>(
scope: &mut v8::PinScope<'s, '_>,
owner: v8::Local<'s, v8::Object>,
attribute: &str,
initial_value: &str,
) -> v8::Local<'s, v8::Object> {
let parsed = svg_owner_attribute_value(scope, owner, attribute)
.as_deref()
.and_then(parse_svg_length_value)
.unwrap_or_default();
let parsed = svg_animated_length_attribute_value(scope, owner, attribute, initial_value);
let base_val = build_svg_length_from_parsed(scope, parsed);
set_svg_length_owner_attribute(scope, base_val, owner, attribute);
let anim_val = build_svg_length_from_parsed(scope, parsed);
@@ -2427,6 +2414,15 @@ pub(super) fn svg_animated_length_attribute_slot(name: &str) -> &'static str {
"y1" => "__moliSvgAnimatedY1",
"x2" => "__moliSvgAnimatedX2",
"y2" => "__moliSvgAnimatedY2",
"fx" => "__moliSvgAnimatedFx",
"fy" => "__moliSvgAnimatedFy",
"fr" => "__moliSvgAnimatedFr",
"refX" => "__moliSvgAnimatedRefX",
"refY" => "__moliSvgAnimatedRefY",
"markerWidth" => "__moliSvgAnimatedMarkerWidth",
"markerHeight" => "__moliSvgAnimatedMarkerHeight",
"textLength" => SVG_TEXT_CONTENT_TEXT_LENGTH_SLOT,
"startOffset" => "__moliSvgAnimatedStartOffset",
_ => "__moliSvgAnimatedUnknown",
}
}
@@ -2833,11 +2829,9 @@ pub(super) fn sync_svg_animated_length_from_owner_attribute<'s>(
animated: v8::Local<'s, v8::Object>,
owner: v8::Local<'s, v8::Object>,
attribute: &str,
initial_value: &str,
) {
let parsed = svg_owner_attribute_value(scope, owner, attribute)
.as_deref()
.and_then(parse_svg_length_value)
.unwrap_or_default();
let parsed = svg_animated_length_attribute_value(scope, owner, attribute, initial_value);
if let Some(base_val) = get_private_value(scope, animated, SVG_ANIMATED_LENGTH_BASE_VAL_SLOT)
.and_then(|value| v8::Local::<v8::Object>::try_from(value).ok())
{
@@ -2851,6 +2845,19 @@ pub(super) fn sync_svg_animated_length_from_owner_attribute<'s>(
}
}
fn svg_animated_length_attribute_value<'s>(
scope: &mut v8::PinScope<'s, '_>,
owner: v8::Local<'s, v8::Object>,
attribute: &str,
initial_value: &str,
) -> SvgParsedLength {
svg_owner_attribute_value(scope, owner, attribute)
.as_deref()
.and_then(parse_svg_length_value)
.or_else(|| parse_svg_length_value(initial_value))
.unwrap_or_default()
}
pub(super) fn set_svg_animated_string_owner_attribute<'s>(
scope: &mut v8::PinScope<'s, '_>,
animated: v8::Local<'s, v8::Object>,
@@ -4,11 +4,57 @@ use crate::util::serialize_v8_array;
use crate::web_api_interfaces;
use moli_webapi_declare::DataPropertyDescriptorDeclaration;
const SVG_RECT_ANIMATED_LENGTH_ATTRIBUTES: &[&str] = &["x", "y", "width", "height", "rx", "ry"];
const SVG_CIRCLE_ANIMATED_LENGTH_ATTRIBUTES: &[&str] = &["cx", "cy", "r"];
const SVG_ELLIPSE_ANIMATED_LENGTH_ATTRIBUTES: &[&str] = &["cx", "cy", "rx", "ry"];
const SVG_LINE_ANIMATED_LENGTH_ATTRIBUTES: &[&str] = &["x1", "y1", "x2", "y2"];
const SVG_BOX_ANIMATED_LENGTH_ATTRIBUTES: &[&str] = &["x", "y", "width", "height"];
const SVG_RECT_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] = &[
("x", "0"),
("y", "0"),
("width", "0"),
("height", "0"),
("rx", "0"),
("ry", "0"),
];
const SVG_CIRCLE_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] =
&[("cx", "0"), ("cy", "0"), ("r", "0")];
const SVG_ELLIPSE_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] =
&[("cx", "0"), ("cy", "0"), ("rx", "0"), ("ry", "0")];
const SVG_LINE_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] =
&[("x1", "0"), ("y1", "0"), ("x2", "0"), ("y2", "0")];
const SVG_BOX_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] =
&[("x", "0"), ("y", "0"), ("width", "0"), ("height", "0")];
const SVG_FILTER_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] = &[
("x", "-10%"),
("y", "-10%"),
("width", "120%"),
("height", "120%"),
];
const SVG_FILTER_PRIMITIVE_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] = &[
("x", "0%"),
("y", "0%"),
("width", "100%"),
("height", "100%"),
];
const SVG_LINEAR_GRADIENT_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] =
&[("x1", "0%"), ("y1", "0%"), ("x2", "100%"), ("y2", "0%")];
const SVG_RADIAL_GRADIENT_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] = &[
("cx", "50%"),
("cy", "50%"),
("r", "50%"),
("fx", "50%"),
("fy", "50%"),
("fr", "0%"),
];
const SVG_MARKER_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] = &[
("refX", "0"),
("refY", "0"),
("markerWidth", "3"),
("markerHeight", "3"),
];
const SVG_SVG_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] = &[
("x", "0"),
("y", "0"),
("width", "100%"),
("height", "100%"),
];
const SVG_TEXT_PATH_ANIMATED_LENGTH_ATTRIBUTES: &[(&str, &str)] = &[("startOffset", "0")];
const SVG_LENGTH_ACCESSOR_NAMES: &[&str] = &[
"unitType",
"value",
@@ -378,27 +424,168 @@ pub(super) fn svg_box_animated_length_getter<'s>(
);
}
pub(super) fn svg_filter_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_FILTER_ANIMATED_LENGTH_ATTRIBUTES,
"SVGFilterElement animated length attributes",
);
}
pub(super) fn svg_filter_primitive_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_FILTER_PRIMITIVE_ANIMATED_LENGTH_ATTRIBUTES,
"SVGFilterPrimitiveStandardAttributes animated length attributes",
);
}
pub(super) fn svg_pattern_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_BOX_ANIMATED_LENGTH_ATTRIBUTES,
"SVGPatternElement animated length attributes",
);
}
pub(super) fn svg_linear_gradient_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_LINEAR_GRADIENT_ANIMATED_LENGTH_ATTRIBUTES,
"SVGLinearGradientElement animated length attributes",
);
}
pub(super) fn svg_radial_gradient_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_RADIAL_GRADIENT_ANIMATED_LENGTH_ATTRIBUTES,
"SVGRadialGradientElement animated length attributes",
);
}
pub(super) fn svg_marker_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_MARKER_ANIMATED_LENGTH_ATTRIBUTES,
"SVGMarkerElement animated length attributes",
);
}
pub(super) fn svg_mask_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_FILTER_ANIMATED_LENGTH_ATTRIBUTES,
"SVGMaskElement animated length attributes",
);
}
pub(super) fn svg_svg_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_SVG_ANIMATED_LENGTH_ATTRIBUTES,
"SVGSVGElement animated length attributes",
);
}
pub(super) fn svg_text_path_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
svg_element_animated_length_getter(
scope,
&args,
rv,
SVG_TEXT_PATH_ANIMATED_LENGTH_ATTRIBUTES,
"SVGTextPathElement animated length attributes",
);
}
fn svg_element_animated_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: &v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'_, v8::Value>,
attributes: &'static [&'static str],
attributes: &'static [(&'static str, &'static str)],
label: &'static str,
) {
let Some(name) = callback_data_item(scope, args, attributes, label) else {
let Some((name, initial_value)) = callback_data_item(scope, args, attributes, label) else {
rv.set_undefined();
return;
};
svg_animated_length_attribute_getter(scope, args.this(), rv, name, initial_value);
}
fn svg_animated_length_attribute_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
owner: v8::Local<'s, v8::Object>,
mut rv: v8::ReturnValue<'_, v8::Value>,
name: &'static str,
initial_value: &'static str,
) {
let slot = svg_animated_length_attribute_slot(name);
let owner = args.this();
if let Some(value) = get_private_value(scope, owner, slot) {
if let Ok(object) = v8::Local::<v8::Object>::try_from(value) {
sync_svg_animated_length_from_owner_attribute(scope, object, owner, name);
sync_svg_animated_length_from_owner_attribute(
scope,
object,
owner,
name,
initial_value,
);
}
rv.set(value);
return;
}
let value = build_svg_animated_length_for_attribute(scope, owner, name);
let value = build_svg_animated_length_for_attribute(scope, owner, name, initial_value);
set_private_value(scope, owner, slot, value.into());
rv.set(value.into());
}
@@ -662,21 +849,9 @@ pub(super) fn svg_geometry_path_length_getter<'s>(
pub(super) fn svg_text_content_text_length_getter<'s>(
scope: &mut v8::PinScope<'s, '_>,
args: v8::FunctionCallbackArguments<'s>,
mut rv: v8::ReturnValue<'_, v8::Value>,
rv: v8::ReturnValue<'_, v8::Value>,
) {
let holder = args.this();
if let Some(value) = get_private_value(scope, holder, SVG_TEXT_CONTENT_TEXT_LENGTH_SLOT) {
rv.set(value);
return;
}
let value = build_svg_animated_length(scope, 0.0);
set_private_value(
scope,
holder,
SVG_TEXT_CONTENT_TEXT_LENGTH_SLOT,
value.into(),
);
rv.set(value.into());
svg_animated_length_attribute_getter(scope, args.this(), rv, "textLength", "0");
}
pub(super) fn svg_element_animated_enumeration_getter<'s>(
@@ -1649,6 +1649,97 @@ fn svg_owner_svg_element_tracks_the_nearest_svg_fragment_root() {
assert_eq!(result, "ok");
}
#[test]
fn svg_animated_lengths_reflect_initial_and_content_attribute_values() {
let mut vm = new_parsed_test_vm(
"https://svg-animated-length-reflection.test/",
"<!doctype html><html><head></head><body></body></html>",
);
let result = vm
.eval(
r#"
(() => {
const assert = (condition, message) => {
if (!condition) throw new Error(message);
};
const ns = "http://www.w3.org/2000/svg";
const cases = [
["filter", SVGFilterElement, [
["x", "-10%"], ["y", "-10%"],
["width", "120%"], ["height", "120%"],
]],
["feBlend", SVGFEBlendElement, [
["x", "0%"], ["y", "0%"],
["width", "100%"], ["height", "100%"],
]],
["linearGradient", SVGLinearGradientElement, [
["x1", "0%"], ["y1", "0%"], ["x2", "100%"], ["y2", "0%"],
]],
["marker", SVGMarkerElement, [
["refX", "0"], ["refY", "0"],
["markerWidth", "3"], ["markerHeight", "3"],
]],
["mask", SVGMaskElement, [
["x", "-10%"], ["y", "-10%"],
["width", "120%"], ["height", "120%"],
]],
["pattern", SVGPatternElement, [
["x", "0"], ["y", "0"], ["width", "0"], ["height", "0"],
]],
["radialGradient", SVGRadialGradientElement, [
["cx", "50%"], ["cy", "50%"], ["r", "50%"],
["fx", "50%"], ["fy", "50%"], ["fr", "0%"],
]],
["svg", SVGSVGElement, [
["x", "0"], ["y", "0"], ["width", "100%"], ["height", "100%"],
]],
["text", SVGTextContentElement, [["textLength", "0"]]],
["textPath", SVGTextPathElement, [["startOffset", "0"]]],
];
for (const [tag, owner, attributes] of cases) {
const element = document.createElementNS(ns, tag);
for (const [name, initial] of attributes) {
const descriptor = Object.getOwnPropertyDescriptor(owner.prototype, name);
assert(typeof descriptor?.get === "function", `${owner.name}.${name} getter`);
assert(descriptor.set === undefined, `${owner.name}.${name} setter`);
assert(descriptor.enumerable && descriptor.configurable,
`${owner.name}.${name} flags`);
const animated = element[name];
assert(animated instanceof SVGAnimatedLength, `${tag}.${name} interface`);
assert(element[name] === animated, `${tag}.${name} SameObject`);
assert(animated.baseVal.valueAsString === initial,
`${tag}.${name} initial baseVal`);
assert(animated.animVal.valueAsString === initial,
`${tag}.${name} initial animVal`);
element.setAttribute(name, "42");
assert(element[name] === animated, `${tag}.${name} SameObject after set`);
assert(animated.baseVal.valueAsString === "42" &&
animated.animVal.valueAsString === "42", `${tag}.${name} content update`);
element.setAttribute(name, "foobar");
assert(element[name] === animated, `${tag}.${name} SameObject after invalid`);
assert(animated.baseVal.valueAsString === initial &&
animated.animVal.valueAsString === initial, `${tag}.${name} invalid fallback`);
element.removeAttribute(name);
assert(element[name] === animated, `${tag}.${name} SameObject after remove`);
assert(animated.baseVal.valueAsString === initial &&
animated.animVal.valueAsString === initial, `${tag}.${name} removed fallback`);
}
}
return "ok";
})()
"#,
)
.expect("SVG animated length reflection probe should evaluate");
assert_eq!(result, "ok");
}
#[test]
fn svg_historical_interfaces_keep_current_element_constructors_only() {
let mut vm = new_parsed_test_vm(