avm2: Implement XML.removeNamespace
This commit is contained in:
parent
d8b4ec0404
commit
5834f273e2
|
@ -1158,6 +1158,30 @@ impl<'gc> E4XNode<'gc> {
|
|||
self.0.read().notification
|
||||
}
|
||||
|
||||
// 13.3.5.4 [[GetNamespace]] ( [ InScopeNamespaces ] )
|
||||
pub fn get_namespace(&self, in_scope_ns: &[E4XNamespace<'gc>]) -> E4XNamespace<'gc> {
|
||||
// 1. If q.uri is null, throw a TypeError exception
|
||||
// NOTE: As stated in the spec, this isn't really possible.
|
||||
match self.namespace() {
|
||||
None => E4XNamespace::default_namespace(),
|
||||
Some(ns) => {
|
||||
// 2. If InScopeNamespaces was not specified, let InScopeNamespaces = { }
|
||||
// 3. Find a Namespace ns in InScopeNamespaces, such that ns.uri == q.uri. If more than one such
|
||||
// Namespace ns exists, the implementation may choose one of the matching Namespaces arbitrarily.
|
||||
// NOTE: Flash just uses whatever namespace URI matches first. They don't do anything with the prefix.
|
||||
if let Some(ns) = in_scope_ns.iter().find(|scope_ns| scope_ns.uri == ns.uri) {
|
||||
*ns
|
||||
} else {
|
||||
// 4. If no such namespace ns exists
|
||||
// a. Let ns be a new namespace created as if by calling the constructor new Namespace(q.uri)
|
||||
// NOTE: We could preserve the prefix here, but Flash doesn't bother.
|
||||
E4XNamespace::new_uri(ns.uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 5. Return ns
|
||||
}
|
||||
|
||||
pub fn in_scope_namespaces(&self) -> Vec<E4XNamespace<'gc>> {
|
||||
let mut result: Vec<E4XNamespace<'gc>> = Vec::new();
|
||||
|
||||
|
|
|
@ -339,9 +339,90 @@ pub fn set_namespace<'gc>(
|
|||
pub fn remove_namespace<'gc>(
|
||||
activation: &mut Activation<'_, 'gc>,
|
||||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
avm2_stub_method!(activation, "XML", "removeNamespace");
|
||||
let xml = this.as_xml_object().unwrap();
|
||||
let node = xml.node();
|
||||
|
||||
// 1. If x.[[Class]] ∈ {"text", "comment", "processing-instruction", "attribute"}, return x
|
||||
if !node.is_element() {
|
||||
return Ok(this.into());
|
||||
}
|
||||
|
||||
// 2. Let ns be a Namespace object created as if by calling the function Namespace( namespace )
|
||||
let value = args.get_value(0);
|
||||
let ns = activation
|
||||
.avm2()
|
||||
.classes()
|
||||
.namespace
|
||||
.construct(activation, &[value])?
|
||||
.as_namespace_object()
|
||||
.unwrap();
|
||||
let ns = E4XNamespace {
|
||||
prefix: ns.prefix(),
|
||||
uri: ns.namespace().as_uri(),
|
||||
};
|
||||
|
||||
// 3. Let thisNS be the result of calling [[GetNamespace]] on x.[[Name]] with argument x.[[InScopeNamespaces]]
|
||||
let in_scope_ns = node.in_scope_namespaces();
|
||||
let this_ns = node.get_namespace(&in_scope_ns);
|
||||
|
||||
// 4. If (thisNS == ns), return x
|
||||
if this_ns == ns {
|
||||
return Ok(this.into());
|
||||
}
|
||||
|
||||
{
|
||||
let E4XNodeKind::Element { attributes, .. } = &*node.kind() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
// 5. For each a in x.[[Attributes]]
|
||||
for attr in attributes {
|
||||
// 5.a. Let aNS be the result of calling [[GetNamespace]] on a.[[Name]] with argument x.[[InScopeNamespaces]]
|
||||
let attr_ns = attr.get_namespace(&in_scope_ns);
|
||||
// 5.b. If (aNS == ns), return x
|
||||
if attr_ns == ns {
|
||||
return Ok(this.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. If ns.prefix == undefined
|
||||
if ns.prefix.is_none() {
|
||||
let E4XNodeKind::Element {
|
||||
ref mut namespaces, ..
|
||||
} = &mut *node.kind_mut(activation.gc())
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
// 6.a. If there exists a namespace n ∈ x.[[InScopeNamespaces]],
|
||||
// such that n.uri == ns.uri, remove the namespace n from x.[[InScopeNamespaces]]
|
||||
namespaces.retain(|namespace| namespace.uri != ns.uri);
|
||||
} else {
|
||||
// 7. Else
|
||||
let E4XNodeKind::Element {
|
||||
ref mut namespaces, ..
|
||||
} = &mut *node.kind_mut(activation.gc())
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
// 7.a. If there exists a namespace n ∈ x.[[InScopeNamespaces]],
|
||||
// such that n.uri == ns.uri and n.prefix == ns.prefix, remove the namespace n from x.[[InScopeNamespaces]]
|
||||
namespaces.retain(|namespace| *namespace != ns);
|
||||
}
|
||||
|
||||
let E4XNodeKind::Element { children, .. } = &*node.kind() else {
|
||||
unreachable!()
|
||||
};
|
||||
// 8. For each property p of x
|
||||
for child in children {
|
||||
// 8.a. If p.[[Class]] = "element", call the removeNamespace method of p with argument ns
|
||||
if child.is_element() {
|
||||
let xml = E4XOrXml::E4X(*child).get_or_create_xml(activation);
|
||||
remove_namespace(activation, xml.into(), args)?;
|
||||
}
|
||||
}
|
||||
|
||||
// 9. Return x
|
||||
Ok(this.into())
|
||||
|
|
|
@ -168,28 +168,9 @@ impl<'gc> XmlObject<'gc> {
|
|||
activation: &mut Activation<'_, 'gc>,
|
||||
in_scope_ns: &[E4XNamespace<'gc>],
|
||||
) -> Result<NamespaceObject<'gc>, Error<'gc>> {
|
||||
// 13.3.5.4 [[GetNamespace]] ( [ InScopeNamespaces ] )
|
||||
// 1. If q.uri is null, throw a TypeError exception
|
||||
// NOTE: As stated in the spec, this not really possible
|
||||
match self.0.node.get().namespace() {
|
||||
None => E4XNamespace::default_namespace(),
|
||||
Some(ns) => {
|
||||
// 2. If InScopeNamespaces was not specified, let InScopeNamespaces = { }
|
||||
// 3. Find a Namespace ns in InScopeNamespaces, such that ns.uri == q.uri. If more than one such
|
||||
// Namespace ns exists, the implementation may choose one of the matching Namespaces arbitrarily.
|
||||
// NOTE: Flash just uses whatever namespace URI matches first. They don't do anything with the prefix.
|
||||
if let Some(ns) = in_scope_ns.iter().find(|scope_ns| scope_ns.uri == ns.uri) {
|
||||
*ns
|
||||
} else {
|
||||
// 4. If no such namespace ns exists
|
||||
// a. Let ns be a new namespace created as if by calling the constructor new Namespace(q.uri)
|
||||
// NOTE: We could preserve the prefix here, but Flash doesn't bother.
|
||||
E4XNamespace::new_uri(ns.uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 5. Return ns
|
||||
.as_namespace_object(activation)
|
||||
self.node()
|
||||
.get_namespace(in_scope_ns)
|
||||
.as_namespace_object(activation)
|
||||
}
|
||||
|
||||
pub fn matches_name(&self, multiname: &Multiname<'gc>) -> bool {
|
||||
|
|
Loading…
Reference in New Issue