Skip to content

Commit

Permalink
avm1: Migrate BlurFilter to NativeObject
Browse files Browse the repository at this point in the history
  • Loading branch information
relrelb committed Oct 15, 2022
1 parent 178bf4f commit 1cbc906
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 187 deletions.
17 changes: 3 additions & 14 deletions core/src/avm1/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub(crate) mod as_broadcaster;
mod bevel_filter;
mod bitmap_data;
mod bitmap_filter;
mod blur_filter;
pub(crate) mod blur_filter;
pub(crate) mod boolean;
pub(crate) mod button;
mod color;
Expand Down Expand Up @@ -498,8 +498,6 @@ pub struct SystemPrototypes<'gc> {
pub context_menu_item_constructor: Object<'gc>,
pub bitmap_filter: Object<'gc>,
pub bitmap_filter_constructor: Object<'gc>,
pub blur_filter: Object<'gc>,
pub blur_filter_constructor: Object<'gc>,
pub bevel_filter: Object<'gc>,
pub bevel_filter_constructor: Object<'gc>,
pub glow_filter: Object<'gc>,
Expand Down Expand Up @@ -753,15 +751,8 @@ pub fn create_globals<'gc>(
bitmap_filter_proto,
);

let blur_filter_proto =
blur_filter::create_proto(gc_context, bitmap_filter_proto, function_proto);
let blur_filter = FunctionObject::constructor(
gc_context,
Executable::Native(blur_filter::constructor),
constructor_to_fn!(blur_filter::constructor),
function_proto,
blur_filter_proto,
);
let blur_filter =
blur_filter::create_constructor(gc_context, bitmap_filter_proto, function_proto);

let bevel_filter_proto =
bevel_filter::create_proto(gc_context, bitmap_filter_proto, function_proto);
Expand Down Expand Up @@ -1157,8 +1148,6 @@ pub fn create_globals<'gc>(
context_menu_item_constructor: context_menu_item,
bitmap_filter: bitmap_filter_proto,
bitmap_filter_constructor: bitmap_filter,
blur_filter: blur_filter_proto,
blur_filter_constructor: blur_filter,
bevel_filter: bevel_filter_proto,
bevel_filter_constructor: bevel_filter,
glow_filter: glow_filter_proto,
Expand Down
36 changes: 25 additions & 11 deletions core/src/avm1/globals/bitmap_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
use crate::avm1::activation::Activation;
use crate::avm1::error::Error;
use crate::avm1::object::NativeObject;
use crate::avm1::property_decl::{define_properties_on, Declaration};
use crate::avm1::{Object, ScriptObject, TObject, Value};
use gc_arena::MutationContext;
use crate::avm1::{Attribute, Object, ScriptObject, TObject, Value};
use gc_arena::{GcCell, MutationContext};

