avm2: Fix rounding behavior in BitmapData rectangle operations
Flash Player performs `x + width` and `y + height` as floating point operations before `round_to_even`. This affects the extent covered by a `Rectangle` in various BitmapData methods, as the sum of two values might be large enough to be rounded up to a larger value (when rounding `x` and `width` individually would have produced a smaller overall extent).
This commit is contained in:
parent
2ae15b05e8
commit
0955ab40e6
|
@ -17,30 +17,45 @@ use crate::bitmap::{is_size_valid, operations};
|
||||||
use crate::character::Character;
|
use crate::character::Character;
|
||||||
use crate::display_object::Bitmap;
|
use crate::display_object::Bitmap;
|
||||||
use crate::display_object::TDisplayObject;
|
use crate::display_object::TDisplayObject;
|
||||||
|
use crate::ecma_conversions::round_to_even;
|
||||||
use crate::swf::BlendMode;
|
use crate::swf::BlendMode;
|
||||||
use gc_arena::GcCell;
|
use gc_arena::GcCell;
|
||||||
use ruffle_render::filters::Filter;
|
use ruffle_render::filters::Filter;
|
||||||
use ruffle_render::transform::Transform;
|
use ruffle_render::transform::Transform;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
// Computes the integer x,y,width,height values from
|
||||||
|
// the given `Rectangle`. This method performs `x + width`
|
||||||
|
// and `y + height` as floating point operations before
|
||||||
|
// `round_to_even`, which is needed to match Flash Player's
|
||||||
|
// rounding behavior.
|
||||||
fn get_rectangle_x_y_width_height<'gc>(
|
fn get_rectangle_x_y_width_height<'gc>(
|
||||||
activation: &mut Activation<'_, 'gc>,
|
activation: &mut Activation<'_, 'gc>,
|
||||||
rectangle: Object<'gc>,
|
rectangle: Object<'gc>,
|
||||||
) -> Result<(i32, i32, i32, i32), Error<'gc>> {
|
) -> Result<(i32, i32, i32, i32), Error<'gc>> {
|
||||||
let x = rectangle
|
let x = rectangle
|
||||||
.get_public_property("x", activation)?
|
.get_public_property("x", activation)?
|
||||||
.coerce_to_i32(activation)?;
|
.coerce_to_number(activation)?;
|
||||||
let y = rectangle
|
let y = rectangle
|
||||||
.get_public_property("y", activation)?
|
.get_public_property("y", activation)?
|
||||||
.coerce_to_i32(activation)?;
|
.coerce_to_number(activation)?;
|
||||||
let width = rectangle
|
let width = rectangle
|
||||||
.get_public_property("width", activation)?
|
.get_public_property("width", activation)?
|
||||||
.coerce_to_i32(activation)?;
|
.coerce_to_number(activation)?;
|
||||||
let height = rectangle
|
let height = rectangle
|
||||||
.get_public_property("height", activation)?
|
.get_public_property("height", activation)?
|
||||||
.coerce_to_i32(activation)?;
|
.coerce_to_number(activation)?;
|
||||||
|
|
||||||
Ok((x, y, width, height))
|
let x_max = round_to_even(x + width);
|
||||||
|
let y_max = round_to_even(y + height);
|
||||||
|
|
||||||
|
let x_int = round_to_even(x);
|
||||||
|
let y_int = round_to_even(y);
|
||||||
|
|
||||||
|
let width_int = x_max - x_int;
|
||||||
|
let height_int = y_max - y_int;
|
||||||
|
|
||||||
|
Ok((x_int, y_int, width_int, height_int))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy the static data from a given Bitmap into a new BitmapData.
|
/// Copy the static data from a given Bitmap into a new BitmapData.
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package {
|
||||||
|
import flash.display.BitmapData;
|
||||||
|
import flash.geom.Rectangle;
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
public function Test() {
|
||||||
|
var otherData = new BitmapData(5, 5, true, 0);
|
||||||
|
otherData.fillRect(new Rectangle(1.6, 1.6, 1.8, 2), 0xFFFFFFFF);
|
||||||
|
trace("First fillRect");
|
||||||
|
print(otherData);
|
||||||
|
|
||||||
|
otherData.fillRect(new Rectangle(0.1, 0, 1.8, 2.5), 0xFFaabbcc);
|
||||||
|
trace("Second fillRect");
|
||||||
|
print(otherData);
|
||||||
|
|
||||||
|
var bytes = otherData.getPixels(new Rectangle(0.5, 0.5, 2.5, 2.5));
|
||||||
|
bytes.position = 0;
|
||||||
|
trace("Bytes len: " + bytes.length);
|
||||||
|
var byteString = "";
|
||||||
|
while (bytes.bytesAvailable != 0) {
|
||||||
|
byteString += bytes.readUnsignedInt().toString(16) + " ";
|
||||||
|
}
|
||||||
|
trace("Bytes: " + byteString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function print(data: BitmapData) {
|
||||||
|
for (var y = 0; y < data.height; y++) {
|
||||||
|
var line = "";
|
||||||
|
for (var x = 0; x < data.width; x++) {
|
||||||
|
line += data.getPixel32(x, y).toString(16) + " "
|
||||||
|
}
|
||||||
|
trace(line)
|
||||||
|
}
|
||||||
|
trace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
First fillRect
|
||||||
|
0 0 0 0 0
|
||||||
|
0 0 0 0 0
|
||||||
|
0 0 ffffffff 0 0
|
||||||
|
0 0 ffffffff 0 0
|
||||||
|
0 0 0 0 0
|
||||||
|
|
||||||
|
Second fillRect
|
||||||
|
ffaabbcc ffaabbcc 0 0 0
|
||||||
|
ffaabbcc ffaabbcc 0 0 0
|
||||||
|
0 0 ffffffff 0 0
|
||||||
|
0 0 ffffffff 0 0
|
||||||
|
0 0 0 0 0
|
||||||
|
|
||||||
|
Bytes len: 36
|
||||||
|
Bytes: ffaabbcc ffaabbcc 0 ffaabbcc ffaabbcc 0 0 0 ffffffff
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
num_frames = 1
|
Loading…
Reference in New Issue