[calligra/calligra/2.9] krita/image: Fix Adjustment layers composition

Dmitry Kazakov dimula73 at gmail.com
Thu Jun 18 08:34:49 UTC 2015


Git commit fc3fcc743d9706f13167b7317fdfb10c02fce7a9 by Dmitry Kazakov.
Committed on 18/06/2015 at 08:30.
Pushed by dkazakov into branch 'calligra/2.9'.

Fix Adjustment layers composition

This was a very old bug related the way how selection is applied
to adjustment layers. Now selection defines not "how the filtered
data is blended into the image" but "how the filter effect is applied
to the composed image". In the result, erasing the selection now will
*not* make your image fully transparent, but just removes the filter
effect from that area.

BUG:324505,294122
CCBUG:349078
CC:kimageshop at kde.org

M  +2    -1    krita/image/kis_adjustment_layer.cc
M  +19   -3    krita/image/kis_async_merger.cpp
M  +39   -25   krita/image/kis_selection_based_layer.cpp
M  +21   -0    krita/image/kis_selection_based_layer.h

http://commits.kde.org/calligra/fc3fcc743d9706f13167b7317fdfb10c02fce7a9

diff --git a/krita/image/kis_adjustment_layer.cc b/krita/image/kis_adjustment_layer.cc
index 2261586..d59f2cc 100644
--- a/krita/image/kis_adjustment_layer.cc
+++ b/krita/image/kis_adjustment_layer.cc
@@ -46,6 +46,7 @@ KisAdjustmentLayer::KisAdjustmentLayer(KisImageWSP image,
     // https://bugs.kde.org/show_bug.cgi?id=294122
     // demand the opposite from each other...
     setCompositeOp(COMPOSITE_COPY);
+    setUseSelectionInProjection(false);
 }
 
 KisAdjustmentLayer::KisAdjustmentLayer(const KisAdjustmentLayer& rhs)
@@ -78,7 +79,7 @@ QRect KisAdjustmentLayer::incomingChangeRect(const QRect &rect) const
     /**
      * We can't paint outside a selection, that is why we call
      * KisSelectionBasedLayer::cropChangeRectBySelection to crop
-     * actual change area in the end
+     * actual change area in the end.
      */
     filteredRect = cropChangeRectBySelection(filteredRect);
 
diff --git a/krita/image/kis_async_merger.cpp b/krita/image/kis_async_merger.cpp
index 62312ab..8c92fcf 100644
--- a/krita/image/kis_async_merger.cpp
+++ b/krita/image/kis_async_merger.cpp
@@ -90,7 +90,7 @@ public:
         KisPaintDeviceSP originalDevice = layer->original();
         originalDevice->clear(m_updateRect);
 
-        QRect applyRect = m_updateRect & m_projection->extent();
+        const QRect applyRect = m_updateRect & m_projection->extent();
 
         // If the intersection of the updaterect and the projection extent is
         //      null, we are finish here.
@@ -107,6 +107,9 @@ public:
             return true;
         }
 
+        KisSelectionSP selection = layer->fetchComposedInternalSelection(applyRect);
+        const QRect filterRect = selection ? applyRect & selection->selectedRect() : applyRect;
+
         KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name());
         if (!filter) return false;
 
@@ -116,8 +119,21 @@ public:
         updater.start(100, filter->name());
         QPointer<KoUpdater> updaterPtr = updater.startSubtask();
 
-        // We do not create a transaction here, as srcDevice != dstDevice
-        filter->process(m_projection, originalDevice, 0, applyRect, filterConfig.data(), updaterPtr);
+        KisPaintDeviceSP dstDevice = originalDevice;
+
+        if (selection) {
+            dstDevice = new KisPaintDevice(originalDevice->colorSpace());
+        }
+
+        if (!filterRect.isEmpty()) {
+            // We do not create a transaction here, as srcDevice != dstDevice
+            filter->process(m_projection, dstDevice, 0, filterRect, filterConfig.data(), updaterPtr);
+        }
+
+        if (selection) {
+            KisPainter::copyAreaOptimized(applyRect.topLeft(), m_projection, originalDevice, applyRect);
+            KisPainter::copyAreaOptimized(filterRect.topLeft(), dstDevice, originalDevice, filterRect, selection);
+        }
 
         updaterPtr->setProgress(100);
 
