diff --git a/core/src/avm1/activation.rs b/core/src/avm1/activation.rs index 0c8c0ee57..bdd28277e 100644 --- a/core/src/avm1/activation.rs +++ b/core/src/avm1/activation.rs @@ -10,6 +10,7 @@ use crate::backend::navigator::{NavigationMethod, Request}; use crate::context::UpdateContext; use crate::display_object::{DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer}; use crate::ecma_conversions::{f64_to_wrapping_i32, f64_to_wrapping_u32}; +use crate::loader::MovieLoaderVMData; use crate::string::{AvmString, SwfStrExt as _, WStr, WString}; use crate::tag_utils::SwfSlice; use crate::vminterface::Instantiator; @@ -1209,8 +1210,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { level, Request::get(url.to_string()), None, - None, - None, + MovieLoaderVMData::Avm1 { broadcaster: None }, ); self.context.navigator.spawn_future(future); } @@ -1340,8 +1340,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { clip_target, request, None, - None, - None, + MovieLoaderVMData::Avm1 { broadcaster: None }, ); self.context.navigator.spawn_future(future); } @@ -1362,8 +1361,7 @@ impl<'a, 'gc> Activation<'a, 'gc> { clip_target, Request::get(url.to_utf8_lossy().into_owned()), None, - None, - None, + MovieLoaderVMData::Avm1 { broadcaster: None }, ); self.context.navigator.spawn_future(future); } diff --git a/core/src/avm1/globals/movie_clip.rs b/core/src/avm1/globals/movie_clip.rs index 77250bffa..11468ac7a 100644 --- a/core/src/avm1/globals/movie_clip.rs +++ b/core/src/avm1/globals/movie_clip.rs @@ -1546,8 +1546,7 @@ fn load_movie<'gc>( DisplayObject::MovieClip(target), request, None, - None, - None, + crate::loader::MovieLoaderVMData::Avm1 { broadcaster: None }, ); activation.context.navigator.spawn_future(future); diff --git a/core/src/avm1/globals/movie_clip_loader.rs b/core/src/avm1/globals/movie_clip_loader.rs index 9caa59b8f..9f622b79e 100644 --- a/core/src/avm1/globals/movie_clip_loader.rs +++ b/core/src/avm1/globals/movie_clip_loader.rs @@ -11,7 +11,7 @@ use crate::avm1::{ArrayObject, Object, Value}; use crate::backend::navigator::Request; use crate::context::GcContext; use crate::display_object::{TDisplayObject, TDisplayObjectContainer}; -use crate::loader::MovieLoaderEventHandler; +use crate::loader::MovieLoaderVMData; const PROTO_DECLS: &[Declaration] = declare_properties! { "loadClip" => method(load_clip; DONT_ENUM | DONT_DELETE); @@ -65,8 +65,9 @@ fn load_clip<'gc>( target, Request::get(url.to_utf8_lossy().into_owned()), None, - Some(MovieLoaderEventHandler::Avm1Broadcast(this)), - None, + MovieLoaderVMData::Avm1 { + broadcaster: Some(this), + }, ); activation.context.navigator.spawn_future(future); diff --git a/core/src/avm2/globals/flash/display/loader.rs b/core/src/avm2/globals/flash/display/loader.rs index b8f70eb5d..dc95c81ec 100644 --- a/core/src/avm2/globals/flash/display/loader.rs +++ b/core/src/avm2/globals/flash/display/loader.rs @@ -15,7 +15,7 @@ use crate::avm2_stub_method; use crate::backend::navigator::{NavigationMethod, Request}; use crate::display_object::LoaderDisplay; use crate::display_object::MovieClip; -use crate::loader::{Avm2LoaderData, MovieLoaderEventHandler}; +use crate::loader::MovieLoaderVMData; use crate::tag_utils::SwfMovie; use std::sync::Arc; @@ -87,13 +87,13 @@ pub fn load<'gc>( content.into(), request, Some(url), - Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)), - Some(Avm2LoaderData { + MovieLoaderVMData::Avm2 { + loader_info, context, default_domain: activation .caller_domain() .expect("Missing caller domain in Loader.load"), - }), + }, ); activation.context.navigator.spawn_future(future); } @@ -218,13 +218,13 @@ pub fn load_bytes<'gc>( activation.context.player.clone(), content.into(), bytearray.bytes().to_vec(), - Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)), - Some(Avm2LoaderData { + MovieLoaderVMData::Avm2 { + loader_info, context, default_domain: activation .caller_domain() .expect("Missing caller domain in Loader.loadBytes"), - }), + }, ); activation.context.navigator.spawn_future(future); } diff --git a/core/src/avm2/object/loaderinfo_object.rs b/core/src/avm2/object/loaderinfo_object.rs index 425f70baf..6bc9ee614 100644 --- a/core/src/avm2/object/loaderinfo_object.rs +++ b/core/src/avm2/object/loaderinfo_object.rs @@ -231,7 +231,7 @@ impl<'gc> LoaderInfoObject<'gc> { Some(LoaderStream::Swf(_, root)) => root .as_movie_clip() .map(|mc| mc.loaded_bytes() >= mc.total_bytes()) - .unwrap_or(false), + .unwrap_or(true), _ => false, }; diff --git a/core/src/loader.rs b/core/src/loader.rs index fc1e019d6..89e71dfb6 100644 --- a/core/src/loader.rs +++ b/core/src/loader.rs @@ -260,16 +260,14 @@ impl<'gc> LoadManager<'gc> { target_clip: DisplayObject<'gc>, request: Request, loader_url: Option, - event_handler: Option>, - avm2_data: Option>, + vm_data: MovieLoaderVMData<'gc>, ) -> OwnedFuture<(), Error> { let loader = Loader::Movie { self_handle: None, target_clip, - event_handler, + vm_data, loader_status: LoaderStatus::Pending, movie: None, - avm2_data, }; let handle = self.add_loader(loader); let loader = self.get_loader_mut(handle).unwrap(); @@ -284,16 +282,14 @@ impl<'gc> LoadManager<'gc> { player: Weak>, target_clip: DisplayObject<'gc>, bytes: Vec, - event_handler: Option>, - avm2_data: Option>, + vm_data: MovieLoaderVMData<'gc>, ) -> OwnedFuture<(), Error> { let loader = Loader::Movie { self_handle: None, target_clip, - event_handler, + vm_data, loader_status: LoaderStatus::Pending, movie: None, - avm2_data, }; let handle = self.add_loader(loader); let loader = self.get_loader_mut(handle).unwrap(); @@ -472,19 +468,19 @@ pub enum LoaderStatus { #[derive(Collect, Clone, Copy)] #[collect(no_drop)] -pub enum MovieLoaderEventHandler<'gc> { - Avm1Broadcast(Object<'gc>), - Avm2LoaderInfo(Avm2Object<'gc>), -} +pub enum MovieLoaderVMData<'gc> { + Avm1 { + broadcaster: Option>, + }, + Avm2 { + loader_info: Avm2Object<'gc>, -#[derive(Collect, Clone, Copy)] -#[collect(no_drop)] -pub struct Avm2LoaderData<'gc> { - /// The context of the SWF being loaded. - pub context: Option>, + /// The context of the SWF being loaded. + context: Option>, - /// The default domain this SWF will use. - pub default_domain: Avm2Domain<'gc>, + /// The default domain this SWF will use. + default_domain: Avm2Domain<'gc>, + }, } /// A struct that holds garbage-collected pointers for asynchronous code. @@ -507,9 +503,8 @@ pub enum Loader<'gc> { /// The target movie clip to load the movie into. target_clip: DisplayObject<'gc>, - /// Event broadcaster (typically a `MovieClipLoader`) to fire events - /// into. - event_handler: Option>, + // Virtual-machine specific data (AVM1 or AVM2) + vm_data: MovieLoaderVMData<'gc>, /// Indicates the completion status of this loader. /// @@ -527,9 +522,6 @@ pub enum Loader<'gc> { /// completed and we expect the Player to periodically tick preload /// until loading completes. movie: Option>, - - /// AVM2 specific data for this SWF. - avm2_data: Option>, }, /// Loader that is loading form data into an AVM1 object scope. @@ -1318,26 +1310,28 @@ impl<'gc> Loader<'gc> { let me = me.unwrap(); - let (clip, event_handler) = match me { + let (clip, vm_data) = match me { Loader::Movie { target_clip, - event_handler, + vm_data, .. - } => (*target_clip, *event_handler), + } => (*target_clip, *vm_data), _ => unreachable!(), }; - match event_handler { - Some(MovieLoaderEventHandler::Avm1Broadcast(broadcaster)) => { - Avm1::run_stack_frame_for_method( - clip, - broadcaster, - uc, - "broadcastMessage".into(), - &["onLoadStart".into(), clip.object()], - ); + match vm_data { + MovieLoaderVMData::Avm1 { broadcaster } => { + if let Some(broadcaster) = broadcaster { + Avm1::run_stack_frame_for_method( + clip, + broadcaster, + uc, + "broadcastMessage".into(), + &["onLoadStart".into(), clip.object()], + ); + } } - Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) => { + MovieLoaderVMData::Avm2 { loader_info, .. } => { let mut activation = Avm2Activation::from_nothing(uc.reborrow()); // Update the LoadersTream - we still have a fake SwfMovie, but we now have the real target clip. @@ -1356,7 +1350,6 @@ impl<'gc> Loader<'gc> { let open_evt = Avm2EventObject::bare_default_event(&mut activation.context, "open"); Avm2::dispatch_event(uc, open_evt, loader_info); } - None => {} } Ok(()) @@ -1379,22 +1372,25 @@ impl<'gc> Loader<'gc> { } } player.lock().unwrap().update(|uc| { - let (clip, event_handler, avm2_data) = match uc.load_manager.get_loader(handle) { + let (clip, vm_data) = match uc.load_manager.get_loader(handle) { Some(Loader::Movie { target_clip, - event_handler, - avm2_data, + vm_data, .. - }) => (*target_clip, *event_handler, *avm2_data), + }) => (*target_clip, *vm_data), None => return Err(Error::Cancelled), _ => unreachable!(), }; let mut activation = Avm2Activation::from_nothing(uc.reborrow()); - let domain = if let Some(avm2_data) = avm2_data { - let domain = avm2_data - .context + let domain = if let MovieLoaderVMData::Avm2 { + context, + default_domain, + .. + } = vm_data + { + let domain = context .and_then(|o| { o.get_public_property("applicationDomain", &mut activation) .ok() @@ -1402,7 +1398,7 @@ impl<'gc> Loader<'gc> { .and_then(|v| v.coerce_to_object(&mut activation).ok()) .and_then(|o| o.as_application_domain()) .unwrap_or_else(|| { - let parent_domain = avm2_data.default_domain; + let parent_domain = default_domain; Avm2Domain::movie_domain(&mut activation, parent_domain) }); Some(domain) @@ -1430,7 +1426,7 @@ impl<'gc> Loader<'gc> { _ => unreachable!(), }; - if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = event_handler { + if let MovieLoaderVMData::Avm2 { loader_info, .. } = vm_data { // Update the LoaderStream - we now have a real SWF movie and a real target clip loader_info .as_loader_info_object() @@ -1458,9 +1454,7 @@ impl<'gc> Loader<'gc> { if let Some(mc) = clip.as_movie_clip() { let loader_info = - if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = - event_handler - { + if let MovieLoaderVMData::Avm2 { loader_info, .. } = vm_data { Some(*loader_info.as_loader_info_object().unwrap()) } else { None @@ -1570,31 +1564,33 @@ impl<'gc> Loader<'gc> { let me = me.unwrap(); - let (clip, event_handler) = match me { + let (clip, vm_data) = match me { Loader::Movie { target_clip, - event_handler, + vm_data, .. - } => (*target_clip, *event_handler), + } => (*target_clip, *vm_data), _ => unreachable!(), }; - match event_handler { - Some(MovieLoaderEventHandler::Avm1Broadcast(broadcaster)) => { - Avm1::run_stack_frame_for_method( - clip, - broadcaster, - uc, - "broadcastMessage".into(), - &[ - "onLoadProgress".into(), - clip.object(), - cur_len.into(), - total_len.into(), - ], - ); + match vm_data { + MovieLoaderVMData::Avm1 { broadcaster } => { + if let Some(broadcaster) = broadcaster { + Avm1::run_stack_frame_for_method( + clip, + broadcaster, + uc, + "broadcastMessage".into(), + &[ + "onLoadProgress".into(), + clip.object(), + cur_len.into(), + total_len.into(), + ], + ); + } } - Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) => { + MovieLoaderVMData::Avm2 { loader_info, .. } => { let mut activation = Avm2Activation::from_nothing(uc.reborrow()); let progress_evt = activation @@ -1615,7 +1611,6 @@ impl<'gc> Loader<'gc> { Avm2::dispatch_event(uc, progress_evt, loader_info); } - None => {} } Ok(()) @@ -1627,23 +1622,22 @@ impl<'gc> Loader<'gc> { uc: &mut UpdateContext<'_, 'gc>, dobj: Option>, ) -> Result<(), Error> { - let (target_clip, event_handler, movie) = match uc.load_manager.get_loader_mut(handle) { + let (target_clip, vm_data, movie) = match uc.load_manager.get_loader_mut(handle) { Some(Loader::Movie { target_clip, movie, - event_handler, + vm_data, .. - }) => (*target_clip, *event_handler, movie.clone()), + }) => (*target_clip, *vm_data, movie.clone()), None => return Err(Error::Cancelled), _ => unreachable!(), }; - let loader_info = - if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = event_handler { - Some(*loader_info.as_loader_info_object().unwrap()) - } else { - None - }; + let loader_info = if let MovieLoaderVMData::Avm2 { loader_info, .. } = vm_data { + Some(*loader_info.as_loader_info_object().unwrap()) + } else { + None + }; if let Some(loader_info) = loader_info { // Store the real movie into the `LoaderStream`, so that @@ -1673,7 +1667,7 @@ impl<'gc> Loader<'gc> { } } - if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = event_handler { + if let MovieLoaderVMData::Avm2 { loader_info, .. } = vm_data { let domain = uc .library .library_for_movie(movie.unwrap()) @@ -1707,23 +1701,25 @@ impl<'gc> Loader<'gc> { } } - match event_handler { - Some(MovieLoaderEventHandler::Avm1Broadcast(broadcaster)) => { - Avm1::run_stack_frame_for_method( - target_clip, - broadcaster, - uc, - "broadcastMessage".into(), - // TODO: Pass an actual httpStatus argument instead of 0. - &["onLoadComplete".into(), target_clip.object(), 0.into()], - ); + match vm_data { + MovieLoaderVMData::Avm1 { broadcaster } => { + if let Some(broadcaster) = broadcaster { + Avm1::run_stack_frame_for_method( + target_clip, + broadcaster, + uc, + "broadcastMessage".into(), + // TODO: Pass an actual httpStatus argument instead of 0. + &["onLoadComplete".into(), target_clip.object(), 0.into()], + ); + } } // This is fired after we process the movie's first frame, // in `MovieClip.on_exit_frame` - Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) => { + MovieLoaderVMData::Avm2 { loader_info, .. } => { let loader_info_obj = loader_info.as_loader_info_object().unwrap(); loader_info_obj.set_loader_stream( - LoaderStream::Swf(target_clip.as_movie_clip().unwrap().movie(), target_clip), + LoaderStream::Swf(target_clip.as_movie_clip().unwrap().movie(), dobj.unwrap()), uc.gc_context, ); @@ -1733,7 +1729,6 @@ impl<'gc> Loader<'gc> { } } } - None => {} } if let Loader::Movie { loader_status, .. } = uc.load_manager.get_loader_mut(handle).unwrap() @@ -1758,31 +1753,33 @@ impl<'gc> Loader<'gc> { //error types we can actually inspect. //This also can get errors from decoding an invalid SWF file, //too. We should distinguish those to player code. - let (clip, event_handler) = match uc.load_manager.get_loader_mut(handle) { + let (clip, vm_data) = match uc.load_manager.get_loader_mut(handle) { Some(Loader::Movie { target_clip, - event_handler, + vm_data, .. - }) => (*target_clip, *event_handler), + }) => (*target_clip, *vm_data), None => return Err(Error::Cancelled), _ => unreachable!(), }; - match event_handler { - Some(MovieLoaderEventHandler::Avm1Broadcast(broadcaster)) => { - Avm1::run_stack_frame_for_method( - clip, - broadcaster, - uc, - "broadcastMessage".into(), - &[ - "onLoadError".into(), - clip.object(), - "LoadNeverCompleted".into(), - ], - ); + match vm_data { + MovieLoaderVMData::Avm1 { broadcaster } => { + if let Some(broadcaster) = broadcaster { + Avm1::run_stack_frame_for_method( + clip, + broadcaster, + uc, + "broadcastMessage".into(), + &[ + "onLoadError".into(), + clip.object(), + "LoadNeverCompleted".into(), + ], + ); + } } - Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) => { + MovieLoaderVMData::Avm2 { loader_info, .. } => { let mut activation = Avm2Activation::from_nothing(uc.reborrow()); // FIXME - Match the exact error message generated by Flash @@ -1802,7 +1799,6 @@ impl<'gc> Loader<'gc> { Avm2::dispatch_event(uc, io_error_evt, loader_info); } - None => {} } if let Loader::Movie { loader_status, .. } = uc.load_manager.get_loader_mut(handle).unwrap() @@ -1819,13 +1815,13 @@ impl<'gc> Loader<'gc> { /// /// Used to fire listener events on clips and terminate completed loaders. fn movie_clip_loaded(&mut self, queue: &mut ActionQueue<'gc>) -> bool { - let (clip, event_handler, loader_status) = match self { + let (clip, vm_data, loader_status) = match self { Loader::Movie { target_clip, - event_handler, + vm_data, loader_status, .. - } => (*target_clip, *event_handler, *loader_status), + } => (*target_clip, *vm_data, *loader_status), _ => return false, }; @@ -1835,7 +1831,10 @@ impl<'gc> Loader<'gc> { LoaderStatus::Failed => true, LoaderStatus::Succeeded => { // AVM2 is handled separately - if let Some(MovieLoaderEventHandler::Avm1Broadcast(broadcaster)) = event_handler { + if let MovieLoaderVMData::Avm1 { + broadcaster: Some(broadcaster), + } = vm_data + { queue.queue_action( clip, ActionType::Method {