diff --git a/core/src/avm2/filters.rs b/core/src/avm2/filters.rs index 9eabf515a..6ab278dbc 100644 --- a/core/src/avm2/filters.rs +++ b/core/src/avm2/filters.rs @@ -28,47 +28,47 @@ impl FilterAvm2Ext for Filter { ) -> Result> { let bevel_filter = activation.avm2().classes().bevelfilter; if object.is_of_type(bevel_filter, activation) { - return BevelFilter::from_avm2_object(activation, object); + return avm2_to_bevel_filter(activation, object); } let blur_filter = activation.avm2().classes().blurfilter; if object.is_of_type(blur_filter, activation) { - return BlurFilter::from_avm2_object(activation, object); + return avm2_to_blur_filter(activation, object); } let color_matrix_filter = activation.avm2().classes().colormatrixfilter; if object.is_of_type(color_matrix_filter, activation) { - return ColorMatrixFilter::from_avm2_object(activation, object); + return avm2_to_color_matrix_filter(activation, object); } let convolution_filter = activation.avm2().classes().convolutionfilter; if object.is_of_type(convolution_filter, activation) { - return ConvolutionFilter::from_avm2_object(activation, object); + return avm2_to_convolution_filter(activation, object); } let displacement_map_filter = activation.avm2().classes().displacementmapfilter; if object.is_of_type(displacement_map_filter, activation) { - return DisplacementMapFilter::from_avm2_object(activation, object); + return avm2_to_displacement_map_filter(activation, object); } let drop_shadow_filter = activation.avm2().classes().dropshadowfilter; if object.is_of_type(drop_shadow_filter, activation) { - return DropShadowFilter::from_avm2_object(activation, object); + return avm2_to_drop_shadow_filter(activation, object); } let glow_filter = activation.avm2().classes().glowfilter; if object.is_of_type(glow_filter, activation) { - return GlowFilter::from_avm2_object(activation, object); + return avm2_to_glow_filter(activation, object); } let gradient_bevel_filter = activation.avm2().classes().gradientbevelfilter; if object.is_of_type(gradient_bevel_filter, activation) { - return GradientBevelFilter::from_avm2_object(activation, object); + return avm2_to_gradient_bevel_filter(activation, object); } let gradient_glow_filter = activation.avm2().classes().gradientglowfilter; if object.is_of_type(gradient_glow_filter, activation) { - return GradientGlowFilter::from_avm2_object(activation, object); + return avm2_to_gradient_glow_filter(activation, object); } Err(Error::AvmError(type_error( @@ -85,741 +85,732 @@ impl FilterAvm2Ext for Filter { activation: &mut Activation<'_, 'gc>, ) -> Result, Error<'gc>> { match self { - Filter::BevelFilter(filter) => filter.as_avm2_object(activation), - Filter::BlurFilter(filter) => filter.as_avm2_object(activation), - Filter::ColorMatrixFilter(filter) => filter.as_avm2_object(activation), - Filter::ConvolutionFilter(filter) => filter.as_avm2_object(activation), - Filter::DisplacementMapFilter(filter) => filter.as_avm2_object(activation), - Filter::DropShadowFilter(filter) => filter.as_avm2_object(activation), - Filter::GlowFilter(filter) => filter.as_avm2_object(activation), - Filter::GradientBevelFilter(filter) => filter.as_avm2_object(activation), - Filter::GradientGlowFilter(filter) => filter.as_avm2_object(activation), - } - } -} - -impl FilterAvm2Ext for BevelFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let angle = object - .get_public_property("angle", activation)? - .coerce_to_number(activation)?; - let blur_x = object - .get_public_property("blurX", activation)? - .coerce_to_number(activation)?; - let blur_y = object - .get_public_property("blurY", activation)? - .coerce_to_number(activation)?; - let distance = object - .get_public_property("distance", activation)? - .coerce_to_number(activation)?; - let highlight_alpha = object - .get_public_property("highlightAlpha", activation)? - .coerce_to_number(activation)?; - let highlight_color = object - .get_public_property("highlightColor", activation)? - .coerce_to_u32(activation)?; - let knockout = object - .get_public_property("knockout", activation)? - .coerce_to_boolean(); - let quality = object - .get_public_property("quality", activation)? - .coerce_to_u32(activation)?; - let shadow_alpha = object - .get_public_property("shadowAlpha", activation)? - .coerce_to_number(activation)?; - let shadow_color = object - .get_public_property("shadowColor", activation)? - .coerce_to_u32(activation)?; - let strength = object - .get_public_property("strength", activation)? - .coerce_to_number(activation)?; - let bevel_type = object - .get_public_property("type", activation)? - .coerce_to_string(activation)?; - let mut flags = BevelFilterFlags::COMPOSITE_SOURCE; - if &bevel_type == b"inner" { - flags |= BevelFilterFlags::INNER_SHADOW; - } else if &bevel_type != b"outer" { - flags |= BevelFilterFlags::ON_TOP; - } - if knockout { - flags |= BevelFilterFlags::KNOCKOUT; - } - flags |= BevelFilterFlags::from_passes(quality.clamp(1, 15) as u8); - Ok(Filter::BevelFilter(BevelFilter { - shadow_color: Color::from_rgb(shadow_color, (shadow_alpha * 255.0) as u8), - highlight_color: Color::from_rgb(highlight_color, (highlight_alpha * 255.0) as u8), - blur_x: Fixed16::from_f64(blur_x.max(0.0)), - blur_y: Fixed16::from_f64(blur_y.max(0.0)), - angle: Fixed16::from_f64(angle.to_radians()), - distance: Fixed16::from_f64(distance), - strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), - flags, - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - activation.avm2().classes().bevelfilter.construct( - activation, - &[ - self.distance.to_f64().into(), - self.angle.to_f64().to_degrees().into(), - self.highlight_color.to_rgb().into(), - (f64::from(self.highlight_color.a) / 255.0).into(), - self.shadow_color.to_rgb().into(), - (f64::from(self.shadow_color.a) / 255.0).into(), - self.blur_x.to_f64().into(), - self.blur_y.to_f64().into(), - self.strength.to_f64().into(), - self.num_passes().into(), - if self.is_on_top() { - "full" - } else if self.is_inner() { - "inner" - } else { - "outer" - } - .into(), - self.is_knockout().into(), - ], - ) - } -} - -impl FilterAvm2Ext for BlurFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let blur_x = object - .get_public_property("blurX", activation)? - .coerce_to_number(activation)?; - let blur_y = object - .get_public_property("blurY", activation)? - .coerce_to_number(activation)?; - let quality = object - .get_public_property("quality", activation)? - .coerce_to_u32(activation)?; - Ok(Filter::BlurFilter(BlurFilter { - blur_x: Fixed16::from_f64(blur_x.max(0.0)), - blur_y: Fixed16::from_f64(blur_y.max(0.0)), - flags: BlurFilterFlags::from_passes(quality.clamp(1, 15) as u8), - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - activation.avm2().classes().blurfilter.construct( - activation, - &[ - self.blur_x.to_f64().into(), - self.blur_y.to_f64().into(), - self.num_passes().into(), - ], - ) - } -} - -impl FilterAvm2Ext for ColorMatrixFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let mut matrix = [0.0; 20]; - if let Some(matrix_object) = object - .get_public_property("matrix", activation)? - .as_object() - { - if let Some(array) = matrix_object.as_array_storage() { - for i in 0..matrix.len().min(array.length()) { - matrix[i] = array - .get(i) - .expect("Length was already checked at this point") - .coerce_to_number(activation)? as f32; - } + Filter::BevelFilter(filter) => bevel_filter_to_avm2(activation, filter), + Filter::BlurFilter(filter) => blur_filter_to_avm2(activation, filter), + Filter::ColorMatrixFilter(filter) => color_matrix_filter_to_avm2(activation, filter), + Filter::ConvolutionFilter(filter) => convolution_filter_to_avm2(activation, filter), + Filter::DisplacementMapFilter(filter) => { + displacement_map_filter_to_avm2(activation, filter) } - } - Ok(Filter::ColorMatrixFilter(ColorMatrixFilter { matrix })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - let matrix = ArrayObject::from_storage( - activation, - self.matrix.iter().map(|v| Value::from(*v)).collect(), - )?; - activation - .avm2() - .classes() - .colormatrixfilter - .construct(activation, &[matrix.into()]) - } -} - -impl FilterAvm2Ext for ConvolutionFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let mut matrix = vec![]; - if let Some(matrix_object) = object - .get_public_property("matrix", activation)? - .as_object() - { - if let Some(array) = matrix_object.as_array_storage() { - for value in array.iter() { - matrix.push(Fixed16::from_f64( - value - .unwrap_or(Value::Undefined) - .coerce_to_number(activation)?, - )); - } + Filter::DropShadowFilter(filter) => drop_shadow_filter_to_avm2(activation, filter), + Filter::GlowFilter(filter) => glow_filter_to_avm2(activation, filter), + Filter::GradientBevelFilter(filter) => { + gradient_bevel_filter_to_avm2(activation, filter) } + Filter::GradientGlowFilter(filter) => gradient_glow_filter_to_avm2(activation, filter), } - let alpha = object - .get_public_property("alpha", activation)? - .coerce_to_number(activation)?; - let bias = object - .get_public_property("bias", activation)? - .coerce_to_number(activation)?; - let clamp = object - .get_public_property("clamp", activation)? - .coerce_to_boolean(); - let color = object - .get_public_property("color", activation)? - .coerce_to_u32(activation)?; - let divisor = object - .get_public_property("divisor", activation)? - .coerce_to_number(activation)?; - let matrix_x = object - .get_public_property("matrixX", activation)? - .coerce_to_u32(activation)?; - let matrix_y = object - .get_public_property("matrixY", activation)? - .coerce_to_u32(activation)?; - let preserve_alpha = object - .get_public_property("preserveAlpha", activation)? - .coerce_to_boolean(); - let mut flags = ConvolutionFilterFlags::empty(); - if clamp { - flags |= ConvolutionFilterFlags::CLAMP - }; - if preserve_alpha { - flags |= ConvolutionFilterFlags::PRESERVE_ALPHA - }; - matrix.resize((matrix_x * matrix_y) as usize, Fixed16::ZERO); - Ok(Filter::ConvolutionFilter(ConvolutionFilter { - bias: Fixed16::from_f64(bias), - default_color: Color::from_rgb(color, (alpha * 255.0) as u8), - divisor: Fixed16::from_f64(divisor), - matrix, - num_matrix_cols: matrix_x.clamp(0, 255) as u8, - num_matrix_rows: matrix_y.clamp(0, 255) as u8, - flags, - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - let matrix = ArrayObject::from_storage( - activation, - self.matrix - .iter() - .map(|v| Value::from(v.to_f64())) - .collect(), - )?; - activation.avm2().classes().convolutionfilter.construct( - activation, - &[ - self.num_matrix_cols.into(), - self.num_matrix_rows.into(), - matrix.into(), - self.divisor.to_f64().into(), - self.bias.to_f64().into(), - self.is_preserve_alpha().into(), - self.is_clamped().into(), - self.default_color.to_rgb().into(), - (f64::from(self.default_color.a) / 255.0).into(), - ], - ) } } -impl FilterAvm2Ext for DisplacementMapFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let alpha = object - .get_public_property("alpha", activation)? - .coerce_to_number(activation)?; - let color = object - .get_public_property("color", activation)? - .coerce_to_u32(activation)?; - let component_x = object - .get_public_property("componentX", activation)? - .coerce_to_u32(activation)?; - let component_y = object - .get_public_property("componentY", activation)? - .coerce_to_u32(activation)?; - let map_point = - if let Value::Object(point) = object.get_public_property("mapPoint", activation)? { - ( - point - .get_public_property("x", activation)? - .coerce_to_i32(activation)?, - point - .get_public_property("y", activation)? - .coerce_to_i32(activation)?, - ) +fn avm2_to_bevel_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let angle = object + .get_public_property("angle", activation)? + .coerce_to_number(activation)?; + let blur_x = object + .get_public_property("blurX", activation)? + .coerce_to_number(activation)?; + let blur_y = object + .get_public_property("blurY", activation)? + .coerce_to_number(activation)?; + let distance = object + .get_public_property("distance", activation)? + .coerce_to_number(activation)?; + let highlight_alpha = object + .get_public_property("highlightAlpha", activation)? + .coerce_to_number(activation)?; + let highlight_color = object + .get_public_property("highlightColor", activation)? + .coerce_to_u32(activation)?; + let knockout = object + .get_public_property("knockout", activation)? + .coerce_to_boolean(); + let quality = object + .get_public_property("quality", activation)? + .coerce_to_u32(activation)?; + let shadow_alpha = object + .get_public_property("shadowAlpha", activation)? + .coerce_to_number(activation)?; + let shadow_color = object + .get_public_property("shadowColor", activation)? + .coerce_to_u32(activation)?; + let strength = object + .get_public_property("strength", activation)? + .coerce_to_number(activation)?; + let bevel_type = object + .get_public_property("type", activation)? + .coerce_to_string(activation)?; + let mut flags = BevelFilterFlags::COMPOSITE_SOURCE; + if &bevel_type == b"inner" { + flags |= BevelFilterFlags::INNER_SHADOW; + } else if &bevel_type != b"outer" { + flags |= BevelFilterFlags::ON_TOP; + } + if knockout { + flags |= BevelFilterFlags::KNOCKOUT; + } + flags |= BevelFilterFlags::from_passes(quality.clamp(1, 15) as u8); + Ok(Filter::BevelFilter(BevelFilter { + shadow_color: Color::from_rgb(shadow_color, (shadow_alpha * 255.0) as u8), + highlight_color: Color::from_rgb(highlight_color, (highlight_alpha * 255.0) as u8), + blur_x: Fixed16::from_f64(blur_x.max(0.0)), + blur_y: Fixed16::from_f64(blur_y.max(0.0)), + angle: Fixed16::from_f64(angle.to_radians()), + distance: Fixed16::from_f64(distance), + strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), + flags, + })) +} + +fn bevel_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &BevelFilter, +) -> Result, Error<'gc>> { + activation.avm2().classes().bevelfilter.construct( + activation, + &[ + filter.distance.to_f64().into(), + filter.angle.to_f64().to_degrees().into(), + filter.highlight_color.to_rgb().into(), + (f64::from(filter.highlight_color.a) / 255.0).into(), + filter.shadow_color.to_rgb().into(), + (f64::from(filter.shadow_color.a) / 255.0).into(), + filter.blur_x.to_f64().into(), + filter.blur_y.to_f64().into(), + filter.strength.to_f64().into(), + filter.num_passes().into(), + if filter.is_on_top() { + "full" + } else if filter.is_inner() { + "inner" } else { - (0, 0) - }; - let mode = if let Value::String(mode) = object.get_public_property("mode", activation)? { - if &mode == b"clamp" { - DisplacementMapFilterMode::Clamp - } else if &mode == b"ignore" { - DisplacementMapFilterMode::Ignore - } else if &mode == b"color" { - DisplacementMapFilterMode::Color - } else if &mode == b"wrap" { - DisplacementMapFilterMode::Wrap - } else { - return Err(Error::AvmError(argument_error( - activation, - "Parameter mode must be one of the accepted values.", - 2008, - )?)); + "outer" } + .into(), + filter.is_knockout().into(), + ], + ) +} + +fn avm2_to_blur_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let blur_x = object + .get_public_property("blurX", activation)? + .coerce_to_number(activation)?; + let blur_y = object + .get_public_property("blurY", activation)? + .coerce_to_number(activation)?; + let quality = object + .get_public_property("quality", activation)? + .coerce_to_u32(activation)?; + Ok(Filter::BlurFilter(BlurFilter { + blur_x: Fixed16::from_f64(blur_x.max(0.0)), + blur_y: Fixed16::from_f64(blur_y.max(0.0)), + flags: BlurFilterFlags::from_passes(quality.clamp(1, 15) as u8), + })) +} + +fn blur_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &BlurFilter, +) -> Result, Error<'gc>> { + activation.avm2().classes().blurfilter.construct( + activation, + &[ + filter.blur_x.to_f64().into(), + filter.blur_y.to_f64().into(), + filter.num_passes().into(), + ], + ) +} + +fn avm2_to_color_matrix_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let mut matrix = [0.0; 20]; + if let Some(matrix_object) = object + .get_public_property("matrix", activation)? + .as_object() + { + if let Some(array) = matrix_object.as_array_storage() { + for i in 0..matrix.len().min(array.length()) { + matrix[i] = array + .get(i) + .expect("Length was already checked at this point") + .coerce_to_number(activation)? as f32; + } + } + } + Ok(Filter::ColorMatrixFilter(ColorMatrixFilter { matrix })) +} + +fn color_matrix_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &ColorMatrixFilter, +) -> Result, Error<'gc>> { + let matrix = ArrayObject::from_storage( + activation, + filter.matrix.iter().map(|v| Value::from(*v)).collect(), + )?; + activation + .avm2() + .classes() + .colormatrixfilter + .construct(activation, &[matrix.into()]) +} + +fn avm2_to_convolution_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let mut matrix = vec![]; + if let Some(matrix_object) = object + .get_public_property("matrix", activation)? + .as_object() + { + if let Some(array) = matrix_object.as_array_storage() { + for value in array.iter() { + matrix.push(Fixed16::from_f64( + value + .unwrap_or(Value::Undefined) + .coerce_to_number(activation)?, + )); + } + } + } + let alpha = object + .get_public_property("alpha", activation)? + .coerce_to_number(activation)?; + let bias = object + .get_public_property("bias", activation)? + .coerce_to_number(activation)?; + let clamp = object + .get_public_property("clamp", activation)? + .coerce_to_boolean(); + let color = object + .get_public_property("color", activation)? + .coerce_to_u32(activation)?; + let divisor = object + .get_public_property("divisor", activation)? + .coerce_to_number(activation)?; + let matrix_x = object + .get_public_property("matrixX", activation)? + .coerce_to_u32(activation)?; + let matrix_y = object + .get_public_property("matrixY", activation)? + .coerce_to_u32(activation)?; + let preserve_alpha = object + .get_public_property("preserveAlpha", activation)? + .coerce_to_boolean(); + let mut flags = ConvolutionFilterFlags::empty(); + if clamp { + flags |= ConvolutionFilterFlags::CLAMP + }; + if preserve_alpha { + flags |= ConvolutionFilterFlags::PRESERVE_ALPHA + }; + matrix.resize((matrix_x * matrix_y) as usize, Fixed16::ZERO); + Ok(Filter::ConvolutionFilter(ConvolutionFilter { + bias: Fixed16::from_f64(bias), + default_color: Color::from_rgb(color, (alpha * 255.0) as u8), + divisor: Fixed16::from_f64(divisor), + matrix, + num_matrix_cols: matrix_x.clamp(0, 255) as u8, + num_matrix_rows: matrix_y.clamp(0, 255) as u8, + flags, + })) +} + +fn convolution_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &ConvolutionFilter, +) -> Result, Error<'gc>> { + let matrix = ArrayObject::from_storage( + activation, + filter + .matrix + .iter() + .map(|v| Value::from(v.to_f64())) + .collect(), + )?; + activation.avm2().classes().convolutionfilter.construct( + activation, + &[ + filter.num_matrix_cols.into(), + filter.num_matrix_rows.into(), + matrix.into(), + filter.divisor.to_f64().into(), + filter.bias.to_f64().into(), + filter.is_preserve_alpha().into(), + filter.is_clamped().into(), + filter.default_color.to_rgb().into(), + (f64::from(filter.default_color.a) / 255.0).into(), + ], + ) +} + +fn avm2_to_displacement_map_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let alpha = object + .get_public_property("alpha", activation)? + .coerce_to_number(activation)?; + let color = object + .get_public_property("color", activation)? + .coerce_to_u32(activation)?; + let component_x = object + .get_public_property("componentX", activation)? + .coerce_to_u32(activation)?; + let component_y = object + .get_public_property("componentY", activation)? + .coerce_to_u32(activation)?; + let map_point = + if let Value::Object(point) = object.get_public_property("mapPoint", activation)? { + ( + point + .get_public_property("x", activation)? + .coerce_to_i32(activation)?, + point + .get_public_property("y", activation)? + .coerce_to_i32(activation)?, + ) } else { - DisplacementMapFilterMode::Wrap + (0, 0) }; - let scale_x = object - .get_public_property("scaleX", activation)? - .coerce_to_number(activation)?; - let scale_y = object - .get_public_property("scaleY", activation)? - .coerce_to_number(activation)?; - let map_bitmap = if let Value::Object(bitmap) = - object.get_public_property("mapBitmap", activation)? - { + let mode = if let Value::String(mode) = object.get_public_property("mode", activation)? { + if &mode == b"clamp" { + DisplacementMapFilterMode::Clamp + } else if &mode == b"ignore" { + DisplacementMapFilterMode::Ignore + } else if &mode == b"color" { + DisplacementMapFilterMode::Color + } else if &mode == b"wrap" { + DisplacementMapFilterMode::Wrap + } else { + return Err(Error::AvmError(argument_error( + activation, + "Parameter mode must be one of the accepted values.", + 2008, + )?)); + } + } else { + DisplacementMapFilterMode::Wrap + }; + let scale_x = object + .get_public_property("scaleX", activation)? + .coerce_to_number(activation)?; + let scale_y = object + .get_public_property("scaleY", activation)? + .coerce_to_number(activation)?; + let map_bitmap = + if let Value::Object(bitmap) = object.get_public_property("mapBitmap", activation)? { if let Some(bitmap) = bitmap.as_bitmap_data() { bitmap .write(activation.context.gc_context) .bitmap_handle(activation.context.renderer) } else { return Err(Error::AvmError(type_error( - activation, - &format!("Type Coercion failed: cannot convert {bitmap:?} to flash.display.BitmapData."), - 1034, - )?)); + activation, + &format!( + "Type Coercion failed: cannot convert {bitmap:?} to flash.display.BitmapData." + ), + 1034, + )?)); } } else { None }; - Ok(Filter::DisplacementMapFilter(DisplacementMapFilter { - color: Color::from_rgb(color, (alpha * 255.0) as u8), - component_x: component_x as u8, - component_y: component_y as u8, - map_bitmap, - map_point, - mode, - scale_x: scale_x as f32, - scale_y: scale_y as f32, - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - let point = activation.avm2().classes().point; - let map_point = point.construct( - activation, - &[self.map_point.0.into(), self.map_point.1.into()], - )?; - let mode = match self.mode { - DisplacementMapFilterMode::Clamp => "clamp", - DisplacementMapFilterMode::Color => "color", - DisplacementMapFilterMode::Ignore => "ignore", - DisplacementMapFilterMode::Wrap => "wrap", - }; - activation.avm2().classes().displacementmapfilter.construct( - activation, - &[ - Value::Null, // TODO: This should be a BitmapData... - map_point.into(), - self.component_x.into(), - self.component_y.into(), - self.scale_x.into(), - self.scale_y.into(), - mode.into(), - self.color.to_rgb().into(), - (f64::from(self.color.a) / 255.0).into(), - ], - ) - } + Ok(Filter::DisplacementMapFilter(DisplacementMapFilter { + color: Color::from_rgb(color, (alpha * 255.0) as u8), + component_x: component_x as u8, + component_y: component_y as u8, + map_bitmap, + map_point, + mode, + scale_x: scale_x as f32, + scale_y: scale_y as f32, + })) } -impl FilterAvm2Ext for DropShadowFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let alpha = object - .get_public_property("alpha", activation)? - .coerce_to_number(activation)?; - let angle = object - .get_public_property("angle", activation)? - .coerce_to_number(activation)?; - let blur_x = object - .get_public_property("blurX", activation)? - .coerce_to_number(activation)?; - let blur_y = object - .get_public_property("blurY", activation)? - .coerce_to_number(activation)?; - let color = object - .get_public_property("color", activation)? - .coerce_to_u32(activation)?; - let distance = object - .get_public_property("distance", activation)? - .coerce_to_number(activation)?; - let hide_object = object - .get_public_property("hideObject", activation)? - .coerce_to_boolean(); - let inner = object - .get_public_property("inner", activation)? - .coerce_to_boolean(); - let knockout = object - .get_public_property("knockout", activation)? - .coerce_to_boolean(); - let quality = object - .get_public_property("quality", activation)? - .coerce_to_u32(activation)?; - let strength = object - .get_public_property("strength", activation)? - .coerce_to_number(activation)?; - let mut flags = DropShadowFilterFlags::empty(); - if !hide_object { - flags |= DropShadowFilterFlags::COMPOSITE_SOURCE - }; - if inner { - flags |= DropShadowFilterFlags::INNER_SHADOW - }; - if knockout { - flags |= DropShadowFilterFlags::KNOCKOUT - }; - flags |= DropShadowFilterFlags::from_passes(quality.clamp(1, 15) as u8); - Ok(Filter::DropShadowFilter(DropShadowFilter { - color: Color::from_rgb(color, (alpha * 255.0) as u8), - angle: Fixed16::from_f64(angle.to_radians()), - blur_x: Fixed16::from_f64(blur_x.max(0.0)), - blur_y: Fixed16::from_f64(blur_y.max(0.0)), - distance: Fixed16::from_f64(distance), - strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), - flags, - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - activation.avm2().classes().dropshadowfilter.construct( - activation, - &[ - self.distance.to_f64().into(), - self.angle.to_f64().to_degrees().into(), - self.color.to_rgb().into(), - (f64::from(self.color.a) / 255.0).into(), - self.blur_x.to_f64().into(), - self.blur_y.to_f64().into(), - self.strength.to_f64().into(), - self.num_passes().into(), - self.is_inner().into(), - self.is_knockout().into(), - self.hide_object().into(), - ], - ) - } +fn displacement_map_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &DisplacementMapFilter, +) -> Result, Error<'gc>> { + let point = activation.avm2().classes().point; + let map_point = point.construct( + activation, + &[filter.map_point.0.into(), filter.map_point.1.into()], + )?; + let mode = match filter.mode { + DisplacementMapFilterMode::Clamp => "clamp", + DisplacementMapFilterMode::Color => "color", + DisplacementMapFilterMode::Ignore => "ignore", + DisplacementMapFilterMode::Wrap => "wrap", + }; + activation.avm2().classes().displacementmapfilter.construct( + activation, + &[ + Value::Null, // TODO: This should be a BitmapData... + map_point.into(), + filter.component_x.into(), + filter.component_y.into(), + filter.scale_x.into(), + filter.scale_y.into(), + mode.into(), + filter.color.to_rgb().into(), + (f64::from(filter.color.a) / 255.0).into(), + ], + ) } -impl FilterAvm2Ext for GlowFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let alpha = object - .get_public_property("alpha", activation)? - .coerce_to_number(activation)?; - let blur_x = object - .get_public_property("blurX", activation)? - .coerce_to_number(activation)?; - let blur_y = object - .get_public_property("blurY", activation)? - .coerce_to_number(activation)?; - let color = object - .get_public_property("color", activation)? - .coerce_to_u32(activation)?; - let inner = object - .get_public_property("inner", activation)? - .coerce_to_boolean(); - let knockout = object - .get_public_property("knockout", activation)? - .coerce_to_boolean(); - let quality = object - .get_public_property("quality", activation)? - .coerce_to_u32(activation)?; - let strength = object - .get_public_property("strength", activation)? - .coerce_to_number(activation)?; - let mut flags = GlowFilterFlags::COMPOSITE_SOURCE; - if inner { - flags |= GlowFilterFlags::INNER_GLOW - }; - if knockout { - flags |= GlowFilterFlags::KNOCKOUT - }; - flags |= GlowFilterFlags::from_passes(quality.clamp(1, 15) as u8); - Ok(Filter::GlowFilter(GlowFilter { - color: Color::from_rgb(color, (alpha * 255.0) as u8), - blur_x: Fixed16::from_f64(blur_x.max(0.0)), - blur_y: Fixed16::from_f64(blur_y.max(0.0)), - strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), - flags, - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - activation.avm2().classes().glowfilter.construct( - activation, - &[ - self.color.to_rgb().into(), - (f64::from(self.color.a) / 255.0).into(), - self.blur_x.to_f64().into(), - self.blur_y.to_f64().into(), - self.strength.to_f64().into(), - self.num_passes().into(), - self.is_inner().into(), - self.is_knockout().into(), - ], - ) - } +fn avm2_to_drop_shadow_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let alpha = object + .get_public_property("alpha", activation)? + .coerce_to_number(activation)?; + let angle = object + .get_public_property("angle", activation)? + .coerce_to_number(activation)?; + let blur_x = object + .get_public_property("blurX", activation)? + .coerce_to_number(activation)?; + let blur_y = object + .get_public_property("blurY", activation)? + .coerce_to_number(activation)?; + let color = object + .get_public_property("color", activation)? + .coerce_to_u32(activation)?; + let distance = object + .get_public_property("distance", activation)? + .coerce_to_number(activation)?; + let hide_object = object + .get_public_property("hideObject", activation)? + .coerce_to_boolean(); + let inner = object + .get_public_property("inner", activation)? + .coerce_to_boolean(); + let knockout = object + .get_public_property("knockout", activation)? + .coerce_to_boolean(); + let quality = object + .get_public_property("quality", activation)? + .coerce_to_u32(activation)?; + let strength = object + .get_public_property("strength", activation)? + .coerce_to_number(activation)?; + let mut flags = DropShadowFilterFlags::empty(); + if !hide_object { + flags |= DropShadowFilterFlags::COMPOSITE_SOURCE + }; + if inner { + flags |= DropShadowFilterFlags::INNER_SHADOW + }; + if knockout { + flags |= DropShadowFilterFlags::KNOCKOUT + }; + flags |= DropShadowFilterFlags::from_passes(quality.clamp(1, 15) as u8); + Ok(Filter::DropShadowFilter(DropShadowFilter { + color: Color::from_rgb(color, (alpha * 255.0) as u8), + angle: Fixed16::from_f64(angle.to_radians()), + blur_x: Fixed16::from_f64(blur_x.max(0.0)), + blur_y: Fixed16::from_f64(blur_y.max(0.0)), + distance: Fixed16::from_f64(distance), + strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), + flags, + })) } -impl FilterAvm2Ext for GradientBevelFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let angle = object - .get_public_property("angle", activation)? - .coerce_to_number(activation)?; - let blur_x = object - .get_public_property("blurX", activation)? - .coerce_to_number(activation)?; - let blur_y = object - .get_public_property("blurY", activation)? - .coerce_to_number(activation)?; - let distance = object - .get_public_property("distance", activation)? - .coerce_to_number(activation)?; - let knockout = object - .get_public_property("knockout", activation)? - .coerce_to_boolean(); - let quality = object - .get_public_property("quality", activation)? - .coerce_to_u32(activation)?; - let strength = object - .get_public_property("strength", activation)? - .coerce_to_number(activation)?; - let bevel_type = object - .get_public_property("type", activation)? - .coerce_to_string(activation)?; - let colors = get_gradient_colors(activation, object)?; - let mut flags = GradientFilterFlags::COMPOSITE_SOURCE; - if knockout { - flags |= GradientFilterFlags::KNOCKOUT; - } - if &bevel_type == b"inner" { - flags |= GradientFilterFlags::INNER_SHADOW; - } else if &bevel_type != b"outer" { - flags |= GradientFilterFlags::ON_TOP; - } - flags |= GradientFilterFlags::from_passes(quality.clamp(1, 15) as u8); - Ok(Filter::GradientBevelFilter(GradientBevelFilter { - colors, - blur_x: Fixed16::from_f64(blur_x.max(0.0)), - blur_y: Fixed16::from_f64(blur_y.max(0.0)), - angle: Fixed16::from_f64(angle.to_radians()), - distance: Fixed16::from_f64(distance), - strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), - flags, - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - let colors = ArrayObject::from_storage( - activation, - self.colors - .iter() - .map(|v| Value::from(v.color.to_rgb())) - .collect(), - )?; - let alphas = ArrayObject::from_storage( - activation, - self.colors - .iter() - .map(|v| Value::from(f64::from(v.color.a) / 255.0)) - .collect(), - )?; - let ratios = ArrayObject::from_storage( - activation, - self.colors.iter().map(|v| Value::from(v.ratio)).collect(), - )?; - activation.avm2().classes().gradientbevelfilter.construct( - activation, - &[ - self.distance.to_f64().into(), - self.angle.to_f64().to_degrees().into(), - colors.into(), - alphas.into(), - ratios.into(), - self.blur_x.to_f64().into(), - self.blur_y.to_f64().into(), - self.strength.to_f64().into(), - self.num_passes().into(), - if self.is_on_top() { - "full" - } else if self.is_inner() { - "inner" - } else { - "outer" - } - .into(), - self.is_knockout().into(), - ], - ) - } +fn drop_shadow_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &DropShadowFilter, +) -> Result, Error<'gc>> { + activation.avm2().classes().dropshadowfilter.construct( + activation, + &[ + filter.distance.to_f64().into(), + filter.angle.to_f64().to_degrees().into(), + filter.color.to_rgb().into(), + (f64::from(filter.color.a) / 255.0).into(), + filter.blur_x.to_f64().into(), + filter.blur_y.to_f64().into(), + filter.strength.to_f64().into(), + filter.num_passes().into(), + filter.is_inner().into(), + filter.is_knockout().into(), + filter.hide_object().into(), + ], + ) } -impl FilterAvm2Ext for GradientGlowFilter { - fn from_avm2_object<'gc>( - activation: &mut Activation<'_, 'gc>, - object: Object<'gc>, - ) -> Result> { - let angle = object - .get_public_property("angle", activation)? - .coerce_to_number(activation)?; - let blur_x = object - .get_public_property("blurX", activation)? - .coerce_to_number(activation)?; - let blur_y = object - .get_public_property("blurY", activation)? - .coerce_to_number(activation)?; - let distance = object - .get_public_property("distance", activation)? - .coerce_to_number(activation)?; - let knockout = object - .get_public_property("knockout", activation)? - .coerce_to_boolean(); - let quality = object - .get_public_property("quality", activation)? - .coerce_to_u32(activation)?; - let strength = object - .get_public_property("strength", activation)? - .coerce_to_number(activation)?; - let glow_type = object - .get_public_property("type", activation)? - .coerce_to_string(activation)?; - let colors = get_gradient_colors(activation, object)?; - let mut flags = GradientFilterFlags::COMPOSITE_SOURCE; - if knockout { - flags |= GradientFilterFlags::KNOCKOUT; - } - if &glow_type == b"inner" { - flags |= GradientFilterFlags::INNER_SHADOW; - } else if &glow_type != b"outer" { - flags |= GradientFilterFlags::ON_TOP; - } - flags |= GradientFilterFlags::from_passes(quality.clamp(1, 15) as u8); - Ok(Filter::GradientGlowFilter(GradientGlowFilter { - colors, - blur_x: Fixed16::from_f64(blur_x.max(0.0)), - blur_y: Fixed16::from_f64(blur_y.max(0.0)), - angle: Fixed16::from_f64(angle.to_radians()), - distance: Fixed16::from_f64(distance), - strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), - flags, - })) - } - - fn as_avm2_object<'gc>( - &self, - activation: &mut Activation<'_, 'gc>, - ) -> Result, Error<'gc>> { - let colors = ArrayObject::from_storage( - activation, - self.colors - .iter() - .map(|v| Value::from(v.color.to_rgb())) - .collect(), - )?; - let alphas = ArrayObject::from_storage( - activation, - self.colors - .iter() - .map(|v| Value::from(f64::from(v.color.a) / 255.0)) - .collect(), - )?; - let ratios = ArrayObject::from_storage( - activation, - self.colors.iter().map(|v| Value::from(v.ratio)).collect(), - )?; - activation.avm2().classes().gradientglowfilter.construct( - activation, - &[ - self.distance.to_f64().into(), - self.angle.to_f64().to_degrees().into(), - colors.into(), - alphas.into(), - ratios.into(), - self.blur_x.to_f64().into(), - self.blur_y.to_f64().into(), - self.strength.to_f64().into(), - self.num_passes().into(), - if self.is_on_top() { - "full" - } else if self.is_inner() { - "inner" - } else { - "outer" - } - .into(), - self.is_knockout().into(), - ], - ) - } +fn avm2_to_glow_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let alpha = object + .get_public_property("alpha", activation)? + .coerce_to_number(activation)?; + let blur_x = object + .get_public_property("blurX", activation)? + .coerce_to_number(activation)?; + let blur_y = object + .get_public_property("blurY", activation)? + .coerce_to_number(activation)?; + let color = object + .get_public_property("color", activation)? + .coerce_to_u32(activation)?; + let inner = object + .get_public_property("inner", activation)? + .coerce_to_boolean(); + let knockout = object + .get_public_property("knockout", activation)? + .coerce_to_boolean(); + let quality = object + .get_public_property("quality", activation)? + .coerce_to_u32(activation)?; + let strength = object + .get_public_property("strength", activation)? + .coerce_to_number(activation)?; + let mut flags = GlowFilterFlags::COMPOSITE_SOURCE; + if inner { + flags |= GlowFilterFlags::INNER_GLOW + }; + if knockout { + flags |= GlowFilterFlags::KNOCKOUT + }; + flags |= GlowFilterFlags::from_passes(quality.clamp(1, 15) as u8); + Ok(Filter::GlowFilter(GlowFilter { + color: Color::from_rgb(color, (alpha * 255.0) as u8), + blur_x: Fixed16::from_f64(blur_x.max(0.0)), + blur_y: Fixed16::from_f64(blur_y.max(0.0)), + strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), + flags, + })) } +fn glow_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &GlowFilter, +) -> Result, Error<'gc>> { + activation.avm2().classes().glowfilter.construct( + activation, + &[ + filter.color.to_rgb().into(), + (f64::from(filter.color.a) / 255.0).into(), + filter.blur_x.to_f64().into(), + filter.blur_y.to_f64().into(), + filter.strength.to_f64().into(), + filter.num_passes().into(), + filter.is_inner().into(), + filter.is_knockout().into(), + ], + ) +} + +fn avm2_to_gradient_bevel_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let angle = object + .get_public_property("angle", activation)? + .coerce_to_number(activation)?; + let blur_x = object + .get_public_property("blurX", activation)? + .coerce_to_number(activation)?; + let blur_y = object + .get_public_property("blurY", activation)? + .coerce_to_number(activation)?; + let distance = object + .get_public_property("distance", activation)? + .coerce_to_number(activation)?; + let knockout = object + .get_public_property("knockout", activation)? + .coerce_to_boolean(); + let quality = object + .get_public_property("quality", activation)? + .coerce_to_u32(activation)?; + let strength = object + .get_public_property("strength", activation)? + .coerce_to_number(activation)?; + let bevel_type = object + .get_public_property("type", activation)? + .coerce_to_string(activation)?; + let colors = get_gradient_colors(activation, object)?; + let mut flags = GradientFilterFlags::COMPOSITE_SOURCE; + if knockout { + flags |= GradientFilterFlags::KNOCKOUT; + } + if &bevel_type == b"inner" { + flags |= GradientFilterFlags::INNER_SHADOW; + } else if &bevel_type != b"outer" { + flags |= GradientFilterFlags::ON_TOP; + } + flags |= GradientFilterFlags::from_passes(quality.clamp(1, 15) as u8); + Ok(Filter::GradientBevelFilter(GradientBevelFilter { + colors, + blur_x: Fixed16::from_f64(blur_x.max(0.0)), + blur_y: Fixed16::from_f64(blur_y.max(0.0)), + angle: Fixed16::from_f64(angle.to_radians()), + distance: Fixed16::from_f64(distance), + strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), + flags, + })) +} + +fn gradient_bevel_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &GradientBevelFilter, +) -> Result, Error<'gc>> { + let colors = ArrayObject::from_storage( + activation, + filter + .colors + .iter() + .map(|v| Value::from(v.color.to_rgb())) + .collect(), + )?; + let alphas = ArrayObject::from_storage( + activation, + filter + .colors + .iter() + .map(|v| Value::from(f64::from(v.color.a) / 255.0)) + .collect(), + )?; + let ratios = ArrayObject::from_storage( + activation, + filter.colors.iter().map(|v| Value::from(v.ratio)).collect(), + )?; + activation.avm2().classes().gradientbevelfilter.construct( + activation, + &[ + filter.distance.to_f64().into(), + filter.angle.to_f64().to_degrees().into(), + colors.into(), + alphas.into(), + ratios.into(), + filter.blur_x.to_f64().into(), + filter.blur_y.to_f64().into(), + filter.strength.to_f64().into(), + filter.num_passes().into(), + if filter.is_on_top() { + "full" + } else if filter.is_inner() { + "inner" + } else { + "outer" + } + .into(), + filter.is_knockout().into(), + ], + ) +} + +fn avm2_to_gradient_glow_filter<'gc>( + activation: &mut Activation<'_, 'gc>, + object: Object<'gc>, +) -> Result> { + let angle = object + .get_public_property("angle", activation)? + .coerce_to_number(activation)?; + let blur_x = object + .get_public_property("blurX", activation)? + .coerce_to_number(activation)?; + let blur_y = object + .get_public_property("blurY", activation)? + .coerce_to_number(activation)?; + let distance = object + .get_public_property("distance", activation)? + .coerce_to_number(activation)?; + let knockout = object + .get_public_property("knockout", activation)? + .coerce_to_boolean(); + let quality = object + .get_public_property("quality", activation)? + .coerce_to_u32(activation)?; + let strength = object + .get_public_property("strength", activation)? + .coerce_to_number(activation)?; + let glow_type = object + .get_public_property("type", activation)? + .coerce_to_string(activation)?; + let colors = get_gradient_colors(activation, object)?; + let mut flags = GradientFilterFlags::COMPOSITE_SOURCE; + if knockout { + flags |= GradientFilterFlags::KNOCKOUT; + } + if &glow_type == b"inner" { + flags |= GradientFilterFlags::INNER_SHADOW; + } else if &glow_type != b"outer" { + flags |= GradientFilterFlags::ON_TOP; + } + flags |= GradientFilterFlags::from_passes(quality.clamp(1, 15) as u8); + Ok(Filter::GradientGlowFilter(GradientGlowFilter { + colors, + blur_x: Fixed16::from_f64(blur_x.max(0.0)), + blur_y: Fixed16::from_f64(blur_y.max(0.0)), + angle: Fixed16::from_f64(angle.to_radians()), + distance: Fixed16::from_f64(distance), + strength: Fixed8::from_f64(strength.clamp(0.0, 255.0)), + flags, + })) +} + +fn gradient_glow_filter_to_avm2<'gc>( + activation: &mut Activation<'_, 'gc>, + filter: &GradientGlowFilter, +) -> Result, Error<'gc>> { + let colors = ArrayObject::from_storage( + activation, + filter + .colors + .iter() + .map(|v| Value::from(v.color.to_rgb())) + .collect(), + )?; + let alphas = ArrayObject::from_storage( + activation, + filter + .colors + .iter() + .map(|v| Value::from(f64::from(v.color.a) / 255.0)) + .collect(), + )?; + let ratios = ArrayObject::from_storage( + activation, + filter.colors.iter().map(|v| Value::from(v.ratio)).collect(), + )?; + activation.avm2().classes().gradientglowfilter.construct( + activation, + &[ + filter.distance.to_f64().into(), + filter.angle.to_f64().to_degrees().into(), + colors.into(), + alphas.into(), + ratios.into(), + filter.blur_x.to_f64().into(), + filter.blur_y.to_f64().into(), + filter.strength.to_f64().into(), + filter.num_passes().into(), + if filter.is_on_top() { + "full" + } else if filter.is_inner() { + "inner" + } else { + "outer" + } + .into(), + filter.is_knockout().into(), + ], + ) +} fn get_gradient_colors<'gc>( activation: &mut Activation<'_, 'gc>, object: Object<'gc>,