avm1: Match Flash's property enumeration order (fix #153)

This commit is contained in:
Mike Welsh 2020-03-27 17:12:50 -07:00
parent 2cdf780e6f
commit 8da9487c0a
4 changed files with 23 additions and 21 deletions

View File

@ -1522,7 +1522,7 @@ impl<'gc> Avm1<'gc> {
match object {
Value::Object(ob) => {
for k in ob.get_keys(self) {
for k in ob.get_keys(self).into_iter().rev() {
self.push(k);
}
}
@ -1539,7 +1539,7 @@ impl<'gc> Avm1<'gc> {
let object = self.pop().as_object()?;
self.push(Value::Null); // Sentinel that indicates end of enumeration
for k in object.get_keys(self) {
for k in object.get_keys(self).into_iter().rev() {
self.push(k);
}

View File

@ -463,20 +463,23 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
let proto_keys = self.proto().map_or_else(Vec::new, |p| p.get_keys(avm));
let mut out_keys = vec![];
let object = self.0.read();
for key in proto_keys {
if !object.values.contains_key(&key, avm.is_case_sensitive()) {
out_keys.push(key);
}
}
for key in self.0.read().values.iter().filter_map(move |(k, p)| {
// Prototype keys come first.
out_keys.extend(
proto_keys
.into_iter()
.filter(|k| !object.values.contains_key(k, avm.is_case_sensitive())),
);
// Then our own keys.
out_keys.extend(self.0.read().values.iter().filter_map(move |(k, p)| {
if p.is_enumerable() {
Some(k.to_string())
} else {
None
}
}) {
out_keys.push(key)
}
}));
out_keys
}

View File

@ -255,14 +255,11 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
// Keys from the underlying object are listed first, followed by
// child display objects in order from highest depth to lowest depth.
let mut keys = self.base.get_keys(avm);
for child in self
.display_object
.children()
.map(|child| child.name().to_string())
{
keys.push(child)
}
keys.extend(
self.display_object
.children()
.map(|child| child.name().to_string()),
);
keys
}

View File

@ -81,12 +81,14 @@ impl<V> PropertyMap<V> {
}
}
/// Returns the value tuples in Flash's iteration order (most recently added first).
pub fn iter(&self) -> impl Iterator<Item = (&String, &V)> {
self.0.iter().map(|(k, v)| (&k.0, v))
self.0.iter().rev().map(|(k, v)| (&k.0, v))
}
/// Returns the key-value tuples in Flash's iteration order (most recently added first).
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&String, &mut V)> {
self.0.iter_mut().map(|(k, v)| (&k.0, v))
self.0.iter_mut().rev().map(|(k, v)| (&k.0, v))
}
pub fn remove(&mut self, key: &str, case_sensitive: bool) -> Option<V> {