diff --git a/core/src/avm1/globals/bevel_filter.rs b/core/src/avm1/globals/bevel_filter.rs index 06e138009..a2d8b4ce0 100644 --- a/core/src/avm1/globals/bevel_filter.rs +++ b/core/src/avm1/globals/bevel_filter.rs @@ -3,7 +3,7 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; use crate::avm1::function::{Executable, FunctionObject}; -use crate::avm1::object::bevel_filter::{BevelFilterType, BevelFilterObject}; +use crate::avm1::object::bevel_filter::{BevelFilterObject, BevelFilterType}; use crate::avm1::{AvmString, Object, TObject, Value}; use enumset::EnumSet; use gc_arena::MutationContext; @@ -15,34 +15,48 @@ pub fn constructor<'gc>( ) -> Result, Error<'gc>> { let distance = args .get(0) - .unwrap_or(&4.into()) - .coerce_to_f64(activation) - .map(|x| x.max(0.0).min(255.0))?; + .unwrap_or(&4.0.into()) + .coerce_to_f64(activation)?; let angle = args .get(1) - .unwrap_or(&45.0.into()) - .coerce_to_f64(activation) - .map(|x| x.max(0.0).min(360.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 + }; - //TODO: range let highlight_color = args .get(2) - .unwrap_or(&0x000000.into()) + .unwrap_or(&0xFFFFFF.into()) .coerce_to_i32(activation)?; + let highlight_color_clamped = if highlight_color.is_negative() { + 0x1000000 - (highlight_color.abs() % 0x1000000) + } else { + highlight_color % (0x1000000) + }; + let highlight_alpha = args .get(3) .unwrap_or(&1.into()) .coerce_to_f64(activation) .map(|x| x.max(0.0).min(1.0))?; - //TODO: range let shadow_color = args .get(4) .unwrap_or(&0x000000.into()) .coerce_to_i32(activation)?; + let shadow_color_clamped = if shadow_color.is_negative() { + 0x1000000 - (shadow_color.abs() % 0x1000000) + } else { + shadow_color % (0x1000000) + }; + let shadow_alpha = args .get(5) .unwrap_or(&1.into()) @@ -87,10 +101,10 @@ pub fn constructor<'gc>( let bevel_filter = this.as_bevel_filter_object().unwrap(); bevel_filter.set_distance(activation.context.gc_context, distance); - bevel_filter.set_angle(activation.context.gc_context, angle); - bevel_filter.set_highlight_color(activation.context.gc_context, highlight_color); + bevel_filter.set_angle(activation.context.gc_context, clamped_angle); + bevel_filter.set_highlight_color(activation.context.gc_context, highlight_color_clamped); bevel_filter.set_highlight_alpha(activation.context.gc_context, highlight_alpha); - bevel_filter.set_shadow_color(activation.context.gc_context, shadow_color); + bevel_filter.set_shadow_color(activation.context.gc_context, shadow_color_clamped); bevel_filter.set_shadow_alpha(activation.context.gc_context, shadow_alpha); bevel_filter.set_blur_x(activation.context.gc_context, blur_x); bevel_filter.set_blur_y(activation.context.gc_context, blur_y); @@ -102,23 +116,14 @@ pub fn constructor<'gc>( Ok(Value::Undefined) } -pub fn clone<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Object<'gc>, - args: &[Value<'gc>], -) -> Result, Error<'gc>> { - Ok(Value::Undefined) -} - pub fn get_distance<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this.as_bevel_filter_object().unwrap().get_distance().into()) } -//TODO: check if int? pub fn set_distance<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, @@ -137,9 +142,9 @@ pub fn set_distance<'gc>( } pub fn get_angle<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this.as_bevel_filter_object().unwrap().get_angle().into()) } @@ -151,21 +156,26 @@ pub fn set_angle<'gc>( ) -> Result, Error<'gc>> { let angle = args .get(0) - .unwrap_or(&45.0.into()) - .coerce_to_f64(activation) - .map(|x| x.max(0.0).min(360.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 + }; this.as_bevel_filter_object() .unwrap() - .set_angle(activation.context.gc_context, angle); + .set_angle(activation.context.gc_context, clamped_angle); Ok(Value::Undefined) } pub fn get_highlight_color<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this .as_bevel_filter_object() @@ -182,19 +192,25 @@ pub fn set_highlight_color<'gc>( let color = args .get(0) .unwrap_or(&0x000000.into()) - .coerce_to_i32(activation) - .map(|x| x.max(0x000000).min(0xFFFFFF))?; + .coerce_to_i32(activation)?; + + let col = if color.is_negative() { + 0x1000000 - (color.abs() % 0x1000000) + } else { + color % (0x1000000) + }; this.as_bevel_filter_object() .unwrap() - .set_highlight_color(activation.context.gc_context, color); + .set_highlight_color(activation.context.gc_context, col); - Ok(Value::Undefined)} + Ok(Value::Undefined) +} pub fn get_highlight_alpha<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this .as_bevel_filter_object() @@ -222,9 +238,9 @@ pub fn set_highlight_alpha<'gc>( } pub fn get_shadow_color<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this .as_bevel_filter_object() @@ -238,13 +254,28 @@ pub fn set_shadow_color<'gc>( this: Object<'gc>, args: &[Value<'gc>], ) -> Result, Error<'gc>> { + let color = args + .get(0) + .unwrap_or(&0x000000.into()) + .coerce_to_i32(activation)?; + + let col = if color.is_negative() { + 0x1000000 - (color.abs() % 0x1000000) + } else { + color % (0x1000000) + }; + + this.as_bevel_filter_object() + .unwrap() + .set_shadow_color(activation.context.gc_context, col); + Ok(Value::Undefined) } pub fn get_shadow_alpha<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this .as_bevel_filter_object() @@ -258,13 +289,23 @@ pub fn set_shadow_alpha<'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.max(0.0).min(1.0))?; + + this.as_bevel_filter_object() + .unwrap() + .set_shadow_alpha(activation.context.gc_context, alpha); + Ok(Value::Undefined) } pub fn get_quality<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this.as_bevel_filter_object().unwrap().get_quality().into()) } @@ -288,11 +329,11 @@ pub fn set_quality<'gc>( } pub fn get_strength<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Value::Undefined) + Ok(this.as_bevel_filter_object().unwrap().get_strength().into()) } pub fn set_strength<'gc>( @@ -300,15 +341,25 @@ pub fn set_strength<'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.max(0.0).min(255.0))?; + + this.as_bevel_filter_object() + .unwrap() + .set_strength(activation.context.gc_context, strength); + Ok(Value::Undefined) } pub fn get_knockout<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { - Ok(Value::Undefined) + Ok(this.as_bevel_filter_object().unwrap().get_knockout().into()) } pub fn set_knockout<'gc>( @@ -316,13 +367,22 @@ pub fn set_knockout<'gc>( this: Object<'gc>, args: &[Value<'gc>], ) -> Result, Error<'gc>> { + let knockout = args + .get(0) + .unwrap_or(&false.into()) + .as_bool(activation.current_swf_version()); + + this.as_bevel_filter_object() + .unwrap() + .set_knockout(activation.context.gc_context, knockout); + Ok(Value::Undefined) } pub fn get_blur_x<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this.as_bevel_filter_object().unwrap().get_blur_x().into()) } @@ -346,9 +406,9 @@ pub fn set_blur_x<'gc>( } pub fn get_blur_y<'gc>( - activation: &mut Activation<'_, 'gc, '_>, + _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { Ok(this.as_bevel_filter_object().unwrap().get_blur_y().into()) } @@ -374,7 +434,7 @@ pub fn set_blur_y<'gc>( pub fn get_type<'gc>( activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, - args: &[Value<'gc>], + _args: &[Value<'gc>], ) -> Result, Error<'gc>> { let type_: &str = this.as_bevel_filter_object().unwrap().get_type().into(); Ok(AvmString::new(activation.context.gc_context, type_.to_string()).into()) @@ -387,7 +447,10 @@ pub fn set_type<'gc>( ) -> Result, Error<'gc>> { let type_: BevelFilterType = args .get(0) - .unwrap_or(&Value::String(AvmString::new(activation.context.gc_context, "full".to_string()))) + .unwrap_or(&Value::String(AvmString::new( + activation.context.gc_context, + "full".to_string(), + ))) .coerce_to_string(activation) .map(|s| s.as_str().into())?; @@ -403,9 +466,8 @@ pub fn create_proto<'gc>( fn_proto: Object<'gc>, ) -> Object<'gc> { let object = BevelFilterObject::empty_object(gc_context, Some(proto)); - let mut script_object = object.as_script_object().unwrap(); + let script_object = object.as_script_object().unwrap(); - script_object.force_set_function("clone", clone, gc_context, EnumSet::empty(), Some(proto)); script_object.add_property( gc_context, "distance", @@ -610,5 +672,5 @@ pub fn create_proto<'gc>( )), EnumSet::empty(), ); - script_object.into() + object.into() } diff --git a/core/src/avm1/globals/bitmap_filter.rs b/core/src/avm1/globals/bitmap_filter.rs index e4bc6f3d2..8dd3da877 100644 --- a/core/src/avm1/globals/bitmap_filter.rs +++ b/core/src/avm1/globals/bitmap_filter.rs @@ -2,7 +2,7 @@ use crate::avm1::activation::Activation; use crate::avm1::error::Error; -use crate::avm1::{Object, ScriptObject, Value}; +use crate::avm1::{Object, ScriptObject, TObject, Value}; use enumset::EnumSet; use gc_arena::MutationContext; @@ -15,10 +15,57 @@ pub fn constructor<'gc>( } pub fn clone<'gc>( - _activation: &mut Activation<'_, 'gc, '_>, - _this: Object<'gc>, + activation: &mut Activation<'_, 'gc, '_>, + this: Object<'gc>, _args: &[Value<'gc>], ) -> Result, 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.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.into()); + } + Ok(Value::Undefined) } diff --git a/core/src/avm1/globals/blur_filter.rs b/core/src/avm1/globals/blur_filter.rs index 11b6e5ba6..2ff0b81e9 100644 --- a/core/src/avm1/globals/blur_filter.rs +++ b/core/src/avm1/globals/blur_filter.rs @@ -40,21 +40,6 @@ pub fn constructor<'gc>( Ok(Value::Undefined) } -pub fn clone<'gc>( - activation: &mut Activation<'_, 'gc, '_>, - this: Object<'gc>, - _args: &[Value<'gc>], -) -> Result, Error<'gc>> { - 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])?; - Ok(cloned.into()) -} - pub fn get_blur_x<'gc>( _activation: &mut Activation<'_, 'gc, '_>, this: Object<'gc>, @@ -139,9 +124,7 @@ pub fn create_proto<'gc>( fn_proto: Object<'gc>, ) -> Object<'gc> { let blur_filter = BlurFilterObject::empty_object(gc_context, Some(proto)); - let mut object = blur_filter.as_script_object().unwrap(); - - object.force_set_function("clone", clone, gc_context, EnumSet::empty(), Some(fn_proto)); + let object = blur_filter.as_script_object().unwrap(); object.add_property( gc_context, diff --git a/core/src/avm1/object/bevel_filter.rs b/core/src/avm1/object/bevel_filter.rs index 4e221f2d4..27991d7b3 100644 --- a/core/src/avm1/object/bevel_filter.rs +++ b/core/src/avm1/object/bevel_filter.rs @@ -47,7 +47,6 @@ pub struct BevelFilterData<'gc> { /// The underlying script object. base: ScriptObject<'gc>, - //TODO: is this an int angle: f64, blur_x: f64, blur_y: f64, @@ -104,7 +103,7 @@ impl<'gc> BevelFilterObject<'gc> { [set_shadow_alpha, get_shadow_alpha, shadow_alpha, f64], [set_shadow_color, get_shadow_color, shadow_color, i32], [set_strength, get_strength, strength, f64], - [set_type, get_type, type_, BevelFilterType], //TODO: type + [set_type, get_type, type_, BevelFilterType], ); pub fn empty_object(gc_context: MutationContext<'gc, '_>, proto: Option>) -> Self { @@ -112,17 +111,17 @@ impl<'gc> BevelFilterObject<'gc> { gc_context, BevelFilterData { base: ScriptObject::object(gc_context, proto), - angle: 45.0, + angle: 44.9999999772279, blur_x: 4.0, blur_y: 4.0, - distance: 4.0, // TODO: check if int + distance: 4.0, highlight_alpha: 1.0, - highlight_color: 0xFFFFFF.into(), //TODO: int? + highlight_color: 0xFFFFFF, knockout: false, - quality: 1, //TODO: must be int!! + quality: 1, shadow_alpha: 1.0, - shadow_color: 0x000000.into(), //TODO: is int? - strength: 1.0, // Int? + shadow_color: 0x000000, + strength: 1.0, type_: BevelFilterType::Inner, }, )) diff --git a/core/tests/swfs/avm1/bevel_filter/output.txt b/core/tests/swfs/avm1/bevel_filter/output.txt index 707921354..8d2cee918 100644 --- a/core/tests/swfs/avm1/bevel_filter/output.txt +++ b/core/tests/swfs/avm1/bevel_filter/output.txt @@ -28,6 +28,8 @@ false 1 // x.type inner +// x.angle (after set to 360) +0 // x.angle (after set to 361) 1 // x.blurX(after set to 100) @@ -36,6 +38,8 @@ inner 100 // x.distance (after set to 1000) 1000 +// x.distance (after set to 2.5) +2.5 // x.highlightAlpha (after set to 1.5) 1 // x.highlightColor (after set to 0x1000000) @@ -50,6 +54,8 @@ inner 0 // x.strength (after set to 256) 255 +// x.strength (after set to 1.5) +1.5 // x.angle (after set to -1) -1 // x.angle (after set to -366) @@ -64,6 +70,8 @@ inner 0 // x.highlightColor (after set to -1) 16777215 +// x.highlightColor (after set to -10) +16777206 // x.quality(after set to 2.5) 2 // x.quality(after set to -1) @@ -72,6 +80,8 @@ inner 0 // x.shadowColor (after set to -1) 16777215 +// x.shadowColor (after set to -0x11234567) +14465689 // x.strength (after set to -1) 0 // x.type (after set to "invalid") diff --git a/core/tests/swfs/avm1/bevel_filter/test.fla b/core/tests/swfs/avm1/bevel_filter/test.fla index fe4958926..9b287e00a 100644 Binary files a/core/tests/swfs/avm1/bevel_filter/test.fla and b/core/tests/swfs/avm1/bevel_filter/test.fla differ diff --git a/core/tests/swfs/avm1/bevel_filter/test.swf b/core/tests/swfs/avm1/bevel_filter/test.swf index 547e5a674..0151b3911 100644 Binary files a/core/tests/swfs/avm1/bevel_filter/test.swf and b/core/tests/swfs/avm1/bevel_filter/test.swf differ