Add interface support, and add interface checking to `ActionInstanceOf`.
This commit is contained in:
parent
ca93bba5c1
commit
ee4b47d062
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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>>;
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue