mirror of
https://github.com/lexmount/moli.git
synced 2026-09-28 08:01:37 +00:00
fix(svg): reflect animated number attributes
This commit is contained in:
@@ -100,12 +100,20 @@ pub fn svg_element_interface_name(local_name: &str) -> &'static str {
|
||||
"feColorMatrix" => "SVGFEColorMatrixElement",
|
||||
"feComposite" => "SVGFECompositeElement",
|
||||
"feConvolveMatrix" => "SVGFEConvolveMatrixElement",
|
||||
"feDiffuseLighting" => "SVGFEDiffuseLightingElement",
|
||||
"feDisplacementMap" => "SVGFEDisplacementMapElement",
|
||||
"feDistantLight" => "SVGFEDistantLightElement",
|
||||
"feDropShadow" => "SVGFEDropShadowElement",
|
||||
"feFuncA" => "SVGFEFuncAElement",
|
||||
"feFuncB" => "SVGFEFuncBElement",
|
||||
"feFuncG" => "SVGFEFuncGElement",
|
||||
"feFuncR" => "SVGFEFuncRElement",
|
||||
"feGaussianBlur" => "SVGFEGaussianBlurElement",
|
||||
"feMorphology" => "SVGFEMorphologyElement",
|
||||
"feOffset" => "SVGFEOffsetElement",
|
||||
"fePointLight" => "SVGFEPointLightElement",
|
||||
"feSpecularLighting" => "SVGFESpecularLightingElement",
|
||||
"feSpotLight" => "SVGFESpotLightElement",
|
||||
"feTurbulence" => "SVGFETurbulenceElement",
|
||||
"filter" => "SVGFilterElement",
|
||||
"foreignObject" => "SVGForeignObjectElement",
|
||||
@@ -123,6 +131,7 @@ pub fn svg_element_interface_name(local_name: &str) -> &'static str {
|
||||
"radialGradient" => "SVGRadialGradientElement",
|
||||
"rect" => "SVGRectElement",
|
||||
"script" => "SVGScriptElement",
|
||||
"stop" => "SVGStopElement",
|
||||
"svg" => "SVGSVGElement",
|
||||
"style" => "SVGStyleElement",
|
||||
"symbol" => "SVGSymbolElement",
|
||||
|
||||
@@ -273,18 +273,47 @@ fn svg_element_interface_name_specializes_standard_elements() {
|
||||
svg_element_interface_name("feConvolveMatrix"),
|
||||
"SVGFEConvolveMatrixElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feDiffuseLighting"),
|
||||
"SVGFEDiffuseLightingElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feDisplacementMap"),
|
||||
"SVGFEDisplacementMapElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feDistantLight"),
|
||||
"SVGFEDistantLightElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feDropShadow"),
|
||||
"SVGFEDropShadowElement"
|
||||
);
|
||||
assert_eq!(svg_element_interface_name("feFuncA"), "SVGFEFuncAElement");
|
||||
assert_eq!(svg_element_interface_name("feFuncB"), "SVGFEFuncBElement");
|
||||
assert_eq!(svg_element_interface_name("feFuncG"), "SVGFEFuncGElement");
|
||||
assert_eq!(svg_element_interface_name("feFuncR"), "SVGFEFuncRElement");
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feGaussianBlur"),
|
||||
"SVGFEGaussianBlurElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feMorphology"),
|
||||
"SVGFEMorphologyElement"
|
||||
);
|
||||
assert_eq!(svg_element_interface_name("feOffset"), "SVGFEOffsetElement");
|
||||
assert_eq!(
|
||||
svg_element_interface_name("fePointLight"),
|
||||
"SVGFEPointLightElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feSpecularLighting"),
|
||||
"SVGFESpecularLightingElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feSpotLight"),
|
||||
"SVGFESpotLightElement"
|
||||
);
|
||||
assert_eq!(
|
||||
svg_element_interface_name("feTurbulence"),
|
||||
"SVGFETurbulenceElement"
|
||||
@@ -314,6 +343,7 @@ fn svg_element_interface_name_specializes_standard_elements() {
|
||||
);
|
||||
assert_eq!(svg_element_interface_name("rect"), "SVGRectElement");
|
||||
assert_eq!(svg_element_interface_name("script"), "SVGScriptElement");
|
||||
assert_eq!(svg_element_interface_name("stop"), "SVGStopElement");
|
||||
assert_eq!(svg_element_interface_name("svg"), "SVGSVGElement");
|
||||
assert_eq!(svg_element_interface_name("symbol"), "SVGSymbolElement");
|
||||
assert_eq!(svg_element_interface_name("text"), "SVGTextElement");
|
||||
|
||||
@@ -161,11 +161,31 @@ const NODE_BRIDGE_DESCRIPTORS: &[BridgeDescriptor] = &[
|
||||
web_api_interfaces::SVGFEConvolveMatrixElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGFEDiffuseLightingElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGFEDisplacementMapElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGFEDistantLightElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(web_api_interfaces::SVGFEDropShadowElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGFEGaussianBlurElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(web_api_interfaces::SVGFEMorphologyElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGFEOffsetElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGFEPointLightElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGFESpecularLightingElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(web_api_interfaces::SVGFESpotLightElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGFETurbulenceElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGForeignObjectElement::DESCRIPTOR,
|
||||
@@ -198,20 +218,12 @@ const NODE_BRIDGE_DESCRIPTORS: &[BridgeDescriptor] = &[
|
||||
svg_gradient_transform: true,
|
||||
},
|
||||
),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGMetadataElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGScriptElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(
|
||||
web_api_interfaces::SVGStyleElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
),
|
||||
descriptor(web_api_interfaces::SVGMaskElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGMarkerElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGMaskElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGMetadataElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGScriptElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGStopElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
descriptor(web_api_interfaces::SVGStyleElement::DESCRIPTOR, ELEMENT_GROUPS),
|
||||
specialized_descriptor(
|
||||
web_api_interfaces::SVGPathElement::DESCRIPTOR,
|
||||
ELEMENT_GROUPS,
|
||||
|
||||
@@ -1301,6 +1301,152 @@ struct SvgMatrixTemplateAccessorsDeclaration {
|
||||
f: (),
|
||||
}
|
||||
|
||||
macro_rules! define_svg_animated_number_accessors {
|
||||
(
|
||||
$declaration:ident,
|
||||
$interface:literal,
|
||||
$(($field:ident, $name:literal, $index:literal)),+ $(,)?
|
||||
) => {
|
||||
#[derive(WebApiFunctionTemplate)]
|
||||
#[webapi(name = $interface, enumerable)]
|
||||
struct $declaration {
|
||||
$(
|
||||
#[webapi(
|
||||
accessor_property = $name,
|
||||
getter = svg_element_animated_number_getter,
|
||||
data = callback_data_index_value(scope, $index)
|
||||
)]
|
||||
$field: (),
|
||||
)+
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgComponentTransferFunctionAnimatedNumberAccessorsDeclaration,
|
||||
"SVGComponentTransferFunctionElement",
|
||||
(slope, "slope", 0),
|
||||
(intercept, "intercept", 1),
|
||||
(amplitude, "amplitude", 2),
|
||||
(exponent, "exponent", 3),
|
||||
(offset, "offset", 4),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeCompositeAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFECompositeElement",
|
||||
(k1, "k1", 5),
|
||||
(k2, "k2", 6),
|
||||
(k3, "k3", 7),
|
||||
(k4, "k4", 8),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeConvolveMatrixAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEConvolveMatrixElement",
|
||||
(divisor, "divisor", 9),
|
||||
(bias, "bias", 10),
|
||||
(kernel_unit_length_x, "kernelUnitLengthX", 11),
|
||||
(kernel_unit_length_y, "kernelUnitLengthY", 12),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeDiffuseLightingAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEDiffuseLightingElement",
|
||||
(surface_scale, "surfaceScale", 13),
|
||||
(diffuse_constant, "diffuseConstant", 14),
|
||||
(kernel_unit_length_x, "kernelUnitLengthX", 15),
|
||||
(kernel_unit_length_y, "kernelUnitLengthY", 16),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeDisplacementMapAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEDisplacementMapElement",
|
||||
(scale, "scale", 17),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeDistantLightAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEDistantLightElement",
|
||||
(azimuth, "azimuth", 18),
|
||||
(elevation, "elevation", 19),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeDropShadowAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEDropShadowElement",
|
||||
(dx, "dx", 20),
|
||||
(dy, "dy", 21),
|
||||
(std_deviation_x, "stdDeviationX", 22),
|
||||
(std_deviation_y, "stdDeviationY", 23),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeGaussianBlurAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEGaussianBlurElement",
|
||||
(std_deviation_x, "stdDeviationX", 24),
|
||||
(std_deviation_y, "stdDeviationY", 25),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeMorphologyAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEMorphologyElement",
|
||||
(radius_x, "radiusX", 26),
|
||||
(radius_y, "radiusY", 27),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeOffsetAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEOffsetElement",
|
||||
(dx, "dx", 28),
|
||||
(dy, "dy", 29),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFePointLightAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFEPointLightElement",
|
||||
(x, "x", 30),
|
||||
(y, "y", 31),
|
||||
(z, "z", 32),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeSpecularLightingAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFESpecularLightingElement",
|
||||
(surface_scale, "surfaceScale", 33),
|
||||
(specular_constant, "specularConstant", 34),
|
||||
(specular_exponent, "specularExponent", 35),
|
||||
(kernel_unit_length_x, "kernelUnitLengthX", 36),
|
||||
(kernel_unit_length_y, "kernelUnitLengthY", 37),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeSpotLightAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFESpotLightElement",
|
||||
(x, "x", 38),
|
||||
(y, "y", 39),
|
||||
(z, "z", 40),
|
||||
(points_at_x, "pointsAtX", 41),
|
||||
(points_at_y, "pointsAtY", 42),
|
||||
(points_at_z, "pointsAtZ", 43),
|
||||
(specular_exponent, "specularExponent", 44),
|
||||
(limiting_cone_angle, "limitingConeAngle", 45),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgFeTurbulenceAnimatedNumberAccessorsDeclaration,
|
||||
"SVGFETurbulenceElement",
|
||||
(base_frequency_x, "baseFrequencyX", 46),
|
||||
(base_frequency_y, "baseFrequencyY", 47),
|
||||
(seed, "seed", 48),
|
||||
);
|
||||
|
||||
define_svg_animated_number_accessors!(
|
||||
SvgStopAnimatedNumberAccessorsDeclaration,
|
||||
"SVGStopElement",
|
||||
(offset, "offset", 49),
|
||||
);
|
||||
|
||||
#[derive(WebApiFunctionTemplate)]
|
||||
#[webapi(interface = web_api_interfaces::SVGElement, enumerable, receiver)]
|
||||
struct SvgElementPrototypeAccessorsDeclaration {
|
||||
@@ -2220,12 +2366,73 @@ pub(super) fn install_svg_svg_element_bindings(
|
||||
SvgSvgElementTemplateMethodsDeclaration::initialize_prototype_template(scope, proto);
|
||||
}
|
||||
|
||||
fn install_svg_animated_number_element_bindings<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_, ()>,
|
||||
prototype: v8::Local<'s, v8::ObjectTemplate>,
|
||||
interface_name: &str,
|
||||
) {
|
||||
macro_rules! install_accessors {
|
||||
($declaration:ty) => {
|
||||
<$declaration>::initialize_prototype_template(scope, prototype)
|
||||
};
|
||||
}
|
||||
match interface_name {
|
||||
"SVGComponentTransferFunctionElement" => {
|
||||
install_accessors!(SvgComponentTransferFunctionAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFECompositeElement" => {
|
||||
install_accessors!(SvgFeCompositeAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEConvolveMatrixElement" => {
|
||||
install_accessors!(SvgFeConvolveMatrixAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEDiffuseLightingElement" => {
|
||||
install_accessors!(SvgFeDiffuseLightingAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEDisplacementMapElement" => {
|
||||
install_accessors!(SvgFeDisplacementMapAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEDistantLightElement" => {
|
||||
install_accessors!(SvgFeDistantLightAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEDropShadowElement" => {
|
||||
install_accessors!(SvgFeDropShadowAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEGaussianBlurElement" => {
|
||||
install_accessors!(SvgFeGaussianBlurAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEMorphologyElement" => {
|
||||
install_accessors!(SvgFeMorphologyAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEOffsetElement" => {
|
||||
install_accessors!(SvgFeOffsetAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFEPointLightElement" => {
|
||||
install_accessors!(SvgFePointLightAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFESpecularLightingElement" => {
|
||||
install_accessors!(SvgFeSpecularLightingAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFESpotLightElement" => {
|
||||
install_accessors!(SvgFeSpotLightAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGFETurbulenceElement" => {
|
||||
install_accessors!(SvgFeTurbulenceAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
"SVGStopElement" => {
|
||||
install_accessors!(SvgStopAnimatedNumberAccessorsDeclaration);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn install_svg_element_accessor_bindings<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_, ()>,
|
||||
template: v8::Local<'s, v8::FunctionTemplate>,
|
||||
interface_name: &str,
|
||||
) {
|
||||
let prototype = template.prototype_template(scope);
|
||||
install_svg_animated_number_element_bindings(scope, prototype, interface_name);
|
||||
if matches!(
|
||||
interface_name,
|
||||
"SVGSVGElement"
|
||||
@@ -2244,8 +2451,13 @@ pub(super) fn install_svg_element_accessor_bindings<'s>(
|
||||
| "SVGFEColorMatrixElement"
|
||||
| "SVGFECompositeElement"
|
||||
| "SVGFEConvolveMatrixElement"
|
||||
| "SVGFEDiffuseLightingElement"
|
||||
| "SVGFEDisplacementMapElement"
|
||||
| "SVGFEDropShadowElement"
|
||||
| "SVGFEGaussianBlurElement"
|
||||
| "SVGFEMorphologyElement"
|
||||
| "SVGFEOffsetElement"
|
||||
| "SVGFESpecularLightingElement"
|
||||
| "SVGFETurbulenceElement"
|
||||
) {
|
||||
SvgFilterPrimitiveStandardAttributesPrototypeAccessorsDeclaration::initialize_prototype_template(
|
||||
|
||||
@@ -572,6 +572,38 @@ pub(super) fn build_svg_animated_number_for_attribute<'s>(
|
||||
object
|
||||
}
|
||||
|
||||
pub(super) fn build_svg_animated_number_for_property<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
owner: v8::Local<'s, v8::Object>,
|
||||
property: SvgAnimatedNumberProperty,
|
||||
) -> v8::Local<'s, v8::Object> {
|
||||
let object = build_svg_animated_number(scope, property.initial_value);
|
||||
set_svg_animated_number_owner_attribute(scope, object, owner, property.attribute);
|
||||
let index = u32::try_from(property.index).expect("SVG number property index exceeds u32");
|
||||
let index = v8::Integer::new_from_unsigned(scope, index);
|
||||
set_private_value(
|
||||
scope,
|
||||
object,
|
||||
SVG_ANIMATED_NUMBER_PROPERTY_INDEX_SLOT,
|
||||
index.into(),
|
||||
);
|
||||
sync_svg_animated_number_from_property(scope, object);
|
||||
object
|
||||
}
|
||||
|
||||
pub(super) fn svg_animated_number_property_for_object<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
) -> Option<SvgAnimatedNumberProperty> {
|
||||
let index = get_private_value(scope, animated, SVG_ANIMATED_NUMBER_PROPERTY_INDEX_SLOT)?
|
||||
.uint32_value(scope)?;
|
||||
SVG_ANIMATED_NUMBER_PROPERTIES.get(index as usize).copied()
|
||||
}
|
||||
|
||||
pub(super) fn svg_animated_number_cache_slot(property: SvgAnimatedNumberProperty) -> String {
|
||||
format!("__moliSvgAnimatedNumberProperty{}", property.index)
|
||||
}
|
||||
|
||||
pub(super) fn build_svg_animated_integer<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
value: i32,
|
||||
@@ -3264,6 +3296,57 @@ pub(super) fn sync_svg_animated_number_from_owner_attribute<'s>(
|
||||
.as_deref()
|
||||
.and_then(parse_svg_number_value)
|
||||
.unwrap_or(0.0);
|
||||
set_svg_animated_number_values(scope, animated, value);
|
||||
}
|
||||
|
||||
pub(super) fn sync_svg_animated_number_from_stored_owner_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
) {
|
||||
if svg_animated_number_property_for_object(scope, animated).is_some() {
|
||||
sync_svg_animated_number_from_property(scope, animated);
|
||||
return;
|
||||
}
|
||||
let Some(owner) = get_private_value(scope, animated, SVG_ANIMATED_NUMBER_OWNER_ELEMENT_SLOT)
|
||||
.and_then(|value| v8::Local::<v8::Object>::try_from(value).ok())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(attribute) =
|
||||
get_private_value(scope, animated, SVG_ANIMATED_NUMBER_OWNER_ATTRIBUTE_SLOT)
|
||||
.and_then(|value| value.to_string(scope))
|
||||
.map(|value| value.to_rust_string_lossy(scope))
|
||||
.filter(|value| !value.is_empty())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
sync_svg_animated_number_from_owner_attribute(scope, animated, owner, &attribute);
|
||||
}
|
||||
|
||||
pub(super) fn sync_svg_animated_number_from_property<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
) {
|
||||
let Some(property) = svg_animated_number_property_for_object(scope, animated) else {
|
||||
return;
|
||||
};
|
||||
let Some(owner) = get_private_value(scope, animated, SVG_ANIMATED_NUMBER_OWNER_ELEMENT_SLOT)
|
||||
.and_then(|value| v8::Local::<v8::Object>::try_from(value).ok())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let value = svg_owner_attribute_value(scope, owner, property.attribute)
|
||||
.as_deref()
|
||||
.and_then(|raw| parse_svg_animated_number(property, raw))
|
||||
.unwrap_or(property.initial_value);
|
||||
set_svg_animated_number_values(scope, animated, value);
|
||||
}
|
||||
|
||||
pub(super) fn set_svg_animated_number_values(
|
||||
scope: &mut v8::PinScope<'_, '_>,
|
||||
animated: v8::Local<'_, v8::Object>,
|
||||
value: f64,
|
||||
) {
|
||||
let value = v8::Number::new(scope, value);
|
||||
set_private_value(
|
||||
scope,
|
||||
@@ -3283,6 +3366,10 @@ pub(super) fn reflect_svg_animated_number_to_owner_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
) {
|
||||
if svg_animated_number_property_for_object(scope, animated).is_some() {
|
||||
reflect_svg_animated_number_property_to_owner_attribute(scope, animated);
|
||||
return;
|
||||
}
|
||||
let Some(owner) = get_private_value(scope, animated, SVG_ANIMATED_NUMBER_OWNER_ELEMENT_SLOT)
|
||||
.and_then(|value| v8::Local::<v8::Object>::try_from(value).ok())
|
||||
else {
|
||||
@@ -3307,6 +3394,85 @@ pub(super) fn reflect_svg_animated_number_to_owner_attribute<'s>(
|
||||
let _ = runtime.set_attribute(scope, runtime_ptr, handle, &attribute, &value);
|
||||
}
|
||||
|
||||
pub(super) fn reflect_svg_animated_number_property_to_owner_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
animated: v8::Local<'s, v8::Object>,
|
||||
) {
|
||||
let Some(property) = svg_animated_number_property_for_object(scope, animated) else {
|
||||
return;
|
||||
};
|
||||
let Some(owner) = get_private_value(scope, animated, SVG_ANIMATED_NUMBER_OWNER_ELEMENT_SLOT)
|
||||
.and_then(|value| v8::Local::<v8::Object>::try_from(value).ok())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let value = svg_number_slot(scope, animated, SVG_ANIMATED_NUMBER_BASE_VAL_SLOT)
|
||||
.unwrap_or(property.initial_value);
|
||||
let serialized = match property.component {
|
||||
SvgAnimatedNumberComponent::Scalar | SvgAnimatedNumberComponent::NumberOrPercentage => {
|
||||
svg_geometry::serialize_number(value)
|
||||
}
|
||||
SvgAnimatedNumberComponent::PairFirst | SvgAnimatedNumberComponent::PairSecondOrFirst => {
|
||||
let (mut first, mut second) =
|
||||
svg_owner_attribute_value(scope, owner, property.attribute)
|
||||
.as_deref()
|
||||
.and_then(parse_svg_number_pair)
|
||||
.unwrap_or((property.initial_value, property.initial_value));
|
||||
match property.component {
|
||||
SvgAnimatedNumberComponent::PairFirst => first = value,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst => second = value,
|
||||
SvgAnimatedNumberComponent::Scalar
|
||||
| SvgAnimatedNumberComponent::NumberOrPercentage => unreachable!(),
|
||||
}
|
||||
format!(
|
||||
"{} {}",
|
||||
svg_geometry::serialize_number(first),
|
||||
svg_geometry::serialize_number(second)
|
||||
)
|
||||
}
|
||||
};
|
||||
let Ok((runtime_ptr, handle)) =
|
||||
crate::native_bridge::node_runtime_and_handle_from_object(scope, owner)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let runtime = unsafe { &mut *runtime_ptr };
|
||||
let _ = runtime.set_attribute(scope, runtime_ptr, handle, property.attribute, &serialized);
|
||||
}
|
||||
|
||||
pub(super) fn parse_svg_animated_number(
|
||||
property: SvgAnimatedNumberProperty,
|
||||
value: &str,
|
||||
) -> Option<f64> {
|
||||
match property.component {
|
||||
SvgAnimatedNumberComponent::Scalar => parse_svg_number_value(value),
|
||||
SvgAnimatedNumberComponent::PairFirst => {
|
||||
parse_svg_number_pair(value).map(|(first, _)| first)
|
||||
}
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst => {
|
||||
parse_svg_number_pair(value).map(|(_, second)| second)
|
||||
}
|
||||
SvgAnimatedNumberComponent::NumberOrPercentage => parse_svg_number_or_percentage(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_svg_number_pair(value: &str) -> Option<(f64, f64)> {
|
||||
let values = svg_geometry::parse_number_list(value)?;
|
||||
match values.as_slice() {
|
||||
[first] => Some((*first, *first)),
|
||||
[first, second] => Some((*first, *second)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_svg_number_or_percentage(value: &str) -> Option<f64> {
|
||||
let value = value.trim();
|
||||
match value.strip_suffix('%') {
|
||||
Some(percentage) => parse_svg_number_value(percentage).map(|value| value / 100.0),
|
||||
None => parse_svg_number_value(value),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_svg_length_owner_attribute<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
length: v8::Local<'s, v8::Object>,
|
||||
|
||||
@@ -837,13 +837,22 @@ fn require_svg_graphics_element_receiver<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
receiver: v8::Local<'s, v8::Object>,
|
||||
member: &str,
|
||||
) -> bool {
|
||||
require_svg_interface_receiver(scope, receiver, "SVGGraphicsElement", member)
|
||||
}
|
||||
|
||||
fn require_svg_interface_receiver<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
receiver: v8::Local<'s, v8::Object>,
|
||||
interface: &str,
|
||||
member: &str,
|
||||
) -> bool {
|
||||
let Ok((runtime_ptr, handle)) =
|
||||
crate::native_bridge::node_runtime_and_handle_from_object_or_detached(scope, receiver)
|
||||
else {
|
||||
webidl::throw_type_error(
|
||||
scope,
|
||||
&format!("SVGGraphicsElement.{member} called on incompatible receiver."),
|
||||
&format!("{interface}.{member} called on incompatible receiver."),
|
||||
);
|
||||
return false;
|
||||
};
|
||||
@@ -856,12 +865,12 @@ fn require_svg_graphics_element_receiver<'s>(
|
||||
else {
|
||||
webidl::throw_type_error(
|
||||
scope,
|
||||
&format!("SVGGraphicsElement.{member} called on incompatible receiver."),
|
||||
&format!("{interface}.{member} called on incompatible receiver."),
|
||||
);
|
||||
return false;
|
||||
};
|
||||
loop {
|
||||
if interface_name == "SVGGraphicsElement" {
|
||||
if interface_name == interface {
|
||||
return true;
|
||||
}
|
||||
let Some(parent) =
|
||||
@@ -874,7 +883,7 @@ fn require_svg_graphics_element_receiver<'s>(
|
||||
}
|
||||
webidl::throw_type_error(
|
||||
scope,
|
||||
&format!("SVGGraphicsElement.{member} called on incompatible receiver."),
|
||||
&format!("{interface}.{member} called on incompatible receiver."),
|
||||
);
|
||||
false
|
||||
}
|
||||
@@ -980,6 +989,37 @@ pub(super) fn svg_element_animated_enumeration_getter<'s>(
|
||||
rv.set(value.into());
|
||||
}
|
||||
|
||||
pub(super) fn svg_element_animated_number_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
mut rv: v8::ReturnValue<'_, v8::Value>,
|
||||
) {
|
||||
let Some(property) = callback_data_item(
|
||||
scope,
|
||||
&args,
|
||||
SVG_ANIMATED_NUMBER_PROPERTIES,
|
||||
"SVG animated number properties",
|
||||
) else {
|
||||
rv.set_undefined();
|
||||
return;
|
||||
};
|
||||
let holder = args.this();
|
||||
if !require_svg_interface_receiver(scope, holder, property.interface, property.name) {
|
||||
return;
|
||||
}
|
||||
let cache_slot = svg_animated_number_cache_slot(property);
|
||||
if let Some(value) = get_private_value(scope, holder, &cache_slot) {
|
||||
if let Ok(animated) = v8::Local::<v8::Object>::try_from(value) {
|
||||
sync_svg_animated_number_from_property(scope, animated);
|
||||
}
|
||||
rv.set(value);
|
||||
return;
|
||||
}
|
||||
let value = build_svg_animated_number_for_property(scope, holder, property);
|
||||
set_private_value(scope, holder, &cache_slot, value.into());
|
||||
rv.set(value.into());
|
||||
}
|
||||
|
||||
pub(super) fn svg_element_animated_integer_getter<'s>(
|
||||
scope: &mut v8::PinScope<'s, '_>,
|
||||
args: v8::FunctionCallbackArguments<'s>,
|
||||
@@ -1785,7 +1825,11 @@ pub(super) fn svg_animated_number_getter<'s>(
|
||||
return;
|
||||
}
|
||||
};
|
||||
let value = svg_number_slot(scope, args.this(), slot).unwrap_or(0.0);
|
||||
sync_svg_animated_number_from_stored_owner_attribute(scope, args.this());
|
||||
let initial_value = svg_animated_number_property_for_object(scope, args.this())
|
||||
.map(|property| property.initial_value)
|
||||
.unwrap_or_default();
|
||||
let value = svg_number_slot(scope, args.this(), slot).unwrap_or(initial_value);
|
||||
rv.set(v8::Number::new(scope, value).into());
|
||||
}
|
||||
|
||||
@@ -1974,7 +2018,7 @@ pub(super) fn svg_animated_number_setter<'s>(
|
||||
{
|
||||
return;
|
||||
}
|
||||
let value = match webidl::convert::<webidl::UnrestrictedDouble>(
|
||||
let value = match webidl::convert::<webidl::Double>(
|
||||
scope,
|
||||
args.get(0),
|
||||
webidl::Context::member("SVGAnimatedNumber", "baseVal"),
|
||||
@@ -1985,18 +2029,7 @@ pub(super) fn svg_animated_number_setter<'s>(
|
||||
return;
|
||||
}
|
||||
};
|
||||
set_private_value(
|
||||
scope,
|
||||
args.this(),
|
||||
SVG_ANIMATED_NUMBER_BASE_VAL_SLOT,
|
||||
v8::Number::new(scope, value).into(),
|
||||
);
|
||||
set_private_value(
|
||||
scope,
|
||||
args.this(),
|
||||
SVG_ANIMATED_NUMBER_ANIM_VAL_SLOT,
|
||||
v8::Number::new(scope, value).into(),
|
||||
);
|
||||
set_svg_animated_number_values(scope, args.this(), value);
|
||||
reflect_svg_animated_number_to_owner_attribute(scope, args.this());
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ const SVG_LENGTH_VALUE_AS_STRING_SLOT: &str = "__moliSvgLengthValueAsString";
|
||||
const SVG_NUMBER_VALUE_SLOT: &str = "__moliSvgNumberValue";
|
||||
const SVG_ANIMATED_NUMBER_OWNER_ELEMENT_SLOT: &str = "__moliSvgAnimatedNumberOwnerElement";
|
||||
const SVG_ANIMATED_NUMBER_OWNER_ATTRIBUTE_SLOT: &str = "__moliSvgAnimatedNumberOwnerAttribute";
|
||||
const SVG_ANIMATED_NUMBER_PROPERTY_INDEX_SLOT: &str = "__moliSvgAnimatedNumberPropertyIndex";
|
||||
const SVG_ANIMATED_NUMBER_BASE_VAL_SLOT: &str = "__moliSvgAnimatedNumberBaseVal";
|
||||
const SVG_ANIMATED_NUMBER_ANIM_VAL_SLOT: &str = "__moliSvgAnimatedNumberAnimVal";
|
||||
const SVG_ANIMATED_INTEGER_BASE_VAL_SLOT: &str = "__moliSvgAnimatedIntegerBaseVal";
|
||||
@@ -198,6 +199,24 @@ struct SvgAnimatedIntegerProperty {
|
||||
component: SvgAnimatedIntegerComponent,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum SvgAnimatedNumberComponent {
|
||||
Scalar,
|
||||
PairFirst,
|
||||
PairSecondOrFirst,
|
||||
NumberOrPercentage,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct SvgAnimatedNumberProperty {
|
||||
index: usize,
|
||||
interface: &'static str,
|
||||
name: &'static str,
|
||||
attribute: &'static str,
|
||||
initial_value: f64,
|
||||
component: SvgAnimatedNumberComponent,
|
||||
}
|
||||
|
||||
#[derive(webidl::WebIdlArgs)]
|
||||
#[webidl(prefix = "SVG list item")]
|
||||
struct SvgListItemArgs<'s> {
|
||||
@@ -766,6 +785,427 @@ const SVG_ANIMATED_ENUMERATION_PROPERTIES: &[SvgAnimatedEnumerationProperty] = &
|
||||
},
|
||||
];
|
||||
|
||||
const fn svg_animated_number_property(
|
||||
index: usize,
|
||||
interface: &'static str,
|
||||
name: &'static str,
|
||||
attribute: &'static str,
|
||||
initial_value: f64,
|
||||
component: SvgAnimatedNumberComponent,
|
||||
) -> SvgAnimatedNumberProperty {
|
||||
SvgAnimatedNumberProperty {
|
||||
index,
|
||||
interface,
|
||||
name,
|
||||
attribute,
|
||||
initial_value,
|
||||
component,
|
||||
}
|
||||
}
|
||||
|
||||
const SVG_ANIMATED_NUMBER_PROPERTIES: &[SvgAnimatedNumberProperty] = &[
|
||||
svg_animated_number_property(
|
||||
0,
|
||||
"SVGComponentTransferFunctionElement",
|
||||
"slope",
|
||||
"slope",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
1,
|
||||
"SVGComponentTransferFunctionElement",
|
||||
"intercept",
|
||||
"intercept",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
2,
|
||||
"SVGComponentTransferFunctionElement",
|
||||
"amplitude",
|
||||
"amplitude",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
3,
|
||||
"SVGComponentTransferFunctionElement",
|
||||
"exponent",
|
||||
"exponent",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
4,
|
||||
"SVGComponentTransferFunctionElement",
|
||||
"offset",
|
||||
"offset",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
5,
|
||||
"SVGFECompositeElement",
|
||||
"k1",
|
||||
"k1",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
6,
|
||||
"SVGFECompositeElement",
|
||||
"k2",
|
||||
"k2",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
7,
|
||||
"SVGFECompositeElement",
|
||||
"k3",
|
||||
"k3",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
8,
|
||||
"SVGFECompositeElement",
|
||||
"k4",
|
||||
"k4",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
9,
|
||||
"SVGFEConvolveMatrixElement",
|
||||
"divisor",
|
||||
"divisor",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
10,
|
||||
"SVGFEConvolveMatrixElement",
|
||||
"bias",
|
||||
"bias",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
11,
|
||||
"SVGFEConvolveMatrixElement",
|
||||
"kernelUnitLengthX",
|
||||
"kernelUnitLength",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
12,
|
||||
"SVGFEConvolveMatrixElement",
|
||||
"kernelUnitLengthY",
|
||||
"kernelUnitLength",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
13,
|
||||
"SVGFEDiffuseLightingElement",
|
||||
"surfaceScale",
|
||||
"surfaceScale",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
14,
|
||||
"SVGFEDiffuseLightingElement",
|
||||
"diffuseConstant",
|
||||
"diffuseConstant",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
15,
|
||||
"SVGFEDiffuseLightingElement",
|
||||
"kernelUnitLengthX",
|
||||
"kernelUnitLength",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
16,
|
||||
"SVGFEDiffuseLightingElement",
|
||||
"kernelUnitLengthY",
|
||||
"kernelUnitLength",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
17,
|
||||
"SVGFEDisplacementMapElement",
|
||||
"scale",
|
||||
"scale",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
18,
|
||||
"SVGFEDistantLightElement",
|
||||
"azimuth",
|
||||
"azimuth",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
19,
|
||||
"SVGFEDistantLightElement",
|
||||
"elevation",
|
||||
"elevation",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
20,
|
||||
"SVGFEDropShadowElement",
|
||||
"dx",
|
||||
"dx",
|
||||
2.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
21,
|
||||
"SVGFEDropShadowElement",
|
||||
"dy",
|
||||
"dy",
|
||||
2.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
22,
|
||||
"SVGFEDropShadowElement",
|
||||
"stdDeviationX",
|
||||
"stdDeviation",
|
||||
2.0,
|
||||
SvgAnimatedNumberComponent::PairFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
23,
|
||||
"SVGFEDropShadowElement",
|
||||
"stdDeviationY",
|
||||
"stdDeviation",
|
||||
2.0,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
24,
|
||||
"SVGFEGaussianBlurElement",
|
||||
"stdDeviationX",
|
||||
"stdDeviation",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
25,
|
||||
"SVGFEGaussianBlurElement",
|
||||
"stdDeviationY",
|
||||
"stdDeviation",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
26,
|
||||
"SVGFEMorphologyElement",
|
||||
"radiusX",
|
||||
"radius",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
27,
|
||||
"SVGFEMorphologyElement",
|
||||
"radiusY",
|
||||
"radius",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
28,
|
||||
"SVGFEOffsetElement",
|
||||
"dx",
|
||||
"dx",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
29,
|
||||
"SVGFEOffsetElement",
|
||||
"dy",
|
||||
"dy",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
30,
|
||||
"SVGFEPointLightElement",
|
||||
"x",
|
||||
"x",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
31,
|
||||
"SVGFEPointLightElement",
|
||||
"y",
|
||||
"y",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
32,
|
||||
"SVGFEPointLightElement",
|
||||
"z",
|
||||
"z",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
33,
|
||||
"SVGFESpecularLightingElement",
|
||||
"surfaceScale",
|
||||
"surfaceScale",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
34,
|
||||
"SVGFESpecularLightingElement",
|
||||
"specularConstant",
|
||||
"specularConstant",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
35,
|
||||
"SVGFESpecularLightingElement",
|
||||
"specularExponent",
|
||||
"specularExponent",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
36,
|
||||
"SVGFESpecularLightingElement",
|
||||
"kernelUnitLengthX",
|
||||
"kernelUnitLength",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
37,
|
||||
"SVGFESpecularLightingElement",
|
||||
"kernelUnitLengthY",
|
||||
"kernelUnitLength",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
38,
|
||||
"SVGFESpotLightElement",
|
||||
"x",
|
||||
"x",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
39,
|
||||
"SVGFESpotLightElement",
|
||||
"y",
|
||||
"y",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
40,
|
||||
"SVGFESpotLightElement",
|
||||
"z",
|
||||
"z",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
41,
|
||||
"SVGFESpotLightElement",
|
||||
"pointsAtX",
|
||||
"pointsAtX",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
42,
|
||||
"SVGFESpotLightElement",
|
||||
"pointsAtY",
|
||||
"pointsAtY",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
43,
|
||||
"SVGFESpotLightElement",
|
||||
"pointsAtZ",
|
||||
"pointsAtZ",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
44,
|
||||
"SVGFESpotLightElement",
|
||||
"specularExponent",
|
||||
"specularExponent",
|
||||
1.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
45,
|
||||
"SVGFESpotLightElement",
|
||||
"limitingConeAngle",
|
||||
"limitingConeAngle",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
46,
|
||||
"SVGFETurbulenceElement",
|
||||
"baseFrequencyX",
|
||||
"baseFrequency",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
47,
|
||||
"SVGFETurbulenceElement",
|
||||
"baseFrequencyY",
|
||||
"baseFrequency",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::PairSecondOrFirst,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
48,
|
||||
"SVGFETurbulenceElement",
|
||||
"seed",
|
||||
"seed",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::Scalar,
|
||||
),
|
||||
svg_animated_number_property(
|
||||
49,
|
||||
"SVGStopElement",
|
||||
"offset",
|
||||
"offset",
|
||||
0.0,
|
||||
SvgAnimatedNumberComponent::NumberOrPercentage,
|
||||
),
|
||||
];
|
||||
|
||||
const SVG_ANIMATED_INTEGER_PROPERTIES: &[SvgAnimatedIntegerProperty] = &[
|
||||
SvgAnimatedIntegerProperty {
|
||||
index: 0,
|
||||
|
||||
@@ -1144,6 +1144,211 @@ fn svg_animated_integers_reflect_filter_content_attributes() {
|
||||
assert_eq!(result, "ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn svg_animated_numbers_reflect_filter_and_stop_content_attributes() {
|
||||
let mut vm = new_parsed_test_vm(
|
||||
"https://svg-animated-number.test/",
|
||||
"<!doctype html><html><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 = [
|
||||
["feFuncA", SVGFEFuncAElement, SVGComponentTransferFunctionElement, [
|
||||
["slope", "slope", 1], ["intercept", "intercept", 0],
|
||||
["amplitude", "amplitude", 1], ["exponent", "exponent", 1],
|
||||
["offset", "offset", 0],
|
||||
]],
|
||||
["feComposite", SVGFECompositeElement, SVGFECompositeElement, [
|
||||
["k1", "k1", 0], ["k2", "k2", 0],
|
||||
["k3", "k3", 0], ["k4", "k4", 0],
|
||||
]],
|
||||
["feConvolveMatrix", SVGFEConvolveMatrixElement,
|
||||
SVGFEConvolveMatrixElement, [
|
||||
["divisor", "divisor", 1], ["bias", "bias", 0],
|
||||
["kernelUnitLengthX", "kernelUnitLength", 0],
|
||||
["kernelUnitLengthY", "kernelUnitLength", 0],
|
||||
]],
|
||||
["feDiffuseLighting", SVGFEDiffuseLightingElement,
|
||||
SVGFEDiffuseLightingElement, [
|
||||
["surfaceScale", "surfaceScale", 1],
|
||||
["diffuseConstant", "diffuseConstant", 1],
|
||||
["kernelUnitLengthX", "kernelUnitLength", 0],
|
||||
["kernelUnitLengthY", "kernelUnitLength", 0],
|
||||
]],
|
||||
["feDisplacementMap", SVGFEDisplacementMapElement,
|
||||
SVGFEDisplacementMapElement, [["scale", "scale", 0]]],
|
||||
["feDistantLight", SVGFEDistantLightElement,
|
||||
SVGFEDistantLightElement, [
|
||||
["azimuth", "azimuth", 0], ["elevation", "elevation", 0],
|
||||
]],
|
||||
["feDropShadow", SVGFEDropShadowElement, SVGFEDropShadowElement, [
|
||||
["dx", "dx", 2], ["dy", "dy", 2],
|
||||
["stdDeviationX", "stdDeviation", 2],
|
||||
["stdDeviationY", "stdDeviation", 2],
|
||||
]],
|
||||
["feGaussianBlur", SVGFEGaussianBlurElement,
|
||||
SVGFEGaussianBlurElement, [
|
||||
["stdDeviationX", "stdDeviation", 0],
|
||||
["stdDeviationY", "stdDeviation", 0],
|
||||
]],
|
||||
["feMorphology", SVGFEMorphologyElement, SVGFEMorphologyElement, [
|
||||
["radiusX", "radius", 0], ["radiusY", "radius", 0],
|
||||
]],
|
||||
["feOffset", SVGFEOffsetElement, SVGFEOffsetElement, [
|
||||
["dx", "dx", 0], ["dy", "dy", 0],
|
||||
]],
|
||||
["fePointLight", SVGFEPointLightElement, SVGFEPointLightElement, [
|
||||
["x", "x", 0], ["y", "y", 0], ["z", "z", 0],
|
||||
]],
|
||||
["feSpecularLighting", SVGFESpecularLightingElement,
|
||||
SVGFESpecularLightingElement, [
|
||||
["surfaceScale", "surfaceScale", 1],
|
||||
["specularConstant", "specularConstant", 1],
|
||||
["specularExponent", "specularExponent", 1],
|
||||
["kernelUnitLengthX", "kernelUnitLength", 0],
|
||||
["kernelUnitLengthY", "kernelUnitLength", 0],
|
||||
]],
|
||||
["feSpotLight", SVGFESpotLightElement, SVGFESpotLightElement, [
|
||||
["x", "x", 0], ["y", "y", 0], ["z", "z", 0],
|
||||
["pointsAtX", "pointsAtX", 0], ["pointsAtY", "pointsAtY", 0],
|
||||
["pointsAtZ", "pointsAtZ", 0],
|
||||
["specularExponent", "specularExponent", 1],
|
||||
["limitingConeAngle", "limitingConeAngle", 0],
|
||||
]],
|
||||
["feTurbulence", SVGFETurbulenceElement, SVGFETurbulenceElement, [
|
||||
["baseFrequencyX", "baseFrequency", 0],
|
||||
["baseFrequencyY", "baseFrequency", 0], ["seed", "seed", 0],
|
||||
]],
|
||||
["stop", SVGStopElement, SVGStopElement, [["offset", "offset", 0]]],
|
||||
];
|
||||
|
||||
assert(typeof SVGAnimatedNumber === "function", "constructor exposed");
|
||||
let illegalConstructor = false;
|
||||
try {
|
||||
new SVGAnimatedNumber();
|
||||
} catch (error) {
|
||||
illegalConstructor = error instanceof TypeError;
|
||||
}
|
||||
assert(illegalConstructor, "illegal constructor");
|
||||
|
||||
const baseDescriptor = Object.getOwnPropertyDescriptor(
|
||||
SVGAnimatedNumber.prototype,
|
||||
"baseVal",
|
||||
);
|
||||
const animDescriptor = Object.getOwnPropertyDescriptor(
|
||||
SVGAnimatedNumber.prototype,
|
||||
"animVal",
|
||||
);
|
||||
assert(typeof baseDescriptor.get === "function" &&
|
||||
typeof baseDescriptor.set === "function", "baseVal descriptor");
|
||||
assert(typeof animDescriptor.get === "function" && animDescriptor.set === undefined,
|
||||
"animVal descriptor");
|
||||
|
||||
for (const [tag, constructor, owner, properties] of cases) {
|
||||
const element = document.createElementNS(ns, tag);
|
||||
assert(element instanceof constructor, `${tag} interface`);
|
||||
for (const [property, attribute, initial] of properties) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(owner.prototype, property);
|
||||
assert(typeof descriptor.get === "function" && descriptor.set === undefined,
|
||||
`${owner.name}.${property} descriptor`);
|
||||
assert(descriptor.enumerable && descriptor.configurable,
|
||||
`${owner.name}.${property} descriptor flags`);
|
||||
|
||||
const animated = element[property];
|
||||
assert(animated instanceof SVGAnimatedNumber, `${tag}.${property} interface`);
|
||||
assert(element[property] === animated, `${tag}.${property} SameObject`);
|
||||
assert(animated.baseVal === initial && animated.animVal === initial,
|
||||
`${tag}.${property} initial value`);
|
||||
|
||||
element.setAttribute(attribute, "42");
|
||||
assert(animated.baseVal === 42 && animated.animVal === 42,
|
||||
`${tag}.${property} live content update`);
|
||||
element.setAttribute(attribute, "foobar");
|
||||
assert(animated.baseVal === initial && animated.animVal === initial,
|
||||
`${tag}.${property} invalid fallback`);
|
||||
element.removeAttribute(attribute);
|
||||
assert(animated.baseVal === initial && animated.animVal === initial,
|
||||
`${tag}.${property} removed fallback`);
|
||||
}
|
||||
}
|
||||
|
||||
const gaussian = document.createElementNS(ns, "feGaussianBlur");
|
||||
const deviationX = gaussian.stdDeviationX;
|
||||
const deviationY = gaussian.stdDeviationY;
|
||||
gaussian.setAttribute("stdDeviation", "5");
|
||||
assert(deviationX.baseVal === 5 && deviationY.baseVal === 5,
|
||||
"single optional-number value");
|
||||
gaussian.setAttribute("stdDeviation", "5, 7");
|
||||
assert(deviationX.baseVal === 5 && deviationY.baseVal === 7,
|
||||
"paired optional-number values");
|
||||
deviationX.baseVal = 3;
|
||||
assert(gaussian.getAttribute("stdDeviation") === "3 7",
|
||||
"first pair component reflection");
|
||||
deviationY.baseVal = 9;
|
||||
assert(gaussian.getAttribute("stdDeviation") === "3 9" &&
|
||||
deviationX.baseVal === 3 && deviationY.animVal === 9,
|
||||
"second pair component reflection");
|
||||
|
||||
const specular = document.createElementNS(ns, "feSpecularLighting");
|
||||
const surfaceScale = specular.surfaceScale;
|
||||
surfaceScale.baseVal = -1;
|
||||
assert(surfaceScale.baseVal === -1 && surfaceScale.animVal === -1 &&
|
||||
specular.getAttribute("surfaceScale") === "-1", "scalar reflection");
|
||||
surfaceScale.baseVal = 300;
|
||||
for (const invalid of ["aString", NaN, Infinity, specular]) {
|
||||
let rejected = false;
|
||||
try {
|
||||
surfaceScale.baseVal = invalid;
|
||||
} catch (error) {
|
||||
rejected = error instanceof TypeError;
|
||||
}
|
||||
assert(rejected && surfaceScale.baseVal === 300,
|
||||
"restricted float rejects invalid values");
|
||||
}
|
||||
|
||||
const stop = document.createElementNS(ns, "stop");
|
||||
const stopOffset = stop.offset;
|
||||
stop.setAttribute("offset", "50%");
|
||||
assert(stopOffset.baseVal === 0.5 && stopOffset.animVal === 0.5,
|
||||
"stop percentage content value");
|
||||
stopOffset.baseVal = 0.25;
|
||||
assert(stop.getAttribute("offset") === "0.25", "stop number reflection");
|
||||
|
||||
let incompatibleAnimatedReceiver = false;
|
||||
try {
|
||||
baseDescriptor.get.call({});
|
||||
} catch (error) {
|
||||
incompatibleAnimatedReceiver = error instanceof TypeError;
|
||||
}
|
||||
assert(incompatibleAnimatedReceiver, "animated number receiver brand");
|
||||
|
||||
const k1Descriptor = Object.getOwnPropertyDescriptor(
|
||||
SVGFECompositeElement.prototype,
|
||||
"k1",
|
||||
);
|
||||
let incompatibleElementReceiver = false;
|
||||
try {
|
||||
k1Descriptor.get.call(specular);
|
||||
} catch (error) {
|
||||
incompatibleElementReceiver = error instanceof TypeError;
|
||||
}
|
||||
assert(incompatibleElementReceiver, "element receiver brand");
|
||||
return "ok";
|
||||
})()
|
||||
"#,
|
||||
)
|
||||
.expect("SVG animated number probe should evaluate");
|
||||
|
||||
assert_eq!(result, "ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn svg_animated_boolean_reflects_preserve_alpha() {
|
||||
let mut vm = new_parsed_test_vm(
|
||||
|
||||
@@ -401,6 +401,15 @@ interfaces! {
|
||||
SVGFEMorphologyElement: SVGElement;
|
||||
SVGFETurbulenceElement: SVGElement;
|
||||
SVGTextPathElement: SVGTextContentElement;
|
||||
SVGFEDiffuseLightingElement: SVGElement;
|
||||
SVGFEDistantLightElement: SVGElement;
|
||||
SVGFEDropShadowElement: SVGElement;
|
||||
SVGFEGaussianBlurElement: SVGElement;
|
||||
SVGFEOffsetElement: SVGElement;
|
||||
SVGFEPointLightElement: SVGElement;
|
||||
SVGFESpecularLightingElement: SVGElement;
|
||||
SVGFESpotLightElement: SVGElement;
|
||||
SVGStopElement: SVGElement;
|
||||
SVGElement: Element;
|
||||
SVGEllipseElement: SVGGeometryElement;
|
||||
SVGForeignObjectElement: SVGGraphicsElement;
|
||||
|
||||
Reference in New Issue
Block a user