Skip to content
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

avm2: Perform early allocation and exposing of SimpleButton object #14182

Merged
merged 3 commits into from
Nov 30, 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
51 changes: 25 additions & 26 deletions core/src/display_object/avm2_button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,21 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {

let needs_frame_construction = self.0.read().needs_frame_construction;
if needs_frame_construction {
if needs_avm2_construction {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
match Avm2StageObject::for_display_object(&mut activation, (*self).into(), class) {
Ok(object) => {
self.0.write(activation.context.gc_context).object = Some(object.into())
}
Err(e) => tracing::error!("Got {} when constructing AVM2 side of button", e),
};
if !self.placed_by_script() {
// This is run before we actually call the constructor - the un-constructed object
// is exposed to ActionScript via `parent.<childName>`.
self.set_on_parent_field(&mut activation.context);
}
}

// Prevent re-entrantly constructing this button (since we may run a nested frame here)
self.0.write(context.gc_context).needs_frame_construction = false;
let (up_state, up_should_fire) = self.create_state(context, swf::ButtonState::UP);
Expand Down Expand Up @@ -548,36 +563,20 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {
if needs_avm2_construction {
self.set_state(context, ButtonState::Up);

let mut activation = Avm2Activation::from_nothing(context.reborrow());
match Avm2StageObject::for_display_object(&mut activation, (*self).into(), class) {
Ok(object) => {
self.0.write(activation.context.gc_context).object = Some(object.into())
}
Err(e) => tracing::error!("Got {} when constructing AVM2 side of button", e),
};

if !self.placed_by_script() {
// This is run before we actually call the constructor - the un-constructed object
// is exposed to ActionScript via `parent.<childName>`.
self.set_on_parent_field(&mut activation.context);
}

if has_movie_clip_state && self.movie().version() > 9 {
self.0
.write(activation.context.gc_context)
.weird_framescript_order = true;

let stage = activation.context.stage;

stage.construct_frame(&mut activation.context);
stage.frame_constructed(&mut activation.context);
self.set_state(&mut activation.context, ButtonState::Up);
stage.run_frame_scripts(&mut activation.context);
stage.exit_frame(&mut activation.context);
self.0.write(context.gc_context).weird_framescript_order = true;

let stage = context.stage;
stage.construct_frame(context);
stage.frame_constructed(context);
self.set_state(context, ButtonState::Up);
stage.run_frame_scripts(context);
stage.exit_frame(context);
}

let avm2_object = self.0.read().object;
if let Some(avm2_object) = avm2_object {
let mut activation = Avm2Activation::from_nothing(context.reborrow());
if let Err(e) = class.call_native_init(avm2_object.into(), &[], &mut activation)
{
tracing::error!("Got {} when constructing AVM2 side of button", e);
Expand All @@ -586,7 +585,7 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {

// Note - we do *not* call `on_construction_complete` here, since we already
// set the button object on a parent field (and we don't want to re-run a setter)
self.fire_added_events(&mut activation.context);
self.fire_added_events(context);
}
}
}
Expand Down
71 changes: 71 additions & 0 deletions tests/tests/swfs/avm2/simplebutton_childevents/Main.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package
{
import flash.display.*;
import flash.events.*;
import flash.system.*;

public class Main extends EventWatcher
{

public static var frame1ScriptRan:Array = [];

public static var frame2ScriptRan:Array = [];


public var my_button:SimpleButton;

public static var INSTANCE: Main;

public function Main()
{
INSTANCE = this;
var self:*;

addFrameScript(0,this.frame1,1,this.frame2);
self = this;
this.addEventListener(Event.EXIT_FRAME,function(e:*):*
{
frame1ScriptRan.sort();
frame2ScriptRan.sort();
trace("frame1ScriptRan = " + frame1ScriptRan);
trace("frame2ScriptRan = " + frame2ScriptRan);
frame1ScriptRan = [];
frame2ScriptRan = [];
});
trace("Calling Main super()");
super();
}

public function stop_display_object_handlers(dobj:DisplayObject) : *
{
var i:* = undefined;
if(dobj instanceof EventWatcher)
{
dobj.destroy();
}
if(dobj instanceof DisplayObjectContainer)
{
for(i = 0; i < dobj.numChildren; i += 1)
{
this.stop_display_object_handlers(dobj.getChildAt(i));
}
}
}

internal function frame1() : *
{
Main.frame1ScriptRan.push("MainTimeline");
}

internal function frame2() : *
{
Main.frame2ScriptRan.push("MainTimeline");
this.stop();
this.stop_display_object_handlers(this.my_button.upState);
this.stop_display_object_handlers(this.my_button.downState);
this.stop_display_object_handlers(this.my_button.overState);
this.stop_display_object_handlers(this.my_button.hitTestState);
System.gc();
}
}
}
16 changes: 16 additions & 0 deletions tests/tests/swfs/avm2/simplebutton_childevents/MyButton.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package {

import flash.display.SimpleButton;


public class MyButton extends SimpleButton {


public function MyButton() {
trace("Calling MyButton super()");
super();
trace("Called MyButton super()");
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

public class UpButtonShape extends EventWatcher {
public function UpButtonShape() {
trace("//Constructed UpButtonShape (", this.name, "): this.parent = " + this.parent + " this.stage " + this.stage);
trace("//Constructed UpButtonShape (", this.name, "): this.parent = " + this.parent + " this.stage " + this.stage + " Main.INSTANCE.my_button = " + Main.INSTANCE.my_button);
}
}

Expand Down
6 changes: 4 additions & 2 deletions tests/tests/swfs/avm2/simplebutton_childevents/output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ instance2:[Event type="added" bubbles=true cancelable=false eventPhase=3] target
target.stage: [object Stage] target.name: instance3 target.parent: [object UpButtonShape] target.parent.parent: null
root1:[Event type="added" bubbles=true cancelable=false eventPhase=3] target: [object Shape]
target.stage: [object Stage] target.name: instance3 target.parent: [object UpButtonShape] target.parent.parent: null
//Constructed UpButtonShape ( instance2 ): this.parent = null this.stage [object Stage]
//Constructed UpButtonShape ( instance2 ): this.parent = null this.stage [object Stage] Main.INSTANCE.my_button = [object MyButton]
instance4:[Event type="added" bubbles=true cancelable=false eventPhase=3] target: [object Shape]
target.stage: [object Stage] target.name: instance5 target.parent: [object OverButtonShape] target.parent.parent: null
root1:[Event type="added" bubbles=true cancelable=false eventPhase=3] target: [object Shape]
Expand Down Expand Up @@ -38,7 +38,9 @@ instance4:[Event type="exitFrame" bubbles=false cancelable=false eventPhase=2] t
target.stage: null target.name: instance4 target.parent: null target.parent.parent: <missing>
instance6:[Event type="exitFrame" bubbles=false cancelable=false eventPhase=2] target: [object DownButtonShape]
target.stage: null target.name: instance6 target.parent: null target.parent.parent: <missing>
root1:[Event type="added" bubbles=true cancelable=false eventPhase=3] target: [object SimpleButton]
Calling MyButton super()
Called MyButton super()
root1:[Event type="added" bubbles=true cancelable=false eventPhase=3] target: [object MyButton]
target.stage: [object Stage] target.name: my_button target.parent: [object Main] target.parent.parent: [object Stage]
root1:[Event type="added" bubbles=true cancelable=false eventPhase=2] target: [object Main]
target.stage: [object Stage] target.name: root1 target.parent: [object Stage] target.parent.parent: null
Expand Down
Binary file modified tests/tests/swfs/avm2/simplebutton_childevents/test.fla
Binary file not shown.
Binary file modified tests/tests/swfs/avm2/simplebutton_childevents/test.swf
Binary file not shown.
98 changes: 98 additions & 0 deletions tests/tests/swfs/avm2/simplebutton_symbolclass/Main.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package
{
import flash.accessibility.*;
import flash.display.*;
import flash.errors.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.media.*;
import flash.net.*;
import flash.net.drm.*;
import flash.system.*;
import flash.text.*;
import flash.text.ime.*;
import flash.ui.*;
import flash.utils.*;

public dynamic class Main extends MovieClip
{

public static var INSTANCE: Main;


public var timeline_symbol:MyButton;

public var my_button:*;

public function Main()
{
INSTANCE = this;
trace("Calling Main super()");
super();
trace("Called Main super()");
addFrameScript(0,this.frame1,1,this.frame2);
}

public function inspect_display_object(dobj:DisplayObject) : *
{
var i:* = undefined;
trace(dobj);
if(dobj instanceof DisplayObjectContainer)
{
trace("// numChildren: ",dobj.numChildren);
for(i = 0; i < dobj.numChildren; i += 1)
{
trace(dobj.getChildAt(i));
}
}
}

internal function frame1() : *
{
trace("//var my_button = new MyButton();");
this.my_button = new MyButton();
trace("//this.addChild(my_button);");
this.addChild(this.my_button);
trace("//my_button");
trace(this.my_button);
trace("//my_button.upState");
this.inspect_display_object(this.my_button.upState);
trace("//my_button.overState");
this.inspect_display_object(this.my_button.overState);
trace("//my_button.downState");
this.inspect_display_object(this.my_button.downState);
trace("//my_button.hitTestState");
this.inspect_display_object(this.my_button.hitTestState);
trace("//my_button.upState = new UpButtonShape();");
this.my_button.upState = new UpButtonShape();
trace("//my_button.overState = new OverButtonShape();");
this.my_button.overState = new OverButtonShape();
trace("//my_button.downState = new DownButtonShape();");
this.my_button.downState = new DownButtonShape();
trace("//my_button.hitTestState = new HitButtonShape();");
this.my_button.hitTestState = new HitButtonShape();
trace("//my_button.upState");
this.inspect_display_object(this.my_button.upState);
trace("//my_button.overState");
this.inspect_display_object(this.my_button.overState);
trace("//my_button.downState");
this.inspect_display_object(this.my_button.downState);
trace("//my_button.hitTestState");
this.inspect_display_object(this.my_button.hitTestState);
}

internal function frame2() : *
{
trace("//this.timeline_symbol.upState");
this.inspect_display_object(this.timeline_symbol.upState);
trace("//this.timeline_symbol.overState");
this.inspect_display_object(this.timeline_symbol.overState);
trace("//this.timeline_symbol.downState");
this.inspect_display_object(this.timeline_symbol.downState);
trace("//this.timeline_symbol.hitTestState");
this.inspect_display_object(this.timeline_symbol.hitTestState);
this.stop();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

public class OverButtonShape extends MovieClip {
public function OverButtonShape() {
trace("//Constructed OverButtonShape (", this.name, ")!");
trace("//Constructed OverButtonShape (", this.name, "): Main.INSTANCE.my_button = " + Main.INSTANCE.my_button);
}
}

Expand Down
8 changes: 5 additions & 3 deletions tests/tests/swfs/avm2/simplebutton_symbolclass/output.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
Calling Main super()
Called Main super()
//var my_button = new MyButton();
//Constructed UpButtonShape ( instance3 )!
//Constructed OverButtonShape ( instance5 )!
//Constructed OverButtonShape ( instance5 ): Main.INSTANCE.my_button = undefined
//Constructed DownButtonShape ( instance7 )!
///MyButton constructor!
//this.addChild(my_button);
Expand All @@ -24,7 +26,7 @@
//my_button.upState = new UpButtonShape();
//Constructed UpButtonShape ( instance11 )!
//my_button.overState = new OverButtonShape();
//Constructed OverButtonShape ( instance13 )!
//Constructed OverButtonShape ( instance13 ): Main.INSTANCE.my_button = [object MyButton]
//my_button.downState = new DownButtonShape();
//Constructed DownButtonShape ( instance15 )!
//my_button.hitTestState = new HitButtonShape();
Expand All @@ -46,7 +48,7 @@
// numChildren: 1
[object Shape]
//Constructed UpButtonShape ( instance20 )!
//Constructed OverButtonShape ( instance22 )!
//Constructed OverButtonShape ( instance22 ): Main.INSTANCE.my_button = [object MyButton]
//Constructed DownButtonShape ( instance24 )!
//this.timeline_symbol.upState
[object Sprite]
Expand Down
Binary file modified tests/tests/swfs/avm2/simplebutton_symbolclass/test.fla
100644 → 100755
Binary file not shown.
Binary file modified tests/tests/swfs/avm2/simplebutton_symbolclass/test.swf
Binary file not shown.