avm2: Support indices in XMLList.child

This commit is contained in:
sleepycatcoding 2023-10-23 23:05:21 +03:00 committed by Nathan Adams
parent d9dad1109a
commit ed6fa6b2fe
4 changed files with 64 additions and 36 deletions

View File

@ -216,29 +216,9 @@ pub fn child<'gc>(
) -> Result<Value<'gc>, Error<'gc>> {
let xml = this.as_xml_object().unwrap();
let multiname = name_to_multiname(activation, &args[0], false)?;
let children = if let E4XNodeKind::Element { children, .. } = &*xml.node().kind() {
if let Some(local_name) = multiname.local_name() {
if let Ok(index) = local_name.parse::<usize>() {
let children = if let Some(node) = children.get(index) {
vec![E4XOrXml::E4X(*node)]
} else {
Vec::new()
};
return Ok(XmlListObject::new(activation, children, None, None).into());
}
}
children
.iter()
.filter(|node| node.matches_name(&multiname))
.map(|node| E4XOrXml::E4X(*node))
.collect()
} else {
Vec::new()
};
// FIXME: If name is not a number index, then we should call [[Get]] (get_property_local) with the name.
Ok(XmlListObject::new(activation, children, Some(xml.into()), Some(multiname)).into())
let list = xml.child(&multiname, activation);
Ok(list.into())
}
pub fn child_index<'gc>(

View File

@ -166,21 +166,26 @@ pub fn child<'gc>(
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let list = this.as_xml_list_object().unwrap();
let this = this.as_xml_list_object().unwrap();
let multiname = name_to_multiname(activation, &args[0], false)?;
let children = list.children();
let mut sub_children = Vec::new();
for child in &*children {
if let E4XNodeKind::Element { ref children, .. } = &*child.node().kind() {
sub_children.extend(
children
.iter()
.filter(|node| node.matches_name(&multiname))
.map(|node| E4XOrXml::E4X(*node)),
);
let mut children = this.children_mut(activation.gc());
// 1. Let m be a new XMLList with m.[[TargetObject]] = list
let list = XmlListObject::new(activation, Some(this.into()), None);
// 2. For i = 0 to list.[[Length]]-1
for child in &mut *children {
// 2.a. Let r = list[i].child(propertyName)
let child = child.get_or_create_xml(activation);
let r = child.child(&multiname, activation);
// 2.b. If r.[[Length]] > 0, call the [[Append]] method of m with argument r
if r.length() > 0 {
list.append(r.into(), activation.gc());
}
}
Ok(XmlListObject::new(activation, sub_children, Some(list.into()), None).into())
// 3. Return m
Ok(list.into())
}
pub fn children<'gc>(
@ -308,6 +313,7 @@ pub fn descendants<'gc>(
}
}
// ECMA-357 13.5.4.20 XMLList.prototype.text ( )
pub fn text<'gc>(
activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,

View File

@ -14,7 +14,7 @@ use gc_arena::{Collect, GcCell, GcWeakCell, Mutation};
use ruffle_wstr::WString;
use std::cell::{Ref, RefMut};
use super::xml_list_object::E4XOrXml;
use super::xml_list_object::{E4XOrXml, XmlOrXmlListObject};
use super::PrimitiveObject;
/// A class instance allocator that allocates XML objects.
@ -70,6 +70,49 @@ impl<'gc> XmlObject<'gc> {
))
}
pub fn child(
&self,
name: &Multiname<'gc>,
activation: &mut Activation<'_, 'gc>,
) -> XmlListObject<'gc> {
let children = if let E4XNodeKind::Element { children, .. } = &*self.node().kind() {
if let Some(local_name) = name.local_name() {
if let Ok(index) = local_name.parse::<usize>() {
let children = if let Some(node) = children.get(index) {
vec![E4XOrXml::E4X(*node)]
} else {
Vec::new()
};
let list = XmlListObject::new_with_children(activation, children, None, None);
if list.length() > 0 {
// NOTE: Since avmplus uses appendNode here, when the node exists, that implicitly sets the target_dirty flag.
list.set_dirty_flag(activation.gc());
}
return list;
}
}
children
.iter()
.filter(|node| node.matches_name(name))
.map(|node| E4XOrXml::E4X(*node))
.collect()
} else {
Vec::new()
};
// FIXME: If name is not a number index, then we should call [[Get]] (get_property_local) with the name.
XmlListObject::new_with_children(
activation,
children,
Some(XmlOrXmlListObject::Xml(*self)),
Some(name.clone()),
)
}
pub fn length(&self) -> Option<usize> {
self.node().length()
}

View File

@ -1,2 +1 @@
num_ticks = 1
known_failure = true