Skip to content

avm2: Move DisplayObject assignment into an initializer #11084

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/src/avm2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions core/src/avm2/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -188,6 +189,7 @@ impl<'gc> SystemClasses<'gc> {
graphicstrianglepath: object,
graphicssolidfill: object,
graphicsstroke: object,
loader: object,
loaderinfo: object,
bytearray: object,
stage: object,
Expand Down Expand Up @@ -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),
Expand Down
1 change: 1 addition & 0 deletions core/src/avm2/globals/flash/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions core/src/avm2/globals/flash/display/Bitmap.as
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
8 changes: 2 additions & 6 deletions core/src/avm2/globals/flash/display/Loader.as
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package flash.display {

[Ruffle(InstanceAllocator)]
public class Loader extends DisplayObjectContainer {
import flash.display.LoaderInfo;
import flash.display.DisplayObject;
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion core/src/avm2/globals/flash/display/MorphShape.as
Original file line number Diff line number Diff line change
@@ -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`
}
}
}
7 changes: 2 additions & 5 deletions core/src/avm2/globals/flash/display/Shape.as
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
1 change: 1 addition & 0 deletions core/src/avm2/globals/flash/display/SimpleButton.as
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 1 addition & 6 deletions core/src/avm2/globals/flash/display/Sprite.as
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
129 changes: 64 additions & 65 deletions core/src/avm2/globals/flash/display/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<Object<'gc>, 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<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, 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());
Expand All @@ -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!();
}
}

Expand Down
Loading