avm2: Use `Gc` instead of `GcCell` in `LoaderInfoObject`
This commit is contained in:
parent
fa759a06a4
commit
49188bd5d7
|
@ -1389,7 +1389,7 @@ impl<'gc> Object<'gc> {
|
|||
Self::XmlListObject(o) => WeakObject::XmlListObject(XmlListObjectWeak(GcCell::downgrade(o.0))),
|
||||
Self::RegExpObject(o) => WeakObject::RegExpObject(RegExpObjectWeak(Gc::downgrade(o.0))),
|
||||
Self::ByteArrayObject(o) => WeakObject::ByteArrayObject(ByteArrayObjectWeak(Gc::downgrade(o.0))),
|
||||
Self::LoaderInfoObject(o) => WeakObject::LoaderInfoObject(LoaderInfoObjectWeak(GcCell::downgrade(o.0))),
|
||||
Self::LoaderInfoObject(o) => WeakObject::LoaderInfoObject(LoaderInfoObjectWeak(Gc::downgrade(o.0))),
|
||||
Self::ClassObject(o) => WeakObject::ClassObject(ClassObjectWeak(Gc::downgrade(o.0))),
|
||||
Self::VectorObject(o) => WeakObject::VectorObject(VectorObjectWeak(Gc::downgrade(o.0))),
|
||||
Self::SoundObject(o) => WeakObject::SoundObject(SoundObjectWeak(Gc::downgrade(o.0))),
|
||||
|
|
|
@ -13,8 +13,12 @@ use crate::display_object::{DisplayObject, TDisplayObject};
|
|||
use crate::loader::ContentType;
|
||||
use crate::tag_utils::SwfMovie;
|
||||
use core::fmt;
|
||||
use gc_arena::{Collect, GcCell, GcWeakCell, Mutation};
|
||||
use std::cell::{Ref, RefMut};
|
||||
use gc_arena::barrier::unlock;
|
||||
use gc_arena::{
|
||||
lock::{Lock, RefLock},
|
||||
Collect, Gc, GcWeak, Mutation,
|
||||
};
|
||||
use std::cell::{Cell, Ref, RefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// ActionScript cannot construct a LoaderInfo. Note that LoaderInfo isn't a final class.
|
||||
|
@ -70,16 +74,16 @@ impl<'gc> LoaderStream<'gc> {
|
|||
/// resource.
|
||||
#[derive(Collect, Clone, Copy)]
|
||||
#[collect(no_drop)]
|
||||
pub struct LoaderInfoObject<'gc>(pub GcCell<'gc, LoaderInfoObjectData<'gc>>);
|
||||
pub struct LoaderInfoObject<'gc>(pub Gc<'gc, LoaderInfoObjectData<'gc>>);
|
||||
|
||||
#[derive(Collect, Clone, Copy, Debug)]
|
||||
#[collect(no_drop)]
|
||||
pub struct LoaderInfoObjectWeak<'gc>(pub GcWeakCell<'gc, LoaderInfoObjectData<'gc>>);
|
||||
pub struct LoaderInfoObjectWeak<'gc>(pub GcWeak<'gc, LoaderInfoObjectData<'gc>>);
|
||||
|
||||
impl fmt::Debug for LoaderInfoObject<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("LoaderInfoObject")
|
||||
.field("ptr", &self.0.as_ptr())
|
||||
.field("ptr", &Gc::as_ptr(self.0))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -88,18 +92,18 @@ impl fmt::Debug for LoaderInfoObject<'_> {
|
|||
#[collect(no_drop)]
|
||||
pub struct LoaderInfoObjectData<'gc> {
|
||||
/// All normal script data.
|
||||
base: ScriptObjectData<'gc>,
|
||||
base: RefLock<ScriptObjectData<'gc>>,
|
||||
|
||||
/// The loaded stream that this gets its info from.
|
||||
loaded_stream: Option<LoaderStream<'gc>>,
|
||||
loaded_stream: RefLock<LoaderStream<'gc>>,
|
||||
|
||||
loader: Option<Object<'gc>>,
|
||||
|
||||
/// Whether or not we've fired our 'init' event
|
||||
init_event_fired: bool,
|
||||
init_event_fired: Cell<bool>,
|
||||
|
||||
/// Whether or not we've fired our 'complete' event
|
||||
complete_event_fired: bool,
|
||||
complete_event_fired: Cell<bool>,
|
||||
|
||||
/// The `EventDispatcher` used for `LoaderInfo.sharedEvents`.
|
||||
// FIXME: If we ever implement sandboxing, then ensure that we allow
|
||||
|
@ -108,14 +112,13 @@ pub struct LoaderInfoObjectData<'gc> {
|
|||
|
||||
uncaught_error_events: Object<'gc>,
|
||||
|
||||
cached_avm1movie: Option<Object<'gc>>,
|
||||
cached_avm1movie: Lock<Option<Object<'gc>>>,
|
||||
|
||||
#[collect(require_static)]
|
||||
content_type: ContentType,
|
||||
content_type: Cell<ContentType>,
|
||||
|
||||
expose_content: bool,
|
||||
expose_content: Cell<bool>,
|
||||
|
||||
errored: bool,
|
||||
errored: Cell<bool>,
|
||||
}
|
||||
|
||||
impl<'gc> LoaderInfoObject<'gc> {
|
||||
|
@ -127,17 +130,17 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
loader: Option<Object<'gc>>,
|
||||
) -> Result<Object<'gc>, Error<'gc>> {
|
||||
let class = activation.avm2().classes().loaderinfo;
|
||||
let base = ScriptObjectData::new(class);
|
||||
let loaded_stream = Some(LoaderStream::Swf(movie, root));
|
||||
let base = ScriptObjectData::new(class).into();
|
||||
let loaded_stream = LoaderStream::Swf(movie, root);
|
||||
|
||||
let this: Object<'gc> = LoaderInfoObject(GcCell::new(
|
||||
let this: Object<'gc> = LoaderInfoObject(Gc::new(
|
||||
activation.context.gc_context,
|
||||
LoaderInfoObjectData {
|
||||
base,
|
||||
loaded_stream,
|
||||
loaded_stream: RefLock::new(loaded_stream),
|
||||
loader,
|
||||
init_event_fired: false,
|
||||
complete_event_fired: false,
|
||||
init_event_fired: Cell::new(false),
|
||||
complete_event_fired: Cell::new(false),
|
||||
shared_events: activation
|
||||
.context
|
||||
.avm2
|
||||
|
@ -150,10 +153,10 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
.classes()
|
||||
.uncaughterrorevents
|
||||
.construct(activation, &[])?,
|
||||
cached_avm1movie: None,
|
||||
content_type: ContentType::Swf,
|
||||
expose_content: false,
|
||||
errored: false,
|
||||
cached_avm1movie: Lock::new(None),
|
||||
content_type: Cell::new(ContentType::Swf),
|
||||
expose_content: Cell::new(false),
|
||||
errored: Cell::new(false),
|
||||
},
|
||||
))
|
||||
.into();
|
||||
|
@ -176,16 +179,16 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
is_stage: bool,
|
||||
) -> Result<Object<'gc>, Error<'gc>> {
|
||||
let class = activation.avm2().classes().loaderinfo;
|
||||
let base = ScriptObjectData::new(class);
|
||||
let base = ScriptObjectData::new(class).into();
|
||||
|
||||
let this: Object<'gc> = LoaderInfoObject(GcCell::new(
|
||||
let this: Object<'gc> = LoaderInfoObject(Gc::new(
|
||||
activation.context.gc_context,
|
||||
LoaderInfoObjectData {
|
||||
base,
|
||||
loaded_stream: Some(LoaderStream::NotYetLoaded(movie, root_clip, is_stage)),
|
||||
loaded_stream: RefLock::new(LoaderStream::NotYetLoaded(movie, root_clip, is_stage)),
|
||||
loader,
|
||||
init_event_fired: false,
|
||||
complete_event_fired: false,
|
||||
init_event_fired: Cell::new(false),
|
||||
complete_event_fired: Cell::new(false),
|
||||
shared_events: activation
|
||||
.context
|
||||
.avm2
|
||||
|
@ -198,10 +201,10 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
.classes()
|
||||
.uncaughterrorevents
|
||||
.construct(activation, &[])?,
|
||||
cached_avm1movie: None,
|
||||
content_type: ContentType::Unknown,
|
||||
expose_content: false,
|
||||
errored: false,
|
||||
cached_avm1movie: Lock::new(None),
|
||||
content_type: Cell::new(ContentType::Unknown),
|
||||
expose_content: Cell::new(false),
|
||||
errored: Cell::new(false),
|
||||
},
|
||||
))
|
||||
.into();
|
||||
|
@ -213,45 +216,43 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
}
|
||||
|
||||
pub fn loader(&self) -> Option<Object<'gc>> {
|
||||
return self.0.read().loader;
|
||||
self.0.loader
|
||||
}
|
||||
|
||||
pub fn shared_events(&self) -> Object<'gc> {
|
||||
return self.0.read().shared_events;
|
||||
self.0.shared_events
|
||||
}
|
||||
|
||||
pub fn uncaught_error_events(&self) -> Object<'gc> {
|
||||
return self.0.read().uncaught_error_events;
|
||||
self.0.uncaught_error_events
|
||||
}
|
||||
|
||||
/// Gets the `ContentType`, 'hiding' it by returning `ContentType::Unknown`
|
||||
/// if we haven't yet fired the 'init' event. The real ContentType first becomes
|
||||
/// visible to ActionScript in the 'init' event.
|
||||
pub fn content_type_hide_before_init(&self) -> ContentType {
|
||||
if self.0.read().init_event_fired {
|
||||
self.0.read().content_type
|
||||
if self.0.init_event_fired.get() {
|
||||
self.0.content_type.get()
|
||||
} else {
|
||||
ContentType::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_errored(&self, val: bool, mc: &Mutation<'gc>) {
|
||||
self.0.write(mc).errored = val;
|
||||
pub fn set_errored(&self, val: bool, _mc: &Mutation<'gc>) {
|
||||
self.0.errored.set(val);
|
||||
}
|
||||
|
||||
pub fn errored(&self) -> bool {
|
||||
self.0.read().errored
|
||||
self.0.errored.get()
|
||||
}
|
||||
|
||||
pub fn init_event_fired(&self) -> bool {
|
||||
self.0.read().init_event_fired
|
||||
self.0.init_event_fired.get()
|
||||
}
|
||||
|
||||
pub fn reset_init_and_complete_events(&self, mc: &Mutation<'gc>) {
|
||||
let mut write = self.0.write(mc);
|
||||
|
||||
write.init_event_fired = false;
|
||||
write.complete_event_fired = false;
|
||||
pub fn reset_init_and_complete_events(&self, _mc: &Mutation<'gc>) {
|
||||
self.0.init_event_fired.set(false);
|
||||
self.0.complete_event_fired.set(false);
|
||||
}
|
||||
|
||||
pub fn fire_init_and_complete_events(
|
||||
|
@ -260,9 +261,9 @@ impl<'gc> LoaderInfoObject<'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;
|
||||
self.0.expose_content.set(true);
|
||||
if !self.0.init_event_fired.get() {
|
||||
self.0.init_event_fired.set(true);
|
||||
|
||||
// TODO - 'init' should be fired earlier during the download.
|
||||
// Right now, we fire it when downloading is fully completed.
|
||||
|
@ -270,11 +271,11 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
Avm2::dispatch_event(context, init_evt, (*self).into());
|
||||
}
|
||||
|
||||
if !self.0.read().complete_event_fired {
|
||||
if !self.0.complete_event_fired.get() {
|
||||
// NOTE: We have to check load progress here because this function
|
||||
// is called unconditionally at the end of every frame.
|
||||
let (should_complete, from_url) = match self.0.read().loaded_stream {
|
||||
Some(LoaderStream::Swf(ref movie, root)) => (
|
||||
let (should_complete, from_url) = match &*self.0.loaded_stream.borrow() {
|
||||
LoaderStream::Swf(ref movie, root) => (
|
||||
root.as_movie_clip()
|
||||
.map(|mc| mc.loaded_bytes() as i32 >= mc.total_bytes())
|
||||
.unwrap_or(true),
|
||||
|
@ -305,7 +306,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
Avm2::dispatch_event(context, http_status_evt, (*self).into());
|
||||
}
|
||||
|
||||
self.0.write(context.gc_context).complete_event_fired = true;
|
||||
self.0.complete_event_fired.set(true);
|
||||
let complete_evt = EventObject::bare_default_event(context, "complete");
|
||||
Avm2::dispatch_event(context, complete_evt, (*self).into());
|
||||
}
|
||||
|
@ -314,32 +315,26 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
|
||||
/// Unwrap this object's loader stream
|
||||
pub fn as_loader_stream(&self) -> Option<Ref<LoaderStream<'gc>>> {
|
||||
if self.0.read().loaded_stream.is_some() {
|
||||
Some(Ref::map(self.0.read(), |v: &LoaderInfoObjectData<'gc>| {
|
||||
v.loaded_stream.as_ref().unwrap()
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Some(self.0.loaded_stream.borrow())
|
||||
}
|
||||
|
||||
pub fn expose_content(&self) -> bool {
|
||||
self.0.read().expose_content
|
||||
self.0.expose_content.get()
|
||||
}
|
||||
|
||||
/// 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_expose_content(&self, _mc: &Mutation<'gc>) {
|
||||
self.0.expose_content.set(true);
|
||||
}
|
||||
|
||||
pub fn set_loader_stream(&self, stream: LoaderStream<'gc>, mc: &Mutation<'gc>) {
|
||||
self.0.write(mc).loaded_stream = Some(stream);
|
||||
*unlock!(Gc::write(mc, self.0), LoaderInfoObjectData, loaded_stream).borrow_mut() = stream;
|
||||
}
|
||||
|
||||
pub fn set_content_type(&self, content_type: ContentType, mc: &Mutation<'gc>) {
|
||||
self.0.write(mc).content_type = content_type;
|
||||
pub fn set_content_type(&self, content_type: ContentType, _mc: &Mutation<'gc>) {
|
||||
self.0.content_type.set(content_type);
|
||||
}
|
||||
|
||||
/// Returns the AVM1Movie corresponding to the loaded movie- if
|
||||
|
@ -349,7 +344,7 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
activation: &mut Activation<'_, 'gc>,
|
||||
obj: DisplayObject<'gc>,
|
||||
) -> Object<'gc> {
|
||||
let cached_avm1movie = self.0.read().cached_avm1movie;
|
||||
let cached_avm1movie = self.0.cached_avm1movie.get();
|
||||
if cached_avm1movie.is_none() {
|
||||
let class_object = activation.avm2().classes().avm1movie;
|
||||
let object = StageObject::for_display_object(activation, obj, class_object)
|
||||
|
@ -359,10 +354,15 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
.call_native_init(object.into(), &[], activation)
|
||||
.expect("Native init should succeed");
|
||||
|
||||
self.0.write(activation.context.gc_context).cached_avm1movie = Some(object.into());
|
||||
unlock!(
|
||||
Gc::write(activation.context.gc_context, self.0),
|
||||
LoaderInfoObjectData,
|
||||
cached_avm1movie
|
||||
)
|
||||
.set(Some(object.into()));
|
||||
}
|
||||
|
||||
return self.0.read().cached_avm1movie.unwrap();
|
||||
self.0.cached_avm1movie.get().unwrap()
|
||||
}
|
||||
|
||||
pub fn unload(&self, activation: &mut Activation<'_, 'gc>) {
|
||||
|
@ -375,7 +375,6 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
|
||||
let loader = self
|
||||
.0
|
||||
.read()
|
||||
.loader
|
||||
.expect("LoaderInfo must have been created by Loader");
|
||||
|
||||
|
@ -391,15 +390,15 @@ impl<'gc> LoaderInfoObject<'gc> {
|
|||
|
||||
impl<'gc> TObject<'gc> for LoaderInfoObject<'gc> {
|
||||
fn base(&self) -> Ref<ScriptObjectData<'gc>> {
|
||||
Ref::map(self.0.read(), |read| &read.base)
|
||||
self.0.base.borrow()
|
||||
}
|
||||
|
||||
fn base_mut(&self, mc: &Mutation<'gc>) -> RefMut<ScriptObjectData<'gc>> {
|
||||
RefMut::map(self.0.write(mc), |write| &mut write.base)
|
||||
unlock!(Gc::write(mc, self.0), LoaderInfoObjectData, base).borrow_mut()
|
||||
}
|
||||
|
||||
fn as_ptr(&self) -> *const ObjectPtr {
|
||||
self.0.as_ptr() as *const ObjectPtr
|
||||
Gc::as_ptr(self.0) as *const ObjectPtr
|
||||
}
|
||||
|
||||
fn value_of(&self, _mc: &Mutation<'gc>) -> Result<Value<'gc>, Error<'gc>> {
|
||||
|
|
Loading…
Reference in New Issue