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__`?
|
//TODO: What happens if we try to extend an object which has no `__proto__`?
|
||||||
//e.g. `class Whatever extends Object.prototype`
|
//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(
|
let sub_prototype: Object<'gc> =
|
||||||
context.gc_context,
|
ScriptObject::object(context.gc_context, Some(super_proto)).into();
|
||||||
Box::new(ScriptObject::object(context.gc_context, Some(super_proto)))
|
|
||||||
as Box<dyn Object<'gc>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
sub_prototype.write(context.gc_context).set(
|
sub_prototype.set("constructor", superclass.into(), self, context)?;
|
||||||
"constructor",
|
subclass.set("prototype", sub_prototype.into(), self, context)?;
|
||||||
superclass.into(),
|
|
||||||
self,
|
|
||||||
context,
|
|
||||||
sub_prototype,
|
|
||||||
)?;
|
|
||||||
subclass.write(context.gc_context).set(
|
|
||||||
"prototype",
|
|
||||||
sub_prototype.into(),
|
|
||||||
self,
|
|
||||||
context,
|
|
||||||
subclass,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1364,7 +1349,6 @@ impl<'gc> Avm1<'gc> {
|
||||||
let constr = self.pop()?.as_object()?;
|
let constr = self.pop()?.as_object()?;
|
||||||
let obj = self.pop()?.as_object()?;
|
let obj = self.pop()?.as_object()?;
|
||||||
|
|
||||||
//TODO: Interface detection on SWF7
|
|
||||||
let prototype = constr
|
let prototype = constr
|
||||||
.get("prototype", self, context)?
|
.get("prototype", self, context)?
|
||||||
.resolve(self, context)?
|
.resolve(self, context)?
|
||||||
|
@ -1377,6 +1361,15 @@ impl<'gc> Avm1<'gc> {
|
||||||
return Ok(());
|
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();
|
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.
|
/// Get the object's type string.
|
||||||
fn type_of(&self) -> &'static str;
|
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.
|
/// Get the underlying script object, if it exists.
|
||||||
fn as_script_object(&self) -> Option<ScriptObject<'gc>>;
|
fn as_script_object(&self) -> Option<ScriptObject<'gc>>;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ pub struct ScriptObjectData<'gc> {
|
||||||
prototype: Option<Object<'gc>>,
|
prototype: Option<Object<'gc>>,
|
||||||
values: HashMap<String, Property<'gc>>,
|
values: HashMap<String, Property<'gc>>,
|
||||||
function: Option<Executable<'gc>>,
|
function: Option<Executable<'gc>>,
|
||||||
|
interfaces: Vec<Object<'gc>>,
|
||||||
type_of: &'static str,
|
type_of: &'static str,
|
||||||
array: ArrayStorage<'gc>,
|
array: ArrayStorage<'gc>,
|
||||||
}
|
}
|
||||||
|
@ -37,6 +38,7 @@ unsafe impl<'gc> Collect for ScriptObjectData<'gc> {
|
||||||
self.values.trace(cc);
|
self.values.trace(cc);
|
||||||
self.function.trace(cc);
|
self.function.trace(cc);
|
||||||
self.array.trace(cc);
|
self.array.trace(cc);
|
||||||
|
self.interfaces.trace(cc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +66,7 @@ impl<'gc> ScriptObject<'gc> {
|
||||||
values: HashMap::new(),
|
values: HashMap::new(),
|
||||||
function: None,
|
function: None,
|
||||||
array: ArrayStorage::Properties { length: 0 },
|
array: ArrayStorage::Properties { length: 0 },
|
||||||
|
interfaces: vec![],
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -80,6 +83,7 @@ impl<'gc> ScriptObject<'gc> {
|
||||||
values: HashMap::new(),
|
values: HashMap::new(),
|
||||||
function: None,
|
function: None,
|
||||||
array: ArrayStorage::Vector(Vec::new()),
|
array: ArrayStorage::Vector(Vec::new()),
|
||||||
|
interfaces: vec![],
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
object.sync_native_property("length", gc_context, Some(0.into()));
|
object.sync_native_property("length", gc_context, Some(0.into()));
|
||||||
|
@ -99,6 +103,7 @@ impl<'gc> ScriptObject<'gc> {
|
||||||
values: HashMap::new(),
|
values: HashMap::new(),
|
||||||
function: None,
|
function: None,
|
||||||
array: ArrayStorage::Properties { length: 0 },
|
array: ArrayStorage::Properties { length: 0 },
|
||||||
|
interfaces: vec![],
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.into()
|
.into()
|
||||||
|
@ -118,6 +123,7 @@ impl<'gc> ScriptObject<'gc> {
|
||||||
values: HashMap::new(),
|
values: HashMap::new(),
|
||||||
function: None,
|
function: None,
|
||||||
array: ArrayStorage::Properties { length: 0 },
|
array: ArrayStorage::Properties { length: 0 },
|
||||||
|
interfaces: vec![],
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -136,6 +142,7 @@ impl<'gc> ScriptObject<'gc> {
|
||||||
function: Some(function.into()),
|
function: Some(function.into()),
|
||||||
values: HashMap::new(),
|
values: HashMap::new(),
|
||||||
array: ArrayStorage::Properties { length: 0 },
|
array: ArrayStorage::Properties { length: 0 },
|
||||||
|
interfaces: vec![],
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -465,6 +472,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
||||||
self.0.read().type_of
|
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>> {
|
fn as_script_object(&self) -> Option<ScriptObject<'gc>> {
|
||||||
Some(*self)
|
Some(*self)
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,6 +228,14 @@ impl<'gc> TObject<'gc> for StageObject<'gc> {
|
||||||
self.base.delete_array_element(index, gc_context)
|
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 {
|
fn as_string(&self) -> String {
|
||||||
self.display_object.path()
|
self.display_object.path()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue