Skip to content

Commit

Permalink
avm2: Allow null ratios is Graphics gradient APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
adrian17 committed Nov 22, 2024
1 parent cec004a commit d9faefb
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 25 deletions.
49 changes: 24 additions & 25 deletions core/src/avm2/globals/flash/display/graphics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,13 @@ pub fn begin_gradient_fill<'gc>(
let gradient_type = parse_gradient_type(activation, gradient_type)?;
let colors = args.get_object(activation, 1, "colors")?;
let alphas = args.try_get_object(activation, 2);
let ratios = args
.try_get_object(activation, 3)
.expect("Ratios should never be null");
let ratios = args.try_get_object(activation, 3);

let records = build_gradient_records(
activation,
&colors.as_array_storage().expect("Guaranteed by AS"),
alphas,
&ratios.as_array_storage().expect("Guaranteed by AS"),
ratios,
)?;

let matrix = if let Some(matrix) = args.try_get_object(activation, 4) {
Expand Down Expand Up @@ -164,14 +162,18 @@ fn build_gradient_records<'gc>(
activation: &mut Activation<'_, 'gc>,
colors: &ArrayStorage<'gc>,
alphas: Option<Object<'gc>>,
ratios: &ArrayStorage<'gc>,
ratios: Option<Object<'gc>>,
) -> Result<Vec<GradientRecord>, Error<'gc>> {
let alphas = alphas.as_ref().map(|o| o.as_array_storage().unwrap());
let ratios = ratios.as_ref().map(|o| o.as_array_storage().unwrap());

let mut length = colors.length().min(ratios.length());
let mut length = colors.length();
if let Some(ref alphas) = alphas {
length = length.min(alphas.length());
}
if let Some(ref ratios) = ratios {
length = length.min(ratios.length());
}

let mut records = Vec::with_capacity(length);
for i in 0..length {
Expand All @@ -189,12 +191,19 @@ fn build_gradient_records<'gc>(
1.0
};

let ratio = ratios
.get(i)
.expect("Length should be guaranteed")
.coerce_to_u32(activation)?;
let ratio = if let Some(ref ratios) = ratios {
let ratio = ratios
.get(i)
.expect("Length should be guaranteed")
.coerce_to_u32(activation)?;
ratio.clamp(0, 255) as u8
} else {
// For example, with length=3: 0/2, 1/2, 2/2.
((i * 255) / (length - 1)) as u8
};

records.push(GradientRecord {
ratio: ratio.clamp(0, 255) as u8,
ratio,
color: Color::from_rgb(color, (alpha * 255.0) as u8),
})
}
Expand Down Expand Up @@ -850,18 +859,13 @@ pub fn line_gradient_style<'gc>(
let gradient_type = parse_gradient_type(activation, gradient_type?)?;
let colors = args.get_object(activation, 1, "colors")?;
let alphas = args.try_get_object(activation, 2);

// FP permits null ratios, but I don't understand the logic behind how it renders them.
// Panic here so we can get an error report if any game actually tries to pass null.
let ratios = args
.try_get_object(activation, 3)
.expect("Ratios should never be null");
let ratios = args.try_get_object(activation, 3);

let records = build_gradient_records(
activation,
&colors.as_array_storage().expect("Guaranteed by AS"),
alphas,
&ratios.as_array_storage().expect("Guaranteed by AS"),
ratios,
)?;
let matrix = if let Some(matrix) = args.try_get_object(activation, 4) {
Matrix::from(object_to_matrix(matrix, activation)?)
Expand Down Expand Up @@ -1609,18 +1613,13 @@ fn handle_gradient_fill<'gc>(
obj: &Object<'gc>,
) -> Result<FillStyle, Error<'gc>> {
let alphas = obj.get_public_property("alphas", activation)?.as_object();
let ratios = obj.get_public_property("ratios", activation)?.as_object();

let colors = obj
.get_public_property("colors", activation)?
.as_object()
.ok_or_else(|| make_error_2007(activation, "colors"))?;

// See the comment in the `line_gradient_style` function.
let ratios = obj
.get_public_property("ratios", activation)?
.as_object()
.expect("Ratios should never be null");

let gradient_type = {
let gradient_type = obj
.get_public_property("type", activation)?
Expand All @@ -1632,7 +1631,7 @@ fn handle_gradient_fill<'gc>(
activation,
&colors.as_array_storage().expect("Guaranteed by AS"),
alphas,
&ratios.as_array_storage().expect("Guaranteed by AS"),
ratios,
)?;

let matrix = {
Expand Down
24 changes: 24 additions & 0 deletions tests/tests/swfs/avm2/graphics_gradients_nulls/Test.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// compiled with mxmlc

package {
import flash.display.MovieClip;
import flash.display.Graphics;
import flash.geom.Matrix;

public class Test extends MovieClip {

public function Test() {
var matrix = new Matrix();
matrix.createGradientBox(200, 200, 0, 100, 100);
graphics.beginGradientFill(
"linear",
[0, 0xFFFFFF, 0, 0xFFFFFF, 0],
null, //[1, 1, 1, 1, 1],
null, //[0, 64, 128, 192, 255],
matrix
);
graphics.drawRect(100, 100, 200, 200);
graphics.endFill();
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
Binary file not shown.
7 changes: 7 additions & 0 deletions tests/tests/swfs/avm2/graphics_gradients_nulls/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
num_frames = 1

[image_comparisons.output]
tolerance = 5 # expected png generated from FP

[player_options]
with_renderer = { optional = false, sample_count = 1 }

0 comments on commit d9faefb

Please sign in to comment.