refactor(svg): synchronize transform list members through one path

This commit is contained in:
ldm0
2026-10-07 18:41:02 +08:00
committed by Donough Liu
parent 6ef92ff113
commit 926860a30c
3 changed files with 44 additions and 20 deletions
@@ -1436,25 +1436,20 @@ pub(super) fn sync_svg_animated_transform_list_from_owner_attribute<'s>(
attribute: &str,
) {
let raw = svg_owner_attribute_value(scope, owner, attribute);
let raw_value = raw.clone().unwrap_or_default();
if let Some(base_val) = svg_animated_transform_list_member(scope, animated, "baseVal")
&& svg_transform_list_synced_attribute_value(scope, base_val)
.as_deref()
.is_some_and(|synced| synced == raw_value)
{
set_svg_transform_list_owner_attribute(scope, base_val, owner, attribute);
return;
}
let base_items = build_svg_transform_list_items_from_attribute(scope, raw.as_deref());
let anim_items = build_svg_transform_list_items_from_attribute(scope, raw.as_deref());
if let Some(base_val) = svg_animated_transform_list_member(scope, animated, "baseVal") {
set_svg_transform_list_items(scope, base_val, base_items);
set_svg_transform_list_owner_attribute(scope, base_val, owner, attribute);
set_svg_transform_list_synced_attribute_value(scope, base_val, &raw_value);
}
if let Some(anim_val) = svg_animated_transform_list_member(scope, animated, "animVal") {
set_svg_transform_list_items(scope, anim_val, anim_items);
set_svg_transform_list_synced_attribute_value(scope, anim_val, &raw_value);
let raw_value = raw.as_deref().unwrap_or_default();
for member in ["baseVal", "animVal"] {
let Some(list) = svg_animated_transform_list_member(scope, animated, member) else {
continue;
};
if member == "baseVal" {
set_svg_transform_list_owner_attribute(scope, list, owner, attribute);
}
if svg_transform_list_synced_attribute_value(scope, list).as_deref() == Some(raw_value) {
continue;
}
let items = build_svg_transform_list_items_from_attribute(scope, raw.as_deref());
set_svg_transform_list_items(scope, list, items);
set_svg_transform_list_synced_attribute_value(scope, list, raw_value);
}
}
@@ -1510,7 +1505,7 @@ pub(super) fn reflect_svg_transform_list_to_owner_attribute<'s>(
};
let value = serialize_svg_transform_list_items(scope, list);
let Ok((runtime_ptr, handle)) =
crate::native_bridge::node_runtime_and_handle_from_object(scope, owner)
crate::native_bridge::node_runtime_and_handle_from_object_or_detached(scope, owner)
else {
return;
};
@@ -2149,6 +2149,7 @@ mod http_fixture;
mod media_owner_playback_interfaces;
mod media_recorder_shell;
mod svg_animation_interfaces;
mod svg_transform_sync_consolidation;
mod audio_event_interfaces;
mod hyperlink_null_url_protocol;
@@ -0,0 +1,28 @@
use super::*;
#[test]
fn svg_transform_sync_retains_members_and_reflects_windowless_mutations() {
let mut vm = new_parsed_test_vm(
"https://svg_transform_sync_consolidation.test/",
"<!doctype html><body></body>",
);
assert_eq!(vm.eval(r#"(() => {
const docs=[document,document.implementation.createHTMLDocument('detached')];
for(const doc of docs){
const group=doc.createElementNS('http://www.w3.org/2000/svg','g');group.setAttribute('transform','translate(1 2)');
const animated=group.transform,base=animated.baseVal,anim=animated.animVal;
const baseItem=base.getItem(0),animItem=anim.getItem(0);
if(group.transform!==animated||group.transform.baseVal!==base||group.transform.animVal!==anim)throw Error('SameObject');
if(base.getItem(0)!==baseItem||anim.getItem(0)!==animItem)throw Error('unchanged tear-off identity');
group.setAttribute('transform','translate(3 4)');
const refreshed=group.transform;
if(refreshed.baseVal!==base||refreshed.animVal!==anim||base.getItem(0).matrix.e!==3||anim.getItem(0).matrix.f!==4)throw Error('attribute synchronization');
const item=base.getItem(0);item.setTranslate(5,6);
if(!group.getAttribute('transform').includes('5'))throw Error('windowless reflection');
group.transform;
if(anim.getItem(0).matrix.e!==5||anim.getItem(0).matrix.f!==6)throw Error('animated list synchronization');
const retained=anim.getItem(0);group.transform;if(anim.getItem(0)!==retained)throw Error('animated tear-off identity');
}
return 'ok';
})()"#).expect("native binding regression"), "ok");
}