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>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(bitmap_data) = this.as_bitmap_data() {
|
if let Some(bitmap_data) = this.as_bitmap_data() {
|
||||||
bitmap_data.check_valid(activation)?;
|
bitmap_data.check_valid(activation)?;
|
||||||
let source_bitmap = args
|
let source_bitmap = args.get_object(activation, 0, "sourceBitmapData")?;
|
||||||
.get(0)
|
|
||||||
.unwrap_or(&Value::Undefined)
|
|
||||||
.coerce_to_object(activation)?;
|
|
||||||
|
|
||||||
let source_rect = args.get_object(activation, 1, "sourceRect")?;
|
let source_rect = args.get_object(activation, 1, "sourceRect")?;
|
||||||
|
|
||||||
|
|
|
@ -146,10 +146,12 @@ pub fn get_content<'gc>(
|
||||||
this: Object<'gc>,
|
this: Object<'gc>,
|
||||||
_args: &[Value<'gc>],
|
_args: &[Value<'gc>],
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
if let Some(loader_stream) = this
|
let loader_info = this.as_loader_info_object().unwrap();
|
||||||
.as_loader_info_object()
|
if !loader_info.expose_content() {
|
||||||
.and_then(|o| o.as_loader_stream())
|
return Ok(Value::Null);
|
||||||
{
|
}
|
||||||
|
|
||||||
|
if let Some(loader_stream) = loader_info.as_loader_stream() {
|
||||||
match &*loader_stream {
|
match &*loader_stream {
|
||||||
LoaderStream::Swf(_, root) | LoaderStream::NotYetLoaded(_, Some(root), _) => {
|
LoaderStream::Swf(_, root) | LoaderStream::NotYetLoaded(_, Some(root), _) => {
|
||||||
if root.movie().is_action_script_3() || !root.movie().is_movie() {
|
if root.movie().is_action_script_3() || !root.movie().is_movie() {
|
||||||
|
|
|
@ -113,6 +113,8 @@ pub struct LoaderInfoObjectData<'gc> {
|
||||||
#[collect(require_static)]
|
#[collect(require_static)]
|
||||||
content_type: ContentType,
|
content_type: ContentType,
|
||||||
|
|
||||||
|
expose_content: bool,
|
||||||
|
|
||||||
errored: bool,
|
errored: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +152,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
||||||
.construct(activation, &[])?,
|
.construct(activation, &[])?,
|
||||||
cached_avm1movie: None,
|
cached_avm1movie: None,
|
||||||
content_type: ContentType::Swf,
|
content_type: ContentType::Swf,
|
||||||
|
expose_content: false,
|
||||||
errored: false,
|
errored: false,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -197,6 +200,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
||||||
.construct(activation, &[])?,
|
.construct(activation, &[])?,
|
||||||
cached_avm1movie: None,
|
cached_avm1movie: None,
|
||||||
content_type: ContentType::Unknown,
|
content_type: ContentType::Unknown,
|
||||||
|
expose_content: false,
|
||||||
errored: false,
|
errored: false,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -239,12 +243,17 @@ impl<'gc> LoaderInfoObject<'gc> {
|
||||||
self.0.read().errored
|
self.0.read().errored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn init_event_fired(&self) -> bool {
|
||||||
|
self.0.read().init_event_fired
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fire_init_and_complete_events(
|
pub fn fire_init_and_complete_events(
|
||||||
&self,
|
&self,
|
||||||
context: &mut UpdateContext<'_, 'gc>,
|
context: &mut UpdateContext<'_, 'gc>,
|
||||||
status: u16,
|
status: u16,
|
||||||
redirected: bool,
|
redirected: bool,
|
||||||
) {
|
) {
|
||||||
|
self.0.write(context.gc_context).expose_content = true;
|
||||||
if !self.0.read().init_event_fired {
|
if !self.0.read().init_event_fired {
|
||||||
self.0.write(context.gc_context).init_event_fired = true;
|
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>) {
|
pub fn set_loader_stream(&self, stream: LoaderStream<'gc>, mc: &Mutation<'gc>) {
|
||||||
self.0.write(mc).loaded_stream = Some(stream);
|
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::api_version::ApiVersion;
|
||||||
use crate::avm2::object::LoaderInfoObject;
|
use crate::avm2::object::LoaderInfoObject;
|
||||||
use crate::avm2::Activation as Avm2Activation;
|
use crate::avm2::Activation as Avm2Activation;
|
||||||
|
use crate::avm2::TObject as _;
|
||||||
use crate::avm2::{Avm2, Object as Avm2Object, SoundChannelObject};
|
use crate::avm2::{Avm2, Object as Avm2Object, SoundChannelObject};
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
audio::{AudioBackend, AudioManager, SoundHandle, SoundInstanceHandle},
|
audio::{AudioBackend, AudioManager, SoundHandle, SoundInstanceHandle},
|
||||||
|
@ -397,6 +398,10 @@ impl<'a, 'gc> UpdateContext<'a, 'gc> {
|
||||||
let stage_loader_info =
|
let stage_loader_info =
|
||||||
LoaderInfoObject::not_yet_loaded(&mut activation, swf, None, Some(root), true)
|
LoaderInfoObject::not_yet_loaded(&mut activation, swf, None, Some(root), true)
|
||||||
.expect("Failed to construct Stage LoaderInfo");
|
.expect("Failed to construct Stage LoaderInfo");
|
||||||
|
stage_loader_info
|
||||||
|
.as_loader_info_object()
|
||||||
|
.unwrap()
|
||||||
|
.set_expose_content(activation.context.gc_context);
|
||||||
activation
|
activation
|
||||||
.context
|
.context
|
||||||
.stage
|
.stage
|
||||||
|
|
|
@ -358,14 +358,6 @@ impl<'gc> TDisplayObject<'gc> for Bitmap<'gc> {
|
||||||
)
|
)
|
||||||
.expect("can't throw from post_instantiation -_-");
|
.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(
|
self.set_bitmap_data(
|
||||||
&mut activation.context,
|
&mut activation.context,
|
||||||
bitmap_data_obj.as_bitmap_data().unwrap(),
|
bitmap_data_obj.as_bitmap_data().unwrap(),
|
||||||
|
|
|
@ -335,10 +335,9 @@ impl<'gc> MovieClip<'gc> {
|
||||||
let loader_info =
|
let loader_info =
|
||||||
LoaderInfoObject::not_yet_loaded(activation, movie.clone(), None, None, false)
|
LoaderInfoObject::not_yet_loaded(activation, movie.clone(), None, None, false)
|
||||||
.expect("Failed to construct LoaderInfoObject");
|
.expect("Failed to construct LoaderInfoObject");
|
||||||
loader_info
|
let loader_info_obj = loader_info.as_loader_info_object().unwrap();
|
||||||
.as_loader_info_object()
|
loader_info_obj.set_expose_content(activation.context.gc_context);
|
||||||
.unwrap()
|
loader_info_obj.set_content_type(ContentType::Swf, activation.context.gc_context);
|
||||||
.set_content_type(ContentType::Swf, activation.context.gc_context);
|
|
||||||
Some(loader_info)
|
Some(loader_info)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -387,17 +386,18 @@ impl<'gc> MovieClip<'gc> {
|
||||||
));
|
));
|
||||||
|
|
||||||
if movie.is_action_script_3() {
|
if movie.is_action_script_3() {
|
||||||
mc.0.read()
|
let mc_data = mc.0.read();
|
||||||
|
let loader_info = mc_data
|
||||||
.static_data
|
.static_data
|
||||||
.loader_info
|
.loader_info
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_loader_info_object()
|
.as_loader_info_object()
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.set_loader_stream(
|
loader_info.set_loader_stream(
|
||||||
LoaderStream::Swf(movie, mc.into()),
|
LoaderStream::Swf(movie, mc.into()),
|
||||||
activation.context.gc_context,
|
activation.context.gc_context,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
mc.set_is_root(activation.context.gc_context, true);
|
mc.set_is_root(activation.context.gc_context, true);
|
||||||
mc
|
mc
|
||||||
|
|
|
@ -10,8 +10,8 @@ use crate::avm2::object::{
|
||||||
TObject as _,
|
TObject as _,
|
||||||
};
|
};
|
||||||
use crate::avm2::{
|
use crate::avm2::{
|
||||||
Activation as Avm2Activation, Avm2, Domain as Avm2Domain, Object as Avm2Object,
|
Activation as Avm2Activation, Avm2, BitmapDataObject, Domain as Avm2Domain,
|
||||||
Value as Avm2Value,
|
Object as Avm2Object, Value as Avm2Value,
|
||||||
};
|
};
|
||||||
use crate::backend::navigator::{OwnedFuture, Request};
|
use crate::backend::navigator::{OwnedFuture, Request};
|
||||||
use crate::backend::ui::DialogResultFuture;
|
use crate::backend::ui::DialogResultFuture;
|
||||||
|
@ -19,7 +19,7 @@ use crate::bitmap::bitmap_data::Color;
|
||||||
use crate::bitmap::bitmap_data::{BitmapData, BitmapDataWrapper};
|
use crate::bitmap::bitmap_data::{BitmapData, BitmapDataWrapper};
|
||||||
use crate::context::{ActionQueue, ActionType, UpdateContext};
|
use crate::context::{ActionQueue, ActionType, UpdateContext};
|
||||||
use crate::display_object::{
|
use crate::display_object::{
|
||||||
Bitmap, DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer, TInteractiveObject,
|
DisplayObject, MovieClip, TDisplayObject, TDisplayObjectContainer, TInteractiveObject,
|
||||||
};
|
};
|
||||||
use crate::events::ClipEvent;
|
use crate::events::ClipEvent;
|
||||||
use crate::frame_lifecycle::catchup_display_object_to_frame;
|
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 bitmap = ruffle_render::utils::decode_define_bits_jpeg(data, None)?;
|
||||||
|
|
||||||
let transparency = true;
|
let transparency = true;
|
||||||
let bitmap_data = BitmapDataWrapper::new(GcCell::new(
|
let bitmap_data = BitmapData::new_with_pixels(
|
||||||
activation.context.gc_context,
|
bitmap.width(),
|
||||||
BitmapData::new_with_pixels(
|
bitmap.height(),
|
||||||
bitmap.width(),
|
transparency,
|
||||||
bitmap.height(),
|
bitmap.as_colors().map(Color::from).collect(),
|
||||||
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 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 {
|
if let MovieLoaderVMData::Avm2 { loader_info, .. } = vm_data {
|
||||||
let fake_movie = Arc::new(SwfMovie::fake_with_compressed_len(
|
let fake_movie = Arc::new(SwfMovie::fake_with_compressed_len(
|
||||||
|
@ -1890,7 +1897,7 @@ impl<'gc> Loader<'gc> {
|
||||||
.as_loader_info_object()
|
.as_loader_info_object()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_loader_stream(
|
.set_loader_stream(
|
||||||
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj.into()), false),
|
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj), false),
|
||||||
activation.context.gc_context,
|
activation.context.gc_context,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1902,14 +1909,12 @@ impl<'gc> Loader<'gc> {
|
||||||
activation.context.swf.version(),
|
activation.context.swf.version(),
|
||||||
data.to_vec(),
|
data.to_vec(),
|
||||||
));
|
));
|
||||||
|
let loader_info_obj = loader_info.as_loader_info_object().unwrap();
|
||||||
|
|
||||||
loader_info
|
loader_info_obj.set_loader_stream(
|
||||||
.as_loader_info_object()
|
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj), false),
|
||||||
.unwrap()
|
activation.context.gc_context,
|
||||||
.set_loader_stream(
|
);
|
||||||
LoaderStream::NotYetLoaded(fake_movie, Some(bitmap_dobj.into()), false),
|
|
||||||
activation.context.gc_context,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if from_bytes {
|
if from_bytes {
|
||||||
|
@ -1918,7 +1923,6 @@ impl<'gc> Loader<'gc> {
|
||||||
callback: Box::new(move |uc, bitmap_obj| {
|
callback: Box::new(move |uc, bitmap_obj| {
|
||||||
uc.post_frame_callbacks.push(PostFrameCallback {
|
uc.post_frame_callbacks.push(PostFrameCallback {
|
||||||
callback: Box::new(move |uc, bitmap_obj| {
|
callback: Box::new(move |uc, bitmap_obj| {
|
||||||
bitmap_obj.post_instantiation(uc, None, Instantiator::Movie, true);
|
|
||||||
if let Err(e) = Loader::movie_loader_complete(
|
if let Err(e) = Loader::movie_loader_complete(
|
||||||
handle,
|
handle,
|
||||||
uc,
|
uc,
|
||||||
|
@ -1932,19 +1936,13 @@ impl<'gc> Loader<'gc> {
|
||||||
data: bitmap_obj,
|
data: bitmap_obj,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
data: bitmap_dobj.into(),
|
data: bitmap_dobj,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
bitmap_dobj.post_instantiation(
|
|
||||||
&mut activation.context,
|
|
||||||
None,
|
|
||||||
Instantiator::Movie,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
Loader::movie_loader_complete(
|
Loader::movie_loader_complete(
|
||||||
handle,
|
handle,
|
||||||
&mut activation.context,
|
&mut activation.context,
|
||||||
Some(bitmap_dobj.into()),
|
Some(bitmap_dobj),
|
||||||
status,
|
status,
|
||||||
redirected,
|
redirected,
|
||||||
)?;
|
)?;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
import flash.events.HTTPStatusEvent;
|
import flash.events.HTTPStatusEvent;
|
||||||
import flash.display.MovieClip;
|
import flash.display.MovieClip;
|
||||||
import flash.utils.ByteArray;
|
import flash.utils.ByteArray;
|
||||||
|
import flash.display.Bitmap;
|
||||||
|
|
||||||
public class Main extends MovieClip {
|
public class Main extends MovieClip {
|
||||||
|
|
||||||
|
@ -92,6 +93,8 @@
|
||||||
|
|
||||||
loader.contentLoaderInfo.addEventListener(Event.INIT, function(e) {
|
loader.contentLoaderInfo.addEventListener(Event.INIT, function(e) {
|
||||||
dump(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) {
|
loader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS, function(e) {
|
||||||
|
|
|
@ -18,6 +18,8 @@ Called super() in Main()
|
||||||
exitFrame in Test
|
exitFrame in Test
|
||||||
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:///
|
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:///
|
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
|
||||||
exitFrame in Test
|
exitFrame in Test
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue