Skip to content

Commit

Permalink
avm2: Implement Bitmap.pixelSnapping
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinnerbone committed Jul 21, 2023
1 parent 289f73c commit 4410d66
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 10 deletions.
32 changes: 22 additions & 10 deletions core/src/avm2/globals/flash/display/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ use crate::avm2::globals::flash::display::display_object::initialize_for_allocat
use crate::avm2::object::{BitmapDataObject, ClassObject, Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use ruffle_render::bitmap::PixelSnapping;
use ruffle_wstr::WStr;

use crate::avm2::error::make_error_2008;
use crate::avm2::parameters::ParametersExt;
use crate::bitmap::bitmap_data::BitmapDataWrapper;
use crate::character::Character;
use crate::display_object::{Bitmap, TDisplayObject};
use crate::{avm2_stub_getter, avm2_stub_setter};

pub fn bitmap_allocator<'gc>(
class: ClassObject<'gc>,
Expand Down Expand Up @@ -79,15 +81,17 @@ pub fn init<'gc>(
let bitmap_data = args
.try_get_object(activation, 0)
.and_then(|o| o.as_bitmap_data());
//TODO: Pixel snapping is not supported
let _pixel_snapping = args.get_string(activation, 1);
let Some(pixel_snapping) = PixelSnapping::from_wstr(&args.get_string(activation, 1)?) else {
return Err(make_error_2008(activation, "pixelSnapping"));
};
let smoothing = args.get_bool(2);

if let Some(bitmap) = this.as_display_object().and_then(|dobj| dobj.as_bitmap()) {
if let Some(bitmap_data) = bitmap_data {
bitmap.set_bitmap_data(&mut activation.context, bitmap_data);
}
bitmap.set_smoothing(activation.context.gc_context, smoothing);
bitmap.set_pixel_snapping(activation.context.gc_context, pixel_snapping);
} else {
unreachable!();
}
Expand Down Expand Up @@ -138,21 +142,29 @@ pub fn set_bitmap_data<'gc>(

/// Stub `Bitmap.pixelSnapping`'s getter
pub fn get_pixel_snapping<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: Object<'gc>,
_activation: &mut Activation<'_, 'gc>,
this: Object<'gc>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
avm2_stub_getter!(activation, "flash.display.Bitmap", "pixelSnapping");
Ok("auto".into())
if let Some(bitmap) = this.as_display_object().and_then(|dobj| dobj.as_bitmap()) {
let value: &WStr = bitmap.pixel_snapping().into();
return Ok(Value::String(value.into()));
}
Ok(Value::Undefined)
}

/// Stub `Bitmap.pixelSnapping`'s setter
pub fn set_pixel_snapping<'gc>(
activation: &mut Activation<'_, 'gc>,
_this: Object<'gc>,
_args: &[Value<'gc>],
this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
avm2_stub_setter!(activation, "flash.display.Bitmap", "pixelSnapping");
if let Some(bitmap) = this.as_display_object().and_then(|dobj| dobj.as_bitmap()) {
let Some(value) = PixelSnapping::from_wstr(&args.get_string(activation, 0)?) else {
return Err(make_error_2008(activation, "pixelSnapping"));
};
bitmap.set_pixel_snapping(activation.context.gc_context, value);
}
Ok(Value::Undefined)
}

Expand Down
8 changes: 8 additions & 0 deletions core/src/display_object/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ impl<'gc> Bitmap<'gc> {
self.0.read().height as u16
}

pub fn pixel_snapping(self) -> PixelSnapping {
self.0.read().pixel_snapping
}

pub fn set_pixel_snapping(self, mc: MutationContext<'gc, '_>, value: PixelSnapping) {
self.0.write(mc).pixel_snapping = value;
}

pub fn bitmap_data_wrapper(self) -> BitmapDataWrapper<'gc> {
self.0.read().bitmap_data
}
Expand Down
23 changes: 23 additions & 0 deletions render/src/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fmt::Debug;
use std::sync::Arc;

use downcast_rs::{impl_downcast, Downcast};
use ruffle_wstr::WStr;
use swf::{Rectangle, Twips};

use crate::backend::RenderBackend;
Expand Down Expand Up @@ -67,7 +68,29 @@ pub enum PixelSnapping {
Never,
}

impl From<PixelSnapping> for &'static WStr {
fn from(value: PixelSnapping) -> &'static WStr {
match value {
PixelSnapping::Always => WStr::from_units(b"always"),
PixelSnapping::Auto => WStr::from_units(b"auto"),
PixelSnapping::Never => WStr::from_units(b"never"),
}
}
}

impl PixelSnapping {
pub fn from_wstr(str: &WStr) -> Option<Self> {
if str == b"always" {
Some(PixelSnapping::Always)
} else if str == b"auto" {
Some(PixelSnapping::Auto)
} else if str == b"never" {
Some(PixelSnapping::Never)
} else {
None
}
}

pub fn apply(&self, matrix: &mut Matrix) {
match self {
PixelSnapping::Always => {
Expand Down
57 changes: 57 additions & 0 deletions tests/tests/swfs/avm2/bitmap_pixelsnapping/Test.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package {

import flash.display.MovieClip;
import flash.display.Bitmap;
import flash.display.PixelSnapping;


public class Test extends MovieClip {


public function Test() {
addTest(PixelSnapping.NEVER, 1.0);
addTest(PixelSnapping.ALWAYS, 1.0);
addTest(PixelSnapping.AUTO, 1.0);

addTest(PixelSnapping.NEVER, 0.99);
addTest(PixelSnapping.ALWAYS, 0.99);
addTest(PixelSnapping.AUTO, 0.99);

addTest(PixelSnapping.NEVER, 1.01);
addTest(PixelSnapping.ALWAYS, 1.01);
addTest(PixelSnapping.AUTO, 1.01);

addTest(PixelSnapping.NEVER, 2.0);
addTest(PixelSnapping.ALWAYS, 2.0);
addTest(PixelSnapping.AUTO, 2.0);

addTest(PixelSnapping.NEVER, 2.5);
addTest(PixelSnapping.ALWAYS, 2.5);
addTest(PixelSnapping.AUTO, 2.5);

try {
var bitmap = new Bitmap(new TestImage());
bitmap.pixelSnapping = "test";
} catch (err) {
trace(err);
}

try {
var bitmap = new Bitmap(new TestImage(), "test");
} catch (err) {
trace(err);
}
}

function addTest(snapping: String, scale: Number) {
var bitmap = new Bitmap(new TestImage());
bitmap.pixelSnapping = snapping;
bitmap.x = (numChildren % 3 * 100) + 10.5;
bitmap.y = (Math.floor(numChildren / 3) * 100) + 10.5;
bitmap.width *= scale;
bitmap.height *= scale;
addChild(bitmap);
}
}

}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions tests/tests/swfs/avm2/bitmap_pixelsnapping/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ArgumentError: Error #2008: Parameter pixelSnapping must be one of the accepted values.
ArgumentError: Error #2008: Parameter pixelSnapping must be one of the accepted values.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
8 changes: 8 additions & 0 deletions tests/tests/swfs/avm2/bitmap_pixelsnapping/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
num_frames = 1
ignore = true # big differences across rendering backends :(

[image_comparison]
tolerance = 0

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

0 comments on commit 4410d66

Please sign in to comment.