avm1: Rewrite `Date` implementation
The new implementation is simpler, and supports many AVM1 quirks not supported before. In addition, migrate `Date` to `NativeObject`.
This commit is contained in:
parent
a59114d569
commit
967ff56e3b
|
@ -25,7 +25,7 @@ pub(crate) mod color_transform;
|
||||||
pub(crate) mod context_menu;
|
pub(crate) mod context_menu;
|
||||||
pub(crate) mod context_menu_item;
|
pub(crate) mod context_menu_item;
|
||||||
pub mod convolution_filter;
|
pub mod convolution_filter;
|
||||||
mod date;
|
pub(crate) mod date;
|
||||||
pub mod displacement_map_filter;
|
pub mod displacement_map_filter;
|
||||||
pub mod drop_shadow_filter;
|
pub mod drop_shadow_filter;
|
||||||
pub(crate) mod error;
|
pub(crate) mod error;
|
||||||
|
@ -516,7 +516,6 @@ pub struct SystemPrototypes<'gc> {
|
||||||
pub gradient_bevel_filter_constructor: Object<'gc>,
|
pub gradient_bevel_filter_constructor: Object<'gc>,
|
||||||
pub gradient_glow_filter: Object<'gc>,
|
pub gradient_glow_filter: Object<'gc>,
|
||||||
pub gradient_glow_filter_constructor: Object<'gc>,
|
pub gradient_glow_filter_constructor: Object<'gc>,
|
||||||
pub date: Object<'gc>,
|
|
||||||
pub date_constructor: Object<'gc>,
|
pub date_constructor: Object<'gc>,
|
||||||
pub bitmap_data: Object<'gc>,
|
pub bitmap_data: Object<'gc>,
|
||||||
pub bitmap_data_constructor: Object<'gc>,
|
pub bitmap_data_constructor: Object<'gc>,
|
||||||
|
@ -589,7 +588,6 @@ pub fn create_globals<'gc>(
|
||||||
function_proto,
|
function_proto,
|
||||||
movie_clip_loader_proto,
|
movie_clip_loader_proto,
|
||||||
);
|
);
|
||||||
let date_proto = date::create_proto(gc_context, object_proto, function_proto);
|
|
||||||
|
|
||||||
let video_proto = video::create_proto(gc_context, object_proto, function_proto);
|
let video_proto = video::create_proto(gc_context, object_proto, function_proto);
|
||||||
|
|
||||||
|
@ -689,7 +687,7 @@ pub fn create_globals<'gc>(
|
||||||
let string = string::create_string_object(gc_context, string_proto, function_proto);
|
let string = string::create_string_object(gc_context, string_proto, function_proto);
|
||||||
let number = number::create_number_object(gc_context, number_proto, function_proto);
|
let number = number::create_number_object(gc_context, number_proto, function_proto);
|
||||||
let boolean = boolean::create_boolean_object(gc_context, boolean_proto, function_proto);
|
let boolean = boolean::create_boolean_object(gc_context, boolean_proto, function_proto);
|
||||||
let date = date::create_date_object(gc_context, date_proto, function_proto);
|
let date = date::create_constructor(gc_context, object_proto, function_proto);
|
||||||
|
|
||||||
let flash = ScriptObject::new(gc_context, Some(object_proto));
|
let flash = ScriptObject::new(gc_context, Some(object_proto));
|
||||||
|
|
||||||
|
@ -1178,7 +1176,6 @@ pub fn create_globals<'gc>(
|
||||||
gradient_bevel_filter_constructor: gradient_bevel_filter,
|
gradient_bevel_filter_constructor: gradient_bevel_filter,
|
||||||
gradient_glow_filter: gradient_glow_filter_proto,
|
gradient_glow_filter: gradient_glow_filter_proto,
|
||||||
gradient_glow_filter_constructor: gradient_glow_filter,
|
gradient_glow_filter_constructor: gradient_glow_filter,
|
||||||
date: date_proto,
|
|
||||||
date_constructor: date,
|
date_constructor: date,
|
||||||
bitmap_data: bitmap_data_proto,
|
bitmap_data: bitmap_data_proto,
|
||||||
bitmap_data_constructor: bitmap_data,
|
bitmap_data_constructor: bitmap_data,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,6 +2,7 @@ use crate::avm1::activation::Activation;
|
||||||
use crate::avm1::error::Error;
|
use crate::avm1::error::Error;
|
||||||
use crate::avm1::function::{Executable, FunctionObject};
|
use crate::avm1::function::{Executable, FunctionObject};
|
||||||
use crate::avm1::object::shared_object::SharedObject;
|
use crate::avm1::object::shared_object::SharedObject;
|
||||||
|
use crate::avm1::object::NativeObject;
|
||||||
use crate::avm1::property::Attribute;
|
use crate::avm1::property::Attribute;
|
||||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||||
use crate::avm1::{Object, ScriptObject, TObject, Value};
|
use crate::avm1::{Object, ScriptObject, TObject, Value};
|
||||||
|
@ -82,9 +83,8 @@ fn serialize_value<'gc>(
|
||||||
// TODO: What happens if an exception is thrown here?
|
// TODO: What happens if an exception is thrown here?
|
||||||
let string = xml_node.into_string(activation).unwrap();
|
let string = xml_node.into_string(activation).unwrap();
|
||||||
Some(AmfValue::XML(string.to_utf8_lossy().into_owned(), true))
|
Some(AmfValue::XML(string.to_utf8_lossy().into_owned(), true))
|
||||||
} else if let Some(date) = o.as_date_object() {
|
} else if let NativeObject::Date(date) = o.native() {
|
||||||
date.date_time()
|
Some(AmfValue::Date(date.read().time(), None))
|
||||||
.map(|date_time| AmfValue::Date(date_time.timestamp_millis() as f64, None))
|
|
||||||
} else {
|
} else {
|
||||||
let mut object_body = Vec::new();
|
let mut object_body = Vec::new();
|
||||||
recursive_serialize(activation, o, &mut object_body);
|
recursive_serialize(activation, o, &mut object_body);
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
use crate::avm1::function::{Executable, ExecutionName, ExecutionReason, FunctionObject};
|
use crate::avm1::function::{Executable, ExecutionName, ExecutionReason, FunctionObject};
|
||||||
use crate::avm1::globals::color_transform::ColorTransformObject;
|
use crate::avm1::globals::color_transform::ColorTransformObject;
|
||||||
|
use crate::avm1::globals::date::Date;
|
||||||
use crate::avm1::object::array_object::ArrayObject;
|
use crate::avm1::object::array_object::ArrayObject;
|
||||||
use crate::avm1::object::bevel_filter::BevelFilterObject;
|
use crate::avm1::object::bevel_filter::BevelFilterObject;
|
||||||
use crate::avm1::object::bitmap_data::BitmapDataObject;
|
use crate::avm1::object::bitmap_data::BitmapDataObject;
|
||||||
use crate::avm1::object::blur_filter::BlurFilterObject;
|
use crate::avm1::object::blur_filter::BlurFilterObject;
|
||||||
use crate::avm1::object::color_matrix_filter::ColorMatrixFilterObject;
|
use crate::avm1::object::color_matrix_filter::ColorMatrixFilterObject;
|
||||||
use crate::avm1::object::convolution_filter::ConvolutionFilterObject;
|
use crate::avm1::object::convolution_filter::ConvolutionFilterObject;
|
||||||
use crate::avm1::object::date_object::DateObject;
|
|
||||||
use crate::avm1::object::displacement_map_filter::DisplacementMapFilterObject;
|
use crate::avm1::object::displacement_map_filter::DisplacementMapFilterObject;
|
||||||
use crate::avm1::object::drop_shadow_filter::DropShadowFilterObject;
|
use crate::avm1::object::drop_shadow_filter::DropShadowFilterObject;
|
||||||
use crate::avm1::object::glow_filter::GlowFilterObject;
|
use crate::avm1::object::glow_filter::GlowFilterObject;
|
||||||
|
@ -36,7 +36,6 @@ pub mod blur_filter;
|
||||||
pub mod color_matrix_filter;
|
pub mod color_matrix_filter;
|
||||||
pub mod convolution_filter;
|
pub mod convolution_filter;
|
||||||
mod custom_object;
|
mod custom_object;
|
||||||
pub mod date_object;
|
|
||||||
pub mod displacement_map_filter;
|
pub mod displacement_map_filter;
|
||||||
pub mod drop_shadow_filter;
|
pub mod drop_shadow_filter;
|
||||||
pub mod glow_filter;
|
pub mod glow_filter;
|
||||||
|
@ -56,6 +55,7 @@ pub mod xml_object;
|
||||||
#[collect(no_drop)]
|
#[collect(no_drop)]
|
||||||
pub enum NativeObject<'gc> {
|
pub enum NativeObject<'gc> {
|
||||||
None,
|
None,
|
||||||
|
Date(GcCell<'gc, Date>),
|
||||||
ColorTransform(GcCell<'gc, ColorTransformObject>),
|
ColorTransform(GcCell<'gc, ColorTransformObject>),
|
||||||
TextFormat(GcCell<'gc, TextFormat>),
|
TextFormat(GcCell<'gc, TextFormat>),
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,6 @@ pub enum NativeObject<'gc> {
|
||||||
ConvolutionFilterObject(ConvolutionFilterObject<'gc>),
|
ConvolutionFilterObject(ConvolutionFilterObject<'gc>),
|
||||||
GradientBevelFilterObject(GradientBevelFilterObject<'gc>),
|
GradientBevelFilterObject(GradientBevelFilterObject<'gc>),
|
||||||
GradientGlowFilterObject(GradientGlowFilterObject<'gc>),
|
GradientGlowFilterObject(GradientGlowFilterObject<'gc>),
|
||||||
DateObject(DateObject<'gc>),
|
|
||||||
BitmapData(BitmapDataObject<'gc>),
|
BitmapData(BitmapDataObject<'gc>),
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
|
@ -553,11 +552,6 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the underlying `DateObject`, if it exists
|
|
||||||
fn as_date_object(&self) -> Option<DateObject<'gc>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the underlying `TransformObject`, if it exists
|
/// Get the underlying `TransformObject`, if it exists
|
||||||
fn as_transform_object(&self) -> Option<TransformObject<'gc>> {
|
fn as_transform_object(&self) -> Option<TransformObject<'gc>> {
|
||||||
None
|
None
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
use crate::avm1::{Object, ScriptObject, TObject};
|
|
||||||
use crate::impl_custom_object;
|
|
||||||
use chrono::{DateTime, Utc};
|
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Collect)]
|
|
||||||
#[collect(no_drop)]
|
|
||||||
pub struct DateObject<'gc>(GcCell<'gc, DateObjectData<'gc>>);
|
|
||||||
|
|
||||||
#[derive(Collect)]
|
|
||||||
#[collect(no_drop)]
|
|
||||||
pub struct DateObjectData<'gc> {
|
|
||||||
/// The underlying script object.
|
|
||||||
base: ScriptObject<'gc>,
|
|
||||||
|
|
||||||
/// The DateTime represented by this object
|
|
||||||
#[collect(require_static)]
|
|
||||||
date_time: Option<DateTime<Utc>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for DateObject<'_> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let this = self.0.read();
|
|
||||||
f.debug_struct("DateObject")
|
|
||||||
.field("date_time", &this.date_time)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc> DateObject<'gc> {
|
|
||||||
pub fn empty(
|
|
||||||
gc_context: MutationContext<'gc, '_>,
|
|
||||||
proto: Option<Object<'gc>>,
|
|
||||||
) -> DateObject<'gc> {
|
|
||||||
Self::with_date_time(gc_context, proto, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_date_time(
|
|
||||||
gc_context: MutationContext<'gc, '_>,
|
|
||||||
proto: Option<Object<'gc>>,
|
|
||||||
date_time: Option<DateTime<Utc>>,
|
|
||||||
) -> DateObject<'gc> {
|
|
||||||
DateObject(GcCell::allocate(
|
|
||||||
gc_context,
|
|
||||||
DateObjectData {
|
|
||||||
base: ScriptObject::new(gc_context, proto),
|
|
||||||
date_time,
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn date_time(self) -> Option<DateTime<Utc>> {
|
|
||||||
self.0.read().date_time
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_date_time(
|
|
||||||
self,
|
|
||||||
gc_context: MutationContext<'gc, '_>,
|
|
||||||
date_time: Option<DateTime<Utc>>,
|
|
||||||
) {
|
|
||||||
self.0.write(gc_context).date_time = date_time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'gc> TObject<'gc> for DateObject<'gc> {
|
|
||||||
impl_custom_object!(base {
|
|
||||||
bare_object(as_date_object -> DateObject::empty);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ use crate::avm1::activation::Activation;
|
||||||
use crate::avm1::error::Error;
|
use crate::avm1::error::Error;
|
||||||
use crate::avm1::function::ExecutionReason;
|
use crate::avm1::function::ExecutionReason;
|
||||||
use crate::avm1::object::value_object::ValueObject;
|
use crate::avm1::object::value_object::ValueObject;
|
||||||
|
use crate::avm1::object::NativeObject;
|
||||||
use crate::avm1::{Object, TObject};
|
use crate::avm1::{Object, TObject};
|
||||||
use crate::display_object::TDisplayObject;
|
use crate::display_object::TDisplayObject;
|
||||||
use crate::ecma_conversions::{
|
use crate::ecma_conversions::{
|
||||||
|
@ -207,7 +208,8 @@ impl<'gc> Value<'gc> {
|
||||||
) -> Result<Value<'gc>, Error<'gc>> {
|
) -> Result<Value<'gc>, Error<'gc>> {
|
||||||
let result = match self {
|
let result = match self {
|
||||||
Value::Object(object) => {
|
Value::Object(object) => {
|
||||||
let val = if activation.swf_version() > 5 && object.as_date_object().is_some() {
|
let is_date = matches!(object.native(), NativeObject::Date(_));
|
||||||
|
let val = if activation.swf_version() > 5 && is_date {
|
||||||
// In SWFv6 and higher, Date objects call `toString`.
|
// In SWFv6 and higher, Date objects call `toString`.
|
||||||
object.call_method(
|
object.call_method(
|
||||||
"toString".into(),
|
"toString".into(),
|
||||||
|
|
Loading…
Reference in New Issue