avm1: Get child clip instances in StageObject
Add the logic to get children display objects as properties in `StageObject`.
This commit is contained in:
parent
783ede6f79
commit
c29b042f5e
|
@ -48,23 +48,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
if self.has_own_property(name) {
|
if self.has_own_property(name) {
|
||||||
self.get_local(name, avm, context, (*self).into())
|
self.get_local(name, avm, context, (*self).into())
|
||||||
} else {
|
} else {
|
||||||
let mut depth = 0;
|
search_prototype(self.proto(), name, avm, context, (*self).into())
|
||||||
let mut proto = self.proto();
|
|
||||||
|
|
||||||
while proto.is_some() {
|
|
||||||
if depth == 255 {
|
|
||||||
return Err("Encountered an excessively deep prototype chain.".into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if proto.unwrap().has_own_property(name) {
|
|
||||||
return proto.unwrap().get_local(name, avm, context, (*self).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
proto = proto.unwrap().proto();
|
|
||||||
depth += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::Undefined.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,3 +184,28 @@ impl<'gc> Object<'gc> {
|
||||||
a.as_ptr() == b.as_ptr()
|
a.as_ptr() == b.as_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn search_prototype<'gc>(
|
||||||
|
mut proto: Option<Object<'gc>>,
|
||||||
|
name: &str,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
this: Object<'gc>,
|
||||||
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
|
let mut depth = 0;
|
||||||
|
|
||||||
|
while proto.is_some() {
|
||||||
|
if depth == 255 {
|
||||||
|
return Err("Encountered an excessively deep prototype chain.".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if proto.unwrap().has_own_property(name) {
|
||||||
|
return proto.unwrap().get_local(name, avm, context, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
proto = proto.unwrap().proto();
|
||||||
|
depth += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Undefined.into())
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::avm1::function::Executable;
|
use crate::avm1::function::Executable;
|
||||||
use crate::avm1::property::Attribute;
|
use crate::avm1::property::Attribute;
|
||||||
use crate::avm1::return_value::ReturnValue;
|
use crate::avm1::return_value::ReturnValue;
|
||||||
use crate::avm1::{Avm1, Error, Object, ObjectPtr, ScriptObject, TObject, Value};
|
use crate::avm1::{Avm1, Error, Object, ObjectPtr, ScriptObject, TDisplayObject, TObject, Value};
|
||||||
use crate::context::UpdateContext;
|
use crate::context::UpdateContext;
|
||||||
use crate::display_object::DisplayObject;
|
use crate::display_object::DisplayObject;
|
||||||
use enumset::EnumSet;
|
use enumset::EnumSet;
|
||||||
|
@ -57,6 +57,26 @@ impl fmt::Debug for StageObject<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> TObject<'gc> for StageObject<'gc> {
|
impl<'gc> TObject<'gc> for StageObject<'gc> {
|
||||||
|
fn get(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
avm: &mut Avm1<'gc>,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
|
// Property search order for DisplayObjects:
|
||||||
|
if self.has_own_property(name) {
|
||||||
|
// 1) Actual properties on the underlying object
|
||||||
|
self.get_local(name, avm, context, (*self).into())
|
||||||
|
} else if let Some(child) = self.display_object.get_child_by_name(name) {
|
||||||
|
// 2) Child display objects with the given instance name
|
||||||
|
Ok(child.object().into())
|
||||||
|
} else {
|
||||||
|
// 3) Prototype
|
||||||
|
crate::avm1::object::search_prototype(self.proto(), name, avm, context, (*self).into())
|
||||||
|
}
|
||||||
|
// 4) TODO: __resolve?
|
||||||
|
}
|
||||||
|
|
||||||
fn get_local(
|
fn get_local(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -66,15 +86,15 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
|
||||||
) -> Result<ReturnValue<'gc>, Error> {
|
) -> Result<ReturnValue<'gc>, Error> {
|
||||||
self.base.get_local(name, avm, context, this)
|
self.base.get_local(name, avm, context, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(
|
fn set(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
value: Value<'gc>,
|
value: Value<'gc>,
|
||||||
avm: &mut Avm1<'gc>,
|
avm: &mut Avm1<'gc>,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
this: Object<'gc>,
|
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.base.set(name, value, avm, context, this)
|
self.base.set(name, value, avm, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(
|
fn call(
|
||||||
|
@ -127,10 +147,19 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_property(&self, name: &str) -> bool {
|
fn has_property(&self, name: &str) -> bool {
|
||||||
self.base.has_property(name)
|
if self.base.has_property(name) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.display_object.get_child_by_name(name).is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_own_property(&self, name: &str) -> bool {
|
fn has_own_property(&self, name: &str) -> bool {
|
||||||
|
// Note that `hasOwnProperty` does NOT return true for child display objects.
|
||||||
self.base.has_own_property(name)
|
self.base.has_own_property(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,11 +172,19 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_keys(&self) -> HashSet<String> {
|
fn get_keys(&self) -> HashSet<String> {
|
||||||
self.base.get_keys()
|
// Keys from the underlying object are listed first, followed by
|
||||||
|
// child display objects in order from highest depth to lowest depth.
|
||||||
|
// TODO: It's possible to have multiple instances with the same name,
|
||||||
|
// and that name will be returned multiple times in the key list for a `for..in` loop.
|
||||||
|
let mut keys = self.base.get_keys();
|
||||||
|
for child in self.display_object.children() {
|
||||||
|
keys.insert(child.name().to_string());
|
||||||
|
}
|
||||||
|
keys
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self) -> String {
|
fn as_string(&self) -> String {
|
||||||
self.base.as_string()
|
self.display_object.path()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_of(&self) -> &'static str {
|
fn type_of(&self) -> &'static str {
|
||||||
|
|
Loading…
Reference in New Issue