avm2: AVM2 built-in class suport (merge #802)
Initial support for defining built-ins in AVM2
This commit is contained in:
commit
f782ea8020
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::globals::SystemPrototypes;
|
||||
use crate::avm2::object::{Object, TObject};
|
||||
use crate::avm2::object::{Object, ScriptObject, TObject};
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::script::Script;
|
||||
use crate::avm2::script::TranslationUnit;
|
||||
|
@ -36,7 +36,7 @@ mod scope;
|
|||
mod script;
|
||||
mod slot;
|
||||
mod string;
|
||||
mod r#trait;
|
||||
mod traits;
|
||||
mod value;
|
||||
|
||||
/// Boxed error alias.
|
||||
|
@ -56,7 +56,7 @@ pub struct Avm2<'gc> {
|
|||
globals: Object<'gc>,
|
||||
|
||||
/// System prototypes.
|
||||
system_prototypes: SystemPrototypes<'gc>,
|
||||
system_prototypes: Option<SystemPrototypes<'gc>>,
|
||||
|
||||
#[cfg(feature = "avm_debug")]
|
||||
pub debug_output: bool,
|
||||
|
@ -65,21 +65,28 @@ pub struct Avm2<'gc> {
|
|||
impl<'gc> Avm2<'gc> {
|
||||
/// Construct a new AVM interpreter.
|
||||
pub fn new(mc: MutationContext<'gc, '_>) -> Self {
|
||||
let (globals, system_prototypes) = globals::construct_global_scope(mc);
|
||||
let globals = ScriptObject::bare_object(mc);
|
||||
|
||||
Self {
|
||||
stack: Vec::new(),
|
||||
globals,
|
||||
system_prototypes,
|
||||
system_prototypes: None,
|
||||
|
||||
#[cfg(feature = "avm_debug")]
|
||||
debug_output: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_player_globals(context: &mut UpdateContext<'_, 'gc, '_>) -> Result<(), Error> {
|
||||
let mut activation = Activation::from_nothing(context.reborrow());
|
||||
globals::load_player_globals(&mut activation)
|
||||
}
|
||||
|
||||
/// Return the current set of system prototypes.
|
||||
///
|
||||
/// This function panics if the interpreter has not yet been initialized.
|
||||
pub fn prototypes(&self) -> &SystemPrototypes<'gc> {
|
||||
&self.system_prototypes
|
||||
self.system_prototypes.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Run a script's initializer method.
|
||||
|
|
|
@ -2,13 +2,30 @@
|
|||
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Multiname, Namespace, QName};
|
||||
use crate::avm2::r#trait::{Trait, TraitKind};
|
||||
use crate::avm2::script::TranslationUnit;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::{Trait, TraitKind};
|
||||
use crate::avm2::{Avm2, Error};
|
||||
use crate::collect::CollectWrapper;
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
use swf::avm2::types::{Class as AbcClass, Instance as AbcInstance};
|
||||
|
||||
/// All possible attributes for a given class.
|
||||
#[derive(EnumSetType, Debug)]
|
||||
pub enum ClassAttributes {
|
||||
/// Class is sealed, attempts to set or init dynamic properties on an
|
||||
/// object will generate a runtime error.
|
||||
Sealed,
|
||||
|
||||
/// Class is final, attempts to construct child classes from it will
|
||||
/// generate a verification error.
|
||||
Final,
|
||||
|
||||
/// Class is an interface.
|
||||
Interface,
|
||||
}
|
||||
|
||||
/// A loaded ABC Class which can be used to construct objects with.
|
||||
#[derive(Clone, Debug, Collect)]
|
||||
#[collect(no_drop)]
|
||||
|
@ -19,14 +36,8 @@ pub struct Class<'gc> {
|
|||
/// The name of this class's superclass.
|
||||
super_class: Option<Multiname<'gc>>,
|
||||
|
||||
/// If this class is sealed (dynamic property writes should fail)
|
||||
is_sealed: bool,
|
||||
|
||||
/// If this class is final (subclassing should fail)
|
||||
is_final: bool,
|
||||
|
||||
/// If this class is an interface
|
||||
is_interface: bool,
|
||||
/// Attributes of the given class.
|
||||
attributes: CollectWrapper<EnumSet<ClassAttributes>>,
|
||||
|
||||
/// The namespace that protected traits of this class are stored into.
|
||||
protected_namespace: Option<Namespace<'gc>>,
|
||||
|
@ -97,6 +108,48 @@ fn do_trait_lookup<'gc>(
|
|||
}
|
||||
|
||||
impl<'gc> Class<'gc> {
|
||||
/// Create a new class.
|
||||
///
|
||||
/// This function is primarily intended for use by native code to define
|
||||
/// builtin classes. The absolute minimum necessary to define a class is
|
||||
/// required here; further methods allow further changes to the class.
|
||||
///
|
||||
/// Classes created in this way cannot have traits loaded from an ABC file
|
||||
/// using `load_traits`.
|
||||
pub fn new(
|
||||
name: QName<'gc>,
|
||||
super_class: Option<Multiname<'gc>>,
|
||||
instance_init: Method<'gc>,
|
||||
class_init: Method<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> GcCell<'gc, Self> {
|
||||
GcCell::allocate(
|
||||
mc,
|
||||
Self {
|
||||
name,
|
||||
super_class,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
protected_namespace: None,
|
||||
interfaces: Vec::new(),
|
||||
instance_init,
|
||||
instance_traits: Vec::new(),
|
||||
class_init,
|
||||
class_traits: Vec::new(),
|
||||
traits_loaded: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Set the attributes of the class (sealed/final/interface status).
|
||||
pub fn set_attributes(&mut self, attributes: EnumSet<ClassAttributes>) {
|
||||
self.attributes = CollectWrapper(attributes);
|
||||
}
|
||||
|
||||
/// Add a protected namespace to this class.
|
||||
pub fn set_protected_namespace(&mut self, ns: Namespace<'gc>) {
|
||||
self.protected_namespace = Some(ns)
|
||||
}
|
||||
|
||||
/// Construct a class from a `TranslationUnit` and it's class index.
|
||||
///
|
||||
/// The returned class will be allocated, but no traits will be loaded. The
|
||||
|
@ -149,14 +202,25 @@ impl<'gc> Class<'gc> {
|
|||
let instance_init = unit.load_method(abc_instance.init_method.0, mc)?;
|
||||
let class_init = unit.load_method(abc_class.init_method.0, mc)?;
|
||||
|
||||
let mut attributes = EnumSet::new();
|
||||
if abc_instance.is_sealed {
|
||||
attributes |= ClassAttributes::Sealed;
|
||||
}
|
||||
|
||||
if abc_instance.is_final {
|
||||
attributes |= ClassAttributes::Final;
|
||||
}
|
||||
|
||||
if abc_instance.is_interface {
|
||||
attributes |= ClassAttributes::Interface;
|
||||
}
|
||||
|
||||
Ok(GcCell::allocate(
|
||||
mc,
|
||||
Self {
|
||||
name,
|
||||
super_class,
|
||||
is_sealed: abc_instance.is_sealed,
|
||||
is_final: abc_instance.is_final,
|
||||
is_interface: abc_instance.is_interface,
|
||||
attributes: CollectWrapper(attributes),
|
||||
protected_namespace,
|
||||
interfaces,
|
||||
instance_init,
|
||||
|
@ -221,6 +285,14 @@ impl<'gc> Class<'gc> {
|
|||
&self.super_class
|
||||
}
|
||||
|
||||
/// Define a trait on the class.
|
||||
///
|
||||
/// Class traits will be accessible as properties on the class constructor
|
||||
/// function.
|
||||
pub fn define_class_trait(&mut self, my_trait: Trait<'gc>) {
|
||||
self.class_traits.push(my_trait);
|
||||
}
|
||||
|
||||
/// Given a name, append class traits matching the name to a list of known
|
||||
/// traits.
|
||||
///
|
||||
|
@ -265,6 +337,15 @@ impl<'gc> Class<'gc> {
|
|||
None
|
||||
}
|
||||
|
||||
/// Define a trait on instances of the class.
|
||||
///
|
||||
/// Instance traits will be accessible as properties on instances of the
|
||||
/// class. They will not be accessible on the class prototype, and any
|
||||
/// properties defined on the prototype will be shadowed by these traits.
|
||||
pub fn define_instance_trait(&mut self, my_trait: Trait<'gc>) {
|
||||
self.class_traits.push(my_trait);
|
||||
}
|
||||
|
||||
/// Given a name, append instance traits matching the name to a list of
|
||||
/// known traits.
|
||||
///
|
||||
|
@ -322,4 +403,8 @@ impl<'gc> Class<'gc> {
|
|||
pub fn interfaces(&self) -> &[Multiname<'gc>] {
|
||||
&self.interfaces
|
||||
}
|
||||
|
||||
pub fn implements(&mut self, iface: Multiname<'gc>) {
|
||||
self.interfaces.push(iface)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
//! Global scope built-ins
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::NativeMethod;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::{FunctionObject, ScriptObject};
|
||||
use crate::avm2::object::{Object, TObject};
|
||||
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::Trait;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::{Collect, MutationContext};
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
use std::f64::NAN;
|
||||
|
||||
mod boolean;
|
||||
|
@ -49,6 +51,34 @@ pub struct SystemPrototypes<'gc> {
|
|||
pub namespace: Object<'gc>,
|
||||
}
|
||||
|
||||
impl<'gc> SystemPrototypes<'gc> {
|
||||
/// Construct a minimal set of system prototypes necessary for
|
||||
/// bootstrapping player globals.
|
||||
///
|
||||
/// All other system prototypes aside from the three given here will be set
|
||||
/// to the empty object also handed to this function. It is the caller's
|
||||
/// responsibility to instantiate each class and replace the empty object
|
||||
/// with that.
|
||||
fn new(
|
||||
object: Object<'gc>,
|
||||
function: Object<'gc>,
|
||||
class: Object<'gc>,
|
||||
empty: Object<'gc>,
|
||||
) -> Self {
|
||||
SystemPrototypes {
|
||||
object,
|
||||
function,
|
||||
class,
|
||||
string: empty,
|
||||
boolean: empty,
|
||||
number: empty,
|
||||
int: empty,
|
||||
uint: empty,
|
||||
namespace: empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a free-function builtin to the global scope.
|
||||
fn function<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
|
@ -67,25 +97,47 @@ fn function<'gc>(
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
/// Add a class builtin to the global scope.
|
||||
fn class<'gc>(
|
||||
/// Add a class builtin with prototype methods to the global scope.
|
||||
///
|
||||
/// Since the function has to return a normal prototype object in this case, we
|
||||
/// have to construct a constructor to go along with it, as if we had called
|
||||
/// `install_foreign_trait` with such a class.
|
||||
fn dynamic_class<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
mut global_scope: Object<'gc>,
|
||||
package: impl Into<AvmString<'gc>>,
|
||||
name: impl Into<AvmString<'gc>>,
|
||||
constr: NativeMethod<'gc>,
|
||||
proto: Object<'gc>,
|
||||
fn_proto: Object<'gc>,
|
||||
constr: Object<'gc>,
|
||||
) {
|
||||
global_scope
|
||||
.install_dynamic_property(
|
||||
mc,
|
||||
QName::new(Namespace::package(package), name),
|
||||
FunctionObject::from_builtin_constr(mc, constr, proto, fn_proto)
|
||||
.unwrap()
|
||||
.into(),
|
||||
)
|
||||
.unwrap();
|
||||
let name = constr
|
||||
.as_class()
|
||||
.expect("constrs have classes in them")
|
||||
.read()
|
||||
.name()
|
||||
.clone();
|
||||
|
||||
global_scope.install_const(mc, name, 0, constr.into());
|
||||
}
|
||||
|
||||
/// Add a class builtin to the global scope.
|
||||
///
|
||||
/// This function returns a prototype which may be stored in `SystemPrototypes`.
|
||||
fn class<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
mut global: Object<'gc>,
|
||||
class_def: GcCell<'gc, Class<'gc>>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let class_trait = Trait::from_class(class_def);
|
||||
let global_scope = Scope::push_scope(global.get_scope(), global, activation.context.gc_context);
|
||||
let mut constr = global
|
||||
.install_foreign_trait(activation, class_trait, Some(global_scope), global)?
|
||||
.coerce_to_object(activation)?;
|
||||
|
||||
constr
|
||||
.get_property(
|
||||
constr,
|
||||
&QName::new(Namespace::public_namespace(), "prototype"),
|
||||
activation,
|
||||
)?
|
||||
.coerce_to_object(activation)
|
||||
}
|
||||
|
||||
/// Add a builtin constant to the global scope.
|
||||
|
@ -99,181 +151,132 @@ fn constant<'gc>(
|
|||
global_scope.install_const(mc, QName::new(Namespace::package(package), name), 0, value)
|
||||
}
|
||||
|
||||
/// Construct a new global scope.
|
||||
/// Initialize all remaining builtin classes.
|
||||
///
|
||||
/// This function returns both the global scope object, as well as all builtin
|
||||
/// prototypes that other parts of the VM will need to use.
|
||||
pub fn construct_global_scope<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> (Object<'gc>, SystemPrototypes<'gc>) {
|
||||
let gs = ScriptObject::bare_object(mc);
|
||||
/// This should be called only once, to construct the global scope of the
|
||||
/// player. It will return a list of prototypes it has created, which should be
|
||||
/// stored on the AVM.
|
||||
pub fn load_player_globals<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Result<(), Error> {
|
||||
let gs = activation.avm2().globals();
|
||||
|
||||
// public / root package
|
||||
let object_proto = ScriptObject::bare_object(mc);
|
||||
let fn_proto = function::create_proto(mc, object_proto);
|
||||
let class_proto = class::create_proto(mc, object_proto, fn_proto);
|
||||
let string_proto = string::create_proto(mc, object_proto, fn_proto);
|
||||
let boolean_proto = boolean::create_proto(mc, object_proto, fn_proto);
|
||||
let number_proto = number::create_proto(mc, object_proto, fn_proto);
|
||||
let int_proto = int::create_proto(mc, object_proto, fn_proto);
|
||||
let uint_proto = uint::create_proto(mc, object_proto, fn_proto);
|
||||
let namespace_proto = namespace::create_proto(mc, object_proto, fn_proto);
|
||||
let object_proto = object::create_proto(activation);
|
||||
let (function_constr, fn_proto) = function::create_class(activation, object_proto);
|
||||
let (class_constr, class_proto) = class::create_class(activation, object_proto, fn_proto);
|
||||
|
||||
object::fill_proto(mc, object_proto, fn_proto);
|
||||
let object_constr = object::fill_proto(activation.context.gc_context, object_proto, fn_proto);
|
||||
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"",
|
||||
"Object",
|
||||
object::constructor,
|
||||
dynamic_class(activation.context.gc_context, gs, object_constr);
|
||||
dynamic_class(activation.context.gc_context, gs, function_constr);
|
||||
dynamic_class(activation.context.gc_context, gs, class_constr);
|
||||
|
||||
// At this point, we need at least a partial set of system prototypes in
|
||||
// order to continue initializing the player. The rest of the prototypes
|
||||
// are set to a bare object until we have a chance to initialize them.
|
||||
activation.context.avm2.system_prototypes = Some(SystemPrototypes::new(
|
||||
object_proto,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"",
|
||||
"Function",
|
||||
function::constructor,
|
||||
fn_proto,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"",
|
||||
"Class",
|
||||
class::constructor,
|
||||
class_proto,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
ScriptObject::bare_object(activation.context.gc_context),
|
||||
));
|
||||
|
||||
// Even sillier: for the sake of clarity and the borrow checker we need to
|
||||
// clone the prototypes list and modify it outside of the activation. This
|
||||
// also has the side effect that none of these classes can get at each
|
||||
// other from the activation they're handed.
|
||||
let mut sp = activation.context.avm2.system_prototypes.clone().unwrap();
|
||||
|
||||
sp.string = class(
|
||||
activation,
|
||||
gs,
|
||||
string::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
sp.boolean = class(
|
||||
activation,
|
||||
gs,
|
||||
boolean::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
sp.number = class(
|
||||
activation,
|
||||
gs,
|
||||
number::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
sp.int = class(
|
||||
activation,
|
||||
gs,
|
||||
int::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
sp.uint = class(
|
||||
activation,
|
||||
gs,
|
||||
uint::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
sp.namespace = class(
|
||||
activation,
|
||||
gs,
|
||||
namespace::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
|
||||
activation.context.avm2.system_prototypes = Some(sp);
|
||||
|
||||
function(
|
||||
activation.context.gc_context,
|
||||
gs,
|
||||
"",
|
||||
"String",
|
||||
string::constructor,
|
||||
string_proto,
|
||||
"trace",
|
||||
trace,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
constant(
|
||||
activation.context.gc_context,
|
||||
gs,
|
||||
"",
|
||||
"Boolean",
|
||||
boolean::constructor,
|
||||
boolean_proto,
|
||||
fn_proto,
|
||||
"undefined",
|
||||
Value::Undefined,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
constant(activation.context.gc_context, gs, "", "null", Value::Null);
|
||||
constant(activation.context.gc_context, gs, "", "NaN", NAN.into());
|
||||
constant(
|
||||
activation.context.gc_context,
|
||||
gs,
|
||||
"",
|
||||
"Number",
|
||||
number::constructor,
|
||||
number_proto,
|
||||
fn_proto,
|
||||
"Infinity",
|
||||
f64::INFINITY.into(),
|
||||
);
|
||||
class(mc, gs, "", "int", int::constructor, int_proto, fn_proto);
|
||||
class(mc, gs, "", "uint", uint::constructor, uint_proto, fn_proto);
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"",
|
||||
"Namespace",
|
||||
namespace::constructor,
|
||||
namespace_proto,
|
||||
fn_proto,
|
||||
);
|
||||
function(mc, gs, "", "trace", trace, fn_proto);
|
||||
constant(mc, gs, "", "undefined", Value::Undefined);
|
||||
constant(mc, gs, "", "null", Value::Null);
|
||||
constant(mc, gs, "", "NaN", NAN.into());
|
||||
constant(mc, gs, "", "Infinity", f64::INFINITY.into());
|
||||
|
||||
// package `flash.events`
|
||||
let eventdispatcher_proto =
|
||||
flash::events::eventdispatcher::create_proto(mc, object_proto, fn_proto);
|
||||
|
||||
class(
|
||||
mc,
|
||||
activation,
|
||||
gs,
|
||||
"flash.events",
|
||||
"EventDispatcher",
|
||||
flash::events::eventdispatcher::constructor,
|
||||
eventdispatcher_proto,
|
||||
fn_proto,
|
||||
);
|
||||
flash::events::eventdispatcher::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
|
||||
// package `flash.display`
|
||||
let displayobject_proto =
|
||||
flash::display::displayobject::create_proto(mc, eventdispatcher_proto, fn_proto);
|
||||
let interactiveobject_proto =
|
||||
flash::display::interactiveobject::create_proto(mc, displayobject_proto, fn_proto);
|
||||
let displayobjectcontainer_proto =
|
||||
flash::display::displayobjectcontainer::create_proto(mc, interactiveobject_proto, fn_proto);
|
||||
let sprite_proto =
|
||||
flash::display::sprite::create_proto(mc, displayobjectcontainer_proto, fn_proto);
|
||||
let movieclip_proto = flash::display::movieclip::create_proto(mc, sprite_proto, fn_proto);
|
||||
class(
|
||||
activation,
|
||||
gs,
|
||||
flash::display::displayobject::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
class(
|
||||
activation,
|
||||
gs,
|
||||
flash::display::interactiveobject::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
class(
|
||||
activation,
|
||||
gs,
|
||||
flash::display::displayobjectcontainer::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
class(
|
||||
activation,
|
||||
gs,
|
||||
flash::display::sprite::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
class(
|
||||
activation,
|
||||
gs,
|
||||
flash::display::movieclip::create_class(activation.context.gc_context),
|
||||
)?;
|
||||
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"flash.display",
|
||||
"DisplayObject",
|
||||
flash::display::displayobject::constructor,
|
||||
displayobject_proto,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"flash.display",
|
||||
"InteractiveObject",
|
||||
flash::display::interactiveobject::constructor,
|
||||
interactiveobject_proto,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"flash.display",
|
||||
"DisplayObjectContainer",
|
||||
flash::display::displayobjectcontainer::constructor,
|
||||
sprite_proto,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"flash.display",
|
||||
"Sprite",
|
||||
flash::display::sprite::constructor,
|
||||
sprite_proto,
|
||||
fn_proto,
|
||||
);
|
||||
class(
|
||||
mc,
|
||||
gs,
|
||||
"flash.display",
|
||||
"MovieClip",
|
||||
flash::display::movieclip::constructor,
|
||||
movieclip_proto,
|
||||
fn_proto,
|
||||
);
|
||||
|
||||
let system_prototypes = SystemPrototypes {
|
||||
object: object_proto,
|
||||
function: fn_proto,
|
||||
class: class_proto,
|
||||
string: string_proto,
|
||||
boolean: boolean_proto,
|
||||
number: number_proto,
|
||||
int: int_proto,
|
||||
uint: uint_proto,
|
||||
namespace: namespace_proto,
|
||||
};
|
||||
|
||||
(gs, system_prototypes)
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `Boolean` impl
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `Boolean`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `Boolean`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
|||
Err("Boolean constructor is a stub.".into())
|
||||
}
|
||||
|
||||
/// Construct `Boolean.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `Boolean`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `Boolean`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package(""), "Boolean"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
//! `Class` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
|
||||
/// Implements `Class`
|
||||
/// Implements `Class`'s instance initializer.
|
||||
///
|
||||
/// Notably, you cannot construct new classes this way, so this returns an
|
||||
/// error.
|
||||
pub fn constructor<'gc>(
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -18,11 +21,45 @@ pub fn constructor<'gc>(
|
|||
Err("Classes cannot be constructed.".into())
|
||||
}
|
||||
|
||||
/// Construct `Class.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implement's `Class`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Err("Classes cannot be constructed.".into())
|
||||
}
|
||||
|
||||
/// Construct `Class` and `Class.prototype`, respectively.
|
||||
pub fn create_class<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
fn_proto: Object<'gc>,
|
||||
) -> (Object<'gc>, Object<'gc>) {
|
||||
let class_class = Class::new(
|
||||
QName::new(Namespace::public_namespace(), "Class"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
|
||||
let globals = activation.avm2().globals();
|
||||
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
|
||||
let proto = ScriptObject::prototype(
|
||||
activation.context.gc_context,
|
||||
super_proto,
|
||||
class_class,
|
||||
Some(scope),
|
||||
);
|
||||
|
||||
let constr = FunctionObject::from_builtin_constr(
|
||||
activation.context.gc_context,
|
||||
instance_init,
|
||||
proto,
|
||||
fn_proto,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
(constr, proto)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `flash.display.DisplayObject` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `flash.display.DisplayObject`'s constructor.
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `flash.display.DisplayObject`'s instance constructor.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `DisplayObject.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
// TODO: Use `StageObject` here.
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `flash.display.DisplayObject`'s class constructor.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `DisplayObject`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package("flash.display"), "DisplayObject"),
|
||||
Some(QName::new(Namespace::package("flash.events"), "EventDispatcher").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `flash.display.DisplayObjectContainer` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `flash.display.DisplayObjectContainer`'s constructor.
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `flash.display.DisplayObjectContainer`'s instance constructor.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,12 +18,25 @@ pub fn constructor<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `DisplayObjectContainer.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
// TODO: Use `StageObject` here.
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `flash.display.DisplayObjectContainer`'s class constructor.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `DisplayObjectContainer`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(
|
||||
Namespace::package("flash.display"),
|
||||
"DisplayObjectContainer",
|
||||
),
|
||||
Some(QName::new(Namespace::package("flash.display"), "InteractiveObject").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `flash.display.InteractiveObject` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `flash.display.InteractiveObject`'s constructor.
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `flash.display.InteractiveObject`'s instance constructor.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `InteractiveObject.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
// TODO: Use `StageObject` here.
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `flash.display.InteractiveObject`'s class constructor.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `InteractiveObject`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package("flash.display"), "InteractiveObject"),
|
||||
Some(QName::new(Namespace::package("flash.display"), "DisplayObject").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `flash.display.MovieClip` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `flash.display.MovieClip`'s constructor.
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `flash.display.MovieClip`'s instance constructor.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `MovieClip.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
// TODO: Use `StageObject` here.
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `flash.display.MovieClip`'s class constructor.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `MovieClip`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package("flash.display"), "MovieClip"),
|
||||
Some(QName::new(Namespace::package("flash.display"), "Sprite").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `flash.display.Sprite` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `flash.display.Sprite`'s constructor.
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `flash.display.Sprite`'s instance constructor.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,12 +18,28 @@ pub fn constructor<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `Sprite.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
// TODO: Use `StageObject` here.
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `flash.display.Sprite`'s class constructor.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `Sprite`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package("flash.display"), "Sprite"),
|
||||
Some(
|
||||
QName::new(
|
||||
Namespace::package("flash.display"),
|
||||
"DisplayObjectContainer",
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `flash.events.EventDispatcher` builtin/prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `flash.events.EventDispatcher`'s constructor.
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `flash.events.EventDispatcher`'s instance constructor.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,12 +18,22 @@ pub fn constructor<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `EventDispatcher.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
// TODO: Use `StageObject` here.
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `flash.events.EventDispatcher`'s class constructor.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `EventDispatcher`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package("flash.events"), "EventDispatcher"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,25 @@
|
|||
//! Function builtin and prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
|
||||
/// Implements `Function`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `Function`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `Function`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -38,22 +49,42 @@ fn call<'gc>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Partially construct `Function.prototype`.
|
||||
///
|
||||
/// `__proto__` and other cross-linked properties of this object will *not*
|
||||
/// be defined here. The caller of this function is responsible for linking
|
||||
/// them in order to obtain a valid ECMAScript `Function` prototype. The
|
||||
/// returned object is also a bare object, which will need to be linked into
|
||||
/// the prototype of `Object`.
|
||||
pub fn create_proto<'gc>(gc_context: MutationContext<'gc, '_>, proto: Object<'gc>) -> Object<'gc> {
|
||||
let mut function_proto = ScriptObject::object(gc_context, proto);
|
||||
|
||||
function_proto.install_method(
|
||||
gc_context,
|
||||
QName::new(Namespace::as3_namespace(), "call"),
|
||||
0,
|
||||
FunctionObject::from_builtin(gc_context, call, function_proto),
|
||||
/// Construct `Function` and `Function.prototype`, respectively.
|
||||
pub fn create_class<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
proto: Object<'gc>,
|
||||
) -> (Object<'gc>, Object<'gc>) {
|
||||
let function_class = Class::new(
|
||||
QName::new(Namespace::public_namespace(), "Function"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
|
||||
function_proto
|
||||
let globals = activation.avm2().globals();
|
||||
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
|
||||
let mut function_proto = ScriptObject::prototype(
|
||||
activation.context.gc_context,
|
||||
proto,
|
||||
function_class,
|
||||
Some(scope),
|
||||
);
|
||||
|
||||
function_proto.install_method(
|
||||
activation.context.gc_context,
|
||||
QName::new(Namespace::as3_namespace(), "call"),
|
||||
0,
|
||||
FunctionObject::from_builtin(activation.context.gc_context, call, function_proto),
|
||||
);
|
||||
|
||||
let constr = FunctionObject::from_builtin_constr(
|
||||
activation.context.gc_context,
|
||||
instance_init,
|
||||
proto,
|
||||
function_proto,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
(constr, function_proto)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `int` impl
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `int`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `int`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
|||
Err("int constructor is a stub.".into())
|
||||
}
|
||||
|
||||
/// Construct `int.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `int`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `int`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package(""), "int"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `Namespace` impl
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `Namespace`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `Namespace`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
|||
Err("Namespace constructor is a stub.".into())
|
||||
}
|
||||
|
||||
/// Construct `Namespace.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `Namespace`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `Namespace`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package(""), "Namespace"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `Number` impl
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `Number`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `Number`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
|||
Err("Number constructor is a stub.".into())
|
||||
}
|
||||
|
||||
/// Construct `Number.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `Number`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `Number`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package(""), "Number"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
//! Object builtin and prototype
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::{FunctionObject, Object, TObject};
|
||||
use crate::avm2::object::{FunctionObject, Object, ScriptObject, TObject};
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
|
||||
/// Implements `Object`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `Object`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Implements `Object`'s class initializer
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -140,7 +152,26 @@ pub fn set_property_is_enumerable<'gc>(
|
|||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Partially construct `Object.prototype`.
|
||||
/// Create object prototype.
|
||||
///
|
||||
/// This function creates a suitable class and object prototype attached to it,
|
||||
/// but does not actually fill it with methods. That requires a valid function
|
||||
/// prototype, and is thus done by `fill_proto` below.
|
||||
pub fn create_proto<'gc>(activation: &mut Activation<'_, 'gc, '_>) -> Object<'gc> {
|
||||
let object_class = Class::new(
|
||||
QName::new(Namespace::public_namespace(), "Object"),
|
||||
None,
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
|
||||
let globals = activation.avm2().globals();
|
||||
let scope = Scope::push_scope(globals.get_scope(), globals, activation.context.gc_context);
|
||||
ScriptObject::bare_prototype(activation.context.gc_context, object_class, Some(scope))
|
||||
}
|
||||
|
||||
/// Finish constructing `Object.prototype`, and also construct `Object`.
|
||||
///
|
||||
/// `__proto__` and other cross-linked properties of this object will *not*
|
||||
/// be defined here. The caller of this function is responsible for linking
|
||||
|
@ -153,7 +184,7 @@ pub fn fill_proto<'gc>(
|
|||
gc_context: MutationContext<'gc, '_>,
|
||||
mut object_proto: Object<'gc>,
|
||||
fn_proto: Object<'gc>,
|
||||
) {
|
||||
) -> Object<'gc> {
|
||||
object_proto.install_method(
|
||||
gc_context,
|
||||
QName::new(Namespace::public_namespace(), "toString"),
|
||||
|
@ -196,4 +227,6 @@ pub fn fill_proto<'gc>(
|
|||
0,
|
||||
FunctionObject::from_builtin(gc_context, set_property_is_enumerable, fn_proto),
|
||||
);
|
||||
|
||||
FunctionObject::from_builtin_constr(gc_context, instance_init, object_proto, fn_proto).unwrap()
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `String` impl
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `String`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `String`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
|||
Err("String constructor is a stub.".into())
|
||||
}
|
||||
|
||||
/// Construct `String.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `String`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `String`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package(""), "String"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
//! `uint` impl
|
||||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::object::{Object, ScriptObject};
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::Method;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::Object;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::MutationContext;
|
||||
use gc_arena::{GcCell, MutationContext};
|
||||
|
||||
/// Implements `uint`
|
||||
pub fn constructor<'gc>(
|
||||
/// Implements `uint`'s instance initializer.
|
||||
pub fn instance_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
|
@ -15,11 +18,22 @@ pub fn constructor<'gc>(
|
|||
Err("uint constructor is a stub.".into())
|
||||
}
|
||||
|
||||
/// Construct `uint.prototype`.
|
||||
pub fn create_proto<'gc>(
|
||||
mc: MutationContext<'gc, '_>,
|
||||
super_proto: Object<'gc>,
|
||||
_fn_proto: Object<'gc>,
|
||||
) -> Object<'gc> {
|
||||
ScriptObject::object(mc, super_proto)
|
||||
/// Implements `uint`'s class initializer.
|
||||
pub fn class_init<'gc>(
|
||||
_activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
Ok(Value::Undefined)
|
||||
}
|
||||
|
||||
/// Construct `uint`'s class.
|
||||
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
|
||||
Class::new(
|
||||
QName::new(Namespace::package(""), "uint"),
|
||||
Some(QName::new(Namespace::public_namespace(), "Object").into()),
|
||||
Method::from_builtin(instance_init),
|
||||
Method::from_builtin(class_init),
|
||||
mc,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,15 +5,12 @@ use crate::avm2::object::Object;
|
|||
use crate::avm2::script::TranslationUnit;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use crate::collect::CollectWrapper;
|
||||
use gc_arena::{Collect, CollectionContext, Gc, MutationContext};
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use swf::avm2::types::{AbcFile, Index, Method as AbcMethod, MethodBody as AbcMethodBody};
|
||||
|
||||
#[derive(Clone, Debug, Collect)]
|
||||
#[collect(require_static)]
|
||||
pub struct CollectWrapper<T>(T);
|
||||
|
||||
/// Represents a function defined in Ruffle's code.
|
||||
///
|
||||
/// Parameters are as follows:
|
||||
|
@ -162,6 +159,12 @@ impl<'gc> From<Gc<'gc, BytecodeMethod<'gc>>> for Method<'gc> {
|
|||
}
|
||||
|
||||
impl<'gc> Method<'gc> {
|
||||
/// Builtin method constructor, because for some reason `nf.into()` just
|
||||
/// causes odd lifetime mismatches.
|
||||
pub fn from_builtin(nf: NativeMethod<'gc>) -> Self {
|
||||
Self::Native(nf)
|
||||
}
|
||||
|
||||
/// Access the bytecode of this method.
|
||||
///
|
||||
/// This function returns `Err` if there is no bytecode for this method.
|
||||
|
|
|
@ -357,3 +357,12 @@ impl<'gc> Multiname<'gc> {
|
|||
self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gc> From<QName<'gc>> for Multiname<'gc> {
|
||||
fn from(q: QName<'gc>) -> Self {
|
||||
Self {
|
||||
ns: vec![q.ns],
|
||||
name: Some(q.name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ use crate::avm2::activation::Activation;
|
|||
use crate::avm2::class::Class;
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::names::{Multiname, Namespace, QName};
|
||||
use crate::avm2::r#trait::{Trait, TraitKind};
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::{Trait, TraitKind};
|
||||
use crate::avm2::value::{Hint, Value};
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
|
@ -415,23 +415,29 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
/// bound to. It should always be `self` except when doing things with
|
||||
/// `super`, which needs to create bound methods pointing to a different
|
||||
/// object.
|
||||
///
|
||||
/// The value of the trait at the time of installation will be returned
|
||||
/// here.
|
||||
fn install_trait(
|
||||
&mut self,
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
trait_entry: Trait<'gc>,
|
||||
reciever: Object<'gc>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
self.install_foreign_trait(activation, trait_entry, self.get_scope(), reciever)
|
||||
}
|
||||
|
||||
/// Install a trait from anywyere.
|
||||
///
|
||||
/// The value of the trait at the time of installation will be returned
|
||||
/// here.
|
||||
fn install_foreign_trait(
|
||||
&mut self,
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
trait_entry: Trait<'gc>,
|
||||
scope: Option<GcCell<'gc, Scope<'gc>>>,
|
||||
reciever: Object<'gc>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
let fn_proto = activation.avm2().prototypes().function;
|
||||
let trait_name = trait_entry.name().clone();
|
||||
avm_debug!(
|
||||
|
@ -447,12 +453,15 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
default_value,
|
||||
..
|
||||
} => {
|
||||
let value = default_value.clone().unwrap_or(Value::Undefined);
|
||||
self.install_slot(
|
||||
activation.context.gc_context,
|
||||
trait_name,
|
||||
*slot_id,
|
||||
default_value.clone().unwrap_or(Value::Undefined),
|
||||
value.clone(),
|
||||
);
|
||||
|
||||
Ok(value)
|
||||
}
|
||||
TraitKind::Method {
|
||||
disp_id, method, ..
|
||||
|
@ -470,6 +479,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
*disp_id,
|
||||
function,
|
||||
);
|
||||
|
||||
Ok(function.into())
|
||||
}
|
||||
TraitKind::Getter {
|
||||
disp_id, method, ..
|
||||
|
@ -487,6 +498,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
*disp_id,
|
||||
function,
|
||||
)?;
|
||||
|
||||
Ok(function.into())
|
||||
}
|
||||
TraitKind::Setter {
|
||||
disp_id, method, ..
|
||||
|
@ -504,6 +517,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
*disp_id,
|
||||
function,
|
||||
)?;
|
||||
|
||||
Ok(function.into())
|
||||
}
|
||||
TraitKind::Class { slot_id, class } => {
|
||||
let class_read = class.read();
|
||||
|
@ -533,6 +548,8 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
*slot_id,
|
||||
class_object.into(),
|
||||
);
|
||||
|
||||
Ok(class_object.into())
|
||||
}
|
||||
TraitKind::Function {
|
||||
slot_id, function, ..
|
||||
|
@ -561,22 +578,25 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
*slot_id,
|
||||
fobject.into(),
|
||||
);
|
||||
|
||||
Ok(fobject.into())
|
||||
}
|
||||
TraitKind::Const {
|
||||
slot_id,
|
||||
default_value,
|
||||
..
|
||||
} => {
|
||||
let value = default_value.clone().unwrap_or(Value::Undefined);
|
||||
self.install_const(
|
||||
activation.context.gc_context,
|
||||
trait_name,
|
||||
*slot_id,
|
||||
default_value.clone().unwrap_or(Value::Undefined),
|
||||
value.clone(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Call the object.
|
||||
|
@ -703,6 +723,9 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
/// Get a raw pointer value for this object.
|
||||
fn as_ptr(&self) -> *const ObjectPtr;
|
||||
|
||||
/// Get this object's `Class`, if it has one.
|
||||
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>>;
|
||||
|
||||
/// Get this object's `Executable`, if it has one.
|
||||
fn as_executable(&self) -> Option<Executable<'gc>> {
|
||||
None
|
||||
|
|
|
@ -179,6 +179,10 @@ macro_rules! impl_avm2_custom_object {
|
|||
self.0.as_ptr() as *const ObjectPtr
|
||||
}
|
||||
|
||||
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
|
||||
self.0.read().base.as_class()
|
||||
}
|
||||
|
||||
fn install_method(
|
||||
&mut self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
|
|
|
@ -7,9 +7,9 @@ use crate::avm2::method::{Method, NativeMethod};
|
|||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::script_object::{ScriptObject, ScriptObjectClass, ScriptObjectData};
|
||||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||
use crate::avm2::r#trait::Trait;
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::Trait;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use crate::impl_avm2_custom_object;
|
||||
|
@ -195,10 +195,15 @@ impl<'gc> FunctionObject<'gc> {
|
|||
mut prototype: Object<'gc>,
|
||||
fn_proto: Object<'gc>,
|
||||
) -> Result<Object<'gc>, Error> {
|
||||
let scope = prototype.get_scope();
|
||||
let class = prototype
|
||||
.as_class()
|
||||
.map(|c| ScriptObjectClass::ClassConstructor(c, scope))
|
||||
.unwrap_or(ScriptObjectClass::NoClass);
|
||||
let mut base: Object<'gc> = FunctionObject(GcCell::allocate(
|
||||
mc,
|
||||
FunctionObjectData {
|
||||
base: ScriptObjectData::base_new(Some(fn_proto), ScriptObjectClass::NoClass),
|
||||
base: ScriptObjectData::base_new(Some(fn_proto), class),
|
||||
exec: Some(Executable::from_method(constr.into(), None, None, mc)),
|
||||
},
|
||||
))
|
||||
|
|
|
@ -6,8 +6,8 @@ use crate::avm2::class::Class;
|
|||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData};
|
||||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||
use crate::avm2::r#trait::Trait;
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::traits::Trait;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use crate::impl_avm2_custom_object;
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
use crate::avm2::activation::Activation;
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::function::Executable;
|
||||
use crate::avm2::names::{Namespace, QName};
|
||||
use crate::avm2::object::script_object::{ScriptObjectClass, ScriptObjectData};
|
||||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||
use crate::avm2::r#trait::Trait;
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::Trait;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use crate::impl_avm2_custom_object;
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
|
||||
/// An Object which represents a primitive value of some other kind.
|
||||
|
@ -50,181 +50,14 @@ impl<'gc> PrimitiveObject<'gc> {
|
|||
}
|
||||
|
||||
impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
|
||||
fn get_property_local(
|
||||
self,
|
||||
reciever: Object<'gc>,
|
||||
name: &QName<'gc>,
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
) -> Result<Value<'gc>, Error> {
|
||||
let read = self.0.read();
|
||||
let rv = read.base.get_property_local(reciever, name, activation)?;
|
||||
impl_avm2_custom_object!(base);
|
||||
|
||||
drop(read);
|
||||
|
||||
rv.resolve(activation)
|
||||
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
||||
Ok(self.0.read().primitive.clone())
|
||||
}
|
||||
|
||||
fn set_property_local(
|
||||
self,
|
||||
reciever: Object<'gc>,
|
||||
name: &QName<'gc>,
|
||||
value: Value<'gc>,
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
) -> Result<(), Error> {
|
||||
let mut write = self.0.write(activation.context.gc_context);
|
||||
let rv = write
|
||||
.base
|
||||
.set_property_local(reciever, name, value, activation)?;
|
||||
|
||||
drop(write);
|
||||
|
||||
rv.resolve(activation)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_property_local(
|
||||
self,
|
||||
reciever: Object<'gc>,
|
||||
name: &QName<'gc>,
|
||||
value: Value<'gc>,
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
) -> Result<(), Error> {
|
||||
let mut write = self.0.write(activation.context.gc_context);
|
||||
let rv = write
|
||||
.base
|
||||
.init_property_local(reciever, name, value, activation)?;
|
||||
|
||||
drop(write);
|
||||
|
||||
rv.resolve(activation)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_property_overwritable(
|
||||
self,
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
name: &QName<'gc>,
|
||||
) -> bool {
|
||||
self.0.write(gc_context).base.is_property_overwritable(name)
|
||||
}
|
||||
|
||||
fn delete_property(
|
||||
&self,
|
||||
gc_context: MutationContext<'gc, '_>,
|
||||
multiname: &QName<'gc>,
|
||||
) -> bool {
|
||||
self.0.write(gc_context).base.delete_property(multiname)
|
||||
}
|
||||
|
||||
fn get_slot(self, id: u32) -> Result<Value<'gc>, Error> {
|
||||
self.0.read().base.get_slot(id)
|
||||
}
|
||||
|
||||
fn set_slot(
|
||||
self,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.write(mc).base.set_slot(id, value, mc)
|
||||
}
|
||||
|
||||
fn init_slot(
|
||||
self,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.write(mc).base.init_slot(id, value, mc)
|
||||
}
|
||||
|
||||
fn get_method(self, id: u32) -> Option<Object<'gc>> {
|
||||
self.0.read().base.get_method(id)
|
||||
}
|
||||
|
||||
fn get_trait(self, name: &QName<'gc>) -> Result<Vec<Trait<'gc>>, Error> {
|
||||
self.0.read().base.get_trait(name)
|
||||
}
|
||||
|
||||
fn get_provided_trait(
|
||||
&self,
|
||||
name: &QName<'gc>,
|
||||
known_traits: &mut Vec<Trait<'gc>>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.read().base.get_provided_trait(name, known_traits)
|
||||
}
|
||||
|
||||
fn get_scope(self) -> Option<GcCell<'gc, Scope<'gc>>> {
|
||||
self.0.read().base.get_scope()
|
||||
}
|
||||
|
||||
fn resolve_any(self, local_name: AvmString<'gc>) -> Result<Option<Namespace<'gc>>, Error> {
|
||||
self.0.read().base.resolve_any(local_name)
|
||||
}
|
||||
|
||||
fn resolve_any_trait(
|
||||
self,
|
||||
local_name: AvmString<'gc>,
|
||||
) -> Result<Option<Namespace<'gc>>, Error> {
|
||||
self.0.read().base.resolve_any_trait(local_name)
|
||||
}
|
||||
|
||||
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {
|
||||
self.0.read().base.has_own_property(name)
|
||||
}
|
||||
|
||||
fn has_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
|
||||
self.0.read().base.has_trait(name)
|
||||
}
|
||||
|
||||
fn provides_trait(self, name: &QName<'gc>) -> Result<bool, Error> {
|
||||
self.0.read().base.provides_trait(name)
|
||||
}
|
||||
|
||||
fn has_instantiated_property(self, name: &QName<'gc>) -> bool {
|
||||
self.0.read().base.has_instantiated_property(name)
|
||||
}
|
||||
|
||||
fn has_own_virtual_getter(self, name: &QName<'gc>) -> bool {
|
||||
self.0.read().base.has_own_virtual_getter(name)
|
||||
}
|
||||
|
||||
fn has_own_virtual_setter(self, name: &QName<'gc>) -> bool {
|
||||
self.0.read().base.has_own_virtual_setter(name)
|
||||
}
|
||||
|
||||
fn proto(&self) -> Option<Object<'gc>> {
|
||||
self.0.read().base.proto()
|
||||
}
|
||||
|
||||
fn get_enumerant_name(&self, index: u32) -> Option<QName<'gc>> {
|
||||
self.0.read().base.get_enumerant_name(index)
|
||||
}
|
||||
|
||||
fn property_is_enumerable(&self, name: &QName<'gc>) -> bool {
|
||||
self.0.read().base.property_is_enumerable(name)
|
||||
}
|
||||
|
||||
fn set_local_property_is_enumerable(
|
||||
&self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
name: &QName<'gc>,
|
||||
is_enumerable: bool,
|
||||
) -> Result<(), Error> {
|
||||
self.0
|
||||
.write(mc)
|
||||
.base
|
||||
.set_local_property_is_enumerable(name, is_enumerable)
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> *const ObjectPtr {
|
||||
self.0.as_ptr() as *const ObjectPtr
|
||||
}
|
||||
|
||||
fn as_executable(&self) -> Option<Executable<'gc>> {
|
||||
None
|
||||
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
||||
Ok(self.0.read().primitive.clone())
|
||||
}
|
||||
|
||||
fn construct(
|
||||
|
@ -266,88 +99,4 @@ impl<'gc> TObject<'gc> for PrimitiveObject<'gc> {
|
|||
))
|
||||
.into())
|
||||
}
|
||||
|
||||
fn to_string(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
||||
Ok(self.0.read().primitive.clone())
|
||||
}
|
||||
|
||||
fn value_of(&self, _mc: MutationContext<'gc, '_>) -> Result<Value<'gc>, Error> {
|
||||
Ok(self.0.read().primitive.clone())
|
||||
}
|
||||
|
||||
fn install_method(
|
||||
&mut self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
name: QName<'gc>,
|
||||
disp_id: u32,
|
||||
function: Object<'gc>,
|
||||
) {
|
||||
self.0
|
||||
.write(mc)
|
||||
.base
|
||||
.install_method(name, disp_id, function)
|
||||
}
|
||||
|
||||
fn install_getter(
|
||||
&mut self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
name: QName<'gc>,
|
||||
disp_id: u32,
|
||||
function: Object<'gc>,
|
||||
) -> Result<(), Error> {
|
||||
self.0
|
||||
.write(mc)
|
||||
.base
|
||||
.install_getter(name, disp_id, function)
|
||||
}
|
||||
|
||||
fn install_setter(
|
||||
&mut self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
name: QName<'gc>,
|
||||
disp_id: u32,
|
||||
function: Object<'gc>,
|
||||
) -> Result<(), Error> {
|
||||
self.0
|
||||
.write(mc)
|
||||
.base
|
||||
.install_setter(name, disp_id, function)
|
||||
}
|
||||
|
||||
fn install_dynamic_property(
|
||||
&mut self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
name: QName<'gc>,
|
||||
value: Value<'gc>,
|
||||
) -> Result<(), Error> {
|
||||
self.0.write(mc).base.install_dynamic_property(name, value)
|
||||
}
|
||||
|
||||
fn install_slot(
|
||||
&mut self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
name: QName<'gc>,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
) {
|
||||
self.0.write(mc).base.install_slot(name, id, value)
|
||||
}
|
||||
|
||||
fn install_const(
|
||||
&mut self,
|
||||
mc: MutationContext<'gc, '_>,
|
||||
name: QName<'gc>,
|
||||
id: u32,
|
||||
value: Value<'gc>,
|
||||
) {
|
||||
self.0.write(mc).base.install_const(name, id, value)
|
||||
}
|
||||
|
||||
fn interfaces(&self) -> Vec<Object<'gc>> {
|
||||
self.0.read().base.interfaces()
|
||||
}
|
||||
|
||||
fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
|
||||
self.0.write(context).base.set_interfaces(iface_list)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ use crate::avm2::names::{Namespace, QName};
|
|||
use crate::avm2::object::{Object, ObjectPtr, TObject};
|
||||
use crate::avm2::property::Property;
|
||||
use crate::avm2::property_map::PropertyMap;
|
||||
use crate::avm2::r#trait::Trait;
|
||||
use crate::avm2::return_value::ReturnValue;
|
||||
use crate::avm2::scope::Scope;
|
||||
use crate::avm2::slot::Slot;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::Trait;
|
||||
use crate::avm2::value::Value;
|
||||
use crate::avm2::Error;
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
|
@ -337,6 +337,10 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
|
|||
fn set_interfaces(&self, context: MutationContext<'gc, '_>, iface_list: Vec<Object<'gc>>) {
|
||||
self.0.write(context).set_interfaces(iface_list)
|
||||
}
|
||||
|
||||
fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
|
||||
self.0.read().as_class()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gc> ScriptObject<'gc> {
|
||||
|
@ -897,4 +901,13 @@ impl<'gc> ScriptObjectData<'gc> {
|
|||
pub fn set_interfaces(&mut self, iface_list: Vec<Object<'gc>>) {
|
||||
self.interfaces = iface_list;
|
||||
}
|
||||
|
||||
/// Get the class for this object, if it has one.
|
||||
pub fn as_class(&self) -> Option<GcCell<'gc, Class<'gc>>> {
|
||||
match self.class {
|
||||
ScriptObjectClass::ClassConstructor(class, _) => Some(class),
|
||||
ScriptObjectClass::InstancePrototype(class, _) => Some(class),
|
||||
ScriptObjectClass::NoClass => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,19 +2,16 @@
|
|||
|
||||
use crate::avm2::class::Class;
|
||||
use crate::avm2::method::{BytecodeMethod, Method};
|
||||
use crate::avm2::r#trait::Trait;
|
||||
use crate::avm2::string::AvmString;
|
||||
use crate::avm2::traits::Trait;
|
||||
use crate::avm2::{Avm2, Error};
|
||||
use crate::collect::CollectWrapper;
|
||||
use fnv::FnvHashMap;
|
||||
use gc_arena::{Collect, Gc, GcCell, MutationContext};
|
||||
use std::mem::drop;
|
||||
use std::rc::Rc;
|
||||
use swf::avm2::types::{AbcFile, Index, Script as AbcScript};
|
||||
|
||||
#[derive(Clone, Debug, Collect)]
|
||||
#[collect(require_static)]
|
||||
pub struct CollectWrapper<T>(T);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Collect)]
|
||||
#[collect(no_drop)]
|
||||
pub struct TranslationUnit<'gc>(GcCell<'gc, TranslationUnitData<'gc>>);
|
||||
|
|
|
@ -6,9 +6,23 @@ use crate::avm2::names::{Multiname, QName};
|
|||
use crate::avm2::script::TranslationUnit;
|
||||
use crate::avm2::value::{abc_default_value, Value};
|
||||
use crate::avm2::{Avm2, Error};
|
||||
use crate::collect::CollectWrapper;
|
||||
use enumset::{EnumSet, EnumSetType};
|
||||
use gc_arena::{Collect, GcCell, MutationContext};
|
||||
use swf::avm2::types::{Trait as AbcTrait, TraitKind as AbcTraitKind};
|
||||
|
||||
/// All attributes a trait can have.
|
||||
#[derive(Debug, EnumSetType)]
|
||||
pub enum TraitAttributes {
|
||||
/// Whether or not traits in downstream classes are allowed to override
|
||||
/// this trait.
|
||||
Final,
|
||||
|
||||
/// Whether or not this trait is intended to override an upstream class's
|
||||
/// trait.
|
||||
Override,
|
||||
}
|
||||
|
||||
/// Represents a trait as loaded into the VM.
|
||||
///
|
||||
/// A trait is an uninstantiated AVM2 property. Traits are used by objects to
|
||||
|
@ -25,18 +39,22 @@ pub struct Trait<'gc> {
|
|||
/// The name of this trait.
|
||||
name: QName<'gc>,
|
||||
|
||||
/// Whether or not traits in downstream classes are allowed to override
|
||||
/// this trait.
|
||||
is_final: bool,
|
||||
|
||||
/// Whether or not this trait is intended to override an upstream class's
|
||||
/// trait.
|
||||
is_override: bool,
|
||||
/// The attributes set on this trait.
|
||||
attributes: CollectWrapper<EnumSet<TraitAttributes>>,
|
||||
|
||||
/// The kind of trait in use.
|
||||
kind: TraitKind<'gc>,
|
||||
}
|
||||
|
||||
fn trait_attribs_from_abc_traits(abc_trait: &AbcTrait) -> CollectWrapper<EnumSet<TraitAttributes>> {
|
||||
CollectWrapper(match (abc_trait.is_final, abc_trait.is_override) {
|
||||
(true, true) => TraitAttributes::Final | TraitAttributes::Override,
|
||||
(true, false) => TraitAttributes::Final.into(),
|
||||
(false, true) => TraitAttributes::Override.into(),
|
||||
(false, false) => EnumSet::empty(),
|
||||
})
|
||||
}
|
||||
|
||||
/// The fields for a particular kind of trait.
|
||||
///
|
||||
/// The kind of a trait also determines how it's instantiated on the object.
|
||||
|
@ -81,6 +99,83 @@ pub enum TraitKind<'gc> {
|
|||
}
|
||||
|
||||
impl<'gc> Trait<'gc> {
|
||||
pub fn from_class(class: GcCell<'gc, Class<'gc>>) -> Self {
|
||||
let name = class.read().name().clone();
|
||||
|
||||
Trait {
|
||||
name,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
kind: TraitKind::Class { slot_id: 0, class },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_method(name: QName<'gc>, method: Method<'gc>) -> Self {
|
||||
Trait {
|
||||
name,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
kind: TraitKind::Method { disp_id: 0, method },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_getter(name: QName<'gc>, method: Method<'gc>) -> Self {
|
||||
Trait {
|
||||
name,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
kind: TraitKind::Getter { disp_id: 0, method },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_setter(name: QName<'gc>, method: Method<'gc>) -> Self {
|
||||
Trait {
|
||||
name,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
kind: TraitKind::Setter { disp_id: 0, method },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_function(name: QName<'gc>, function: Method<'gc>) -> Self {
|
||||
Trait {
|
||||
name,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
kind: TraitKind::Function {
|
||||
slot_id: 0,
|
||||
function,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_slot(
|
||||
name: QName<'gc>,
|
||||
type_name: Multiname<'gc>,
|
||||
default_value: Option<Value<'gc>>,
|
||||
) -> Self {
|
||||
Trait {
|
||||
name,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
kind: TraitKind::Slot {
|
||||
slot_id: 0,
|
||||
type_name,
|
||||
default_value,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_const(
|
||||
name: QName<'gc>,
|
||||
type_name: Multiname<'gc>,
|
||||
default_value: Option<Value<'gc>>,
|
||||
) -> Self {
|
||||
Trait {
|
||||
name,
|
||||
attributes: CollectWrapper(EnumSet::empty()),
|
||||
kind: TraitKind::Slot {
|
||||
slot_id: 0,
|
||||
type_name,
|
||||
default_value,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an ABC trait into a loaded trait.
|
||||
pub fn from_abc_trait(
|
||||
unit: TranslationUnit<'gc>,
|
||||
|
@ -97,8 +192,7 @@ impl<'gc> Trait<'gc> {
|
|||
value,
|
||||
} => Trait {
|
||||
name,
|
||||
is_final: abc_trait.is_final,
|
||||
is_override: abc_trait.is_override,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
kind: TraitKind::Slot {
|
||||
slot_id: *slot_id,
|
||||
type_name: if type_name.0 == 0 {
|
||||
|
@ -115,8 +209,7 @@ impl<'gc> Trait<'gc> {
|
|||
},
|
||||
AbcTraitKind::Method { disp_id, method } => Trait {
|
||||
name,
|
||||
is_final: abc_trait.is_final,
|
||||
is_override: abc_trait.is_override,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
kind: TraitKind::Method {
|
||||
disp_id: *disp_id,
|
||||
method: unit.load_method(method.0, mc)?,
|
||||
|
@ -124,8 +217,7 @@ impl<'gc> Trait<'gc> {
|
|||
},
|
||||
AbcTraitKind::Getter { disp_id, method } => Trait {
|
||||
name,
|
||||
is_final: abc_trait.is_final,
|
||||
is_override: abc_trait.is_override,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
kind: TraitKind::Getter {
|
||||
disp_id: *disp_id,
|
||||
method: unit.load_method(method.0, mc)?,
|
||||
|
@ -133,8 +225,7 @@ impl<'gc> Trait<'gc> {
|
|||
},
|
||||
AbcTraitKind::Setter { disp_id, method } => Trait {
|
||||
name,
|
||||
is_final: abc_trait.is_final,
|
||||
is_override: abc_trait.is_override,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
kind: TraitKind::Setter {
|
||||
disp_id: *disp_id,
|
||||
method: unit.load_method(method.0, mc)?,
|
||||
|
@ -142,8 +233,7 @@ impl<'gc> Trait<'gc> {
|
|||
},
|
||||
AbcTraitKind::Class { slot_id, class } => Trait {
|
||||
name,
|
||||
is_final: abc_trait.is_final,
|
||||
is_override: abc_trait.is_override,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
kind: TraitKind::Class {
|
||||
slot_id: *slot_id,
|
||||
class: unit.load_class(class.0, avm2, mc)?,
|
||||
|
@ -151,8 +241,7 @@ impl<'gc> Trait<'gc> {
|
|||
},
|
||||
AbcTraitKind::Function { slot_id, function } => Trait {
|
||||
name,
|
||||
is_final: abc_trait.is_final,
|
||||
is_override: abc_trait.is_override,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
kind: TraitKind::Function {
|
||||
slot_id: *slot_id,
|
||||
function: unit.load_method(function.0, mc)?,
|
||||
|
@ -164,8 +253,7 @@ impl<'gc> Trait<'gc> {
|
|||
value,
|
||||
} => Trait {
|
||||
name,
|
||||
is_final: abc_trait.is_final,
|
||||
is_override: abc_trait.is_override,
|
||||
attributes: trait_attribs_from_abc_traits(abc_trait),
|
||||
kind: TraitKind::Const {
|
||||
slot_id: *slot_id,
|
||||
type_name: if type_name.0 == 0 {
|
||||
|
@ -192,10 +280,27 @@ impl<'gc> Trait<'gc> {
|
|||
}
|
||||
|
||||
pub fn is_final(&self) -> bool {
|
||||
self.is_final
|
||||
self.attributes.0.contains(TraitAttributes::Final)
|
||||
}
|
||||
|
||||
pub fn is_override(&self) -> bool {
|
||||
self.is_override
|
||||
self.attributes.0.contains(TraitAttributes::Override)
|
||||
}
|
||||
|
||||
pub fn set_attributes(&mut self, attribs: EnumSet<TraitAttributes>) {
|
||||
self.attributes.0 = attribs;
|
||||
}
|
||||
|
||||
/// Set the slot or dispatch ID of this trait.
|
||||
pub fn set_slot_id(&mut self, id: u32) {
|
||||
match &mut self.kind {
|
||||
TraitKind::Slot { slot_id, .. } => *slot_id = id,
|
||||
TraitKind::Method { disp_id, .. } => *disp_id = id,
|
||||
TraitKind::Getter { disp_id, .. } => *disp_id = id,
|
||||
TraitKind::Setter { disp_id, .. } => *disp_id = id,
|
||||
TraitKind::Class { slot_id, .. } => *slot_id = id,
|
||||
TraitKind::Function { slot_id, .. } => *slot_id = id,
|
||||
TraitKind::Const { slot_id, .. } => *slot_id = id,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
//! Collect Wrapper Utility
|
||||
|
||||
use gc_arena::Collect;
|
||||
|
||||
#[derive(Clone, Debug, Collect)]
|
||||
#[collect(require_static)]
|
||||
pub struct CollectWrapper<T>(pub T);
|
|
@ -1,5 +1,6 @@
|
|||
//! Layout box structure
|
||||
|
||||
use crate::collect::CollectWrapper;
|
||||
use crate::context::UpdateContext;
|
||||
use crate::drawing::Drawing;
|
||||
use crate::font::{EvalParameters, Font};
|
||||
|
@ -552,10 +553,6 @@ pub struct LayoutBox<'gc> {
|
|||
content: LayoutContent<'gc>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Collect)]
|
||||
#[collect(require_static)]
|
||||
pub struct CollectWrapper<T>(T);
|
||||
|
||||
/// Represents different content modes of a given `LayoutBox`.
|
||||
///
|
||||
/// Currently, a `LayoutBox` can contain `Text`, `Bullet`s, or a `Drawing`.
|
||||
|
|
|
@ -18,6 +18,7 @@ mod avm1;
|
|||
mod avm2;
|
||||
mod bounding_box;
|
||||
mod character;
|
||||
mod collect;
|
||||
pub mod color_transform;
|
||||
mod context;
|
||||
mod drawing;
|
||||
|
|
|
@ -259,6 +259,7 @@ impl Player {
|
|||
storage,
|
||||
};
|
||||
|
||||
player.mutate_with_update_context(|context| Avm2::load_player_globals(context))?;
|
||||
player.build_matrices();
|
||||
player.audio.set_frame_rate(frame_rate);
|
||||
|
||||
|
|
Loading…
Reference in New Issue