Move AVM2 into the UpdateContext.

This commit is contained in:
David Wendt 2020-07-27 23:19:43 -04:00
parent bfa5f8ae35
commit 8ebf5405e2
23 changed files with 501 additions and 632 deletions

View File

@ -843,6 +843,7 @@ mod tests {
use crate::avm1::globals::system::SystemProperties;
use crate::avm1::property::Attribute::*;
use crate::avm1::{Avm1, Timers};
use crate::avm2::Avm2;
use crate::backend::audio::NullAudioBackend;
use crate::backend::input::NullInputBackend;
use crate::backend::navigator::NullNavigatorBackend;
@ -864,7 +865,8 @@ mod tests {
F: for<'a, 'gc> FnOnce(&mut Activation<'_, 'gc, '_>, Object<'gc>) -> R,
{
rootless_arena(|gc_context| {
let mut avm = Avm1::new(gc_context, swf_version);
let mut avm1 = Avm1::new(gc_context, swf_version);
let mut avm2 = Avm2::new(gc_context);
let swf = Arc::new(SwfMovie::empty(swf_version));
let mut root: DisplayObject<'_> =
MovieClip::new(SwfSlice::empty(swf.clone()), gc_context).into();
@ -872,8 +874,8 @@ mod tests {
let mut levels = BTreeMap::new();
levels.insert(0, root);
let object = ScriptObject::object(gc_context, Some(avm.prototypes().object)).into();
let globals = avm.global_object_cell();
let object = ScriptObject::object(gc_context, Some(avm1.prototypes().object)).into();
let globals = avm1.global_object_cell();
let mut context = UpdateContext {
gc_context,
@ -893,7 +895,7 @@ mod tests {
library: &mut Library::default(),
navigator: &mut NullNavigatorBackend::new(),
renderer: &mut NullRenderer::new(),
system_prototypes: avm.prototypes().clone(),
system_prototypes: avm1.prototypes().clone(),
mouse_hovered_object: None,
mouse_position: &(Twips::new(0), Twips::new(0)),
drag_object: &mut None,
@ -907,7 +909,8 @@ mod tests {
unbound_text_fields: &mut Vec::new(),
timers: &mut Timers::new(),
needs_render: &mut false,
avm1: &mut avm,
avm1: &mut avm1,
avm2: &mut avm2,
};
root.post_instantiation(&mut context, root, None, false);

View File

@ -2,6 +2,7 @@ use crate::avm1::activation::{Activation, ActivationIdentifier};
use crate::avm1::error::Error;
use crate::avm1::globals::system::SystemProperties;
use crate::avm1::{Avm1, Object, Timers, UpdateContext};
use crate::avm2::Avm2;
use crate::backend::audio::NullAudioBackend;
use crate::backend::input::NullInputBackend;
use crate::backend::navigator::NullNavigatorBackend;
@ -27,6 +28,7 @@ where
F: FnOnce(&mut Activation<'_, 'gc, '_>, Object<'gc>) -> Result<(), Error<'gc>>,
{
let mut avm1 = Avm1::new(gc_context, swf_version);
let mut avm2 = Avm2::new(gc_context);
let swf = Arc::new(SwfMovie::empty(swf_version));
let mut root: DisplayObject<'gc> =
MovieClip::new(SwfSlice::empty(swf.clone()), gc_context).into();
@ -69,6 +71,7 @@ where
timers: &mut Timers::new(),
needs_render: &mut false,
avm1: &mut avm1,
avm2: &mut avm2,
};
root.post_instantiation(&mut context, root, None, false);
root.set_name(context.gc_context, "");

View File

@ -85,20 +85,19 @@ impl<'gc> Avm2<'gc> {
/// Run a script's initializer method.
pub fn run_script_initializer(
&mut self,
script: GcCell<'gc, Script<'gc>>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut init_activation = Activation::from_script(self, context, script, self.globals)?;
let globals = context.avm2.globals;
let mut init_activation = Activation::from_script(context.reborrow(), script, globals)?;
init_activation.run_stack_frame_for_script(context, script)
init_activation.run_stack_frame_for_script(script)
}
/// Load an ABC file embedded in a `SwfSlice`.
///
/// The `SwfSlice` must resolve to the contents of an ABC file.
pub fn load_abc(
&mut self,
abc: SwfSlice,
_abc_name: &str,
_lazy_init: bool,
@ -111,16 +110,15 @@ impl<'gc> Avm2<'gc> {
for i in (0..abc_file.scripts.len()).rev() {
let script = tunit.load_script(i as u32, context.gc_context)?;
let mut globals = self.globals();
let mut globals = context.avm2.globals();
let scope = Scope::push_scope(None, globals, context.gc_context);
let mut null_activation = Activation::from_nothing(self, context);
let mut null_activation = Activation::from_nothing(context.reborrow());
// TODO: Lazyinit means we shouldn't do this until traits are
// actually mentioned...
for trait_entry in script.read().traits()?.iter() {
globals.install_foreign_trait(
&mut null_activation,
context,
trait_entry.clone(),
Some(scope),
globals,
@ -129,7 +127,7 @@ impl<'gc> Avm2<'gc> {
drop(null_activation);
self.run_script_initializer(script, context)?;
Self::run_script_initializer(script, context)?;
}
Ok(())

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@ use crate::avm2::script_object::{ScriptObject, ScriptObjectClass, ScriptObjectDa
use crate::avm2::string::AvmString;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, CollectionContext, Gc, GcCell, MutationContext};
use std::fmt;
@ -87,22 +86,17 @@ impl<'gc> Executable<'gc> {
&self,
unbound_reciever: Option<Object<'gc>>,
arguments: &[Value<'gc>],
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error> {
match self {
Executable::Native(nf, reciever) => nf(
activation,
context,
reciever.or(unbound_reciever),
arguments,
),
Executable::Native(nf, reciever) => {
nf(activation, reciever.or(unbound_reciever), arguments)
}
Executable::Action(bm) => {
let reciever = bm.reciever.or(unbound_reciever);
let mut activation = Activation::from_method(
activation.avm2(),
context,
activation.context.reborrow(),
bm.method,
bm.scope,
reciever,
@ -110,7 +104,7 @@ impl<'gc> Executable<'gc> {
base_proto,
)?;
activation.run_actions(bm.method, context)
activation.run_actions(bm.method)
}
}
}
@ -161,8 +155,7 @@ impl<'gc> FunctionObject<'gc> {
/// to be limited to interfaces (at least by the AS3 compiler in Animate
/// CC 2020.)
pub fn from_class(
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>,
base_class: Option<Object<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
@ -174,7 +167,6 @@ impl<'gc> FunctionObject<'gc> {
base_class,
&QName::new(Namespace::public_namespace(), "prototype"),
activation,
context,
)?
.as_object()
.map_err(|_| {
@ -189,9 +181,9 @@ impl<'gc> FunctionObject<'gc> {
.into()
});
super_proto?.derive(activation, context, class, scope)?
super_proto?.derive(activation, class, scope)?
} else {
ScriptObject::bare_object(context.gc_context)
ScriptObject::bare_object(activation.context.gc_context)
};
let mut interfaces = Vec::new();
@ -199,8 +191,8 @@ impl<'gc> FunctionObject<'gc> {
for interface_name in interface_names {
let interface = if let Some(scope) = scope {
scope
.write(context.gc_context)
.resolve(&interface_name, activation, context)?
.write(activation.context.gc_context)
.resolve(&interface_name, activation)?
} else {
None
};
@ -215,7 +207,6 @@ impl<'gc> FunctionObject<'gc> {
interface,
&QName::new(Namespace::public_namespace(), "prototype"),
activation,
context,
)?
.as_object()?;
@ -223,7 +214,7 @@ impl<'gc> FunctionObject<'gc> {
}
if !interfaces.is_empty() {
class_proto.set_interfaces(context.gc_context, interfaces);
class_proto.set_interfaces(activation.context.gc_context, interfaces);
}
let fn_proto = activation.avm2().prototypes().function;
@ -232,7 +223,7 @@ impl<'gc> FunctionObject<'gc> {
let initializer = class_read.instance_init();
let mut constr: Object<'gc> = FunctionObject(GcCell::allocate(
context.gc_context,
activation.context.gc_context,
FunctionObjectData {
base: ScriptObjectData::base_new(
Some(fn_proto),
@ -242,26 +233,26 @@ impl<'gc> FunctionObject<'gc> {
initializer,
scope,
None,
context.gc_context,
activation.context.gc_context,
)),
},
))
.into();
constr.install_dynamic_property(
context.gc_context,
activation.context.gc_context,
QName::new(Namespace::public_namespace(), "prototype"),
class_proto.into(),
)?;
class_proto.install_dynamic_property(
context.gc_context,
activation.context.gc_context,
QName::new(Namespace::public_namespace(), "constructor"),
constr.into(),
)?;
let class_initializer = class_read.class_init();
let class_constr = FunctionObject::from_method(
context.gc_context,
activation.context.gc_context,
class_initializer,
scope,
class_constr_proto,
@ -346,15 +337,14 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
self,
reciever: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let read = self.0.read();
let rv = read.base.get_property_local(reciever, name, activation)?;
drop(read);
rv.resolve(activation, context)
rv.resolve(activation)
}
fn set_property_local(
@ -362,17 +352,16 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut write = self.0.write(context.gc_context);
let mut write = self.0.write(activation.context.gc_context);
let rv = write
.base
.set_property_local(reciever, name, value, activation, context)?;
.set_property_local(reciever, name, value, activation)?;
drop(write);
rv.resolve(activation, context)?;
rv.resolve(activation)?;
Ok(())
}
@ -382,17 +371,16 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let mut write = self.0.write(context.gc_context);
let mut write = self.0.write(activation.context.gc_context);
let rv = write
.base
.init_property_local(reciever, name, value, activation, context)?;
.init_property_local(reciever, name, value, activation)?;
drop(write);
rv.resolve(activation, context)?;
rv.resolve(activation)?;
Ok(())
}
@ -526,12 +514,11 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
self,
reciever: Option<Object<'gc>>,
arguments: &[Value<'gc>],
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error> {
if let Some(exec) = &self.0.read().exec {
exec.exec(reciever, arguments, activation, context, base_proto)
exec.exec(reciever, arguments, activation, base_proto)
} else {
Err("Not a callable function!".into())
}
@ -539,15 +526,14 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
fn construct(
&self,
_activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
_args: &[Value<'gc>],
) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::FunctionObject(*self);
let base = ScriptObjectData::base_new(Some(this), ScriptObjectClass::NoClass);
Ok(FunctionObject(GcCell::allocate(
context.gc_context,
activation.context.gc_context,
FunctionObjectData { base, exec: None },
))
.into())
@ -555,8 +541,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
fn derive(
&self,
_activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
) -> Result<Object<'gc>, Error> {
@ -567,7 +552,7 @@ impl<'gc> TObject<'gc> for FunctionObject<'gc> {
);
Ok(FunctionObject(GcCell::allocate(
context.gc_context,
activation.context.gc_context,
FunctionObjectData { base, exec: None },
))
.into())

View File

@ -9,7 +9,6 @@ use crate::avm2::script_object::ScriptObject;
use crate::avm2::string::AvmString;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, MutationContext};
use std::f64::NAN;
@ -19,8 +18,7 @@ mod function;
mod object;
fn trace<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -5,7 +5,6 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `Class`
@ -13,8 +12,7 @@ use gc_arena::MutationContext;
/// Notably, you cannot construct new classes this way, so this returns an
/// error.
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `flash.display.DisplayObject`'s constructor.
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `flash.display.DisplayObjectContainer`'s constructor.
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `flash.display.InteractiveObject`'s constructor.
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `flash.display.MovieClip`'s constructor.
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `flash.display.Sprite`'s constructor.
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -5,13 +5,11 @@ use crate::avm2::object::Object;
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `flash.events.EventDispatcher`'s constructor.
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {

View File

@ -7,13 +7,11 @@ use crate::avm2::object::{Object, TObject};
use crate::avm2::script_object::ScriptObject;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `Function`
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_action_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
@ -22,8 +20,7 @@ pub fn constructor<'gc>(
/// Implements `Function.prototype.call`
fn call<'gc>(
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
func: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
@ -32,9 +29,9 @@ fn call<'gc>(
if let Some(func) = func {
if args.len() > 1 {
Ok(func.call(this, &args[1..], activation, context, base_proto)?)
Ok(func.call(this, &args[1..], activation, base_proto)?)
} else {
Ok(func.call(this, &[], activation, context, base_proto)?)
Ok(func.call(this, &[], activation, base_proto)?)
}
} else {
Err("Not a callable function".into())

View File

@ -6,13 +6,11 @@ use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::MutationContext;
/// Implements `Object`
pub fn constructor<'gc>(
_activation: &mut Activation<'_, 'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
@ -21,44 +19,40 @@ pub fn constructor<'gc>(
/// Implements `Object.prototype.toString`
fn to_string<'gc>(
_: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(this
.map(|t| t.to_string(context.gc_context))
.map(|t| t.to_string(activation.context.gc_context))
.unwrap_or(Ok(Value::Undefined))?)
}
/// Implements `Object.prototype.toLocaleString`
fn to_locale_string<'gc>(
_: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(this
.map(|t| t.to_string(context.gc_context))
.map(|t| t.to_string(activation.context.gc_context))
.unwrap_or(Ok(Value::Undefined))?)
}
/// Implements `Object.prototype.valueOf`
fn value_of<'gc>(
_: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(this
.map(|t| t.value_of(context.gc_context))
.map(|t| t.value_of(activation.context.gc_context))
.unwrap_or(Ok(Value::Undefined))?)
}
/// `Object.prototype.hasOwnProperty`
pub fn has_own_property<'gc>(
_activation: &mut Activation<'_, 'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
@ -79,8 +73,7 @@ pub fn has_own_property<'gc>(
/// `Object.prototype.isPrototypeOf`
pub fn is_prototype_of<'gc>(
_activation: &mut Activation<'_, 'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
@ -102,8 +95,7 @@ pub fn is_prototype_of<'gc>(
/// `Object.prototype.propertyIsEnumerable`
pub fn property_is_enumerable<'gc>(
_activation: &mut Activation<'_, 'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
@ -124,8 +116,7 @@ pub fn property_is_enumerable<'gc>(
/// `Object.prototype.setPropertyIsEnumerable`
pub fn set_property_is_enumerable<'gc>(
_activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
@ -142,7 +133,7 @@ pub fn set_property_is_enumerable<'gc>(
if let Some(ns) = this.resolve_any(name)? {
if !ns.is_private() {
let qname = QName::new(ns, name);
this.set_local_property_is_enumerable(context.gc_context, &qname, is_enum)?;
this.set_local_property_is_enumerable(activation.context.gc_context, &qname, is_enum)?;
}
}

View File

@ -5,7 +5,6 @@ use crate::avm2::object::Object;
use crate::avm2::script::TranslationUnit;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, CollectionContext, Gc, MutationContext};
use std::fmt;
use std::rc::Rc;
@ -30,8 +29,7 @@ pub struct CollectWrapper<T>(T);
/// your function yields `None`, you must ensure that the top-most activation
/// in the AVM1 runtime will return with the value of this function.
pub type NativeMethod<'gc> = fn(
&mut Activation<'_, 'gc>,
&mut UpdateContext<'_, 'gc, '_>,
&mut Activation<'_, 'gc, '_>,
Option<Object<'gc>>,
&[Value<'gc>],
) -> Result<Value<'gc>, Error>;

View File

@ -10,7 +10,6 @@ use crate::avm2::script_object::ScriptObject;
use crate::avm2::string::AvmString;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, MutationContext};
use ruffle_macros::enum_trait_object;
use std::fmt::Debug;
@ -32,8 +31,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
self,
reciever: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error>;
/// Retrieve a property by it's QName.
@ -41,23 +39,22 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
&mut self,
reciever: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
if !self.has_instantiated_property(name) {
for abc_trait in self.get_trait(name)? {
self.install_trait(activation, context, abc_trait, reciever)?;
self.install_trait(activation, abc_trait, reciever)?;
}
}
let has_no_getter = self.has_own_virtual_setter(name) && !self.has_own_virtual_getter(name);
if self.has_own_property(name)? && !has_no_getter {
return self.get_property_local(reciever, name, activation, context);
return self.get_property_local(reciever, name, activation);
}
if let Some(mut proto) = self.proto() {
return proto.get_property(reciever, name, activation, context);
return proto.get_property(reciever, name, activation);
}
Ok(Value::Undefined)
@ -85,8 +82,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error>;
/// Set a property by it's QName.
@ -95,17 +91,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
if !self.has_instantiated_property(name) {
for abc_trait in self.get_trait(name)? {
self.install_trait(activation, context, abc_trait, reciever)?;
self.install_trait(activation, abc_trait, reciever)?;
}
}
if self.has_own_virtual_setter(name) {
return self.set_property_local(reciever, name, value, activation, context);
return self.set_property_local(reciever, name, value, activation);
}
let mut proto = self.proto();
@ -114,13 +109,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
//we're calling a virtual setter. If you call `set_property` on
//a non-virtual you will actually alter the prototype.
if my_proto.has_own_virtual_setter(name) {
return my_proto.set_property(reciever, name, value, activation, context);
return my_proto.set_property(reciever, name, value, activation);
}
proto = my_proto.proto();
}
reciever.set_property_local(reciever, name, value, activation, context)
reciever.set_property_local(reciever, name, value, activation)
}
/// Init a property on this specific object.
@ -129,8 +124,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error>;
/// Init a property by it's QName.
@ -139,17 +133,16 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
if !self.has_instantiated_property(name) {
for abc_trait in self.get_trait(name)? {
self.install_trait(activation, context, abc_trait, reciever)?;
self.install_trait(activation, abc_trait, reciever)?;
}
}
if self.has_own_virtual_setter(name) {
return self.init_property_local(reciever, name, value, activation, context);
return self.init_property_local(reciever, name, value, activation);
}
let mut proto = self.proto();
@ -158,13 +151,13 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
//we're calling a virtual setter. If you call `set_property` on
//a non-virtual you will actually alter the prototype.
if my_proto.has_own_virtual_setter(name) {
return my_proto.init_property(reciever, name, value, activation, context);
return my_proto.init_property(reciever, name, value, activation);
}
proto = my_proto.proto();
}
reciever.init_property_local(reciever, name, value, activation, context)
reciever.init_property_local(reciever, name, value, activation)
}
/// Retrieve a slot by it's index.
@ -411,19 +404,17 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// object.
fn install_trait(
&mut self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
trait_entry: Trait<'gc>,
reciever: Object<'gc>,
) -> Result<(), Error> {
self.install_foreign_trait(activation, context, trait_entry, self.get_scope(), reciever)
self.install_foreign_trait(activation, trait_entry, self.get_scope(), reciever)
}
/// Install a trait from anywyere.
fn install_foreign_trait(
&mut self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
trait_entry: Trait<'gc>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
reciever: Object<'gc>,
@ -444,7 +435,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
..
} => {
self.install_slot(
context.gc_context,
activation.context.gc_context,
trait_name,
*slot_id,
default_value.clone().unwrap_or(Value::Undefined),
@ -454,37 +445,52 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
disp_id, method, ..
} => {
let function = FunctionObject::from_method(
context.gc_context,
activation.context.gc_context,
method.clone(),
scope,
fn_proto,
Some(reciever),
);
self.install_method(context.gc_context, trait_name, *disp_id, function);
self.install_method(
activation.context.gc_context,
trait_name,
*disp_id,
function,
);
}
TraitKind::Getter {
disp_id, method, ..
} => {
let function = FunctionObject::from_method(
context.gc_context,
activation.context.gc_context,
method.clone(),
scope,
fn_proto,
Some(reciever),
);
self.install_getter(context.gc_context, trait_name, *disp_id, function)?;
self.install_getter(
activation.context.gc_context,
trait_name,
*disp_id,
function,
)?;
}
TraitKind::Setter {
disp_id, method, ..
} => {
let function = FunctionObject::from_method(
context.gc_context,
activation.context.gc_context,
method.clone(),
scope,
fn_proto,
Some(reciever),
);
self.install_setter(context.gc_context, trait_name, *disp_id, function)?;
self.install_setter(
activation.context.gc_context,
trait_name,
*disp_id,
function,
)?;
}
TraitKind::Class { slot_id, class } => {
let class_read = class.read();
@ -494,7 +500,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
.unwrap_or_else(|| QName::dynamic_name("Object"));
let super_class: Result<Object<'gc>, Error> = self
.get_property(reciever, &super_name, activation, context)?
.get_property(reciever, &super_name, activation)?
.as_object()
.map_err(|_e| {
format!("Could not resolve superclass {:?}", super_name.local_name())
@ -507,9 +513,9 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
};
let (class_object, _cinit) =
FunctionObject::from_class(activation, context, *class, super_class, scope)?;
FunctionObject::from_class(activation, *class, super_class, scope)?;
self.install_const(
context.gc_context,
activation.context.gc_context,
class_read.name().clone(),
*slot_id,
class_object.into(),
@ -519,22 +525,29 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
slot_id, function, ..
} => {
let mut fobject = FunctionObject::from_method(
context.gc_context,
activation.context.gc_context,
function.clone(),
scope,
fn_proto,
None,
);
let es3_proto =
ScriptObject::object(context.gc_context, activation.avm2().prototypes().object);
let es3_proto = ScriptObject::object(
activation.context.gc_context,
activation.avm2().prototypes().object,
);
fobject.install_slot(
context.gc_context,
activation.context.gc_context,
QName::new(Namespace::public_namespace(), "prototype"),
0,
es3_proto.into(),
);
self.install_const(context.gc_context, trait_name, *slot_id, fobject.into());
self.install_const(
activation.context.gc_context,
trait_name,
*slot_id,
fobject.into(),
);
}
TraitKind::Const {
slot_id,
@ -542,7 +555,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
..
} => {
self.install_const(
context.gc_context,
activation.context.gc_context,
trait_name,
*slot_id,
default_value.clone().unwrap_or(Value::Undefined),
@ -558,8 +571,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
self,
_reciever: Option<Object<'gc>>,
_arguments: &[Value<'gc>],
_activation: &mut Activation<'_, 'gc>,
_context: &mut UpdateContext<'_, 'gc, '_>,
_activation: &mut Activation<'_, 'gc, '_>,
_base_proto: Option<Object<'gc>>,
) -> Result<Value<'gc>, Error> {
Err("Object is not callable".into())
@ -584,8 +596,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// purely so that host objects can be constructed by the VM.
fn construct(
&self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
args: &[Value<'gc>],
) -> Result<Object<'gc>, Error>;
@ -600,8 +611,7 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
/// traits.
fn derive(
&self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
) -> Result<Object<'gc>, Error>;
@ -638,18 +648,12 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
#[allow(unused_mut)] //it's not unused
fn is_instance_of(
&self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
mut constructor: Object<'gc>,
check_interfaces: bool,
) -> Result<bool, Error> {
let type_proto = constructor
.get_property(
constructor,
&QName::dynamic_name("prototype"),
activation,
context,
)?
.get_property(constructor, &QName::dynamic_name("prototype"), activation)?
.as_object()?;
let mut my_proto = self.proto();

View File

@ -4,7 +4,6 @@ use crate::avm2::activation::Activation;
use crate::avm2::function::Executable;
use crate::avm2::object::Object;
use crate::avm2::{Error, Value};
use crate::context::UpdateContext;
use std::fmt;
/// Represents the return value of a function call that has not yet executed.
@ -83,11 +82,7 @@ impl<'gc> ReturnValue<'gc> {
///
/// All return values must eventually resolved - it is a compile error to
/// fail to do so.
pub fn resolve(
self,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
pub fn resolve(self, activation: &mut Activation<'_, 'gc, '_>) -> Result<Value<'gc>, Error> {
match self {
Self::Immediate(v) => Ok(v),
Self::ResultOf {
@ -95,13 +90,7 @@ impl<'gc> ReturnValue<'gc> {
unbound_reciever,
arguments,
base_proto,
} => executable.exec(
unbound_reciever,
&arguments,
activation,
context,
base_proto,
),
} => executable.exec(unbound_reciever, &arguments, activation, base_proto),
}
}
}

View File

@ -5,7 +5,6 @@ use crate::avm2::names::Multiname;
use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::Ref;
@ -100,8 +99,7 @@ impl<'gc> Scope<'gc> {
pub fn find(
&self,
name: &Multiname<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Option<Object<'gc>>, Error> {
if let Some(qname) = self.locals().resolve_multiname(name)? {
if self.locals().has_property(&qname)? {
@ -110,7 +108,7 @@ impl<'gc> Scope<'gc> {
}
if let Some(scope) = self.parent() {
return scope.find(name, activation, context);
return scope.find(name, activation);
}
Ok(None)
@ -123,8 +121,7 @@ impl<'gc> Scope<'gc> {
pub fn resolve(
&mut self,
name: &Multiname<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Option<Value<'gc>>, Error> {
if let Some(qname) = self.locals().resolve_multiname(name)? {
if self.locals().has_property(&qname)? {
@ -132,15 +129,14 @@ impl<'gc> Scope<'gc> {
self.values,
&qname,
activation,
context,
)?));
}
}
if let Some(parent) = self.parent {
return parent
.write(context.gc_context)
.resolve(name, activation, context);
.write(activation.context.gc_context)
.resolve(name, activation);
}
//TODO: Should undefined variables halt execution?

View File

@ -14,7 +14,6 @@ use crate::avm2::slot::Slot;
use crate::avm2::string::AvmString;
use crate::avm2::value::Value;
use crate::avm2::Error;
use crate::context::UpdateContext;
use gc_arena::{Collect, GcCell, MutationContext};
use std::collections::HashMap;
use std::fmt::Debug;
@ -80,15 +79,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
self,
reciever: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<Value<'gc>, Error> {
let rv = self
.0
.read()
.get_property_local(reciever, name, activation)?;
rv.resolve(activation, context)
rv.resolve(activation)
}
fn set_property_local(
@ -96,15 +94,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let rv = self
.0
.write(context.gc_context)
.set_property_local(reciever, name, value, activation, context)?;
.write(activation.context.gc_context)
.set_property_local(reciever, name, value, activation)?;
rv.resolve(activation, context)?;
rv.resolve(activation)?;
Ok(())
}
@ -114,15 +111,14 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<(), Error> {
let rv = self
.0
.write(context.gc_context)
.init_property_local(reciever, name, value, activation, context)?;
.write(activation.context.gc_context)
.init_property_local(reciever, name, value, activation)?;
rv.resolve(activation, context)?;
rv.resolve(activation)?;
Ok(())
}
@ -245,24 +241,22 @@ impl<'gc> TObject<'gc> for ScriptObject<'gc> {
fn construct(
&self,
_activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
_args: &[Value<'gc>],
) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::ScriptObject(*self);
Ok(ScriptObject::object(context.gc_context, this))
Ok(ScriptObject::object(activation.context.gc_context, this))
}
fn derive(
&self,
_activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
class: GcCell<'gc, Class<'gc>>,
scope: Option<GcCell<'gc, Scope<'gc>>>,
) -> Result<Object<'gc>, Error> {
let this: Object<'gc> = Object::ScriptObject(*self);
Ok(ScriptObject::prototype(
context.gc_context,
activation.context.gc_context,
this,
class,
scope,
@ -419,7 +413,7 @@ impl<'gc> ScriptObjectData<'gc> {
&self,
reciever: Object<'gc>,
name: &QName<'gc>,
activation: &mut Activation<'_, 'gc>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> {
let prop = self.values.get(name);
@ -435,8 +429,7 @@ impl<'gc> ScriptObjectData<'gc> {
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> {
let slot_id = if let Some(prop) = self.values.get(name) {
if let Some(slot_id) = prop.slot_id() {
@ -449,7 +442,7 @@ impl<'gc> ScriptObjectData<'gc> {
};
if let Some(slot_id) = slot_id {
self.set_slot(slot_id, value, context.gc_context)?;
self.set_slot(slot_id, value, activation.context.gc_context)?;
Ok(Value::Undefined.into())
} else if self.values.contains_key(name) {
let prop = self.values.get_mut(name).unwrap();
@ -470,12 +463,11 @@ impl<'gc> ScriptObjectData<'gc> {
reciever: Object<'gc>,
name: &QName<'gc>,
value: Value<'gc>,
activation: &mut Activation<'_, 'gc>,
context: &mut UpdateContext<'_, 'gc, '_>,
activation: &mut Activation<'_, 'gc, '_>,
) -> Result<ReturnValue<'gc>, Error> {
if let Some(prop) = self.values.get_mut(name) {
if let Some(slot_id) = prop.slot_id() {
self.init_slot(slot_id, value, context.gc_context)?;
self.init_slot(slot_id, value, activation.context.gc_context)?;
Ok(Value::Undefined.into())
} else {
let proto = self.proto;

View File

@ -3,6 +3,7 @@ use crate::avm1;
use crate::avm1::globals::system::SystemProperties;
use crate::avm1::{Avm1, Object, Timers, Value};
use crate::avm2::Avm2;
use crate::backend::input::InputBackend;
use crate::backend::storage::StorageBackend;
use crate::backend::{audio::AudioBackend, navigator::NavigatorBackend, render::RenderBackend};
@ -117,6 +118,9 @@ pub struct UpdateContext<'a, 'gc, 'gc_context> {
/// The AVM1 global state.
pub avm1: &'a mut Avm1<'gc>,
/// The AVM2 global state.
pub avm2: &'a mut Avm2<'gc>,
}
unsafe impl<'a, 'gc, 'gc_context> Collect for UpdateContext<'a, 'gc, 'gc_context> {
@ -145,6 +149,7 @@ unsafe impl<'a, 'gc, 'gc_context> Collect for UpdateContext<'a, 'gc, 'gc_context
self.unbound_text_fields.trace(cc);
self.timers.trace(cc);
self.avm1.trace(cc);
self.avm2.trace(cc);
}
}
@ -188,6 +193,7 @@ impl<'a, 'gc, 'gc_context> UpdateContext<'a, 'gc, 'gc_context> {
unbound_text_fields: self.unbound_text_fields,
timers: self.timers,
avm1: self.avm1,
avm2: self.avm2,
}
}
}

View File

@ -370,13 +370,14 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player");
Box::pin(async move {
player.lock().expect("Could not lock player!!").update(
|_avm2, uc| -> Result<(), Error> {
player
.lock()
.expect("Could not lock player!!")
.update(|uc| -> Result<(), Error> {
url = uc.navigator.resolve_relative_url(&url).into_owned();
Ok(())
},
)?;
})?;
let data = (fetch.await)
.and_then(|data| Ok((data.len(), SwfMovie::from_data(&data, Some(url.clone()))?)));
@ -414,8 +415,10 @@ impl<'gc> Loader<'gc> {
.expect("Could not upgrade weak reference to player");
Box::pin(async move {
player.lock().expect("Could not lock player!!").update(
|_avm2, uc| -> Result<(), Error> {
player
.lock()
.expect("Could not lock player!!")
.update(|uc| -> Result<(), Error> {
url = uc.navigator.resolve_relative_url(&url).into_owned();
let (clip, broadcaster) = match uc.load_manager.get_loader(handle) {
@ -446,8 +449,7 @@ impl<'gc> Loader<'gc> {
}
Ok(())
},
)?;
})?;
let data = (fetch.await)
.and_then(|data| Ok((data.len(), SwfMovie::from_data(&data, Some(url.clone()))?)));
@ -457,7 +459,7 @@ impl<'gc> Loader<'gc> {
player
.lock()
.expect("Could not lock player!!")
.update(|_avm2, uc| {
.update(|uc| {
let (clip, broadcaster) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie {
target_clip,
@ -530,8 +532,10 @@ impl<'gc> Loader<'gc> {
//error types we can actually inspect.
//This also can get errors from decoding an invalid SWF file,
//too. We should distinguish those to player code.
player.lock().expect("Could not lock player!!").update(
|_avm2, uc| -> Result<(), Error> {
player
.lock()
.expect("Could not lock player!!")
.update(|uc| -> Result<(), Error> {
let (clip, broadcaster) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie {
target_clip,
@ -564,8 +568,7 @@ impl<'gc> Loader<'gc> {
};
Ok(())
},
)
})
}
})
}
@ -588,7 +591,7 @@ impl<'gc> Loader<'gc> {
let data = fetch.await?;
// Fire the load handler.
player.lock().unwrap().update(|_avm2, uc| {
player.lock().unwrap().update(|uc| {
let loader = uc.load_manager.get_loader(handle);
let that = match loader {
Some(&Loader::Form { target_object, .. }) => target_object,
@ -635,7 +638,7 @@ impl<'gc> Loader<'gc> {
let data = fetch.await;
// Fire the load handler.
player.lock().unwrap().update(|_avm2, uc| {
player.lock().unwrap().update(|uc| {
let loader = uc.load_manager.get_loader(handle);
let that = match loader {
Some(&Loader::LoadVars { target_object, .. }) => target_object,
@ -737,7 +740,7 @@ impl<'gc> Loader<'gc> {
let xmlstring = String::from_utf8(data)?;
player.lock().expect("Could not lock player!!").update(
|_avm2, uc| -> Result<(), Error> {
|uc| -> Result<(), Error> {
let (mut node, active_clip) = match uc.load_manager.get_loader(handle) {
Some(Loader::XML {
target_node,
@ -773,7 +776,7 @@ impl<'gc> Loader<'gc> {
)?;
} else {
player.lock().expect("Could not lock player!!").update(
|_avm2, uc| -> Result<(), Error> {
|uc| -> Result<(), Error> {
let (mut node, active_clip) = match uc.load_manager.get_loader(handle) {
Some(Loader::XML {
target_node,

View File

@ -275,7 +275,7 @@ impl Player {
/// This should not be called if a root movie fetch has already been kicked
/// off.
pub fn fetch_root_movie(&mut self, movie_url: &str) {
self.mutate_with_update_context(|_avm2, context| {
self.mutate_with_update_context(|context| {
let fetch = context.navigator.fetch(movie_url, RequestOptions::get());
let process = context.load_manager.load_root_movie(
context.player.clone().unwrap(),
@ -305,7 +305,7 @@ impl Player {
self.frame_rate = movie.header().frame_rate.into();
self.swf = movie;
self.mutate_with_update_context(|_avm2, context| {
self.mutate_with_update_context(|context| {
let mut root: DisplayObject =
MovieClip::from_movie(context.gc_context, context.swf.clone()).into();
root.set_depth(context.gc_context, 0);
@ -447,7 +447,7 @@ impl Player {
{
if self.input.is_key_down(KeyCode::Control) && self.input.is_key_down(KeyCode::Alt)
{
self.mutate_with_update_context(|_avm2, context| {
self.mutate_with_update_context(|context| {
let mut dumper = VariableDumper::new(" ");
let levels = context.levels.clone();
@ -483,19 +483,19 @@ impl Player {
{
if self.input.is_key_down(KeyCode::Control) && self.input.is_key_down(KeyCode::Alt)
{
self.mutate_with_update_context(|avm2, context| {
self.mutate_with_update_context(|context| {
if context.avm1.show_debug_output() {
log::info!(
"AVM Debugging turned off! Press CTRL+ALT+D to turn off again."
);
context.avm1.set_show_debug_output(false);
avm2.set_show_debug_output(false);
context.avm2.set_show_debug_output(false);
} else {
log::info!(
"AVM Debugging turned on! Press CTRL+ALT+D to turn on again."
);
context.avm1.set_show_debug_output(true);
avm2.set_show_debug_output(true);
context.avm2.set_show_debug_output(true);
}
});
}
@ -537,7 +537,7 @@ impl Player {
};
if button_event.is_some() {
self.mutate_with_update_context(|_avm2, context| {
self.mutate_with_update_context(|context| {
let levels: Vec<DisplayObject<'_>> = context.levels.values().copied().collect();
for level in levels {
if let Some(button_event) = button_event {
@ -565,7 +565,7 @@ impl Player {
};
if clip_event.is_some() || listener.is_some() {
self.mutate_with_update_context(|_avm2, context| {
self.mutate_with_update_context(|context| {
let levels: Vec<DisplayObject<'_>> = context.levels.values().copied().collect();
for level in levels {
@ -589,7 +589,7 @@ impl Player {
}
let mut is_mouse_down = self.is_mouse_down;
self.mutate_with_update_context(|avm2, context| {
self.mutate_with_update_context(|context| {
if let Some(node) = context.mouse_hovered_object {
if node.removed() {
context.mouse_hovered_object = None;
@ -616,7 +616,7 @@ impl Player {
_ => (),
}
Self::run_actions(avm2, context);
Self::run_actions(context);
});
self.is_mouse_down = is_mouse_down;
if needs_render {
@ -627,7 +627,7 @@ impl Player {
/// Update dragged object, if any.
fn update_drag(&mut self) {
let mouse_pos = self.mouse_pos;
self.mutate_with_update_context(|_avm2, context| {
self.mutate_with_update_context(|context| {
if let Some(drag_object) = &mut context.drag_object {
if drag_object.display_object.removed() {
// Be sure to clear the drag if the object was removed.
@ -662,7 +662,7 @@ impl Player {
let mouse_pos = self.mouse_pos;
let mut new_cursor = self.mouse_cursor;
let hover_changed = self.mutate_with_update_context(|avm2, context| {
let hover_changed = self.mutate_with_update_context(|context| {
// Check hovered object.
let mut new_hovered = None;
for (_depth, level) in context.levels.clone().iter().rev() {
@ -692,7 +692,7 @@ impl Player {
context.mouse_hovered_object = new_hovered;
Self::run_actions(avm2, context);
Self::run_actions(context);
true
} else {
false
@ -713,7 +713,7 @@ impl Player {
/// This should only be called once. Further movie loads should preload the
/// specific `MovieClip` referenced.
fn preload(&mut self) {
self.mutate_with_update_context(|_avm2, context| {
self.mutate_with_update_context(|context| {
let mut morph_shapes = fnv::FnvHashMap::default();
let root = *context.levels.get(&0).expect("root level");
root.as_movie_clip()
@ -732,7 +732,7 @@ impl Player {
}
pub fn run_frame(&mut self) {
self.update(|_avm2, update_context| {
self.update(|update_context| {
// TODO: In what order are levels run?
// NOTE: We have to copy all the layer pointers into a separate list
// because level updates can create more levels, which we don't
@ -813,7 +813,7 @@ impl Player {
self.input.deref_mut()
}
fn run_actions<'gc>(avm2: &mut Avm2<'gc>, context: &mut UpdateContext<'_, 'gc, '_>) {
fn run_actions<'gc>(context: &mut UpdateContext<'_, 'gc, '_>) {
// Note that actions can queue further actions, so a while loop is necessary here.
while let Some(actions) = context.action_queue.pop_action() {
// We don't run frame actions if the clip was removed after it queued the action.
@ -917,7 +917,7 @@ impl Player {
is_lazy_initialize,
abc,
} => {
if let Err(e) = avm2.load_abc(abc, &name, is_lazy_initialize, context) {
if let Err(e) = Avm2::load_abc(abc, &name, is_lazy_initialize, context) {
log::warn!("Error loading ABC file: {}", e);
}
}
@ -966,7 +966,7 @@ impl Player {
/// This takes cares of populating the `UpdateContext` struct, avoiding borrow issues.
fn mutate_with_update_context<F, R>(&mut self, f: F) -> R
where
F: for<'a, 'gc> FnOnce(&mut Avm2<'gc>, &mut UpdateContext<'a, 'gc, '_>) -> R,
F: for<'a, 'gc> FnOnce(&mut UpdateContext<'a, 'gc, '_>) -> R,
{
// We have to do this piecewise borrowing of fields before the closure to avoid
// completely borrowing `self`.
@ -1050,9 +1050,10 @@ impl Player {
timers,
needs_render,
avm1,
avm2,
};
let ret = f(avm2, &mut update_context);
let ret = f(&mut update_context);
// Hovered object may have been updated; copy it back to the GC root.
root_data.mouse_hovered_object = update_context.mouse_hovered_object;
@ -1084,15 +1085,12 @@ impl Player {
/// hover state up to date, and running garbage collection.
pub fn update<F, R>(&mut self, func: F) -> R
where
F: for<'a, 'gc, 'gc_context> FnOnce(
&mut Avm2<'gc>,
&mut UpdateContext<'a, 'gc, 'gc_context>,
) -> R,
F: for<'a, 'gc, 'gc_context> FnOnce(&mut UpdateContext<'a, 'gc, 'gc_context>) -> R,
{
let rval = self.mutate_with_update_context(|avm2, context| {
let rval = func(avm2, context);
let rval = self.mutate_with_update_context(|context| {
let rval = func(context);
Self::run_actions(avm2, context);
Self::run_actions(context);
rval
});
@ -1108,7 +1106,7 @@ impl Player {
}
pub fn flush_shared_objects(&mut self) {
self.update(|_avm2, context| {
self.update(|context| {
let mut activation =
Activation::from_stub(context.reborrow(), ActivationIdentifier::root("[Flush]"));
let shared_objects = activation.context.shared_objects.clone();
@ -1122,7 +1120,7 @@ impl Player {
/// Returns the approximate amount of time until the next timer tick.
pub fn update_timers(&mut self, dt: f64) {
self.time_til_next_timer =
self.mutate_with_update_context(|_avm2, context| Timers::update_timers(context, dt));
self.mutate_with_update_context(|context| Timers::update_timers(context, dt));
}
}