Handle removed clips inline in `Avm1::run_frame`, such that
`DisplayObject::prev_avm1_clip` is no longer used. Thus it can be
removed in a follow-up commit.
When we run a 'goto' where the initial and target frame are the same,
we need to skip triggering any sounds in the target frame.
Some games like 'This is the only level too' rely on this behavior:
they repeatedly run 'movieClip.gotoAndStop(current_frame_id)',
where 'current_frame_id' is the id of a frame that starts playing
a sound. Without this change, the sound will restart every frame
intead of playing exactly once.
We previously used 'coerce_to_object', which produced
an error with `Value::Null`. Instead, we can just ues
`value.as_type_of`, which will correctly handle `null`
The 'charCode' and 'keyCode' properties are now implemented
on `KeyboardEvent`
The input injection code we use does not support keyboard events,
so we can't yet write a regression test for this. However,
both 'You need to burn the rope' and 'This is the Only Level TOO'
now properly handle keyboard events with this PR.
* avm2: Implement call stack
* avm2: Class traits should have a special prefix
* avm2: Stack tracebacks should also contain error message
* avm2: Move method naming to Executable
* avm2: Handle getter and setter methods in tracebacks
* chore: Formatting
* chore: Add comments
* avm2: Make full_name write to a string, instead of creating a new one
* core: Make GcArena publicly accessible
* core: Add Deref impl for Either type
* desktop: Add AVM2 call stack to panic message
* avm2: Prefix native methods with a `/`
* chore: Appease clippy
* avm2: Check if method actually contains bytecode instead of unwrapping
* web: Add AVM2 stack trace to panic message
* chore: Formatting
* chore: Clippy
* avm2: Fix stack traces for free standing functions
* core: Remove global data from context
* core: Rename GcGlobalData to GcCallstack
* core: Introduce StaticCallstack, make GcArena private again
Co-authored-by: Adrian Wielgosik <4729533+adrian17@users.noreply.github.com>
Declare `NaN`, `Infinity` and `undefined` in ActionScript, similarly
to how `avmplus` does in its `actionscript.lang.as`.
Note that `null` is only removed, without an ActionScript declaration,
as it seems like `avmplus` neither declares it. Probably `null` is
only usable as a compile-time constant.
Extract `swf::Reader::read_do_abc()` which, as the name suggests,
reads a `DoAbc` tag, and use it before calling to `Avm2::load_abc`.
Finally, introduce `DoAbcFlag` using `bitflags`.
This greatly simplifies the ABC loading code.
This is in keeping with the whole idea of a "recursive frame": gotos run the entire frame lifecycle on the target clip, including broadcasts for `frameConstructed` and `exitFrame`.
We still retain the queue system as events are fired at removal time, and those events can trigger more gotos. If such a goto happens, AS3 code will hit a clip still in the old state rather than an inconsistent one. I don't have test coverage for this exact scenario just yet.
The rationale for the catch-up logic is as follows:
* We must always enter-frame and construct objects, even if those respective display events haven't happened yet.
* Display objects created in event handlers still need to run catchup phases, otherwise they will tag-stream desync
* Frame scripts are never triggered by catchup phases
* `exit_frame` is not a catchup phase as it is *only* an event broadcast currently
Normally a function closures also closes around its base clip.
If the base clip is removed, and then the function is executed, the
base clip then defaults to `this`.
However, Ruffle was incorrectly using the wrong base clip when
loading the `_root` and `_parent` registers in this case.
Fixes#5645.
This PR implements the `Loader.load` method, as well as
the associated `LoaderInfo` properties and events.
We can now load in an external AVM2 SWf: it will be added
as a child of `Loader` object, and will render properly
to the screen.
Limitations:
* The only supported `URLRequest` property is `url`
* `LoaderContext` is not supported at all - we always use the default
behavior
* Only `Loader.load` is implemented - we do not yet support unloading.
* We fire a plain 'Event' for the 'progress' event, instead of using
the (not yet implemented) 'ProgressEvent' class
The main changes in this PR are:
* The AVM2 `Loader` class now has an associated display object,
`LoaderDisplay`. This is basically a stub, and just renders
its single child (if it exists).
* `LoaderStream::Stage` is renamed to `LoaderStream::NotYetLoaded`.
This is used for both the `Stage` and an 'uninitialized'
`Loader.contentLoaderInfo`. In both cases, certain properties throw
errors, while others return actual values.
* The rust `Loader` manager now handles both AVM1 and AVM2 movie loads.
Previously, the viewport height and width were stored in
both `Stage` and the `RenderBackend`. Any changes to the viewport
dimensions (e.g. due to window resizing) needed to be updated in both
places to keep our handling of the viewport consistent.
This PR adds a new `ViewportDimensions` type, which holds the
width, height, and scale factor. It is stored inside the
`RenderBackend` impl, and is retrieved using the newly added
method `RenderBackend.get_viewport_dimensions`. After a `Player`
has been constructed, any code that needes access to the viewport
dimensions will ultimate go through this method.
Unfortunately, `Stage` needs to use the viewport dimensions
in `build_matrices`. Therefore, any code modifying the viewport
dimensions should go through `player.set_viewport_dimensions`,
which ensures that the stage matrices are rebuilt after the render
backend is updated.
When doing mouse picking, interactive children were considered
before all non-interactives, which could cause an `_droptarget` to
be set to an underlying movieclip even if a shape occluded it.
Now consider all children in render order so that the top-most
shape will capture the mouse input.
If we try to go to a frame that doesn't exist, or hasn't been loaded yet, we will stop on the last available frame, but skip any tags that would have run there. This is technically a desync, but it hasn't caused any problems so far as any further timeline interaction would trigger a rewind (which isn't affected by desyncs).
Of course, now that we're actually testing the tag stream position it *does* cause problems. We actually have to fix up the position to be correct even though it will never be used (hopefully). It may be prudent to do this outside of the `timeline_debug` feature as well in the future.
Each render backend keeps track of a stack of BlenModes,
which are pushed and popped by 'core' as we render objects
in the displaay tree. For now, I've just implemented BlendMode.ADD,
which maps directly onto blend mode supported by each backend.
All other blend modes (besides 'NORMAL') will produce a warning
when we try to render using them. This may produce a very large amount
of log output, but it's simpler than emitting each warning only once,
and will help to point developers in the right direction when they
get otherwise inexplicable rendering issues (due to a blend mode
not being implemented).
The wgpu implementation is by far the most complicated, as we need
to construct a `RenderPipeline` for each possible
`(BlendMode, MaskState)`. I haven't been able to find any documentation
about the maximum supported number of (simultaneous) WebGPU render
pipelines - if this becomes an issue, we may need to register them
on-demand when a particular blend mode is requested.
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)'
This is the last stub needed for Wonderputt to reach the
main game screen.
As far as I know, ActionScript cannot observe a frame being rendered,
so implementing this method isn't actually necessary for correctness.
The benefit of implementing this would be to make certain animations
appear smoother, since we'll render changes to the scene without
needing to wait for the next frame. However, actually rendering
*immediately* after the event would require some refactoring -
we have a `&mut UpdateContext` while running timers, but we'd need
to bail out and obtain a `&mut Player`.
Many of the class property defintiions were wrong -
instance methods were defined as class properties,
and class properties were defined as instance properties.
This allows Wonderputt to get further (it deliberately assigns
'null' to 'URLRequest.data'). We throw an exception for any other
value, to prevent confusing errors caused by attempting an
unexpected request to a web server with a missig body.
We currently lack the ability to preserve the original
`Value<'gc>` in the error, so we're forced to stringify the error.
This means that only typeless 'catch' blocks will work properly -
however, they're the only kind of 'catch' block that we currently
implement. Implementing support for typed 'catch' blocks will naturally
allow us to preserve the original 'Value<'gc>' in the 'throw'
implementation, since we'll need to switch to a custom `Error<'gc>`
type.
* avm2: Include class name in ScriptObject debug
Currently, the `ScriptObject` debug impl is almost useless -
while you determine if two printed objects are the same
by comparing the pointer value, you'll have no idea what
kind of object it actually is.
This PR now formats the `ScriptObject` output as a struct,
printing a (fake) "class" field containing the class name.
Before/after:
```
[ERROR ruffle_core::avm2::activation] AVM2 error: Cannot coerce Object(ScriptObject(ScriptObject(GcCell(Gc { ptr: 0x55f863936db8 })))) to an QName { ns: Private("Test.as$38"), name: "Second" }
[ERROR ruffle_core::avm2::activation] AVM2 error: Cannot coerce Object(ScriptObject(ScriptObject { class: "Object", ptr: 0x55ee0ad161e0 })) to an QName { ns: Private("Test.as$38"), name: "Second" }
```
Getting access to the class name from a `Debug` impl is tricky:
Developers can (and should be able to) insert logging statements
whereever they want, so any `GcCell` may be mutably borrowed.
Panics in debug impls are extremely frustrating to deal with,
so I've ensured that we only use `try_borrow` at each step.
If any of the attempted borrows fail, we print out an error message
in the "class_name" field, but we're still able to print the
rest of the `ScriptObject`.
Additionally, we have no access to a `MutationContext`, so we
cannot allocate a new `AvmString`. To get around this,
I've created a new method `QName::to_qualified_name_no_mc`,
which uses an `Either` to return a `WString` instead of allocating
an `AvmString`. This is more cumbersome to work with than the
nrmal `QName::to_qualified_name`, so we'll only want to use
it when we have no other choice.
An exception thrown by one event handler shoud not prevent other event
handlers from running on this same event. Some SWFs like Wonderputt
depend on this behavior, as they have buggy event handlers that throw
errors.
Calling `get_trait` copies the returned `Property`, so the caching
we performed in `PropertyClass` was never actually getting used.
Instead, we now store our `PropertyClass` values in a `Vec`
indexed by slot id. `set_property` and `init_property` now perform
coercions by going through the `VTable,` which writes the updated
`PropertyClass` back into the array.
FP allows code like
`class Foo { static var INSTANCE: Foo = new Foo(); }`
However, this breaks our current property type coercion setup -
we cannot resolve the type `Foo` when setting the property `INSTANCE`,
since `Foo` is still being constructed.
Fortunately, we can perform this 'coercion' by just checking if
the object's class name and domain match the type name and domain
of the property.
This returns the approximate interval that the audio backend
updates the sound position information. This is used for syncing
animation to embedded "stream" audio tracks, and fixes some
stuttering in cases where the syncing was being too strict.
Previously, we would create a fresh `LoaderInfo` object each
time the `loaderInfo` property was accessed. However, users can
add event handlers to a `LoaderInfo`, so we need to create and
store exactly one `LoaderInfo` object per movie (and stage).
To verify that we're correctly handling the storage of `LoaderInfo`,
I've implemented firing the "init" event. This required a new
`on_frame_exit` hook, so that we can properly fire the "init"
event after the "exitFrame" for the initial frame but before
the "enterFrame" of the next frame.
The current 'setInterval/setTimeout' implementation is
moved to 'core/src/timers.rs', and now works with both
AVM1 and AVM2 objects. The `flash.utils.Timer` class is implemented
mostly in ActionScript, with minimal modifications to the actual
Ruffle timer code.
* avm2: implement string replace where pattern is string and replacement is a function
* * removed unnecessary vec!
* fixed "no newline at the end of file"
This commit adds support for combining instance allocators with
ActionScript playerglobal class definitions. This is activated
by defining the metadata `[Ruffle(InstanceAllocator = "true")]`
on the ActionScript class definition.
The implementation of this feature is very similar to native methods:
`build_playerglobal` checks for the metadata described above,
and defines a const `NATIVE_INSTANCE_ALLOCATOR_TABLE` mapping
class ids to function pointers.
To demonstrate this feature, I've converted `Event` to ActionScript
(keeping the existing instance allocator function).
I've also converted `ActivityEvent` and `ContextMenuEvent` to
`ActionScript`, to demonstrate how this simplifies inheritance.
In a future PR, we can convert the remaining events to ActionScript,
and remove the `EventData` enum entirely.
Unfortunately, `flex-sdk`'s `asc.jar` compiler strips out all metadata
when the `-optimize` option is passed. As a result, I forked
`flex-sdk` and disabled this behavior:
https://github.com/ruffle-rs/flex-sdk/releases/tag/ruffle-1.0.0
The modified `asc.jar` (built from the forked repository)
is included in this PR, and replaces the our previous 'asc.jar'
downloaded from the official Flex SDK release.
* Change metadata to `[Ruffle(InstanceAllocator)]`
* Strip out metadata before saving bytecode
* avm2: implement string.replace(...) with fn, for now regex only.
* string - added path for replacing regex with fn (replacing string
with fn is still unimplemented)
* regex - factored out common replace logic for when replacement is
a string and when it is a function
* added tests
* Addressed review comments
* removed tinkering cruft; formatting
* addressed review comments
This commit adds support for marking methods as `native`
in ActionScript classes defined in playerglobal. The
`build_playerglobal` now checks for native methods, and
generates Rust code linking them to a corresponding Rust
function definition in the codebase.
To test this functionality, I've reimplemented several
functions as native methods (and moved related code to
pure ActionScript).
* avm2: implement string.split for regex
* Compressed the testing for regexp and unwrapping thereof
* * Moved the split logic into the regex object
* Factored out a method for utf-16 matching
* Added tests
* formatting
* * replaced manual counting with storage.length()
* clippy cleanup
* Address review comments
* fix import path for WString
* remove redundant variable in return statement
* error passing via '?' instead of unwrap()
Though https://github.com/rust-lang/rust-clippy/pull/8355 has been
merged, it seems to still report false-positives on nightly channel.
For now just fix the instances reported by stable clippy, and keep
`needless_borrow` allowed.
The register index was not being increment when preloading the
`super` register which would cause issues when multiple registers
were preloaded.
Fixes#7338.
Alongside comment wordings, fix handling of non-`u8` characters by
replacing `as u8` conversions with `u8::try_from()`, that doesn't
wrap around, but rather fails gracefully.
Based on the work in #6717, plus additional adaptions mentioned in
https://github.com/gfx-rs/wgpu/blob/master/CHANGELOG.md#wgpu-013-2022-06-30,
and more not-mentioned but required changes.
Also bump `wasm-bindgen` to `0.2.81` (along with its helper crates), as
required by the new `wgpu` version.
Note that I don't fully understand some of the required changes, notably:
* `wgpu::PresentMode::Mailbox` no longer works on my machine (Windows 11) -
The `wgpu` documentation says that `wgpu::PresentMode::Fifo` is the
only guaranteed to be supported, so I switched over to it instead.
* `self.staging_belt.recall()` doesn't return a `Future` anymore -
I assume it became synchronous so I simply removed the `executor`
from there.
Properties can be declared with a type
(e.g. `var foo:MyClass = new MyClass();`). When
`set_property`/`init_property` is invoked for that property,
the VM will attempt to coerce the value to the provided type,
throwing an error if this fails. This can have observable behavior
consequences - if a property has type `integer`, for example, then
storing a floating point `Number` to that property will cause the
value to be coerced to an integer. Some SWFs (e.g. 'Solarmax') rely
on this behavior in order to implicitly coerce a floating point value
that's later used for array indexing.
This PR implements property type coercions in Ruffle. There are several
important considerations:
* The class lookup for property types needs to be done lazily, since
we can have a cycle between two classes (e.g. `var prop1:Class2;`
and `var prop2:Class1` in two different classes).
* The class lookup uses special rules (different from
`resolve_definition`), and does *not* use `ScopeStack/`ScopeTree`
This means that a private class can specified as a property name -
the lookup will succeed without using a scope, even though
`flash.utils.getDefinitionByName` would fail with the same name
* The specialized 'Vector' classes (e.g "Vector$int") can be used
as property types, even though they cannot be lookup up normally.
Some Ruffle class definitions were previously using nonexistent
classes as property types (e.g. "BareObject") - these are fixed
in this PR.
- Handle the case where both preload aud suppress flags are
set for the same variable;
- Remove `arguments` field in `Activation`; instead use a normal
local definition;
- When `suppress_this` is set, inherit the `this` value from parent
activation. (This isn't entirely correct, as FP's `this` is mutable
and seems to be part of the scope chain, but this would require a
larger refactoring)
Currently, all three render backends hold on texture-related
resources indefinitely (`register_bitmap` pushes to a `Vec`,
and never removes anything). As a result, the resources used
by the render backend (which may include GPU memory) will grow
over time, even if the corresponding `BitmapData` has been deallocated.
This commit adds a new `unregister_bitmap` method, which is called from
`BitmapData.dispose`. All render backs are changed to now use an
`FnvHashMap<BitmapHandle, _>` instead of a `Vec`, allowing us to
remove individual entries.
Currently, we only call `unregister_bitmap in response to
`BitmapData.dispose` - when `BitmapData` is freed by the
garbage collector, `unregister_bitmap` is *not* called.
This will be addressed in a future PR.
I've kept the rust `flash.geom` module, even though it's now empty,
since we'll need to add things like `flash.geom.Transform` native
methods in the future.
* AVM2: Implement escape()
* chore: Fix formatting
* avm2: Escape resolves non strings to null and use push to append
* chore: Fix nits
* avm2: Escape should coerce objects, add early returns
Previously all the `.as` files compiled into `playerglobal.swf`
were detected automatically using `walkdir`. While this might be
convenient, it can cause unexpected results when untracked `.as`
files exist. So instead, introduce two entry points - `stubs.as`
and `globals.as`, which include all stub ActionScript definitions,
and actual class implementations, respectively. This also simplifies
the `playerglobal.swf` build script a bit.
`flash.geom.Rectangle` is a good candidate, since it doesn't have
any native function, and it depends only on `flash.geom.Point`,
which was already been ported to ActionScript in #7071.
This PR adds support for building a custom `playerglobal.swf`, which can be used
to implement builtin Flash classes in ActionScript. This file is embedded into Ruffle
using `include_bytes!`, and loaded during initialization.
As an example, the `Point` class is reimplemented
in ActionScript, and `flash.text.AntiAliasType` is added.
The ActionScript compilation process is performed by `core/build.rs`.
See that file, along with `core/src/avm2/globals/README.md`, for
more details.
The `render_list` for a container always contains all of the children
under both AVM1 and AVM2 - howver, the depth_list may not contain
some children under AVM2.
When we're not performing some AVM1-specific operation
(e.g. `getInstanceAtDepth`, or dumping out AVM1 variables),
we should be using the render list.
This stubs out BlurFilter, adds properties to GlowFilter,
and make the getter for DisplayObject.filters return
an empty array instead of Undefined.
This is all of the filter-related code that 'Solarmax'
needs in order to reach the main screen (combined with
other unrelated changes I have yet to submit)
Previously, there was an off-by-one bug in `get_enumerant_name`,
which caused us to produce a spurious 'null' as a key.
However, the 'dictionary_foreach' test only checked that certain
keys were present, so the presence of an additional key didn't break
the test.
This commit makes Dictionary enumerants behave in the same way as
Array enumerants - all of the object-specific enumerants
(in this case, the non-primitive dicitonar keys) come first,
followed by 'base' enumerants from ScriptObject (in this case,
primtive/String keys). Additionally, `setPropertyIsEnumerable` is now
ignored for `Dictionary`, consistent with Flash's behavior.
The `dictionary_foreach` test is updated to print out all of
the keys when inspecting the dictionary. Since the enumeration
order is unstable (under both Flash and Ruffle) due to the dependency
on pointer hashing, the test sorts the keys before printing them.
This ensures that we get stable output which is consistent between
Ruffle and Flash.
Flash Player allows this, and returns the path to the root SWF file.
The test only checks that the returned path contains 'test.swf',
to avoid depending on a platform-specific path.
The loop to search for a `non_hole` was missing
a `break;`, so it would actually find the *first*
non-hole, rather than than the last. This was not caught
by the test, since there was only one "real" element
in the array (the other one was set on 'Array.prototype')
Since all `RenderBackend::register_bitmap_*` implementations are
identical now, move them to the default implementation of `RenderBackend`.
Also, turn `RenderBackend::register_bitmap_raw` into `RenderBackend::register_bitmap`,
which accepts a single `Bitmap` parameter.
Replace direct instatiations of `swf::Matrix` where only `tx` and
`ty` are specified, and other fields are default.
This results in a slightly more shorter, readable code.
A method called with `super` is always an instance method,
so we should be using `instance_scope` for consistency with
`call_property`. This fixes a bug where a method cannot
access static class members (via `getlex`) when called bia
`super.method()`
In several places, we read some data from a tag, and then pass
the original tag length to `resize_to_reader`. This is incorrect -
the provided length is used an an offset from the current position
in the reader, so we will extend past the end of the current tag if
we've already read some bytes.
In practice, this doesn't appear to cause any problems - AVM bytecode
has internal length fields, which end up ensuring that we will never
try to read past where the slice *should* end. However, if a `DoAbc`
tag is the last tag in the file, then we'll end up trying to use
`resize_to_reader` with an offset past the end of the movie.
This commit subtracts the number of already-read bytes from `tag_len`,
to ensure that we always construct a correctly-sized `SwfSlice`
Store just the XML declaration string itself, rather than the attributes
it consists of. Then simply return it in ActionScript's `XML.xmlDecl`
property, without using `quick_xml::Writer` at all. This also matches
Flash behavior by capturing the XML declaration as-is, preserving
whitespaces, quotes, casing etc.
Prior to this commit, executing frame scripts on a movie that doesn't have them for this frame, or didn't advance to a new frame, would cause the the movie to ignore all gotos until the next time it ran a frame script.
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.
Guarantee bitmap data after decoding has the expected length for
the given width+height+format. This eases the burden from backends
to worry about this. Pad or truncate the data if it doesn't have
the expected size.
Due to various quirks of how timeline-initiated symbols interact with AVM2, it is possible for user code to gain a reference to uninitialized objects (especially `SimpleButton` which doesn't initialize until after `exitFrame`). It is still possible to attach event handlers to them that fire correctly, and movies expect to be able to.
Internal function calls such as `toString` and event handlers
always used the base clip from the function itself, so add an
`ExecutionReason::InternalCall` to signify this and pass it along
to `call_method`.
Fix various scope behavior when executing a function:
* For function calls in SWFv6+, functions are proper closures and
close over the SWF version, base clip, and scope of their
defining function.
* Function calls in SWFv5 are not closures, and use the version,
base clip, and scope of `this` when the function is called.
Fixes#5502.
Testing under Flash shows that methods can be considered 'unchecked'
(allowing them to be called with more arguments than declared
parameters) even if they have a declared return type.
This is relied on by SteamBirds, which registers an event handler
which takes 0 parameters and an explicitly declared return type
This was recently added in https://github.com/rust-lang/rust/pull/96150
Some of the `__version` rules are currently unused, but I assume
that we still want to keep them for potential future use.
This module is now mostly empty, so move the items up to `globals`.
`getDepth` was the only shared method, so declare this property
inline in each display object type. `Video` was also incorrectly
declaring `getDepth`.
Remove `_root`, `_parent` and `_global` from `MovieClip.prototype`.
Instead, these are "magic" properties similar to `_x` and `_y`.
Add `StageObject::resolve_path_property` to handle these, alongside
the `_levelN` property.
Fixes#768.
The remaining caller was `SwfMovie::from_path`, which is now changed
to be simpler, and a little stricter (panics if `Url::from_file_path`
fails, though it shouldn't happen with canonicalized paths).
Remove the `swf_version` parameter from `Activation` constructors,
because this was incorrectly using the global or root SWF version
most times.
Instead, grab the SWF version for the activation directly from the
base clip.