diff --git a/core/src/avm1/globals.rs b/core/src/avm1/globals.rs index 785dca052..a11d86591 100644 --- a/core/src/avm1/globals.rs +++ b/core/src/avm1/globals.rs @@ -27,7 +27,7 @@ pub(crate) mod context_menu_item; pub mod convolution_filter; pub(crate) mod date; pub mod displacement_map_filter; -pub mod drop_shadow_filter; +pub(crate) mod drop_shadow_filter; pub(crate) mod error; mod external_interface; mod function; @@ -499,8 +499,6 @@ pub struct SystemPrototypes<'gc> { pub context_menu_item_constructor: Object<'gc>, pub bitmap_filter: Object<'gc>, pub bitmap_filter_constructor: Object<'gc>, - pub drop_shadow_filter: Object<'gc>, - pub drop_shadow_filter_constructor: Object<'gc>, pub color_matrix_filter: Object<'gc>, pub color_matrix_filter_constructor: Object<'gc>, pub displacement_map_filter: Object<'gc>, @@ -759,15 +757,8 @@ pub fn create_globals<'gc>( let glow_filter = glow_filter::create_constructor(gc_context, bitmap_filter_proto, function_proto); - let drop_shadow_filter_proto = - drop_shadow_filter::create_proto(gc_context, bitmap_filter_proto, function_proto); - let drop_shadow_filter = FunctionObject::constructor( - gc_context, - Executable::Native(drop_shadow_filter::constructor), - constructor_to_fn!(drop_shadow_filter::constructor), - function_proto, - drop_shadow_filter_proto, - ); + let drop_shadow_filter = + drop_shadow_filter::create_constructor(gc_context, bitmap_filter_proto, function_proto); let color_matrix_filter_proto = color_matrix_filter::create_proto(gc_context, bitmap_filter_proto, function_proto); @@ -1139,8 +1130,6 @@ pub fn create_globals<'gc>( context_menu_item_constructor: context_menu_item, bitmap_filter: bitmap_filter_proto, bitmap_filter_constructor: bitmap_filter, - drop_shadow_filter: drop_shadow_filter_proto, - drop_shadow_filter_constructor: drop_shadow_filter, color_matrix_filter: color_matrix_filter_proto, color_matrix_filter_constructor: color_matrix_filter, displacement_map_filter: displacement_map_filter_proto, diff --git a/core/src/avm1/globals/bitmap_filter.rs b/core/src/avm1/globals/bitmap_filter.rs index 5a617f19c..82038a82b 100644 --- a/core/src/avm1/globals/bitmap_filter.rs +++ b/core/src/avm1/globals/bitmap_filter.rs @@ -34,6 +34,9 @@ pub fn clone<'gc>( NativeObject::GlowFilter(glow_filter) => { NativeObject::GlowFilter(glow_filter.duplicate(activation.context.gc_context)) } + NativeObject::DropShadowFilter(drop_shadow_filter) => NativeObject::DropShadowFilter( + drop_shadow_filter.duplicate(activation.context.gc_context), + ), _ => NativeObject::None, }; if !matches!(native, NativeObject::None) { @@ -53,44 +56,6 @@ pub fn clone<'gc>( return Ok(cloned.into()); } - if let Some(this) = this.as_drop_shadow_filter_object() { - let proto = activation - .context - .avm1 - .prototypes() - .drop_shadow_filter_constructor; - - let distance = this.get("distance", activation)?; - let angle = this.get("angle", activation)?; - let color = this.get("color", activation)?; - let alpha = this.get("alpha", activation)?; - let blur_x = this.get("blurX", activation)?; - let blur_y = this.get("blurY", activation)?; - let strength = this.get("strength", activation)?; - let quality = this.get("quality", activation)?; - let inner = this.get("inner", activation)?; - let knockout = this.get("knockout", activation)?; - let hide_object = this.get("hide_object", activation)?; - - let cloned = proto.construct( - activation, - &[ - distance, - angle, - color, - alpha, - blur_x, - blur_y, - strength, - quality, - inner, - knockout, - hide_object, - ], - )?; - return Ok(cloned); - } - if let Some(this) = this.as_color_matrix_filter_object() { let proto = activation .context diff --git a/core/src/avm1/globals/drop_shadow_filter.rs b/core/src/avm1/globals/drop_shadow_filter.rs index 7c223e491..976d6fc42 100644 --- a/core/src/avm1/globals/drop_shadow_filter.rs +++ b/core/src/avm1/globals/drop_shadow_filter.rs @@ -1,381 +1,389 @@ //! flash.filters.DropShadowFilter object -use crate::avm1::activation::Activation; -use crate::avm1::clamp::Clamp; -use crate::avm1::error::Error; -use crate::avm1::object::drop_shadow_filter::DropShadowFilterObject; +use crate::avm1::function::{Executable, FunctionObject}; +use crate::avm1::object::NativeObject; use crate::avm1::property_decl::{define_properties_on, Declaration}; -use crate::avm1::{Object, TObject, Value}; -use gc_arena::MutationContext; +use crate::avm1::{Activation, Error, Object, ScriptObject, TObject, Value}; +use gc_arena::{Collect, GcCell, MutationContext}; +use swf::Color; + +#[derive(Clone, Debug, Collect)] +#[collect(require_static)] +struct DropShadowFilterData { + distance: f64, + // TODO: Introduce `Angle` struct. + angle: f64, + color: Color, + quality: i32, + inner: bool, + knockout: bool, + blur_x: f64, + blur_y: f64, + // TODO: Introduce unsigned `Fixed8`? + strength: u16, + hide_object: bool, +} + +impl Default for DropShadowFilterData { + #[allow(clippy::approx_constant)] + fn default() -> Self { + Self { + distance: 4.0, + angle: 0.785398163, // ~45 degrees + color: Color::BLACK, + quality: 1, + inner: false, + knockout: false, + blur_x: 4.0, + blur_y: 4.0, + strength: 1 << 8, + hide_object: false, + } + } +} + +#[derive(Clone, Debug, Collect)] +#[collect(no_drop)] +#[repr(transparent)] +pub struct DropShadowFilter<'gc>(GcCell<'gc, DropShadowFilterData>); + +impl<'gc> DropShadowFilter<'gc> { + fn new(activation: &mut Activation<'_, 'gc>, args: &[Value<'gc>]) -> Result> { + let drop_shadow_filter = Self(GcCell::allocate( + activation.context.gc_context, + Default::default(), + )); + drop_shadow_filter.set_distance(activation, args.get(0))?; + drop_shadow_filter.set_angle(activation, args.get(1))?; + drop_shadow_filter.set_color(activation, args.get(2))?; + drop_shadow_filter.set_alpha(activation, args.get(3))?; + drop_shadow_filter.set_blur_x(activation, args.get(4))?; + drop_shadow_filter.set_blur_y(activation, args.get(5))?; + drop_shadow_filter.set_strength(activation, args.get(6))?; + drop_shadow_filter.set_quality(activation, args.get(7))?; + drop_shadow_filter.set_inner(activation, args.get(8))?; + drop_shadow_filter.set_knockout(activation, args.get(9))?; + drop_shadow_filter.set_hide_object(activation, args.get(10))?; + Ok(drop_shadow_filter) + } + + pub(crate) fn duplicate(&self, gc_context: MutationContext<'gc, '_>) -> Self { + Self(GcCell::allocate(gc_context, self.0.read().clone())) + } + + fn distance(&self) -> f64 { + self.0.read().distance + } + + fn set_distance( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let distance = value.coerce_to_f64(activation)?; + self.0.write(activation.context.gc_context).distance = distance; + } + Ok(()) + } + + fn angle(&self) -> f64 { + self.0.read().angle.to_degrees() + } + + fn set_angle( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let angle = (value.coerce_to_f64(activation)? % 360.0).to_radians(); + self.0.write(activation.context.gc_context).angle = angle; + } + Ok(()) + } + + fn color(&self) -> i32 { + self.0.read().color.to_rgb() as i32 + } + + fn set_color( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let color = Color::from_rgb(value.coerce_to_u32(activation)?, 0); + self.0.write(activation.context.gc_context).color = color; + } + Ok(()) + } + + fn alpha(&self) -> f64 { + f64::from(self.0.read().color.a) / 255.0 + } + + fn set_alpha( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let alpha = (value.coerce_to_f64(activation)? * 255.0) as u8; + self.0.write(activation.context.gc_context).color.a = alpha; + } + Ok(()) + } + + fn quality(&self) -> i32 { + self.0.read().quality + } + + fn set_quality( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let quality = value.coerce_to_i32(activation)?.clamp(0, 15); + self.0.write(activation.context.gc_context).quality = quality; + } + Ok(()) + } + + fn inner(&self) -> bool { + self.0.read().inner + } + + fn set_inner( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let inner = value.as_bool(activation.swf_version()); + self.0.write(activation.context.gc_context).inner = inner; + } + Ok(()) + } + + fn knockout(&self) -> bool { + self.0.read().knockout + } + + fn set_knockout( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let knockout = value.as_bool(activation.swf_version()); + self.0.write(activation.context.gc_context).knockout = knockout; + } + Ok(()) + } + + fn blur_x(&self) -> f64 { + self.0.read().blur_x + } + + fn set_blur_x( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let blur_x = value.coerce_to_f64(activation)?.clamp(0.0, 255.0); + self.0.write(activation.context.gc_context).blur_x = blur_x; + } + Ok(()) + } + + fn blur_y(&self) -> f64 { + self.0.read().blur_y + } + + fn set_blur_y( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let blur_y = value.coerce_to_f64(activation)?.clamp(0.0, 255.0); + self.0.write(activation.context.gc_context).blur_y = blur_y; + } + Ok(()) + } + + fn strength(&self) -> f64 { + f64::from(self.0.read().strength) / 256.0 + } + + fn set_strength( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let strength = ((value.coerce_to_f64(activation)? * 256.0) as u16).clamp(0, 0xFF00); + self.0.write(activation.context.gc_context).strength = strength; + } + Ok(()) + } + + fn hide_object(&self) -> bool { + self.0.read().hide_object + } + + fn set_hide_object( + &self, + activation: &mut Activation<'_, 'gc>, + value: Option<&Value<'gc>>, + ) -> Result<(), Error<'gc>> { + if let Some(value) = value { + let hide_object = value.as_bool(activation.swf_version()); + self.0.write(activation.context.gc_context).hide_object = hide_object; + } + Ok(()) + } +} + +macro_rules! drop_shadow_filter_method { + ($index:literal) => { + |activation, this, args| method(activation, this, args, $index) + }; +} const PROTO_DECLS: &[Declaration] = declare_properties! { - "alpha" => property(alpha, set_alpha); - "angle" => property(angle, set_angle); - "blurX" => property(blur_x, set_blur_x); - "blurY" => property(blur_y, set_blur_y); - "color" => property(color, set_color); - "distance" => property(distance, set_distance); - "hideObject" => property(hide_object, set_hide_object); - "inner" => property(inner, set_inner); - "knockout" => property(knockout, set_knockout); - "quality" => property(quality, set_quality); - "strength" => property(strength, set_strength); + "distance" => property(drop_shadow_filter_method!(1), drop_shadow_filter_method!(2); VERSION_8); + "angle" => property(drop_shadow_filter_method!(3), drop_shadow_filter_method!(4); VERSION_8); + "color" => property(drop_shadow_filter_method!(5), drop_shadow_filter_method!(6); VERSION_8); + "alpha" => property(drop_shadow_filter_method!(7), drop_shadow_filter_method!(8); VERSION_8); + "quality" => property(drop_shadow_filter_method!(9), drop_shadow_filter_method!(10); VERSION_8); + "inner" => property(drop_shadow_filter_method!(11), drop_shadow_filter_method!(12); VERSION_8); + "knockout" => property(drop_shadow_filter_method!(13), drop_shadow_filter_method!(14); VERSION_8); + "blurX" => property(drop_shadow_filter_method!(15), drop_shadow_filter_method!(16); VERSION_8); + "blurY" => property(drop_shadow_filter_method!(17), drop_shadow_filter_method!(18); VERSION_8); + "strength" => property(drop_shadow_filter_method!(19), drop_shadow_filter_method!(20); VERSION_8); + "hideObject" => property(drop_shadow_filter_method!(21), drop_shadow_filter_method!(22); VERSION_8); }; -pub fn constructor<'gc>( +fn method<'gc>( activation: &mut Activation<'_, 'gc>, this: Object<'gc>, args: &[Value<'gc>], + index: u8, ) -> Result, Error<'gc>> { - set_distance(activation, this, args.get(0..1).unwrap_or_default())?; - set_angle(activation, this, args.get(1..2).unwrap_or_default())?; - set_color(activation, this, args.get(2..3).unwrap_or_default())?; - set_alpha(activation, this, args.get(3..4).unwrap_or_default())?; - set_blur_x(activation, this, args.get(4..5).unwrap_or_default())?; - set_blur_y(activation, this, args.get(5..6).unwrap_or_default())?; - set_strength(activation, this, args.get(6..7).unwrap_or_default())?; - set_quality(activation, this, args.get(7..8).unwrap_or_default())?; - set_inner(activation, this, args.get(8..9).unwrap_or_default())?; - set_knockout(activation, this, args.get(9..10).unwrap_or_default())?; - set_hide_object(activation, this, args.get(10..11).unwrap_or_default())?; + const CONSTRUCTOR: u8 = 0; + const GET_DISTANCE: u8 = 1; + const SET_DISTANCE: u8 = 2; + const GET_ANGLE: u8 = 3; + const SET_ANGLE: u8 = 4; + const GET_COLOR: u8 = 5; + const SET_COLOR: u8 = 6; + const GET_ALPHA: u8 = 7; + const SET_ALPHA: u8 = 8; + const GET_QUALITY: u8 = 9; + const SET_QUALITY: u8 = 10; + const GET_INNER: u8 = 11; + const SET_INNER: u8 = 12; + const GET_KNOCKOUT: u8 = 13; + const SET_KNOCKOUT: u8 = 14; + const GET_BLUR_X: u8 = 15; + const SET_BLUR_X: u8 = 16; + const GET_BLUR_Y: u8 = 17; + const SET_BLUR_Y: u8 = 18; + const GET_STRENGTH: u8 = 19; + const SET_STRENGTH: u8 = 20; + const GET_HIDE_OBJECT: u8 = 21; + const SET_HIDE_OBJECT: u8 = 22; - Ok(this.into()) -} - -pub fn alpha<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.alpha().into()); + if index == CONSTRUCTOR { + let drop_shadow_filter = DropShadowFilter::new(activation, args)?; + this.set_native( + activation.context.gc_context, + NativeObject::DropShadowFilter(drop_shadow_filter), + ); + return Ok(this.into()); } - Ok(Value::Undefined) -} - -pub fn set_alpha<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let alpha = args - .get(0) - .unwrap_or(&1.into()) - .coerce_to_f64(activation) - .map(|x| x.clamp_also_nan(0.0, 1.0))?; - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_alpha(activation.context.gc_context, alpha); - } - - Ok(Value::Undefined) -} - -pub fn distance<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.distance().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_distance<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let distance = args.get(0).unwrap_or(&4.into()).coerce_to_f64(activation)?; - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_distance(activation.context.gc_context, distance); - } - - Ok(Value::Undefined) -} - -pub fn angle<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.angle().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_angle<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let angle = args - .get(0) - .unwrap_or(&44.9999999772279.into()) - .coerce_to_f64(activation)?; - - let clamped_angle = if angle.is_sign_negative() { - -(angle.abs() % 360.0) - } else { - angle % 360.0 + let this = match this.native() { + NativeObject::DropShadowFilter(drop_shadow_filter) => drop_shadow_filter, + _ => return Ok(Value::Undefined), }; - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_angle(activation.context.gc_context, clamped_angle); - } - - Ok(Value::Undefined) + Ok(match index { + GET_DISTANCE => this.distance().into(), + SET_DISTANCE => { + this.set_distance(activation, args.get(0))?; + Value::Undefined + } + GET_ANGLE => this.angle().into(), + SET_ANGLE => { + this.set_angle(activation, args.get(0))?; + Value::Undefined + } + GET_COLOR => this.color().into(), + SET_COLOR => { + this.set_color(activation, args.get(0))?; + Value::Undefined + } + GET_ALPHA => this.alpha().into(), + SET_ALPHA => { + this.set_alpha(activation, args.get(0))?; + Value::Undefined + } + GET_QUALITY => this.quality().into(), + SET_QUALITY => { + this.set_quality(activation, args.get(0))?; + Value::Undefined + } + GET_INNER => this.inner().into(), + SET_INNER => { + this.set_inner(activation, args.get(0))?; + Value::Undefined + } + GET_KNOCKOUT => this.knockout().into(), + SET_KNOCKOUT => { + this.set_knockout(activation, args.get(0))?; + Value::Undefined + } + GET_BLUR_X => this.blur_x().into(), + SET_BLUR_X => { + this.set_blur_x(activation, args.get(0))?; + Value::Undefined + } + GET_BLUR_Y => this.blur_y().into(), + SET_BLUR_Y => { + this.set_blur_y(activation, args.get(0))?; + Value::Undefined + } + GET_STRENGTH => this.strength().into(), + SET_STRENGTH => { + this.set_strength(activation, args.get(0))?; + Value::Undefined + } + GET_HIDE_OBJECT => this.hide_object().into(), + SET_HIDE_OBJECT => { + this.set_hide_object(activation, args.get(0))?; + Value::Undefined + } + _ => Value::Undefined, + }) } -pub fn blur_x<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.blur_x().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_blur_x<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let blur_x = args - .get(0) - .unwrap_or(&4.into()) - .coerce_to_f64(activation) - .map(|x| x.clamp(0.0, 255.0))?; - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_blur_x(activation.context.gc_context, blur_x); - } - - Ok(Value::Undefined) -} - -pub fn blur_y<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.blur_y().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_blur_y<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let blur_y = args - .get(0) - .unwrap_or(&4.into()) - .coerce_to_f64(activation) - .map(|x| x.clamp(0.0, 255.0))?; - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_blur_y(activation.context.gc_context, blur_y); - } - - Ok(Value::Undefined) -} - -pub fn color<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.color().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_color<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let color = args - .get(0) - .unwrap_or(&0x000000.into()) - .coerce_to_u32(activation)?; - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_color(activation.context.gc_context, color & 0xFFFFFF); - } - - Ok(Value::Undefined) -} - -pub fn hide_object<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.hide_object().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_hide_object<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let hide_object = args - .get(0) - .unwrap_or(&false.into()) - .as_bool(activation.swf_version()); - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_hide_object(activation.context.gc_context, hide_object); - } - - Ok(Value::Undefined) -} - -pub fn inner<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.inner().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_inner<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let inner = args - .get(0) - .unwrap_or(&false.into()) - .as_bool(activation.swf_version()); - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_inner(activation.context.gc_context, inner); - } - - Ok(Value::Undefined) -} - -pub fn knockout<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.knockout().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_knockout<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let knockout = args - .get(0) - .unwrap_or(&false.into()) - .as_bool(activation.swf_version()); - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_knockout(activation.context.gc_context, knockout); - } - - Ok(Value::Undefined) -} - -pub fn quality<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.quality().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_quality<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let quality = args - .get(0) - .unwrap_or(&1.into()) - .coerce_to_i32(activation) - .map(|x| x.clamp(0, 15))?; - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_quality(activation.context.gc_context, quality); - } - - Ok(Value::Undefined) -} - -pub fn strength<'gc>( - _activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - if let Some(object) = this.as_drop_shadow_filter_object() { - return Ok(object.strength().into()); - } - - Ok(Value::Undefined) -} - -pub fn set_strength<'gc>( - activation: &mut Activation<'_, 'gc>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - let strength = args - .get(0) - .unwrap_or(&1.into()) - .coerce_to_f64(activation) - .map(|x| x.clamp_also_nan(0.0, 255.0))?; - - if let Some(object) = this.as_drop_shadow_filter_object() { - object.set_strength(activation.context.gc_context, strength); - } - - Ok(Value::Undefined) -} - -pub fn create_proto<'gc>( +pub fn create_constructor<'gc>( gc_context: MutationContext<'gc, '_>, proto: Object<'gc>, fn_proto: Object<'gc>, ) -> Object<'gc> { - let drop_shadow_filter = DropShadowFilterObject::empty_object(gc_context, proto); - let object = drop_shadow_filter.raw_script_object(); - define_properties_on(PROTO_DECLS, gc_context, object, fn_proto); - drop_shadow_filter.into() + let drop_shadow_filter_proto = ScriptObject::new(gc_context, Some(proto)); + define_properties_on(PROTO_DECLS, gc_context, drop_shadow_filter_proto, fn_proto); + FunctionObject::constructor( + gc_context, + Executable::Native(drop_shadow_filter_method!(0)), + constructor_to_fn!(drop_shadow_filter_method!(0)), + fn_proto, + drop_shadow_filter_proto.into(), + ) } diff --git a/core/src/avm1/object.rs b/core/src/avm1/object.rs index 8e4b7f0d7..a7187fadc 100644 --- a/core/src/avm1/object.rs +++ b/core/src/avm1/object.rs @@ -5,13 +5,13 @@ use crate::avm1::globals::bevel_filter::BevelFilter; use crate::avm1::globals::blur_filter::BlurFilter; use crate::avm1::globals::color_transform::ColorTransformObject; use crate::avm1::globals::date::Date; +use crate::avm1::globals::drop_shadow_filter::DropShadowFilter; use crate::avm1::globals::glow_filter::GlowFilter; use crate::avm1::object::array_object::ArrayObject; use crate::avm1::object::bitmap_data::BitmapDataObject; use crate::avm1::object::color_matrix_filter::ColorMatrixFilterObject; use crate::avm1::object::convolution_filter::ConvolutionFilterObject; use crate::avm1::object::displacement_map_filter::DisplacementMapFilterObject; -use crate::avm1::object::drop_shadow_filter::DropShadowFilterObject; use crate::avm1::object::gradient_bevel_filter::GradientBevelFilterObject; use crate::avm1::object::gradient_glow_filter::GradientGlowFilterObject; use crate::avm1::object::shared_object::SharedObject; @@ -37,7 +37,6 @@ pub mod color_matrix_filter; pub mod convolution_filter; mod custom_object; pub mod displacement_map_filter; -pub mod drop_shadow_filter; pub mod gradient_bevel_filter; pub mod gradient_glow_filter; pub mod script_object; @@ -58,6 +57,7 @@ pub enum NativeObject<'gc> { BlurFilter(BlurFilter<'gc>), BevelFilter(BevelFilter<'gc>), GlowFilter(GlowFilter<'gc>), + DropShadowFilter(DropShadowFilter<'gc>), ColorTransform(GcCell<'gc, ColorTransformObject>), TextFormat(GcCell<'gc, TextFormat>), NetStream(NetStream<'gc>), @@ -81,7 +81,6 @@ pub enum NativeObject<'gc> { FunctionObject(FunctionObject<'gc>), SharedObject(SharedObject<'gc>), TransformObject(TransformObject<'gc>), - DropShadowFilterObject(DropShadowFilterObject<'gc>), ColorMatrixFilterObject(ColorMatrixFilterObject<'gc>), DisplacementMapFilterObject(DisplacementMapFilterObject<'gc>), ConvolutionFilterObject(ConvolutionFilterObject<'gc>), @@ -609,11 +608,6 @@ pub trait TObject<'gc>: 'gc + Collect + Into> + Clone + Copy { None } - /// Get the underlying `DropShadowFilterObject`, if it exists - fn as_drop_shadow_filter_object(&self) -> Option> { - None - } - /// Get the underlying `ColorMatrixFilterObject`, if it exists fn as_color_matrix_filter_object(&self) -> Option> { None diff --git a/core/src/avm1/object/drop_shadow_filter.rs b/core/src/avm1/object/drop_shadow_filter.rs deleted file mode 100644 index e0341f90a..000000000 --- a/core/src/avm1/object/drop_shadow_filter.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::add_field_accessors; -use crate::avm1::{Object, ScriptObject, TObject}; -use crate::impl_custom_object; -use gc_arena::{Collect, GcCell, MutationContext}; - -use std::fmt; - -/// A DropShadowFilter -#[derive(Clone, Copy, Collect)] -#[collect(no_drop)] -pub struct DropShadowFilterObject<'gc>(GcCell<'gc, DropShadowFilterData<'gc>>); - -#[derive(Clone, Collect)] -#[collect(no_drop)] -pub struct DropShadowFilterData<'gc> { - /// The underlying script object. - base: ScriptObject<'gc>, - - alpha: f64, - angle: f64, - blur_x: f64, - blur_y: f64, - color: u32, - distance: f64, - hide_object: bool, - inner: bool, - knockout: bool, - quality: i32, - strength: f64, -} - -impl fmt::Debug for DropShadowFilterObject<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let this = self.0.read(); - f.debug_struct("DropShadowFilter") - .field("alpha", &this.alpha) - .field("angle", &this.angle) - .field("blurX", &this.blur_x) - .field("blurY", &this.blur_y) - .field("color", &this.color) - .field("distance", &this.distance) - .field("hide_object", &this.hide_object) - .field("inner", &this.inner) - .field("knockout", &this.knockout) - .field("quality", &this.quality) - .field("strength", &this.strength) - .finish() - } -} - -impl<'gc> DropShadowFilterObject<'gc> { - add_field_accessors!( - [set_alpha, alpha, alpha, f64], - [set_angle, angle, angle, f64], - [set_blur_x, blur_x, blur_x, f64], - [set_blur_y, blur_y, blur_y, f64], - [set_color, color, color, u32], - [set_hide_object, hide_object, hide_object, bool], - [set_distance, distance, distance, f64], - [set_inner, inner, inner, bool], - [set_knockout, knockout, knockout, bool], - [set_quality, quality, quality, i32], - [set_strength, strength, strength, f64], - ); - - pub fn empty_object(gc_context: MutationContext<'gc, '_>, proto: Object<'gc>) -> Self { - DropShadowFilterObject(GcCell::allocate( - gc_context, - DropShadowFilterData { - base: ScriptObject::new(gc_context, Some(proto)), - distance: 4.0, - hide_object: false, - angle: 44.9999999772279, - color: 0x000000, - alpha: 1.0, - blur_x: 4.0, - blur_y: 4.0, - strength: 1.0, - quality: 1, - inner: false, - knockout: false, - }, - )) - } -} - -impl<'gc> TObject<'gc> for DropShadowFilterObject<'gc> { - impl_custom_object!(base { - bare_object(as_drop_shadow_filter_object -> DropShadowFilterObject::empty_object); - }); -}