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_item;
|
||||
pub mod convolution_filter;
|
||||
mod date;
|
||||
pub(crate) mod date;
|
||||
pub mod displacement_map_filter;
|
||||
pub mod drop_shadow_filter;
|
||||
pub(crate) mod error;
|
||||
|
@ -516,7 +516,6 @@ pub struct SystemPrototypes<'gc> {
|
|||
pub gradient_bevel_filter_constructor: Object<'gc>,
|
||||
pub gradient_glow_filter: Object<'gc>,
|
||||
pub gradient_glow_filter_constructor: Object<'gc>,
|
||||
pub date: Object<'gc>,
|
||||
pub date_constructor: Object<'gc>,
|
||||
pub bitmap_data: Object<'gc>,
|
||||
pub bitmap_data_constructor: Object<'gc>,
|
||||
|
@ -589,7 +588,6 @@ pub fn create_globals<'gc>(
|
|||
function_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);
|
||||
|
||||
|
@ -689,7 +687,7 @@ pub fn create_globals<'gc>(
|
|||
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 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));
|
||||
|
||||
|
@ -1178,7 +1176,6 @@ pub fn create_globals<'gc>(
|
|||
gradient_bevel_filter_constructor: gradient_bevel_filter,
|
||||
gradient_glow_filter: gradient_glow_filter_proto,
|
||||
gradient_glow_filter_constructor: gradient_glow_filter,
|
||||
date: date_proto,
|
||||
date_constructor: date,
|
||||
bitmap_data: bitmap_data_proto,
|
||||
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::function::{Executable, FunctionObject};
|
||||
use crate::avm1::object::shared_object::SharedObject;
|
||||
use crate::avm1::object::NativeObject;
|
||||
use crate::avm1::property::Attribute;
|
||||
use crate::avm1::property_decl::{define_properties_on, Declaration};
|
||||
use crate::avm1::{Object, ScriptObject, TObject, Value};
|
||||
|
@ -82,9 +83,8 @@ fn serialize_value<'gc>(
|
|||
// TODO: What happens if an exception is thrown here?
|
||||
let string = xml_node.into_string(activation).unwrap();
|
||||
Some(AmfValue::XML(string.to_utf8_lossy().into_owned(), true))
|
||||
} else if let Some(date) = o.as_date_object() {
|
||||
date.date_time()
|
||||
.map(|date_time| AmfValue::Date(date_time.timestamp_millis() as f64, None))
|
||||
} else if let NativeObject::Date(date) = o.native() {
|
||||
Some(AmfValue::Date(date.read().time(), None))
|
||||
} else {
|
||||
let mut object_body = Vec::new();
|
||||
recursive_serialize(activation, o, &mut object_body);
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
use crate::avm1::function::{Executable, ExecutionName, ExecutionReason, FunctionObject};
|
||||
use crate::avm1::globals::color_transform::ColorTransformObject;
|
||||
use crate::avm1::globals::date::Date;
|
||||
use crate::avm1::object::array_object::ArrayObject;
|
||||
use crate::avm1::object::bevel_filter::BevelFilterObject;
|
||||
use crate::avm1::object::bitmap_data::BitmapDataObject;
|
||||
use crate::avm1::object::blur_filter::BlurFilterObject;
|
||||
use crate::avm1::object::color_matrix_filter::ColorMatrixFilterObject;
|
||||
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::drop_shadow_filter::DropShadowFilterObject;
|
||||
use crate::avm1::object::glow_filter::GlowFilterObject;
|
||||
|
@ -36,7 +36,6 @@ pub mod blur_filter;
|
|||
pub mod color_matrix_filter;
|
||||
pub mod convolution_filter;
|
||||
mod custom_object;
|
||||
pub mod date_object;
|
||||
pub mod displacement_map_filter;
|
||||
pub mod drop_shadow_filter;
|
||||
pub mod glow_filter;
|
||||
|
@ -56,6 +55,7 @@ pub mod xml_object;
|
|||
#[collect(no_drop)]
|
||||
pub enum NativeObject<'gc> {
|
||||
None,
|
||||
Date(GcCell<'gc, Date>),
|
||||
ColorTransform(GcCell<'gc, ColorTransformObject>),
|
||||
TextFormat(GcCell<'gc, TextFormat>),
|
||||
}
|
||||
|
@ -87,7 +87,6 @@ pub enum NativeObject<'gc> {
|
|||
ConvolutionFilterObject(ConvolutionFilterObject<'gc>),
|
||||
GradientBevelFilterObject(GradientBevelFilterObject<'gc>),
|
||||
GradientGlowFilterObject(GradientGlowFilterObject<'gc>),
|
||||
DateObject(DateObject<'gc>),
|
||||
BitmapData(BitmapDataObject<'gc>),
|
||||
}
|
||||
)]
|
||||
|
@ -553,11 +552,6 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
|
|||
None
|
||||
}
|
||||
|
||||
/// Get the underlying `DateObject`, if it exists
|
||||
fn as_date_object(&self) -> Option<DateObject<'gc>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get the underlying `TransformObject`, if it exists
|
||||
fn as_transform_object(&self) -> Option<TransformObject<'gc>> {
|
||||
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::function::ExecutionReason;
|
||||
use crate::avm1::object::value_object::ValueObject;
|
||||
use crate::avm1::object::NativeObject;
|
||||
use crate::avm1::{Object, TObject};
|
||||
use crate::display_object::TDisplayObject;
|
||||
use crate::ecma_conversions::{
|
||||
|
@ -207,7 +208,8 @@ impl<'gc> Value<'gc> {
|
|||
) -> Result<Value<'gc>, Error<'gc>> {
|
||||
let result = match self {
|
||||
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`.
|
||||
object.call_method(
|
||||
"toString".into(),
|
||||
|
|
Loading…
Reference in New Issue