`DisplayObject`s all have a AVM1 `Value`. Added `toString()` default method for Objects (but not functions)

This commit is contained in:
Nathan Adams 2019-08-31 17:54:15 +02:00
parent bd63a82e9e
commit 7a18ece455
7 changed files with 36 additions and 31 deletions

View File

@ -369,7 +369,7 @@ impl<'gc> Avm1<'gc> {
fn action_call_method(
&mut self,
_context: &mut ActionContext<'_, 'gc, '_>,
context: &mut ActionContext<'_, 'gc, '_>,
) -> Result<(), Error> {
let method_name = self.pop()?;
let object = self.pop()?;
@ -383,13 +383,13 @@ impl<'gc> Avm1<'gc> {
Value::Undefined | Value::Null => {
self.stack.push(
object.call(
_context.gc_context,
_context
context.gc_context,
context
.active_clip
.read()
.as_movie_clip()
.unwrap()
.object(),
.object()
.as_object()?
.to_owned(),
&args,
)?,
);
@ -397,13 +397,13 @@ impl<'gc> Avm1<'gc> {
Value::String(name) => {
if name.is_empty() {
self.stack.push(object.call(
_context.gc_context,
context.gc_context,
object.as_object()?.to_owned(),
&args,
)?);
} else {
self.stack.push(object.as_object()?.read().get(&name).call(
_context.gc_context,
context.gc_context,
object.as_object()?.to_owned(),
&args,
)?);
@ -588,8 +588,7 @@ impl<'gc> Avm1<'gc> {
context
.start_clip
.read()
.as_movie_clip()
.map_or(Value::Undefined, |clip| Value::Object(clip.object())),
.object()
);
return Ok(());
}
@ -601,7 +600,7 @@ impl<'gc> Avm1<'gc> {
Self::resolve_slash_path_variable(context.active_clip, context.root, path)
{
if let Some(clip) = node.read().as_movie_clip() {
let object = clip.object();
let object = clip.object().as_object()?;
if object.read().has_property(var_name) {
result = Some(object.read().get(var_name));
}
@ -1004,7 +1003,7 @@ impl<'gc> Avm1<'gc> {
Self::resolve_slash_path_variable(context.active_clip, context.root, var_path)
{
if let Some(clip) = node.write(context.gc_context).as_movie_clip_mut() {
clip.object().write(context.gc_context).set(var_name, value);
clip.object().as_object()?.write(context.gc_context).set(var_name, value);
}
}
Ok(())

View File

@ -20,7 +20,7 @@ fn round<'gc>(
}
pub fn create<'gc>(gc_context: MutationContext<'gc, '_>) -> Value<'gc> {
let mut math = Object::object();
let mut math = Object::object(gc_context);
math.set_function("abs", abs, gc_context);
math.set_function("round", round, gc_context);

View File

@ -42,7 +42,7 @@ macro_rules! with_movie_clip_mut {
}
pub fn create_movie_object<'gc>(gc_context: MutationContext<'gc, '_>) -> Object<'gc> {
let mut object = Object::object();
let mut object = Object::object(gc_context);
with_movie_clip_mut!(
gc_context,

View File

@ -11,6 +11,10 @@ pub const TYPE_OF_OBJECT: &str = "object";
pub const TYPE_OF_FUNCTION: &str = "function";
pub const TYPE_OF_MOVIE_CLIP: &str = "movieclip";
fn default_to_string<'gc>(_: MutationContext<'gc, '_>, _: GcCell<'gc, Object<'gc>>, _: &[Value<'gc>]) -> Value<'gc> {
Value::String("[Object object]".to_string())
}
#[derive(Clone)]
pub struct Object<'gc> {
display_node: Option<DisplayNode<'gc>>,
@ -37,13 +41,17 @@ impl fmt::Debug for Object<'_> {
}
impl<'gc> Object<'gc> {
pub fn object() -> Self {
Self {
pub fn object(gc_context: MutationContext<'gc, '_>) -> Self {
let mut result = Self {
type_of: TYPE_OF_OBJECT,
display_node: None,
values: HashMap::new(),
function: None,
}
};
result.set_function("toString", default_to_string, gc_context);
result
}
pub fn function(function: NativeFunction<'gc>) -> Self {

View File

@ -119,9 +119,9 @@ impl<'gc> Value<'gc> {
}
}
pub fn as_object(&self) -> Result<&GcCell<'gc, Object<'gc>>, Error> {
pub fn as_object(&self) -> Result<GcCell<'gc, Object<'gc>>, Error> {
if let Value::Object(object) = self {
Ok(object)
Ok(object.to_owned())
} else {
Err(format!("Expected Object, found {:?}", self).into())
}

View File

@ -1,10 +1,9 @@
use crate::avm1::object::Object;
use crate::player::{RenderContext, UpdateContext};
use crate::prelude::*;
use crate::transform::Transform;
use gc_arena::{Collect, GcCell, MutationContext};
use std::fmt::Debug;
use crate::avm1::Value;
#[derive(Clone, Collect, Debug)]
#[collect(empty_drop)]
@ -118,8 +117,8 @@ pub trait DisplayObject<'gc>: 'gc + Collect + Debug {
}
fn box_clone(&self) -> Box<dyn DisplayObject<'gc>>;
fn object(&self) -> Object<'gc> {
Object::object() // todo: impl for every type and delete this fallback
fn object(&self) -> Value<'gc> {
Value::Undefined // todo: impl for every type and delete this fallback
}
fn hit_test(&self, _: (Twips, Twips)) -> bool {

View File

@ -15,6 +15,7 @@ use crate::text::Text;
use gc_arena::{Gc, GcCell, MutationContext};
use std::collections::{BTreeMap, HashMap};
use swf::read::SwfRead;
use crate::avm1::Value;
type Depth = i16;
type FrameNumber = u16;
@ -34,7 +35,6 @@ pub struct MovieClip<'gc> {
impl<'gc> MovieClip<'gc> {
pub fn new(gc_context: MutationContext<'gc, '_>) -> Self {
let object = GcCell::allocate(gc_context, create_movie_object(gc_context));
Self {
base: Default::default(),
static_data: Gc::allocate(gc_context, MovieClipStatic::default()),
@ -44,7 +44,7 @@ impl<'gc> MovieClip<'gc> {
current_frame: 0,
audio_stream: None,
children: BTreeMap::new(),
object,
object: GcCell::allocate(gc_context, create_movie_object(gc_context)),
}
}
@ -55,7 +55,6 @@ impl<'gc> MovieClip<'gc> {
tag_stream_len: usize,
num_frames: u16,
) -> Self {
let object = GcCell::allocate(gc_context, create_movie_object(gc_context));
Self {
base: Default::default(),
static_data: Gc::allocate(
@ -75,7 +74,7 @@ impl<'gc> MovieClip<'gc> {
current_frame: 0,
audio_stream: None,
children: BTreeMap::new(),
object,
object: GcCell::allocate(gc_context, create_movie_object(gc_context)),
}
}
@ -232,10 +231,6 @@ impl<'gc> MovieClip<'gc> {
self.static_data.id
}
pub fn object(&self) -> GcCell<'gc, Object<'gc>> {
self.object
}
fn tag_stream_start(&self) -> u64 {
self.static_data.tag_stream_start
}
@ -442,6 +437,10 @@ impl<'gc> DisplayObject<'gc> for MovieClip<'gc> {
object.set_display_node(display_object);
object.set_type_of(TYPE_OF_MOVIE_CLIP);
}
fn object(&self) -> Value<'gc> {
Value::Object(self.object)
}
}
unsafe impl<'gc> gc_arena::Collect for MovieClip<'gc> {