Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: Replace GcCell with Gc in LoaderDisplay & MorphShape #19710

Merged
merged 2 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/src/display_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2237,7 +2237,7 @@ pub trait TDisplayObject<'gc>:
}
}
if let Some(ratio) = place_object.ratio {
if let Some(mut morph_shape) = self.as_morph_shape() {
if let Some(morph_shape) = self.as_morph_shape() {
morph_shape.set_ratio(context.gc(), ratio);
} else if let Some(video) = self.as_video() {
video.seek(context, ratio.into());
Expand Down
50 changes: 26 additions & 24 deletions core/src/display_object/loader_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,42 +12,43 @@ use crate::display_object::container::ChildContainer;
use crate::display_object::interactive::InteractiveObjectBase;
use crate::tag_utils::SwfMovie;
use core::fmt;
use gc_arena::GcWeakCell;
use gc_arena::{Collect, GcCell, Mutation};
use gc_arena::barrier::unlock;
use gc_arena::lock::{Lock, RefLock};
use gc_arena::{Collect, Gc, GcWeak, Mutation};
use std::cell::{Ref, RefMut};
use std::sync::Arc;

use super::interactive::Avm2MousePick;

#[derive(Clone, Collect, Copy)]
#[collect(no_drop)]
pub struct LoaderDisplay<'gc>(GcCell<'gc, LoaderDisplayData<'gc>>);
pub struct LoaderDisplay<'gc>(Gc<'gc, LoaderDisplayData<'gc>>);

impl fmt::Debug for LoaderDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LoaderDisplay")
.field("ptr", &self.0.as_ptr())
.field("ptr", &Gc::as_ptr(self.0))
.finish()
}
}

#[derive(Clone, Collect)]
#[collect(no_drop)]
pub struct LoaderDisplayData<'gc> {
base: InteractiveObjectBase<'gc>,
container: ChildContainer<'gc>,
avm2_object: Option<Avm2Object<'gc>>,
base: RefLock<InteractiveObjectBase<'gc>>,
container: RefLock<ChildContainer<'gc>>,
avm2_object: Lock<Option<Avm2Object<'gc>>>,
movie: Arc<SwfMovie>,
}

impl<'gc> LoaderDisplay<'gc> {
pub fn empty(activation: &mut Activation<'_, 'gc>, movie: Arc<SwfMovie>) -> Self {
let obj = LoaderDisplay(GcCell::new(
let obj = LoaderDisplay(Gc::new(
activation.gc(),
LoaderDisplayData {
base: Default::default(),
container: ChildContainer::new(movie.clone()),
avm2_object: None,
base: RefLock::new(Default::default()),
container: RefLock::new(ChildContainer::new(movie.clone())),
avm2_object: Lock::new(None),
movie,
},
));
Expand All @@ -58,25 +59,25 @@ impl<'gc> LoaderDisplay<'gc> {
}

pub fn downgrade(self) -> LoaderDisplayWeak<'gc> {
LoaderDisplayWeak(GcCell::downgrade(self.0))
LoaderDisplayWeak(Gc::downgrade(self.0))
}
}

impl<'gc> TDisplayObject<'gc> for LoaderDisplay<'gc> {
fn base(&self) -> Ref<DisplayObjectBase<'gc>> {
Ref::map(self.0.read(), |r| &r.base.base)
Ref::map(self.raw_interactive(), |r| &r.base)
}

fn base_mut<'a>(&'a self, mc: &Mutation<'gc>) -> RefMut<'a, DisplayObjectBase<'gc>> {
RefMut::map(self.0.write(mc), |w| &mut w.base.base)
RefMut::map(self.raw_interactive_mut(mc), |w| &mut w.base)
}

fn instantiate(&self, gc_context: &Mutation<'gc>) -> DisplayObject<'gc> {
Self(GcCell::new(gc_context, self.0.read().clone())).into()
Self(Gc::new(gc_context, self.0.as_ref().clone())).into()
}

fn as_ptr(&self) -> *const DisplayObjectPtr {
self.0.as_ptr() as *const DisplayObjectPtr
Gc::as_ptr(self.0) as *const DisplayObjectPtr
}

fn id(&self) -> CharacterId {
Expand All @@ -93,14 +94,15 @@ impl<'gc> TDisplayObject<'gc> for LoaderDisplay<'gc> {

fn object2(&self) -> Avm2Value<'gc> {
self.0
.read()
.avm2_object
.get()
.map(Avm2Value::from)
.unwrap_or(Avm2Value::Null)
}

fn set_object2(&self, context: &mut UpdateContext<'gc>, to: Avm2Object<'gc>) {
self.0.write(context.gc()).avm2_object = Some(to);
let mc = context.gc();
unlock!(Gc::write(mc, self.0), LoaderDisplayData, avm2_object).set(Some(to))
}

fn as_container(self) -> Option<DisplayObjectContainer<'gc>> {
Expand Down Expand Up @@ -130,7 +132,7 @@ impl<'gc> TDisplayObject<'gc> for LoaderDisplay<'gc> {
}

