core: Store the root of each loaded movie and use it as a last-ditch way to get the root

This commit is contained in:
David Wendt 2021-05-06 18:43:23 -04:00 committed by Mike Welsh
parent 9ded256c23
commit 6a9249e52f
5 changed files with 33 additions and 25 deletions

View File

@ -403,7 +403,7 @@ pub fn root<'gc>(
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
if let Some(dobj) = this.and_then(|this| this.as_display_object()) { if let Some(dobj) = this.and_then(|this| this.as_display_object()) {
return Ok(dobj return Ok(dobj
.avm2_root(&activation.context) .avm2_root(&mut activation.context)
.map(|root| root.object2()) .map(|root| root.object2())
.unwrap_or(Value::Null)); .unwrap_or(Value::Null));
} }
@ -558,7 +558,7 @@ pub fn loader_info<'gc>(
_args: &[Value<'gc>], _args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> { ) -> Result<Value<'gc>, Error> {
if let Some(dobj) = this.and_then(|this| this.as_display_object()) { if let Some(dobj) = this.and_then(|this| this.as_display_object()) {
if let Some(root) = dobj.avm2_root(&activation.context) { if let Some(root) = dobj.avm2_root(&mut activation.context) {
if DisplayObject::ptr_eq(root, dobj) { if DisplayObject::ptr_eq(root, dobj) {
let movie = dobj.movie(); let movie = dobj.movie();

View File

@ -1254,7 +1254,7 @@ pub trait TDisplayObject<'gc>:
/// ///
/// This function implements the AVM2 concept of root clips. For the AVM1 /// This function implements the AVM2 concept of root clips. For the AVM1
/// version, see `avm1_root`. /// version, see `avm1_root`.
fn avm2_root(&self, context: &UpdateContext<'_, 'gc, '_>) -> Option<DisplayObject<'gc>> { fn avm2_root(&self, context: &mut UpdateContext<'_, 'gc, '_>) -> Option<DisplayObject<'gc>> {
let mut parent = Some((*self).into()); let mut parent = Some((*self).into());
while let Some(p) = parent { while let Some(p) = parent {
@ -1280,17 +1280,8 @@ pub trait TDisplayObject<'gc>:
} }
parent.or_else(|| { parent.or_else(|| {
if let Avm1Value::Object(object) = self.object() { let movie = self.movie()?;
object.as_display_object() context.library.library_for_movie_mut(movie).root()
} else if let Avm2Value::Object(object) = self.object2() {
if self.is_on_stage(context) {
object.as_display_object()
} else {
None
}
} else {
None
}
}) })
} }

View File

@ -143,6 +143,9 @@ pub struct MovieLibrary<'gc> {
/// Shared reference to the constructor registry used for this movie. /// Shared reference to the constructor registry used for this movie.
/// Should be `None` if this is an AVM2 movie. /// Should be `None` if this is an AVM2 movie.
avm1_constructor_registry: Option<Gc<'gc, Avm1ConstructorRegistry<'gc>>>, avm1_constructor_registry: Option<Gc<'gc, Avm1ConstructorRegistry<'gc>>>,
/// The root display object for this movie.
root: Option<DisplayObject<'gc>>,
} }
impl<'gc> MovieLibrary<'gc> { impl<'gc> MovieLibrary<'gc> {
@ -155,6 +158,7 @@ impl<'gc> MovieLibrary<'gc> {
avm_type, avm_type,
avm2_domain: None, avm2_domain: None,
avm1_constructor_registry: None, avm1_constructor_registry: None,
root: None,
} }
} }
@ -361,6 +365,18 @@ impl<'gc> MovieLibrary<'gc> {
pub fn avm2_domain(&self) -> Avm2Domain<'gc> { pub fn avm2_domain(&self) -> Avm2Domain<'gc> {
self.avm2_domain.unwrap() self.avm2_domain.unwrap()
} }
/// Retrieve the root display object that was created to represent the
/// movie being loaded.
pub fn root(&self) -> Option<DisplayObject<'gc>> {
self.root
}
/// Set the root display object that was created to represent the
/// movie being loaded.
pub fn set_root(&mut self, root: DisplayObject<'gc>) {
self.root = Some(root);
}
} }
/// Symbol library for multiple movies. /// Symbol library for multiple movies.

View File

@ -488,12 +488,6 @@ impl<'gc> Loader<'gc> {
.lock() .lock()
.expect("Could not lock player!!") .expect("Could not lock player!!")
.update(|uc| { .update(|uc| {
let domain =
Avm2Domain::movie_domain(uc.gc_context, uc.avm2.global_domain());
uc.library
.library_for_movie_mut(movie.clone())
.set_avm2_domain(domain);
let (clip, broadcaster) = match uc.load_manager.get_loader(handle) { let (clip, broadcaster) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie { Some(Loader::Movie {
target_clip, target_clip,
@ -504,6 +498,13 @@ impl<'gc> Loader<'gc> {
_ => unreachable!(), _ => unreachable!(),
}; };
let domain =
Avm2Domain::movie_domain(uc.gc_context, uc.avm2.global_domain());
let library = uc.library.library_for_movie_mut(movie.clone());
library.set_avm2_domain(domain);
library.set_root(clip);
if let Some(broadcaster) = broadcaster { if let Some(broadcaster) = broadcaster {
Avm1::run_stack_frame_for_method( Avm1::run_stack_frame_for_method(
clip, clip,

View File

@ -386,14 +386,14 @@ impl Player {
context.swf.height(), context.swf.height(),
); );
let domain = Avm2Domain::movie_domain(context.gc_context, context.avm2.global_domain()); let domain = Avm2Domain::movie_domain(context.gc_context, context.avm2.global_domain());
context
.library
.library_for_movie_mut(context.swf.clone())
.set_avm2_domain(domain);
let root: DisplayObject = let root: DisplayObject =
MovieClip::from_movie(context.gc_context, context.swf.clone()).into(); MovieClip::from_movie(context.gc_context, context.swf.clone()).into();
let library = context.library.library_for_movie_mut(context.swf.clone());
library.set_avm2_domain(domain);
library.set_root(root);
root.set_depth(context.gc_context, 0); root.set_depth(context.gc_context, 0);
let flashvars = if !context.swf.parameters().is_empty() { let flashvars = if !context.swf.parameters().is_empty() {
let object = ScriptObject::object(context.gc_context, None); let object = ScriptObject::object(context.gc_context, None);