core: Add a special loader state for "downloaded but still parsing", and a function that ticks the preload.
Currently we do this automatically with no execution limit.
This commit is contained in:
parent
70e638b21f
commit
940de4bb7e
|
@ -235,6 +235,7 @@ impl<'gc> LoadManager<'gc> {
|
||||||
target_clip,
|
target_clip,
|
||||||
event_handler,
|
event_handler,
|
||||||
loader_status: LoaderStatus::Pending,
|
loader_status: LoaderStatus::Pending,
|
||||||
|
movie: None,
|
||||||
};
|
};
|
||||||
let handle = self.add_loader(loader);
|
let handle = self.add_loader(loader);
|
||||||
let loader = self.get_loader_mut(handle).unwrap();
|
let loader = self.get_loader_mut(handle).unwrap();
|
||||||
|
@ -364,6 +365,8 @@ impl<'gc> Default for LoadManager<'gc> {
|
||||||
pub enum LoaderStatus {
|
pub enum LoaderStatus {
|
||||||
/// The movie hasn't been loaded yet.
|
/// The movie hasn't been loaded yet.
|
||||||
Pending,
|
Pending,
|
||||||
|
/// The movie is currently being parsed (e.g. mc.preload)
|
||||||
|
Parsing,
|
||||||
/// The movie loaded successfully.
|
/// The movie loaded successfully.
|
||||||
Succeeded,
|
Succeeded,
|
||||||
/// An error occurred while loading the movie.
|
/// An error occurred while loading the movie.
|
||||||
|
@ -410,6 +413,13 @@ pub enum Loader<'gc> {
|
||||||
/// or an error has occurred (in which case we don't care about the
|
/// or an error has occurred (in which case we don't care about the
|
||||||
/// loader anymore).
|
/// loader anymore).
|
||||||
loader_status: LoaderStatus,
|
loader_status: LoaderStatus,
|
||||||
|
|
||||||
|
/// The SWF being loaded.
|
||||||
|
///
|
||||||
|
/// This is only available if the asynchronous loader path has
|
||||||
|
/// completed and we expect the Player to periodically tick preload
|
||||||
|
/// until loading completes.
|
||||||
|
movie: Option<Arc<SwfMovie>>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Loader that is loading form data into an AVM1 object scope.
|
/// Loader that is loading form data into an AVM1 object scope.
|
||||||
|
@ -465,6 +475,94 @@ pub enum Loader<'gc> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gc> Loader<'gc> {
|
impl<'gc> Loader<'gc> {
|
||||||
|
/// Process tags on a loaded movie.
|
||||||
|
///
|
||||||
|
/// Is only callable on Movie loaders, panics otherwise. Will
|
||||||
|
/// do nothing unless the movie is ready to be preloaded. Movies which
|
||||||
|
/// complete their preload will fire all events and be removed from the
|
||||||
|
/// load manager queue.
|
||||||
|
///
|
||||||
|
/// Returns any AVM errors encountered while sending events to user code.
|
||||||
|
fn preload_tick(
|
||||||
|
handle: Handle,
|
||||||
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
|
limit: &mut ExecutionLimit,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let (mc, event_handler, movie) = match context.load_manager.get_loader_mut(handle) {
|
||||||
|
Some(Self::Movie {
|
||||||
|
target_clip,
|
||||||
|
event_handler,
|
||||||
|
movie,
|
||||||
|
loader_status,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
if movie.is_none() {
|
||||||
|
//Non-SWF load or file not loaded yet
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
*loader_status = LoaderStatus::Parsing;
|
||||||
|
|
||||||
|
(*target_clip, *event_handler, movie.clone().unwrap())
|
||||||
|
}
|
||||||
|
None => return Err(Error::Cancelled),
|
||||||
|
Some(_) => panic!("Attempted to preload a non-SWF loader"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let did_finish = mc
|
||||||
|
.as_movie_clip()
|
||||||
|
.map(|mc| mc.preload(context, limit))
|
||||||
|
.unwrap_or(false);
|
||||||
|
if did_finish {
|
||||||
|
let length = movie.compressed_len();
|
||||||
|
Loader::movie_loader_progress(handle, context, length, length)?;
|
||||||
|
|
||||||
|
mc.post_instantiation(context, None, Instantiator::Movie, false);
|
||||||
|
catchup_display_object_to_frame(context, mc);
|
||||||
|
|
||||||
|
let loader_info =
|
||||||
|
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = event_handler {
|
||||||
|
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
|
||||||
|
// 'bytesTotal' starts returning the correct value
|
||||||
|
// (we previously had a fake empty SwfMovie).
|
||||||
|
// However, we still use `LoaderStream::NotYetLoaded`, since
|
||||||
|
// the actual MovieClip display object has not run its first
|
||||||
|
// frame yet.
|
||||||
|
loader_info
|
||||||
|
.set_loader_stream(LoaderStream::NotYetLoaded(movie), context.gc_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) = event_handler {
|
||||||
|
let mut activation = Avm2Activation::from_nothing(context.reborrow());
|
||||||
|
let mut loader = loader_info
|
||||||
|
.get_property(&Avm2Multiname::public("loader"), &mut activation)
|
||||||
|
.map_err(|e| Error::Avm2Error(e.to_string()))?
|
||||||
|
.as_object()
|
||||||
|
.unwrap()
|
||||||
|
.as_display_object()
|
||||||
|
.unwrap()
|
||||||
|
.as_container()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Note that we do *not* use the 'addChild' method here:
|
||||||
|
// Per the flash docs, our implementation always throws
|
||||||
|
// an 'unsupported' error. Also, the AVM2 side of our movie
|
||||||
|
// clip does not yet exist.
|
||||||
|
loader.insert_at_index(&mut activation.context, mc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader::movie_loader_complete(handle, context)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a future for the root movie loader.
|
/// Construct a future for the root movie loader.
|
||||||
fn root_movie_loader(
|
fn root_movie_loader(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -584,7 +682,6 @@ impl<'gc> Loader<'gc> {
|
||||||
// This only seems to happen for an AVM2 event handler
|
// This only seems to happen for an AVM2 event handler
|
||||||
Loader::movie_loader_progress(handle, uc, 0, length)?;
|
Loader::movie_loader_progress(handle, uc, 0, length)?;
|
||||||
}
|
}
|
||||||
Loader::movie_loader_progress(handle, uc, length, length)?;
|
|
||||||
|
|
||||||
match sniffed_type {
|
match sniffed_type {
|
||||||
ContentType::Swf => {
|
ContentType::Swf => {
|
||||||
|
@ -594,6 +691,13 @@ impl<'gc> Loader<'gc> {
|
||||||
loader_url,
|
loader_url,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
|
match uc.load_manager.get_loader_mut(handle) {
|
||||||
|
Some(Loader::Movie { movie: old, .. }) => {
|
||||||
|
*old = Some(movie.clone())
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
let mut activation = Avm2Activation::from_nothing(uc.reborrow());
|
let mut activation = Avm2Activation::from_nothing(uc.reborrow());
|
||||||
let parent_domain = activation.avm2().global_domain();
|
let parent_domain = activation.avm2().global_domain();
|
||||||
let domain =
|
let domain =
|
||||||
|
@ -619,61 +723,16 @@ impl<'gc> Loader<'gc> {
|
||||||
|
|
||||||
mc.replace_with_movie(
|
mc.replace_with_movie(
|
||||||
&mut activation.context,
|
&mut activation.context,
|
||||||
Some(movie.clone()),
|
Some(movie),
|
||||||
loader_info,
|
loader_info,
|
||||||
);
|
);
|
||||||
// FIXME - do we need to call 'set_place_frame'
|
|
||||||
mc.preload(
|
|
||||||
&mut activation.context,
|
|
||||||
&mut ExecutionLimit::none(),
|
|
||||||
);
|
|
||||||
mc.post_instantiation(
|
|
||||||
&mut activation.context,
|
|
||||||
None,
|
|
||||||
Instantiator::Movie,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
catchup_display_object_to_frame(
|
|
||||||
&mut activation.context,
|
|
||||||
mc.into(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(loader_info) = loader_info {
|
|
||||||
// Store the real movie into the `LoaderStream`, so that
|
|
||||||
// 'bytesTotal' starts returning the correct value
|
|
||||||
// (we previously had a fake empty SwfMovie).
|
|
||||||
// However, we still use `LoaderStream::NotYetLoaded`, since
|
|
||||||
// the actual MovieClip display object has not run its first
|
|
||||||
// frame yet.
|
|
||||||
loader_info.set_loader_stream(
|
|
||||||
LoaderStream::NotYetLoaded(movie),
|
|
||||||
activation.context.gc_context,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) =
|
return Loader::preload_tick(
|
||||||
event_handler
|
handle,
|
||||||
{
|
uc,
|
||||||
let mut loader = loader_info
|
&mut ExecutionLimit::none(),
|
||||||
.get_property(
|
);
|
||||||
&Avm2Multiname::public("loader"),
|
|
||||||
&mut activation,
|
|
||||||
)
|
|
||||||
.map_err(|e| Error::Avm2Error(e.to_string()))?
|
|
||||||
.as_object()
|
|
||||||
.unwrap()
|
|
||||||
.as_display_object()
|
|
||||||
.unwrap()
|
|
||||||
.as_container()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Note that we do *not* use the 'addChild' method here:
|
|
||||||
// Per the flash docs, our implementation always throws
|
|
||||||
// an 'unsupported' error. Also, the AVM2 side of our movie
|
|
||||||
// clip does not yet exist.
|
|
||||||
loader.insert_at_index(&mut activation.context, clip, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ContentType::Gif | ContentType::Jpeg | ContentType::Png => {
|
ContentType::Gif | ContentType::Jpeg | ContentType::Png => {
|
||||||
let bitmap = uc.renderer.register_bitmap_jpeg_2(&response.body)?;
|
let bitmap = uc.renderer.register_bitmap_jpeg_2(&response.body)?;
|
||||||
|
@ -687,6 +746,7 @@ impl<'gc> Loader<'gc> {
|
||||||
ContentType::Unknown => {}
|
ContentType::Unknown => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader::movie_loader_progress(handle, uc, length, length)?;
|
||||||
Loader::movie_loader_complete(handle, uc)?;
|
Loader::movie_loader_complete(handle, uc)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1383,6 +1443,7 @@ impl<'gc> Loader<'gc> {
|
||||||
|
|
||||||
match loader_status {
|
match loader_status {
|
||||||
LoaderStatus::Pending => false,
|
LoaderStatus::Pending => false,
|
||||||
|
LoaderStatus::Parsing => false,
|
||||||
LoaderStatus::Failed => true,
|
LoaderStatus::Failed => true,
|
||||||
LoaderStatus::Succeeded => {
|
LoaderStatus::Succeeded => {
|
||||||
// AVM2 is handled separately
|
// AVM2 is handled separately
|
||||||
|
|
Loading…
Reference in New Issue