fn movie(&self) -> Arc<SwfMovie> {
self.0.read().movie.clone()
self.0.movie.clone()
}

fn on_parent_removed(&self, context: &mut UpdateContext<'gc>) {
Expand All @@ -142,11 +144,11 @@ impl<'gc> TDisplayObject<'gc> for LoaderDisplay<'gc> {

impl<'gc> TInteractiveObject<'gc> for LoaderDisplay<'gc> {
fn raw_interactive(&self) -> Ref<InteractiveObjectBase<'gc>> {
Ref::map(self.0.read(), |r| &r.base)
self.0.base.borrow()
}

fn raw_interactive_mut(&self, mc: &Mutation<'gc>) -> RefMut<InteractiveObjectBase<'gc>> {
RefMut::map(self.0.write(mc), |w| &mut w.base)
unlock!(Gc::write(mc, self.0), LoaderDisplayData, base).borrow_mut()
}

fn as_displayobject(self) -> DisplayObject<'gc> {
Expand Down Expand Up @@ -254,17 +256,17 @@ impl<'gc> TInteractiveObject<'gc> for LoaderDisplay<'gc> {

impl<'gc> TDisplayObjectContainer<'gc> for LoaderDisplay<'gc> {
fn raw_container(&self) -> Ref<'_, ChildContainer<'gc>> {
Ref::map(self.0.read(), |this| &this.container)
self.0.container.borrow()
}

fn raw_container_mut(&self, gc_context: &Mutation<'gc>) -> RefMut<'_, ChildContainer<'gc>> {
RefMut::map(self.0.write(gc_context), |this| &mut this.container)
unlock!(Gc::write(gc_context, self.0), LoaderDisplayData, container).borrow_mut()
}
}

#[derive(Clone, Debug, Collect, Copy)]
#[collect(no_drop)]
pub struct LoaderDisplayWeak<'gc>(GcWeakCell<'gc, LoaderDisplayData<'gc>>);
pub struct LoaderDisplayWeak<'gc>(GcWeak<'gc, LoaderDisplayData<'gc>>);

impl<'gc> LoaderDisplayWeak<'gc> {
pub fn upgrade(self, mc: &Mutation<'gc>) -> Option<LoaderDisplay<'gc>> {
Expand Down
66 changes: 34 additions & 32 deletions core/src/display_object/morph_shape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,35 @@ use crate::library::{Library, MovieLibrarySource};
use crate::prelude::*;
use crate::tag_utils::SwfMovie;
use core::fmt;
use gc_arena::{Collect, Gc, GcCell, Mutation};
use gc_arena::barrier::unlock;
use gc_arena::lock::{Lock, RefLock};
use gc_arena::{Collect, Gc, Mutation};
use ruffle_render::backend::ShapeHandle;
use ruffle_render::commands::CommandHandler;
use std::cell::{Ref, RefCell, RefMut};
use std::cell::{Cell, Ref, RefCell, RefMut};
use std::sync::Arc;
use swf::{Fixed16, Fixed8};

#[derive(Clone, Collect, Copy)]
#[collect(no_drop)]
pub struct MorphShape<'gc>(GcCell<'gc, MorphShapeData<'gc>>);
pub struct MorphShape<'gc>(Gc<'gc, MorphShapeData<'gc>>);

impl fmt::Debug for MorphShape<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MorphShape")
.field("ptr", &self.0.as_ptr())
.field("ptr", &Gc::as_ptr(self.0))
.finish()
}
}

#[derive(Clone, Collect)]
#[collect(no_drop)]
pub struct MorphShapeData<'gc> {
base: DisplayObjectBase<'gc>,
shared: Gc<'gc, MorphShapeShared>,
ratio: u16,
base: RefLock<DisplayObjectBase<'gc>>,
shared: Lock<Gc<'gc, MorphShapeShared>>,
ratio: Cell<u16>,
/// The AVM2 representation of this MorphShape.
object: Option<Avm2Object<'gc>>,
object: Lock<Option<Avm2Object<'gc>>>,
}

