[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    [krita/kazakov/masking-brush] /: Implement dependent size changes for the Masking Brush
From:       Dmitry Kazakov <null () kde ! org>
Date:       2017-12-27 9:13:49
Message-ID: E1eU7mX-0007TS-9Z () code ! kde ! org
[Download RAW message or body]

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@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@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);


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic