From 8da9487c0ac6adfdde24ac1f16ac813f7735a993 Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Fri, 27 Mar 2020 17:12:50 -0700 Subject: [PATCH] avm1: Match Flash's property enumeration order (fix #153) --- core/src/avm1.rs | 4 ++-- core/src/avm1/script_object.rs | 21 ++++++++++++--------- core/src/avm1/stage_object.rs | 13 +++++-------- core/src/property_map.rs | 6 ++++-- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/core/src/avm1.rs b/core/src/avm1.rs index 63d1f34f5..a75ce2bff 100644 --- a/core/src/avm1.rs +++ b/core/src/avm1.rs @@ -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); } diff --git a/core/src/avm1/script_object.rs b/core/src/avm1/script_object.rs index 9185518fc..14277a90c 100644 --- a/core/src/avm1/script_object.rs +++ b/core/src/avm1/script_object.rs @@ -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 } diff --git a/core/src/avm1/stage_object.rs b/core/src/avm1/stage_object.rs index b52693e5e..571f14f6b 100644 --- a/core/src/avm1/stage_object.rs +++ b/core/src/avm1/stage_object.rs @@ -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 } diff --git a/core/src/property_map.rs b/core/src/property_map.rs index 2a983260b..aeda1e1ac 100644 --- a/core/src/property_map.rs +++ b/core/src/property_map.rs @@ -81,12 +81,14 @@ impl PropertyMap { } } + /// Returns the value tuples in Flash's iteration order (most recently added first). pub fn iter(&self) -> impl Iterator { - 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 { - 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 {