Skip to content
Open
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
10 changes: 5 additions & 5 deletions core/src/avm1/activation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::avm1::callable_value::CallableValue;
use crate::avm1::error::Error;
use crate::avm1::function::{Avm1Function, ExecutionReason, FunctionObject};
use crate::avm1::object_reference::MovieClipReference;
use crate::avm1::property::Attribute;
use crate::avm1::runtime::skip_actions;
use crate::avm1::scope::{Scope, ScopeClass};
Expand Down Expand Up @@ -30,8 +31,6 @@ use swf::avm1::types::*;
use url::form_urlencoded;
use web_time::Instant;

use super::object_reference::MovieClipReference;

macro_rules! avm_debug {
($avm: expr, $($arg:tt)*) => (
if $avm.show_debug_output() {
Expand Down Expand Up @@ -870,16 +869,17 @@ impl<'a, 'gc> Activation<'a, 'gc> {
let swf_version = self.swf_version();
let func_data = parent_data.to_unbounded_subslice(action.actions);
let constant_pool = self.constant_pool();
let bc = self.base_clip.object().coerce_to_object(self);

let mcr = MovieClipReference::from_display_object(self, self.base_clip);

let func = Avm1Function::from_swf_function(
self.gc(),
swf_version,
func_data,
action,
self.scope(),
constant_pool,
// `base_clip` should always be a living `MovieClip` so this can't fail
MovieClipReference::try_from_stage_object(self, bc).unwrap(),
mcr,
);
let name = func.name();
let prototype = Object::new(
Expand Down
29 changes: 24 additions & 5 deletions core/src/avm1/object_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ struct MovieClipReferenceData<'gc> {
}

impl<'gc> MovieClipReference<'gc> {
pub fn from_display_object(
activation: &mut Activation<'_, 'gc>,
display_object: DisplayObject<'gc>,
) -> Self {
let bc = display_object.object().coerce_to_object(activation);

// This can fail if `display_object.object() == Undefined`, so create a reference with only a path
match MovieClipReference::try_from_stage_object(activation, bc) {
Some(mcr) => mcr,
None => {
let mc_ref = MovieClipReferenceData {
path: MovieClipPath::new_from_path(activation.gc(), display_object.path()),
cached_object: None.into(),
};
MovieClipReference(Gc::new(activation.gc(), mc_ref))
}
}
}

pub fn try_from_stage_object(
activation: &mut Activation<'_, 'gc>,
object: Object<'gc>,
Expand Down Expand Up @@ -94,12 +113,12 @@ impl<'gc> MovieClipReference<'gc> {
Some(Self(Gc::new(activation.gc(), mc_ref)))
}

/// Handle the logic of swfv5 DisplayObjects
/// Handle the logic of SWFv5 DisplayObjects
fn process_swf5_references(
activation: &mut Activation<'_, 'gc>,
mut display_object: DisplayObject<'gc>,
) -> Option<DisplayObject<'gc>> {
// In swfv5 paths resolve to the first MovieClip parent if the target isn't a movieclip
// In SWFv5 paths resolve to the first MovieClip parent if the target isn't a MovieClip
if activation.swf_version() <= 5 {
while display_object.as_movie_clip().is_none() {
if let Some(p) = display_object.avm1_parent() {
Expand Down Expand Up @@ -128,12 +147,12 @@ impl<'gc> MovieClipReference<'gc> {
.and_then(|c| c.upgrade(activation.gc()))
{
if let Some(display_object) = cache.as_display_object_no_super() {
// We have to fallback to manual path-walking if the object is removed
// We have to fall back to manual path-walking if the object is removed
if !display_object.avm1_removed() {
let display_object = Self::process_swf5_references(activation, display_object)?;

// Note that there is a bug here but this *is* how it works in Flash:
// If we are using the cached DisplayObject, we return it's path, which can be changed by modifying `_name`
// If we are using the cached DisplayObject, we return its path, which can be changed by modifying `_name`
// However, if we remove and re-create the clip, the stored path (the original path) will differ from the path of the cached object (the modified path)
// Essentially, changes to `_name` are reverted after the clip is re-created

Expand Down Expand Up @@ -192,7 +211,7 @@ impl<'gc> MovieClipReference<'gc> {
None => istr!(""),
// Found the reference, cached, we can't re-use `self.path` sadly, it would be quicker if we could
// But if the clip has been re-named, since being created then `mc.path() != path`
Some((true, _, dobj)) => AvmString::new(activation.gc(), dobj.path()),
Some((true, _, disp_obj)) => AvmString::new(activation.gc(), disp_obj.path()),
// Found the reference, un-cached, so our cached path must be correct
Some((false, _, _)) => self.0.path.full_path,
}
Expand Down
Loading