ソースを参照

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.
Andrew Smith 3 年 前
コミット
297e095755

+ 4 - 13
Userland/Applications/PixelPaint/Image.cpp

@@ -96,7 +96,7 @@ ErrorOr<NonnullRefPtr<Image>> 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() };

+ 33 - 6
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<Gfx::Bitmap> bitmap)
+ErrorOr<void> Layer::try_set_bitmaps(NonnullRefPtr<Gfx::Bitmap> content, RefPtr<Gfx::Bitmap> 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<Gfx::Bitmap> 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);

+ 5 - 2
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<Gfx::Bitmap> bitmap);
-    void set_mask_bitmap(NonnullRefPtr<Gfx::Bitmap> bitmap);
+    void flip(Gfx::Orientation orientation);
+    void rotate(Gfx::RotationDirection direction);
+    void crop(Gfx::IntRect const& rect);
+
+    ErrorOr<void> try_set_bitmaps(NonnullRefPtr<Gfx::Bitmap> content, RefPtr<Gfx::Bitmap> mask);
 
     void did_modify_bitmap(Gfx::IntRect const& = {});