const PROTO_DECLS: &[Declaration] = declare_properties! {
"clone" => method(clone);
Expand All @@ -23,15 +24,28 @@ pub fn clone<'gc>(
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(this) = this.as_blur_filter_object() {
let proto = activation.context.avm1.prototypes().blur_filter_constructor;

let blur_x = this.get("blurX", activation)?;
let blur_y = this.get("blurY", activation)?;
let quality = this.get("quality", activation)?;

let cloned = proto.construct(activation, &[blur_x, blur_y, quality])?;
return Ok(cloned);
let native = match this.native() {
NativeObject::BlurFilter(blur_filter) => NativeObject::BlurFilter(GcCell::allocate(
activation.context.gc_context,
blur_filter.read().clone(),
)),
_ => NativeObject::None,
};
if !matches!(native, NativeObject::None) {
let proto = this.get_local_stored("__proto__", activation);
let cloned = ScriptObject::new(activation.context.gc_context, None);
// Set `__proto__` manually since `ScriptObject::new()` doesn't support primitive prototypes.
// TODO: Pass `proto` to `ScriptObject::new()` once possible.
if let Some(proto) = proto {
cloned.define_value(
activation.context.gc_context,
"__proto__",
proto,
Attribute::DONT_ENUM | Attribute::DONT_DELETE,
);
}
cloned.set_native(activation.context.gc_context, native);
return Ok(cloned.into());
}

if let Some(this) = this.as_bevel_filter_object() {
Expand Down
200 changes: 105 additions & 95 deletions core/src/avm1/globals/blur_filter.rs
Original file line number Diff line number Diff line change
@@ -1,127 +1,137 @@
//! flash.filters.BlurFilter object
use crate::avm1::activation::Activation;
use crate::avm1::error::Error;
use crate::avm1::object::blur_filter::BlurFilterObject;
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};

#[derive(Clone, Debug, Collect)]
#[collect(require_static)]
pub struct BlurFilterObject {
blur_x: f64,
blur_y: f64,
quality: i32,
}

macro_rules! blur_filter_method {
($index:literal) => {
|activation, this, args| method(activation, this, args, $index)
};
}

const PROTO_DECLS: &[Declaration] = declare_properties! {
"blurX" => property(blur_x, set_blur_x);
"blurY" => property(get_blur_y, set_blur_y);
"quality" => property(get_quality, set_quality);
"blurX" => property(blur_filter_method!(1), blur_filter_method!(2));
"blurY" => property(blur_filter_method!(3), blur_filter_method!(4));
"quality" => property(blur_filter_method!(5), blur_filter_method!(6));
};

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_blur_x(activation, this, args.get(0..1).unwrap_or_default())?;
set_blur_y(activation, this, args.get(1..2).unwrap_or_default())?;
set_quality(activation, this, args.get(2..3).unwrap_or_default())?;

Ok(this.into())
}

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_blur_filter_object() {
return Ok(filter.blur_x().into());
const CONSTRUCTOR: u8 = 0;
const GET_BLUR_X: u8 = 1;
const SET_BLUR_X: u8 = 2;
const GET_BLUR_Y: u8 = 3;
const SET_BLUR_Y: u8 = 4;
const GET_QUALITY: u8 = 5;
const SET_QUALITY: u8 = 6;

if index == CONSTRUCTOR {
let blur_filter = GcCell::allocate(
activation.context.gc_context,
BlurFilterObject {
blur_x: 4.0,
blur_y: 4.0,
quality: 1,
},
);
set_blur_x(activation, blur_filter, args.get(0))?;
set_blur_y(activation, blur_filter, args.get(1))?;
set_quality(activation, blur_filter, args.get(2))?;
this.set_native(
activation.context.gc_context,
NativeObject::BlurFilter(blur_filter),
);
return Ok(this.into());
}

Ok(this.into())
let blur_filter = match this.native() {
NativeObject::BlurFilter(blur_filter) => blur_filter,
_ => return Ok(Value::Undefined),
};

Ok(match index {
GET_BLUR_X => blur_filter.read().blur_x.into(),
SET_BLUR_X => {
set_blur_x(activation, blur_filter, args.get(0))?;
Value::Undefined
}
GET_BLUR_Y => blur_filter.read().blur_y.into(),
SET_BLUR_Y => {
set_blur_y(activation, blur_filter, args.get(0))?;
Value::Undefined
}
GET_QUALITY => blur_filter.read().quality.into(),
SET_QUALITY => {
set_quality(activation, blur_filter, args.get(0))?;
Value::Undefined
}
_ => Value::Undefined,
})
}

pub fn set_blur_x<'gc>(
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_blur_filter_object() {
filter.set_blur_x(activation.context.gc_context, blur_x);
blur_filter: GcCell<'gc, BlurFilterObject>,
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);
blur_filter.write(activation.context.gc_context).blur_x = blur_x;
}

Ok(Value::Undefined)
Ok(())
}

pub fn get_blur_y<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_blur_filter_object() {
return Ok(filter.blur_y().into());
}

Ok(Value::Undefined)
}

pub fn set_blur_y<'gc>(
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_blur_filter_object() {
filter.set_blur_y(activation.context.gc_context, blur_y);
blur_filter: GcCell<'gc, BlurFilterObject>,
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);
blur_filter.write(activation.context.gc_context).blur_y = blur_y;
}

