diff --git a/core/src/avm2/globals/flash/display/loader.rs b/core/src/avm2/globals/flash/display/loader.rs index 0ac0931a4e4c..bb12a57c5417 100644 --- a/core/src/avm2/globals/flash/display/loader.rs +++ b/core/src/avm2/globals/flash/display/loader.rs @@ -226,6 +226,7 @@ pub fn load_bytes<'gc>( )? .as_object() .unwrap(); + let future = activation.context.load_manager.load_movie_into_clip_bytes( activation.context.player.clone(), content.into(), @@ -255,5 +256,21 @@ pub fn unload<'gc>( this, &[0.into()], ); + + let loader_info = this + .get_property( + &Multiname::new( + activation.avm2().flash_display_internal, + "_contentLoaderInfo", + ), + activation, + )? + .as_object() + .unwrap(); + + let loader_info_object = loader_info.as_loader_info_object().unwrap(); + + loader_info_object.unload(activation); + Ok(Value::Undefined) } diff --git a/core/src/avm2/globals/flash/display/loader_info.rs b/core/src/avm2/globals/flash/display/loader_info.rs index 51df653f76a6..43c7f6b4c398 100644 --- a/core/src/avm2/globals/flash/display/loader_info.rs +++ b/core/src/avm2/globals/flash/display/loader_info.rs @@ -61,7 +61,22 @@ pub fn get_application_domain<'gc>( .and_then(|o| o.as_loader_stream()) { match &*loader_stream { - LoaderStream::NotYetLoaded(movie, _, _) | LoaderStream::Swf(movie, _) => { + LoaderStream::NotYetLoaded(movie, _, _) => { + let domain = activation + .context + .library + .library_for_movie_mut(movie.clone()) + .try_avm2_domain(); + + if let Some(domain) = domain { + return Ok(DomainObject::from_domain(activation, domain)?.into()); + } else { + return Ok(Value::Null); + } + } + + // A loaded SWF will always have an AVM2 domain present. + LoaderStream::Swf(movie, _) => { let domain = activation .context .library diff --git a/core/src/avm2/object/loaderinfo_object.rs b/core/src/avm2/object/loaderinfo_object.rs index 4d96cb8ae6db..d35dfc7dbfd0 100644 --- a/core/src/avm2/object/loaderinfo_object.rs +++ b/core/src/avm2/object/loaderinfo_object.rs @@ -1,6 +1,7 @@ //! Loader-info object use crate::avm2::activation::Activation; +use crate::avm2::error::argument_error; use crate::avm2::object::script_object::ScriptObjectData; use crate::avm2::object::{ClassObject, Object, ObjectPtr, TObject}; use crate::avm2::value::Value; @@ -15,36 +16,18 @@ use gc_arena::{Collect, GcCell, GcWeakCell, Mutation}; use std::cell::{Ref, RefMut}; use std::sync::Arc; -/// A class instance allocator that allocates LoaderInfo objects. +/// ActionScript cannot construct a LoaderInfo. Note that LoaderInfo isn't a final class. pub fn loader_info_allocator<'gc>( class: ClassObject<'gc>, activation: &mut Activation<'_, 'gc>, ) -> Result, Error<'gc>> { - let base = ScriptObjectData::new(class); - - Ok(LoaderInfoObject(GcCell::new( - activation.context.gc_context, - LoaderInfoObjectData { - base, - loaded_stream: None, - loader: None, - init_event_fired: false, - complete_event_fired: false, - shared_events: activation - .context - .avm2 - .classes() - .eventdispatcher - .construct(activation, &[])?, - uncaught_error_events: activation - .context - .avm2 - .classes() - .uncaughterrorevents - .construct(activation, &[])?, - }, - )) - .into()) + let class_name = class.inner_class_definition().read().name().local_name(); + + Err(Error::AvmError(argument_error( + activation, + &format!("Error #2012: {class_name}$ class cannot be instantiated."), + 2012, + )?)) } /// Represents a thing which can be loaded by a loader. @@ -97,7 +80,7 @@ pub struct LoaderInfoObjectData<'gc> { /// All normal script data. base: ScriptObjectData<'gc>, - /// The loaded stream that this gets it's info from. + /// The loaded stream that this gets its info from. loaded_stream: Option>, loader: Option>, @@ -281,6 +264,12 @@ impl<'gc> LoaderInfoObject<'gc> { pub fn set_loader_stream(&self, stream: LoaderStream<'gc>, mc: &Mutation<'gc>) { self.0.write(mc).loaded_stream = Some(stream); } + + pub fn unload(&self, activation: &mut Activation<'_, 'gc>) { + let empty_swf = Arc::new(SwfMovie::empty(activation.context.swf.version())); + let loader_stream = LoaderStream::NotYetLoaded(empty_swf, None, false); + self.set_loader_stream(loader_stream, activation.context.gc_context); + } } impl<'gc> TObject<'gc> for LoaderInfoObject<'gc> { diff --git a/core/src/library.rs b/core/src/library.rs index d6515ba77f6b..2f21b0bc1211 100644 --- a/core/src/library.rs +++ b/core/src/library.rs @@ -347,6 +347,10 @@ impl<'gc> MovieLibrary<'gc> { pub fn avm2_domain(&self) -> Avm2Domain<'gc> { self.avm2_domain.unwrap() } + + pub fn try_avm2_domain(&self) -> Option> { + self.avm2_domain + } } pub struct MovieLibrarySource<'a, 'gc> { diff --git a/tests/tests/swfs/avm2/loaderinfo_more/Test.as b/tests/tests/swfs/avm2/loaderinfo_more/Test.as new file mode 100644 index 000000000000..81f14108ba47 --- /dev/null +++ b/tests/tests/swfs/avm2/loaderinfo_more/Test.as @@ -0,0 +1,26 @@ + package { + import flash.display.Loader; + import flash.display.Sprite; + import flash.net.URLRequest; + import flash.system.ApplicationDomain; + import flash.system.LoaderContext; + + public class Test extends Sprite { + public function Test() { + var appDomain:ApplicationDomain = new ApplicationDomain(); + var loader:Loader = new Loader(); + trace(loader.contentLoaderInfo.applicationDomain); + loader.load(new URLRequest("loadable.swf"), new LoaderContext(null, appDomain)); + trace(loader.contentLoaderInfo.applicationDomain); + loader.contentLoaderInfo.addEventListener("complete", function(e:*) { + trace(loader.contentLoaderInfo.applicationDomain); + loader.unload(); + trace(loader.contentLoaderInfo.applicationDomain); + trace(loader.contentLoaderInfo.bytesLoaded); + trace(loader.contentLoaderInfo.bytesTotal); + }); + addChild(loader); + } + } +} + diff --git a/tests/tests/swfs/avm2/loaderinfo_more/loadable.swf b/tests/tests/swfs/avm2/loaderinfo_more/loadable.swf new file mode 100644 index 000000000000..43712e53f790 Binary files /dev/null and b/tests/tests/swfs/avm2/loaderinfo_more/loadable.swf differ diff --git a/tests/tests/swfs/avm2/loaderinfo_more/output.txt b/tests/tests/swfs/avm2/loaderinfo_more/output.txt new file mode 100644 index 000000000000..9f11ed81c77e --- /dev/null +++ b/tests/tests/swfs/avm2/loaderinfo_more/output.txt @@ -0,0 +1,6 @@ +null +null +[object ApplicationDomain] +null +0 +0 diff --git a/tests/tests/swfs/avm2/loaderinfo_more/test.swf b/tests/tests/swfs/avm2/loaderinfo_more/test.swf new file mode 100644 index 000000000000..a1ab1945ab9a Binary files /dev/null and b/tests/tests/swfs/avm2/loaderinfo_more/test.swf differ diff --git a/tests/tests/swfs/avm2/loaderinfo_more/test.toml b/tests/tests/swfs/avm2/loaderinfo_more/test.toml new file mode 100644 index 000000000000..568cadba535f --- /dev/null +++ b/tests/tests/swfs/avm2/loaderinfo_more/test.toml @@ -0,0 +1 @@ +num_ticks = 2