[krita/kazakov/masking-brush] /: Implement dependent size changes for the Masking Brush

Dmitry Kazakov null at kde.org
Wed Dec 27 09:13:49 UTC 2017


Git commit a641fec91cba9f024286088f7c2ae622f94e5516 by Dmitry Kazakov.
Committed on 27/12/2017 at 09:10.
Pushed by dkazakov into branch 'kazakov/masking-brush'.

Implement dependent size changes for the Masking Brush

Now the masking brush changes according to these requirements:

1) When the brush size is changed in the brush editor, masking
   brush size is kept unchanged

2) When the brush size is changed using quick-controls, that is
   toolbox slider, shift+gesture, HUD display, the masking brush size
   is changed proportionally.

3) Technically, the masking brush supports disabling this "dependent
   size" functionality, but I'm not sure if it should be visible in GUI.
   It is already overcomplicated.

Technical changes:

1) Now the brushes are always **copied** when fetched from the
   brushes registry. That is, if you load the brush using
   KisBrush::fromXML(), you will always have your own copy of the
   brush object, not shared with the one in the server.

2) For the efficiency reasons, the brush tip QImage will be lazily
   shared with the one on the server using the Qt's internal algorithm.
   If you change the brush tip in you copy of the brush, Qt will deep-
   copy the corresponding QImage.

3) For the efficiency reasons, brush mipmap pyramid (KisQImagePyramid)
   is also shared among all the instances of the brush with
   the same brush tip QImage. Every time one changes the instance of
   the brush, the pyramid object is detached and reset. This basic
   lazy copying algorithm is implemented in KisSharedQImagePyramid.

CC:kimageshop at kde.org

M  +1    -0    libs/brush/CMakeLists.txt
C  +32   -19   libs/brush/KisSharedQImagePyramid.cpp [from: plugins/paintops/libpaintop/KisMaskingBrushOption.h - 050% similarity]
A  +61   -0    libs/brush/KisSharedQImagePyramid.h     [License: GPL (v2+)]
M  +1    -3    libs/brush/kis_auto_brush_factory.cpp
M  +1    -1    libs/brush/kis_auto_brush_factory.h
M  +7    -16   libs/brush/kis_brush.cpp
M  +10   -9    libs/brush/kis_brush.h
M  +1    -1    libs/brush/kis_brush_factory.h
M  +2    -2    libs/brush/kis_brush_registry.cpp
M  +1    -1    libs/brush/kis_brush_registry.h
M  +0    -1    libs/brush/kis_gbr_brush.cpp
M  +0    -1    libs/brush/kis_png_brush.cpp
M  +4    -5    libs/brush/kis_predefined_brush_factory.cpp
M  +1    -1    libs/brush/kis_predefined_brush_factory.h
M  +1    -3    libs/brush/kis_text_brush_factory.cpp
M  +1    -1    libs/brush/kis_text_brush_factory.h
M  +1    -1    libs/brush/tests/kis_auto_brush_factory_test.cpp
M  +13   -8    libs/brush/tests/kis_gbr_brush_test.cpp
M  +2    -0    libs/image/brushengine/KisPaintopSettingsIds.cpp
M  +2    -0    libs/image/brushengine/KisPaintopSettingsIds.h
M  +6    -0    libs/image/brushengine/kis_paintop_settings.cpp
M  +3    -1    plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp
M  +1    -1    plugins/paintops/hairy/kis_hairy_paintop.cpp
M  +6    -3    plugins/paintops/libpaintop/KisMaskingBrushOption.cpp
M  +4    -1    plugins/paintops/libpaintop/KisMaskingBrushOption.h
M  +16   -4    plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.cpp
M  +3    -2    plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h
M  +2    -2    plugins/paintops/libpaintop/kis_brush_based_paintop.cpp
M  +1    -1    plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp
M  +71   -60   plugins/paintops/libpaintop/kis_brush_chooser.cpp
M  +2    -5    plugins/paintops/libpaintop/kis_brush_chooser.h
M  +2    -17   plugins/paintops/libpaintop/kis_brush_option.cpp
M  +0    -5    plugins/paintops/libpaintop/kis_brush_option.h
M  +1    -1    plugins/paintops/sketch/kis_sketch_paintop.cpp
M  +1    -1    plugins/paintops/spray/kis_spray_paintop.cpp

https://commits.kde.org/krita/a641fec91cba9f024286088f7c2ae622f94e5516