Ok(Value::Undefined)
Ok(())
}

pub fn get_quality<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
if let Some(filter) = this.as_blur_filter_object() {
return Ok(filter.quality().into());
}

Ok(Value::Undefined)
}

pub fn set_quality<'gc>(
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_blur_filter_object() {
filter.set_quality(activation.context.gc_context, quality);
blur_filter: GcCell<'gc, BlurFilterObject>,
value: Option<&Value<'gc>>,
) -> Result<(), Error<'gc>> {
if let Some(value) = value {
let quality = value.coerce_to_i32(activation)?.clamp(0, 15);
blur_filter.write(activation.context.gc_context).quality = quality;
}

Ok(Value::Undefined)
Ok(())
}

pub fn create_proto<'gc>(
pub fn create_constructor<'gc>(
gc_context: MutationContext<'gc, '_>,
proto: Object<'gc>,
fn_proto: Object<'gc>,
) -> Object<'gc> {
let blur_filter = BlurFilterObject::empty_object(gc_context, proto);
let object = blur_filter.as_script_object().unwrap();
define_properties_on(PROTO_DECLS, gc_context, object, fn_proto);
blur_filter.into()
let blur_filter_proto = ScriptObject::new(gc_context, Some(proto));
define_properties_on(PROTO_DECLS, gc_context, blur_filter_proto, fn_proto);
FunctionObject::constructor(
gc_context,
Executable::Native(blur_filter_method!(0)),
constructor_to_fn!(blur_filter_method!(0)),
fn_proto,
blur_filter_proto.into(),
)
}
10 changes: 2 additions & 8 deletions core/src/avm1/object.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! Object trait to expose objects to AVM
use crate::avm1::function::{Executable, ExecutionName, ExecutionReason, FunctionObject};
use crate::avm1::globals::blur_filter::BlurFilterObject;
use crate::avm1::globals::color_transform::ColorTransformObject;
use crate::avm1::globals::date::Date;
use crate::avm1::object::array_object::ArrayObject;
use crate::avm1::object::bevel_filter::BevelFilterObject;
use crate::avm1::object::bitmap_data::BitmapDataObject;
use crate::avm1::object::blur_filter::BlurFilterObject;
use crate::avm1::object::color_matrix_filter::ColorMatrixFilterObject;
use crate::avm1::object::convolution_filter::ConvolutionFilterObject;
use crate::avm1::object::displacement_map_filter::DisplacementMapFilterObject;
Expand All @@ -32,7 +32,6 @@ use std::fmt::Debug;
pub mod array_object;
pub mod bevel_filter;
pub mod bitmap_data;
pub mod blur_filter;
pub mod color_matrix_filter;
pub mod convolution_filter;
mod custom_object;
Expand All @@ -56,6 +55,7 @@ pub mod xml_object;
pub enum NativeObject<'gc> {
None,
Date(GcCell<'gc, Date>),
BlurFilter(GcCell<'gc, BlurFilterObject>),
ColorTransform(GcCell<'gc, ColorTransformObject>),
TextFormat(GcCell<'gc, TextFormat>),
}
Expand All @@ -78,7 +78,6 @@ pub enum NativeObject<'gc> {
FunctionObject(FunctionObject<'gc>),
SharedObject(SharedObject<'gc>),
TransformObject(TransformObject<'gc>),
BlurFilterObject(BlurFilterObject<'gc>),
BevelFilterObject(BevelFilterObject<'gc>),
GlowFilterObject(GlowFilterObject<'gc>),
DropShadowFilterObject(DropShadowFilterObject<'gc>),
Expand Down Expand Up @@ -557,11 +556,6 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
None
}

/// Get the underlying `BlurFilterObject`, if it exists
fn as_blur_filter_object(&self) -> Option<BlurFilterObject<'gc>> {
None
}

/// Get the underlying `BevelFilterObject`, if it exists
fn as_bevel_filter_object(&self) -> Option<BevelFilterObject<'gc>> {
None
Expand Down
Loading

0 comments on commit 1cbc906

Please sign in to comment.