impl<'gc> MorphShape<'gc> {
Expand All @@ -43,46 +45,46 @@ impl<'gc> MorphShape<'gc> {
movie: Arc<SwfMovie>,
) -> Self {
let shared = MorphShapeShared::from_swf_tag(&tag, movie);
MorphShape(GcCell::new(
MorphShape(Gc::new(
gc_context,
MorphShapeData {
base: Default::default(),
shared: Gc::new(gc_context, shared),
ratio: 0,
object: None,
shared: Lock::new(Gc::new(gc_context, shared)),
ratio: Cell::new(0),
object: Lock::new(None),
},
))
}

pub fn ratio(self) -> u16 {
self.0.read().ratio
self.0.ratio.get()
}

pub fn set_ratio(&mut self, gc_context: &Mutation<'gc>, ratio: u16) {
self.0.write(gc_context).ratio = ratio;
pub fn set_ratio(self, gc_context: &Mutation<'gc>, ratio: u16) {
self.0.ratio.set(ratio);
self.invalidate_cached_bitmap(gc_context);
}
}

impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> {
fn base(&self) -> Ref<DisplayObjectBase<'gc>> {
Ref::map(self.0.read(), |r| &r.base)
self.0.base.borrow()
}

fn base_mut<'a>(&'a self, mc: &Mutation<'gc>) -> RefMut<'a, DisplayObjectBase<'gc>> {
RefMut::map(self.0.write(mc), |w| &mut w.base)
unlock!(Gc::write(mc, self.0), MorphShapeData, base).borrow_mut()
}

fn instantiate(&self, gc_context: &Mutation<'gc>) -> DisplayObject<'gc> {
Self(GcCell::new(gc_context, self.0.read().clone())).into()
Self(Gc::new(gc_context, self.0.as_ref().clone())).into()
}

fn as_ptr(&self) -> *const DisplayObjectPtr {
self.0.as_ptr() as *const DisplayObjectPtr
Gc::as_ptr(self.0) as *const DisplayObjectPtr
}

fn id(&self) -> CharacterId {
self.0.read().shared.id
self.0.shared.get().id
}

fn as_morph_shape(&self) -> Option<Self> {
Expand All @@ -95,7 +97,8 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> {
.library_for_movie_mut(self.movie())
.get_morph_shape(id)
{
self.0.write(context.gc()).shared = new_morph_shape.0.read().shared;
unlock!(Gc::write(context.gc(), self.0), MorphShapeData, shared)
.set(new_morph_shape.0.shared.get())
} else {
tracing::warn!("PlaceObject: expected morph shape at character ID {}", id);
}
Expand All @@ -108,14 +111,15 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> {

fn object2(&self) -> Avm2Value<'gc> {
self.0
.read()
.object
.get()
.map(Avm2Value::from)
.unwrap_or(Avm2Value::Null)
}

fn set_object2(&self, context: &mut UpdateContext<'gc>, to: Avm2Object<'gc>) {
self.0.write(context.gc()).object = Some(to);
let mc = context.gc();
unlock!(Gc::write(mc, self.0), MorphShapeData, object).set(Some(to))
}

/// Construct objects placed on this frame.
Expand All @@ -128,27 +132,25 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> {
(*self).into(),
class,
) {
Ok(object) => self.0.write(context.gc()).object = Some(object.into()),
Ok(object) => self.set_object2(context, object.into()),
Err(e) => tracing::error!("Got {} when constructing AVM2 side of MorphShape", e),
};
self.on_construction_complete(context);
}
}

fn render_self(&self, context: &mut RenderContext) {
let this = self.0.read();
let ratio = this.ratio;
let shared = this.shared;
let ratio = self.0.ratio.get();
let shared = self.0.shared.get();
let shape_handle = shared.get_shape(context, context.library, ratio);
context
.commands
.render_shape(shape_handle, context.transform_stack.transform());
}

fn self_bounds(&self) -> Rectangle<Twips> {
let this = self.0.read();
let ratio = this.ratio;
let shared = this.shared;
let ratio = self.0.ratio.get();
let shared = self.0.shared.get();
let frame = shared.get_frame(ratio);
frame.bounds.clone()
}
Expand All @@ -162,7 +164,7 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> {
if (!options.contains(HitTestOptions::SKIP_INVISIBLE) || self.visible())
&& self.world_bounds().contains(point)
{
if let Some(frame) = self.0.read().shared.frames.borrow().get(&self.ratio()) {
if let Some(frame) = self.0.shared.get().frames.borrow().get(&self.ratio()) {
let Some(local_matrix) = self.global_to_local_matrix() else {
return false;
};
Expand All @@ -180,7 +182,7 @@ impl<'gc> TDisplayObject<'gc> for MorphShape<'gc> {
}

fn movie(&self) -> Arc<SwfMovie> {
self.0.read().shared.movie.clone()
self.0.shared.get().movie.clone()
}
}

Expand Down
Loading