diff --git a/libs/brush/CMakeLists.txt b/libs/brush/CMakeLists.txt
index 88e61fe6074..e2ca732025d 100644
--- a/libs/brush/CMakeLists.txt
+++ b/libs/brush/CMakeLists.txt
@@ -20,6 +20,7 @@ set(kritalibbrush_LIB_SRCS
     kis_png_brush.cpp
     kis_svg_brush.cpp
     kis_qimage_pyramid.cpp
+    KisSharedQImagePyramid.cpp
     kis_text_brush.cpp
     kis_auto_brush_factory.cpp
     kis_text_brush_factory.cpp
diff --git a/plugins/paintops/libpaintop/KisMaskingBrushOption.h b/libs/brush/KisSharedQImagePyramid.cpp
similarity index 50%
copy from plugins/paintops/libpaintop/KisMaskingBrushOption.h
copy to libs/brush/KisSharedQImagePyramid.cpp
index f35dcd57d35..75e86f42087 100644
--- a/plugins/paintops/libpaintop/KisMaskingBrushOption.h
+++ b/libs/brush/KisSharedQImagePyramid.cpp
@@ -16,34 +16,47 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#ifndef KISMASKINGBRUSHOPTION_H
-#define KISMASKINGBRUSHOPTION_H
+#include "KisSharedQImagePyramid.h"
 
-#include <kritapaintop_export.h>
-#include <QScopedPointer>
+#include <QMutexLocker>
 
-#include <kis_types.h>
-#include "kis_paintop_option.h"
+#include "kis_qimage_pyramid.h"
+#include "kis_brush.h"
 
 
-class PAINTOP_EXPORT KisMaskingBrushOption : public KisPaintOpOption
+KisSharedQImagePyramid::KisSharedQImagePyramid()
 {
-public:
-    KisMaskingBrushOption();
-    ~KisMaskingBrushOption() override;
+}
 
-    void writeOptionSetting(KisPropertiesConfigurationSP setting) const override;
-    void readOptionSetting(const KisPropertiesConfigurationSP setting) override;
+KisSharedQImagePyramid::~KisSharedQImagePyramid()
+{
+}
+
+const KisQImagePyramid *KisSharedQImagePyramid::pyramid(const KisBrush *brush) const
+{
+    const KisQImagePyramid * result = 0;
 
-    void setImage(KisImageWSP image) override;
+    if (m_cachedPyramidPointer) {
+        result = m_cachedPyramidPointer;
+    } else {
+        QMutexLocker l(&m_mutex);
 
-    void lodLimitations(KisPaintopLodLimitations *l) const override;
+        if (!m_pyramid) {
+            m_pyramid.reset(new KisQImagePyramid(brush->brushTipImage()));
+        }
 
-private:
-    struct Private;
-    const QScopedPointer<Private> m_d;
-};
+        m_cachedPyramidPointer = m_pyramid.data();
+        result = m_pyramid.data();
+    }
 
+    return result;
+}
 
 
-#endif // KISMASKINGBRUSHOPTION_H
+
+bool KisSharedQImagePyramid::isNull() const
+{
+    QMutexLocker l(&m_mutex);
+    return bool(m_pyramid);
+}
+
diff --git a/libs/brush/KisSharedQImagePyramid.h b/libs/brush/KisSharedQImagePyramid.h
new file mode 100644
index 00000000000..bc3d9b5cbe9
--- /dev/null
+++ b/libs/brush/KisSharedQImagePyramid.h
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (c) 2017 Dmitry Kazakov <dimula73 at gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KISSHAREDQIMAGEPYRAMID_H
+#define KISSHAREDQIMAGEPYRAMID_H
+
+#include "kritabrush_export.h"
+
+#include <QSharedPointer>
+#include <QMutex>
+#include <QAtomicPointer>
+
+
+class KisQImagePyramid;
+class KisBrush;
+
+/**
+ * A special class for storing the shared brushes pyramid among different brushes,
+ * which can be used by different threads. All the calls to pyramid() are thread-safe.
+ *
+ * Please note, that one cannot alter the pyramid. If the brush alters the pyramid,
+ * it should just detach from this object and create a new, unshared one.
+ */
+
+class BRUSH_EXPORT KisSharedQImagePyramid
+{
+public:
+    KisSharedQImagePyramid();
+    ~KisSharedQImagePyramid();
+
+public:
+
+    // lazy create and return the pyramid
+    const KisQImagePyramid* pyramid(const KisBrush *brush) const;
+
+    // return true if the pyramid is already prepared
+    bool isNull() const;
+
+private:
+    mutable QMutex m_mutex;
+
+    mutable QSharedPointer<const KisQImagePyramid> m_pyramid;
+    mutable QAtomicPointer<const KisQImagePyramid> m_cachedPyramidPointer;
+};
+
+#endif // KISSHAREDQIMAGEPYRAMID_H
diff --git a/libs/brush/kis_auto_brush_factory.cpp b/libs/brush/kis_auto_brush_factory.cpp
index d597c469303..ec0a697a136 100644
--- a/libs/brush/kis_auto_brush_factory.cpp
+++ b/libs/brush/kis_auto_brush_factory.cpp
@@ -26,10 +26,8 @@
 #include "kis_mask_generator.h"
 #include <kis_dom_utils.h>
 
-KisBrushSP KisAutoBrushFactory::getOrCreateBrush(const QDomElement& brushDefinition, bool forceCopy)
+KisBrushSP KisAutoBrushFactory::createBrush(const QDomElement &brushDefinition)
 {
-    Q_UNUSED(forceCopy);
-
     KisMaskGenerator* mask = KisMaskGenerator::fromXML(brushDefinition.firstChildElement("MaskGenerator"));
     double angle = KisDomUtils::toDouble(brushDefinition.attribute("angle", "0.0"));
     double randomness = KisDomUtils::toDouble(brushDefinition.attribute("randomness", "0.0"));
diff --git a/libs/brush/kis_auto_brush_factory.h b/libs/brush/kis_auto_brush_factory.h
index 719bd29b2af..e52385b4ca1 100644
--- a/libs/brush/kis_auto_brush_factory.h
+++ b/libs/brush/kis_auto_brush_factory.h
@@ -50,7 +50,7 @@ public:
      * object. If this call leads to the creation of a resource, it should be
      * added to the resource provider, too.
      */
-    KisBrushSP getOrCreateBrush(const QDomElement& brushDefinition, bool forceCopy) override;
+    KisBrushSP createBrush(const QDomElement& brushDefinition) override;
 
 };
 
diff --git a/libs/brush/kis_brush.cpp b/libs/brush/kis_brush.cpp
index 5fc231b1453..0a8c45ff1b3 100644
--- a/libs/brush/kis_brush.cpp
+++ b/libs/brush/kis_brush.cpp
@@ -46,6 +46,7 @@
 #include <brushengine/kis_paint_information.h>
 #include <kis_fixed_paint_device.h>
 #include <kis_qimage_pyramid.h>
+#include <KisSharedQImagePyramid.h>
 #include <brushengine/kis_paintop_lod_limitations.h>
 
 
@@ -126,7 +127,7 @@ struct KisBrush::Private {
     double spacing;
     QPointF hotSpot;
 
-    mutable QSharedPointer<const KisQImagePyramid> brushPyramid;
+    mutable QSharedPointer<KisSharedQImagePyramid> brushPyramid;
 
     QImage brushTipImage;
 
@@ -179,7 +180,6 @@ KisBrush::KisBrush(const KisBrush& rhs)
 
 KisBrush::~KisBrush()
 {
-    clearBrushPyramid();
     delete d;
 }
 
@@ -348,9 +348,9 @@ void KisBrush::toXML(QDomDocument& /*document*/ , QDomElement& element) const
     element.setAttribute("BrushVersion", "2");
 }
 
-KisBrushSP KisBrush::fromXML(const QDomElement& element, bool forceCopy)
+KisBrushSP KisBrush::fromXML(const QDomElement& element)
 {
-    KisBrushSP brush = KisBrushRegistry::instance()->getOrCreateBrush(element, forceCopy);
+    KisBrushSP brush = KisBrushRegistry::instance()->createBrush(element);
     if (brush && element.attribute("BrushVersion", "1") == "1") {
         brush->setScale(brush->scale() * 2.0);
     }
@@ -454,16 +454,9 @@ bool KisBrush::threadingAllowed() const
     return d->threadingAllowed;
 }
 
-void KisBrush::prepareBrushPyramid() const
-{
-    if (!d->brushPyramid) {
-        d->brushPyramid = toQShared(new KisQImagePyramid(brushTipImage()));
-    }
-}
-
 void KisBrush::clearBrushPyramid()
 {
-    d->brushPyramid.clear();
+    d->brushPyramid.reset(new KisSharedQImagePyramid());
 }
 
 void KisBrush::mask(KisFixedPaintDeviceSP dst, const KoColor& color, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY, qreal softnessFactor) const
@@ -489,8 +482,7 @@ void KisBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst,
     Q_UNUSED(info_);
     Q_UNUSED(softnessFactor);
 
