2019-10-20 23:09:49 +00:00
|
|
|
//! MovieClip prototype
|
|
|
|
|
2019-10-19 02:53:29 +00:00
|
|
|
use crate::avm1::function::Executable;
|
2019-10-08 18:35:23 +00:00
|
|
|
use crate::avm1::object::{Attribute::*, Object};
|
2019-10-21 22:37:04 +00:00
|
|
|
use crate::avm1::return_value::ReturnValue;
|
2019-10-26 03:21:14 +00:00
|
|
|
use crate::avm1::{Avm1, Error, UpdateContext, Value};
|
2019-10-21 22:37:04 +00:00
|
|
|
use crate::display_object::{DisplayNode, DisplayObject, MovieClip};
|
2019-10-10 00:37:24 +00:00
|
|
|
use enumset::EnumSet;
|
2019-10-10 03:15:48 +00:00
|
|
|
use gc_arena::{GcCell, MutationContext};
|
2019-08-30 23:25:04 +00:00
|
|
|
|
2019-10-23 18:15:46 +00:00
|
|
|
/// Implements `MovieClip`
|
|
|
|
pub fn constructor<'gc>(
|
|
|
|
_avm: &mut Avm1<'gc>,
|
|
|
|
_action_context: &mut UpdateContext<'_, 'gc, '_>,
|
|
|
|
_this: GcCell<'gc, Object<'gc>>,
|
|
|
|
_args: &[Value<'gc>],
|
|
|
|
) -> Result<ReturnValue<'gc>, Error> {
|
|
|
|
Ok(Value::Undefined.into())
|
|
|
|
}
|
|
|
|
|
2019-08-30 23:25:04 +00:00
|
|
|
macro_rules! with_movie_clip {
|
2019-10-17 02:31:41 +00:00
|
|
|
( $gc_context: ident, $object:ident, $fn_proto: expr, $($name:expr => $fn:expr),* ) => {{
|
2019-08-30 23:25:04 +00:00
|
|
|
$(
|
2019-09-27 13:46:53 +00:00
|
|
|
$object.force_set_function(
|
2019-08-30 23:25:04 +00:00
|
|
|
$name,
|
2019-10-26 03:21:14 +00:00
|
|
|
|_avm, _context, this, args| -> Result<ReturnValue<'gc>, Error> {
|
2019-08-30 23:25:04 +00:00
|
|
|
if let Some(display_object) = this.read().display_node() {
|
|
|
|
if let Some(movie_clip) = display_object.read().as_movie_clip() {
|
2019-11-05 02:47:21 +00:00
|
|
|
return Ok($fn(movie_clip, args));
|
2019-08-30 23:25:04 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-31 00:25:52 +00:00
|
|
|
Ok(Value::Undefined.into())
|
2019-08-30 23:25:04 +00:00
|
|
|
},
|
|
|
|
$gc_context,
|
2019-10-08 18:35:23 +00:00
|
|
|
DontDelete | ReadOnly | DontEnum,
|
2019-10-17 02:31:41 +00:00
|
|
|
$fn_proto
|
2019-08-30 23:25:04 +00:00
|
|
|
);
|
|
|
|
)*
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! with_movie_clip_mut {
|
2019-10-17 02:31:41 +00:00
|
|
|
( $gc_context: ident, $object:ident, $fn_proto: expr, $($name:expr => $fn:expr),* ) => {{
|
2019-08-30 23:25:04 +00:00
|
|
|
$(
|
2019-09-27 13:46:53 +00:00
|
|
|
$object.force_set_function(
|
2019-08-30 23:25:04 +00:00
|
|
|
$name,
|
2019-10-26 03:21:14 +00:00
|
|
|
|_avm, context: &mut UpdateContext<'_, 'gc, '_>, this, args| -> Result<ReturnValue<'gc>, Error> {
|
2019-08-30 23:25:04 +00:00
|
|
|
if let Some(display_object) = this.read().display_node() {
|
2019-09-02 17:28:38 +00:00
|
|
|
if let Some(movie_clip) = display_object.write(context.gc_context).as_movie_clip_mut() {
|
2019-10-31 00:25:52 +00:00
|
|
|
return Ok($fn(movie_clip, context, display_object, args).into());
|
2019-08-30 23:25:04 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-31 00:25:52 +00:00
|
|
|
Ok(Value::Undefined.into())
|
2019-10-18 04:10:13 +00:00
|
|
|
} as crate::avm1::function::NativeFunction<'gc>,
|
2019-08-30 23:25:04 +00:00
|
|
|
$gc_context,
|
2019-10-08 18:35:23 +00:00
|
|
|
DontDelete | ReadOnly | DontEnum,
|
2019-10-17 02:31:41 +00:00
|
|
|
$fn_proto
|
2019-08-30 23:25:04 +00:00
|
|
|
);
|
|
|
|
)*
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
2019-10-10 03:15:48 +00:00
|
|
|
pub fn overwrite_root<'gc>(
|
|
|
|
_avm: &mut Avm1<'gc>,
|
2019-10-27 18:58:30 +00:00
|
|
|
ac: &mut UpdateContext<'_, 'gc, '_>,
|
2019-10-10 03:15:48 +00:00
|
|
|
this: GcCell<'gc, Object<'gc>>,
|
|
|
|
args: &[Value<'gc>],
|
2019-10-26 03:21:14 +00:00
|
|
|
) -> Result<ReturnValue<'gc>, Error> {
|
2019-10-10 03:15:48 +00:00
|
|
|
let new_val = args
|
|
|
|
.get(0)
|
|
|
|
.map(|v| v.to_owned())
|
|
|
|
.unwrap_or(Value::Undefined);
|
|
|
|
this.write(ac.gc_context)
|
|
|
|
.force_set("_root", new_val, EnumSet::new());
|
|
|
|
|
2019-10-31 00:25:52 +00:00
|
|
|
Ok(Value::Undefined.into())
|
2019-10-10 03:15:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn overwrite_global<'gc>(
|
|
|
|
_avm: &mut Avm1<'gc>,
|
2019-10-27 18:58:30 +00:00
|
|
|
ac: &mut UpdateContext<'_, 'gc, '_>,
|
2019-10-10 03:15:48 +00:00
|
|
|
this: GcCell<'gc, Object<'gc>>,
|
|
|
|
args: &[Value<'gc>],
|
2019-10-26 03:21:14 +00:00
|
|
|
) -> Result<ReturnValue<'gc>, Error> {
|
2019-10-10 03:15:48 +00:00
|
|
|
let new_val = args
|
|
|
|
.get(0)
|
|
|
|
.map(|v| v.to_owned())
|
|
|
|
.unwrap_or(Value::Undefined);
|
|
|
|
this.write(ac.gc_context)
|
|
|
|
.force_set("_global", new_val, EnumSet::new());
|
|
|
|
|
2019-10-31 00:25:52 +00:00
|
|
|
Ok(Value::Undefined.into())
|
2019-10-10 03:15:48 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 02:31:41 +00:00
|
|
|
pub fn create_proto<'gc>(
|
|
|
|
gc_context: MutationContext<'gc, '_>,
|
|
|
|
proto: GcCell<'gc, Object<'gc>>,
|
|
|
|
fn_proto: GcCell<'gc, Object<'gc>>,
|
|
|
|
) -> GcCell<'gc, Object<'gc>> {
|
|
|
|
let mut object = Object::object(gc_context, Some(proto));
|
2019-08-30 23:25:04 +00:00
|
|
|
|
|
|
|
with_movie_clip_mut!(
|
|
|
|
gc_context,
|
|
|
|
object,
|
2019-10-17 02:31:41 +00:00
|
|
|
Some(fn_proto),
|
2019-10-27 18:58:30 +00:00
|
|
|
"nextFrame" => |movie_clip: &mut MovieClip<'gc>, context: &mut UpdateContext<'_, 'gc, '_>, _cell: DisplayNode<'gc>, _args| {
|
|
|
|
movie_clip.next_frame(context);
|
2019-08-30 23:25:04 +00:00
|
|
|
Value::Undefined
|
|
|
|
},
|
2019-10-27 18:58:30 +00:00
|
|
|
"prevFrame" => |movie_clip: &mut MovieClip<'gc>, context: &mut UpdateContext<'_, 'gc, '_>, _cell: DisplayNode<'gc>, _args| {
|
|
|
|
movie_clip.prev_frame(context);
|
2019-08-30 23:25:04 +00:00
|
|
|
Value::Undefined
|
|
|
|
},
|
2019-10-27 18:58:30 +00:00
|
|
|
"play" => |movie_clip: &mut MovieClip<'gc>, _context: &mut UpdateContext<'_, 'gc, '_>, _cell: DisplayNode<'gc>, _args| {
|
2019-08-30 23:25:04 +00:00
|
|
|
movie_clip.play();
|
|
|
|
Value::Undefined
|
|
|
|
},
|
2019-10-29 01:12:44 +00:00
|
|
|
"stop" => |movie_clip: &mut MovieClip<'gc>, context: &mut UpdateContext<'_, 'gc, '_>, _cell: DisplayNode<'gc>, _args| {
|
|
|
|
movie_clip.stop(context);
|
2019-08-30 23:25:04 +00:00
|
|
|
Value::Undefined
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
with_movie_clip!(
|
|
|
|
gc_context,
|
|
|
|
object,
|
2019-10-17 02:31:41 +00:00
|
|
|
Some(fn_proto),
|
2019-10-18 04:10:13 +00:00
|
|
|
"getBytesLoaded" => |_movie_clip: &MovieClip<'gc>, _args| {
|
2019-08-30 23:25:04 +00:00
|
|
|
// TODO find a correct value
|
2019-11-05 02:47:21 +00:00
|
|
|
1.0.into()
|
2019-08-30 23:25:04 +00:00
|
|
|
},
|
2019-10-18 04:10:13 +00:00
|
|
|
"getBytesTotal" => |_movie_clip: &MovieClip<'gc>, _args| {
|
2019-08-30 23:25:04 +00:00
|
|
|
// TODO find a correct value
|
2019-11-05 02:47:21 +00:00
|
|
|
1.0.into()
|
2019-10-21 22:37:04 +00:00
|
|
|
},
|
|
|
|
"toString" => |movie_clip: &MovieClip, _args| {
|
2019-11-05 02:47:21 +00:00
|
|
|
movie_clip.name().to_string().into()
|
2019-08-30 23:25:04 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-10-10 00:37:24 +00:00
|
|
|
object.force_set_virtual(
|
|
|
|
"_global",
|
2019-10-31 00:25:52 +00:00
|
|
|
Executable::Native(|avm, context, _this, _args| Ok(avm.global_object(context).into())),
|
2019-10-19 02:53:29 +00:00
|
|
|
Some(Executable::Native(overwrite_global)),
|
2019-10-10 00:37:24 +00:00
|
|
|
EnumSet::new(),
|
|
|
|
);
|
|
|
|
|
|
|
|
object.force_set_virtual(
|
|
|
|
"_root",
|
2019-10-31 00:25:52 +00:00
|
|
|
Executable::Native(|avm, context, _this, _args| Ok(avm.root_object(context).into())),
|
2019-10-19 02:53:29 +00:00
|
|
|
Some(Executable::Native(overwrite_root)),
|
2019-10-10 00:37:24 +00:00
|
|
|
EnumSet::new(),
|
|
|
|
);
|
|
|
|
|
|
|
|
object.force_set_virtual(
|
|
|
|
"_parent",
|
2019-10-19 02:53:29 +00:00
|
|
|
Executable::Native(|_avm, _context, this, _args| {
|
2019-10-31 00:25:52 +00:00
|
|
|
Ok(this
|
|
|
|
.read()
|
|
|
|
.display_node()
|
|
|
|
.and_then(|mc| mc.read().parent())
|
|
|
|
.and_then(|dn| dn.read().object().as_object().ok())
|
|
|
|
.map(|o| Value::Object(o.to_owned()))
|
|
|
|
.unwrap_or(Value::Undefined)
|
|
|
|
.into())
|
2019-10-19 02:53:29 +00:00
|
|
|
}),
|
2019-10-10 00:37:24 +00:00
|
|
|
None,
|
|
|
|
EnumSet::new(),
|
|
|
|
);
|
|
|
|
|
2019-10-17 02:31:41 +00:00
|
|
|
GcCell::allocate(gc_context, object)
|
2019-08-30 23:25:04 +00:00
|
|
|
}
|