From cc8edb3bf19979b30353085802964ebf691f7a68 Mon Sep 17 00:00:00 2001 From: Nathan Adams Date: Sun, 18 Jun 2023 22:20:14 +0200 Subject: [PATCH] core: Invalidate cacheAsBitmap when various more properties change --- core/src/display_object.rs | 35 ++++++++++++++++++ .../nested_rotation/expected.png | Bin 0 -> 6674 bytes .../nested_rotation/output.txt | 0 .../cache_as_bitmap/nested_rotation/test.fla | Bin 0 -> 6195 bytes .../cache_as_bitmap/nested_rotation/test.swf | Bin 0 -> 733 bytes .../cache_as_bitmap/nested_rotation/test.toml | 7 ++++ 6 files changed, 42 insertions(+) create mode 100644 tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/expected.png create mode 100644 tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/output.txt create mode 100644 tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/test.fla create mode 100644 tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/test.swf create mode 100644 tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/test.toml diff --git a/core/src/display_object.rs b/core/src/display_object.rs index c7598ca5e..c24de764a 100644 --- a/core/src/display_object.rs +++ b/core/src/display_object.rs @@ -1024,8 +1024,14 @@ pub trait TDisplayObject<'gc>: /// Sets the `x` position in pixels of this display object in local space. /// Set by the `_x`/`x` ActionScript properties. + /// This invalidates any ancestors cacheAsBitmap automatically. fn set_x(&self, gc_context: MutationContext<'gc, '_>, x: Twips) { self.base_mut(gc_context).set_x(x); + if let Some(parent) = self.parent() { + // Self-transform changes are automatically handled, + // we only want to inform ancestors to avoid unnecessary invalidations for tx/ty + parent.invalidate_cached_bitmap(gc_context); + } } /// The `y` position in pixels of this display object in local space. @@ -1036,8 +1042,14 @@ pub trait TDisplayObject<'gc>: /// Sets the `y` position in pixels of this display object in local space. /// Set by the `_y`/`y` ActionScript properties. + /// This invalidates any ancestors cacheAsBitmap automatically. fn set_y(&self, gc_context: MutationContext<'gc, '_>, y: Twips) { self.base_mut(gc_context).set_y(y); + if let Some(parent) = self.parent() { + // Self-transform changes are automatically handled, + // we only want to inform ancestors to avoid unnecessary invalidations for tx/ty + parent.invalidate_cached_bitmap(gc_context); + } } /// The rotation in degrees this display object in local space. @@ -1050,9 +1062,15 @@ pub trait TDisplayObject<'gc>: /// Sets the rotation in degrees this display object in local space. /// Set by the `_rotation`/`rotation` ActionScript properties. + /// This invalidates any ancestors cacheAsBitmap automatically. fn set_rotation(&self, gc_context: MutationContext<'gc, '_>, radians: Degrees) { self.base_mut(gc_context).set_rotation(radians); self.set_scale_rotation_cached(gc_context); + if let Some(parent) = self.parent() { + // Self-transform changes are automatically handled, + // we only want to inform ancestors to avoid unnecessary invalidations for tx/ty + parent.invalidate_cached_bitmap(gc_context); + } } /// The X axis scale for this display object in local space. @@ -1065,9 +1083,15 @@ pub trait TDisplayObject<'gc>: /// Sets the X axis scale for this display object in local space. /// Set by the `_xscale`/`scaleX` ActionScript properties. + /// This invalidates any ancestors cacheAsBitmap automatically. fn set_scale_x(&self, gc_context: MutationContext<'gc, '_>, value: Percent) { self.base_mut(gc_context).set_scale_x(value); self.set_scale_rotation_cached(gc_context); + if let Some(parent) = self.parent() { + // Self-transform changes are automatically handled, + // we only want to inform ancestors to avoid unnecessary invalidations for tx/ty + parent.invalidate_cached_bitmap(gc_context); + } } /// The Y axis scale for this display object in local space. @@ -1080,9 +1104,15 @@ pub trait TDisplayObject<'gc>: /// Sets the Y axis scale for this display object in local space. /// Returned by the `_yscale`/`scaleY` ActionScript properties. + /// This invalidates any ancestors cacheAsBitmap automatically. fn set_scale_y(&self, gc_context: MutationContext<'gc, '_>, value: Percent) { self.base_mut(gc_context).set_scale_y(value); self.set_scale_rotation_cached(gc_context); + if let Some(parent) = self.parent() { + // Self-transform changes are automatically handled, + // we only want to inform ancestors to avoid unnecessary invalidations for tx/ty + parent.invalidate_cached_bitmap(gc_context); + } } /// Gets the pixel width of the AABB containing this display object in local space. @@ -1319,6 +1349,7 @@ pub trait TDisplayObject<'gc>: } } self.base_mut(gc_context).set_masker(node); + self.invalidate_cached_bitmap(gc_context); } fn maskee(&self) -> Option> { self.base().maskee() @@ -1335,6 +1366,7 @@ pub trait TDisplayObject<'gc>: } } self.base_mut(gc_context).set_maskee(node); + self.invalidate_cached_bitmap(gc_context); } fn scroll_rect(&self) -> Option> { @@ -1380,6 +1412,7 @@ pub trait TDisplayObject<'gc>: /// Returned by the `_visible`/`visible` ActionScript properties. fn set_visible(&self, gc_context: MutationContext<'gc, '_>, value: bool) { self.base_mut(gc_context).set_visible(value); + self.invalidate_cached_bitmap(gc_context); } /// The blend mode used when rendering this display object. @@ -1392,6 +1425,7 @@ pub trait TDisplayObject<'gc>: /// Values other than the default `BlendMode::Normal` implicitly cause cache-as-bitmap behavior. fn set_blend_mode(&self, gc_context: MutationContext<'gc, '_>, value: BlendMode) { self.base_mut(gc_context).set_blend_mode(value); + self.invalidate_cached_bitmap(gc_context); } /// The opaque background color of this display object. @@ -1405,6 +1439,7 @@ pub trait TDisplayObject<'gc>: /// is ignored. fn set_opaque_background(&self, gc_context: MutationContext<'gc, '_>, value: Option) { self.base_mut(gc_context).set_opaque_background(value); + self.invalidate_cached_bitmap(gc_context); } /// Whether this display object represents the root of loaded content. diff --git a/tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/expected.png b/tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..902c92cf41875bdae0133c48ef57975afc641101 GIT binary patch literal 6674 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 P`taotB*Ky3QOeWNfBbv| literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/test.toml b/tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/test.toml new file mode 100644 index 000000000..4a2532106 --- /dev/null +++ b/tests/tests/swfs/visual/cache_as_bitmap/nested_rotation/test.toml @@ -0,0 +1,7 @@ +num_frames = 3 + +[image_comparison] +tolerance = 0 + +[player_options] +with_renderer = { optional = false, sample_count = 1 }