avm1: Migrate `BevelFilter` to `NativeObject`

This commit is contained in:
relrelb 2022-10-15 19:44:32 +03:00 committed by relrelb
parent 37f171de06
commit 760f9e29df
9 changed files with 528 additions and 585 deletions

View File

@ -13,7 +13,7 @@ use std::str;
mod accessibility; mod accessibility;
mod array; mod array;
pub(crate) mod as_broadcaster; pub(crate) mod as_broadcaster;
mod bevel_filter; pub(crate) mod bevel_filter;
mod bitmap_data; mod bitmap_data;
mod bitmap_filter; mod bitmap_filter;
pub(crate) mod blur_filter; pub(crate) mod blur_filter;
@ -498,8 +498,6 @@ pub struct SystemPrototypes<'gc> {
pub context_menu_item_constructor: Object<'gc>, pub context_menu_item_constructor: Object<'gc>,
pub bitmap_filter: Object<'gc>, pub bitmap_filter: Object<'gc>,
pub bitmap_filter_constructor: Object<'gc>, pub bitmap_filter_constructor: Object<'gc>,
pub bevel_filter: Object<'gc>,
pub bevel_filter_constructor: Object<'gc>,
pub glow_filter: Object<'gc>, pub glow_filter: Object<'gc>,
pub glow_filter_constructor: Object<'gc>, pub glow_filter_constructor: Object<'gc>,
pub drop_shadow_filter: Object<'gc>, pub drop_shadow_filter: Object<'gc>,
@ -754,15 +752,8 @@ pub fn create_globals<'gc>(
let blur_filter = let blur_filter =
blur_filter::create_constructor(gc_context, bitmap_filter_proto, function_proto); blur_filter::create_constructor(gc_context, bitmap_filter_proto, function_proto);
let bevel_filter_proto = let bevel_filter =
bevel_filter::create_proto(gc_context, bitmap_filter_proto, function_proto); bevel_filter::create_constructor(gc_context, bitmap_filter_proto, function_proto);
let bevel_filter = FunctionObject::constructor(
gc_context,
Executable::Native(bevel_filter::constructor),
constructor_to_fn!(bevel_filter::constructor),
function_proto,
bevel_filter_proto,
);
let glow_filter_proto = let glow_filter_proto =
glow_filter::create_proto(gc_context, bitmap_filter_proto, function_proto); glow_filter::create_proto(gc_context, bitmap_filter_proto, function_proto);
@ -1148,8 +1139,6 @@ pub fn create_globals<'gc>(
context_menu_item_constructor: context_menu_item, context_menu_item_constructor: context_menu_item,
bitmap_filter: bitmap_filter_proto, bitmap_filter: bitmap_filter_proto,
bitmap_filter_constructor: bitmap_filter, bitmap_filter_constructor: bitmap_filter,
bevel_filter: bevel_filter_proto,
bevel_filter_constructor: bevel_filter,
glow_filter: glow_filter_proto, glow_filter: glow_filter_proto,
glow_filter_constructor: glow_filter, glow_filter_constructor: glow_filter,
drop_shadow_filter: drop_shadow_filter_proto, drop_shadow_filter: drop_shadow_filter_proto,

View File

@ -1,415 +1,539 @@
//! flash.filters.BevelFilter object //! flash.filters.BevelFilter object
use crate::avm1::activation::Activation; use crate::avm1::function::{Executable, FunctionObject};
use crate::avm1::error::Error; use crate::avm1::object::NativeObject;
use crate::avm1::object::bevel_filter::{BevelFilterObject, BevelFilterType};
use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{Object, TObject, Value}; use crate::avm1::{Activation, Error, Object, ScriptObject, TObject, Value};
use crate::string::{AvmString, WStr}; use crate::string::{AvmString, WStr};
use gc_arena::MutationContext; use gc_arena::{Collect, GcCell, MutationContext};
use swf::Color;
#[derive(Copy, Clone, Debug, Collect)]
#[collect(no_drop)]
pub enum BevelFilterType {
Inner,
Outer,
Full,
}
impl From<&WStr> for BevelFilterType {
fn from(value: &WStr) -> Self {
if value == b"inner" {
Self::Inner
} else if value == b"outer" {
Self::Outer
} else {
Self::Full
}
}
}
impl From<BevelFilterType> for &'static WStr {
fn from(type_: BevelFilterType) -> &'static WStr {
match type_ {
BevelFilterType::Inner => WStr::from_units(b"inner"),
BevelFilterType::Outer => WStr::from_units(b"outer"),
BevelFilterType::Full => WStr::from_units(b"full"),
}
}
}
#[derive(Clone, Debug, Collect)]
#[collect(require_static)]
pub struct BevelFilterObject {
distance: f64,
// TODO: Introduce `Angle<Radians>` struct.
angle: f64,
highlight: Color,
shadow: Color,
quality: i32,
// TODO: Introduce unsigned `Fixed8`?
strength: u16,
knockout: bool,
blur_x: f64,
blur_y: f64,
type_: BevelFilterType,
}
impl BevelFilterObject {
fn new<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
args: &[Value<'gc>],
) -> Result<GcCell<'gc, Self>, Error<'gc>> {
let bevel_filter = GcCell::allocate(activation.context.gc_context, Default::default());
bevel_filter.set_distance(activation, args.get(0))?;
bevel_filter.set_angle(activation, args.get(1))?;
bevel_filter.set_highlight_color(activation, args.get(2))?;
bevel_filter.set_highlight_alpha(activation, args.get(3))?;
bevel_filter.set_shadow_color(activation, args.get(4))?;
bevel_filter.set_shadow_alpha(activation, args.get(5))?;
bevel_filter.set_blur_x(activation, args.get(6))?;
bevel_filter.set_blur_y(activation, args.get(7))?;
bevel_filter.set_strength(activation, args.get(8))?;
bevel_filter.set_quality(activation, args.get(9))?;
bevel_filter.set_type(activation, args.get(10))?;
bevel_filter.set_knockout(activation, args.get(11))?;
Ok(bevel_filter)
}
}
impl Default for BevelFilterObject {
#[allow(clippy::approx_constant)]
fn default() -> Self {
Self {
distance: 4.0,
angle: 0.785398163, // ~45 degrees
highlight: Color::WHITE,
shadow: Color::BLACK,
quality: 1,
strength: 1 << 8,
knockout: false,
blur_x: 4.0,
blur_y: 4.0,
type_: BevelFilterType::Inner,
}
}
}
trait BevelFilterExt<'gc> {
fn distance(self) -> f64;
fn set_distance(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn angle(self) -> f64;
fn set_angle(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn highlight_color(self) -> i32;
fn set_highlight_color(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn highlight_alpha(self) -> f64;
fn set_highlight_alpha(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn shadow_color(self) -> i32;
fn set_shadow_color(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn shadow_alpha(self) -> f64;
fn set_shadow_alpha(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn quality(self) -> i32;
fn set_quality(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn strength(self) -> f64;
fn set_strength(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn knockout(self) -> bool;
fn set_knockout(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn blur_x(self) -> f64;
fn set_blur_x(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn blur_y(self) -> f64;
fn set_blur_y(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
fn type_(self) -> BevelFilterType;
fn set_type(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>>;
}
impl<'gc> BevelFilterExt<'gc> for GcCell<'gc, BevelFilterObject> {
fn distance(self) -> f64 {
self.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.write(activation.context.gc_context).distance = distance;
}
Ok(())
}
fn angle(self) -> f64 {
self.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.write(activation.context.gc_context).angle = angle;
}
Ok(())
}
fn highlight_color(self) -> i32 {
self.read().highlight.to_rgb() as i32
}
fn set_highlight_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.write(activation.context.gc_context).highlight = color;
}
Ok(())
}
fn highlight_alpha(self) -> f64 {
f64::from(self.read().highlight.a) / 255.0
}
fn set_highlight_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.write(activation.context.gc_context).highlight.a = alpha;
}
Ok(())
}
fn shadow_color(self) -> i32 {
self.read().shadow.to_rgb() as i32
}
fn set_shadow_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.write(activation.context.gc_context).shadow = color;
}
Ok(())
}
fn shadow_alpha(self) -> f64 {
f64::from(self.read().shadow.a) / 255.0
}
fn set_shadow_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.write(activation.context.gc_context).shadow.a = alpha;
}
Ok(())
}
fn quality(self) -> i32 {
self.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.write(activation.context.gc_context).quality = quality;
}
Ok(())
}
fn strength(self) -> f64 {
f64::from(self.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.write(activation.context.gc_context).strength = strength;
}
Ok(())
}
fn knockout(self) -> bool {
self.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.write(activation.context.gc_context).knockout = knockout;
}
Ok(())
}
fn blur_x(self) -> f64 {
self.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.write(activation.context.gc_context).blur_x = blur_x;
}
Ok(())
}
fn blur_y(self) -> f64 {
self.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.write(activation.context.gc_context).blur_y = blur_y;
}
Ok(())
}
fn type_(self) -> BevelFilterType {
self.read().type_
}
fn set_type(
self,
activation: &mut Activation<'_, 'gc, '_>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>> {
if let Some(value) = value {
let type_ = value.coerce_to_string(activation)?.as_wstr().into();
self.write(activation.context.gc_context).type_ = type_;
}
Ok(())
}
}
macro_rules! bevel_filter_method {
($index:literal) => {
|activation, this, args| method(activation, this, args, $index)
};
}
const PROTO_DECLS: &[Declaration] = declare_properties! { const PROTO_DECLS: &[Declaration] = declare_properties! {
"distance" => property(distance, set_distance); "distance" => property(bevel_filter_method!(1), bevel_filter_method!(2));
"angle" => property(angle, set_angle); "angle" => property(bevel_filter_method!(3), bevel_filter_method!(4));
"highlightColor" => property(highlight_color, set_highlight_color); "highlightColor" => property(bevel_filter_method!(5), bevel_filter_method!(6));
"highlightAlpha" => property(highlight_alpha, set_highlight_alpha); "highlightAlpha" => property(bevel_filter_method!(7), bevel_filter_method!(8));
"shadowColor" => property(shadow_color, set_shadow_color); "shadowColor" => property(bevel_filter_method!(9), bevel_filter_method!(10));
"shadowAlpha" => property(shadow_alpha, set_shadow_alpha); "shadowAlpha" => property(bevel_filter_method!(11), bevel_filter_method!(12));
"quality" => property(quality, set_quality); "quality" => property(bevel_filter_method!(13), bevel_filter_method!(14));
"strength" => property(strength, set_strength); "strength" => property(bevel_filter_method!(15), bevel_filter_method!(16));
"knockout" => property(knockout, set_knockout); "knockout" => property(bevel_filter_method!(17), bevel_filter_method!(18));
"blurX" => property(blur_x, set_blur_x); "blurX" => property(bevel_filter_method!(19), bevel_filter_method!(20));
"blurY" => property(blur_y, set_blur_y); "blurY" => property(bevel_filter_method!(21), bevel_filter_method!(22));
"type" => property(get_type, set_type); "type" => property(bevel_filter_method!(23), bevel_filter_method!(24));
}; };
pub fn constructor<'gc>( fn method<'gc>(
activation: &mut Activation<'_, 'gc, '_>, activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>, this: Object<'gc>,
args: &[Value<'gc>], args: &[Value<'gc>],
index: u8,
) -> Result<Value<'gc>, Error<'gc>> { ) -> Result<Value<'gc>, Error<'gc>> {
set_distance(activation, this, args.get(0..1).unwrap_or_default())?; const CONSTRUCTOR: u8 = 0;
set_angle(activation, this, args.get(1..2).unwrap_or_default())?; const GET_DISTANCE: u8 = 1;
set_highlight_color(activation, this, args.get(2..3).unwrap_or_default())?; const SET_DISTANCE: u8 = 2;
set_highlight_alpha(activation, this, args.get(3..4).unwrap_or_default())?; const GET_ANGLE: u8 = 3;
set_shadow_color(activation, this, args.get(4..5).unwrap_or_default())?; const SET_ANGLE: u8 = 4;
set_shadow_alpha(activation, this, args.get(5..6).unwrap_or_default())?; const GET_HIGHLIGHT_COLOR: u8 = 5;
set_blur_x(activation, this, args.get(6..7).unwrap_or_default())?; const SET_HIGHLIGHT_COLOR: u8 = 6;
set_blur_y(activation, this, args.get(7..8).unwrap_or_default())?; const GET_HIGHLIGHT_ALPHA: u8 = 7;
set_strength(activation, this, args.get(8..9).unwrap_or_default())?; const SET_HIGHLIGHT_ALPHA: u8 = 8;
set_quality(activation, this, args.get(9..10).unwrap_or_default())?; const GET_SHADOW_COLOR: u8 = 9;
set_type(activation, this, args.get(10..11).unwrap_or_default())?; const SET_SHADOW_COLOR: u8 = 10;
set_knockout(activation, this, args.get(11..12).unwrap_or_default())?; const GET_SHADOW_ALPHA: u8 = 11;
const SET_SHADOW_ALPHA: u8 = 12;
const GET_QUALITY: u8 = 13;
const SET_QUALITY: u8 = 14;
const GET_STRENGTH: u8 = 15;
const SET_STRENGTH: u8 = 16;
const GET_KNOCKOUT: u8 = 17;
const SET_KNOCKOUT: u8 = 18;
const GET_BLUR_X: u8 = 19;
const SET_BLUR_X: u8 = 20;
const GET_BLUR_Y: u8 = 21;
const SET_BLUR_Y: u8 = 22;
const GET_TYPE: u8 = 23;
const SET_TYPE: u8 = 24;
Ok(this.into()) if index == CONSTRUCTOR {
let bevel_filter = BevelFilterObject::new(activation, args)?;
this.set_native(
activation.context.gc_context,
NativeObject::BevelFilter(bevel_filter),
);
return Ok(this.into());
} }
pub fn distance<'gc>( let this = match this.native() {
_activation: &mut Activation<'_, 'gc, '_>, NativeObject::BevelFilter(bevel_filter) => bevel_filter,
this: Object<'gc>, _ => return Ok(Value::Undefined),
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_bevel_filter_object() {
return Ok(filter.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(filter) = this.as_bevel_filter_object() {
filter.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(filter) = this.as_bevel_filter_object() {
return Ok(filter.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
}; };
if let Some(filter) = this.as_bevel_filter_object() { Ok(match index {
filter.set_angle(activation.context.gc_context, clamped_angle); 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_HIGHLIGHT_COLOR => this.highlight_color().into(),
SET_HIGHLIGHT_COLOR => {
this.set_highlight_color(activation, args.get(0))?;
Value::Undefined
}
GET_HIGHLIGHT_ALPHA => this.highlight_alpha().into(),
SET_HIGHLIGHT_ALPHA => {
this.set_highlight_alpha(activation, args.get(0))?;
Value::Undefined
}
GET_SHADOW_COLOR => this.shadow_color().into(),
SET_SHADOW_COLOR => {
this.set_shadow_color(activation, args.get(0))?;
Value::Undefined
}
GET_SHADOW_ALPHA => this.shadow_alpha().into(),
SET_SHADOW_ALPHA => {
this.set_shadow_alpha(activation, args.get(0))?;
Value::Undefined
}
GET_QUALITY => this.quality().into(),
SET_QUALITY => {
this.set_quality(activation, args.get(0))?;
Value::Undefined
}
GET_STRENGTH => this.strength().into(),
SET_STRENGTH => {
this.set_strength(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_TYPE => {
let type_: &WStr = this.type_().into();
AvmString::from(type_).into()
}
SET_TYPE => {
this.set_type(activation, args.get(0))?;
Value::Undefined
}
_ => Value::Undefined,
})
} }
Ok(Value::Undefined) pub fn create_constructor<'gc>(
}
pub fn highlight_color<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_bevel_filter_object() {
return Ok(filter.highlight_color().into());
}
Ok(Value::Undefined)
}
pub fn set_highlight_color<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let highlight_color = args
.get(0)
.unwrap_or(&0xFFFFFF.into())
.coerce_to_u32(activation)?;
if let Some(filter) = this.as_bevel_filter_object() {
filter.set_highlight_color(activation.context.gc_context, highlight_color & 0xFFFFFF);
}
Ok(Value::Undefined)
}
pub fn highlight_alpha<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_bevel_filter_object() {
return Ok(filter.highlight_alpha().into());
}
Ok(Value::Undefined)
}
pub fn set_highlight_alpha<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let highlight_alpha = args
.get(0)
.unwrap_or(&1.into())
.coerce_to_f64(activation)
.map(|x| x.clamp(0.0, 1.0))?;
if let Some(filter) = this.as_bevel_filter_object() {
filter.set_highlight_alpha(activation.context.gc_context, highlight_alpha);
}
Ok(Value::Undefined)
}
pub fn shadow_color<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_bevel_filter_object() {
return Ok(filter.shadow_color().into());
}
Ok(Value::Undefined)
}
pub fn set_shadow_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(filter) = this.as_bevel_filter_object() {
filter.set_shadow_color(activation.context.gc_context, color & 0xFFFFFF);
}
Ok(Value::Undefined)
}
pub fn shadow_alpha<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_bevel_filter_object() {
return Ok(filter.shadow_alpha().into());
}
Ok(Value::Undefined)
}
pub fn set_shadow_alpha<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let shadow_alpha = args
.get(0)
.unwrap_or(&1.into())
.coerce_to_f64(activation)
.map(|x| x.clamp(0.0, 1.0))?;
if let Some(filter) = this.as_bevel_filter_object() {
filter.set_shadow_alpha(activation.context.gc_context, shadow_alpha);
}
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(filter) = this.as_bevel_filter_object() {
return Ok(filter.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(filter) = this.as_bevel_filter_object() {
filter.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(filter) = this.as_bevel_filter_object() {
return Ok(filter.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(0.0, 255.0))?;
if let Some(filter) = this.as_bevel_filter_object() {
filter.set_strength(activation.context.gc_context, strength);
}
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(filter) = this.as_bevel_filter_object() {
return Ok(filter.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(filter) = this.as_bevel_filter_object() {
filter.set_knockout(activation.context.gc_context, knockout);
}
Ok(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(filter) = this.as_bevel_filter_object() {
return Ok(filter.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(filter) = this.as_bevel_filter_object() {
filter.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(filter) = this.as_bevel_filter_object() {
return Ok(filter.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(filter) = this.as_bevel_filter_object() {
filter.set_blur_y(activation.context.gc_context, blur_y);
}
Ok(Value::Undefined)
}
pub fn get_type<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_bevel_filter_object() {
let type_: &WStr = filter.get_type().into();
return Ok(AvmString::from(type_).into());
}
Ok(Value::Undefined)
}
pub fn set_type<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let type_: BevelFilterType = args
.get(0)
.unwrap_or(&"inner".into())
.coerce_to_string(activation)
.map(|s| s.as_wstr().into())?;
if let Some(filter) = this.as_bevel_filter_object() {
filter.set_type(activation.context.gc_context, type_);
}
Ok(Value::Undefined)
}
pub fn create_proto<'gc>(
gc_context: MutationContext<'gc, '_>, gc_context: MutationContext<'gc, '_>,
proto: Object<'gc>, proto: Object<'gc>,
fn_proto: Object<'gc>, fn_proto: Object<'gc>,
) -> Object<'gc> { ) -> Object<'gc> {
let object = BevelFilterObject::empty_object(gc_context, proto); let bevel_filter_proto = ScriptObject::new(gc_context, Some(proto));
let script_object = object.as_script_object().unwrap(); define_properties_on(PROTO_DECLS, gc_context, bevel_filter_proto, fn_proto);
define_properties_on(PROTO_DECLS, gc_context, script_object, fn_proto); FunctionObject::constructor(
object.into() gc_context,
Executable::Native(bevel_filter_method!(0)),
constructor_to_fn!(bevel_filter_method!(0)),
fn_proto,
bevel_filter_proto.into(),
)
} }

View File

@ -29,6 +29,10 @@ pub fn clone<'gc>(
activation.context.gc_context, activation.context.gc_context,
blur_filter.read().clone(), blur_filter.read().clone(),
)), )),
NativeObject::BevelFilter(bevel_filter) => NativeObject::BevelFilter(GcCell::allocate(
activation.context.gc_context,
bevel_filter.read().clone(),
)),
_ => NativeObject::None, _ => NativeObject::None,
}; };
if !matches!(native, NativeObject::None) { if !matches!(native, NativeObject::None) {
@ -48,46 +52,6 @@ pub fn clone<'gc>(
return Ok(cloned.into()); return Ok(cloned.into());
} }
if let Some(this) = this.as_bevel_filter_object() {
let proto = activation
.context
.avm1
.prototypes()
.bevel_filter_constructor;
let distance = this.get("distance", activation)?;
let angle = this.get("angle", activation)?;
let highlight_color = this.get("highlightColor", activation)?;
let highlight_alpha = this.get("highlightAlpha", activation)?;
let shadow_color = this.get("shadowColor", activation)?;
let shadow_alpha = this.get("shadowAlpha", 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 type_ = this.get("type", activation)?;
let knockout = this.get("knockout", activation)?;
let cloned = proto.construct(
activation,
&[
distance,
angle,
highlight_color,
highlight_alpha,
shadow_color,
shadow_alpha,
blur_x,
blur_y,
strength,
quality,
type_,
knockout,
],
)?;
return Ok(cloned);
}
if let Some(this) = this.as_glow_filter_object() { if let Some(this) = this.as_glow_filter_object() {
let proto = activation.context.avm1.prototypes().glow_filter_constructor; let proto = activation.context.avm1.prototypes().glow_filter_constructor;

View File

@ -2,7 +2,7 @@
use crate::avm1::activation::Activation; use crate::avm1::activation::Activation;
use crate::avm1::error::Error; use crate::avm1::error::Error;
use crate::avm1::object::bevel_filter::BevelFilterType; use crate::avm1::globals::bevel_filter::BevelFilterType;
use crate::avm1::object::gradient_bevel_filter::GradientBevelFilterObject; use crate::avm1::object::gradient_bevel_filter::GradientBevelFilterObject;
use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{ArrayObject, Object, TObject, Value}; use crate::avm1::{ArrayObject, Object, TObject, Value};

View File

@ -2,7 +2,7 @@
use crate::avm1::activation::Activation; use crate::avm1::activation::Activation;
use crate::avm1::error::Error; use crate::avm1::error::Error;
use crate::avm1::object::bevel_filter::BevelFilterType; use crate::avm1::globals::bevel_filter::BevelFilterType;
use crate::avm1::object::gradient_glow_filter::GradientGlowFilterObject; use crate::avm1::object::gradient_glow_filter::GradientGlowFilterObject;
use crate::avm1::property_decl::{define_properties_on, Declaration}; use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{ArrayObject, Object, TObject, Value}; use crate::avm1::{ArrayObject, Object, TObject, Value};

View File

@ -1,11 +1,11 @@
//! Object trait to expose objects to AVM //! Object trait to expose objects to AVM
use crate::avm1::function::{Executable, ExecutionName, ExecutionReason, FunctionObject}; use crate::avm1::function::{Executable, ExecutionName, ExecutionReason, FunctionObject};
use crate::avm1::globals::bevel_filter::BevelFilterObject;
use crate::avm1::globals::blur_filter::BlurFilterObject; use crate::avm1::globals::blur_filter::BlurFilterObject;
use crate::avm1::globals::color_transform::ColorTransformObject; use crate::avm1::globals::color_transform::ColorTransformObject;
use crate::avm1::globals::date::Date; 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::bitmap_data::BitmapDataObject; use crate::avm1::object::bitmap_data::BitmapDataObject;
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;
@ -30,7 +30,6 @@ use ruffle_macros::enum_trait_object;
use std::fmt::Debug; use std::fmt::Debug;
pub mod array_object; pub mod array_object;
pub mod bevel_filter;
pub mod bitmap_data; pub mod bitmap_data;
pub mod color_matrix_filter; pub mod color_matrix_filter;
pub mod convolution_filter; pub mod convolution_filter;
@ -56,6 +55,7 @@ pub enum NativeObject<'gc> {
None, None,
Date(GcCell<'gc, Date>), Date(GcCell<'gc, Date>),
BlurFilter(GcCell<'gc, BlurFilterObject>), BlurFilter(GcCell<'gc, BlurFilterObject>),
BevelFilter(GcCell<'gc, BevelFilterObject>),
ColorTransform(GcCell<'gc, ColorTransformObject>), ColorTransform(GcCell<'gc, ColorTransformObject>),
TextFormat(GcCell<'gc, TextFormat>), TextFormat(GcCell<'gc, TextFormat>),
} }
@ -78,7 +78,6 @@ pub enum NativeObject<'gc> {
FunctionObject(FunctionObject<'gc>), FunctionObject(FunctionObject<'gc>),
SharedObject(SharedObject<'gc>), SharedObject(SharedObject<'gc>),
TransformObject(TransformObject<'gc>), TransformObject(TransformObject<'gc>),
BevelFilterObject(BevelFilterObject<'gc>),
GlowFilterObject(GlowFilterObject<'gc>), GlowFilterObject(GlowFilterObject<'gc>),
DropShadowFilterObject(DropShadowFilterObject<'gc>), DropShadowFilterObject(DropShadowFilterObject<'gc>),
ColorMatrixFilterObject(ColorMatrixFilterObject<'gc>), ColorMatrixFilterObject(ColorMatrixFilterObject<'gc>),
@ -556,11 +555,6 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
None None
} }
/// Get the underlying `BevelFilterObject`, if it exists
fn as_bevel_filter_object(&self) -> Option<BevelFilterObject<'gc>> {
None
}
/// Get the underlying `GlowFilterObject`, if it exists /// Get the underlying `GlowFilterObject`, if it exists
fn as_glow_filter_object(&self) -> Option<GlowFilterObject<'gc>> { fn as_glow_filter_object(&self) -> Option<GlowFilterObject<'gc>> {
None None

View File

@ -1,126 +0,0 @@
use crate::add_field_accessors;
use crate::avm1::{Object, ScriptObject, TObject};
use crate::impl_custom_object;
use crate::string::WStr;
use gc_arena::{Collect, GcCell, MutationContext};
use std::fmt;
#[derive(Copy, Clone, Debug, Collect)]
#[collect(no_drop)]
pub enum BevelFilterType {
Inner,
Outer,
Full,
}
impl<'a> From<&'a WStr> for BevelFilterType {
fn from(value: &'a WStr) -> Self {
if value == b"inner" {
BevelFilterType::Inner
} else if value == b"outer" {
BevelFilterType::Outer
} else {
BevelFilterType::Full
}
}
}
impl From<BevelFilterType> for &'static WStr {
fn from(v: BevelFilterType) -> &'static WStr {
let s: &[u8] = match v {
BevelFilterType::Inner => b"inner",
BevelFilterType::Outer => b"outer",
BevelFilterType::Full => b"full",
};
WStr::from_units(s)
}
}
/// A BevelFilter
#[derive(Clone, Copy, Collect)]
#[collect(no_drop)]
pub struct BevelFilterObject<'gc>(GcCell<'gc, BevelFilterData<'gc>>);
#[derive(Clone, Collect)]
#[collect(no_drop)]
pub struct BevelFilterData<'gc> {
/// The underlying script object.
base: ScriptObject<'gc>,
angle: f64,
blur_x: f64,
blur_y: f64,
distance: f64,
highlight_alpha: f64,
highlight_color: u32,
knockout: bool,
quality: i32,
shadow_alpha: f64,
shadow_color: u32,
strength: f64,
type_: BevelFilterType,
}
impl fmt::Debug for BevelFilterObject<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let this = self.0.read();
f.debug_struct("BevelFilter")
.field("angle", &this.angle)
.field("blurX", &this.blur_x)
.field("blurY", &this.blur_y)
.field("distance", &this.distance)
.field("highlightAlpha", &this.highlight_alpha)
.field("highlightColor", &this.highlight_color)
.field("knockout", &this.knockout)
.field("quality", &this.quality)
.field("shadowAlpha", &this.shadow_alpha)
.field("strength", &this.strength)
.field("type", &this.type_)
.finish()
}
}
impl<'gc> BevelFilterObject<'gc> {
add_field_accessors!(
[set_angle, angle, angle, f64],
[set_blur_x, blur_x, blur_x, f64],
[set_blur_y, blur_y, blur_y, f64],
[set_distance, distance, distance, f64],
[set_highlight_alpha, highlight_alpha, highlight_alpha, f64],
[set_highlight_color, highlight_color, highlight_color, u32],
[set_knockout, knockout, knockout, bool],
[set_quality, quality, quality, i32],
[set_shadow_alpha, shadow_alpha, shadow_alpha, f64],
[set_shadow_color, shadow_color, shadow_color, u32],
[set_strength, strength, strength, f64],
[set_type, get_type, type_, BevelFilterType],
);
pub fn empty_object(gc_context: MutationContext<'gc, '_>, proto: Object<'gc>) -> Self {
BevelFilterObject(GcCell::allocate(
gc_context,
BevelFilterData {
base: ScriptObject::new(gc_context, Some(proto)),
angle: 44.9999999772279,
blur_x: 4.0,
blur_y: 4.0,
distance: 4.0,
highlight_alpha: 1.0,
highlight_color: 0xFFFFFF,
knockout: false,
quality: 1,
shadow_alpha: 1.0,
shadow_color: 0x000000,
strength: 1.0,
type_: BevelFilterType::Inner,
},
))
}
}
impl<'gc> TObject<'gc> for BevelFilterObject<'gc> {
impl_custom_object!(base {
bare_object(as_bevel_filter_object -> BevelFilterObject::empty_object);
});
}

View File

@ -1,9 +1,8 @@
use crate::add_field_accessors; use crate::add_field_accessors;
use crate::avm1::globals::bevel_filter::BevelFilterType;
use crate::avm1::{Object, ScriptObject, TObject}; use crate::avm1::{Object, ScriptObject, TObject};
use crate::impl_custom_object; use crate::impl_custom_object;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use crate::avm1::object::bevel_filter::BevelFilterType;
use std::fmt; use std::fmt;
/// A GradientBevelFilter /// A GradientBevelFilter

View File

@ -1,9 +1,8 @@
use crate::add_field_accessors; use crate::add_field_accessors;
use crate::avm1::globals::bevel_filter::BevelFilterType;
use crate::avm1::{Object, ScriptObject, TObject}; use crate::avm1::{Object, ScriptObject, TObject};
use crate::impl_custom_object; use crate::impl_custom_object;
use gc_arena::{Collect, GcCell, MutationContext}; use gc_arena::{Collect, GcCell, MutationContext};
use crate::avm1::object::bevel_filter::BevelFilterType;
use std::fmt; use std::fmt;
/// A GradientGlowFilter /// A GradientGlowFilter