diff --git a/krita/image/kis_selection_based_layer.cpp b/krita/image/kis_selection_based_layer.cpp
index d8c1729..6569b7c 100644
--- a/krita/image/kis_selection_based_layer.cpp
+++ b/krita/image/kis_selection_based_layer.cpp
@@ -39,8 +39,11 @@
 struct KisSelectionBasedLayer::Private
 {
 public:
+    Private() : useSelectionInProjection(true) {}
+
     KisSelectionSP selection;
     KisPaintDeviceSP paintDevice;
+    bool useSelectionInProjection;
 };
 
 
@@ -113,40 +116,51 @@ bool KisSelectionBasedLayer::needProjection() const
     return m_d->selection;
 }
 
-void KisSelectionBasedLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
-        KisPaintDeviceSP projection,
-        const QRect& rect) const
+void KisSelectionBasedLayer::setUseSelectionInProjection(bool value) const
 {
-    lockTemporaryTarget();
+    m_d->useSelectionInProjection = value;
+}
 
+KisSelectionSP KisSelectionBasedLayer::fetchComposedInternalSelection(const QRect &rect) const
+{
+    if (!m_d->selection) return 0;
     m_d->selection->updateProjection(rect);
 
     KisSelectionSP tempSelection = m_d->selection;
-    KisPainter gc(projection);
 
-    if (m_d->selection) {
-        if (hasTemporaryTarget()) {
-            /**
-             * Cloning a selection with COW
-             * FIXME: check whether it's faster than usual bitBlt'ing
-             */
-            tempSelection = new KisSelection(*tempSelection);
-
-            KisPainter gc2(tempSelection->pixelSelection());
-            setupTemporaryPainter(&gc2);
-            gc2.bitBlt(rect.topLeft(), temporaryTarget(), rect);
-        }
-
-        projection->clear(rect);
-        gc.setCompositeOp(colorSpace()->compositeOp(COMPOSITE_OVER));
-        gc.setSelection(tempSelection);
-    } else {
-        gc.setCompositeOp(colorSpace()->compositeOp(COMPOSITE_COPY));
-    }
+    lockTemporaryTarget();
+
+    if (hasTemporaryTarget()) {
+        /**
+         * Cloning a selection with COW
+         * FIXME: check whether it's faster than usual bitBlt'ing
+         */
+        tempSelection = new KisSelection(*tempSelection);
 
-    gc.bitBlt(rect.topLeft(), original, rect);
+        KisPainter gc2(tempSelection->pixelSelection());
+        setupTemporaryPainter(&gc2);
+        gc2.bitBlt(rect.topLeft(), temporaryTarget(), rect);
+    }
 
     unlockTemporaryTarget();
+
+    return tempSelection;
+}
+
+void KisSelectionBasedLayer::copyOriginalToProjection(const KisPaintDeviceSP original,
+        KisPaintDeviceSP projection,
+        const QRect& rect) const
+{
+
+    KisPainter gc(projection);
+
+    KisSelectionSP tempSelection;
+
+    if (m_d->useSelectionInProjection) {
+        tempSelection = fetchComposedInternalSelection(rect);
+    }
+
+    KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect, tempSelection);
 }
 
 QRect KisSelectionBasedLayer::cropChangeRectBySelection(const QRect &rect) const
diff --git a/krita/image/kis_selection_based_layer.h b/krita/image/kis_selection_based_layer.h
index 979dd53..43d2979 100644
--- a/krita/image/kis_selection_based_layer.h
+++ b/krita/image/kis_selection_based_layer.h
@@ -107,6 +107,16 @@ public:
     void setInternalSelection(KisSelectionSP selection);
 
     /**
+     * When painted in indirect painting mode, the internal selection
+     * might not contain actual selection, because a part of it is
+     * stored on an indirect painting device. This method returns the
+     * merged copy of the real selection. The area in \p rect only is
+     * guaranteed to be prepared. The content of the rest of the
+     * selection is undefined.
+     */
+    KisSelectionSP fetchComposedInternalSelection(const QRect &rect) const;
+
+    /**
      * gets this layer's x coordinate, taking selection into account
      * @return x-coordinate value
      */
@@ -167,6 +177,17 @@ protected:
 
     QRect cropChangeRectBySelection(const QRect &rect) const;
 
+    /**
+     * Sets if the selection should be used in
+     * copyOriginalToProjection() method.
+     *
+     * Default value is 'true'. The descendants should override it to
+     * get desired behaviour.
+     *
+     * Must be called only once in the child's constructor
+     */
+    void setUseSelectionInProjection(bool value) const;
+
 public Q_SLOTS:
 
     /**



More information about the kimageshop mailing list