core: Delay completion events until after the SWF is reported as fully loaded.

This commit is contained in:
David Wendt 2022-09-05 17:31:57 -04:00 committed by kmeisthax
parent 0a25f265d6
commit 006269e1f8
1 changed files with 35 additions and 14 deletions

View File

@ -8,7 +8,7 @@ use crate::avm2::Avm2;
use crate::avm2::Error;
use crate::avm2::EventObject;
use crate::context::UpdateContext;
use crate::display_object::DisplayObject;
use crate::display_object::{DisplayObject, TDisplayObject};
use crate::tag_utils::SwfMovie;
use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
@ -27,7 +27,8 @@ pub fn loaderinfo_allocator<'gc>(
base,
loaded_stream: None,
loader: None,
events_fired: false,
init_event_fired: false,
complete_event_fired: false,
shared_events: activation
.context
.avm2
@ -75,8 +76,11 @@ pub struct LoaderInfoObjectData<'gc> {
loader: Option<Object<'gc>>,
/// Whether or not we've fired our 'init' and 'complete' events
events_fired: bool,
/// Whether or not we've fired our 'init' event
init_event_fired: bool,
/// Whether or not we've fired our 'complete' event
complete_event_fired: bool,
/// The `EventDispatcher` used for `LoaderInfo.sharedEvents`.
// FIXME: If we ever implement sandboxing, then ensure that we allow
@ -102,7 +106,8 @@ impl<'gc> LoaderInfoObject<'gc> {
base,
loaded_stream,
loader,
events_fired: false,
init_event_fired: false,
complete_event_fired: false,
shared_events: activation
.context
.avm2
@ -138,7 +143,8 @@ impl<'gc> LoaderInfoObject<'gc> {
base,
loaded_stream: Some(LoaderStream::NotYetLoaded(movie, root_clip)),
loader,
events_fired: false,
init_event_fired: false,
complete_event_fired: false,
shared_events: activation
.context
.avm2
@ -164,8 +170,8 @@ impl<'gc> LoaderInfoObject<'gc> {
}
pub fn fire_init_and_complete_events(&self, context: &mut UpdateContext<'_, 'gc, '_>) {
if !self.0.read().events_fired {
self.0.write(context.gc_context).events_fired = true;
if !self.0.read().init_event_fired {
self.0.write(context.gc_context).init_event_fired = true;
// TODO - 'init' should be fired earlier during the download.
// Right now, we fire it when downloading is fully completed.
@ -177,7 +183,21 @@ impl<'gc> LoaderInfoObject<'gc> {
e
);
}
}
if !self.0.read().complete_event_fired {
// NOTE: We have to check load progress here because this function
// is called unconditionally at the end of every frame.
let should_complete = match self.0.read().loaded_stream {
Some(LoaderStream::Swf(_, root)) => root
.as_movie_clip()
.map(|mc| mc.loaded_bytes() >= mc.total_bytes())
.unwrap_or(false),
_ => false,
};
if should_complete {
self.0.write(context.gc_context).complete_event_fired = true;
let complete_evt = EventObject::bare_default_event(context, "complete");
if let Err(e) = Avm2::dispatch_event(context, complete_evt, (*self).into()) {
@ -188,6 +208,7 @@ impl<'gc> LoaderInfoObject<'gc> {
}
}
}
}
/// Unwrap this object's loader stream
pub fn as_loader_stream(&self) -> Option<Ref<LoaderStream<'gc>>> {