Add interface support, and add interface checking to `ActionInstanceOf`.

This commit is contained in:
David Wendt 2019-10-28 18:13:29 -04:00 committed by Mike Welsh
parent ca93bba5c1
commit ee4b47d062
4 changed files with 47 additions and 21 deletions

View File

@ -1041,28 +1041,13 @@ impl<'gc> Avm1<'gc> {
//TODO: What happens if we try to extend an object which has no `__proto__`?
//e.g. `class Whatever extends Object.prototype`
let super_proto = superclass.read().proto().unwrap_or(self.prototypes.object);
let super_proto = superclass.proto().unwrap_or(self.prototypes.object);
let sub_prototype = GcCell::allocate(
context.gc_context,
Box::new(ScriptObject::object(context.gc_context, Some(super_proto)))
as Box<dyn Object<'gc>>,
);
let sub_prototype: Object<'gc> =
ScriptObject::object(context.gc_context, Some(super_proto)).into();
sub_prototype.write(context.gc_context).set(
"constructor",
superclass.into(),
self,
context,
sub_prototype,
)?;
subclass.write(context.gc_context).set(
"prototype",
sub_prototype.into(),
self,
context,
subclass,
)?;
sub_prototype.set("constructor", superclass.into(), self, context)?;
subclass.set("prototype", sub_prototype.into(), self, context)?;
Ok(())
}
@ -1364,7 +1349,6 @@ impl<'gc> Avm1<'gc> {
let constr = self.pop()?.as_object()?;
let obj = self.pop()?.as_object()?;
//TODO: Interface detection on SWF7
let prototype = constr
.get("prototype", self, context)?
.resolve(self, context)?
@ -1377,6 +1361,15 @@ impl<'gc> Avm1<'gc> {
return Ok(());
}
if self.current_swf_version() >= 7 {
for interface in constr.interfaces() {
if Object::ptr_eq(interface, constr) {
self.push(true);
return Ok(());
}
}
}
proto = this_proto.proto();
}

View File

@ -165,6 +165,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// Get the object's type string.
fn type_of(&self) -> &'static str;
/// Enumerate all interfaces implemented by this object.
fn interfaces(&self) -> Vec<Object<'gc>>;
/// Set the interface list for this object. (Only useful for prototypes.)
fn set_interfaces(
&mut self,
gc_context: MutationContext<'gc, '_>,
iface_list: Vec<Object<'gc>>,
);
/// Get the underlying script object, if it exists.
fn as_script_object(&self) -> Option<ScriptObject<'gc>>;

View File

@ -27,6 +27,7 @@ pub struct ScriptObjectData<'gc> {
prototype: Option<Object<'gc>>,
values: HashMap<String, Property<'gc>>,
function: Option<Executable<'gc>>,
interfaces: Vec<Object<'gc>>,
type_of: &'static str,
array: ArrayStorage<'gc>,
}
@ -37,6 +38,7 @@ unsafe impl<'gc> Collect for ScriptObjectData<'gc> {
self.values.trace(cc);
self.function.trace(cc);
self.array.trace(cc);
self.interfaces.trace(cc);
}
}
@ -64,6 +66,7 @@ impl<'gc> ScriptObject<'gc> {
values: HashMap::new(),
function: None,
array: ArrayStorage::Properties { length: 0 },
interfaces: vec![],
},
))
}
@ -80,6 +83,7 @@ impl<'gc> ScriptObject<'gc> {
values: HashMap::new(),
function: None,
array: ArrayStorage::Vector(Vec::new()),
interfaces: vec![],
},
));
object.sync_native_property("length", gc_context, Some(0.into()));
@ -99,6 +103,7 @@ impl<'gc> ScriptObject<'gc> {
values: HashMap::new(),
function: None,
array: ArrayStorage::Properties { length: 0 },
interfaces: vec![],
},
))
.into()
@ -118,6 +123,7 @@ impl<'gc> ScriptObject<'gc> {
values: HashMap::new(),
function: None,
array: ArrayStorage::Properties { length: 0 },
interfaces: vec![],
},
))
}
@ -136,6 +142,7 @@ impl<'gc> ScriptObject<'gc> {
function: Some(function.into()),
values: HashMap::new(),
array: ArrayStorage::Properties { length: 0 },
interfaces: vec![],
},
))
}
@ -465,6 +472,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
self.0.read().type_of
}
fn interfaces(&self) -> Vec<Object<'gc>> {
self.0.read().interfaces.clone()
}
fn set_interfaces(&mut self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
self.0.write(context).interfaces = iface_list;
}
fn as_script_object(&self) -> Option<ScriptObject<'gc>> {
Some(*self)
}

View File

@ -228,6 +228,14 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
self.base.delete_array_element(index, gc_context)
}
fn interfaces(&self) -> Vec<Object<'gc>> {
self.base.interfaces()
}
fn set_interfaces(&mut self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
self.base.set_interfaces(context, iface_list)
}
fn as_string(&self) -> String {
self.display_object.path()
}