avm2: Fix handling of Loader.loadBytes for images
I've switched back to the original code for creating the bitmap/bitmapdata, rather than relying on custom initialization logic that we only used in loader. To make sure that the Bitmap/BitmapData are only exposed to ActionScript at the correct time, I've added a new flag to control when 'LoaderInfo.content' becomes non-null
This commit is contained in:
parent
38d58552f2
commit
bb9e7c04f7
|
@ -211,10 +211,7 @@ pub fn copy_pixels<'gc>(
|
|||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(bitmap_data) = this.as_bitmap_data() {
|
||||
bitmap_data.check_valid(activation)?;
|
||||
let source_bitmap = args
|
||||
.get(0)
|
||||
.unwrap_or(&Value::Undefined)
|
||||
.coerce_to_object(activation)?;
|
||||
let source_bitmap = args.get_object(activation, 0, "sourceBitmapData")?;
|
||||
|
||||
let source_rect = args.get_object(activation, 1, "sourceRect")?;
|
||||
|
||||
|
|
|
@ -146,10 +146,12 @@ pub fn get_content<'gc>(
|
|||
this: Object<'gc>,
|
||||
_args: &[Value<'gc>],
|
||||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
if let Some(loader_stream) = this
|
||||
.as_loader_info_object()
|
||||
.and_then(|o| o.as_loader_stream())
|
||||
{
|
||||
let loader_info = this.as_loader_info_object().unwrap();
|
||||
if !loader_info.expose_content() {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
|
||||
if let Some(loader_stream) = loader_info.as_loader_stream() {
|
||||
match &*loader_stream {
|
||||
LoaderStream::Swf(_, root) | LoaderStream::NotYetLoaded(_, Some(root), _) => {
|
||||
if root.movie().is_action_script_3() || !root.movie().is_movie() {
|
||||
|
|
|
@ -113,6 +113,8 @@ pub struct LoaderInfoObjectData<'gc> {
|
|||
#[collect(require_static)]
|
||||
content_type: ContentType,
|
||||
|
||||
expose_content: bool,
|
||||
|
||||
errored: bool,
|
||||
}
|
||||
|
||||
|
@ -150,6 +152,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
.construct(activation, &[])?,
|
||||
cached_avm1movie: None,
|
||||
content_type: ContentType::Swf,
|
||||
expose_content: false,
|
||||
errored: false,
|
||||
},
|
||||
))
|
||||
|
@ -197,6 +200,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
.construct(activation, &[])?,
|
||||
cached_avm1movie: None,
|
||||
content_type: ContentType::Unknown,
|
||||
expose_content: false,
|
||||
errored: false,
|
||||
},
|
||||
))
|
||||
|
@ -239,12 +243,17 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
self.0.read().errored
|
||||
}
|
||||
|
||||
pub fn init_event_fired(&self) -> bool {
|
||||
self.0.read().init_event_fired
|
||||
}
|
||||
|
||||
pub fn fire_init_and_complete_events(
|
||||
&self,
|
||||
context: &mut UpdateContext<'_, 'gc>,
|
||||
status: u16,
|
||||
redirected: bool,
|
||||
) {
|
||||
self.0.write(context.gc_context).expose_content = true;
|
||||
if !self.0.read().init_event_fired {
|
||||
self.0.write(context.gc_context).init_event_fired = true;
|
||||
|
||||
|
@ -307,6 +316,17 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn expose_content(&self) -> bool {
|
||||
self.0.read().expose_content
|
||||
}
|
||||
|
||||
/// Makes the 'content' visible to ActionScript.
|
||||
/// This is used by certain special loaders (the stage and root movie),
|
||||
/// which expose the loaded content before the 'init' event is fired.
|
||||
pub fn set_expose_content(&self, mc: &Mutation<'gc>) {
|
||||
self.0.write(mc).expose_content = true;
|
||||
}
|
||||
|
||||
pub fn set_loader_stream(&self, stream: LoaderStream<'gc>, mc: &Mutation<'gc>) {
|
||||
self.0.write(mc).loaded_stream = Some(stream);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::avm1::{Object as Avm1Object, Value as Avm1Value};
|
|||
use crate::avm2::api_version::ApiVersion;
|
||||
use crate::avm2::object::LoaderInfoObject;
|
||||
use crate::avm2::Activation as Avm2Activation;
|
||||
use crate::avm2::TObject as _;
|
||||
use crate::avm2::{Avm2, Object as Avm2Object, SoundChannelObject};
|
||||
use crate::backend::{
|
||||
audio::{AudioBackend, AudioManager, SoundHandle, SoundInstanceHandle},
|
||||
|
@ -397,6 +398,10 @@ impl<'a, 'gc> UpdateContext<'a, 'gc> {
|
|||
let stage_loader_info =
|
||||
LoaderInfoObject::not_yet_loaded(&mut activation, swf, None, Some(root), true)
|
||||
.expect("Failed to construct Stage LoaderInfo");
|
||||
stage_loader_info
|
||||
.as_loader_info_object()
|
||||
.unwrap()
|
||||
.set_expose_content(activation.context.gc_context);
|
||||
activation
|
||||
.context
|
||||
.stage
|
||||
|
|
|
@ -358,14 +358,6 @@ impl<'gc> TDisplayObject<'gc> for Bitmap<'gc> {
|
|||
)
|
||||
.expect("can't throw from post_instantiation -_-");
|
||||
|
||||
if bitmap_data_obj.as_bitmap_data().unwrap().disposed() {
|
||||
// Set the real bitmapdata, in case this Bitmap was constructed from a Loader
|
||||
// (it will have real data that doesn't come from a linked class)
|
||||
bitmap_data_obj.init_bitmap_data(
|
||||
activation.context.gc_context,
|
||||
self.bitmap_data_wrapper(),
|
||||
);
|
||||
}
|
||||
self.set_bitmap_data(
|
||||
&mut activation.context,
|
||||
bitmap_data_obj.as_bitmap_data().unwrap(),
|
||||
|
|
|
@ -335,10 +335,9 @@ impl<'gc> MovieClip<'gc> {
|
|||
let loader_info =
|
||||
LoaderInfoObject::not_yet_loaded(activation, movie.clone(), None, None, false)
|
||||
.expect("Failed to construct LoaderInfoObject");
|
||||
loader_info
|
||||
.as_loader_info_object()
|
||||
.unwrap()
|
||||
.set_content_type(ContentType::Swf, activation.context.gc_context);
|
||||
let loader_info_obj = loader_info.as_loader_info_object().unwrap();
|
||||
loader_info_obj.set_expose_content(activation.context.gc_context);
|
||||
loader_info_obj.set_content_type(ContentType::Swf, activation.context.gc_context);
|
||||
Some(loader_info)
|
||||
} else {
|
||||
None
|
||||
|
@ -387,17 +386,18 @@ impl<'gc> MovieClip<'gc> {
|
|||
));
|
||||
|
||||
if movie.is_action_script_3() {
|
||||
mc.0.read()
|
||||
let mc_data = mc.0.read();
|
||||
let loader_info = mc_data
|
||||
.static_data
|
||||
.loader_info
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.as_loader_info_object()
|
||||
.unwrap()
|
||||
.set_loader_stream(
|
||||
LoaderStream::Swf(movie, mc.into()),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
.unwrap();
|
||||
loader_info.set_loader_stream(
|
||||
LoaderStream::Swf(movie, mc.into()),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
}
|
||||
mc.set_is_root(activation.context.gc_context, true);
|
||||
mc
|
||||
|
|
|
@ -10,8 +10,8 @@ use crate::avm2::object::{
|
|||
TObject as _,
|
||||
};
|
||||
use crate::avm2::{
|
||||
Activation as Avm2Activation, Avm2, Domain as Avm2Domain, Object as Avm2Object,
|
||||
Value as Avm2Value,
|
||||
Activation as Avm2Activation, Avm2, BitmapDataObject, Domain as Avm2Domain,
|
||||
Object as Avm2Object, Value as Avm2Value,
|
||||
};
|
||||
use crate::backend::navigator::{OwnedFuture, Request};
|
||||
use crate::backend::ui::DialogResultFuture;
|
||||
|
@ -19,7 +19,7 @@ use crate::bitmap::bitmap_data::Color;
|
|||
use crate::bitmap::bitmap_data::{BitmapData, BitmapDataWrapper};
|
||||
use crate::context::{ActionQueue, ActionType, UpdateContext};
|
||||
use crate::display_object::{
|
||||
Bitmap, DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer, TInteractiveObject,
|
||||
DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer, TInteractiveObject,
|
||||
};
|
||||
use crate::events::ClipEvent;
|
||||
use crate::frame_lifecycle::catchup_display_object_to_frame;
|
||||
|
@ -1863,22 +1863,29 @@ impl<'gc> Loader<'gc> {
|
|||
let bitmap = ruffle_render::utils::decode_define_bits_jpeg(data, None)?;
|
||||
|
||||
let transparency = true;
|
||||
let bitmap_data = BitmapDataWrapper::new(GcCell::new(
|
||||
activation.context.gc_context,
|
||||
BitmapData::new_with_pixels(
|
||||
bitmap.width(),
|
||||
bitmap.height(),
|
||||
transparency,
|
||||
bitmap.as_colors().map(Color::from).collect(),
|
||||
),
|
||||
));
|
||||
let bitmap_dobj = Bitmap::new_with_bitmap_data(
|
||||
activation.context.gc_context,
|
||||
0,
|
||||
bitmap_data,
|
||||
false,
|
||||
&activation.caller_movie_or_root(),
|
||||
let bitmap_data = BitmapData::new_with_pixels(
|
||||
bitmap.width(),
|
||||
bitmap.height(),
|
||||
transparency,
|
||||
bitmap.as_colors().map(Color::from).collect(),
|
||||
);
|
||||
let bitmapdata_wrapper =
|
||||
BitmapDataWrapper::new(GcCell::new(activation.context.gc_context, bitmap_data));
|
||||
let bitmapdata_class = activation.context.avm2.classes().bitmapdata;
|
||||
let bitmapdata_avm2 = BitmapDataObject::from_bitmap_data_internal(
|
||||
&mut activation,
|
||||
bitmapdata_wrapper,
|
||||
bitmapdata_class,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let bitmap_avm2 = activation
|
||||
.avm2()
|
||||
.classes()
|
||||
.bitmap
|
||||
.construct(&mut activation, &[bitmapdata_avm2.into()])
|
||||
.unwrap();
|
||||
let bitmap_dobj = bitmap_avm2.as_display_object().unwrap();
|
||||
|
||||
if let MovieLoaderVMData::Avm2 { loader_info, .. } = vm_data {
|
||||
let fake_movie = Arc::new(SwfMovie::fake_with_compressed_len(
|
||||
|
@ -1890,7 +1897,7 @@ impl<'gc> Loader<'gc> {
|
|||
.as_loader_info_object()
|
||||
.unwrap()
|
||||
.set_loader_stream(
|
||||
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj.into()), false),
|
||||
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj), false),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
}
|
||||
|
@ -1902,14 +1909,12 @@ impl<'gc> Loader<'gc> {
|
|||
activation.context.swf.version(),
|
||||
data.to_vec(),
|
||||
));
|
||||
let loader_info_obj = loader_info.as_loader_info_object().unwrap();
|
||||
|
||||
loader_info
|
||||
.as_loader_info_object()
|
||||
.unwrap()
|
||||
.set_loader_stream(
|
||||
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj.into()), false),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
loader_info_obj.set_loader_stream(
|
||||
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj), false),
|
||||
activation.context.gc_context,
|
||||
);
|
||||
}
|
||||
|
||||
if from_bytes {
|
||||
|
@ -1918,7 +1923,6 @@ impl<'gc> Loader<'gc> {
|
|||
callback: Box::new(move |uc, bitmap_obj| {
|
||||
uc.post_frame_callbacks.push(PostFrameCallback {
|
||||
callback: Box::new(move |uc, bitmap_obj| {
|
||||
bitmap_obj.post_instantiation(uc, None, Instantiator::Movie, true);
|
||||
if let Err(e) = Loader::movie_loader_complete(
|
||||
handle,
|
||||
uc,
|
||||
|
@ -1932,19 +1936,13 @@ impl<'gc> Loader<'gc> {
|
|||
data: bitmap_obj,
|
||||
})
|
||||
}),
|
||||
data: bitmap_dobj.into(),
|
||||
data: bitmap_dobj,
|
||||
});
|
||||
} else {
|
||||
bitmap_dobj.post_instantiation(
|
||||
&mut activation.context,
|
||||
None,
|
||||
Instantiator::Movie,
|
||||
true,
|
||||
);
|
||||
Loader::movie_loader_complete(
|
||||
handle,
|
||||
&mut activation.context,
|
||||
Some(bitmap_dobj.into()),
|
||||
Some(bitmap_dobj),
|
||||
status,
|
||||
redirected,
|
||||
)?;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
import flash.events.HTTPStatusEvent;
|
||||
import flash.display.MovieClip;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.display.Bitmap;
|
||||
|
||||
public class Main extends MovieClip {
|
||||
|
||||
|
@ -92,6 +93,8 @@
|
|||
|
||||
loader.contentLoaderInfo.addEventListener(Event.INIT, function(e) {
|
||||
dump(e);
|
||||
trace("Init: loader.content = " + loader.content);
|
||||
trace("Init: loader.content.bitmapData = " + Bitmap(loader.content).bitmapData);
|
||||
});
|
||||
|
||||
loader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, function(e) {
|
||||
|
|
|
@ -18,6 +18,8 @@ Called super() in Main()
|
|||
exitFrame in Test
|
||||
exitFrame in Test
|
||||
Event [Event type="init" bubbles=false cancelable=false eventPhase=2]: loader.numChildren = 1, loader.content = [object Bitmap], loader.contentLoaderInfo.bytesLoaded = 28417, loader.contentLoaderInfo.bytesTotal = 28417, loader.contentLoaderInfo.url = file:///
|
||||
Init: loader.content = [object Bitmap]
|
||||
Init: loader.content.bitmapData = [object BitmapData]
|
||||
Event [Event type="complete" bubbles=false cancelable=false eventPhase=2]: loader.numChildren = 1, loader.content = [object Bitmap], loader.contentLoaderInfo.bytesLoaded = 28417, loader.contentLoaderInfo.bytesTotal = 28417, loader.contentLoaderInfo.url = file:///
|
||||
exitFrame in Test
|
||||
exitFrame in Test
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue