From b2b1dffbe52790de628d4e5af6b4e11f9eeabedb Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sun, 26 Feb 2023 23:23:40 +0100 Subject: [PATCH] avm2: Move DisplayObject assignment into an initializer --- core/src/avm2.rs | 4 +- core/src/avm2/globals.rs | 3 + core/src/avm2/globals/flash/display.rs | 1 + core/src/avm2/globals/flash/display/Bitmap.as | 1 + core/src/avm2/globals/flash/display/Loader.as | 8 +- .../avm2/globals/flash/display/MorphShape.as | 3 +- core/src/avm2/globals/flash/display/Shape.as | 7 +- .../globals/flash/display/SimpleButton.as | 1 + core/src/avm2/globals/flash/display/Sprite.as | 7 +- core/src/avm2/globals/flash/display/bitmap.rs | 129 +++++++++-------- .../avm2/globals/flash/display/bitmap_data.rs | 132 +++++++++--------- .../globals/flash/display/display_object.rs | 93 ++++++------ core/src/avm2/globals/flash/display/loader.rs | 65 ++++----- .../avm2/globals/flash/display/morph_shape.rs | 13 ++ core/src/avm2/globals/flash/display/shape.rs | 41 ++++-- .../globals/flash/display/simple_button.rs | 77 ++++++++-- core/src/avm2/globals/flash/display/sprite.rs | 42 ++++-- core/src/avm2/globals/flash/media/sound.rs | 2 - .../flash/system/application_domain.rs | 2 - .../src/avm2/globals/flash/text/StaticText.as | 7 +- core/src/avm2/globals/flash/text/TextField.as | 8 +- .../avm2/globals/flash/text/static_text.rs | 21 +-- .../src/avm2/globals/flash/text/text_field.rs | 42 ++++-- .../src/avm2/globals/flash/utils/ByteArray.as | 3 - .../avm2/globals/flash/utils/byte_array.rs | 35 ----- core/src/avm2/object.rs | 2 +- core/src/avm2/object/bitmapdata_object.rs | 26 +++- core/src/avm2/object/bytearray_object.rs | 29 +++- core/src/avm2/object/stage_object.rs | 17 --- core/src/display_object.rs | 24 ++-- core/src/display_object/avm2_button.rs | 9 +- core/src/display_object/bitmap.rs | 48 +++++-- core/src/display_object/graphic.rs | 7 +- core/src/display_object/loader_display.rs | 21 +-- core/src/display_object/morph_shape.rs | 6 +- core/src/display_object/movie_clip.rs | 9 +- core/src/loader.rs | 2 +- .../displayobject_early_init/BitmapTest.as | 16 +++ .../BoundByteArray.as | 12 ++ .../displayobject_early_init/BoundSound.as | 12 ++ .../DetachedSprite.as | 0 .../avm2/displayobject_early_init/Main.as | 44 ++++++ .../avm2/displayobject_early_init/MyButton.as | 17 +++ .../avm2/displayobject_early_init/MyImage.as | 21 +++ .../displayobject_early_init/MyMovieClip.as | 21 +++ .../avm2/displayobject_early_init/MySprite.as | 21 +++ .../OverButtonState.as | 14 ++ .../UnlinkedBitmapData.as | 16 +++ .../UnlinkedButton.as | 17 +++ .../UnlinkedByteArray.as | 11 ++ .../UnlinkedLoader.as | 11 ++ .../UnlinkedMovieClip.as | 11 ++ .../displayobject_early_init/UnlinkedShape.as | 11 ++ .../displayobject_early_init/UnlinkedSound.as | 11 ++ .../UnlinkedSprite.as | 11 ++ .../UnlinkedTextField.as | 11 ++ .../displayobject_early_init/bitmap_test.png | Bin 0 -> 2916 bytes .../avm2/displayobject_early_init/data.txt | 1 + .../avm2/displayobject_early_init/noise.mp3 | Bin 0 -> 4180 bytes .../avm2/displayobject_early_init/output.txt | 54 +++++++ .../avm2/displayobject_early_init/test.fla | Bin 0 -> 14160 bytes .../avm2/displayobject_early_init/test.png | Bin 0 -> 805 bytes .../avm2/displayobject_early_init/test.swf | Bin 0 -> 14299 bytes .../avm2/displayobject_early_init/test.toml | 1 + .../swfs/avm2/displayobject_subclass/Main.as | 18 +++ .../MyDisplayObjectSubclass.as | 10 ++ .../avm2/displayobject_subclass/output.txt | 2 + .../swfs/avm2/displayobject_subclass/test.fla | Bin 0 -> 3815 bytes .../swfs/avm2/displayobject_subclass/test.swf | Bin 0 -> 766 bytes .../avm2/displayobject_subclass/test.toml | 1 + .../avm2/simplebutton_multi_children/Main.as | 26 ++++ .../simplebutton_multi_children/MyButton.as | 14 ++ .../simplebutton_multi_children/output.txt | 20 +++ .../avm2/simplebutton_multi_children/test.fla | Bin 0 -> 4672 bytes .../avm2/simplebutton_multi_children/test.swf | Bin 0 -> 7854 bytes .../simplebutton_multi_children/test.toml | 1 + .../swfs/avm2/sprite_with_frames/expected.png | Bin 6394 -> 6939 bytes .../swfs/avm2/sprite_with_frames/test.fla | Bin 4911 -> 4963 bytes .../swfs/avm2/sprite_with_frames/test.swf | Bin 5240 -> 5657 bytes 79 files changed, 969 insertions(+), 414 deletions(-) create mode 100644 core/src/avm2/globals/flash/display/morph_shape.rs create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/BitmapTest.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/BoundByteArray.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/BoundSound.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/DetachedSprite.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/Main.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/MyButton.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/MyImage.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/MyMovieClip.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/MySprite.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/OverButtonState.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedBitmapData.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedButton.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedByteArray.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedLoader.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedMovieClip.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedShape.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSound.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSprite.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/UnlinkedTextField.as create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/bitmap_test.png create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/data.txt create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/noise.mp3 create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/output.txt create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/test.fla create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/test.png create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/test.swf create mode 100644 tests/tests/swfs/avm2/displayobject_early_init/test.toml create mode 100644 tests/tests/swfs/avm2/displayobject_subclass/Main.as create mode 100644 tests/tests/swfs/avm2/displayobject_subclass/MyDisplayObjectSubclass.as create mode 100644 tests/tests/swfs/avm2/displayobject_subclass/output.txt create mode 100644 tests/tests/swfs/avm2/displayobject_subclass/test.fla create mode 100644 tests/tests/swfs/avm2/displayobject_subclass/test.swf create mode 100644 tests/tests/swfs/avm2/displayobject_subclass/test.toml create mode 100644 tests/tests/swfs/avm2/simplebutton_multi_children/Main.as create mode 100644 tests/tests/swfs/avm2/simplebutton_multi_children/MyButton.as create mode 100644 tests/tests/swfs/avm2/simplebutton_multi_children/output.txt create mode 100644 tests/tests/swfs/avm2/simplebutton_multi_children/test.fla create mode 100644 tests/tests/swfs/avm2/simplebutton_multi_children/test.swf create mode 100644 tests/tests/swfs/avm2/simplebutton_multi_children/test.toml diff --git a/core/src/avm2.rs b/core/src/avm2.rs index f82044f23d24..b4a22e6ec4bb 100644 --- a/core/src/avm2.rs +++ b/core/src/avm2.rs @@ -63,8 +63,8 @@ pub use crate::avm2::globals::flash::ui::context_menu::make_context_menu_state; pub use crate::avm2::multiname::Multiname; pub use crate::avm2::namespace::Namespace; pub use crate::avm2::object::{ - ArrayObject, ClassObject, EventObject, Object, ScriptObject, SoundChannelObject, StageObject, - TObject, + ArrayObject, BitmapDataObject, ClassObject, EventObject, Object, ScriptObject, + SoundChannelObject, StageObject, TObject, }; pub use crate::avm2::qname::QName; pub use crate::avm2::value::Value; diff --git a/core/src/avm2/globals.rs b/core/src/avm2/globals.rs index 60e5ebe2e3b1..9f1f4dadafbc 100644 --- a/core/src/avm2/globals.rs +++ b/core/src/avm2/globals.rs @@ -77,6 +77,7 @@ pub struct SystemClasses<'gc> { pub graphicstrianglepath: ClassObject<'gc>, pub graphicssolidfill: ClassObject<'gc>, pub graphicsstroke: ClassObject<'gc>, + pub loader: ClassObject<'gc>, pub loaderinfo: ClassObject<'gc>, pub bytearray: ClassObject<'gc>, pub stage: ClassObject<'gc>, @@ -188,6 +189,7 @@ impl<'gc> SystemClasses<'gc> { graphicstrianglepath: object, graphicssolidfill: object, graphicsstroke: object, + loader: object, loaderinfo: object, bytearray: object, stage: object, @@ -661,6 +663,7 @@ fn load_playerglobal<'gc>( ("flash.display", "GraphicsSolidFill", graphicssolidfill), ("flash.display", "GraphicsStroke", graphicsstroke), ("flash.display", "Graphics", graphics), + ("flash.display", "Loader", loader), ("flash.display", "LoaderInfo", loaderinfo), ("flash.display", "MorphShape", morphshape), ("flash.display", "MovieClip", movieclip), diff --git a/core/src/avm2/globals/flash/display.rs b/core/src/avm2/globals/flash/display.rs index 49fbb70b1185..60f61f372b68 100644 --- a/core/src/avm2/globals/flash/display.rs +++ b/core/src/avm2/globals/flash/display.rs @@ -8,6 +8,7 @@ pub mod graphics; pub mod interactive_object; pub mod loader; pub mod loader_info; +pub mod morph_shape; pub mod movie_clip; pub mod shape; pub mod simple_button; diff --git a/core/src/avm2/globals/flash/display/Bitmap.as b/core/src/avm2/globals/flash/display/Bitmap.as index f3a0493608a5..c8f035b49469 100644 --- a/core/src/avm2/globals/flash/display/Bitmap.as +++ b/core/src/avm2/globals/flash/display/Bitmap.as @@ -1,5 +1,6 @@ package flash.display { + [Ruffle(InstanceAllocator)] public class Bitmap extends DisplayObject { public native function get bitmapData():BitmapData; public native function set bitmapData(value:BitmapData):void; diff --git a/core/src/avm2/globals/flash/display/Loader.as b/core/src/avm2/globals/flash/display/Loader.as index 7cbe5549561f..ad35d74be912 100644 --- a/core/src/avm2/globals/flash/display/Loader.as +++ b/core/src/avm2/globals/flash/display/Loader.as @@ -1,4 +1,6 @@ package flash.display { + + [Ruffle(InstanceAllocator)] public class Loader extends DisplayObjectContainer { import flash.display.LoaderInfo; import flash.display.DisplayObject; @@ -14,12 +16,6 @@ package flash.display { return this._contentLoaderInfo; } - private native function init(); - - public function Loader() { - this.init() - } - public function get content():DisplayObject { if (this.numChildren == 0) { return null; diff --git a/core/src/avm2/globals/flash/display/MorphShape.as b/core/src/avm2/globals/flash/display/MorphShape.as index f7917c139abd..9b4ad5454646 100644 --- a/core/src/avm2/globals/flash/display/MorphShape.as +++ b/core/src/avm2/globals/flash/display/MorphShape.as @@ -1,7 +1,8 @@ package flash.display { + [Ruffle(InstanceAllocator)] public final class MorphShape extends DisplayObject { public function MorphShape() { - throw new ArgumentError("Error #2012: MorphShape$ class cannot be instantiated.", 2012) + // We throw an error in `morph_shape_allocator` } } } \ No newline at end of file diff --git a/core/src/avm2/globals/flash/display/Shape.as b/core/src/avm2/globals/flash/display/Shape.as index 3965df996ed2..6f15320abaed 100644 --- a/core/src/avm2/globals/flash/display/Shape.as +++ b/core/src/avm2/globals/flash/display/Shape.as @@ -1,10 +1,7 @@ package flash.display { - public class Shape extends DisplayObject { - public function Shape() { - this.init(); - } - private native function init(); + [Ruffle(InstanceAllocator)] + public class Shape extends DisplayObject { public native function get graphics():Graphics; internal var _graphics:Graphics; diff --git a/core/src/avm2/globals/flash/display/SimpleButton.as b/core/src/avm2/globals/flash/display/SimpleButton.as index 6657a876fa1a..b3215655dcc9 100644 --- a/core/src/avm2/globals/flash/display/SimpleButton.as +++ b/core/src/avm2/globals/flash/display/SimpleButton.as @@ -6,6 +6,7 @@ package flash.display { import flash.display.DisplayObject; import flash.media.SoundTransform; + [Ruffle(InstanceAllocator)] public class SimpleButton extends InteractiveObject { public function SimpleButton(upState:DisplayObject = null, overState:DisplayObject = null, downState:DisplayObject = null, hitTestState:DisplayObject = null) { this.init(upState, overState, downState, hitTestState) diff --git a/core/src/avm2/globals/flash/display/Sprite.as b/core/src/avm2/globals/flash/display/Sprite.as index a893b2494d1e..66a2f999e2ce 100644 --- a/core/src/avm2/globals/flash/display/Sprite.as +++ b/core/src/avm2/globals/flash/display/Sprite.as @@ -4,15 +4,10 @@ package flash.display { import flash.geom.Rectangle; import flash.media.SoundTransform; + [Ruffle(InstanceAllocator)] public class Sprite extends DisplayObjectContainer { internal var _graphics:Graphics; - - public function Sprite() { - this.init(); - } - - private native function init(); public native function get graphics():Graphics; public native function get dropTarget():DisplayObject; diff --git a/core/src/avm2/globals/flash/display/bitmap.rs b/core/src/avm2/globals/flash/display/bitmap.rs index 693eeb8b7432..385c56ad2e2b 100644 --- a/core/src/avm2/globals/flash/display/bitmap.rs +++ b/core/src/avm2/globals/flash/display/bitmap.rs @@ -2,7 +2,8 @@ use crate::avm2::activation::Activation; use crate::avm2::globals::flash::display::bitmap_data::fill_bitmap_data_from_symbol; -use crate::avm2::object::{BitmapDataObject, Object, TObject}; +use crate::avm2::globals::flash::display::display_object::initialize_for_allocator; +use crate::avm2::object::{BitmapDataObject, ClassObject, Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; @@ -12,15 +13,70 @@ use crate::character::Character; use crate::display_object::{Bitmap, TDisplayObject}; use crate::{avm2_stub_getter, avm2_stub_setter}; +pub fn bitmap_allocator<'gc>( + class: ClassObject<'gc>, + activation: &mut Activation<'_, 'gc>, +) -> Result, Error<'gc>> { + let bitmap_cls = activation.avm2().classes().bitmap; + let bitmapdata_cls = activation.context.avm2.classes().bitmapdata; + + let mut class_object = Some(class); + let orig_class = class; + while let Some(class) = class_object { + if class == bitmap_cls { + let bitmap_data = BitmapDataWrapper::dummy(activation.context.gc_context); + let display_object = + Bitmap::new_with_bitmap_data(&mut activation.context, 0, bitmap_data, false).into(); + return initialize_for_allocator(activation, display_object, orig_class); + } + + if let Some((movie, symbol)) = activation + .context + .library + .avm2_class_registry() + .class_symbol(class) + { + if let Some(Character::Bitmap(bitmap)) = activation + .context + .library + .library_for_movie_mut(movie) + .character_by_id(symbol) + .cloned() + { + let new_bitmap_data = fill_bitmap_data_from_symbol(activation, &bitmap); + let bitmap_data_obj = BitmapDataObject::from_bitmap_data_internal( + activation, + BitmapDataWrapper::dummy(activation.context.gc_context), + bitmapdata_cls, + )?; + bitmap_data_obj.init_bitmap_data(activation.context.gc_context, new_bitmap_data); + new_bitmap_data.init_object2(activation.context.gc_context, bitmap_data_obj); + + let child = Bitmap::new_with_bitmap_data( + &mut activation.context, + 0, + new_bitmap_data, + false, + ) + .into(); + + let mut obj = initialize_for_allocator(activation, child, orig_class)?; + obj.set_public_property("bitmapData", bitmap_data_obj.into(), activation)?; + return Ok(obj); + } + } + class_object = class.superclass_object(); + } + unreachable!("A Bitmap subclass should have Bitmap in superclass chain"); +} + /// Implements `flash.display.Bitmap`'s `init` method, which is called from the constructor pub fn init<'gc>( activation: &mut Activation<'_, 'gc>, this: Option>, args: &[Value<'gc>], ) -> Result, Error<'gc>> { - if let Some(mut this) = this { - activation.super_init(this, &[])?; - + if let Some(this) = this { let bitmap_data = args .try_get_object(activation, 0) .and_then(|o| o.as_bitmap_data()); @@ -29,69 +85,12 @@ pub fn init<'gc>( let smoothing = args.get_bool(2); if let Some(bitmap) = this.as_display_object().and_then(|dobj| dobj.as_bitmap()) { - //We are being initialized by the movie. This means that we - //need to create bitmap data right away, since all AVM2 bitmaps - //hold bitmap data. - - let bd_object = if let Some(bd_class) = bitmap.avm2_bitmapdata_class() { - // We call the custom BitmapData class with width and height... - // but, it always seems to be 1 in Flash Player when constructed from timeline? - bd_class.construct(activation, &[1.into(), 1.into()])? - } else if let Some(b_class) = bitmap.avm2_bitmap_class() { - // Instantiating Bitmap from a Flex-style bitmap asset. - // Contrary to the above comment, this code path DOES - // trigger from AVM2, since the DisplayObject instantiation - // logic does its job in this case. - if let Some((movie, symbol_id)) = activation - .context - .library - .avm2_class_registry() - .class_symbol(b_class) - { - if let Some(Character::Bitmap(bitmap)) = activation - .context - .library - .library_for_movie_mut(movie) - .character_by_id(symbol_id) - .cloned() - { - let new_bitmap_data = - fill_bitmap_data_from_symbol(activation.context.gc_context, bitmap); - BitmapDataObject::from_bitmap_data( - activation, - new_bitmap_data, - activation.context.avm2.classes().bitmapdata, - )? - } else { - //Class association not to a Bitmap - return Err("Attempted to instantiate Bitmap from timeline with symbol class associated to non-Bitmap!".into()); - } - } else { - //Class association not bidirectional - return Err("Cannot instantiate Bitmap from timeline without bidirectional symbol class association".into()); - } - } else { - // No class association - return Err( - "Cannot instantiate Bitmap from timeline without associated symbol class" - .into(), - ); - }; - - this.set_public_property("bitmapData", bd_object.into(), activation)?; - + if let Some(bitmap_data) = bitmap_data { + bitmap.set_bitmap_data(&mut activation.context, bitmap_data); + } bitmap.set_smoothing(activation.context.gc_context, smoothing); } else { - //We are being initialized by AVM2 (and aren't associated with a - //Bitmap subclass). - - let bitmap_data = bitmap_data - .unwrap_or_else(|| BitmapDataWrapper::dummy(activation.context.gc_context)); - - let bitmap = - Bitmap::new_with_bitmap_data(&mut activation.context, 0, bitmap_data, smoothing); - - this.init_display_object(&mut activation.context, bitmap.into()); + unreachable!(); } } diff --git a/core/src/avm2/globals/flash/display/bitmap_data.rs b/core/src/avm2/globals/flash/display/bitmap_data.rs index e770bf6e399a..dd93c5c9edab 100644 --- a/core/src/avm2/globals/flash/display/bitmap_data.rs +++ b/core/src/avm2/globals/flash/display/bitmap_data.rs @@ -18,7 +18,7 @@ use crate::character::Character; use crate::display_object::Bitmap; use crate::display_object::TDisplayObject; use crate::swf::BlendMode; -use gc_arena::{GcCell, MutationContext}; +use gc_arena::GcCell; use ruffle_render::filters::Filter; use ruffle_render::transform::Transform; use std::str::FromStr; @@ -48,17 +48,19 @@ fn get_rectangle_x_y_width_height<'gc>( /// `bd` is assumed to be an uninstantiated library symbol, associated with the /// class named by `name`. pub fn fill_bitmap_data_from_symbol<'gc>( - gc_context: MutationContext<'gc, '_>, - bitmap: Bitmap<'gc>, + activation: &mut Activation<'_, 'gc>, + bd: &Bitmap<'gc>, ) -> BitmapDataWrapper<'gc> { - let transparency = true; - let bitmap_data = BitmapData::new_with_pixels( - bitmap.width().into(), - bitmap.height().into(), - transparency, - bitmap.bitmap_data().read().pixels().to_vec(), + let new_bitmap_data = GcCell::allocate( + activation.context.gc_context, + BitmapData::new_with_pixels( + Bitmap::width(*bd).into(), + Bitmap::height(*bd).into(), + true, + bd.bitmap_data().read().pixels().to_vec(), + ), ); - BitmapDataWrapper::new(GcCell::allocate(gc_context, bitmap_data)) + BitmapDataWrapper::new(new_bitmap_data) } /// Implements `flash.display.BitmapData`'s 'init' method (invoked from the AS3 constructor) @@ -68,64 +70,62 @@ pub fn init<'gc>( args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(this) = this { - activation.super_init(this, &[])?; - - if this.as_bitmap_data().is_none() { - let name = this.instance_of_class_definition().map(|c| c.read().name()); - let character = this - .instance_of() - .and_then(|t| { - activation - .context - .library - .avm2_class_registry() - .class_symbol(t) - }) - .and_then(|(movie, chara_id)| { - activation - .context - .library - .library_for_movie_mut(movie) - .character_by_id(chara_id) - .cloned() - }); - - let new_bitmap_data = if let Some(Character::Bitmap(bitmap)) = character { - // Instantiating BitmapData from an Animate-style bitmap asset - fill_bitmap_data_from_symbol(activation.context.gc_context, bitmap) - } else { - if character.is_some() { - //TODO: Determine if mismatched symbols will still work as a - //regular BitmapData subclass, or if this should throw - tracing::warn!( - "BitmapData subclass {:?} is associated with a non-bitmap symbol", - name - ); - } + // We set the underlying BitmapData instance - we start out with a dummy BitmapDataWrapper, + // which makes custom classes see a disposed BitmapData before they call super() + let name = this.instance_of_class_definition().map(|c| c.read().name()); + let character = this + .instance_of() + .and_then(|t| { + activation + .context + .library + .avm2_class_registry() + .class_symbol(t) + }) + .and_then(|(movie, chara_id)| { + activation + .context + .library + .library_for_movie_mut(movie) + .character_by_id(chara_id) + .cloned() + }); + + let new_bitmap_data = if let Some(Character::Bitmap(bitmap)) = character { + // Instantiating BitmapData from an Animate-style bitmap asset + fill_bitmap_data_from_symbol(activation, &bitmap) + } else { + if character.is_some() { + //TODO: Determine if mismatched symbols will still work as a + //regular BitmapData subclass, or if this should throw + tracing::warn!( + "BitmapData subclass {:?} is associated with a non-bitmap symbol", + name + ); + } - let width = args.get_u32(activation, 0)?; - let height = args.get_u32(activation, 1)?; - let transparency = args.get_bool(2); - let fill_color = args.get_i32(activation, 3)?; + let width = args.get_u32(activation, 0)?; + let height = args.get_u32(activation, 1)?; + let transparency = args.get_bool(2); + let fill_color = args.get_i32(activation, 3)?; - if !is_size_valid(activation.context.swf.version(), width, height) { - return Err(Error::AvmError(argument_error( - activation, - "Error #2015: Invalid BitmapData.", - 2015, - )?)); - } + if !is_size_valid(activation.context.swf.version(), width, height) { + return Err(Error::AvmError(argument_error( + activation, + "Error #2015: Invalid BitmapData.", + 2015, + )?)); + } - let new_bitmap_data = BitmapData::new(width, height, transparency, fill_color); - BitmapDataWrapper::new(GcCell::allocate( - activation.context.gc_context, - new_bitmap_data, - )) - }; + let new_bitmap_data = BitmapData::new(width, height, transparency, fill_color); + BitmapDataWrapper::new(GcCell::allocate( + activation.context.gc_context, + new_bitmap_data, + )) + }; - new_bitmap_data.init_object2(activation.context.gc_context, this); - this.init_bitmap_data(activation.context.gc_context, new_bitmap_data); - } + new_bitmap_data.init_object2(activation.context.gc_context, this); + this.init_bitmap_data(activation.context.gc_context, new_bitmap_data); } Ok(Value::Undefined) @@ -1026,7 +1026,7 @@ pub fn clone<'gc>( let new_bitmap_data = operations::clone(bitmap_data); let class = activation.avm2().classes().bitmapdata; - let new_bitmap_data_object = BitmapDataObject::from_bitmap_data( + let new_bitmap_data_object = BitmapDataObject::from_bitmap_data_internal( activation, BitmapDataWrapper::new(GcCell::allocate( activation.context.gc_context, @@ -1292,7 +1292,7 @@ pub fn compare<'gc>( match operations::compare(this_bitmap_data, other_bitmap_data) { Some(bitmap_data) => { let class = activation.avm2().classes().bitmapdata; - Ok(BitmapDataObject::from_bitmap_data( + Ok(BitmapDataObject::from_bitmap_data_internal( activation, BitmapDataWrapper::new(GcCell::allocate( activation.context.gc_context, diff --git a/core/src/avm2/globals/flash/display/display_object.rs b/core/src/avm2/globals/flash/display/display_object.rs index 27497fcf3b02..13744628fab8 100644 --- a/core/src/avm2/globals/flash/display/display_object.rs +++ b/core/src/avm2/globals/flash/display/display_object.rs @@ -1,16 +1,15 @@ //! `flash.display.DisplayObject` builtin/prototype use crate::avm2::activation::Activation; -use crate::avm2::error::make_error_2008; +use crate::avm2::error::{argument_error, make_error_2008}; use crate::avm2::filters::FilterAvm2Ext; -pub use crate::avm2::object::stage_allocator as display_object_allocator; use crate::avm2::object::{Object, TObject}; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; -use crate::avm2::Error; -use crate::avm2::Multiname; use crate::avm2::Namespace; use crate::avm2::{ArrayObject, ArrayStorage}; +use crate::avm2::{ClassObject, Error}; +use crate::avm2::{Multiname, StageObject}; use crate::display_object::{DisplayObject, HitTestOptions, TDisplayObject}; use crate::ecma_conversions::round_to_even; use crate::frame_lifecycle::catchup_display_object_to_frame; @@ -21,7 +20,48 @@ use crate::vminterface::Instantiator; use crate::{avm2_stub_getter, avm2_stub_setter}; use ruffle_render::filters::Filter; use std::str::FromStr; -use swf::BlendMode; +use swf::Twips; +use swf::{BlendMode, Rectangle}; + +pub fn display_object_allocator<'gc>( + class: ClassObject<'gc>, + activation: &mut Activation<'_, 'gc>, +) -> Result, Error<'gc>> { + let class_name = class.inner_class_definition().read().name().local_name(); + + return Err(Error::AvmError(argument_error( + activation, + &format!("Error #2012: {class_name}$ class cannot be instantiated."), + 2012, + )?)); +} + +/// Initializes a DisplayObject created from ActionScript. +/// This should be called from the AVM2 class's native allocator +/// (e.g. `sprite_allocator`) +pub fn initialize_for_allocator<'gc>( + activation: &mut Activation<'_, 'gc>, + dobj: DisplayObject<'gc>, + class: ClassObject<'gc>, +) -> Result, Error<'gc>> { + let obj: StageObject = StageObject::for_display_object(activation, dobj, class)?; + dobj.set_placed_by_script(activation.context.gc_context, true); + dobj.set_object2(&mut activation.context, obj.into()); + + // [NA] Should these run for everything? + dobj.post_instantiation(&mut activation.context, None, Instantiator::Avm2, false); + catchup_display_object_to_frame(&mut activation.context, dobj); + + // Movie clips created from ActionScript skip the next enterFrame, + // and consequently are observed to have their currentFrame lag one + // frame behind objects placed by the timeline (even if they were + // both placed in the same frame to begin with). + dobj.base_mut(activation.context.gc_context) + .set_skip_next_enter_frame(true); + dobj.on_construction_complete(&mut activation.context); + + Ok(obj.into()) +} /// Implements `flash.display.DisplayObject`'s native instance constructor. pub fn native_instance_init<'gc>( @@ -32,49 +72,6 @@ pub fn native_instance_init<'gc>( if let Some(this) = this { activation.super_init(this, &[])?; - if this.as_display_object().is_none() { - let mut class_object = this.instance_of(); - - // Iterate the inheritance chain, starting from `this` and working backwards through `super`s - // This accounts for the cases where a super may be linked to symbol, but `this` may not be - while let Some(class) = class_object { - if let Some((movie, symbol)) = activation - .context - .library - .avm2_class_registry() - .class_symbol(class) - { - let child = activation - .context - .library - .library_for_movie_mut(movie) - .instantiate_by_id(symbol, activation.context.gc_context)?; - - this.init_display_object(&mut activation.context, child); - - child.post_instantiation( - &mut activation.context, - None, - Instantiator::Avm2, - false, - ); - catchup_display_object_to_frame(&mut activation.context, child); - child.set_placed_by_script(activation.context.gc_context, true); - - // Movie clips created from ActionScript skip the next enterFrame, - // and consequently are observed to have their currentFrame lag one - // frame behind objects placed by the timeline (even if they were - // both placed in the same frame to begin with). - child - .base_mut(activation.context.gc_context) - .set_skip_next_enter_frame(true); - child.on_construction_complete(&mut activation.context); - break; - } - class_object = class.superclass_object(); - } - } - if let Some(dobj) = this.as_display_object() { if let Some(container) = dobj.as_container() { for child in container.iter_render_list() { diff --git a/core/src/avm2/globals/flash/display/loader.rs b/core/src/avm2/globals/flash/display/loader.rs index 2b8147162890..ea119d469c53 100644 --- a/core/src/avm2/globals/flash/display/loader.rs +++ b/core/src/avm2/globals/flash/display/loader.rs @@ -1,10 +1,12 @@ //! `flash.display.Loader` builtin/prototype use crate::avm2::activation::Activation; +use crate::avm2::globals::flash::display::display_object::initialize_for_allocator; use crate::avm2::object::LoaderInfoObject; use crate::avm2::object::TObject; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; +use crate::avm2::ClassObject; use crate::avm2::Multiname; use crate::avm2::{Error, Object}; use crate::backend::navigator::{NavigationMethod, Request}; @@ -14,39 +16,38 @@ use crate::loader::{Avm2LoaderData, MovieLoaderEventHandler}; use crate::tag_utils::SwfMovie; use std::sync::Arc; -pub fn init<'gc>( +pub fn loader_allocator<'gc>( + class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(mut this) = this { - if this.as_display_object().is_none() { - let new_do = - LoaderDisplay::new_with_avm2(activation, this, activation.context.swf.clone()); - this.init_display_object(&mut activation.context, new_do.into()); - } - - // Some LoaderInfo properties (such as 'bytesLoaded' and 'bytesTotal') are always - // accessible, even before the 'init' event has fired. Using an empty movie gives - // us the correct value (0) for them. - let loader_info = LoaderInfoObject::not_yet_loaded( - activation, - Arc::new(SwfMovie::empty(activation.context.swf.version())), - Some(this), - None, - false, - )?; - this.set_property( - &Multiname::new( - activation.avm2().flash_display_internal, - "_contentLoaderInfo", - ), - loader_info.into(), - activation, - )?; - } - - Ok(Value::Undefined) +) -> Result, Error<'gc>> { + // Loader does not have an associated `Character` variant, and can never be + // instantiated from the timeline. + let display_object = LoaderDisplay::empty(activation, activation.context.swf.clone()).into(); + let mut loader = initialize_for_allocator(activation, display_object, class)?; + + // Note that the initialization of `_contentLoaderInfo` is intentionally done here, + // and not in the Loader constructor - subclasess of Loader can observe 'contentLoaderInfo' + // being set before super() is called. + + // Some LoaderInfo properties (such as 'bytesLoaded' and 'bytesTotal') are always + // accessible, even before the 'init' event has fired. Using an empty movie gives + // us the correct value (0) for them. + let loader_info = LoaderInfoObject::not_yet_loaded( + activation, + Arc::new(SwfMovie::empty(activation.context.swf.version())), + Some(loader), + None, + false, + )?; + loader.set_property( + &Multiname::new( + activation.avm2().flash_display_internal, + "_contentLoaderInfo", + ), + loader_info.into(), + activation, + )?; + Ok(loader) } pub fn load<'gc>( diff --git a/core/src/avm2/globals/flash/display/morph_shape.rs b/core/src/avm2/globals/flash/display/morph_shape.rs new file mode 100644 index 000000000000..e250728eccec --- /dev/null +++ b/core/src/avm2/globals/flash/display/morph_shape.rs @@ -0,0 +1,13 @@ +use crate::avm2::{error::argument_error, Activation, ClassObject, Error, Object}; + +pub fn morph_shape_allocator<'gc>( + _class: ClassObject<'gc>, + activation: &mut Activation<'_, 'gc>, +) -> Result, Error<'gc>> { + // The actual instantiation happens in `MorphShape::construct_frame` + return Err(Error::AvmError(argument_error( + activation, + "Error #2012: MorphShape$ class cannot be instantiated.", + 2012, + )?)); +} diff --git a/core/src/avm2/globals/flash/display/shape.rs b/core/src/avm2/globals/flash/display/shape.rs index 459daa71f354..06f100a14fe0 100644 --- a/core/src/avm2/globals/flash/display/shape.rs +++ b/core/src/avm2/globals/flash/display/shape.rs @@ -1,29 +1,44 @@ //! `flash.display.Shape` builtin/prototype use crate::avm2::activation::Activation; -use crate::avm2::object::{Object, StageObject, TObject}; +use crate::avm2::globals::flash::display::display_object::initialize_for_allocator; +use crate::avm2::object::{ClassObject, Object, StageObject, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Multiname; use crate::display_object::Graphic; -/// Implements `flash.display.Shape`'s 'init' method, which is called from the constructor -pub fn init<'gc>( +pub fn shape_allocator<'gc>( + class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(this) = this { - activation.super_init(this, &[])?; +) -> Result, Error<'gc>> { + let shape_cls = activation.avm2().classes().shape; - if this.as_display_object().is_none() { - let new_do = Graphic::new_with_avm2(&mut activation.context, this); + let mut class_object = Some(class); + let orig_class = class; + while let Some(class) = class_object { + if class == shape_cls { + let display_object = Graphic::empty(&mut activation.context).into(); + return initialize_for_allocator(activation, display_object, orig_class); + } - this.init_display_object(&mut activation.context, new_do.into()); + if let Some((movie, symbol)) = activation + .context + .library + .avm2_class_registry() + .class_symbol(class) + { + let child = activation + .context + .library + .library_for_movie_mut(movie) + .instantiate_by_id(symbol, activation.context.gc_context)?; + + return initialize_for_allocator(activation, child, orig_class); } + class_object = class.superclass_object(); } - - Ok(Value::Undefined) + unreachable!("A Shape subclass should have Shape in superclass chain"); } /// 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 493b39f1b0fc..236d8362feea 100644 --- a/core/src/avm2/globals/flash/display/simple_button.rs +++ b/core/src/avm2/globals/flash/display/simple_button.rs @@ -1,11 +1,11 @@ //! `flash.display.SimpleButton` builtin/prototype use crate::avm2::activation::Activation; -use crate::avm2::object::{Object, TObject}; +use crate::avm2::globals::flash::display::display_object::initialize_for_allocator; +use crate::avm2::object::{ClassObject, Object, StageObject, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::display_object::{Avm2Button, ButtonTracking, TDisplayObject}; -use crate::vminterface::Instantiator; use swf::ButtonState; pub use crate::avm2::globals::flash::media::sound_mixer::{ @@ -13,6 +13,46 @@ pub use crate::avm2::globals::flash::media::sound_mixer::{ }; use crate::avm2::parameters::ParametersExt; +pub fn simple_button_allocator<'gc>( + class: ClassObject<'gc>, + activation: &mut Activation<'_, 'gc>, +) -> Result, Error<'gc>> { + use crate::vminterface::Instantiator; + + let simplebutton_cls = activation.avm2().classes().simplebutton; + + let mut class_object = Some(class); + let orig_class = class; + while let Some(class) = class_object { + if class == simplebutton_cls { + let button = Avm2Button::empty_button(&mut activation.context); + // [NA] Buttons specifically need to PO'd + button.post_instantiation(&mut activation.context, None, Instantiator::Avm2, false); + let display_object = button.into(); + let obj = StageObject::for_display_object(activation, display_object, orig_class)?; + display_object.set_object2(&mut activation.context, obj.into()); + return Ok(obj.into()); + } + + if let Some((movie, symbol)) = activation + .context + .library + .avm2_class_registry() + .class_symbol(class) + { + let child = activation + .context + .library + .library_for_movie_mut(movie) + .instantiate_by_id(symbol, activation.context.gc_context)?; + + return initialize_for_allocator(activation, child, orig_class); + } + class_object = class.superclass_object(); + } + unreachable!("A SimpleButton subclass should have SimpleButton in superclass chain"); +} + /// Implements `flash.display.SimpleButton`'s 'init' method. which is called from the constructor pub fn init<'gc>( activation: &mut Activation<'_, 'gc>, @@ -20,33 +60,42 @@ pub fn init<'gc>( args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(this) = this { - activation.super_init(this, &[])?; - - if this.as_display_object().is_none() { - let new_do = Avm2Button::empty_button(&mut activation.context); - - new_do.post_instantiation(&mut activation.context, None, Instantiator::Avm2, false); - this.init_display_object(&mut activation.context, new_do.into()); - + if let Some(new_do) = this + .as_display_object() + .and_then(|this| this.as_avm2_button()) + { let up_state = args .try_get_object(activation, 0) .and_then(|o| o.as_display_object()); - new_do.set_state_child(&mut activation.context, ButtonState::UP, up_state); + if up_state.is_some() { + new_do.set_state_child(&mut activation.context, ButtonState::UP, up_state); + } let over_state = args .try_get_object(activation, 1) .and_then(|o| o.as_display_object()); - new_do.set_state_child(&mut activation.context, ButtonState::OVER, over_state); + if over_state.is_some() { + new_do.set_state_child(&mut activation.context, ButtonState::OVER, over_state); + } let down_state = args .try_get_object(activation, 2) .and_then(|o| o.as_display_object()); - new_do.set_state_child(&mut activation.context, ButtonState::DOWN, down_state); + if down_state.is_some() { + new_do.set_state_child(&mut activation.context, ButtonState::DOWN, down_state); + } let hit_state = args .try_get_object(activation, 3) .and_then(|o| o.as_display_object()); - new_do.set_state_child(&mut activation.context, ButtonState::HIT_TEST, hit_state); + if hit_state.is_some() { + new_do.set_state_child(&mut activation.context, ButtonState::HIT_TEST, hit_state); + } + + // This performs the child state construction. + new_do.construct_frame(&mut activation.context); + } else { + unreachable!(); } } diff --git a/core/src/avm2/globals/flash/display/sprite.rs b/core/src/avm2/globals/flash/display/sprite.rs index 65b2327ef489..70bc0dae26f9 100644 --- a/core/src/avm2/globals/flash/display/sprite.rs +++ b/core/src/avm2/globals/flash/display/sprite.rs @@ -1,29 +1,47 @@ //! `flash.display.Sprite` builtin/prototype use crate::avm2::activation::Activation; +use crate::avm2::globals::flash::display::display_object::initialize_for_allocator; use crate::avm2::object::{Object, StageObject, TObject}; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; -use crate::avm2::Error; use crate::avm2::Multiname; +use crate::avm2::{ClassObject, Error}; use crate::display_object::{MovieClip, SoundTransform, TDisplayObject}; use swf::{Rectangle, Twips}; -/// Implements `flash.display.Sprite`'s `init` method, which is called from the constructor -pub fn init<'gc>( +pub fn sprite_allocator<'gc>( + class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(this) = this { - activation.super_init(this, &[])?; +) -> Result, Error<'gc>> { + let sprite_cls = activation.avm2().classes().sprite; + + let mut class_object = Some(class); + let orig_class = class; + while let Some(class) = class_object { + if class == sprite_cls { + let movie = activation.context.swf.clone(); + let display_object = MovieClip::new(movie, activation.context.gc_context).into(); + return initialize_for_allocator(activation, display_object, orig_class); + } - if this.as_display_object().is_none() { - init_empty_sprite(activation, this)?; + if let Some((movie, symbol)) = activation + .context + .library + .avm2_class_registry() + .class_symbol(class) + { + let child = activation + .context + .library + .library_for_movie_mut(movie) + .instantiate_by_id(symbol, activation.context.gc_context)?; + + return initialize_for_allocator(activation, child, orig_class); } + class_object = class.superclass_object(); } - - Ok(Value::Undefined) + unreachable!("A Sprite subclass should have Sprite in superclass chain"); } pub fn init_empty_sprite<'gc>( diff --git a/core/src/avm2/globals/flash/media/sound.rs b/core/src/avm2/globals/flash/media/sound.rs index 955ad67c3b93..5735df6796b1 100644 --- a/core/src/avm2/globals/flash/media/sound.rs +++ b/core/src/avm2/globals/flash/media/sound.rs @@ -19,8 +19,6 @@ pub fn init<'gc>( args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(this) = this { - activation.super_init(this, &[])?; - if !args.is_empty() { avm2_stub_constructor!(activation, "flash.media.Sound", "with arguments"); } diff --git a/core/src/avm2/globals/flash/system/application_domain.rs b/core/src/avm2/globals/flash/system/application_domain.rs index d7de7a5d09e0..77f559a3585d 100644 --- a/core/src/avm2/globals/flash/system/application_domain.rs +++ b/core/src/avm2/globals/flash/system/application_domain.rs @@ -18,8 +18,6 @@ pub fn init<'gc>( args: &[Value<'gc>], ) -> Result, Error<'gc>> { if let Some(this) = this { - activation.super_init(this, &[])?; - let parent_domain = if matches!(args[0], Value::Null) { activation.avm2().global_domain() } else { diff --git a/core/src/avm2/globals/flash/text/StaticText.as b/core/src/avm2/globals/flash/text/StaticText.as index 772dc89c2d9f..9fcb1f352684 100644 --- a/core/src/avm2/globals/flash/text/StaticText.as +++ b/core/src/avm2/globals/flash/text/StaticText.as @@ -1,11 +1,8 @@ package flash.text { import flash.display.DisplayObject; - [Ruffle(NativeInstanceInit)] - public class StaticText extends DisplayObject { - public function StaticText() { - throw new ArgumentError("Error #2012: StaticText$ class cannot be instantiated.", 2012); - } + [Ruffle(InstanceAllocator)] + public final class StaticText extends DisplayObject { public native function get text():String; } } \ No newline at end of file diff --git a/core/src/avm2/globals/flash/text/TextField.as b/core/src/avm2/globals/flash/text/TextField.as index 6080855c49fc..f96ed715f1af 100644 --- a/core/src/avm2/globals/flash/text/TextField.as +++ b/core/src/avm2/globals/flash/text/TextField.as @@ -2,15 +2,11 @@ package flash.text { import flash.display.InteractiveObject; import __ruffle__.stub_setter; + + [Ruffle(InstanceAllocator)] public class TextField extends InteractiveObject { internal var _styleSheet:StyleSheet; internal var _useRichTextClipboard:Boolean; - - public function TextField() { - this.init(); - } - - private native function init(); public native function get alwaysShowSelection():Boolean; public native function set alwaysShowSelection(value:Boolean):void; diff --git a/core/src/avm2/globals/flash/text/static_text.rs b/core/src/avm2/globals/flash/text/static_text.rs index 4d1dc6c6aa50..f0a10c58b5d1 100644 --- a/core/src/avm2/globals/flash/text/static_text.rs +++ b/core/src/avm2/globals/flash/text/static_text.rs @@ -1,17 +1,18 @@ -use crate::avm2::{Activation, Error, Object, Value}; +use crate::avm2::error::argument_error; +use crate::avm2::{Activation, ClassObject, Error, Object, Value}; use crate::avm2_stub_getter; -pub fn native_instance_init<'gc>( +pub fn static_text_allocator<'gc>( + _class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc>, - this: Option>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(this) = this { - activation.super_init(this, args)?; - } - - Ok(Value::Undefined) +) -> Result, Error<'gc>> { + return Err(Error::AvmError(argument_error( + activation, + "Error #2012: StaticText$ class cannot be instantiated.", + 2012, + )?)); } + /// Implements `StaticText.text` pub fn get_text<'gc>( activation: &mut Activation<'_, 'gc>, diff --git a/core/src/avm2/globals/flash/text/text_field.rs b/core/src/avm2/globals/flash/text/text_field.rs index 9db50b03ea48..38c85c733afb 100644 --- a/core/src/avm2/globals/flash/text/text_field.rs +++ b/core/src/avm2/globals/flash/text/text_field.rs @@ -1,7 +1,8 @@ //! `flash.text.TextField` builtin/prototype use crate::avm2::activation::Activation; -use crate::avm2::object::{Object, TObject, TextFormatObject}; +use crate::avm2::globals::flash::display::display_object::initialize_for_allocator; +use crate::avm2::object::{ClassObject, Object, TObject, TextFormatObject}; use crate::avm2::parameters::ParametersExt; use crate::avm2::value::Value; use crate::avm2::Error; @@ -11,24 +12,39 @@ use crate::string::AvmString; use crate::{avm2_stub_getter, avm2_stub_setter}; use swf::Color; -/// Implements `flash.text.TextField`'s `init` method, which is called from the constructor. -pub fn init<'gc>( +pub fn text_field_allocator<'gc>( + class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(this) = this { - activation.super_init(this, &[])?; +) -> Result, Error<'gc>> { + let textfield_cls = activation.avm2().classes().textfield; - if this.as_display_object().is_none() { + let mut class_object = Some(class); + let orig_class = class; + while let Some(class) = class_object { + if class == textfield_cls { let movie = activation.context.swf.clone(); - let new_do = EditText::new(&mut activation.context, movie, 0.0, 0.0, 100.0, 100.0); + let display_object = + EditText::new(&mut activation.context, movie, 0.0, 0.0, 100.0, 100.0).into(); + return initialize_for_allocator(activation, display_object, orig_class); + } - this.init_display_object(&mut activation.context, new_do.into()); + if let Some((movie, symbol)) = activation + .context + .library + .avm2_class_registry() + .class_symbol(class) + { + let child = activation + .context + .library + .library_for_movie_mut(movie) + .instantiate_by_id(symbol, activation.context.gc_context)?; + + return initialize_for_allocator(activation, child, orig_class); } + class_object = class.superclass_object(); } - - Ok(Value::Undefined) + unreachable!("A TextField subclass should have TextField in superclass chain"); } pub fn get_always_show_selection<'gc>( diff --git a/core/src/avm2/globals/flash/utils/ByteArray.as b/core/src/avm2/globals/flash/utils/ByteArray.as index aae329889eeb..08bf8b1b7122 100644 --- a/core/src/avm2/globals/flash/utils/ByteArray.as +++ b/core/src/avm2/globals/flash/utils/ByteArray.as @@ -25,12 +25,9 @@ package flash.utils { public native function set position(value:uint):void; public function ByteArray() { - this.init(); this.objectEncoding = _defaultObjectEncoding; } - private native function init():void; - public native function clear():void; public function deflate(): void { diff --git a/core/src/avm2/globals/flash/utils/byte_array.rs b/core/src/avm2/globals/flash/utils/byte_array.rs index 9f88ecc0d348..342ed25286b7 100644 --- a/core/src/avm2/globals/flash/utils/byte_array.rs +++ b/core/src/avm2/globals/flash/utils/byte_array.rs @@ -4,7 +4,6 @@ pub use crate::avm2::object::byte_array_allocator; use crate::avm2::object::{Object, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; -use crate::character::Character; use crate::string::AvmString; use encoding_rs::Encoding; use encoding_rs::UTF_8; @@ -12,40 +11,6 @@ use flash_lso::amf0::read::AMF0Decoder; use flash_lso::amf3::read::AMF3Decoder; use flash_lso::types::{AMFVersion, Element}; -/// Implements `flash.utils.ByteArray`'s instance constructor. -pub fn init<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Option>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(this) = this { - activation.super_init(this, &[])?; - - let class_object = this - .instance_of() - .ok_or("Attempted to construct ByteArray on a bare object")?; - if let Some((movie, id)) = activation - .context - .library - .avm2_class_registry() - .class_symbol(class_object) - { - if let Some(lib) = activation.context.library.library_for_movie(movie) { - if let Some(Character::BinaryData(binary_data)) = lib.character_by_id(id) { - let mut byte_array = this - .as_bytearray_mut(activation.context.gc_context) - .ok_or_else(|| "Unable to get bytearray storage".to_string())?; - byte_array.clear(); - byte_array.write_bytes(binary_data.as_ref())?; - byte_array.set_position(0); - } - } - } - } - - Ok(Value::Undefined) -} - /// Writes a single byte to the bytearray pub fn write_byte<'gc>( activation: &mut Activation<'_, 'gc>, diff --git a/core/src/avm2/object.rs b/core/src/avm2/object.rs index 5464969a8434..66bc163aba88 100644 --- a/core/src/avm2/object.rs +++ b/core/src/avm2/object.rs @@ -89,7 +89,7 @@ pub use crate::avm2::object::script_object::{ScriptObject, ScriptObjectData}; pub use crate::avm2::object::sound_object::{sound_allocator, QueuedPlay, SoundData, SoundObject}; pub use crate::avm2::object::soundchannel_object::{sound_channel_allocator, SoundChannelObject}; pub use crate::avm2::object::stage3d_object::{stage_3d_allocator, Stage3DObject}; -pub use crate::avm2::object::stage_object::{stage_allocator, StageObject}; +pub use crate::avm2::object::stage_object::StageObject; pub use crate::avm2::object::textformat_object::{textformat_allocator, TextFormatObject}; pub use crate::avm2::object::texture_object::TextureObject; pub use crate::avm2::object::vector_object::{vector_allocator, VectorObject}; diff --git a/core/src/avm2/object/bitmapdata_object.rs b/core/src/avm2/object/bitmapdata_object.rs index 7c7d37b67bfe..d77e0071f0dd 100644 --- a/core/src/avm2/object/bitmapdata_object.rs +++ b/core/src/avm2/object/bitmapdata_object.rs @@ -21,7 +21,10 @@ pub fn bitmap_data_allocator<'gc>( activation.context.gc_context, BitmapDataObjectData { base, - bitmap_data: None, + // This always starts out as a dummy (invalid) BitmapDataWrapper, so + // that custom subclasses see a disposed BitmapData before they call super(). + // The real BitmapDataWrapper is set by BitmapData.init() + bitmap_data: Some(BitmapDataWrapper::dummy(activation.context.gc_context)), }, )) .into()) @@ -49,7 +52,16 @@ pub struct BitmapDataObjectData<'gc> { } impl<'gc> BitmapDataObject<'gc> { - pub fn from_bitmap_data( + // Constructs a BitmapData object from a BitmapDataWrapper. + // This is *not* used when explicitly constructing a BitmapData + // instance from ActionScript (e.g. `new BitmapData(100, 100)`, + // or `new MyBitmapDataSubclass(100, 100)`). + // + // Instead, this is used when constructing a `Bitmap` object, + // (from ActionScript or from the timeline), or when we need + // to produce a new BitmapData object from a `BitmapData` method + // like `clone()` + pub fn from_bitmap_data_internal( activation: &mut Activation<'_, 'gc>, bitmap_data: BitmapDataWrapper<'gc>, class: ClassObject<'gc>, @@ -64,7 +76,15 @@ impl<'gc> BitmapDataObject<'gc> { bitmap_data.init_object2(activation.context.gc_context, instance.into()); instance.install_instance_slots(activation.context.gc_context); - class.call_native_init(Some(instance.into()), &[], activation)?; + + // We call the custom BitmapData class with width and height... + // but, it always seems to be 1 in Flash Player when constructed from timeline? + // This will not actually cause us to create a BitmapData with dimensions (1, 1) - + // when the custom class makes a super() call, the BitmapData constructor will + // load in the real data from the linked SymbolClass. + if class != activation.avm2().classes().bitmapdata { + class.call_native_init(Some(instance.into()), &[1.into(), 1.into()], activation)?; + } Ok(instance.into()) } diff --git a/core/src/avm2/object/bytearray_object.rs b/core/src/avm2/object/bytearray_object.rs index 75c45754bd52..a0eb32f44e66 100644 --- a/core/src/avm2/object/bytearray_object.rs +++ b/core/src/avm2/object/bytearray_object.rs @@ -5,6 +5,7 @@ use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::Value; use crate::avm2::Error; use crate::avm2::Multiname; +use crate::character::Character; use core::fmt; use gc_arena::{Collect, GcCell, MutationContext}; use std::cell::{Ref, RefMut}; @@ -14,14 +15,34 @@ pub fn byte_array_allocator<'gc>( class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc>, ) -> Result, Error<'gc>> { + let storage = if let Some((movie, id)) = activation + .context + .library + .avm2_class_registry() + .class_symbol(class) + { + if let Some(lib) = activation.context.library.library_for_movie(movie) { + if let Some(Character::BinaryData(binary_data)) = lib.character_by_id(id) { + Some(ByteArrayStorage::from_vec(binary_data.as_ref().to_vec())) + } else { + None + } + } else { + None + } + } else { + Some(ByteArrayStorage::new()) + }; + + let storage = storage.unwrap_or_else(|| { + unreachable!("A ByteArray subclass should have ByteArray in superclass chain") + }); + let base = ScriptObjectData::new(class); Ok(ByteArrayObject(GcCell::allocate( activation.context.gc_context, - ByteArrayObjectData { - base, - storage: ByteArrayStorage::new(), - }, + ByteArrayObjectData { base, storage }, )) .into()) } diff --git a/core/src/avm2/object/stage_object.rs b/core/src/avm2/object/stage_object.rs index c8ec68de6af4..e1cb8ec06007 100644 --- a/core/src/avm2/object/stage_object.rs +++ b/core/src/avm2/object/stage_object.rs @@ -12,23 +12,6 @@ use gc_arena::{Collect, GcCell, MutationContext}; use std::cell::{Ref, RefMut}; use std::fmt::Debug; -/// A class instance allocator that allocates Stage objects. -pub fn stage_allocator<'gc>( - class: ClassObject<'gc>, - activation: &mut Activation<'_, 'gc>, -) -> Result, Error<'gc>> { - let base = ScriptObjectData::new(class); - - Ok(StageObject(GcCell::allocate( - activation.context.gc_context, - StageObjectData { - base, - display_object: None, - }, - )) - .into()) -} - #[derive(Clone, Collect, Copy)] #[collect(no_drop)] pub struct StageObject<'gc>(GcCell<'gc, StageObjectData<'gc>>); diff --git a/core/src/display_object.rs b/core/src/display_object.rs index e31ea588f51f..c7f6524a783b 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -1345,9 +1345,9 @@ pub trait TDisplayObject<'gc>: /// if possible, set a named property on the parent matching the name of /// the object. /// - /// If the child was placed by AVM2, this function is a no-op, since AVM2 - /// will already trip these events. Objects that cannot be constructed by - /// the timeline do not need to call this method. + /// This still needs to be called for objects placed by AVM2, since we + /// need to stop the underlying MovieClip if the constructed class + /// does not extend MovieClip. /// /// Since we construct AVM2 display objects after they are allocated and /// placed on the render list, these steps have to be done by the child @@ -1393,14 +1393,16 @@ pub trait TDisplayObject<'gc>: } if let Some(movie) = self.as_movie_clip() { - if let Some(obj) = movie.object2().as_object() { - let movieclip_class = context.avm2.classes().movieclip; - // It's possible to have a DefineSprite tag with multiple frames, but have - // the corresponding `SymbolClass` *not* extend `MovieClip` (e.g. extending `Sprite` directly.) - // When this occurs, Flash Player will run the first frame, and immediately stop. - if !obj.is_of_type(movieclip_class, context) { - movie.stop(context); - } + let obj = movie + .object2() + .as_object() + .expect("MovieClip object should have been constructed"); + let movieclip_class = context.avm2.classes().movieclip; + // It's possible to have a DefineSprite tag with multiple frames, but have + // the corresponding `SymbolClass` *not* extend `MovieClip` (e.g. extending `Sprite` directly.) + // When this occurs, Flash Player will run the first frame, and immediately stop. + if !obj.is_of_type(movieclip_class, context) { + movie.stop(context); } } } diff --git a/core/src/display_object/avm2_button.rs b/core/src/display_object/avm2_button.rs index f5cdbf1009dd..6f1d1db5acfc 100644 --- a/core/src/display_object/avm2_button.rs +++ b/core/src/display_object/avm2_button.rs @@ -227,17 +227,21 @@ impl<'gc> Avm2Button<'gc> { } } + // We manually call `construct_frame` for `child` and `state_sprite` - normally + // this would be done in the `DisplayObject` constructor, but SimpleButton does + // not have children in the normal DisplayObjectContainer sense. + if children.len() == 1 { let child = children.first().cloned().unwrap().0; child.set_parent(context, Some(self.into())); child.post_instantiation(context, None, Instantiator::Movie, false); catchup_display_object_to_frame(context, child); + child.construct_frame(context); (child, false) } else { let state_sprite = MovieClip::new(movie, context.gc_context); - state_sprite.set_avm2_class(context.gc_context, Some(sprite_class)); state_sprite.set_parent(context, Some(self.into())); catchup_display_object_to_frame(context, state_sprite.into()); @@ -252,8 +256,11 @@ impl<'gc> Avm2Button<'gc> { child.post_instantiation(context, None, Instantiator::Movie, false); catchup_display_object_to_frame(context, child); child.set_parent(context, Some(state_sprite.into())); + child.construct_frame(context); } + state_sprite.construct_frame(context); + (state_sprite.into(), true) } } diff --git a/core/src/display_object/bitmap.rs b/core/src/display_object/bitmap.rs index dd9e84b0e202..b5e31a1351a3 100644 --- a/core/src/display_object/bitmap.rs +++ b/core/src/display_object/bitmap.rs @@ -2,8 +2,9 @@ use crate::avm1; use crate::avm2::{ - Activation as Avm2Activation, ClassObject as Avm2ClassObject, Object as Avm2Object, - StageObject as Avm2StageObject, Value as Avm2Value, + Activation as Avm2Activation, BitmapDataObject as Avm2BitmapDataObject, + ClassObject as Avm2ClassObject, Object as Avm2Object, StageObject as Avm2StageObject, TObject, + Value as Avm2Value, }; use crate::bitmap::bitmap_data::{BitmapData, BitmapDataWrapper}; use crate::context::{RenderContext, UpdateContext}; @@ -272,23 +273,40 @@ impl<'gc> TDisplayObject<'gc> for Bitmap<'gc> { &self, context: &mut UpdateContext<'_, 'gc>, _init_object: Option>, - _instantiated_by: Instantiator, + instantiated_by: Instantiator, run_frame: bool, ) { if context.is_action_script_3() { let mut activation = Avm2Activation::from_nothing(context.reborrow()); - let bitmap = self - .avm2_bitmap_class() - .unwrap_or_else(|| activation.context.avm2.classes().bitmap); - match Avm2StageObject::for_display_object_childless( - &mut activation, - (*self).into(), - bitmap, - ) { - Ok(object) => { - self.0.write(activation.context.gc_context).avm2_object = Some(object.into()) - } - Err(e) => tracing::error!("Got error when creating AVM2 side of bitmap: {}", e), + if !instantiated_by.is_avm() { + let bitmap_cls = self + .avm2_bitmap_class() + .unwrap_or_else(|| activation.context.avm2.classes().bitmap); + let bitmapdata_cls = self + .avm2_bitmapdata_class() + .unwrap_or_else(|| activation.context.avm2.classes().bitmapdata); + + let mc = activation.context.gc_context; + + let bitmap = Avm2StageObject::for_display_object_childless( + &mut activation, + (*self).into(), + bitmap_cls, + ) + .expect("can't throw from post_instantiation -_-"); + self.0.write(mc).avm2_object = Some(bitmap.into()); + + let bitmap_data_obj = Avm2BitmapDataObject::from_bitmap_data_internal( + &mut activation, + BitmapDataWrapper::dummy(mc), + bitmapdata_cls, + ) + .expect("can't throw from post_instantiation -_-"); + + self.set_bitmap_data( + &mut activation.context, + bitmap_data_obj.as_bitmap_data().unwrap(), + ); } self.on_construction_complete(context); diff --git a/core/src/display_object/graphic.rs b/core/src/display_object/graphic.rs index e36000f12292..58fc3aba9cb3 100644 --- a/core/src/display_object/graphic.rs +++ b/core/src/display_object/graphic.rs @@ -71,10 +71,7 @@ impl<'gc> Graphic<'gc> { } /// Construct an empty `Graphic`. - pub fn new_with_avm2( - context: &mut UpdateContext<'_, 'gc>, - avm2_object: Avm2Object<'gc>, - ) -> Self { + pub fn empty(context: &mut UpdateContext<'_, 'gc>) -> Self { let static_data = GraphicStatic { id: 0, bounds: Default::default(), @@ -100,7 +97,7 @@ impl<'gc> Graphic<'gc> { GraphicData { base: Default::default(), static_data: gc_arena::Gc::allocate(context.gc_context, static_data), - avm2_object: Some(avm2_object), + avm2_object: None, drawing: Some(drawing), }, )) diff --git a/core/src/display_object/loader_display.rs b/core/src/display_object/loader_display.rs index 77a4b1a3b405..459faa4489cd 100644 --- a/core/src/display_object/loader_display.rs +++ b/core/src/display_object/loader_display.rs @@ -36,25 +36,22 @@ impl fmt::Debug for LoaderDisplay<'_> { pub struct LoaderDisplayData<'gc> { base: InteractiveObjectBase<'gc>, container: ChildContainer<'gc>, - avm2_object: Avm2Object<'gc>, + avm2_object: Option>, movie: Arc, } impl<'gc> LoaderDisplay<'gc> { - pub fn new_with_avm2( - activation: &mut Activation<'_, 'gc>, - avm2_object: Avm2Object<'gc>, - movie: Arc, - ) -> Self { + pub fn empty(activation: &mut Activation<'_, 'gc>, movie: Arc) -> Self { let obj = LoaderDisplay(GcCell::allocate( activation.context.gc_context, LoaderDisplayData { base: Default::default(), container: ChildContainer::new(), - avm2_object, + avm2_object: None, // Set later after assignment movie, }, )); + obj.set_placed_by_script(activation.context.gc_context, true); activation.context.avm2.add_orphan_obj(obj.into()); obj @@ -95,7 +92,15 @@ impl<'gc> TDisplayObject<'gc> for LoaderDisplay<'gc> { } fn object2(&self) -> Avm2Value<'gc> { - self.0.read().avm2_object.into() + self.0 + .read() + .avm2_object + .map(Avm2Value::from) + .unwrap_or(Avm2Value::Null) + } + + fn set_object2(&self, context: &mut UpdateContext<'_, 'gc>, to: Avm2Object<'gc>) { + self.0.write(context.gc_context).avm2_object = Some(to); } fn as_container(self) -> Option> { diff --git a/core/src/display_object/morph_shape.rs b/core/src/display_object/morph_shape.rs index 8c25aabaf67f..740476e74901 100644 --- a/core/src/display_object/morph_shape.rs +++ b/core/src/display_object/morph_shape.rs @@ -121,7 +121,11 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> { if context.is_action_script_3() && matches!(self.object2(), Avm2Value::Null) { let class = context.avm2.classes().morphshape; let mut activation = Avm2Activation::from_nothing(context.reborrow()); - match Avm2StageObject::for_display_object(&mut activation, (*self).into(), class) { + match Avm2StageObject::for_display_object_childless( + &mut activation, + (*self).into(), + class, + ) { Ok(object) => self.0.write(context.gc_context).object = Some(object.into()), Err(e) => tracing::error!("Got {} when constructing AVM2 side of MorphShape", e), }; diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index e9791e88a2d1..8e0d46aed919 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -2469,7 +2469,14 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> { if needs_construction { self.construct_as_avm2_object(context); self.on_construction_complete(context); - } else { + // If we're in the load frame and we were constructed by ActionScript, + // then we want to wait for the DisplayObject constructor to run + // 'construct_frame' on children. This is observable by ActionScript - + // before calling super(), 'this.numChildren' will show a non-zero number + // when we have children placed on the load frame, but 'this.getChildAt(0)' + // will return 'null' since the children haven't had their AVM2 objects + // constructed by `construct_frame` yet. + } else if !(is_load_frame && self.placed_by_script()) { // The supercall constructor for display objects is responsible // for triggering construct_frame on frame 1. for child in self.iter_render_list() { diff --git a/core/src/loader.rs b/core/src/loader.rs index 07b1d7b796ba..629c87f770f1 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -1504,7 +1504,7 @@ impl<'gc> Loader<'gc> { bitmap_data, )); let bitmapdata_class = activation.context.avm2.classes().bitmapdata; - let bitmapdata_avm2 = BitmapDataObject::from_bitmap_data( + let bitmapdata_avm2 = BitmapDataObject::from_bitmap_data_internal( &mut activation, bitmapdata_wrapper, bitmapdata_class, diff --git a/tests/tests/swfs/avm2/displayobject_early_init/BitmapTest.as b/tests/tests/swfs/avm2/displayobject_early_init/BitmapTest.as new file mode 100644 index 000000000000..c134aed98a6d --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/BitmapTest.as @@ -0,0 +1,16 @@ +package { + + import flash.display.BitmapData; + + + // FIXME - this should extend Bitmap + public class BitmapTest extends BitmapData { + + + public function BitmapTest() { + //trace("BitmapTest before super(): this.bitmapData.width = " + this.bitmapData.width); + super(100, 100); + } + } + +} diff --git a/tests/tests/swfs/avm2/displayobject_early_init/BoundByteArray.as b/tests/tests/swfs/avm2/displayobject_early_init/BoundByteArray.as new file mode 100644 index 000000000000..90fd4dbef675 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/BoundByteArray.as @@ -0,0 +1,12 @@ +package { + import flash.utils.ByteArray; + + [Embed(source="data.txt", mimeType="application/octet-stream")] + public class BoundByteArray extends ByteArray { + public function BoundByteArray() { + trace("BoundByteArray before super(): this.bytesAvailable = " + this.bytesAvailable); + super(); + trace("BoundByteArray after super(): this.bytseAvailable = " + this.bytesAvailable); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/BoundSound.as b/tests/tests/swfs/avm2/displayobject_early_init/BoundSound.as new file mode 100644 index 000000000000..7c9d73bc0a69 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/BoundSound.as @@ -0,0 +1,12 @@ +package { + import flash.media.Sound; + + [Embed(source="noise.mp3", mimeType="audio/mpeg")] + public class BoundSound extends Sound { + public function BoundSound() { + trace("BoundSound before super(): this.bytesLoaded = " + this.bytesLoaded + " this.bytesTotal = " + this.bytesTotal); + super(); + trace("BoundSound after super(): this.bytesLoaded = " + this.bytesLoaded + " this.bytesTotal = " + this.bytesTotal); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/DetachedSprite.as b/tests/tests/swfs/avm2/displayobject_early_init/DetachedSprite.as new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/tests/swfs/avm2/displayobject_early_init/Main.as b/tests/tests/swfs/avm2/displayobject_early_init/Main.as new file mode 100644 index 000000000000..06537ce71009 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/Main.as @@ -0,0 +1,44 @@ +package { + import flash.display.MovieClip; + + public class Main extends MovieClip { + // FIXME - add 'MyButton' as a timeline child once we fix + // Ruffle's SimpleButton construction handling. + public function Main() { + trace("Constructing MyImage from ActionScript"); + var image = new MyImage(42, 24); + trace("Image: " + image); + + new UnlinkedBitmapData(); + + trace("Constructing MySprite from ActionScript"); + var mySprite = new MySprite(); + trace("mySprite: " + mySprite); + + trace("Constructing MyMovieClip from ActionScript"); + var myMovieClip = new MyMovieClip(); + trace("myMovieClip: " + myMovieClip); + + new UnlinkedSprite(); + new UnlinkedMovieClip(); + new UnlinkedLoader(); + new UnlinkedShape(); + new UnlinkedButton(); + new UnlinkedTextField(); + new UnlinkedByteArray(); + new UnlinkedSound(); + + trace("Constructing MyButton from ActionScript"); + var myButton = new MyButton(); + trace("myButton: " + myButton); + + trace("Constructing BoundByteArray from ActionScript"); + var boundByteArray = new BoundByteArray(); + trace("boundByteArray: " + boundByteArray); + + trace("Constructing BoundSound from ActionScriot"); + var boundSound = new BoundSound(); + trace("boundSound: " + boundSound); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/MyButton.as b/tests/tests/swfs/avm2/displayobject_early_init/MyButton.as new file mode 100644 index 000000000000..bd129df6ce38 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/MyButton.as @@ -0,0 +1,17 @@ +package { + + import flash.display.SimpleButton; + + + public class MyButton extends SimpleButton { + + + public function MyButton() { + // FIXME - test button states when we fix SimpleButton construction to match Flash Player + trace("MyButton before super(): this.mouseEnabled = " + this.mouseEnabled + " this.parent = " + this.parent); + super(); + trace("MyButton after super(): this.mouseEnabled = " + this.mouseEnabled + " this.parent = " + this.parent); + } + } + +} diff --git a/tests/tests/swfs/avm2/displayobject_early_init/MyImage.as b/tests/tests/swfs/avm2/displayobject_early_init/MyImage.as new file mode 100644 index 000000000000..426b873bae17 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/MyImage.as @@ -0,0 +1,21 @@ +package { + + import flash.display.BitmapData; + + + public class MyImage extends BitmapData { + + + public function MyImage(width: int, height: int) { + trace("MyImage before super(): width=" + width + " height=" + height); + try { + this.width; + } catch (e) { + trace("Caught error: " + e); + } + super(width, height) + trace("MyImage after super(): this.width=" + this.width + " this.height=" + this.height + " pixel: " + this.getPixel(0, 0)); + } + } + +} diff --git a/tests/tests/swfs/avm2/displayobject_early_init/MyMovieClip.as b/tests/tests/swfs/avm2/displayobject_early_init/MyMovieClip.as new file mode 100644 index 000000000000..f6249d65e0b3 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/MyMovieClip.as @@ -0,0 +1,21 @@ +package { + + import flash.display.MovieClip; + import flash.text.TextField; + + + public class MyMovieClip extends MovieClip { + + + public function MyMovieClip() { + var earlyGraphics = this.graphics; + trace("MyMovieClip before super(): this.graphics: " + this.graphics + " this.numChildren = " + this.numChildren + " this.getChildAt(0) = " + this.getChildAt(0) + " this.parent = " + this.parent); + var textChild = new TextField(); + textChild.text = "Text before super()"; + this.addChild(textChild); + super(); + trace("MyMovieClip after super(): this.graphics === earlyGraphics: " + (this.graphics === earlyGraphics) + " this.numChildren = " + this.numChildren + " this.getChildAt(0) = " + this.getChildAt(0) + " this.parent = " + this.parent); + } + } + +} diff --git a/tests/tests/swfs/avm2/displayobject_early_init/MySprite.as b/tests/tests/swfs/avm2/displayobject_early_init/MySprite.as new file mode 100644 index 000000000000..75ea70c7d823 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/MySprite.as @@ -0,0 +1,21 @@ +package { + + import flash.display.Sprite; + import flash.text.TextField; + + + public class MySprite extends Sprite { + + + public function MySprite() { + var earlyGraphics = this.graphics; + trace("MySprite before super(): this.graphics: " + this.graphics + " this.numChildren = " + this.numChildren + " this.getChildAt(0) = " + this.getChildAt(0) + " this.parent = " + this.parent); + var textChild = new TextField(); + textChild.text = "Text before super()"; + this.addChild(textChild); + super(); + trace("MySprite after super(): this.graphics === earlyGraphics: " + (this.graphics === earlyGraphics) + " this.numChildren = " + this.numChildren + " this.getChildAt(0) = " + this.getChildAt(0) + " this.parent = " + this.parent); + } + } + +} diff --git a/tests/tests/swfs/avm2/displayobject_early_init/OverButtonState.as b/tests/tests/swfs/avm2/displayobject_early_init/OverButtonState.as new file mode 100644 index 000000000000..fe5d79165c78 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/OverButtonState.as @@ -0,0 +1,14 @@ +package { + + import flash.display.MovieClip; + + + public class OverButtonState extends MovieClip { + + + public function OverButtonState() { + trace("Constructed OverButtonState"); + } + } + +} diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedBitmapData.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedBitmapData.as new file mode 100644 index 000000000000..1d472737c295 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedBitmapData.as @@ -0,0 +1,16 @@ +package { + import flash.display.BitmapData; + + public class UnlinkedBitmapData extends BitmapData { + public function UnlinkedBitmapData() { + trace("UnlinkedBitmapData before super()"); + try { + this.width; + } catch (e) { + trace("Caught error: " + e); + } + super(100, 100); + trace("UnlinkedBitmapData after super(): this.width=" + this.width); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedButton.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedButton.as new file mode 100644 index 000000000000..7cd7952c0964 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedButton.as @@ -0,0 +1,17 @@ +package { + + import flash.display.SimpleButton; + + + public class UnlinkedButton extends SimpleButton { + + + public function UnlinkedButton() { + // FIXME - test button states when we fix SimpleButton construction to match Flash Player + trace("UnlinkedButton before super(): this.mouseEnabled = " + this.mouseEnabled); + super(); + trace("UnlinkedButton after super(): this.mouseEnabled = " + this.mouseEnabled); + } + } + +} diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedByteArray.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedByteArray.as new file mode 100644 index 000000000000..d050488065bc --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedByteArray.as @@ -0,0 +1,11 @@ +package { + import flash.utils.ByteArray; + + public class UnlinkedByteArray extends ByteArray { + public function UnlinkedByteArray() { + trace("UnlinkedByteArray before super(): this.objectEncoding = " + this.objectEncoding); + super(); + trace("UnlinkedByteArray after super(): this.objectEncoding = " + this.objectEncoding); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedLoader.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedLoader.as new file mode 100644 index 000000000000..f9bdece1fd12 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedLoader.as @@ -0,0 +1,11 @@ +package { + import flash.display.Loader; + + public class UnlinkedLoader extends Loader { + public function UnlinkedLoader() { + trace("UnlinkedLoader before super(): this.contentLoaderInfo = " + this.contentLoaderInfo + " this.numChildren = " + this.numChildren); + super(); + trace("UnlinkedLoader after super(): this.contentLoaderInfo = " + this.contentLoaderInfo + " this.numChildren = " + this.numChildren); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedMovieClip.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedMovieClip.as new file mode 100644 index 000000000000..bc9995845152 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedMovieClip.as @@ -0,0 +1,11 @@ +package { + import flash.display.MovieClip; + + public class UnlinkedMovieClip extends MovieClip { + public function UnlinkedMovieClip() { + trace("UnlinkedMovieClip before super(): this.graphics: " + this.graphics + " this.numChildren = " + this.numChildren); + super(); + trace("UnlinkedMovieClip after super(): this.graphics: " + this.graphics + " this.numChildren = " + this.numChildren); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedShape.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedShape.as new file mode 100644 index 000000000000..a80034266a39 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedShape.as @@ -0,0 +1,11 @@ +package { + import flash.display.Shape; + + public class UnlinkedShape extends Shape { + public function UnlinkedShape() { + trace("UnlinkedShape before super(): this.graphics: " + this.graphics); + super(); + trace("UnlinkedShape after super(): this.graphics: " + this.graphics); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSound.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSound.as new file mode 100644 index 000000000000..ef66cb14afdf --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSound.as @@ -0,0 +1,11 @@ +package { + import flash.media.Sound; + + public class UnlinkedSound extends Sound { + public function UnlinkedSound() { + trace("UnlinkedSound before super(): this.bytesLoaded = " + this.bytesLoaded); + super(); + trace("UnlinkedSound after super(): this.bytesLoaded = " + this.bytesLoaded); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSprite.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSprite.as new file mode 100644 index 000000000000..b539de0fb712 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedSprite.as @@ -0,0 +1,11 @@ +package { + import flash.display.Sprite; + + public class UnlinkedSprite extends Sprite { + public function UnlinkedSprite() { + trace("UnlinkedSprite before super(): this.graphics: " + this.graphics + " this.numChildren = " + this.numChildren); + super(); + trace("UnlinkedSprite after super(): this.graphics: " + this.graphics + " this.numChildren = " + this.numChildren); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedTextField.as b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedTextField.as new file mode 100644 index 000000000000..cf44d147272b --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/UnlinkedTextField.as @@ -0,0 +1,11 @@ +package { + import flash.text.TextField; + + public class UnlinkedTextField extends TextField { + public function UnlinkedTextField() { + trace("UnlinkedTextField before super(): this.mouseEnabled = " + this.gridFitType); + super(); + trace("UnlinkedTextField after super(): this.mouseEnabled = " + this.gridFitType); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_early_init/bitmap_test.png b/tests/tests/swfs/avm2/displayobject_early_init/bitmap_test.png new file mode 100644 index 0000000000000000000000000000000000000000..2ccb10f624a43667463445382921a06ac0c8b095 GIT binary patch literal 2916 zcmeH}Sya;p7RLVplprEl8Nz^s6fEe>7!)cDYa%;ZK%rF$5(Jb*3;_f}h#?s%vQ>nk zLRkcqwSc6`5=kIoN1>KQAVLf&o2*GN_$O>hiZd_sI_J#Goa4j2zx(h#-1D7#&-v0W zc(|w?&^Z7AfSQ}Dqt_l^ek$nxz5et{eeoVtB3*rM1Ayw0PXz%AinR9zEjP!r-^LdS ziWcIIxM@2QA09d!!=8m0LX#a9z62ga7ok?p8tK$b^g2jAp>+ZB z5cuAp)NoPz>~RGvh0{Gx_5=)`n0f}<Z1zb9>;(Q*XqM|~$Hr>TrdQ-*3^I14Xa8OWCjOW0>0599n#hJ66D4lv! z<;iR#Nit)8Z~sR}n-k^^I#VBIhpZ9Ai057jUl&?X1a@$n_#v*4L-X(B?Cx$gSd%tZ zbHfjgWKlQaobhpU-pY{S(&QvY@?o~GLo{Ck>7JzH{Uxgt4K4hnu8)MgxJRPoX%Uo`&jjp7LdGN2c>$hamok~)?Tt-$x#1^Vh>u5B5ftETMC09b=qBg)Oih;7F znw{vJJEm|KiI6c_ceYFmj9v$QR*AI193`fBVn+$tut zj-_V;iy-p5C`4&zvZ~?V`;W5fP`j9HSb=OI?TE2CWJZqUylW-i4o2T$U#4O8c<0-i z#WQkng=4l8tbIogO5zV(;qO#=mY9=!djw~^xf^0}G@Zeit+_-{5%Lx!mtF(aC_f(ct=JW6z}e+QY#YBqk=?#}E@wo*l4 zf90Ioc*P8B*t`VWij!dL2@ucl9juwcpEDC;1aEpWU@jcSn}Rr0P9;qRa|LZ9t>!@C zZp%xrOMt*NA)k%1TCXPcZrk+QmS@x!_iG;SKeO+x0Qf*2D=U>7;qA3`Btsx_@^9P; zS>d~ljwI#266@II(MpnuoqITm0%C3dx%orQhG4oYg_i*{an@j-WV4<>H)U+_n1nL( z@Y3D?2mfc1}WcCWS+o@8i&}9kGv3Wrs|WnU~BZvmjkKZ zD_iReg$Lp<$!}7Oo}OK9C|q9{#1knuZrs?F<(q}{(wJR;q3uLAO0V**>ZUFPWZQ+H zn{!Altff8!U?eeaBnNV1a&Gwgc+dLR=vLuR?;q5hyhRs0svd`x;6_92bCeL2D5d;k zlIlYVxt;Dx-DLqp-oCezP&^2A@4l?%FA^D1#l@O%kQT^BIBZ` z+j5K0K*4nBbgp1jh?XJ|SbagG-~s#hkIfO*JtxIF<#>)7IxZ|*7`gn^$;5f*eQO5b z%45k74KC1gT#9@u%^H9iQLQMf3P+>uy>|q!;6?a&+*RQDdFquZu)1q4$T$O<{H65aZi#x3p(;N4X8^BML10l_?&O5!HO6Q;*d&e4OHO7{K857s2w`IX#NZ+h*U zBqS~FoPFq0u)Q0oHAeBZ9LCRM*%3@Uxq-o8RN%Vi*$t0`W7thm9p9oH^j2A~&!cP~ zy*}cW&~_w<2=Pzxf}!)%x3UIk^r}7wh!;HVXTD_oXVreDQ|x2W+|h3136Q{eNzR>S zw_TmpYj4IWt~9HSrPbgXpfZo){c`IIOxTn|e&p9xDM)h4h6#f_S7TeqaY1ZI;~#ceqrWvbsh zkqaTnRk5smDVfr_;`b$+uT`iTIzk+biw?O6YmoCw=_&U&hH!LW`g!(bL=~AemDm{a zoh*?uSbn$zwJ);D`*~!@^daOH?A|l#ufE9iM|QnZO3P(f%#Q9hu}M11k!J-OTSr#h z_o3INjG`2wor;i8Q2_DpH1V%=pr9s%glADTvI1>^&-iS?|L6)f)uTJf#+IjJUhKtY Oz|G0SvEKgL-9G^J6xT`s literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/displayobject_early_init/data.txt b/tests/tests/swfs/avm2/displayobject_early_init/data.txt new file mode 100644 index 000000000000..a46c98ae9979 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/data.txt @@ -0,0 +1 @@ +This is some text diff --git a/tests/tests/swfs/avm2/displayobject_early_init/noise.mp3 b/tests/tests/swfs/avm2/displayobject_early_init/noise.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..862f41452ee420c77b6e151132e8235a042ba864 GIT binary patch literal 4180 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 I&M!;;2eVKzJpcdz literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/displayobject_early_init/output.txt b/tests/tests/swfs/avm2/displayobject_early_init/output.txt new file mode 100644 index 000000000000..d339cf1e39f8 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/output.txt @@ -0,0 +1,54 @@ +MyImage before super(): width=1 height=1 +Caught error: ArgumentError: Error #2015: Invalid BitmapData. +MyImage after super(): this.width=300 this.height=300 pixel: 39679 +MySprite before super(): this.graphics: [object Graphics] this.numChildren = 1 this.getChildAt(0) = null this.parent = [object Main] +MySprite after super(): this.graphics === earlyGraphics: true this.numChildren = 2 this.getChildAt(0) = [object Shape] this.parent = [object Main] +MyMovieClip before super(): this.graphics: [object Graphics] this.numChildren = 1 this.getChildAt(0) = null this.parent = [object Main] +MyMovieClip after super(): this.graphics === earlyGraphics: true this.numChildren = 2 this.getChildAt(0) = [object Shape] this.parent = [object Main] +Constructing MyImage from ActionScript +MyImage before super(): width=42 height=24 +Caught error: ArgumentError: Error #2015: Invalid BitmapData. +MyImage after super(): this.width=300 this.height=300 pixel: 39679 +Image: [object MyImage] +UnlinkedBitmapData before super() +Caught error: ArgumentError: Error #2015: Invalid BitmapData. +UnlinkedBitmapData after super(): this.width=100 +Constructing MySprite from ActionScript +MySprite before super(): this.graphics: [object Graphics] this.numChildren = 1 this.getChildAt(0) = null this.parent = null +MySprite after super(): this.graphics === earlyGraphics: true this.numChildren = 2 this.getChildAt(0) = [object Shape] this.parent = null +mySprite: [object MySprite] +Constructing MyMovieClip from ActionScript +MyMovieClip before super(): this.graphics: [object Graphics] this.numChildren = 1 this.getChildAt(0) = null this.parent = null +MyMovieClip after super(): this.graphics === earlyGraphics: true this.numChildren = 2 this.getChildAt(0) = [object Shape] this.parent = null +myMovieClip: [object MyMovieClip] +UnlinkedSprite before super(): this.graphics: [object Graphics] this.numChildren = 0 +UnlinkedSprite after super(): this.graphics: [object Graphics] this.numChildren = 0 +UnlinkedMovieClip before super(): this.graphics: [object Graphics] this.numChildren = 0 +UnlinkedMovieClip after super(): this.graphics: [object Graphics] this.numChildren = 0 +UnlinkedLoader before super(): this.contentLoaderInfo = [object LoaderInfo] this.numChildren = 0 +UnlinkedLoader after super(): this.contentLoaderInfo = [object LoaderInfo] this.numChildren = 0 +UnlinkedShape before super(): this.graphics: [object Graphics] +UnlinkedShape after super(): this.graphics: [object Graphics] +UnlinkedButton before super(): this.mouseEnabled = true +UnlinkedButton after super(): this.mouseEnabled = true +UnlinkedTextField before super(): this.mouseEnabled = pixel +UnlinkedTextField after super(): this.mouseEnabled = pixel +UnlinkedByteArray before super(): this.objectEncoding = 3 +UnlinkedByteArray after super(): this.objectEncoding = 3 +UnlinkedSound before super(): this.bytesLoaded = 0 +UnlinkedSound after super(): this.bytesLoaded = 0 +Constructing MyButton from ActionScript +Constructed OverButtonState +Constructed OverButtonState +MyButton before super(): this.mouseEnabled = true this.parent = null +MyButton after super(): this.mouseEnabled = true this.parent = null +myButton: [object MyButton] +Constructing BoundByteArray from ActionScript +BoundByteArray before super(): this.bytesAvailable = 18 +BoundByteArray after super(): this.bytseAvailable = 18 +boundByteArray: This is some text + +Constructing BoundSound from ActionScriot +BoundSound before super(): this.bytesLoaded = 0 this.bytesTotal = 0 +BoundSound after super(): this.bytesLoaded = 4180 this.bytesTotal = 4180 +boundSound: [object BoundSound] diff --git a/tests/tests/swfs/avm2/displayobject_early_init/test.fla b/tests/tests/swfs/avm2/displayobject_early_init/test.fla new file mode 100644 index 0000000000000000000000000000000000000000..4dde25a93e1f4d2389c2d5582b83d2200583bda2 GIT binary patch literal 14160 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 Opafb-*aiI!0Qi4poMK z?D{p*Su)$(YWTu5WnbT2^L5p`|Mj1X58YzV-m~v^4)4KR^4WJ+>1(Yi->A3v;U=bB z-k&mS5-oIc`=SkkY}3PPnF!dN3KrHb*%kc!Lhr!d;&t;ucLK6T=nMQ*E literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/displayobject_early_init/test.swf b/tests/tests/swfs/avm2/displayobject_early_init/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..1b3fbc51925ec0addbc780174243076553f5350f GIT binary patch literal 14299 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 Y^YH(^CvGeBqYnE1CjTa^opDF`A7Jok7XSbN literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/displayobject_early_init/test.toml b/tests/tests/swfs/avm2/displayobject_early_init/test.toml new file mode 100644 index 000000000000..dbee897f5863 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_early_init/test.toml @@ -0,0 +1 @@ +num_frames = 1 diff --git a/tests/tests/swfs/avm2/displayobject_subclass/Main.as b/tests/tests/swfs/avm2/displayobject_subclass/Main.as new file mode 100644 index 000000000000..e2c2aade823e --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_subclass/Main.as @@ -0,0 +1,18 @@ +package { + import flash.display.DisplayObject; + + public class Main { + public function Main() { + try { + new MyDisplayObjectSubclass(); + } catch (e) { + trace("Caught err: " + e); + } + try { + new DisplayObject(); + } catch (e) { + trace("Caught err: " + e); + } + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_subclass/MyDisplayObjectSubclass.as b/tests/tests/swfs/avm2/displayobject_subclass/MyDisplayObjectSubclass.as new file mode 100644 index 000000000000..5bfe84a48248 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_subclass/MyDisplayObjectSubclass.as @@ -0,0 +1,10 @@ +package { + import flash.display.DisplayObject; + + public class MyDisplayObjectSubclass extends DisplayObject { + public function MyDisplayObjectSubclass() { + trace("ERR - constructor should not be reachable"); + super(); + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/displayobject_subclass/output.txt b/tests/tests/swfs/avm2/displayobject_subclass/output.txt new file mode 100644 index 000000000000..b67800f4b0e8 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_subclass/output.txt @@ -0,0 +1,2 @@ +Caught err: ArgumentError: Error #2012: MyDisplayObjectSubclass$ class cannot be instantiated. +Caught err: ArgumentError: Error #2012: DisplayObject$ class cannot be instantiated. diff --git a/tests/tests/swfs/avm2/displayobject_subclass/test.fla b/tests/tests/swfs/avm2/displayobject_subclass/test.fla new file mode 100644 index 0000000000000000000000000000000000000000..7cf5792a9835c54c21b7c4bee4972cb7f6773e00 GIT binary patch literal 3815 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 Mlz`_)c?JOd4^LtBBme*a literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/displayobject_subclass/test.swf b/tests/tests/swfs/avm2/displayobject_subclass/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..361041f986a41def8fe758233de0df72a0a6a1c0 GIT binary patch literal 766 zcmVL^Px2Xzb%4SiKm}oT z&;o$Ec6fL=R_tD^P1o)&)|Q_xe0*>xcyQqk3*`(KxTrkNQF$K2#)AZe*&pCX6_AJ(;V!-S@57 zkzqLFpnQIQ($m|fI^%Q8%g#;5>$Iad?0Ru0bfQ+L8*Do5PV8(*CzP(&ayJ5*OJ^i^ zWjl@vb81nfZtS&WSUn!X)X5>t^p9)6-Q0Ytb}L@!@5I;60H3r5pS5F2y~qBpOhuRe zYN6g~#{`$5xv~@bu@vW=$(milidnKNRw-K=v+ zhiwyW3%OO{c!{$soK-m+&7>c`rlqTT82s7Oe*s3iXQsRg*VWMS3Pl3YVy)Crsajm2Z^z`xkyyf%F0D%g(~UV=?6l9+N& zkOaMvX=Dx#cd z>U6JSwOVa4@+(3U(axlV95ItEP{zds8@Pz1Um+|;?ov+>aU*|lIl&tAw)j$BJBr#= w#-8j634clqh-N`Fi=t`Ly{c8yt7ROFB^63}G<2zdZl`{q@R%aM03p3{2%%tq@Bjb+ literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/displayobject_subclass/test.toml b/tests/tests/swfs/avm2/displayobject_subclass/test.toml new file mode 100644 index 000000000000..dbee897f5863 --- /dev/null +++ b/tests/tests/swfs/avm2/displayobject_subclass/test.toml @@ -0,0 +1 @@ +num_frames = 1 diff --git a/tests/tests/swfs/avm2/simplebutton_multi_children/Main.as b/tests/tests/swfs/avm2/simplebutton_multi_children/Main.as new file mode 100644 index 000000000000..711df8013924 --- /dev/null +++ b/tests/tests/swfs/avm2/simplebutton_multi_children/Main.as @@ -0,0 +1,26 @@ +package { + import flash.events.Event; + import flash.display.DisplayObjectContainer; + import flash.display.MovieClip; + + public class Main extends MovieClip { + public function Main() { + this.addEventListener("enterFrame", this.onEnterFrame); + } + + private function onEnterFrame(e: Event) { + var button = new MyButton(); + printChildren("upState", button.upState); + printChildren("downState", button.downState); + printChildren("overState", button.overState); + printChildren("hitTestState", button.hitTestState); + } + + private function printChildren(name: String, container: DisplayObjectContainer) { + trace(name + ": " + container); + for (var i = 0; i < container.numChildren; i++) { + trace("Child " + i + ": " + container.getChildAt(i) + " text: " + container.getChildAt(i)["text"]); + } + } + } +} \ No newline at end of file diff --git a/tests/tests/swfs/avm2/simplebutton_multi_children/MyButton.as b/tests/tests/swfs/avm2/simplebutton_multi_children/MyButton.as new file mode 100644 index 000000000000..4d8fc3d571c2 --- /dev/null +++ b/tests/tests/swfs/avm2/simplebutton_multi_children/MyButton.as @@ -0,0 +1,14 @@ +package { + + import flash.display.SimpleButton; + + + public class MyButton extends SimpleButton { + + + public function MyButton() { + super(); + } + } + +} diff --git a/tests/tests/swfs/avm2/simplebutton_multi_children/output.txt b/tests/tests/swfs/avm2/simplebutton_multi_children/output.txt new file mode 100644 index 000000000000..ae0219a23d25 --- /dev/null +++ b/tests/tests/swfs/avm2/simplebutton_multi_children/output.txt @@ -0,0 +1,20 @@ +upState: [object Sprite] +Child 0: [object TextField] text: Up state child 1 + +Child 1: [object TextField] text: Up state child 2 + +downState: [object Sprite] +Child 0: [object TextField] text: Down state child 1 + +Child 1: [object TextField] text: Down state child 2 + +overState: [object Sprite] +Child 0: [object TextField] text: Over state child 1 + +Child 1: [object TextField] text: Over state child 2 + +hitTestState: [object Sprite] +Child 0: [object TextField] text: Hit state child 1 + +Child 1: [object TextField] text: Hit state child 2 + diff --git a/tests/tests/swfs/avm2/simplebutton_multi_children/test.fla b/tests/tests/swfs/avm2/simplebutton_multi_children/test.fla new file mode 100644 index 0000000000000000000000000000000000000000..63de1eaa310180a360116c978628e9fcdbf25994 GIT binary patch literal 4672 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 b&C2(lM_eK%Ieu~q|LMd35kw!qbpiYjrPO{g literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/simplebutton_multi_children/test.swf b/tests/tests/swfs/avm2/simplebutton_multi_children/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..01668371b7a8791a405d89f08e3c42ba3e917e66 GIT binary patch literal 7854 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 literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/simplebutton_multi_children/test.toml b/tests/tests/swfs/avm2/simplebutton_multi_children/test.toml new file mode 100644 index 000000000000..ded2e363a928 --- /dev/null +++ b/tests/tests/swfs/avm2/simplebutton_multi_children/test.toml @@ -0,0 +1 @@ +num_frames = 2 diff --git a/tests/tests/swfs/avm2/sprite_with_frames/expected.png b/tests/tests/swfs/avm2/sprite_with_frames/expected.png index dfbe61c2e7525b48dc71384af07c9e6e52aef809..1e413205a7d7faaea039e9d0a234dc05d3cd7f45 100644 GIT binary patch literal 6939 zcmeHMU2Icj7(S&)$8f7ZXn`#20_epOEk@&lsh$nGjT&InP`-efV$FPOWV))dC&Q}&Kd4VHaxv( zzJ5Q?`@BD2&-1nitG8C><*v$A6eZ8S$@Q|LEP7l~Or1GPXy)Uy!68Lib;a!}+xC{} z`lP9It^3GY_e1T0?(>x{m(S`%=Y}`?ybb#r z8mhuDx%suTy9du*3k3Nsefy(9r)JceP!Pmzlr;|W$k;t|4nV0)?%u;OFNDY zV&$nC{fNh#3YSjl(6r`XQk;SFh^MRPhpDvnM@wqG*q;9AXe40!NH>BJcufr9h#Px!;2fe0{+-rt(;KYJV5e@D`43Cyt)CJo<2AlPXTF)3o>l-E`JCp# zWZ8f|m~~9Ls45pcVl|v7)lWN1h;KCc_m0|L+t-BV>?Biv5kHDL(6PXrq+4X9gFG4T zqkWD0!HqsO77?bF2pL~ADk%SdP%=FDF>Cmc!pwN`HGxG z1jUnFXZm%s(KQ-^?;=NTN>%{{93+Ufl0d5EdggM8;>F%n+xJuv3LyQ9;OD>(^jW51 z;?QJ3*uW=~E{R#P=F4j$4>=jn=4&k@Q+uSTOvbtR+BYD~JK_{(I>%Xvj?d!Rw5vy) z09*(u9$7~?k^2zf@D@7i?4%5uF3SpLT1e2`K_L?ARN>Xci!>Z5%8prA=Wcns=(}g4 zH?QH9c2gI^Q_{$lk*nbUMH1da#hxmGB9Q9#11a#hm_-ZJ zzNnz5tEH5lv*Terwu|uC)`Tz%^u*5ANqX*BpmQ9#5MX2N6|@_&g=LH=&!K?%SMpNm zB4H>qYmd$82GX_}U7G6KxM$2G+E}iFsN;QN2u%YL{Hw_iO^ZFk30R6#b~nW?S@jFSX!nTetDw(8L~e9}EUu$E#2RA6 z0$J0xF*W}JIjkc4>62U)hsZ}g7)=O<3Xe4Og#94OlZCM82DVrZa{Ez1aXtE4nG3OmD4#mH(_=1ali z00^0BwbueiI7eFHm7#P(ZKxvdYS7Tc)a7Tm8y8Q}IdnX_(>XsstBZPStwn0iozg-v zUps8c&QP!O|JM*BSBB0rbl!sgLDRUx#uYZMuyKXuzc6?EpO*B4=la82emdgnqCdS9 NcllP=;D%S5{{a#z-#!2U literal 6394 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 L`(+tR1mgb#Qh!yW diff --git a/tests/tests/swfs/avm2/sprite_with_frames/test.fla b/tests/tests/swfs/avm2/sprite_with_frames/test.fla index cf590f77b6c8acc588f039ff9587034fe58eceda..8d0a83217840bd1594bce4cd360e7294d40a1a50 100644 GIT binary patch delta 1150 zcmV-^1cCdnCgUcMxqlAUkTBB&002=8000jF002Z!O+;^Fb!}yCbS`*pY`s@)kK#5E z{$8p7!F9j1AIKXaz!g>sWVu6H_Rz6?kxr+|Nt}(_#EEQkkpB9PlPsG(_V$3S%BLju zGtYSD@ysv@-miip+UAriw9hjx-|Quu;#8^fjcM+7J7d>33V(5LI+kUdf2?jcQA%^t zV_Yi2BZ?c;0l}p~;v%F*ROIG9$uw?cViawK0FFDB(~NOC#Wo<5>^CYTEBF*Uj$t{l zO;Dl=vE)fH#lAL#e9m&BfT+xfN(zxr@$Zbs#ZF@Mxq&y^H{>&oQCK}7P`eFj+bGcY+01kc7pi0(H{G|H$bMtq9{ksg%i|fBE$33UYUb z)ron&CliRPE4-I?pcq2}>XI|#aLo~M-Er*O~veZzqhlC3JP_a)({T=ZwD z{(mF=^qkSa7`FlfDgB@7ff#+*@^fxv2d%4kW8fluVp6G+}H+Qw<#i3J%tgFw+A708tE+dJ#mC zeqU+-gXMiD_XMb*5|CkwG)z&MZTD^EBo6Uz;vm~8q`!WTlMDl8It6C6d5SOReCP6= zb36(^F2gde3d$AQ7de;j_L7ZprquSGY3_DAW9J&B*qDxG*?;Dr%lmbl(Sr0Cmx}P1 z;#TS)!KFcxGNMLY7Un+9wcNnOD6WJ6j7L_`oN+qFHb|!VXDTEs`4~HnVL5P3P@+n) z;AuI=6RikMI4g((plwc6T8d(fzc8MZJBiWPR=mBwCSPfSqWVb!b=Q#AjiQR>33BW{ zMg{r16i3LoJ%4(04f9t948{T_j*OOIdT$7*T)RDv*>b_`NU7?HH#dm-Osx zMK)Ca=x{DbK__vuKHN!JPF207zyGla$2bhFFq}^3J%4&P?|J^z=?&+O*PFPOHwc|c z&=2OVOm~0c4MD)Qr^9eI@w`dj_U*v4ro)*xbHXWp|9|T*NPi<)7g3qZr**rz;Bj6h z6lH>@W4x?q8N|eZ>|(?eEi^*lxv6C(ZqL%6?F=x=iB!un(E&;zslmV=_*O9Ruz5f; zzk?g8js)Ks091UU2jUPN$f!;LvNcLgMM$?QyW=FvHIxz+#U~0{EzMPVesI9J*B3f~ z=Kn7Mh=0qxgarR)S#$UfbnRdelWUsOSiJd{69{>X$=V;UMD;3?gYv4zn;w1#Mc zWy3y1_opgaJz$!y-=8C%Vy~ODEV@EQIg11l^#XGJ&;+NWz=c*E>4xGHY=5m-E4yrD zk%DkImS?y=Myl5TeZ%&jNp-P4^EP8fN)Rq}w|^nJL{}x_>NbZOQ3URIMgY!$FFnUL z>|0!Un@uD0Ea%q}MgegA2%Qn_SfVm$2nMvojIvDzrQ*7V10Iq}m3R9s;g{6Pi%|a& ze|pZqH-;U7fJ*--dmu)iDt=8x9!cv)*ebY5zEu)uL=fm$&VN!ebRm*6BK7hx1@!>UZfFq;Lx4GX`-;G&qv9IJ)TkeO7y>OJ67tfMLe>1*borUJB!?01( z4B;0hx%t8A0{{S&3zM!9O#ye4{1HL{s*^twKmy?m zlYtT>8-pS)#3}#)04e|g022TJ00000000000000HlfV){0c?{26F?$A5C8yeX>Db6 cd2nS=O9ci10000B01E)o0ssJh5C8xG062d0S^xk5 diff --git a/tests/tests/swfs/avm2/sprite_with_frames/test.swf b/tests/tests/swfs/avm2/sprite_with_frames/test.swf index 126e575b0eb0a3c91dfa9f89da6ce592dd1266dd..2318486008bfdc81ed1dcd2d679c0b55ec11cadf 100644 GIT binary patch literal 5657 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 literal 5240 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