-    prepareBrushPyramid();
-    QImage outputImage = d->brushPyramid->createImage(KisDabShape(
+    QImage outputImage = d->brushPyramid->pyramid(this)->createImage(KisDabShape(
             shape.scale() * d->scale, shape.ratio(),
             -normalizeAngle(shape.rotation() + d->angle)),
         subPixelX, subPixelY);
@@ -576,8 +568,7 @@ KisFixedPaintDeviceSP KisBrush::paintDevice(const KoColorSpace * colorSpace,
     double angle = normalizeAngle(shape.rotation() + d->angle);
     double scale = shape.scale() * d->scale;
 
-    prepareBrushPyramid();
-    QImage outputImage = d->brushPyramid->createImage(
+    QImage outputImage = d->brushPyramid->pyramid(this)->createImage(
         KisDabShape(scale, shape.ratio(), -angle), subPixelX, subPixelY);
 
     KisFixedPaintDeviceSP dab = new KisFixedPaintDevice(colorSpace);
diff --git a/libs/brush/kis_brush.h b/libs/brush/kis_brush.h
index c336216c592..42935fe01b0 100644
--- a/libs/brush/kis_brush.h
+++ b/libs/brush/kis_brush.h
@@ -325,7 +325,7 @@ public:
      */
     virtual void toXML(QDomDocument& , QDomElement&) const;
 
-    static KisBrushSP fromXML(const QDomElement& element, bool forceCopy = false);
+    static KisBrushSP fromXML(const QDomElement& element);
 
     virtual const KisBoundary* boundary() const;
     virtual QPainterPath outline() const;
@@ -335,14 +335,13 @@ public:
     virtual void setAngle(qreal _angle);
     qreal angle() const;
 
-    void prepareBrushPyramid() const;
     void clearBrushPyramid();
 
     virtual void lodLimitations(KisPaintopLodLimitations *l) const;
 
     virtual KisBrush* clone() const = 0;
 
-//protected:
+protected:
 
     KisBrush(const KisBrush& rhs);
 
@@ -352,12 +351,6 @@ public:
 
     void setHotSpot(QPointF);
 
-    /**
-     * The image is used to represent the brush in the gui, and may also, depending on the brush type
-     * be used to define the actual brush instance.
-     */
-    virtual void setBrushTipImage(const QImage& image);
-
     /**
      * XXX
      */
@@ -365,6 +358,14 @@ public:
 
     virtual void setHasColor(bool hasColor);
 
+public:
+
+    /**
+     * The image is used to represent the brush in the gui, and may also, depending on the brush type
+     * be used to define the actual brush instance.
+     */
+    virtual void setBrushTipImage(const QImage& image);
+
     /**
      * Returns true if the brush has a bunch of pixels almost
      * fully transparent in the very center. If the brush is pierced,
diff --git a/libs/brush/kis_brush_factory.h b/libs/brush/kis_brush_factory.h
index f6d694159ac..ca1b3299594 100644
--- a/libs/brush/kis_brush_factory.h
+++ b/libs/brush/kis_brush_factory.h
@@ -47,7 +47,7 @@ public:
      * object. If this call leads to the creation of a resource, it should be
      * added to the resource provider, too.
      */
-    virtual KisBrushSP getOrCreateBrush(const QDomElement& element, bool forceCopy) = 0;
+    virtual KisBrushSP createBrush(const QDomElement& element) = 0;
 
 };
 
diff --git a/libs/brush/kis_brush_registry.cpp b/libs/brush/kis_brush_registry.cpp
index f64cb5d1d99..e832974f35b 100644
--- a/libs/brush/kis_brush_registry.cpp
+++ b/libs/brush/kis_brush_registry.cpp
@@ -62,7 +62,7 @@ KisBrushRegistry* KisBrushRegistry::instance()
 }
 
 
-KisBrushSP KisBrushRegistry::getOrCreateBrush(const QDomElement& element, bool forceCopy)
+KisBrushSP KisBrushRegistry::createBrush(const QDomElement& element)
 {
     QString brushType = element.attribute("type");
 
@@ -71,6 +71,6 @@ KisBrushSP KisBrushRegistry::getOrCreateBrush(const QDomElement& element, bool f
     KisBrushFactory* factory = get(brushType);
     if (!factory) return 0;
 
-    return factory->getOrCreateBrush(element, forceCopy);
+    return factory->createBrush(element);
 }
 
diff --git a/libs/brush/kis_brush_registry.h b/libs/brush/kis_brush_registry.h
index 82066fcb8ca..1713cc067ba 100644
--- a/libs/brush/kis_brush_registry.h
+++ b/libs/brush/kis_brush_registry.h
@@ -42,7 +42,7 @@ public:
 
     static KisBrushRegistry* instance();
 
-    KisBrushSP getOrCreateBrush(const QDomElement& element, bool forceCopy = false);
+    KisBrushSP createBrush(const QDomElement& element);
 
 private:
     KisBrushRegistry(const KisBrushRegistry&);
diff --git a/libs/brush/kis_gbr_brush.cpp b/libs/brush/kis_gbr_brush.cpp
index 77a9beedddd..d25aa1d341a 100644
--- a/libs/brush/kis_gbr_brush.cpp
+++ b/libs/brush/kis_gbr_brush.cpp
@@ -139,7 +139,6 @@ KisGbrBrush::KisGbrBrush(const KisGbrBrush& rhs)
     , d(new Private(*rhs.d))
 {
     setName(rhs.name());
-    setBrushTipImage(rhs.brushTipImage());
     d->data = QByteArray();
     setValid(rhs.valid());
 }
diff --git a/libs/brush/kis_png_brush.cpp b/libs/brush/kis_png_brush.cpp
index 879b28fa570..4c1b95cb3b8 100644
--- a/libs/brush/kis_png_brush.cpp
+++ b/libs/brush/kis_png_brush.cpp
@@ -38,7 +38,6 @@ KisPngBrush::KisPngBrush(const KisPngBrush &rhs)
     : KisScalingSizeBrush(rhs)
 {
     setSpacing(rhs.spacing());
-    setBrushTipImage(rhs.brushTipImage());
     if (brushTipImage().isGrayscale()) {
         setBrushType(MASK);
         setHasColor(false);
diff --git a/libs/brush/kis_predefined_brush_factory.cpp b/libs/brush/kis_predefined_brush_factory.cpp
index 4a2d32aa0ad..e232c3e595f 100644
--- a/libs/brush/kis_predefined_brush_factory.cpp
+++ b/libs/brush/kis_predefined_brush_factory.cpp
@@ -33,7 +33,7 @@ QString KisPredefinedBrushFactory::id() const
     return m_id;
 }
 
-KisBrushSP KisPredefinedBrushFactory::getOrCreateBrush(const QDomElement& brushDefinition, bool forceCopy)
+KisBrushSP KisPredefinedBrushFactory::createBrush(const QDomElement& brushDefinition)
 {
     KisBrushResourceServer *rServer = KisBrushServer::instance()->brushServer();
     QString brushFileName = brushDefinition.attribute("filename", "");
@@ -49,11 +49,10 @@ KisBrushSP KisPredefinedBrushFactory::getOrCreateBrush(const QDomElement& brushD
         brush = rServer->resources().first();
     }
 
-    Q_ASSERT(brush);
+    KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(brush, 0);
 
-    if (forceCopy) {
-        brush = brush->clone();
-    }
+    // we always return a copy of the brush!
+    brush = brush->clone();
 
     double spacing = KisDomUtils::toDouble(brushDefinition.attribute("spacing", "0.25"));
     brush->setSpacing(spacing);
diff --git a/libs/brush/kis_predefined_brush_factory.h b/libs/brush/kis_predefined_brush_factory.h
index af5fc50d6d9..5c3cc188995 100644
--- a/libs/brush/kis_predefined_brush_factory.h
+++ b/libs/brush/kis_predefined_brush_factory.h
@@ -32,7 +32,7 @@ public:
     KisPredefinedBrushFactory(const QString &brushType);
 
     QString id() const override;
-    KisBrushSP getOrCreateBrush(const QDomElement& brushDefinition, bool forceCopy) override;
+    KisBrushSP createBrush(const QDomElement& brushDefinition) override;
 
 private:
     const QString m_id;
diff --git a/libs/brush/kis_text_brush_factory.cpp b/libs/brush/kis_text_brush_factory.cpp
index 6ae80550710..1d7fad257f7 100644
--- a/libs/brush/kis_text_brush_factory.cpp
+++ b/libs/brush/kis_text_brush_factory.cpp
@@ -22,10 +22,8 @@
 #include <kis_dom_utils.h>
 #include "kis_text_brush.h"
 
-KisBrushSP KisTextBrushFactory::getOrCreateBrush(const QDomElement& brushDefinition, bool forceCopy)
+KisBrushSP KisTextBrushFactory::createBrush(const QDomElement& brushDefinition)
 {
-    Q_UNUSED(forceCopy);
-
     QString text = brushDefinition.attribute("text", "The quick brown fox ate your text");
     QFont font;
     font.fromString(brushDefinition.attribute("font"));
diff --git a/libs/brush/kis_text_brush_factory.h b/libs/brush/kis_text_brush_factory.h
index e854bcc053b..0ee25012533 100644
--- a/libs/brush/kis_text_brush_factory.h
+++ b/libs/brush/kis_text_brush_factory.h
@@ -46,7 +46,7 @@ public:
      * object. If this call leads to the creation of a resource, it should be
      * added to the resource provider, too.
      */
-    KisBrushSP getOrCreateBrush(const QDomElement& brushDefinition, bool forceCopy) override;
+    KisBrushSP createBrush(const QDomElement& brushDefinition) override;
 
 
 };
diff --git a/libs/brush/tests/kis_auto_brush_factory_test.cpp b/libs/brush/tests/kis_auto_brush_factory_test.cpp
index 0b9930b46b4..724d027f3fb 100644
--- a/libs/brush/tests/kis_auto_brush_factory_test.cpp
+++ b/libs/brush/tests/kis_auto_brush_factory_test.cpp
@@ -20,7 +20,7 @@ void KisAutoBrushFactoryTest::testXMLClone()
     QDomDocument d;
     QDomElement e = d.createElement("Brush");
     brush->toXML(d, e);
-    KisBrushSP clone = KisAutoBrushFactory().getOrCreateBrush(e, false);
+    KisBrushSP clone = KisAutoBrushFactory().createBrush(e);
 
     // Test that the clone has the same settings as the original brush.
     QCOMPARE(brush->width(), clone->width());
diff --git a/libs/brush/tests/kis_gbr_brush_test.cpp b/libs/brush/tests/kis_gbr_brush_test.cpp
index e5994faef51..75c31904a67 100644
--- a/libs/brush/tests/kis_gbr_brush_test.cpp
+++ b/libs/brush/tests/kis_gbr_brush_test.cpp
@@ -101,7 +101,6 @@ void KisGbrBrushTest::testImageGeneration()
     Q_UNUSED(res);
     Q_ASSERT(res);
     QVERIFY(!brush->brushTipImage().isNull());
-    brush->prepareBrushPyramid();
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
@@ -128,30 +127,38 @@ void KisGbrBrushTest::testImageGeneration()
     }
 }
 
+#include "KisSharedQImagePyramid.h"
+
 void KisGbrBrushTest::benchmarkPyramidCreation()
 {
-    KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr");
+    QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"));
     brush->load();
     QVERIFY(!brush->brushTipImage().isNull());
 
     QBENCHMARK {
-        brush->prepareBrushPyramid();
-        brush->clearBrushPyramid();
+        KisSharedQImagePyramid sharedPyramid;
+        QVERIFY(sharedPyramid.pyramid(brush.data())); // avoid compiler elimination of unused code!
     }
 }
 
 void KisGbrBrushTest::benchmarkScaling()
 {
-    KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr");
+    QScopedPointer<KisGbrBrush> brush(new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr"));
     brush->load();
     QVERIFY(!brush->brushTipImage().isNull());
-    brush->prepareBrushPyramid();
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
     KisPaintInformation info(QPointF(100.0, 100.0), 0.5);
     KisFixedPaintDeviceSP dab;
 
+    {
+        // warm up the pyramid!
+        dab = brush->paintDevice(cs, KisDabShape(qreal(qrand()) / RAND_MAX * 2.0, 1.0, 0.0), info);
+        QVERIFY(dab); // avoid compiler elimination of unused code!
+        dab.clear();
+    }
+
     QBENCHMARK {
         dab = brush->paintDevice(cs, KisDabShape(qreal(qrand()) / RAND_MAX * 2.0, 1.0, 0.0), info);
         //dab->convertToQImage(0).save(QString("dab_%1_new_smooth.png").arg(i++));
@@ -163,7 +170,6 @@ void KisGbrBrushTest::benchmarkRotation()
     KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr");
     brush->load();
     QVERIFY(!brush->brushTipImage().isNull());
-    brush->prepareBrushPyramid();
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
@@ -180,7 +186,6 @@ void KisGbrBrushTest::benchmarkMaskScaling()
     KisGbrBrush* brush = new KisGbrBrush(QString(FILES_DATA_DIR) + QDir::separator() + "testing_brush_512_bars.gbr");
     brush->load();
     QVERIFY(!brush->brushTipImage().isNull());
-    brush->prepareBrushPyramid();
     qsrand(1);
 
     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8();
diff --git a/libs/image/brushengine/KisPaintopSettingsIds.cpp b/libs/image/brushengine/KisPaintopSettingsIds.cpp
index d078d63a9c8..1edb0cb3303 100644
--- a/libs/image/brushengine/KisPaintopSettingsIds.cpp
+++ b/libs/image/brushengine/KisPaintopSettingsIds.cpp
@@ -23,6 +23,8 @@ namespace KisPaintOpUtils {
 const char MaskingBrushPaintOpId[] = "paintbrush";
 const char MaskingBrushEnabledTag[] = "MaskingBrush/Enabled";
 const char MaskingBrushCompositeOpTag[] = "MaskingBrush/MaskingCompositeOp";
+const char MaskingBrushUseMasterSizeTag[] = "MaskingBrush/UseMasterSize";
+const char MaskingBrushMasterSizeCoeffTag[] = "MaskingBrush/MasterSizeCoeff";
 const char MaskingBrushPresetPrefix[] = "MaskingBrush/Preset/";
 
 }
diff --git a/libs/image/brushengine/KisPaintopSettingsIds.h b/libs/image/brushengine/KisPaintopSettingsIds.h
index bc50c8f4a05..2b8014edf54 100644
--- a/libs/image/brushengine/KisPaintopSettingsIds.h
+++ b/libs/image/brushengine/KisPaintopSettingsIds.h
@@ -26,6 +26,8 @@ namespace KisPaintOpUtils {
 KRITAIMAGE_EXPORT extern const char MaskingBrushPaintOpId[];
 KRITAIMAGE_EXPORT extern const char MaskingBrushEnabledTag[];
 KRITAIMAGE_EXPORT extern const char MaskingBrushCompositeOpTag[];
+KRITAIMAGE_EXPORT extern const char MaskingBrushUseMasterSizeTag[];
+KRITAIMAGE_EXPORT extern const char MaskingBrushMasterSizeCoeffTag[];
 KRITAIMAGE_EXPORT extern const char MaskingBrushPresetPrefix[];
 
 }
diff --git a/libs/image/brushengine/kis_paintop_settings.cpp b/libs/image/brushengine/kis_paintop_settings.cpp
index 8b80a4965c7..1ed78ea6e62 100644
--- a/libs/image/brushengine/kis_paintop_settings.cpp
+++ b/libs/image/brushengine/kis_paintop_settings.cpp
@@ -161,6 +161,12 @@ KisPaintOpSettingsSP KisPaintOpSettings::createMaskingSettings() const
     KisPaintOpSettingsSP maskingSettings = KisPaintOpRegistry::instance()->settings(pixelBrushId);
     this->getPrefixedProperties(KisPaintOpUtils::MaskingBrushPresetPrefix, maskingSettings);
 
+    const bool useMasterSize = this->getBool(KisPaintOpUtils::MaskingBrushUseMasterSizeTag, true);
+    if (useMasterSize) {
+        const qreal masterSizeCoeff = getDouble(KisPaintOpUtils::MaskingBrushMasterSizeCoeffTag, 1.0);
+        maskingSettings->setPaintOpSize(masterSizeCoeff * paintOpSize());
+    }
+
     return maskingSettings;
 }
 
diff --git a/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp b/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp
index 9b687fced21..41c69534c02 100644
--- a/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp
+++ b/plugins/paintops/defaultpaintops/brush/kis_brushop_settings_widget.cpp
@@ -85,8 +85,10 @@ KisBrushOpSettingsWidget::KisBrushOpSettingsWidget(QWidget* parent)
     addPaintOpOption(new KisTextureOption(), i18n("Pattern"));
     addPaintOpOption(new KisCurveOptionWidget(new KisPressureTextureStrengthOption(), i18n("Weak"), i18n("Strong")), i18n("Strength"));
 
+    KisMaskingBrushOption::MasterBrushSizeAdapter sizeAdapter =
+        [this] () { return this->brush()->userEffectiveSize(); };
 
-    addPaintOpOption(new KisMaskingBrushOption(), i18n("Brush Tip"));
+    addPaintOpOption(new KisMaskingBrushOption(sizeAdapter), i18n("Brush Tip"));
 
 
     {
diff --git a/plugins/paintops/hairy/kis_hairy_paintop.cpp b/plugins/paintops/hairy/kis_hairy_paintop.cpp
index ad592f3a244..6811707089d 100644
--- a/plugins/paintops/hairy/kis_hairy_paintop.cpp
+++ b/plugins/paintops/hairy/kis_hairy_paintop.cpp
@@ -49,7 +49,7 @@ KisHairyPaintOp::KisHairyPaintOp(const KisPaintOpSettingsSP settings, KisPainter
     m_dev = node ? node->paintDevice() : 0;
 
     KisBrushOption brushOption;
-    brushOption.readOptionSettingForceCopy(settings);
+    brushOption.readOptionSetting(settings);
     KisBrushSP brush = brushOption.brush();
     KisFixedPaintDeviceSP dab = cachedDab(painter->device()->compositionSourceColorSpace());
     if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
diff --git a/plugins/paintops/libpaintop/KisMaskingBrushOption.cpp b/plugins/paintops/libpaintop/KisMaskingBrushOption.cpp
index df703fdb022..8cd1121a2f2 100644
--- a/plugins/paintops/libpaintop/KisMaskingBrushOption.cpp
+++ b/plugins/paintops/libpaintop/KisMaskingBrushOption.cpp
@@ -65,12 +65,15 @@ struct KisMaskingBrushOption::Private
     QScopedPointer<QWidget> ui;
     KisPredefinedBrushChooser *brushChooser = 0;
     QComboBox *compositeSelector = 0;
+    MasterBrushSizeAdapter masterBrushSizeAdapter;
 };
 
-KisMaskingBrushOption::KisMaskingBrushOption()
+KisMaskingBrushOption::KisMaskingBrushOption(MasterBrushSizeAdapter masterBrushSizeAdapter)
     : KisPaintOpOption(KisPaintOpOption::MASKING_BRUSH, false),
       m_d(new Private())
 {
+    m_d->masterBrushSizeAdapter = masterBrushSizeAdapter;
+
     setObjectName("KisMaskingBrushOption");
     setConfigurationPage(m_d->ui.data());
 
@@ -91,13 +94,13 @@ void KisMaskingBrushOption::writeOptionSetting(KisPropertiesConfigurationSP sett
     props.brush = m_d->brushChooser->brush();
     props.compositeOpId = m_d->compositeSelector->currentData().toString();
 
-    props.write(setting.data());
+    props.write(setting.data(), m_d->masterBrushSizeAdapter());
 }
 
 void KisMaskingBrushOption::readOptionSetting(const KisPropertiesConfigurationSP setting)
 {
     KisMaskingBrushOptionProperties props;
-    props.read(setting.data());
+    props.read(setting.data(), m_d->masterBrushSizeAdapter());
 
     setChecked(props.isEnabled);
 
diff --git a/plugins/paintops/libpaintop/KisMaskingBrushOption.h b/plugins/paintops/libpaintop/KisMaskingBrushOption.h
index f35dcd57d35..a583b09768e 100644
--- a/plugins/paintops/libpaintop/KisMaskingBrushOption.h
+++ b/plugins/paintops/libpaintop/KisMaskingBrushOption.h
@@ -29,7 +29,10 @@
 class PAINTOP_EXPORT KisMaskingBrushOption : public KisPaintOpOption
 {
 public:
-    KisMaskingBrushOption();
+    typedef std::function<qreal()> MasterBrushSizeAdapter;
+
+public:
+    KisMaskingBrushOption(MasterBrushSizeAdapter masterBrushSizeAdapter);
     ~KisMaskingBrushOption() override;
 
     void writeOptionSetting(KisPropertiesConfigurationSP setting) const override;
diff --git a/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.cpp b/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.cpp
index ec395c59897..bf45b61b6af 100644
--- a/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.cpp
+++ b/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.cpp
@@ -25,15 +25,21 @@
 
 
 KisMaskingBrushOptionProperties::KisMaskingBrushOptionProperties()
-    : isEnabled(false),
-      compositeOpId(COMPOSITE_MULT)
+    : compositeOpId(COMPOSITE_MULT)
+
 {
 }
 
-void KisMaskingBrushOptionProperties::write(KisPropertiesConfiguration *setting) const
+void KisMaskingBrushOptionProperties::write(KisPropertiesConfiguration *setting, qreal masterBrushSize) const
 {
     setting->setProperty(KisPaintOpUtils::MaskingBrushEnabledTag, isEnabled);
     setting->setProperty(KisPaintOpUtils::MaskingBrushCompositeOpTag, compositeOpId);
+    setting->setProperty(KisPaintOpUtils::MaskingBrushUseMasterSizeTag, useMasterSize);
+
+    const qreal masterSizeCoeff =
+        brush && masterBrushSize > 0 ? brush->userEffectiveSize() / masterBrushSize : 1.0;
+
+    setting->setProperty(KisPaintOpUtils::MaskingBrushMasterSizeCoeffTag, masterSizeCoeff);
 
     // TODO: skip saving in some cases?
     // if (!isEnabled) return;
@@ -60,10 +66,11 @@ void KisMaskingBrushOptionProperties::write(KisPropertiesConfiguration *setting)
     }
 }
 
-void KisMaskingBrushOptionProperties::read(const KisPropertiesConfiguration *setting)
+void KisMaskingBrushOptionProperties::read(const KisPropertiesConfiguration *setting, qreal masterBrushSize)
 {
     isEnabled = setting->getBool(KisPaintOpUtils::MaskingBrushEnabledTag);
     compositeOpId = setting->getString(KisPaintOpUtils::MaskingBrushCompositeOpTag, COMPOSITE_MULT);
+    useMasterSize = setting->getBool(KisPaintOpUtils::MaskingBrushUseMasterSizeTag, true);
 
     KisPropertiesConfigurationSP embeddedConfig = new KisPropertiesConfiguration();
     setting->getPrefixedProperties(KisPaintOpUtils::MaskingBrushPresetPrefix, embeddedConfig);
@@ -72,4 +79,9 @@ void KisMaskingBrushOptionProperties::read(const KisPropertiesConfiguration *set
     option.readOptionSetting(embeddedConfig);
 
     brush = option.brush();
+
+    if (brush && useMasterSize) {
+        const qreal masterSizeCoeff = setting->getDouble(KisPaintOpUtils::MaskingBrushMasterSizeCoeffTag, 1.0);
+        brush->setUserEffectiveSize(masterSizeCoeff * masterBrushSize);
+    }
 }
diff --git a/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h b/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h
index 5fae6690917..8ad9ff1a1a3 100644
--- a/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h
+++ b/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h
@@ -33,9 +33,10 @@ struct PAINTOP_EXPORT KisMaskingBrushOptionProperties
     bool isEnabled = false;
     KisBrushSP brush;
     QString compositeOpId;
+    bool useMasterSize = true;
 
-    void write(KisPropertiesConfiguration *setting) const;
-    void read(const KisPropertiesConfiguration *setting);
+    void write(KisPropertiesConfiguration *setting, qreal masterBrushSize) const;
+    void read(const KisPropertiesConfiguration *setting, qreal masterBrushSize);
 };
 
 #endif // KISMASKINGBRUSHOPTIONPROPERTIES_H
diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp
index a119ae5348f..f81d876b72c 100644
--- a/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp
+++ b/plugins/paintops/libpaintop/kis_brush_based_paintop.cpp
@@ -45,7 +45,7 @@ void TextBrushInitializationWorkaround::preinitialize(KisPropertiesConfiguration
 {
     if (KisBrushOption::isTextBrush(settings.data())) {
         KisBrushOption brushOption;
-        brushOption.readOptionSettingForceCopy(settings);
+        brushOption.readOptionSetting(settings);
         m_brush = brushOption.brush();
         m_settings = settings;
     }
@@ -90,7 +90,7 @@ KisBrushBasedPaintOp::KisBrushBasedPaintOp(const KisPropertiesConfigurationSP se
 
     if (!m_brush) {
         KisBrushOption brushOption;
-        brushOption.readOptionSettingForceCopy(settings);
+        brushOption.readOptionSetting(settings);
         m_brush = brushOption.brush();
     }
 
diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp
index 97b9a7dddac..51ff8abbb57 100644
--- a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp
+++ b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp
@@ -81,7 +81,7 @@ KisPaintOpSettingsSP KisBrushBasedPaintOpSettings::clone() const
 {
     KisPaintOpSettingsSP _settings = KisOutlineGenerationPolicy<KisPaintOpSettings>::clone();
     KisBrushBasedPaintOpSettingsSP settings = dynamic_cast<KisBrushBasedPaintOpSettings*>(_settings.data());
-    settings->m_savedBrush = this->brush();
+    settings->m_savedBrush = 0;
     return settings;
 }
 
diff --git a/plugins/paintops/libpaintop/kis_brush_chooser.cpp b/plugins/paintops/libpaintop/kis_brush_chooser.cpp
index 8db32f1d86f..3607f976dae 100644
--- a/plugins/paintops/libpaintop/kis_brush_chooser.cpp
+++ b/plugins/paintops/libpaintop/kis_brush_chooser.cpp
@@ -40,7 +40,6 @@
 #include <KoResourceItemChooser.h>
 
 #include <kis_icon.h>
-#include "kis_brush_registry.h"
 #include "kis_brush_server.h"
 #include "widgets/kis_slider_spin_box.h"
 #include "widgets/kis_multipliers_double_slider_spinbox.h"
@@ -133,8 +132,8 @@ KisPredefinedBrushChooser::KisPredefinedBrushChooser(QWidget *parent, const char
     KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer();
     QSharedPointer<KisBrushResourceServerAdapter> adapter(new KisBrushResourceServerAdapter(rServer));
 
-
     m_itemChooser = new KoResourceItemChooser(adapter, this);
+    m_itemChooser->setObjectName("brush_selector");
 
     m_itemChooser->showTaggingBar(true);
     m_itemChooser->setColumnCount(10);
@@ -184,21 +183,52 @@ KisPredefinedBrushChooser::~KisPredefinedBrushChooser()
 {
 }
 
-void KisPredefinedBrushChooser::setBrush(KisBrushSP _brush)
+void KisPredefinedBrushChooser::setBrush(KisBrushSP brush)
 {
-    m_itemChooser->setCurrentResource(_brush.data());
-    update(_brush.data());
+    /**
+     * Warning: since the brushes are always cloned after loading from XML or
+     * fetching from the server, we cannot just ask for that brush explicitly.
+     * Instead, we should search for the brush with the same filename and/or name
+     * and load it. Please take it into account that after selecting the brush
+     * explicitly in the chooser, m_itemChooser->currentResource() might be
+     * **not** the same as the value in m_brush.
+     *
+     * Ideally, if the resource is not found on the server, we should add it, but
+     * it might lead to a set of weird consequences. So for now we just
+     * select nothing.
+     */
+
+    KisBrushResourceServer* server = KisBrushServer::instance()->brushServer();
+    KoResource *resource = server->resourceByFilename(brush->shortFilename()).data();
+
+    if (!resource) {
+        resource = server->resourceByName(brush->name()).data();
+    }
+
+    if (!resource) {
+        resource = brush.data();
+    }
+
+    m_itemChooser->setCurrentResource(resource);
+    update(brush.data());
 }
 
 void KisPredefinedBrushChooser::slotResetBrush()
 {
+    /**
+     * The slot also resets the brush on the server
+     *
+     * TODO: technically, after we refactored all the brushes to be forked,
+     *       we can just re-update the brush from the server without reloading.
+     *       But it needs testing.
+     */
+
     KisBrush *brush = dynamic_cast<KisBrush *>(m_itemChooser->currentResource());
     if (brush) {
         brush->load();
         brush->setScale(1.0);
         brush->setAngle(0.0);
 
-        slotActivatedBrush(brush);
         update(brush);
         emit sigBrushChanged();
     }
@@ -206,35 +236,33 @@ void KisPredefinedBrushChooser::slotResetBrush()
 
 void KisPredefinedBrushChooser::slotSetItemSize(qreal sizeValue)
 {
-    KisBrush *brush = dynamic_cast<KisBrush *>(m_itemChooser->currentResource());
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush);
 
-    if (brush) {
-        int brushWidth = brush->width();
+    if (m_brush) {
+        int brushWidth = m_brush->width();
 
-        brush->setScale(sizeValue / qreal(brushWidth));
-        slotActivatedBrush(brush);
+        m_brush->setScale(sizeValue / qreal(brushWidth));
         emit sigBrushChanged();
     }
 }
 
 void KisPredefinedBrushChooser::slotSetItemRotation(qreal rotationValue)
 {
-    KisBrush *brush = dynamic_cast<KisBrush *>(m_itemChooser->currentResource());
-    if (brush) {
-        brush->setAngle(rotationValue / 180.0 * M_PI);
-        slotActivatedBrush(brush);
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush);
 
+    if (m_brush) {
+        m_brush->setAngle(rotationValue / 180.0 * M_PI);
         emit sigBrushChanged();
     }
 }
 
 void KisPredefinedBrushChooser::slotSpacingChanged()
 {
-    KisBrush *brush = dynamic_cast<KisBrush *>(m_itemChooser->currentResource());
-    if (brush) {
-        brush->setSpacing(brushSpacingSelectionWidget->spacing());
-        brush->setAutoSpacing(brushSpacingSelectionWidget->autoSpacingActive(), brushSpacingSelectionWidget->autoSpacingCoeff());
-        slotActivatedBrush(brush);
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush);
+
+    if (m_brush) {
+        m_brush->setSpacing(brushSpacingSelectionWidget->spacing());
+        m_brush->setAutoSpacing(brushSpacingSelectionWidget->autoSpacingActive(), brushSpacingSelectionWidget->autoSpacingCoeff());
 
         emit sigBrushChanged();
     }
@@ -242,11 +270,11 @@ void KisPredefinedBrushChooser::slotSpacingChanged()
 
 void KisPredefinedBrushChooser::slotSetItemUseColorAsMask(bool useColorAsMask)
 {
-    KisGbrBrush *brush = dynamic_cast<KisGbrBrush *>(m_itemChooser->currentResource());
+    KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush);
+
+    KisGbrBrush *brush = dynamic_cast<KisGbrBrush *>(m_brush.data());
     if (brush) {
         brush->setUseColorAsMask(useColorAsMask);
-        slotActivatedBrush(brush);
-
         emit sigBrushChanged();
     }
 }
@@ -284,72 +312,55 @@ void KisPredefinedBrushChooser::slotOpenClipboardBrush()
 
 void KisPredefinedBrushChooser::update(KoResource * resource)
 {
-    KisBrush* brush = dynamic_cast<KisBrush*>(resource);
-
-    if (brush) {
-
+    {
+        KisBrush* brush = dynamic_cast<KisBrush*>(resource);
+        m_brush = brush ? brush->clone() : 0;
+    }
 
-        brushTipNameLabel->setText(i18n(brush->name().toUtf8().data()));
+    if (m_brush) {
+        brushTipNameLabel->setText(i18n(m_brush->name().toUtf8().data()));
 
         QString brushTypeString = "";
 
-        if (brush->brushType() == INVALID) {
+        if (m_brush->brushType() == INVALID) {
             brushTypeString = i18n("Invalid");
-        } else if (brush->brushType() == MASK) {
+        } else if (m_brush->brushType() == MASK) {
             brushTypeString = i18n("Mask");
-        } else if (brush->brushType() == IMAGE) {
+        } else if (m_brush->brushType() == IMAGE) {
             brushTypeString = i18n("GBR");
-        } else if (brush->brushType() == PIPE_MASK ) {
+        } else if (m_brush->brushType() == PIPE_MASK ) {
             brushTypeString = i18n("Animated Mask");
-        } else if (brush->brushType() == PIPE_IMAGE ) {
+        } else if (m_brush->brushType() == PIPE_IMAGE ) {
             brushTypeString = i18n("Animated Image");
         }
 
 
         QString brushDetailsText = QString("%1 (%2 x %3)")
                        .arg(brushTypeString)
-                       .arg(brush->width())
-                       .arg(brush->height());
+                       .arg(m_brush->width())
+                       .arg(m_brush->height());
 
         brushDetailsLabel->setText(brushDetailsText);
 
 
-        brushSpacingSelectionWidget->setSpacing(brush->autoSpacingActive(),
-                                brush->autoSpacingActive() ?
-                                brush->autoSpacingCoeff() : brush->spacing());
+        brushSpacingSelectionWidget->setSpacing(m_brush->autoSpacingActive(),
+                                m_brush->autoSpacingActive() ?
+                                m_brush->autoSpacingCoeff() : m_brush->spacing());
 
-        brushRotationSpinBox->setValue(brush->angle() * 180 / M_PI);
-        brushSizeSpinBox->setValue(brush->width() * brush->scale());
+        brushRotationSpinBox->setValue(m_brush->angle() * 180 / M_PI);
+        brushSizeSpinBox->setValue(m_brush->width() * m_brush->scale());
 
         // useColorAsMask support is only in gimp brush so far
-        KisGbrBrush *gimpBrush = dynamic_cast<KisGbrBrush*>(resource);
+        KisGbrBrush *gimpBrush = dynamic_cast<KisGbrBrush*>(m_brush.data());
         if (gimpBrush) {
             useColorAsMaskCheckbox->setChecked(gimpBrush->useColorAsMask());
         }
-        useColorAsMaskCheckbox->setEnabled(brush->hasColor() && gimpBrush);
+        useColorAsMaskCheckbox->setEnabled(m_brush->hasColor() && gimpBrush);
 
-        slotActivatedBrush(brush);
         emit sigBrushChanged();
     }
 }
 
-void KisPredefinedBrushChooser::slotActivatedBrush(KoResource * resource)
-{
-    KisBrush* brush = dynamic_cast<KisBrush*>(resource);
-
-    if (m_brush != brush) {
-        if (m_brush) {
-            m_brush->clearBrushPyramid();
-        }
-
-        m_brush = brush;
-
-        if (m_brush) {
-            m_brush->prepareBrushPyramid();
-        }
-    }
-}
-
 void KisPredefinedBrushChooser::slotNewPredefinedBrush(KoResource *resource)
 {
     m_itemChooser->setCurrentResource(resource);
diff --git a/plugins/paintops/libpaintop/kis_brush_chooser.h b/plugins/paintops/libpaintop/kis_brush_chooser.h
index f87a311e14a..644481695f3 100644
--- a/plugins/paintops/libpaintop/kis_brush_chooser.h
+++ b/plugins/paintops/libpaintop/kis_brush_chooser.h
@@ -38,6 +38,7 @@ class KisClipboardBrushWidget;
 class KoResourceItemChooser;
 class KoResource;
 
+
 class PAINTOP_EXPORT KisPredefinedBrushChooser : public QWidget, Ui::WdgPredefinedBrushChooser
 {
 
@@ -51,7 +52,7 @@ public:
         return m_brush;
     };
 
-    void setBrush(KisBrushSP _brush);
+    void setBrush(KisBrushSP brush);
     void setBrushSize(qreal xPixels, qreal yPixels);
     void setImage(KisImageWSP image);
 
@@ -62,7 +63,6 @@ private Q_SLOTS:
     void slotSetItemRotation(qreal);
     void slotSpacingChanged();
     void slotSetItemUseColorAsMask(bool);
-    void slotActivatedBrush(KoResource *);
     void slotOpenStampBrush();
     void slotOpenClipboardBrush();
     void slotImportNewBrushResource();
@@ -70,8 +70,6 @@ private Q_SLOTS:
     void slotNewPredefinedBrush(KoResource *);
     void update(KoResource *);
 
-
-
 Q_SIGNALS:
 
     void sigBrushChanged();
@@ -82,7 +80,6 @@ private:
     KisImageWSP m_image;
     KisCustomBrushWidget* m_stampBrushWidget;
     KisClipboardBrushWidget* m_clipboardBrushWidget;
-
 };
 
 #endif // KIS_PREDEFINED_BRUSH_CHOOSER_H_
diff --git a/plugins/paintops/libpaintop/kis_brush_option.cpp b/plugins/paintops/libpaintop/kis_brush_option.cpp
index 2d800f823ee..e0432072d69 100644
--- a/plugins/paintops/libpaintop/kis_brush_option.cpp
+++ b/plugins/paintops/libpaintop/kis_brush_option.cpp
@@ -56,30 +56,15 @@ QDomElement getBrushXMLElement(const KisPropertiesConfiguration *setting)
     return element;
 }
 
-void KisBrushOption::readOptionSettingInternal(const KisPropertiesConfiguration *setting, bool forceCopy)
+void KisBrushOption::readOptionSettingImpl(const KisPropertiesConfiguration *setting)
 {
     QDomElement element = getBrushXMLElement(setting);
 
     if (!element.isNull()) {
-        m_brush = KisBrush::fromXML(element, forceCopy);
+        m_brush = KisBrush::fromXML(element);
     }
 }
 
-void KisBrushOption::readOptionSettingForceCopy(KisPropertiesConfigurationSP setting)
-{
-    readOptionSettingInternal(setting.data(), true);
-}
-
-void KisBrushOption::readOptionSettingForceCopy(const KisPropertiesConfiguration *setting)
-{
-    readOptionSettingInternal(setting, true);
-}
-
-void KisBrushOption::readOptionSettingImpl(const KisPropertiesConfiguration *setting)
-{
-    readOptionSettingInternal(setting, false);
-}
-
 #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND
 
 #include "kis_text_brush_factory.h"
diff --git a/plugins/paintops/libpaintop/kis_brush_option.h b/plugins/paintops/libpaintop/kis_brush_option.h
index b36b58ab782..26df674e765 100644
--- a/plugins/paintops/libpaintop/kis_brush_option.h
+++ b/plugins/paintops/libpaintop/kis_brush_option.h
@@ -35,8 +35,6 @@ public:
 
     void writeOptionSettingImpl(KisPropertiesConfiguration *setting) const override;
     void readOptionSettingImpl(const KisPropertiesConfiguration *setting) override;
-    void readOptionSettingForceCopy(KisPropertiesConfigurationSP setting);
-    void readOptionSettingForceCopy(const KisPropertiesConfiguration *setting);
 
     KisBrushSP brush() const;
     void setBrush(KisBrushSP brush);
@@ -45,9 +43,6 @@ public:
     static bool isTextBrush(const KisPropertiesConfiguration *setting);
 #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */
 
-private:
-    void readOptionSettingInternal(const KisPropertiesConfiguration *setting, bool forceCopy);
-
 private:
     KisBrushSP m_brush;
 };
diff --git a/plugins/paintops/sketch/kis_sketch_paintop.cpp b/plugins/paintops/sketch/kis_sketch_paintop.cpp
index 26461d555bf..46be473fe34 100644
--- a/plugins/paintops/sketch/kis_sketch_paintop.cpp
+++ b/plugins/paintops/sketch/kis_sketch_paintop.cpp
@@ -75,7 +75,7 @@ KisSketchPaintOp::KisSketchPaintOp(const KisPaintOpSettingsSP settings, KisPaint
     m_rotationOption.readOptionSetting(settings);
     m_rateOption.readOptionSetting(settings);
     m_sketchProperties.readOptionSetting(settings);
-    m_brushOption.readOptionSettingForceCopy(settings);
+    m_brushOption.readOptionSetting(settings);
     m_densityOption.readOptionSetting(settings);
     m_lineWidthOption.readOptionSetting(settings);
     m_offsetScaleOption.readOptionSetting(settings);
diff --git a/plugins/paintops/spray/kis_spray_paintop.cpp b/plugins/paintops/spray/kis_spray_paintop.cpp
index 6e3d353610f..ff833550075 100644
--- a/plugins/paintops/spray/kis_spray_paintop.cpp
+++ b/plugins/paintops/spray/kis_spray_paintop.cpp
@@ -62,7 +62,7 @@ KisSprayPaintOp::KisSprayPaintOp(const KisPaintOpSettingsSP settings, KisPainter
     m_sizeOption.resetAllSensors();
     m_rateOption.resetAllSensors();
 
-    m_brushOption.readOptionSettingForceCopy(settings);
+    m_brushOption.readOptionSetting(settings);
 
     m_colorProperties.fillProperties(settings);
     m_properties.readOptionSetting(settings);


More information about the kimageshop mailing list