core: Refactor `movie_loader` and its `loadBytes` variant to call into the same code.

This commit is contained in:
David Wendt 2022-09-08 22:17:01 -04:00 committed by kmeisthax
parent 86ecf6076e
commit 8f5afe09a1
1 changed files with 122 additions and 216 deletions

View File

@ -708,120 +708,22 @@ impl<'gc> Loader<'gc> {
})?;
match fetch.await {
Ok(response) => {
let sniffed_type = ContentType::sniff(&response.body);
let mut length = response.body.len();
if replacing_root_movie {
sniffed_type.expect(ContentType::Swf)?;
Ok(response) if replacing_root_movie => {
ContentType::sniff(&response.body).expect(ContentType::Swf)?;
let movie =
SwfMovie::from_data(&response.body, Some(response.url), loader_url)?;
player.lock().unwrap().set_root_movie(movie);
return Ok(());
}
player.lock().unwrap().update(|uc| {
let (clip, event_handler) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie {
target_clip,
event_handler,
..
}) => (*target_clip, *event_handler),
None => return Err(Error::Cancelled),
_ => unreachable!(),
};
if let ContentType::Unknown = sniffed_type {
length = 0;
}
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(_)) = event_handler {
// Flash always fires an initial 'progress' event with
// bytesLoaded=0 and bytesTotal set to the proper value.
// This only seems to happen for an AVM2 event handler
Loader::movie_loader_progress(handle, uc, 0, length)?;
}
match sniffed_type {
ContentType::Swf => {
let movie = Arc::new(SwfMovie::from_data(
Ok(response) => {
Loader::movie_loader_data(
handle,
player,
&response.body,
Some(response.url),
loader_url,
)?);
match uc.load_manager.get_loader_mut(handle) {
Some(Loader::Movie {
movie: old,
loader_status,
..
}) => {
*loader_status = LoaderStatus::Parsing;
*old = Some(movie.clone())
}
_ => unreachable!(),
};
let mut activation = Avm2Activation::from_nothing(uc.reborrow());
let parent_domain = activation.avm2().global_domain();
let domain =
Avm2Domain::movie_domain(&mut activation, parent_domain);
activation
.context
.library
.library_for_movie_mut(movie.clone())
.set_avm2_domain(domain);
if let Some(mut mc) = clip.as_movie_clip() {
let loader_info = if let Some(
MovieLoaderEventHandler::Avm2LoaderInfo(loader_info),
) = event_handler
{
Some(*loader_info.as_loader_info_object().unwrap())
} else {
None
};
// Store our downloaded `SwfMovie` into our target `MovieClip`,
// and initialize it.
mc.replace_with_movie(
&mut activation.context,
Some(movie),
loader_info,
);
}
// NOTE: Certain tests specifically expect small files to preload immediately
Loader::preload_tick(
handle,
uc,
&mut ExecutionLimit::with_max_actions_and_time(
10000,
Duration::from_millis(1),
),
)?;
return Ok(());
}
ContentType::Gif | ContentType::Jpeg | ContentType::Png => {
let bitmap = uc.renderer.register_bitmap_jpeg_2(&response.body)?;
let bitmap_obj =
Bitmap::new(uc, 0, bitmap.handle, bitmap.width, bitmap.height);
if let Some(mc) = clip.as_movie_clip() {
mc.replace_at_depth(uc, bitmap_obj.into(), 1);
}
}
ContentType::Unknown => {}
}
Loader::movie_loader_progress(handle, uc, length, length)?;
Loader::movie_loader_complete(handle, uc)?;
Ok(())
})?; //TODO: content sniffing errors need to be reported somehow
}
Err(e) => {
log::error!("Error during movie loading: {:?}", e);
@ -870,115 +772,15 @@ impl<'gc> Loader<'gc> {
Ok(())
})?;
let sniffed_type = ContentType::sniff(&bytes);
let mut length = bytes.len();
if replacing_root_movie {
sniffed_type.expect(ContentType::Swf)?;
ContentType::sniff(&bytes).expect(ContentType::Swf)?;
let movie = SwfMovie::from_data(&bytes, None, None)?;
let movie = SwfMovie::from_data(&bytes, Some("file:///".into()), None)?;
player.lock().unwrap().set_root_movie(movie);
return Ok(());
}
player.lock().unwrap().update(|uc| {
let (clip, event_handler) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie {
target_clip,
event_handler,
..
}) => (*target_clip, *event_handler),
None => return Err(Error::Cancelled),
_ => unreachable!(),
};
if let ContentType::Unknown = sniffed_type {
length = 0;
}
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(_)) = event_handler {
// Flash always fires an initial 'progress' event with
// bytesLoaded=0 and bytesTotal set to the proper value.
// This only seems to happen for an AVM2 event handler
Loader::movie_loader_progress(handle, uc, 0, length)?;
}
match sniffed_type {
ContentType::Swf => {
let movie = Arc::new(SwfMovie::from_data(&bytes, None, None)?);
match uc.load_manager.get_loader_mut(handle) {
Some(Loader::Movie {
movie: old,
loader_status,
..
}) => {
*loader_status = LoaderStatus::Parsing;
*old = Some(movie.clone())
}
_ => unreachable!(),
};
let mut activation = Avm2Activation::from_nothing(uc.reborrow());
let parent_domain = activation.avm2().global_domain();
let domain = Avm2Domain::movie_domain(&mut activation, parent_domain);
activation
.context
.library
.library_for_movie_mut(movie.clone())
.set_avm2_domain(domain);
if let Some(mut mc) = clip.as_movie_clip() {
let loader_info =
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) =
event_handler
{
Some(*loader_info.as_loader_info_object().unwrap())
} else {
None
};
// Store our downloaded `SwfMovie` into our target `MovieClip`,
// and initialize it.
mc.replace_with_movie(
&mut activation.context,
Some(movie),
loader_info,
);
}
// NOTE: Certain tests specifically expect small files to preload immediately
Loader::preload_tick(
handle,
uc,
&mut ExecutionLimit::with_max_actions_and_time(
10000,
Duration::from_millis(1),
),
)?;
return Ok(());
}
ContentType::Gif | ContentType::Jpeg | ContentType::Png => {
let bitmap = uc.renderer.register_bitmap_jpeg_2(&bytes)?;
let bitmap_obj =
Bitmap::new(uc, 0, bitmap.handle, bitmap.width, bitmap.height);
if let Some(mc) = clip.as_movie_clip() {
mc.replace_at_depth(uc, bitmap_obj.into(), 1);
}
}
ContentType::Unknown => {}
}
Loader::movie_loader_progress(handle, uc, length, length)?;
Loader::movie_loader_complete(handle, uc)?;
Ok(())
})?; //TODO: content sniffing errors need to be reported somehow
Ok(())
Loader::movie_loader_data(handle, player, &bytes, Some("file:///".into()), None)
})
}
@ -1455,6 +1257,110 @@ impl<'gc> Loader<'gc> {
Ok(())
}
/// Load data into a movie loader.
fn movie_loader_data(
handle: Handle,
player: Arc<Mutex<Player>>,
data: &[u8],
url: Option<String>,
loader_url: Option<String>,
) -> Result<(), Error> {
let sniffed_type = ContentType::sniff(data);
let mut length = data.len();
player.lock().unwrap().update(|uc| {
let (clip, event_handler) = match uc.load_manager.get_loader(handle) {
Some(Loader::Movie {
target_clip,
event_handler,
..
}) => (*target_clip, *event_handler),
None => return Err(Error::Cancelled),
_ => unreachable!(),
};
if let ContentType::Unknown = sniffed_type {
length = 0;
}
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(_)) = event_handler {
// Flash always fires an initial 'progress' event with
// bytesLoaded=0 and bytesTotal set to the proper value.
// This only seems to happen for an AVM2 event handler
Loader::movie_loader_progress(handle, uc, 0, length)?;
}
match sniffed_type {
ContentType::Swf => {
let movie = Arc::new(SwfMovie::from_data(data, url, loader_url)?);
match uc.load_manager.get_loader_mut(handle) {
Some(Loader::Movie {
movie: old,
loader_status,
..
}) => {
*loader_status = LoaderStatus::Parsing;
*old = Some(movie.clone())
}
_ => unreachable!(),
};
let mut activation = Avm2Activation::from_nothing(uc.reborrow());
let parent_domain = activation.avm2().global_domain();
let domain = Avm2Domain::movie_domain(&mut activation, parent_domain);
activation
.context
.library
.library_for_movie_mut(movie.clone())
.set_avm2_domain(domain);
if let Some(mut mc) = clip.as_movie_clip() {
let loader_info =
if let Some(MovieLoaderEventHandler::Avm2LoaderInfo(loader_info)) =
event_handler
{
Some(*loader_info.as_loader_info_object().unwrap())
} else {
None
};
// Store our downloaded `SwfMovie` into our target `MovieClip`,
// and initialize it.
mc.replace_with_movie(&mut activation.context, Some(movie), loader_info);
}
// NOTE: Certain tests specifically expect small files to preload immediately
Loader::preload_tick(
handle,
uc,
&mut ExecutionLimit::with_max_actions_and_time(
10000,
Duration::from_millis(1),
),
)?;
return Ok(());
}
ContentType::Gif | ContentType::Jpeg | ContentType::Png => {
let bitmap = uc.renderer.register_bitmap_jpeg_2(&data)?;
let bitmap_obj = Bitmap::new(uc, 0, bitmap.handle, bitmap.width, bitmap.height);
if let Some(mc) = clip.as_movie_clip() {
mc.replace_at_depth(uc, bitmap_obj.into(), 1);
}
}
ContentType::Unknown => {}
}
Loader::movie_loader_progress(handle, uc, length, length)?;
Loader::movie_loader_complete(handle, uc)?;
Ok(())
}) //TODO: content sniffing errors need to be reported somehow
}
/// Report a movie loader progress event to script code.
///
/// The current and total length are always reported as compressed lengths.