diff --git a/core/src/avm2/globals/flash/display/bitmap.rs b/core/src/avm2/globals/flash/display/bitmap.rs index 20601f24e480..9decf9895964 100644 --- a/core/src/avm2/globals/flash/display/bitmap.rs +++ b/core/src/avm2/globals/flash/display/bitmap.rs @@ -34,11 +34,9 @@ pub fn bitmap_allocator<'gc>( &activation.caller_movie_or_root(), ) .into(); - return Ok(initialize_for_allocator( - activation.context, - display_object, - orig_class, - )); + return Ok( + initialize_for_allocator(activation.context, display_object, orig_class).into(), + ); } if let Some((movie, symbol)) = activation @@ -66,11 +64,9 @@ pub fn bitmap_allocator<'gc>( &activation.caller_movie_or_root(), ); - return Ok(initialize_for_allocator( - activation.context, - child.into(), - orig_class, - )); + return Ok( + initialize_for_allocator(activation.context, child.into(), orig_class).into(), + ); } } class_def = class.super_class(); diff --git a/core/src/avm2/globals/flash/display/display_object.rs b/core/src/avm2/globals/flash/display/display_object.rs index b9ae02b42e9e..5b9b890e4249 100644 --- a/core/src/avm2/globals/flash/display/display_object.rs +++ b/core/src/avm2/globals/flash/display/display_object.rs @@ -33,7 +33,7 @@ pub fn initialize_for_allocator<'gc>( context: &mut UpdateContext<'gc>, dobj: DisplayObject<'gc>, class: ClassObject<'gc>, -) -> Object<'gc> { +) -> StageObject<'gc> { let obj = StageObject::for_display_object(context.gc(), dobj, class); dobj.set_placed_by_avm2_script(true); dobj.set_object2(context, obj); @@ -50,7 +50,7 @@ pub fn initialize_for_allocator<'gc>( dobj.base().set_skip_next_enter_frame(true); dobj.on_construction_complete(context); - obj.into() + obj } /// Implements `alpha`'s getter. diff --git a/core/src/avm2/globals/flash/display/loader.rs b/core/src/avm2/globals/flash/display/loader.rs index d2e4574f6ad5..f16a41961884 100644 --- a/core/src/avm2/globals/flash/display/loader.rs +++ b/core/src/avm2/globals/flash/display/loader.rs @@ -49,12 +49,14 @@ pub fn loader_allocator<'gc>( None, false, )?; + loader.set_slot( loader_slots::_CONTENT_LOADER_INFO, loader_info.into(), activation, )?; - Ok(loader) + + Ok(loader.into()) } pub fn load<'gc>( @@ -86,7 +88,7 @@ pub fn load<'gc>( } // Unload the loader, in case something was already loaded. - loader_info.unload(activation); + loader_info.unload(activation.context); // This is a dummy MovieClip, which will get overwritten in `Loader` let movie = &activation.context.root_swf; @@ -257,7 +259,7 @@ pub fn load_bytes<'gc>( } // Unload the loader, in case something was already loaded. - loader_info.unload(activation); + loader_info.unload(activation.context); // This is a dummy MovieClip, which will get overwritten in `Loader` let movie = &activation.context.root_swf; @@ -305,7 +307,7 @@ pub fn unload<'gc>( let loader_info = loader_info.as_loader_info_object().unwrap(); - loader_info.unload(activation); + loader_info.unload(activation.context); Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/loader_info.rs b/core/src/avm2/globals/flash/display/loader_info.rs index 623ecb6a361e..49723f3a02c8 100644 --- a/core/src/avm2/globals/flash/display/loader_info.rs +++ b/core/src/avm2/globals/flash/display/loader_info.rs @@ -265,7 +265,7 @@ pub fn get_child_allows_parent<'gc>( avm2_stub_getter!(activation, "flash.display.LoaderInfo", "childAllowsParent"); if let Some(loader) = loader_info.loader() { - let loader = loader.as_display_object().expect("Loader is a DO"); + let loader = loader.display_object(); let parent_movie = loader.movie(); if let Ok(child_url) = Url::parse(root.url()) { @@ -306,7 +306,7 @@ pub fn get_parent_allows_child<'gc>( avm2_stub_getter!(activation, "flash.display.LoaderInfo", "parentAllowsChild"); if let Some(loader) = loader_info.loader() { - let loader = loader.as_display_object().expect("Loader is a DO"); + let loader = loader.display_object(); let parent_movie = loader.movie(); if let Ok(child_url) = Url::parse(root.url()) { diff --git a/core/src/avm2/globals/flash/display/shape.rs b/core/src/avm2/globals/flash/display/shape.rs index 5b1884cd831a..f9f4fc2c1203 100644 --- a/core/src/avm2/globals/flash/display/shape.rs +++ b/core/src/avm2/globals/flash/display/shape.rs @@ -14,11 +14,7 @@ pub fn shape_allocator<'gc>( ) -> Result, Error<'gc>> { let display_object = Graphic::empty(activation.context).into(); - Ok(initialize_for_allocator( - activation.context, - display_object, - class, - )) + Ok(initialize_for_allocator(activation.context, display_object, class).into()) } /// Implements `graphics`. diff --git a/core/src/avm2/globals/flash/display/simple_button.rs b/core/src/avm2/globals/flash/display/simple_button.rs index 5e5cc363aff3..cd72c1329a81 100644 --- a/core/src/avm2/globals/flash/display/simple_button.rs +++ b/core/src/avm2/globals/flash/display/simple_button.rs @@ -51,11 +51,7 @@ pub fn simple_button_allocator<'gc>( .instantiate_by_id(symbol, activation.context.gc_context); if let Some(child) = child { - return Ok(initialize_for_allocator( - activation.context, - child, - orig_class, - )); + return Ok(initialize_for_allocator(activation.context, child, orig_class).into()); } else { return Err(make_error_2136(activation)); } diff --git a/core/src/avm2/globals/flash/display/sprite.rs b/core/src/avm2/globals/flash/display/sprite.rs index 1f01f3a4e9d9..9f80cfcf60c8 100644 --- a/core/src/avm2/globals/flash/display/sprite.rs +++ b/core/src/avm2/globals/flash/display/sprite.rs @@ -24,11 +24,9 @@ pub fn sprite_allocator<'gc>( if class == sprite_cls { let movie = activation.caller_movie_or_root(); let display_object = MovieClip::new(movie, activation.gc()).into(); - return Ok(initialize_for_allocator( - activation.context, - display_object, - orig_class, - )); + return Ok( + initialize_for_allocator(activation.context, display_object, orig_class).into(), + ); } if let Some((movie, symbol)) = activation @@ -44,11 +42,7 @@ pub fn sprite_allocator<'gc>( .instantiate_by_id(symbol, activation.context.gc_context); if let Some(child) = child { - return Ok(initialize_for_allocator( - activation.context, - child, - orig_class, - )); + return Ok(initialize_for_allocator(activation.context, child, orig_class).into()); } else { return Err(make_error_2136(activation)); } diff --git a/core/src/avm2/globals/flash/media/video.rs b/core/src/avm2/globals/flash/media/video.rs index 8cb33dbcf427..2fb43bccff2d 100644 --- a/core/src/avm2/globals/flash/media/video.rs +++ b/core/src/avm2/globals/flash/media/video.rs @@ -16,11 +16,7 @@ pub fn video_allocator<'gc>( if target == video_class { let movie = activation.caller_movie_or_root(); let new_do = Video::new(activation.gc(), movie, 0, 0, None); - return Ok(initialize_for_allocator( - activation.context, - new_do.into(), - class, - )); + return Ok(initialize_for_allocator(activation.context, new_do.into(), class).into()); } if let Some((movie, symbol)) = activation @@ -36,7 +32,7 @@ pub fn video_allocator<'gc>( .instantiate_by_id(symbol, activation.context.gc_context); if let Some(child) = child { - return Ok(initialize_for_allocator(activation.context, child, class)); + return Ok(initialize_for_allocator(activation.context, child, class).into()); } else { return Err(make_error_2136(activation)); } diff --git a/core/src/avm2/globals/flash/text/text_field.rs b/core/src/avm2/globals/flash/text/text_field.rs index 6ffec604029d..8e4501df8fc3 100644 --- a/core/src/avm2/globals/flash/text/text_field.rs +++ b/core/src/avm2/globals/flash/text/text_field.rs @@ -22,11 +22,7 @@ pub fn text_field_allocator<'gc>( let movie = activation.caller_movie_or_root(); let display_object = EditText::new(activation.context, movie, 0.0, 0.0, 100.0, 100.0).into(); - Ok(initialize_for_allocator( - activation.context, - display_object, - class, - )) + Ok(initialize_for_allocator(activation.context, display_object, class).into()) } pub fn get_always_show_selection<'gc>( diff --git a/core/src/avm2/object/loaderinfo_object.rs b/core/src/avm2/object/loaderinfo_object.rs index 9dbbca641c55..b01baa031fc0 100644 --- a/core/src/avm2/object/loaderinfo_object.rs +++ b/core/src/avm2/object/loaderinfo_object.rs @@ -2,18 +2,15 @@ use crate::avm2::activation::Activation; use crate::avm2::object::script_object::ScriptObjectData; -use crate::avm2::object::{EventObject, Object, TObject}; -use crate::avm2::{Avm2, Error, Value}; +use crate::avm2::object::{EventObject, Object, StageObject, TObject}; +use crate::avm2::{Avm2, Error}; use crate::context::UpdateContext; -use crate::display_object::DisplayObject; +use crate::display_object::{DisplayObject, TDisplayObject, TDisplayObjectContainer}; use crate::loader::ContentType; use crate::tag_utils::SwfMovie; use core::fmt; use gc_arena::barrier::unlock; -use gc_arena::{ - lock::{Lock, RefLock}, - Collect, Gc, GcWeak, Mutation, -}; +use gc_arena::{lock::RefLock, Collect, Gc, GcWeak, Mutation}; use ruffle_common::utils::HasPrefixField; use std::cell::{Cell, Ref}; use std::sync::Arc; @@ -81,7 +78,7 @@ pub struct LoaderInfoObjectData<'gc> { /// The loaded stream that this gets its info from. loaded_stream: RefLock>, - loader: Option>, + loader: Option>, /// Whether or not we've fired our 'init' event init_event_fired: Cell, @@ -96,8 +93,6 @@ pub struct LoaderInfoObjectData<'gc> { uncaught_error_events: Object<'gc>, - cached_avm1movie: Lock>>, - content_type: Cell, expose_content: Cell, @@ -113,7 +108,7 @@ impl<'gc> LoaderInfoObject<'gc> { pub fn not_yet_loaded( activation: &mut Activation<'_, 'gc>, movie: Arc, - loader: Option>, + loader: Option>, root_clip: Option>, is_stage: bool, ) -> Result> { @@ -144,7 +139,6 @@ impl<'gc> LoaderInfoObject<'gc> { .construct(activation, &[])? .as_object() .unwrap(), - cached_avm1movie: Lock::new(None), content_type: Cell::new(ContentType::Unknown), expose_content: Cell::new(false), errored: Cell::new(false), @@ -154,7 +148,7 @@ impl<'gc> LoaderInfoObject<'gc> { Ok(object) } - pub fn loader(self) -> Option> { + pub fn loader(self) -> Option> { self.0.loader } @@ -269,27 +263,27 @@ impl<'gc> LoaderInfoObject<'gc> { self.0.content_type.set(content_type); } - pub fn unload(self, activation: &mut Activation<'_, 'gc>) { + pub fn unload(self, context: &mut UpdateContext<'gc>) { // Reset properties - let movie = &activation.context.root_swf; + let movie = &context.root_swf; let empty_swf = Arc::new(SwfMovie::empty(movie.version(), Some(movie.url().into()))); let loader_stream = LoaderStream::NotYetLoaded(empty_swf, None, false); - self.set_loader_stream(loader_stream, activation.gc()); + self.set_loader_stream(loader_stream, context.gc()); self.set_errored(false); self.reset_init_and_complete_events(); - let loader = self + let mut loader = self .0 .loader - .expect("LoaderInfo must have been created by Loader"); - - // Remove the Loader's content element, and ignore the resulting - // error if the loader hadn't loaded it. - let _ = crate::avm2::globals::flash::display::display_object_container::remove_child_at( - activation, - Value::Object(loader), - &[0.into()], - ); + .expect("LoaderInfo must have been created by Loader") + .display_object() + .as_container() + .unwrap(); + + // Remove the Loader's content element if it exists. + if let Some(child) = loader.child_by_index(0) { + loader.remove_child(context, child); + } } } diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 594730f6d9e6..4d16668556f3 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -791,6 +791,22 @@ impl<'gc> MovieClip<'gc> { unlock!(Gc::write(mc, self.0), MovieClipData, drop_target).set(drop_target); } + pub fn has_pending_script(self) -> bool { + self.0.has_pending_script.get() + } + + pub fn set_has_pending_script(self, value: bool) { + self.0.has_pending_script.set(value); + } + + pub fn last_queued_script_frame(self) -> Option { + self.0.last_queued_script_frame.get() + } + + pub fn set_last_queued_script_frame(self, frame: Option) { + self.0.last_queued_script_frame.set(frame); + } + pub fn set_programmatically_played(self) { if self.header_frames() > 1 { self.0.set_programmatically_played() @@ -844,15 +860,15 @@ impl<'gc> MovieClip<'gc> { // Clamp frame number in bounds. let frame = frame.max(1); - // In AS3, no-op gotos have side effects that are visible to user code. - // Hence, we have to run them anyway. - if frame != self.current_frame() { - if self - .0 - .contains_flag(MovieClipFlags::EXECUTING_AVM2_FRAME_SCRIPT) - { - // AVM2 does not allow a clip to see while it is executing a frame script. - // The goto is instead queued and run once the frame script is completed. + // AVM2 does not allow a clip to goto while it is executing a frame script. + // The goto is instead queued and run once the frame script is completed. + if self + .0 + .contains_flag(MovieClipFlags::EXECUTING_AVM2_FRAME_SCRIPT) + { + // In SWFv9, frame-script-queued gotos to the current frame are ignored. + + if self.swf_version() > 9 || frame != self.current_frame() { self.0.queued_goto_frame.set(Some(frame)); // If we have a frame script on that frame, add ourselves to the @@ -861,9 +877,17 @@ impl<'gc> MovieClip<'gc> { if self.has_frame_script(frame) { context.frame_script_cleanup_queue.push_back(self); } - } else { - self.run_goto(context, frame, false); } + } else { + self.goto_frame_now(context, frame) + } + } + + fn goto_frame_now(self, context: &mut UpdateContext<'gc>, frame: FrameNumber) { + // In AS3, no-op gotos have side effects that are visible to user + // code. Hence, we have to run them anyway. + if frame != self.current_frame() { + self.run_goto(context, frame, false); } else if self.movie().is_action_script_3() { // Despite not running, the goto still overwrites the currently enqueued frame. self.0.queued_goto_frame.set(None); @@ -1398,11 +1422,11 @@ impl<'gc> MovieClip<'gc> { } self.0.queued_script_frame.set(self.0.current_frame.get()); - if self.0.last_queued_script_frame.get() != Some(self.0.current_frame.get()) { + if self.last_queued_script_frame() != Some(self.0.current_frame.get()) { // We explicitly clear this variable since AS3 may later GOTO back // to the already-ran frame. Since the frame number *has* changed // in the meantime, it should absolutely run again. - self.0.last_queued_script_frame.set(None); + self.set_last_queued_script_frame(None); } } @@ -2065,12 +2089,10 @@ impl<'gc> MovieClip<'gc> { callable: Option>, context: &mut UpdateContext<'gc>, ) { - let write = Gc::write(context.gc(), self.0); - let current_frame = write.current_frame(); - let mut frame_scripts = - RefMut::map(unlock!(write, MovieClipData, cell).borrow_mut(), |r| { - &mut r.frame_scripts - }); + let current_frame = self.current_frame(); + + let write = unlock!(Gc::write(context.gc(), self.0), MovieClipData, cell); + let mut frame_scripts = RefMut::map(write.borrow_mut(), |r| &mut r.frame_scripts); let index = frame_id as usize; if let Some(callable) = callable { @@ -2084,8 +2106,8 @@ impl<'gc> MovieClip<'gc> { } else { // Ensure newly registered frame scripts are executed, // even if the frame is repeated due to goto. - write.last_queued_script_frame.set(None); - write.has_pending_script.set(true); + self.set_last_queued_script_frame(None); + self.set_has_pending_script(true); } } } else if frame_scripts.len() > index { @@ -2342,19 +2364,11 @@ impl<'gc> MovieClip<'gc> { } } - pub fn run_frame_script_cleanup(context: &mut UpdateContext<'gc>) { - while let Some(clip) = context.frame_script_cleanup_queue.pop_front() { - clip.0.has_pending_script.set(true); - clip.0.last_queued_script_frame.set(None); - clip.run_local_frame_scripts(context); - } - } - - fn run_local_frame_scripts(self, context: &mut UpdateContext<'gc>) { + pub fn run_local_frame_scripts(self, context: &mut UpdateContext<'gc>) { let avm2_object = self.0.object2.get(); if let Some(avm2_object) = avm2_object { - if self.0.has_pending_script.get() { + if self.has_pending_script() { let frame_id = self.0.queued_script_frame.get(); // If we are already executing frame scripts, then we shouldn't // run frame scripts recursively. This is because AVM2 can run @@ -2366,14 +2380,14 @@ impl<'gc> MovieClip<'gc> { .0 .contains_flag(MovieClipFlags::EXECUTING_AVM2_FRAME_SCRIPT) { - let is_fresh_frame = self.0.last_queued_script_frame.get() != Some(frame_id); + let is_fresh_frame = self.last_queued_script_frame() != Some(frame_id); if is_fresh_frame { if let Some(callable) = self.frame_script(frame_id) { let callable = Avm2Value::from(callable); - self.0.last_queued_script_frame.set(Some(frame_id)); - self.0.has_pending_script.set(false); + self.set_last_queued_script_frame(Some(frame_id)); + self.set_has_pending_script(false); self.0 .set_flag(MovieClipFlags::EXECUTING_AVM2_FRAME_SCRIPT, true); @@ -2409,13 +2423,21 @@ impl<'gc> MovieClip<'gc> { let goto_frame = self.0.queued_goto_frame.take(); if let Some(frame) = goto_frame { - self.run_goto(context, frame, false); + self.goto_frame_now(context, frame); + + // In SWFv9, the `goto_frame_now` above won't run `construct_frame`, so + // we need to manually run `construct_frame` to ensure that children + // are constructed. This prevents situations such as a frame script + // queued to run on this frame seeing not-yet-constructed children. + if self.swf_version() <= 9 { + self.construct_frame(context); + } } } fn check_has_pending_script(self) { let has_pending_script = self.has_frame_script(self.0.current_frame.get()); - self.0.has_pending_script.set(has_pending_script); + self.set_has_pending_script(has_pending_script); } } diff --git a/core/src/frame_lifecycle.rs b/core/src/frame_lifecycle.rs index 56e7d012d457..e5a13f8cee6b 100644 --- a/core/src/frame_lifecycle.rs +++ b/core/src/frame_lifecycle.rs @@ -96,7 +96,7 @@ pub fn run_all_phases_avm2(context: &mut UpdateContext<'_>) { orphan.run_frame_scripts(context); }); stage.run_frame_scripts(context); - MovieClip::run_frame_script_cleanup(context); + run_frame_script_cleanup(context); *context.frame_phase = FramePhase::Exit; broadcast_frame_exited(context); @@ -194,6 +194,16 @@ pub fn broadcast_frame_exited<'gc>(context: &mut UpdateContext<'gc>) { LoadManager::run_exit_frame(context); } +/// Empty the `context.frame_script_cleanup_queue` by running frame scripts for +/// each clip in the queue. +fn run_frame_script_cleanup<'gc>(context: &mut UpdateContext<'gc>) { + while let Some(clip) = context.frame_script_cleanup_queue.pop_front() { + clip.set_has_pending_script(true); + clip.set_last_queued_script_frame(None); + clip.run_local_frame_scripts(context); + } +} + /// Run all previously-executed frame phases on a newly-constructed display /// object. /// diff --git a/core/src/loader.rs b/core/src/loader.rs index 615b243ae215..7e61533ed93f 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1906,8 +1906,7 @@ impl<'gc> MovieLoader<'gc> { let mut loader = loader_info .loader() .expect("Loader should be Some") - .as_display_object() - .unwrap() + .display_object() .as_container() .unwrap(); diff --git a/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/Test.as b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/Test.as new file mode 100644 index 000000000000..b5f0a8aa74dd --- /dev/null +++ b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/Test.as @@ -0,0 +1,51 @@ +package { + import flash.display.MovieClip; + + public class Test extends MovieClip { + public var counter:int = 0; + + public var theSprite:TheSprite; + + public function Test() { + super(); + var self:Test = this; + addEventListener("enterFrame",function(e:*):void { + trace("enterFrame dispatched"); + trace("Number of root children: " + self.numChildren); + trace("placed theSprite: " + self.theSprite); + trace("theSprite: " + theSprite); + }); + addEventListener("frameConstructed",function(e:*):void { + trace("frameConstructed dispatched"); + trace("Number of root children: " + self.numChildren); + trace("placed theSprite: " + self.theSprite); + trace("theSprite: " + theSprite); + }); + addEventListener("exitFrame",function(e:*):void { + trace("exitFrame dispatched"); + trace("Number of root children: " + self.numChildren); + trace("placed theSprite: " + self.theSprite); + trace("theSprite: " + theSprite); + }); + addFrameScript(1,frame2,2,frame3); + gotoAndStop(2); + trace("Test constructor complete"); + } + + public function frame2() : void { + trace("frame 2 framescript: On frame 2"); + gotoAndStop(3); + trace("frame 2 framescript: Ran gotoAndStop(3) from frame 2"); + } + + public function frame3() : void { + trace("frame 3 framescript: On frame 3"); + trace("frame 3 framescript: placed theSprite is " + this.theSprite); + if(counter < 2) { + counter++; + gotoAndStop(3); + trace("frame 3 framescript: Ran gotoAndStop(3) from frame 3"); + } + } + } +} diff --git a/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/TheSprite.as b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/TheSprite.as new file mode 100644 index 000000000000..bef55af0a2f7 --- /dev/null +++ b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/TheSprite.as @@ -0,0 +1,12 @@ +package { + import flash.display.MovieClip; + + public class TheSprite extends MovieClip { + public function TheSprite() { + trace("Start of TheSprite ctor"); + super(); + theSprite = this; + trace("End of TheSprite ctor"); + } + } +} diff --git a/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/output.txt b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/output.txt new file mode 100644 index 000000000000..9fde798c847c --- /dev/null +++ b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/output.txt @@ -0,0 +1,52 @@ +frameConstructed dispatched +Number of root children: 0 +placed theSprite: null +theSprite: null +frame 2 framescript: On frame 2 +frame 2 framescript: Ran gotoAndStop(3) from frame 2 +Start of TheSprite ctor +End of TheSprite ctor +frameConstructed dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +frame 3 framescript: On frame 3 +frame 3 framescript: placed theSprite is [object TheSprite] +frame 3 framescript: Ran gotoAndStop(3) from frame 3 +frameConstructed dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +exitFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +exitFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +exitFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +Test constructor complete +frameConstructed dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +exitFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +enterFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +frameConstructed dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +exitFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] diff --git a/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/test.swf b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/test.swf new file mode 100644 index 000000000000..8d692875b687 Binary files /dev/null and b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/test.swf differ diff --git a/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/test.toml b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/test.toml new file mode 100644 index 000000000000..ded2e363a928 --- /dev/null +++ b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/test.toml @@ -0,0 +1 @@ +num_frames = 2 diff --git a/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/theSprite.as b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/theSprite.as new file mode 100644 index 000000000000..fd7f68a28f75 --- /dev/null +++ b/tests/tests/swfs/avm2/swf_10_queued_goto_scripts_construct/theSprite.as @@ -0,0 +1,3 @@ +package { + public var theSprite:TheSprite; +} diff --git a/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/Test.as b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/Test.as new file mode 100644 index 000000000000..b5f0a8aa74dd --- /dev/null +++ b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/Test.as @@ -0,0 +1,51 @@ +package { + import flash.display.MovieClip; + + public class Test extends MovieClip { + public var counter:int = 0; + + public var theSprite:TheSprite; + + public function Test() { + super(); + var self:Test = this; + addEventListener("enterFrame",function(e:*):void { + trace("enterFrame dispatched"); + trace("Number of root children: " + self.numChildren); + trace("placed theSprite: " + self.theSprite); + trace("theSprite: " + theSprite); + }); + addEventListener("frameConstructed",function(e:*):void { + trace("frameConstructed dispatched"); + trace("Number of root children: " + self.numChildren); + trace("placed theSprite: " + self.theSprite); + trace("theSprite: " + theSprite); + }); + addEventListener("exitFrame",function(e:*):void { + trace("exitFrame dispatched"); + trace("Number of root children: " + self.numChildren); + trace("placed theSprite: " + self.theSprite); + trace("theSprite: " + theSprite); + }); + addFrameScript(1,frame2,2,frame3); + gotoAndStop(2); + trace("Test constructor complete"); + } + + public function frame2() : void { + trace("frame 2 framescript: On frame 2"); + gotoAndStop(3); + trace("frame 2 framescript: Ran gotoAndStop(3) from frame 2"); + } + + public function frame3() : void { + trace("frame 3 framescript: On frame 3"); + trace("frame 3 framescript: placed theSprite is " + this.theSprite); + if(counter < 2) { + counter++; + gotoAndStop(3); + trace("frame 3 framescript: Ran gotoAndStop(3) from frame 3"); + } + } + } +} diff --git a/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/TheSprite.as b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/TheSprite.as new file mode 100644 index 000000000000..bef55af0a2f7 --- /dev/null +++ b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/TheSprite.as @@ -0,0 +1,12 @@ +package { + import flash.display.MovieClip; + + public class TheSprite extends MovieClip { + public function TheSprite() { + trace("Start of TheSprite ctor"); + super(); + theSprite = this; + trace("End of TheSprite ctor"); + } + } +} diff --git a/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/output.txt b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/output.txt new file mode 100644 index 000000000000..c9dddf8c0abc --- /dev/null +++ b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/output.txt @@ -0,0 +1,28 @@ +Test constructor complete +frameConstructed dispatched +Number of root children: 0 +placed theSprite: null +theSprite: null +frame 2 framescript: On frame 2 +frame 2 framescript: Ran gotoAndStop(3) from frame 2 +Start of TheSprite ctor +End of TheSprite ctor +frame 3 framescript: On frame 3 +frame 3 framescript: placed theSprite is [object TheSprite] +frame 3 framescript: Ran gotoAndStop(3) from frame 3 +exitFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +enterFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +frameConstructed dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] +exitFrame dispatched +Number of root children: 1 +placed theSprite: [object TheSprite] +theSprite: [object TheSprite] diff --git a/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/test.swf b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/test.swf new file mode 100644 index 000000000000..287c7d45da4c Binary files /dev/null and b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/test.swf differ diff --git a/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/test.toml b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/test.toml new file mode 100644 index 000000000000..ded2e363a928 --- /dev/null +++ b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/test.toml @@ -0,0 +1 @@ +num_frames = 2 diff --git a/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/theSprite.as b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/theSprite.as new file mode 100644 index 000000000000..fd7f68a28f75 --- /dev/null +++ b/tests/tests/swfs/avm2/swf_9_queued_goto_scripts_construct/theSprite.as @@ -0,0 +1,3 @@ +package { + public var theSprite:TheSprite; +}