avm1: Migrate `DropShadowFilter` to `NativeObject`

This commit is contained in:
relrelb 2023-03-29 23:46:08 +03:00 committed by relrelb
parent 814cb00821
commit 3dcf246870
5 changed files with 374 additions and 509 deletions

View File

@ -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,

View File

@ -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

View File

@ -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<Radians>` 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<Self, Error<'gc>> {
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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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<Value<'gc>, 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(),
)
}

View File

@ -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<Object<'gc>> + Clone + Copy {
None
}
/// Get the underlying `DropShadowFilterObject`, if it exists
fn as_drop_shadow_filter_object(&self) -> Option<DropShadowFilterObject<'gc>> {
None
}
/// Get the underlying `ColorMatrixFilterObject`, if it exists
fn as_color_matrix_filter_object(&self) -> Option<ColorMatrixFilterObject<'gc>> {
None

View File

@ -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);
});
}