avm1: Move root_object, target_clip_or_root, target_clip and base_clip from avm1 to StackFrame

This commit is contained in:
Nathan Adams 2020-06-28 15:39:49 +02:00
parent ca305684db
commit d470c52aea
6 changed files with 56 additions and 59 deletions

View File

@ -136,31 +136,6 @@ impl<'gc> Avm1<'gc> {
} }
} }
#[allow(dead_code)]
pub fn base_clip(&self) -> DisplayObject<'gc> {
self.current_stack_frame().unwrap().read().base_clip()
}
/// The current target clip for the executing code.
/// This is the movie clip that contains the bytecode.
/// Timeline actions like `GotoFrame` use this because
/// a goto after an invalid tellTarget has no effect.
pub fn target_clip(&self) -> Option<DisplayObject<'gc>> {
self.current_stack_frame().unwrap().read().target_clip()
}
/// The current target clip of the executing code, or `root` if there is none.
/// Actions that affect `root` after an invalid `tellTarget` will use this.
///
/// The `root` is determined relative to the base clip that defined the
pub fn target_clip_or_root(&self) -> DisplayObject<'gc> {
self.current_stack_frame()
.unwrap()
.read()
.target_clip()
.unwrap_or_else(|| self.base_clip().root())
}
/// Add a stack frame that executes code in timeline scope /// Add a stack frame that executes code in timeline scope
pub fn run_stack_frame_for_action( pub fn run_stack_frame_for_action(
&mut self, &mut self,
@ -473,11 +448,6 @@ impl<'gc> Avm1<'gc> {
value value
} }
/// Obtain the value of `_root`.
pub fn root_object(&self, _context: &mut UpdateContext<'_, 'gc, '_>) -> Value<'gc> {
self.base_clip().root().object()
}
/// Obtain the value of `_global`. /// Obtain the value of `_global`.
pub fn global_object(&self, _context: &mut UpdateContext<'_, 'gc, '_>) -> Value<'gc> { pub fn global_object(&self, _context: &mut UpdateContext<'_, 'gc, '_>) -> Value<'gc> {
Value::Object(self.globals) Value::Object(self.globals)

View File

@ -86,7 +86,7 @@ fn target<'gc>(
let target = this.get("target", activation, context)?; let target = this.get("target", activation, context)?;
// Undefined or empty target is no-op. // Undefined or empty target is no-op.
if target != Value::Undefined && !matches!(&target, &Value::String(ref s) if s.is_empty()) { if target != Value::Undefined && !matches!(&target, &Value::String(ref s) if s.is_empty()) {
let start_clip = activation.avm().target_clip_or_root(); let start_clip = activation.target_clip_or_root();
activation.resolve_target_display_object(context, start_clip, target) activation.resolve_target_display_object(context, start_clip, target)
} else { } else {
Ok(None) Ok(None)

View File

@ -66,7 +66,7 @@ pub fn define_display_object_proto<'gc>(
gc_context, gc_context,
"_root", "_root",
Executable::Native(|activation, context, _this, _args| { Executable::Native(|activation, context, _this, _args| {
Ok(activation.avm().root_object(context).into()) Ok(activation.root_object(context).into())
}), }),
Some(Executable::Native(overwrite_root)), Some(Executable::Native(overwrite_root)),
DontDelete | ReadOnly | DontEnum, DontDelete | ReadOnly | DontEnum,

View File

@ -514,7 +514,7 @@ fn create_empty_movie_clip<'gc>(
// Create empty movie clip. // Create empty movie clip.
let swf_movie = movie_clip let swf_movie = movie_clip
.movie() .movie()
.or_else(|| activation.avm().base_clip().movie()) .or_else(|| activation.base_clip().movie())
.unwrap(); .unwrap();
let mut new_clip = MovieClip::new(SwfSlice::empty(swf_movie), context.gc_context); let mut new_clip = MovieClip::new(SwfSlice::empty(swf_movie), context.gc_context);
@ -533,7 +533,7 @@ fn create_text_field<'gc>(
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
args: &[Value<'gc>], args: &[Value<'gc>],
) -> Result<ReturnValue<'gc>, Error<'gc>> { ) -> Result<ReturnValue<'gc>, Error<'gc>> {
let movie = activation.avm().base_clip().movie().unwrap(); let movie = activation.base_clip().movie().unwrap();
let instance_name = args.get(0).cloned().unwrap_or(Value::Undefined); let instance_name = args.get(0).cloned().unwrap_or(Value::Undefined);
let depth = args let depth = args
.get(1) .get(1)

View File

@ -824,7 +824,7 @@ pub fn xml_load<'gc>(
this.set("loaded", false.into(), activation, ac)?; this.set("loaded", false.into(), activation, ac)?;
let fetch = ac.navigator.fetch(&url, RequestOptions::get()); let fetch = ac.navigator.fetch(&url, RequestOptions::get());
let target_clip = activation.avm().target_clip_or_root(); let target_clip = activation.target_clip_or_root();
let process = ac.load_manager.load_xml_into_node( let process = ac.load_manager.load_xml_into_node(
ac.player.clone().unwrap(), ac.player.clone().unwrap(),
node, node,

View File

@ -327,7 +327,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
let depth = self.avm.pop(); let depth = self.avm.pop();
let target = self.avm.pop(); let target = self.avm.pop();
let source = self.avm.pop(); let source = self.avm.pop();
let start_clip = self.avm.target_clip_or_root(); let start_clip = self.target_clip_or_root();
let source_clip = self.resolve_target_display_object(context, start_clip, source)?; let source_clip = self.resolve_target_display_object(context, start_clip, source)?;
if let Some(movie_clip) = source_clip.and_then(|o| o.as_movie_clip()) { if let Some(movie_clip) = source_clip.and_then(|o| o.as_movie_clip()) {
@ -417,7 +417,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
// Runs any actions on the given frame. // Runs any actions on the given frame.
let frame = self.avm.pop(); let frame = self.avm.pop();
let clip = self.avm.target_clip_or_root(); let clip = self.target_clip_or_root();
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
// Use frame # if parameter is a number, otherwise cast to string and check for frame labels. // Use frame # if parameter is a number, otherwise cast to string and check for frame labels.
let frame = if let Value::Number(frame) = frame { let frame = if let Value::Number(frame) = frame {
@ -435,7 +435,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
if let Some(frame) = frame { if let Some(frame) = frame {
for action in clip.actions_on_frame(context, frame) { for action in clip.actions_on_frame(context, frame) {
self.avm.run_stack_frame_for_action( self.avm.run_stack_frame_for_action(
self.avm.target_clip_or_root(), self.target_clip_or_root(),
self.avm.current_swf_version(), self.avm.current_swf_version(),
action, action,
context, context,
@ -467,7 +467,6 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
.resolve(self, context)?; .resolve(self, context)?;
let this = self let this = self
.avm
.target_clip_or_root() .target_clip_or_root()
.object() .object()
.coerce_to_object(self, context); .coerce_to_object(self, context);
@ -493,7 +492,6 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
match method_name { match method_name {
Value::Undefined | Value::Null => { Value::Undefined | Value::Null => {
let this = self let this = self
.avm
.target_clip_or_root() .target_clip_or_root()
.object() .object()
.coerce_to_object(self, context); .coerce_to_object(self, context);
@ -585,7 +583,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
params, params,
scope, scope,
constant_pool, constant_pool,
self.avm.target_clip_or_root(), self.target_clip_or_root(),
); );
let prototype = let prototype =
ScriptObject::object(context.gc_context, Some(self.avm.prototypes.object)).into(); ScriptObject::object(context.gc_context, Some(self.avm.prototypes.object)).into();
@ -627,7 +625,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
action_func, action_func,
scope, scope,
constant_pool, constant_pool,
self.avm.base_clip(), self.base_clip(),
); );
let prototype = let prototype =
ScriptObject::object(context.gc_context, Some(self.avm.prototypes.object)).into(); ScriptObject::object(context.gc_context, Some(self.avm.prototypes.object)).into();
@ -877,7 +875,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
let prop_index = self.avm.pop().into_number_v1() as usize; let prop_index = self.avm.pop().into_number_v1() as usize;
let path = self.avm.pop(); let path = self.avm.pop();
let ret = if let Some(target) = self.avm.target_clip() { let ret = if let Some(target) = self.target_clip() {
if let Some(clip) = self.resolve_target_display_object(context, target, path)? { if let Some(clip) = self.resolve_target_display_object(context, target, path)? {
let display_properties = self.avm.display_properties; let display_properties = self.avm.display_properties;
let props = display_properties.write(context.gc_context); let props = display_properties.write(context.gc_context);
@ -985,11 +983,11 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
if let Value::Object(target) = target { if let Value::Object(target) = target {
target.as_display_object() target.as_display_object()
} else { } else {
let start = self.avm.target_clip_or_root(); let start = self.target_clip_or_root();
self.resolve_target_display_object(context, start, target.clone())? self.resolve_target_display_object(context, start, target.clone())?
} }
} else { } else {
Some(self.avm.target_clip_or_root()) Some(self.target_clip_or_root())
}; };
if is_load_vars { if is_load_vars {
@ -1054,7 +1052,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
frame: u16, frame: u16,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
if let Some(clip) = self.avm.target_clip() { if let Some(clip) = self.target_clip() {
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
// The frame on the stack is 0-based, not 1-based. // The frame on the stack is 0-based, not 1-based.
clip.goto_frame(self.avm, context, frame + 1, true); clip.goto_frame(self.avm, context, frame + 1, true);
@ -1075,7 +1073,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
// Version 4+ gotoAndPlay/gotoAndStop // Version 4+ gotoAndPlay/gotoAndStop
// Param can either be a frame number or a frame label. // Param can either be a frame number or a frame label.
if let Some(clip) = self.avm.target_clip() { if let Some(clip) = self.target_clip() {
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
let frame = self.avm.pop(); let frame = self.avm.pop();
let _ = globals::movie_clip::goto_frame( let _ = globals::movie_clip::goto_frame(
@ -1100,7 +1098,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
label: &str, label: &str,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
if let Some(clip) = self.avm.target_clip() { if let Some(clip) = self.target_clip() {
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
if let Some(frame) = clip.frame_label_to_number(label) { if let Some(frame) = clip.frame_label_to_number(label) {
clip.goto_frame(self.avm, context, frame, true); clip.goto_frame(self.avm, context, frame, true);
@ -1348,7 +1346,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
&mut self, &mut self,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
if let Some(clip) = self.avm.target_clip() { if let Some(clip) = self.target_clip() {
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
clip.next_frame(self.avm, context); clip.next_frame(self.avm, context);
} else { } else {
@ -1477,7 +1475,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
&mut self, &mut self,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
if let Some(clip) = self.avm.target_clip() { if let Some(clip) = self.target_clip() {
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
clip.play(context) clip.play(context)
} else { } else {
@ -1493,7 +1491,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
&mut self, &mut self,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
if let Some(clip) = self.avm.target_clip() { if let Some(clip) = self.target_clip() {
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
clip.prev_frame(self.avm, context); clip.prev_frame(self.avm, context);
} else { } else {
@ -1584,7 +1582,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
let target = self.avm.pop(); let target = self.avm.pop();
let start_clip = self.avm.target_clip_or_root(); let start_clip = self.target_clip_or_root();
let target_clip = self.resolve_target_display_object(context, start_clip, target)?; let target_clip = self.resolve_target_display_object(context, start_clip, target)?;
if let Some(target_clip) = target_clip.and_then(|o| o.as_movie_clip()) { if let Some(target_clip) = target_clip.and_then(|o| o.as_movie_clip()) {
@ -1622,7 +1620,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
let value = self.avm.pop(); let value = self.avm.pop();
let prop_index = self.avm.pop().coerce_to_u32(self, context)? as usize; let prop_index = self.avm.pop().coerce_to_u32(self, context)? as usize;
let path = self.avm.pop(); let path = self.avm.pop();
if let Some(target) = self.avm.target_clip() { if let Some(target) = self.target_clip() {
if let Some(clip) = self.resolve_target_display_object(context, target, path)? { if let Some(clip) = self.resolve_target_display_object(context, target, path)? {
let display_properties = self.avm.display_properties; let display_properties = self.avm.display_properties;
let props = display_properties.read(); let props = display_properties.read();
@ -1668,7 +1666,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
target: &str, target: &str,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
let base_clip = self.avm.base_clip(); let base_clip = self.base_clip();
let new_target_clip; let new_target_clip;
let root = base_clip.root(); let root = base_clip.root();
let start = base_clip.object().coerce_to_object(self, context); let start = base_clip.object().coerce_to_object(self, context);
@ -1765,7 +1763,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
let target = self.avm.pop(); let target = self.avm.pop();
let start_clip = self.avm.target_clip_or_root(); let start_clip = self.target_clip_or_root();
let display_object = self.resolve_target_display_object(context, start_clip, target)?; let display_object = self.resolve_target_display_object(context, start_clip, target)?;
if let Some(display_object) = display_object { if let Some(display_object) = display_object {
let lock_center = self.avm.pop(); let lock_center = self.avm.pop();
@ -1794,7 +1792,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
&mut self, &mut self,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
) -> Result<FrameControl<'gc>, Error<'gc>> { ) -> Result<FrameControl<'gc>, Error<'gc>> {
if let Some(clip) = self.avm.target_clip() { if let Some(clip) = self.target_clip() {
if let Some(clip) = clip.as_movie_clip() { if let Some(clip) = clip.as_movie_clip() {
clip.stop(context); clip.stop(context);
} else { } else {
@ -2407,7 +2405,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
path: &'s str, path: &'s str,
) -> Result<ReturnValue<'gc>, Error<'gc>> { ) -> Result<ReturnValue<'gc>, Error<'gc>> {
// Resolve a variable path for a GetVariable action. // Resolve a variable path for a GetVariable action.
let start = self.avm().target_clip_or_root(); let start = self.target_clip_or_root();
// Find the right-most : or . in the path. // Find the right-most : or . in the path.
// If we have one, we must resolve as a target path. // If we have one, we must resolve as a target path.
@ -2493,7 +2491,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
value: Value<'gc>, value: Value<'gc>,
) -> Result<(), Error<'gc>> { ) -> Result<(), Error<'gc>> {
// Resolve a variable path for a GetVariable action. // Resolve a variable path for a GetVariable action.
let start = self.avm().target_clip_or_root(); let start = self.target_clip_or_root();
// If the target clip is invalid, we default to root for the variable path. // If the target clip is invalid, we default to root for the variable path.
if path.is_empty() { if path.is_empty() {
@ -2551,7 +2549,7 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
*level *level
} else { } else {
let mut level: DisplayObject<'_> = MovieClip::new( let mut level: DisplayObject<'_> = MovieClip::new(
SwfSlice::empty(self.avm().base_clip().movie().unwrap()), SwfSlice::empty(self.base_clip().movie().unwrap()),
context.gc_context, context.gc_context,
) )
.into(); .into();
@ -2567,4 +2565,33 @@ impl<'a, 'gc: 'a> StackFrame<'a, 'gc> {
pub fn activation(&self) -> GcCell<'gc, Activation<'gc>> { pub fn activation(&self) -> GcCell<'gc, Activation<'gc>> {
self.activation self.activation
} }
#[allow(dead_code)]
pub fn base_clip(&self) -> DisplayObject<'gc> {
self.activation.read().base_clip()
}
/// The current target clip for the executing code.
/// This is the movie clip that contains the bytecode.
/// Timeline actions like `GotoFrame` use this because
/// a goto after an invalid tellTarget has no effect.
pub fn target_clip(&self) -> Option<DisplayObject<'gc>> {
self.activation.read().target_clip()
}
/// The current target clip of the executing code.
/// Actions that affect `root` after an invalid `tellTarget` will use this.
///
/// The `root` is determined relative to the base clip that defined the
pub fn target_clip_or_root(&self) -> DisplayObject<'gc> {
self.activation
.read()
.target_clip()
.unwrap_or_else(|| self.base_clip().root())
}
/// Obtain the value of `_root`.
pub fn root_object(&self, _context: &mut UpdateContext<'_, 'gc, '_>) -> Value<'gc> {
self.base_clip().root().object()
}
} }