2020-07-04 21:18:41 +00:00
|
|
|
use crate::avm2::activation::Activation;
|
2020-07-07 04:24:16 +00:00
|
|
|
use crate::avm2::class::Class;
|
2020-09-24 03:35:11 +00:00
|
|
|
use crate::avm2::domain::Domain;
|
2021-06-19 01:49:40 +00:00
|
|
|
use crate::avm2::method::{Method, NativeMethodImpl};
|
2022-12-18 21:56:55 +00:00
|
|
|
use crate::avm2::object::{ClassObject, FunctionObject, Object, ScriptObject, TObject};
|
2021-09-07 22:17:38 +00:00
|
|
|
use crate::avm2::scope::{Scope, ScopeChain};
|
2020-09-24 03:35:11 +00:00
|
|
|
use crate::avm2::script::Script;
|
2022-06-15 19:00:17 +00:00
|
|
|
use crate::avm2::Avm2;
|
2020-07-04 21:18:41 +00:00
|
|
|
use crate::avm2::Error;
|
2022-09-09 21:33:30 +00:00
|
|
|
use crate::avm2::Multiname;
|
2022-08-12 22:29:46 +00:00
|
|
|
use crate::avm2::Namespace;
|
|
|
|
use crate::avm2::QName;
|
2021-12-13 11:31:24 +00:00
|
|
|
use crate::string::AvmString;
|
2021-07-28 00:08:26 +00:00
|
|
|
use crate::tag_utils::{self, ControlFlow, SwfMovie, SwfSlice, SwfStream};
|
2020-07-07 04:24:16 +00:00
|
|
|
use gc_arena::{Collect, GcCell, MutationContext};
|
2022-06-15 19:00:17 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use swf::TagCode;
|
2020-02-12 19:58:33 +00:00
|
|
|
|
2020-08-26 03:10:59 +00:00
|
|
|
mod array;
|
2023-03-07 23:16:47 +00:00
|
|
|
mod avmplus;
|
2020-07-17 02:33:26 +00:00
|
|
|
mod boolean;
|
2020-03-09 01:53:33 +00:00
|
|
|
mod class;
|
2021-07-27 23:58:13 +00:00
|
|
|
mod date;
|
2022-08-28 18:23:58 +00:00
|
|
|
mod error;
|
2022-08-28 20:45:10 +00:00
|
|
|
pub mod flash;
|
2020-02-19 03:26:08 +00:00
|
|
|
mod function;
|
2020-09-22 00:37:22 +00:00
|
|
|
mod global_scope;
|
2020-07-17 02:33:26 +00:00
|
|
|
mod int;
|
2021-12-13 17:32:04 +00:00
|
|
|
mod json;
|
2020-11-10 23:43:44 +00:00
|
|
|
mod math;
|
2020-07-17 02:33:26 +00:00
|
|
|
mod namespace;
|
|
|
|
mod number;
|
2020-02-19 03:26:08 +00:00
|
|
|
mod object;
|
2023-04-01 01:25:08 +00:00
|
|
|
mod q_name;
|
2023-03-27 03:45:18 +00:00
|
|
|
mod reg_exp;
|
2020-07-17 02:33:26 +00:00
|
|
|
mod string;
|
2021-12-13 11:31:24 +00:00
|
|
|
mod toplevel;
|
2020-07-17 02:33:26 +00:00
|
|
|
mod r#uint;
|
2021-03-13 03:24:20 +00:00
|
|
|
mod vector;
|
2021-01-15 22:35:10 +00:00
|
|
|
mod xml;
|
|
|
|
mod xml_list;
|
2020-02-19 03:26:08 +00:00
|
|
|
|
2021-06-19 23:07:55 +00:00
|
|
|
/// This structure represents all system builtin classes.
|
2021-05-28 02:22:38 +00:00
|
|
|
#[derive(Clone, Collect)]
|
|
|
|
#[collect(no_drop)]
|
2021-06-18 22:11:37 +00:00
|
|
|
pub struct SystemClasses<'gc> {
|
2021-09-24 20:54:36 +00:00
|
|
|
pub object: ClassObject<'gc>,
|
|
|
|
pub function: ClassObject<'gc>,
|
|
|
|
pub class: ClassObject<'gc>,
|
|
|
|
pub global: ClassObject<'gc>,
|
|
|
|
pub string: ClassObject<'gc>,
|
|
|
|
pub boolean: ClassObject<'gc>,
|
|
|
|
pub number: ClassObject<'gc>,
|
|
|
|
pub int: ClassObject<'gc>,
|
|
|
|
pub uint: ClassObject<'gc>,
|
|
|
|
pub namespace: ClassObject<'gc>,
|
|
|
|
pub array: ClassObject<'gc>,
|
|
|
|
pub movieclip: ClassObject<'gc>,
|
|
|
|
pub framelabel: ClassObject<'gc>,
|
|
|
|
pub scene: ClassObject<'gc>,
|
|
|
|
pub application_domain: ClassObject<'gc>,
|
|
|
|
pub event: ClassObject<'gc>,
|
2021-08-25 08:02:53 +00:00
|
|
|
pub fullscreenevent: ClassObject<'gc>,
|
2021-09-24 20:54:36 +00:00
|
|
|
pub video: ClassObject<'gc>,
|
|
|
|
pub xml: ClassObject<'gc>,
|
|
|
|
pub xml_list: ClassObject<'gc>,
|
|
|
|
pub display_object: ClassObject<'gc>,
|
|
|
|
pub shape: ClassObject<'gc>,
|
|
|
|
pub textfield: ClassObject<'gc>,
|
|
|
|
pub textformat: ClassObject<'gc>,
|
|
|
|
pub graphics: ClassObject<'gc>,
|
2023-03-16 10:18:15 +00:00
|
|
|
pub igraphicsdata: ClassObject<'gc>,
|
2023-03-17 11:50:31 +00:00
|
|
|
pub graphicsbitmapfill: ClassObject<'gc>,
|
2023-03-17 11:52:15 +00:00
|
|
|
pub graphicsendfill: ClassObject<'gc>,
|
2023-03-17 12:01:04 +00:00
|
|
|
pub graphicsgradientfill: ClassObject<'gc>,
|
2023-03-17 12:20:24 +00:00
|
|
|
pub graphicspath: ClassObject<'gc>,
|
2023-03-18 01:03:25 +00:00
|
|
|
pub graphicstrianglepath: ClassObject<'gc>,
|
2023-03-17 12:23:14 +00:00
|
|
|
pub graphicssolidfill: ClassObject<'gc>,
|
2023-03-17 12:27:16 +00:00
|
|
|
pub graphicsstroke: ClassObject<'gc>,
|
2021-09-24 20:54:36 +00:00
|
|
|
pub loaderinfo: ClassObject<'gc>,
|
|
|
|
pub bytearray: ClassObject<'gc>,
|
|
|
|
pub stage: ClassObject<'gc>,
|
|
|
|
pub sprite: ClassObject<'gc>,
|
|
|
|
pub simplebutton: ClassObject<'gc>,
|
|
|
|
pub regexp: ClassObject<'gc>,
|
|
|
|
pub vector: ClassObject<'gc>,
|
|
|
|
pub soundtransform: ClassObject<'gc>,
|
|
|
|
pub soundchannel: ClassObject<'gc>,
|
|
|
|
pub bitmap: ClassObject<'gc>,
|
|
|
|
pub bitmapdata: ClassObject<'gc>,
|
|
|
|
pub date: ClassObject<'gc>,
|
2021-09-29 03:15:44 +00:00
|
|
|
pub qname: ClassObject<'gc>,
|
2021-12-02 05:52:06 +00:00
|
|
|
pub mouseevent: ClassObject<'gc>,
|
2022-07-25 04:09:05 +00:00
|
|
|
pub progressevent: ClassObject<'gc>,
|
2022-05-20 19:35:01 +00:00
|
|
|
pub textevent: ClassObject<'gc>,
|
|
|
|
pub errorevent: ClassObject<'gc>,
|
avm2: Partially implement `URLLoader` and related classes
This PR implements the `URLLoader` class, allowing AVM2 scripts
to load data from a URL. This requires several other related
classes (`URLLoaderDataFormat`, `URLRequest`, `IOError`) to be
implemented as well.
Currently implemented:
* Fetching from URLs using the 'navigator' backend
* The `text` and `binary` data formats (which store data
in a `String` or `ByteArray` respectively)
* The `open`, `complete`, and `ioError` events
* The `bytesLoaded`, `bytesTotal`, and `data` properties
Not yet implemented:
* The HTTP and security events
* All of the properties of `IOError`
* The properties on `URLRequest` (besides `url`)
* The "variables" data format
This should be enough to get some basic uses of `URLLoader` working
(e.g. simple GET requests to a particular website).
Note that in Flash's `playerglobal`, the `URLLoader` class is just
a think wrapper around the more general `URLStream`. However,
implementing `URLStream` will require changes to `Navigator``
to support notifications when data arrives in the stream. When
that happens, we should be able to re-use a large amount of the
code in this PR.
2022-04-06 01:27:39 +00:00
|
|
|
pub ioerrorevent: ClassObject<'gc>,
|
2022-05-20 19:35:01 +00:00
|
|
|
pub securityerrorevent: ClassObject<'gc>,
|
avm2: Implement DisplayObject.transform and most of Transform
This PR implements the 'DisplayObject.transform' getters/setters,
and most of the getters/setters in the `Transform` class
From testing in FP, it appears that each call to the
'DisplayObject.transform' property produces a new
'Transform' instance, which is permanently tied to the
owner 'DisplayObject'. All of the getters/setters in
`Transform` operate directly on owner `DisplayObject`.
However, note that the `Matrix` and `ColorTransform`
valuse *produced* the getter are plain ActionScript objects,
and have no further tie to the `DisplayObject`.
Using the `DisplayObject.transform` setter results in
values being *copied* from the input `Transform` object.
The input object retains its original owner `DisplayObject`.
Not implemented:
* Transform.concatenatedColorTransform
* Transform.pixelBounds
When a DisplayObject is not a descendant of the stage,
the `concatenatedMatrix` property produces a bizarre matrix:
a scale matrix that the depends on the global state quality.
Any DisplayObject that *is* a descendant of the stage has
a `concatenatedMatrix` that does not depend on the stage quality.
I'm not sure why the behavior occurs - for now, I just manually
mimic the values prdduced by FP. However, these values may indicate
that we need to do some internal scaling based on stage quality values,
and then 'undo' this in certain circumstances when constructing
an ActionScript matrix.
Unfortunately, some of the computed 'concatenatedMatrix' values
are off by f32::EPSILON. This is likely due to us storing some
internal values in pixels rather than twips (the rounding introduced
by round-trip twips conversions could cause this slight difference0.
For now, I've opted to mark these tests as 'approximate'.
To support this, I've extended our test framework to support providing
a regex that matches floating-point values in the output. This allows
us to print out 'Matrix.toString()' and still perform approximate
comparisons between strings of the format
'(a=0, b=0, c=0, d=0, tx=0, ty=0)'
2022-06-19 20:37:31 +00:00
|
|
|
pub transform: ClassObject<'gc>,
|
|
|
|
pub colortransform: ClassObject<'gc>,
|
|
|
|
pub matrix: ClassObject<'gc>,
|
2022-07-25 04:09:05 +00:00
|
|
|
pub illegaloperationerror: ClassObject<'gc>,
|
|
|
|
pub eventdispatcher: ClassObject<'gc>,
|
2022-08-22 20:49:58 +00:00
|
|
|
pub rectangle: ClassObject<'gc>,
|
2022-08-27 23:31:00 +00:00
|
|
|
pub keyboardevent: ClassObject<'gc>,
|
2022-08-29 20:06:30 +00:00
|
|
|
pub point: ClassObject<'gc>,
|
2022-09-13 17:17:24 +00:00
|
|
|
pub rangeerror: ClassObject<'gc>,
|
|
|
|
pub referenceerror: ClassObject<'gc>,
|
|
|
|
pub argumenterror: ClassObject<'gc>,
|
2023-04-22 22:30:35 +00:00
|
|
|
pub syntaxerror: ClassObject<'gc>,
|
2022-09-21 23:06:07 +00:00
|
|
|
pub typeerror: ClassObject<'gc>,
|
2022-09-26 10:12:21 +00:00
|
|
|
pub verifyerror: ClassObject<'gc>,
|
2022-09-26 09:49:27 +00:00
|
|
|
pub ioerror: ClassObject<'gc>,
|
2022-10-04 07:12:09 +00:00
|
|
|
pub eoferror: ClassObject<'gc>,
|
2023-03-25 09:24:09 +00:00
|
|
|
pub urierror: ClassObject<'gc>,
|
2023-03-27 17:22:19 +00:00
|
|
|
pub error: ClassObject<'gc>,
|
2022-09-18 01:21:40 +00:00
|
|
|
pub uncaughterrorevents: ClassObject<'gc>,
|
2022-11-23 23:30:47 +00:00
|
|
|
pub statictext: ClassObject<'gc>,
|
2022-10-15 18:44:06 +00:00
|
|
|
pub textlinemetrics: ClassObject<'gc>,
|
avm2: Partially implement Stage3D for wgpu backend
This PR implements core 'stage3D' APIs. We are now able
to render at least two demos from the Context3D docs - a simple
triangle render, and a rotating cube.
Implemented in this PR:
* Stage3D access and Context3D creation
* IndexBuffer3D and VertexBuffer3D creation, uploading, and usage
* Program3D uploading and usage (via `naga-agal`)
* Context3D: configureBackBuffer, clear, drawTriangles, and present
Not yet implemented:
* Any 'dispose()' methods
* Depth and stencil buffers
* Context3D texture apis
* Scissor rectangle
General implementation strategy:
A new `Object` variant is added for each of the Stage3D objects
(VertexBuffer3D, Program3D, etc). This stores a handle to the
parent `Context3D`, and (depending on the object) a handle
to the underlying native resource, via `Rc<dyn
SomeRenderBackendTrait>`).
Calling methods on Context3D does not usually result in an immediate
call to a `wgpu` method. Instead, we queue up commands in our
`Context3D` instance, and execute them all on a call to `present`.
This avoids some nasty wgpu lifetime issues, and is very similar
to the approah we use for normal rendering.
The actual rendering happens on a `Texture`, with dimensions
determined by `createBackBuffer`. During 'Stage' rendering,
we render all of these Stage3D textures *behind* the normal
stage (but in front of the overall stage background color).
2022-09-18 20:50:21 +00:00
|
|
|
pub stage3d: ClassObject<'gc>,
|
|
|
|
pub context3d: ClassObject<'gc>,
|
|
|
|
pub indexbuffer3d: ClassObject<'gc>,
|
|
|
|
pub vertexbuffer3d: ClassObject<'gc>,
|
|
|
|
pub program3d: ClassObject<'gc>,
|
2023-02-11 00:18:10 +00:00
|
|
|
pub urlvariables: ClassObject<'gc>,
|
2023-02-22 22:22:12 +00:00
|
|
|
pub bevelfilter: ClassObject<'gc>,
|
|
|
|
pub bitmapfilter: ClassObject<'gc>,
|
|
|
|
pub blurfilter: ClassObject<'gc>,
|
|
|
|
pub colormatrixfilter: ClassObject<'gc>,
|
|
|
|
pub convolutionfilter: ClassObject<'gc>,
|
|
|
|
pub displacementmapfilter: ClassObject<'gc>,
|
|
|
|
pub dropshadowfilter: ClassObject<'gc>,
|
|
|
|
pub glowfilter: ClassObject<'gc>,
|
|
|
|
pub gradientbevelfilter: ClassObject<'gc>,
|
|
|
|
pub gradientglowfilter: ClassObject<'gc>,
|
2022-09-24 03:14:49 +00:00
|
|
|
pub texture: ClassObject<'gc>,
|
|
|
|
pub cubetexture: ClassObject<'gc>,
|
|
|
|
pub rectangletexture: ClassObject<'gc>,
|
2023-04-21 19:26:59 +00:00
|
|
|
pub morphshape: ClassObject<'gc>,
|
2021-05-28 02:22:38 +00:00
|
|
|
}
|
|
|
|
|
2021-06-18 22:11:37 +00:00
|
|
|
impl<'gc> SystemClasses<'gc> {
|
2021-06-19 23:07:55 +00:00
|
|
|
/// Construct a minimal set of system classes necessary for bootstrapping
|
|
|
|
/// player globals.
|
2021-05-28 02:22:38 +00:00
|
|
|
///
|
2021-06-19 23:07:55 +00:00
|
|
|
/// All other system classes aside from the three given here will be set to
|
|
|
|
/// the empty object also handed to this function. It is the caller's
|
2021-05-28 02:22:38 +00:00
|
|
|
/// responsibility to instantiate each class and replace the empty object
|
|
|
|
/// with that.
|
2021-12-04 21:32:39 +00:00
|
|
|
fn new(
|
|
|
|
object: ClassObject<'gc>,
|
|
|
|
function: ClassObject<'gc>,
|
|
|
|
class: ClassObject<'gc>,
|
|
|
|
global: ClassObject<'gc>,
|
|
|
|
) -> Self {
|
2021-06-18 22:11:37 +00:00
|
|
|
SystemClasses {
|
2021-05-28 02:22:38 +00:00
|
|
|
object,
|
|
|
|
function,
|
|
|
|
class,
|
2021-12-01 09:08:25 +00:00
|
|
|
global,
|
2021-09-24 20:54:36 +00:00
|
|
|
// temporary initialization
|
|
|
|
string: object,
|
|
|
|
boolean: object,
|
|
|
|
number: object,
|
|
|
|
int: object,
|
|
|
|
uint: object,
|
|
|
|
namespace: object,
|
|
|
|
array: object,
|
|
|
|
movieclip: object,
|
|
|
|
framelabel: object,
|
|
|
|
scene: object,
|
|
|
|
application_domain: object,
|
|
|
|
event: object,
|
2021-08-25 08:02:53 +00:00
|
|
|
fullscreenevent: object,
|
2021-09-24 20:54:36 +00:00
|
|
|
video: object,
|
|
|
|
xml: object,
|
|
|
|
xml_list: object,
|
|
|
|
display_object: object,
|
|
|
|
shape: object,
|
|
|
|
textfield: object,
|
|
|
|
textformat: object,
|
|
|
|
graphics: object,
|
2023-03-16 10:18:15 +00:00
|
|
|
igraphicsdata: object,
|
2023-03-17 11:50:31 +00:00
|
|
|
graphicsbitmapfill: object,
|
2023-03-17 11:52:15 +00:00
|
|
|
graphicsendfill: object,
|
2023-03-17 12:01:04 +00:00
|
|
|
graphicsgradientfill: object,
|
2023-03-17 12:20:24 +00:00
|
|
|
graphicspath: object,
|
2023-03-18 01:03:25 +00:00
|
|
|
graphicstrianglepath: object,
|
2023-03-17 12:23:14 +00:00
|
|
|
graphicssolidfill: object,
|
2023-03-17 12:27:16 +00:00
|
|
|
graphicsstroke: object,
|
2021-09-24 20:54:36 +00:00
|
|
|
loaderinfo: object,
|
|
|
|
bytearray: object,
|
|
|
|
stage: object,
|
|
|
|
sprite: object,
|
|
|
|
simplebutton: object,
|
|
|
|
regexp: object,
|
|
|
|
vector: object,
|
|
|
|
soundtransform: object,
|
|
|
|
soundchannel: object,
|
|
|
|
bitmap: object,
|
|
|
|
bitmapdata: object,
|
|
|
|
date: object,
|
2021-09-29 03:15:44 +00:00
|
|
|
qname: object,
|
2021-12-02 05:52:06 +00:00
|
|
|
mouseevent: object,
|
2022-07-25 04:09:05 +00:00
|
|
|
progressevent: object,
|
2022-05-20 19:35:01 +00:00
|
|
|
textevent: object,
|
|
|
|
errorevent: object,
|
avm2: Partially implement `URLLoader` and related classes
This PR implements the `URLLoader` class, allowing AVM2 scripts
to load data from a URL. This requires several other related
classes (`URLLoaderDataFormat`, `URLRequest`, `IOError`) to be
implemented as well.
Currently implemented:
* Fetching from URLs using the 'navigator' backend
* The `text` and `binary` data formats (which store data
in a `String` or `ByteArray` respectively)
* The `open`, `complete`, and `ioError` events
* The `bytesLoaded`, `bytesTotal`, and `data` properties
Not yet implemented:
* The HTTP and security events
* All of the properties of `IOError`
* The properties on `URLRequest` (besides `url`)
* The "variables" data format
This should be enough to get some basic uses of `URLLoader` working
(e.g. simple GET requests to a particular website).
Note that in Flash's `playerglobal`, the `URLLoader` class is just
a think wrapper around the more general `URLStream`. However,
implementing `URLStream` will require changes to `Navigator``
to support notifications when data arrives in the stream. When
that happens, we should be able to re-use a large amount of the
code in this PR.
2022-04-06 01:27:39 +00:00
|
|
|
ioerrorevent: object,
|
2022-05-20 19:35:01 +00:00
|
|
|
securityerrorevent: object,
|
avm2: Implement DisplayObject.transform and most of Transform
This PR implements the 'DisplayObject.transform' getters/setters,
and most of the getters/setters in the `Transform` class
From testing in FP, it appears that each call to the
'DisplayObject.transform' property produces a new
'Transform' instance, which is permanently tied to the
owner 'DisplayObject'. All of the getters/setters in
`Transform` operate directly on owner `DisplayObject`.
However, note that the `Matrix` and `ColorTransform`
valuse *produced* the getter are plain ActionScript objects,
and have no further tie to the `DisplayObject`.
Using the `DisplayObject.transform` setter results in
values being *copied* from the input `Transform` object.
The input object retains its original owner `DisplayObject`.
Not implemented:
* Transform.concatenatedColorTransform
* Transform.pixelBounds
When a DisplayObject is not a descendant of the stage,
the `concatenatedMatrix` property produces a bizarre matrix:
a scale matrix that the depends on the global state quality.
Any DisplayObject that *is* a descendant of the stage has
a `concatenatedMatrix` that does not depend on the stage quality.
I'm not sure why the behavior occurs - for now, I just manually
mimic the values prdduced by FP. However, these values may indicate
that we need to do some internal scaling based on stage quality values,
and then 'undo' this in certain circumstances when constructing
an ActionScript matrix.
Unfortunately, some of the computed 'concatenatedMatrix' values
are off by f32::EPSILON. This is likely due to us storing some
internal values in pixels rather than twips (the rounding introduced
by round-trip twips conversions could cause this slight difference0.
For now, I've opted to mark these tests as 'approximate'.
To support this, I've extended our test framework to support providing
a regex that matches floating-point values in the output. This allows
us to print out 'Matrix.toString()' and still perform approximate
comparisons between strings of the format
'(a=0, b=0, c=0, d=0, tx=0, ty=0)'
2022-06-19 20:37:31 +00:00
|
|
|
transform: object,
|
|
|
|
colortransform: object,
|
|
|
|
matrix: object,
|
2022-07-25 04:09:05 +00:00
|
|
|
illegaloperationerror: object,
|
|
|
|
eventdispatcher: object,
|
2022-08-22 20:49:58 +00:00
|
|
|
rectangle: object,
|
2022-08-27 23:31:00 +00:00
|
|
|
keyboardevent: object,
|
2022-08-29 20:06:30 +00:00
|
|
|
point: object,
|
2022-09-13 17:17:24 +00:00
|
|
|
rangeerror: object,
|
|
|
|
referenceerror: object,
|
|
|
|
argumenterror: object,
|
2023-04-22 22:30:35 +00:00
|
|
|
syntaxerror: object,
|
2022-09-21 23:06:07 +00:00
|
|
|
typeerror: object,
|
2022-09-26 10:12:21 +00:00
|
|
|
verifyerror: object,
|
2022-09-26 09:49:27 +00:00
|
|
|
ioerror: object,
|
2022-10-04 07:12:09 +00:00
|
|
|
eoferror: object,
|
2023-03-25 09:24:09 +00:00
|
|
|
urierror: object,
|
2023-03-27 17:22:19 +00:00
|
|
|
error: object,
|
2022-09-18 01:21:40 +00:00
|
|
|
uncaughterrorevents: object,
|
2022-11-23 23:30:47 +00:00
|
|
|
statictext: object,
|
2022-10-15 18:44:06 +00:00
|
|
|
textlinemetrics: object,
|
avm2: Partially implement Stage3D for wgpu backend
This PR implements core 'stage3D' APIs. We are now able
to render at least two demos from the Context3D docs - a simple
triangle render, and a rotating cube.
Implemented in this PR:
* Stage3D access and Context3D creation
* IndexBuffer3D and VertexBuffer3D creation, uploading, and usage
* Program3D uploading and usage (via `naga-agal`)
* Context3D: configureBackBuffer, clear, drawTriangles, and present
Not yet implemented:
* Any 'dispose()' methods
* Depth and stencil buffers
* Context3D texture apis
* Scissor rectangle
General implementation strategy:
A new `Object` variant is added for each of the Stage3D objects
(VertexBuffer3D, Program3D, etc). This stores a handle to the
parent `Context3D`, and (depending on the object) a handle
to the underlying native resource, via `Rc<dyn
SomeRenderBackendTrait>`).
Calling methods on Context3D does not usually result in an immediate
call to a `wgpu` method. Instead, we queue up commands in our
`Context3D` instance, and execute them all on a call to `present`.
This avoids some nasty wgpu lifetime issues, and is very similar
to the approah we use for normal rendering.
The actual rendering happens on a `Texture`, with dimensions
determined by `createBackBuffer`. During 'Stage' rendering,
we render all of these Stage3D textures *behind* the normal
stage (but in front of the overall stage background color).
2022-09-18 20:50:21 +00:00
|
|
|
stage3d: object,
|
|
|
|
context3d: object,
|
|
|
|
indexbuffer3d: object,
|
|
|
|
vertexbuffer3d: object,
|
|
|
|
program3d: object,
|
2023-02-11 00:18:10 +00:00
|
|
|
urlvariables: object,
|
2023-02-22 22:22:12 +00:00
|
|
|
bevelfilter: object,
|
|
|
|
bitmapfilter: object,
|
|
|
|
blurfilter: object,
|
|
|
|
colormatrixfilter: object,
|
|
|
|
convolutionfilter: object,
|
|
|
|
displacementmapfilter: object,
|
|
|
|
dropshadowfilter: object,
|
|
|
|
glowfilter: object,
|
|
|
|
gradientbevelfilter: object,
|
|
|
|
gradientglowfilter: object,
|
2022-09-24 03:14:49 +00:00
|
|
|
texture: object,
|
|
|
|
cubetexture: object,
|
|
|
|
rectangletexture: object,
|
2023-04-21 19:26:59 +00:00
|
|
|
morphshape: object,
|
2021-05-28 02:22:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-23 02:27:03 +00:00
|
|
|
/// Add a free-function builtin to the global scope.
|
|
|
|
fn function<'gc>(
|
2023-01-06 23:33:31 +00:00
|
|
|
activation: &mut Activation<'_, 'gc>,
|
2020-07-14 02:21:18 +00:00
|
|
|
package: impl Into<AvmString<'gc>>,
|
2021-06-13 04:03:41 +00:00
|
|
|
name: &'static str,
|
2021-06-19 01:49:40 +00:00
|
|
|
nf: NativeMethodImpl,
|
2020-10-09 01:54:51 +00:00
|
|
|
script: Script<'gc>,
|
2022-09-13 21:04:04 +00:00
|
|
|
) -> Result<(), Error<'gc>> {
|
2021-12-01 09:08:25 +00:00
|
|
|
let (_, mut global, mut domain) = script.init();
|
2021-09-21 21:50:06 +00:00
|
|
|
let mc = activation.context.gc_context;
|
2021-09-14 22:57:52 +00:00
|
|
|
let scope = activation.create_scopechain();
|
2023-02-09 16:54:38 +00:00
|
|
|
let qname = QName::new(
|
2023-03-25 23:38:30 +00:00
|
|
|
Namespace::package(package, &mut activation.borrow_gc()),
|
2023-02-09 16:54:38 +00:00
|
|
|
name,
|
|
|
|
);
|
2021-06-19 20:28:04 +00:00
|
|
|
let method = Method::from_builtin(nf, name, mc);
|
2021-10-24 02:48:48 +00:00
|
|
|
let as3fn = FunctionObject::from_method(activation, method, scope, None, None).into();
|
2023-02-23 10:48:19 +00:00
|
|
|
domain.export_definition(qname, script, mc);
|
2022-07-01 04:34:26 +00:00
|
|
|
global.install_const_late(mc, qname, as3fn, activation.avm2().classes().function);
|
2020-09-24 03:35:11 +00:00
|
|
|
|
|
|
|
Ok(())
|
2020-02-23 02:27:03 +00:00
|
|
|
}
|
|
|
|
|
2021-06-19 23:07:55 +00:00
|
|
|
/// Add a fully-formed class object builtin to the global scope.
|
2020-08-05 03:00:17 +00:00
|
|
|
///
|
2021-06-19 23:07:55 +00:00
|
|
|
/// This allows the caller to pre-populate the class's prototype with dynamic
|
|
|
|
/// properties, if necessary.
|
2020-08-05 03:00:17 +00:00
|
|
|
fn dynamic_class<'gc>(
|
2020-02-23 00:39:12 +00:00
|
|
|
mc: MutationContext<'gc, '_>,
|
2021-09-24 20:54:36 +00:00
|
|
|
class_object: ClassObject<'gc>,
|
2020-10-09 01:54:51 +00:00
|
|
|
script: Script<'gc>,
|
2022-07-01 04:34:26 +00:00
|
|
|
// The `ClassObject` of the `Class` class
|
|
|
|
class_class: ClassObject<'gc>,
|
2023-02-23 10:48:19 +00:00
|
|
|
) {
|
2021-09-07 06:29:07 +00:00
|
|
|
let (_, mut global, mut domain) = script.init();
|
2021-09-24 20:54:36 +00:00
|
|
|
let class = class_object.inner_class_definition();
|
2021-11-27 17:50:13 +00:00
|
|
|
let name = class.read().name();
|
2020-08-05 03:00:17 +00:00
|
|
|
|
2022-07-01 04:34:26 +00:00
|
|
|
global.install_const_late(mc, name, class_object.into(), class_class);
|
2020-10-09 01:54:51 +00:00
|
|
|
domain.export_definition(name, script, mc)
|
2020-02-23 00:39:12 +00:00
|
|
|
}
|
|
|
|
|
2020-07-07 04:24:16 +00:00
|
|
|
/// Add a class builtin to the global scope.
|
2020-08-05 03:00:17 +00:00
|
|
|
///
|
2022-06-29 14:28:42 +00:00
|
|
|
/// This function returns the class object and class prototype as a class, which
|
|
|
|
/// may be stored in `SystemClasses`
|
2021-05-16 02:36:11 +00:00
|
|
|
fn class<'gc>(
|
2020-07-07 04:24:16 +00:00
|
|
|
class_def: GcCell<'gc, Class<'gc>>,
|
2020-10-09 01:54:51 +00:00
|
|
|
script: Script<'gc>,
|
2023-02-09 16:54:38 +00:00
|
|
|
activation: &mut Activation<'_, 'gc>,
|
2022-09-13 21:04:04 +00:00
|
|
|
) -> Result<ClassObject<'gc>, Error<'gc>> {
|
2021-09-07 06:29:07 +00:00
|
|
|
let (_, mut global, mut domain) = script.init();
|
2020-08-26 03:10:59 +00:00
|
|
|
|
|
|
|
let class_read = class_def.read();
|
|
|
|
let super_class = if let Some(sc_name) = class_read.super_class_name() {
|
2022-09-13 21:04:04 +00:00
|
|
|
let super_class: Result<Object<'gc>, Error<'gc>> = activation
|
2022-07-21 06:11:46 +00:00
|
|
|
.resolve_definition(sc_name)
|
2022-02-08 04:39:49 +00:00
|
|
|
.ok()
|
2022-07-21 06:11:46 +00:00
|
|
|
.and_then(|v| v)
|
2022-02-08 04:39:49 +00:00
|
|
|
.and_then(|v| v.as_object())
|
|
|
|
.ok_or_else(|| {
|
2021-09-17 04:47:02 +00:00
|
|
|
format!(
|
2022-02-08 04:39:49 +00:00
|
|
|
"Could not resolve superclass {} when defining global class {}",
|
|
|
|
sc_name.to_qualified_name(activation.context.gc_context),
|
|
|
|
class_read
|
|
|
|
.name()
|
|
|
|
.to_qualified_name(activation.context.gc_context)
|
2021-09-17 04:47:02 +00:00
|
|
|
)
|
|
|
|
.into()
|
2020-08-26 03:10:59 +00:00
|
|
|
});
|
2021-09-24 20:54:36 +00:00
|
|
|
let super_class = super_class?
|
|
|
|
.as_class_object()
|
|
|
|
.ok_or_else(|| Error::from("Base class of a global class is not a class"))?;
|
2020-08-26 03:10:59 +00:00
|
|
|
|
2021-09-24 20:54:36 +00:00
|
|
|
Some(super_class)
|
2020-08-26 03:10:59 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2021-11-27 17:50:13 +00:00
|
|
|
let class_name = class_read.name();
|
2021-05-31 20:34:46 +00:00
|
|
|
drop(class_read);
|
|
|
|
|
2021-09-14 22:57:52 +00:00
|
|
|
let class_object = ClassObject::from_class(activation, class_def, super_class)?;
|
2021-12-01 09:08:25 +00:00
|
|
|
global.install_const_late(
|
2020-08-26 03:10:59 +00:00
|
|
|
activation.context.gc_context,
|
2021-11-27 17:50:13 +00:00
|
|
|
class_name,
|
2021-06-19 23:07:55 +00:00
|
|
|
class_object.into(),
|
2022-07-01 04:34:26 +00:00
|
|
|
activation.avm2().classes().class,
|
2020-08-26 03:10:59 +00:00
|
|
|
);
|
2023-02-23 10:48:19 +00:00
|
|
|
domain.export_definition(class_name, script, activation.context.gc_context);
|
2023-02-25 23:57:50 +00:00
|
|
|
domain.export_class(class_def, activation.context.gc_context);
|
2020-07-07 04:24:16 +00:00
|
|
|
|
2022-06-29 14:28:42 +00:00
|
|
|
Ok(class_object)
|
2020-07-07 04:24:16 +00:00
|
|
|
}
|
|
|
|
|
2021-05-28 02:22:38 +00:00
|
|
|
macro_rules! avm2_system_class {
|
2021-09-14 22:57:52 +00:00
|
|
|
($field:ident, $activation:ident, $class:expr, $script:expr) => {
|
2023-02-09 16:54:38 +00:00
|
|
|
let class_object = class($class, $script, $activation)?;
|
2021-05-28 02:22:38 +00:00
|
|
|
|
2021-06-18 22:11:37 +00:00
|
|
|
let sc = $activation.avm2().system_classes.as_mut().unwrap();
|
2021-06-19 23:07:55 +00:00
|
|
|
sc.$field = class_object;
|
2021-05-28 02:22:38 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2020-09-24 03:35:11 +00:00
|
|
|
/// Initialize the player global domain.
|
2020-07-07 04:24:16 +00:00
|
|
|
///
|
2020-08-05 03:00:17 +00:00
|
|
|
/// This should be called only once, to construct the global scope of the
|
|
|
|
/// player. It will return a list of prototypes it has created, which should be
|
2020-09-24 03:35:11 +00:00
|
|
|
/// stored on the AVM. All relevant declarations will also be attached to the
|
|
|
|
/// given domain.
|
|
|
|
pub fn load_player_globals<'gc>(
|
2023-01-06 23:33:31 +00:00
|
|
|
activation: &mut Activation<'_, 'gc>,
|
2020-10-09 01:54:51 +00:00
|
|
|
domain: Domain<'gc>,
|
2022-09-13 21:04:04 +00:00
|
|
|
) -> Result<(), Error<'gc>> {
|
2020-09-24 03:35:11 +00:00
|
|
|
let mc = activation.context.gc_context;
|
2021-09-07 06:29:07 +00:00
|
|
|
|
2022-06-29 15:47:58 +00:00
|
|
|
let globals = ScriptObject::custom_object(activation.context.gc_context, None, None);
|
2021-09-07 22:17:38 +00:00
|
|
|
let gs = ScopeChain::new(domain).chain(mc, &[Scope::new(globals)]);
|
2021-09-07 06:29:07 +00:00
|
|
|
let script = Script::empty_script(mc, globals, domain);
|
2020-02-19 03:26:08 +00:00
|
|
|
|
2021-09-14 22:57:52 +00:00
|
|
|
// Set the outer scope of this activation to the global scope.
|
|
|
|
activation.set_outer(gs);
|
|
|
|
|
2020-02-23 00:39:12 +00:00
|
|
|
// public / root package
|
2021-05-16 02:36:11 +00:00
|
|
|
//
|
2021-09-21 21:50:06 +00:00
|
|
|
// This part of global initialization is very complicated, because
|
|
|
|
// everything has to circularly reference everything else:
|
|
|
|
//
|
|
|
|
// - Object is an instance of itself, as well as it's prototype
|
|
|
|
// - All other types are instances of Class, which is an instance of
|
|
|
|
// itself
|
|
|
|
// - Function's prototype is an instance of itself
|
|
|
|
// - All methods created by the above-mentioned classes are also instances
|
|
|
|
// of Function
|
2021-12-01 09:08:25 +00:00
|
|
|
// - All classes are put on Global's trait list, but Global needs
|
|
|
|
// to be initialized first, but you can't do that until Object/Class are ready.
|
2021-09-21 21:50:06 +00:00
|
|
|
//
|
|
|
|
// Hence, this ridiculously complicated dance of classdef, type allocation,
|
|
|
|
// and partial initialization.
|
2023-02-09 16:54:38 +00:00
|
|
|
let object_classdef = object::create_class(activation);
|
2021-09-14 22:57:52 +00:00
|
|
|
let object_class = ClassObject::from_class_partial(activation, object_classdef, None)?;
|
2022-06-29 15:47:58 +00:00
|
|
|
let object_proto = ScriptObject::custom_object(mc, Some(object_class), None);
|
2023-02-25 23:57:50 +00:00
|
|
|
domain.export_class(object_classdef, mc);
|
2020-02-23 00:39:12 +00:00
|
|
|
|
2023-02-09 16:54:38 +00:00
|
|
|
let fn_classdef = function::create_class(activation);
|
2021-10-09 08:47:28 +00:00
|
|
|
let fn_class = ClassObject::from_class_partial(activation, fn_classdef, Some(object_class))?;
|
2022-06-29 15:47:58 +00:00
|
|
|
let fn_proto = ScriptObject::custom_object(mc, Some(fn_class), Some(object_proto));
|
2023-02-25 23:57:50 +00:00
|
|
|
domain.export_class(fn_classdef, mc);
|
2021-05-16 02:36:11 +00:00
|
|
|
|
2023-02-09 16:54:38 +00:00
|
|
|
let class_classdef = class::create_class(activation);
|
2021-09-07 06:29:07 +00:00
|
|
|
let class_class =
|
2021-10-09 08:47:28 +00:00
|
|
|
ClassObject::from_class_partial(activation, class_classdef, Some(object_class))?;
|
2022-06-29 15:47:58 +00:00
|
|
|
let class_proto = ScriptObject::custom_object(mc, Some(object_class), Some(object_proto));
|
2023-02-25 23:57:50 +00:00
|
|
|
domain.export_class(class_classdef, mc);
|
2020-02-19 03:26:08 +00:00
|
|
|
|
2023-02-09 16:54:38 +00:00
|
|
|
let global_classdef = global_scope::create_class(activation);
|
2021-12-01 09:08:25 +00:00
|
|
|
let global_class =
|
|
|
|
ClassObject::from_class_partial(activation, global_classdef, Some(object_class))?;
|
2022-06-29 15:47:58 +00:00
|
|
|
let global_proto = ScriptObject::custom_object(mc, Some(object_class), Some(object_proto));
|
2023-02-25 23:57:50 +00:00
|
|
|
domain.export_class(global_classdef, mc);
|
2021-12-01 09:08:25 +00:00
|
|
|
|
2021-09-21 21:50:06 +00:00
|
|
|
// Now to weave the Gordian knot...
|
|
|
|
object_class.link_prototype(activation, object_proto)?;
|
2021-09-24 20:54:36 +00:00
|
|
|
object_class.link_type(activation, class_proto, class_class);
|
2021-09-21 21:50:06 +00:00
|
|
|
|
|
|
|
fn_class.link_prototype(activation, fn_proto)?;
|
2021-09-24 20:54:36 +00:00
|
|
|
fn_class.link_type(activation, class_proto, class_class);
|
2021-09-21 21:50:06 +00:00
|
|
|
|
|
|
|
class_class.link_prototype(activation, class_proto)?;
|
2021-09-24 20:54:36 +00:00
|
|
|
class_class.link_type(activation, class_proto, class_class);
|
2020-08-05 03:00:17 +00:00
|
|
|
|
2021-12-01 09:08:25 +00:00
|
|
|
global_class.link_prototype(activation, global_proto)?;
|
|
|
|
global_class.link_type(activation, class_proto, class_class);
|
|
|
|
|
2022-06-29 14:28:42 +00:00
|
|
|
// At this point, we need at least a partial set of system classes in
|
|
|
|
// order to continue initializing the player. The rest of the classes
|
|
|
|
// are set to a temporary class until we have a chance to initialize them.
|
2020-08-05 03:00:17 +00:00
|
|
|
|
2021-12-04 21:32:39 +00:00
|
|
|
activation.context.avm2.system_classes = Some(SystemClasses::new(
|
|
|
|
object_class,
|
|
|
|
fn_class,
|
|
|
|
class_class,
|
|
|
|
global_class,
|
|
|
|
));
|
2021-05-28 02:22:38 +00:00
|
|
|
|
2021-09-21 21:50:06 +00:00
|
|
|
// Our activation environment is now functional enough to finish
|
|
|
|
// initializing the core class weave. The order of initialization shouldn't
|
|
|
|
// matter here, as long as all the initialization machinery can see and
|
|
|
|
// link the various system types together correctly.
|
|
|
|
let class_class = class_class.into_finished_class(activation)?;
|
2021-12-01 09:08:25 +00:00
|
|
|
let fn_class = fn_class.into_finished_class(activation)?;
|
|
|
|
let object_class = object_class.into_finished_class(activation)?;
|
|
|
|
let _global_class = global_class.into_finished_class(activation)?;
|
|
|
|
|
2022-06-29 14:28:42 +00:00
|
|
|
globals.set_proto(mc, global_proto);
|
|
|
|
globals.set_instance_of(mc, global_class);
|
2021-12-01 09:08:25 +00:00
|
|
|
globals.fork_vtable(activation.context.gc_context);
|
|
|
|
|
|
|
|
// From this point, `globals` is safe to be modified
|
2021-06-08 00:53:24 +00:00
|
|
|
|
2023-02-23 10:48:19 +00:00
|
|
|
dynamic_class(mc, object_class, script, class_class);
|
|
|
|
dynamic_class(mc, fn_class, script, class_class);
|
|
|
|
dynamic_class(mc, class_class, script, class_class);
|
2021-09-21 21:50:06 +00:00
|
|
|
|
|
|
|
// After this point, it is safe to initialize any other classes.
|
|
|
|
// Make sure to initialize superclasses *before* their subclasses!
|
2021-09-07 06:29:07 +00:00
|
|
|
|
2023-02-09 16:54:38 +00:00
|
|
|
avm2_system_class!(string, activation, string::create_class(activation), script);
|
|
|
|
avm2_system_class!(
|
|
|
|
boolean,
|
|
|
|
activation,
|
|
|
|
boolean::create_class(activation),
|
|
|
|
script
|
|
|
|
);
|
|
|
|
avm2_system_class!(number, activation, number::create_class(activation), script);
|
|
|
|
avm2_system_class!(int, activation, int::create_class(activation), script);
|
|
|
|
avm2_system_class!(uint, activation, uint::create_class(activation), script);
|
|
|
|
avm2_system_class!(
|
|
|
|
namespace,
|
|
|
|
activation,
|
|
|
|
namespace::create_class(activation),
|
|
|
|
script
|
|
|
|
);
|
|
|
|
avm2_system_class!(array, activation, array::create_class(activation), script);
|
2021-09-14 22:57:52 +00:00
|
|
|
|
2021-12-13 11:31:24 +00:00
|
|
|
function(activation, "", "trace", toplevel::trace, script)?;
|
2022-11-06 18:28:22 +00:00
|
|
|
function(
|
|
|
|
activation,
|
|
|
|
"__ruffle__",
|
|
|
|
"log_warn",
|
|
|
|
toplevel::log_warn,
|
|
|
|
script,
|
|
|
|
)?;
|
2023-02-01 20:45:10 +00:00
|
|
|
function(
|
|
|
|
activation,
|
|
|
|
"__ruffle__",
|
|
|
|
"stub_method",
|
|
|
|
toplevel::stub_method,
|
|
|
|
script,
|
|
|
|
)?;
|
|
|
|
function(
|
|
|
|
activation,
|
|
|
|
"__ruffle__",
|
|
|
|
"stub_getter",
|
|
|
|
toplevel::stub_getter,
|
|
|
|
script,
|
|
|
|
)?;
|
|
|
|
function(
|
|
|
|
activation,
|
|
|
|
"__ruffle__",
|
|
|
|
"stub_setter",
|
|
|
|
toplevel::stub_setter,
|
|
|
|
script,
|
|
|
|
)?;
|
2023-02-07 17:32:31 +00:00
|
|
|
function(
|
|
|
|
activation,
|
|
|
|
"__ruffle__",
|
|
|
|
"stub_constructor",
|
|
|
|
toplevel::stub_constructor,
|
|
|
|
script,
|
|
|
|
)?;
|
2021-12-13 11:31:24 +00:00
|
|
|
function(activation, "", "isFinite", toplevel::is_finite, script)?;
|
|
|
|
function(activation, "", "isNaN", toplevel::is_nan, script)?;
|
2021-12-13 14:46:57 +00:00
|
|
|
function(activation, "", "parseInt", toplevel::parse_int, script)?;
|
|
|
|
function(activation, "", "parseFloat", toplevel::parse_float, script)?;
|
2022-06-22 05:43:22 +00:00
|
|
|
function(activation, "", "escape", toplevel::escape, script)?;
|
2023-02-25 21:05:36 +00:00
|
|
|
function(activation, "", "encodeURI", toplevel::encode_uri, script)?;
|
|
|
|
function(
|
|
|
|
activation,
|
|
|
|
"",
|
|
|
|
"encodeURIComponent",
|
|
|
|
toplevel::encode_uri_component,
|
|
|
|
script,
|
|
|
|
)?;
|
2023-03-25 09:24:09 +00:00
|
|
|
function(activation, "", "decodeURI", toplevel::decode_uri, script)?;
|
|
|
|
function(
|
|
|
|
activation,
|
|
|
|
"",
|
|
|
|
"decodeURIComponent",
|
|
|
|
toplevel::decode_uri_component,
|
|
|
|
script,
|
|
|
|
)?;
|
2023-03-08 01:23:16 +00:00
|
|
|
function(activation, "", "unescape", toplevel::unescape, script)?;
|
2021-09-07 06:29:07 +00:00
|
|
|
|
2023-02-09 16:54:38 +00:00
|
|
|
avm2_system_class!(vector, activation, vector::create_class(activation), script);
|
2021-01-15 22:35:10 +00:00
|
|
|
|
2023-02-09 16:54:38 +00:00
|
|
|
avm2_system_class!(date, activation, date::create_class(activation), script);
|
2021-07-27 23:58:13 +00:00
|
|
|
|
2023-02-23 19:39:45 +00:00
|
|
|
// Inside this call, the macro `avm2_system_classes_playerglobal`
|
|
|
|
// triggers classloading. Therefore, we run `load_playerglobal`
|
|
|
|
// relative late, so that it can access classes defined before
|
|
|
|
// this call.
|
|
|
|
load_playerglobal(activation, domain)?;
|
|
|
|
|
2020-07-07 04:24:16 +00:00
|
|
|
Ok(())
|
2020-02-12 19:58:33 +00:00
|
|
|
}
|
2022-06-15 19:00:17 +00:00
|
|
|
|
|
|
|
/// This file is built by 'core/build_playerglobal/'
|
|
|
|
/// See that tool, and 'core/src/avm2/globals/README.md', for more details
|
|
|
|
const PLAYERGLOBAL: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/playerglobal.swf"));
|
|
|
|
|
2022-07-21 06:11:46 +00:00
|
|
|
mod native {
|
|
|
|
include!(concat!(env!("OUT_DIR"), "/native_table.rs"));
|
|
|
|
}
|
2022-06-16 02:11:14 +00:00
|
|
|
|
2022-06-15 19:00:17 +00:00
|
|
|
/// Loads classes from our custom 'playerglobal' (which are written in ActionScript)
|
|
|
|
/// into the environment. See 'core/src/avm2/globals/README.md' for more information
|
|
|
|
fn load_playerglobal<'gc>(
|
2023-01-06 23:33:31 +00:00
|
|
|
activation: &mut Activation<'_, 'gc>,
|
2022-06-15 19:00:17 +00:00
|
|
|
domain: Domain<'gc>,
|
2022-09-13 21:04:04 +00:00
|
|
|
) -> Result<(), Error<'gc>> {
|
2022-07-21 06:11:46 +00:00
|
|
|
activation.avm2().native_method_table = native::NATIVE_METHOD_TABLE;
|
|
|
|
activation.avm2().native_instance_allocator_table = native::NATIVE_INSTANCE_ALLOCATOR_TABLE;
|
2022-11-23 23:30:47 +00:00
|
|
|
activation.avm2().native_instance_init_table = native::NATIVE_INSTANCE_INIT_TABLE;
|
2023-03-15 20:05:30 +00:00
|
|
|
activation.avm2().native_call_handler_table = native::NATIVE_CALL_HANDLER_TABLE;
|
2022-06-16 02:11:14 +00:00
|
|
|
|
2023-02-26 10:25:41 +00:00
|
|
|
let movie = SwfMovie::from_data(PLAYERGLOBAL, "file:///".into(), None)
|
|
|
|
.expect("playerglobal.swf should be valid");
|
2022-06-15 19:00:17 +00:00
|
|
|
|
2022-09-26 09:54:47 +00:00
|
|
|
let slice = SwfSlice::from(Arc::new(movie));
|
2022-06-15 19:00:17 +00:00
|
|
|
|
|
|
|
let mut reader = slice.read_from(0);
|
|
|
|
|
2022-08-26 12:20:04 +00:00
|
|
|
let tag_callback = |reader: &mut SwfStream<'_>, tag_code, _tag_len| {
|
2023-02-12 19:41:38 +00:00
|
|
|
if tag_code == TagCode::DoAbc2 {
|
2022-08-26 12:20:04 +00:00
|
|
|
let do_abc = reader
|
2023-02-12 19:41:38 +00:00
|
|
|
.read_do_abc_2()
|
2022-08-26 12:20:04 +00:00
|
|
|
.expect("playerglobal.swf should be valid");
|
2023-03-06 17:34:06 +00:00
|
|
|
Avm2::do_abc(
|
|
|
|
&mut activation.context,
|
|
|
|
do_abc.data,
|
|
|
|
None,
|
|
|
|
do_abc.flags,
|
|
|
|
domain,
|
|
|
|
)
|
|
|
|
.expect("playerglobal.swf should be valid");
|
2022-06-15 19:00:17 +00:00
|
|
|
} else if tag_code != TagCode::End {
|
2023-02-12 19:41:38 +00:00
|
|
|
panic!("playerglobal should only contain `DoAbc2` tag - found tag {tag_code:?}")
|
2022-06-15 19:00:17 +00:00
|
|
|
}
|
2021-07-28 00:08:26 +00:00
|
|
|
Ok(ControlFlow::Continue)
|
2022-06-15 19:00:17 +00:00
|
|
|
};
|
|
|
|
|
2021-07-28 00:08:26 +00:00
|
|
|
let _ = tag_utils::decode_tags(&mut reader, tag_callback);
|
2022-06-15 19:00:17 +00:00
|
|
|
macro_rules! avm2_system_classes_playerglobal {
|
|
|
|
($activation:expr, $script:expr, [$(($package:expr, $class_name:expr, $field:ident)),* $(,)?]) => {
|
2023-03-25 23:38:30 +00:00
|
|
|
let activation = $activation;
|
2022-06-15 19:00:17 +00:00
|
|
|
$(
|
2023-03-25 23:38:30 +00:00
|
|
|
let ns = Namespace::package($package, &mut activation.borrow_gc());
|
|
|
|
let name = Multiname::new(ns, $class_name);
|
2022-09-09 21:33:30 +00:00
|
|
|
let class_object = activation.resolve_class(&name)?;
|
2023-03-25 23:38:30 +00:00
|
|
|
let sc = activation.avm2().system_classes.as_mut().unwrap();
|
2022-06-15 19:00:17 +00:00
|
|
|
sc.$field = class_object;
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This acts the same way as 'avm2_system_class', but for classes
|
|
|
|
// declared in 'playerglobal'. Classes are declared as ("package", "class", field_name),
|
2022-06-29 14:28:42 +00:00
|
|
|
// and are stored in 'avm2().system_classes'
|
2022-07-21 06:11:46 +00:00
|
|
|
avm2_system_classes_playerglobal!(
|
2023-03-25 23:38:30 +00:00
|
|
|
&mut *activation,
|
2022-07-21 06:11:46 +00:00
|
|
|
script,
|
|
|
|
[
|
2023-03-27 17:22:19 +00:00
|
|
|
("", "Error", error),
|
2022-09-13 17:17:24 +00:00
|
|
|
("", "ArgumentError", argumenterror),
|
2023-04-01 01:25:08 +00:00
|
|
|
("", "QName", qname),
|
2022-09-13 17:17:24 +00:00
|
|
|
("", "RangeError", rangeerror),
|
2023-03-27 03:45:18 +00:00
|
|
|
("", "RegExp", regexp),
|
2022-09-13 17:17:24 +00:00
|
|
|
("", "ReferenceError", referenceerror),
|
2023-04-22 22:30:35 +00:00
|
|
|
("", "SyntaxError", syntaxerror),
|
2022-09-21 23:06:07 +00:00
|
|
|
("", "TypeError", typeerror),
|
2023-03-25 09:24:09 +00:00
|
|
|
("", "URIError", urierror),
|
2022-09-26 10:12:21 +00:00
|
|
|
("", "VerifyError", verifyerror),
|
2022-09-22 06:08:54 +00:00
|
|
|
("", "XML", xml),
|
|
|
|
("", "XMLList", xml_list),
|
2023-02-23 19:14:05 +00:00
|
|
|
("flash.display", "Bitmap", bitmap),
|
|
|
|
("flash.display", "BitmapData", bitmapdata),
|
2022-07-21 06:11:46 +00:00
|
|
|
("flash.display", "Scene", scene),
|
2022-12-21 22:58:08 +00:00
|
|
|
("flash.display", "FrameLabel", framelabel),
|
2023-03-16 10:18:15 +00:00
|
|
|
("flash.display", "IGraphicsData", igraphicsdata),
|
2023-03-17 11:50:31 +00:00
|
|
|
("flash.display", "GraphicsBitmapFill", graphicsbitmapfill),
|
2023-03-17 11:52:15 +00:00
|
|
|
("flash.display", "GraphicsEndFill", graphicsendfill),
|
2023-03-17 12:01:04 +00:00
|
|
|
(
|
|
|
|
"flash.display",
|
|
|
|
"GraphicsGradientFill",
|
|
|
|
graphicsgradientfill
|
|
|
|
),
|
2023-03-17 12:20:24 +00:00
|
|
|
("flash.display", "GraphicsPath", graphicspath),
|
2023-03-18 01:03:25 +00:00
|
|
|
(
|
|
|
|
"flash.display",
|
|
|
|
"GraphicsTrianglePath",
|
|
|
|
graphicstrianglepath
|
|
|
|
),
|
2023-03-17 12:23:14 +00:00
|
|
|
("flash.display", "GraphicsSolidFill", graphicssolidfill),
|
2023-03-17 12:27:16 +00:00
|
|
|
("flash.display", "GraphicsStroke", graphicsstroke),
|
2023-02-24 23:54:01 +00:00
|
|
|
("flash.display", "Graphics", graphics),
|
2023-02-23 19:18:29 +00:00
|
|
|
("flash.display", "LoaderInfo", loaderinfo),
|
2023-04-21 19:26:59 +00:00
|
|
|
("flash.display", "MorphShape", morphshape),
|
2023-02-23 19:25:34 +00:00
|
|
|
("flash.display", "MovieClip", movieclip),
|
2023-02-23 19:21:49 +00:00
|
|
|
("flash.display", "Shape", shape),
|
2023-02-23 19:28:21 +00:00
|
|
|
("flash.display", "SimpleButton", simplebutton),
|
2023-02-23 19:23:58 +00:00
|
|
|
("flash.display", "Sprite", sprite),
|
2023-02-23 19:14:05 +00:00
|
|
|
("flash.display", "Stage", stage),
|
avm2: Partially implement Stage3D for wgpu backend
This PR implements core 'stage3D' APIs. We are now able
to render at least two demos from the Context3D docs - a simple
triangle render, and a rotating cube.
Implemented in this PR:
* Stage3D access and Context3D creation
* IndexBuffer3D and VertexBuffer3D creation, uploading, and usage
* Program3D uploading and usage (via `naga-agal`)
* Context3D: configureBackBuffer, clear, drawTriangles, and present
Not yet implemented:
* Any 'dispose()' methods
* Depth and stencil buffers
* Context3D texture apis
* Scissor rectangle
General implementation strategy:
A new `Object` variant is added for each of the Stage3D objects
(VertexBuffer3D, Program3D, etc). This stores a handle to the
parent `Context3D`, and (depending on the object) a handle
to the underlying native resource, via `Rc<dyn
SomeRenderBackendTrait>`).
Calling methods on Context3D does not usually result in an immediate
call to a `wgpu` method. Instead, we queue up commands in our
`Context3D` instance, and execute them all on a call to `present`.
This avoids some nasty wgpu lifetime issues, and is very similar
to the approah we use for normal rendering.
The actual rendering happens on a `Texture`, with dimensions
determined by `createBackBuffer`. During 'Stage' rendering,
we render all of these Stage3D textures *behind* the normal
stage (but in front of the overall stage background color).
2022-09-18 20:50:21 +00:00
|
|
|
("flash.display", "Stage3D", stage3d),
|
|
|
|
("flash.display3D", "Context3D", context3d),
|
|
|
|
("flash.display3D", "IndexBuffer3D", indexbuffer3d),
|
|
|
|
("flash.display3D", "Program3D", program3d),
|
2022-09-24 03:14:49 +00:00
|
|
|
("flash.display3D.textures", "CubeTexture", cubetexture),
|
|
|
|
("flash.display3D.textures", "Texture", texture),
|
|
|
|
(
|
|
|
|
"flash.display3D.textures",
|
|
|
|
"RectangleTexture",
|
|
|
|
rectangletexture
|
|
|
|
),
|
avm2: Partially implement Stage3D for wgpu backend
This PR implements core 'stage3D' APIs. We are now able
to render at least two demos from the Context3D docs - a simple
triangle render, and a rotating cube.
Implemented in this PR:
* Stage3D access and Context3D creation
* IndexBuffer3D and VertexBuffer3D creation, uploading, and usage
* Program3D uploading and usage (via `naga-agal`)
* Context3D: configureBackBuffer, clear, drawTriangles, and present
Not yet implemented:
* Any 'dispose()' methods
* Depth and stencil buffers
* Context3D texture apis
* Scissor rectangle
General implementation strategy:
A new `Object` variant is added for each of the Stage3D objects
(VertexBuffer3D, Program3D, etc). This stores a handle to the
parent `Context3D`, and (depending on the object) a handle
to the underlying native resource, via `Rc<dyn
SomeRenderBackendTrait>`).
Calling methods on Context3D does not usually result in an immediate
call to a `wgpu` method. Instead, we queue up commands in our
`Context3D` instance, and execute them all on a call to `present`.
This avoids some nasty wgpu lifetime issues, and is very similar
to the approah we use for normal rendering.
The actual rendering happens on a `Texture`, with dimensions
determined by `createBackBuffer`. During 'Stage' rendering,
we render all of these Stage3D textures *behind* the normal
stage (but in front of the overall stage background color).
2022-09-18 20:50:21 +00:00
|
|
|
("flash.display3D", "VertexBuffer3D", vertexbuffer3d),
|
2022-07-25 04:09:05 +00:00
|
|
|
(
|
|
|
|
"flash.errors",
|
|
|
|
"IllegalOperationError",
|
|
|
|
illegaloperationerror
|
|
|
|
),
|
2022-09-26 09:49:27 +00:00
|
|
|
("flash.errors", "IOError", ioerror),
|
2022-10-04 07:12:09 +00:00
|
|
|
("flash.errors", "EOFError", eoferror),
|
2022-07-21 06:11:46 +00:00
|
|
|
("flash.events", "Event", event),
|
2023-02-23 19:01:20 +00:00
|
|
|
("flash.events", "EventDispatcher", eventdispatcher),
|
2022-07-27 14:44:42 +00:00
|
|
|
("flash.events", "TextEvent", textevent),
|
|
|
|
("flash.events", "ErrorEvent", errorevent),
|
2022-08-27 23:31:00 +00:00
|
|
|
("flash.events", "KeyboardEvent", keyboardevent),
|
2022-07-25 04:09:05 +00:00
|
|
|
("flash.events", "ProgressEvent", progressevent),
|
2022-07-27 14:44:42 +00:00
|
|
|
("flash.events", "SecurityErrorEvent", securityerrorevent),
|
|
|
|
("flash.events", "IOErrorEvent", ioerrorevent),
|
|
|
|
("flash.events", "MouseEvent", mouseevent),
|
|
|
|
("flash.events", "FullScreenEvent", fullscreenevent),
|
2022-09-18 01:21:40 +00:00
|
|
|
("flash.events", "UncaughtErrorEvents", uncaughterrorevents),
|
avm2: Implement DisplayObject.transform and most of Transform
This PR implements the 'DisplayObject.transform' getters/setters,
and most of the getters/setters in the `Transform` class
From testing in FP, it appears that each call to the
'DisplayObject.transform' property produces a new
'Transform' instance, which is permanently tied to the
owner 'DisplayObject'. All of the getters/setters in
`Transform` operate directly on owner `DisplayObject`.
However, note that the `Matrix` and `ColorTransform`
valuse *produced* the getter are plain ActionScript objects,
and have no further tie to the `DisplayObject`.
Using the `DisplayObject.transform` setter results in
values being *copied* from the input `Transform` object.
The input object retains its original owner `DisplayObject`.
Not implemented:
* Transform.concatenatedColorTransform
* Transform.pixelBounds
When a DisplayObject is not a descendant of the stage,
the `concatenatedMatrix` property produces a bizarre matrix:
a scale matrix that the depends on the global state quality.
Any DisplayObject that *is* a descendant of the stage has
a `concatenatedMatrix` that does not depend on the stage quality.
I'm not sure why the behavior occurs - for now, I just manually
mimic the values prdduced by FP. However, these values may indicate
that we need to do some internal scaling based on stage quality values,
and then 'undo' this in certain circumstances when constructing
an ActionScript matrix.
Unfortunately, some of the computed 'concatenatedMatrix' values
are off by f32::EPSILON. This is likely due to us storing some
internal values in pixels rather than twips (the rounding introduced
by round-trip twips conversions could cause this slight difference0.
For now, I've opted to mark these tests as 'approximate'.
To support this, I've extended our test framework to support providing
a regex that matches floating-point values in the output. This allows
us to print out 'Matrix.toString()' and still perform approximate
comparisons between strings of the format
'(a=0, b=0, c=0, d=0, tx=0, ty=0)'
2022-06-19 20:37:31 +00:00
|
|
|
("flash.geom", "Matrix", matrix),
|
2022-08-29 20:06:30 +00:00
|
|
|
("flash.geom", "Point", point),
|
2022-08-22 20:49:58 +00:00
|
|
|
("flash.geom", "Rectangle", rectangle),
|
avm2: Implement DisplayObject.transform and most of Transform
This PR implements the 'DisplayObject.transform' getters/setters,
and most of the getters/setters in the `Transform` class
From testing in FP, it appears that each call to the
'DisplayObject.transform' property produces a new
'Transform' instance, which is permanently tied to the
owner 'DisplayObject'. All of the getters/setters in
`Transform` operate directly on owner `DisplayObject`.
However, note that the `Matrix` and `ColorTransform`
valuse *produced* the getter are plain ActionScript objects,
and have no further tie to the `DisplayObject`.
Using the `DisplayObject.transform` setter results in
values being *copied* from the input `Transform` object.
The input object retains its original owner `DisplayObject`.
Not implemented:
* Transform.concatenatedColorTransform
* Transform.pixelBounds
When a DisplayObject is not a descendant of the stage,
the `concatenatedMatrix` property produces a bizarre matrix:
a scale matrix that the depends on the global state quality.
Any DisplayObject that *is* a descendant of the stage has
a `concatenatedMatrix` that does not depend on the stage quality.
I'm not sure why the behavior occurs - for now, I just manually
mimic the values prdduced by FP. However, these values may indicate
that we need to do some internal scaling based on stage quality values,
and then 'undo' this in certain circumstances when constructing
an ActionScript matrix.
Unfortunately, some of the computed 'concatenatedMatrix' values
are off by f32::EPSILON. This is likely due to us storing some
internal values in pixels rather than twips (the rounding introduced
by round-trip twips conversions could cause this slight difference0.
For now, I've opted to mark these tests as 'approximate'.
To support this, I've extended our test framework to support providing
a regex that matches floating-point values in the output. This allows
us to print out 'Matrix.toString()' and still perform approximate
comparisons between strings of the format
'(a=0, b=0, c=0, d=0, tx=0, ty=0)'
2022-06-19 20:37:31 +00:00
|
|
|
("flash.geom", "Transform", transform),
|
|
|
|
("flash.geom", "ColorTransform", colortransform),
|
2023-03-16 18:42:39 +00:00
|
|
|
("flash.media", "SoundChannel", soundchannel),
|
2023-03-16 22:55:38 +00:00
|
|
|
("flash.media", "SoundTransform", soundtransform),
|
2023-02-11 00:18:10 +00:00
|
|
|
("flash.net", "URLVariables", urlvariables),
|
2022-09-16 06:48:40 +00:00
|
|
|
("flash.utils", "ByteArray", bytearray),
|
2023-03-26 19:12:19 +00:00
|
|
|
("flash.system", "ApplicationDomain", application_domain),
|
2022-11-23 23:30:47 +00:00
|
|
|
("flash.text", "StaticText", statictext),
|
2023-02-25 15:34:12 +00:00
|
|
|
("flash.text", "TextFormat", textformat),
|
2023-02-23 19:32:04 +00:00
|
|
|
("flash.text", "TextField", textfield),
|
2022-10-15 18:44:06 +00:00
|
|
|
("flash.text", "TextLineMetrics", textlinemetrics),
|
2023-02-22 22:22:12 +00:00
|
|
|
("flash.filters", "BevelFilter", bevelfilter),
|
|
|
|
("flash.filters", "BitmapFilter", bitmapfilter),
|
|
|
|
("flash.filters", "BlurFilter", blurfilter),
|
|
|
|
("flash.filters", "ColorMatrixFilter", colormatrixfilter),
|
|
|
|
("flash.filters", "ConvolutionFilter", convolutionfilter),
|
|
|
|
(
|
|
|
|
"flash.filters",
|
|
|
|
"DisplacementMapFilter",
|
|
|
|
displacementmapfilter
|
|
|
|
),
|
|
|
|
("flash.filters", "DropShadowFilter", dropshadowfilter),
|
|
|
|
("flash.filters", "GlowFilter", glowfilter),
|
|
|
|
("flash.filters", "GradientBevelFilter", gradientbevelfilter),
|
|
|
|
("flash.filters", "GradientGlowFilter", gradientglowfilter),
|
2022-07-21 06:11:46 +00:00
|
|
|
]
|
|
|
|
);
|
2022-06-15 19:00:17 +00:00
|
|
|
|
2022-09-16 06:48:40 +00:00
|
|
|
// Domain memory must be initialized after playerglobals is loaded because it relies on ByteArray.
|
|
|
|
domain.init_default_domain_memory(activation)?;
|
2022-06-15 19:00:17 +00:00
|
|
|
Ok(())
|
|
|
|
}
|