From 297e0957552178558bf153f3d6227039abb29b0f Mon Sep 17 00:00:00 2001 From: Andrew Smith Date: Sat, 12 Mar 2022 12:48:05 -0600 Subject: [PATCH] PixelPaint: Correctly apply flip/rotate/crop to layers' alpha mask -Layer now has methods for flip/rotate/crop, which are responsible for handling the alpha mask. -Fixed crash when the display image size is out of sync with the content image size. -Changed API for setting content and mask image in Layer. Now, both must be set at the same time, and it can result in an error if you provide mismatched dimensions. --- Userland/Applications/PixelPaint/Image.cpp | 17 +++------- Userland/Applications/PixelPaint/Layer.cpp | 39 ++++++++++++++++++---- Userland/Applications/PixelPaint/Layer.h | 7 ++-- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/Userland/Applications/PixelPaint/Image.cpp b/Userland/Applications/PixelPaint/Image.cpp index 7ce629a54a..7ca784a218 100644 --- a/Userland/Applications/PixelPaint/Image.cpp +++ b/Userland/Applications/PixelPaint/Image.cpp @@ -96,7 +96,7 @@ ErrorOr> Image::try_create_from_pixel_paint_json(JsonObject auto mask_base64_encoded = mask_object.as_string(); auto mask_data = TRY(decode_base64(mask_base64_encoded)); auto mask = TRY(try_decode_bitmap(mask_data)); - layer->set_mask_bitmap(move(mask)); + TRY(layer->try_set_bitmaps(layer->content_bitmap(), mask)); } auto width = layer_object.get("width").to_i32(); @@ -485,10 +485,7 @@ void ImageUndoCommand::redo() void Image::flip(Gfx::Orientation orientation) { for (auto& layer : m_layers) { - auto flipped = layer.content_bitmap().flipped(orientation).release_value_but_fixme_should_propagate_errors(); - layer.set_content_bitmap(*flipped); - layer.did_modify_bitmap(rect()); - // FIXME: Respect mask + layer.flip(orientation); } did_change(); @@ -497,10 +494,7 @@ void Image::flip(Gfx::Orientation orientation) void Image::rotate(Gfx::RotationDirection direction) { for (auto& layer : m_layers) { - auto rotated = layer.content_bitmap().rotated(direction).release_value_but_fixme_should_propagate_errors(); - layer.set_content_bitmap(*rotated); - layer.did_modify_bitmap(rect()); - // FIXME: Respect mask + layer.rotate(direction); } m_size = { m_size.height(), m_size.width() }; @@ -510,10 +504,7 @@ void Image::rotate(Gfx::RotationDirection direction) void Image::crop(Gfx::IntRect const& cropped_rect) { for (auto& layer : m_layers) { - auto cropped = layer.content_bitmap().cropped(cropped_rect).release_value_but_fixme_should_propagate_errors(); - layer.set_content_bitmap(*cropped); - layer.did_modify_bitmap(rect()); - // FIXME: Respect mask + layer.crop(cropped_rect); } m_size = { cropped_rect.width(), cropped_rect.height() }; diff --git a/Userland/Applications/PixelPaint/Layer.cpp b/Userland/Applications/PixelPaint/Layer.cpp index f3f5dc5e73..5298946c97 100644 --- a/Userland/Applications/PixelPaint/Layer.cpp +++ b/Userland/Applications/PixelPaint/Layer.cpp @@ -142,16 +142,42 @@ void Layer::erase_selection(Selection const& selection) did_modify_bitmap(translated_to_layer_space); } -void Layer::set_content_bitmap(NonnullRefPtr bitmap) +ErrorOr Layer::try_set_bitmaps(NonnullRefPtr content, RefPtr mask) { - m_content_bitmap = move(bitmap); + if (mask && content->size() != mask->size()) + return Error::from_string_literal("Layer content and mask must be same size"sv); + + m_content_bitmap = move(content); + m_mask_bitmap = move(mask); update_cached_bitmap(); + return {}; } -void Layer::set_mask_bitmap(NonnullRefPtr bitmap) +void Layer::flip(Gfx::Orientation orientation) { - m_mask_bitmap = move(bitmap); - update_cached_bitmap(); + m_content_bitmap = *m_content_bitmap->flipped(orientation).release_value_but_fixme_should_propagate_errors(); + if (m_mask_bitmap) + m_mask_bitmap = *m_mask_bitmap->flipped(orientation).release_value_but_fixme_should_propagate_errors(); + + did_modify_bitmap(); +} + +void Layer::rotate(Gfx::RotationDirection direction) +{ + m_content_bitmap = *m_content_bitmap->rotated(direction).release_value_but_fixme_should_propagate_errors(); + if (m_mask_bitmap) + m_mask_bitmap = *m_mask_bitmap->rotated(direction).release_value_but_fixme_should_propagate_errors(); + + did_modify_bitmap(); +} + +void Layer::crop(Gfx::IntRect const& rect) +{ + m_content_bitmap = *m_content_bitmap->cropped(rect).release_value_but_fixme_should_propagate_errors(); + if (m_mask_bitmap) + m_mask_bitmap = *m_mask_bitmap->cropped(rect).release_value_but_fixme_should_propagate_errors(); + + did_modify_bitmap(); } void Layer::update_cached_bitmap() @@ -163,8 +189,9 @@ void Layer::update_cached_bitmap() return; } - if (m_content_bitmap.ptr() == m_cached_display_bitmap.ptr()) + if (m_cached_display_bitmap.ptr() == m_content_bitmap.ptr() || m_cached_display_bitmap->size() != size()) { m_cached_display_bitmap = MUST(Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, size())); + } // FIXME: This can probably be done nicer m_cached_display_bitmap->fill(Color::Transparent); diff --git a/Userland/Applications/PixelPaint/Layer.h b/Userland/Applications/PixelPaint/Layer.h index b9197872c9..55a92d1ae0 100644 --- a/Userland/Applications/PixelPaint/Layer.h +++ b/Userland/Applications/PixelPaint/Layer.h @@ -53,8 +53,11 @@ public: String const& name() const { return m_name; } void set_name(String); - void set_content_bitmap(NonnullRefPtr bitmap); - void set_mask_bitmap(NonnullRefPtr bitmap); + void flip(Gfx::Orientation orientation); + void rotate(Gfx::RotationDirection direction); + void crop(Gfx::IntRect const& rect); + + ErrorOr try_set_bitmaps(NonnullRefPtr content, RefPtr mask); void did_modify_bitmap(Gfx::IntRect const& = {});