[gimp] app: add GimpBrushCache which stores brush stuff based on transform parameters



commit 21b8007b297030f5f44bbba3390891193e807d02
Author: Michael Natterer <mitch gimp org>
Date:   Tue Apr 5 22:11:27 2011 +0200

    app: add GimpBrushCache which stores brush stuff based on transform parameters
    
    such as masks and outlines. The cache is currently very stupid and
    only cacheds the last transformed object. Add caches to GimpBrush for
    its mask, its pixmap and its boundary, and remove the same caches and
    a ton of members from GimpBrushCore. This involves adding lots of
    const qualifiers because GimpBrush returns const pointers now for
    trasnformed stuff.

 app/core/Makefile.am          |    2 +
 app/core/core-types.h         |    1 +
 app/core/gimpbrush-boundary.c |    6 +-
 app/core/gimpbrush.c          |  269 ++++++++++++++++++++++++--------
 app/core/gimpbrush.h          |  109 +++++++------
 app/core/gimpbrushcache.c     |  232 +++++++++++++++++++++++++++
 app/core/gimpbrushcache.h     |   87 ++++++++++
 app/paint/gimpbrushcore.c     |  351 ++++++++++++++++-------------------------
 app/paint/gimpbrushcore.h     |  108 ++++++-------
 app/paint/gimpheal.c          |   10 +-
 app/tools/gimpbrushtool.c     |   17 +--
 11 files changed, 781 insertions(+), 411 deletions(-)
---
diff --git a/app/core/Makefile.am b/app/core/Makefile.am
index 3e5632b..3a8ee12 100644
--- a/app/core/Makefile.am
+++ b/app/core/Makefile.am
@@ -62,6 +62,8 @@ libappcore_a_sources = \
 	gimpbrush-load.h			\
 	gimpbrush-transform.c			\
 	gimpbrush-transform.h			\
+	gimpbrushcache.c			\
+	gimpbrushcache.h			\
 	gimpbrushclipboard.c			\
 	gimpbrushclipboard.h			\
 	gimpbrushgenerated.c			\
diff --git a/app/core/core-types.h b/app/core/core-types.h
index d73c687..b0874be 100644
--- a/app/core/core-types.h
+++ b/app/core/core-types.h
@@ -101,6 +101,7 @@ typedef struct _GimpToolInfo        GimpToolInfo;
 typedef struct _GimpDataFactory      GimpDataFactory;
 typedef struct _GimpData             GimpData;
 typedef struct _GimpBrush            GimpBrush;
+typedef struct _GimpBrushCache       GimpBrushCache;
 typedef struct _GimpBrushClipboard   GimpBrushClipboard;
 typedef struct _GimpBrushGenerated   GimpBrushGenerated;
 typedef struct _GimpBrushPipe        GimpBrushPipe;
diff --git a/app/core/gimpbrush-boundary.c b/app/core/gimpbrush-boundary.c
index 2abdec9..6810805 100644
--- a/app/core/gimpbrush-boundary.c
+++ b/app/core/gimpbrush-boundary.c
@@ -38,7 +38,7 @@ gimp_brush_transform_boundary_exact (GimpBrush *brush,
                                      gdouble    angle,
                                      gdouble    hardness)
 {
-  TempBuf *mask;
+  const TempBuf *mask;
 
   mask = gimp_brush_transform_mask (brush,
                                     scale, aspect_ratio, angle, hardness);
@@ -49,7 +49,7 @@ gimp_brush_transform_boundary_exact (GimpBrush *brush,
       BoundSeg    *bound_segs;
       gint         n_bound_segs;
 
-      pixel_region_init_temp_buf (&maskPR, mask,
+      pixel_region_init_temp_buf (&maskPR, (TempBuf *) mask,
                                   0, 0, mask->width, mask->height);
 
       bound_segs = boundary_find (&maskPR, BOUNDARY_WITHIN_BOUNDS,
@@ -57,8 +57,6 @@ gimp_brush_transform_boundary_exact (GimpBrush *brush,
                                   0,
                                   &n_bound_segs);
 
-      temp_buf_free (mask);
-
       if (bound_segs)
         {
           BoundSeg *stroke_segs;
diff --git a/app/core/gimpbrush.c b/app/core/gimpbrush.c
index ceeafea..68f605c 100644
--- a/app/core/gimpbrush.c
+++ b/app/core/gimpbrush.c
@@ -18,6 +18,7 @@
 #include "config.h"
 
 #include <glib-object.h>
+#include <cairo.h>
 
 #include "libgimpbase/gimpbase.h"
 #include "libgimpmath/gimpmath.h"
@@ -26,10 +27,12 @@
 
 #include "base/temp-buf.h"
 
+#include "gimpbezierdesc.h"
 #include "gimpbrush.h"
 #include "gimpbrush-boundary.h"
 #include "gimpbrush-load.h"
 #include "gimpbrush-transform.h"
+#include "gimpbrushcache.h"
 #include "gimpbrushgenerated.h"
 #include "gimpmarshal.h"
 #include "gimptagged.h"
@@ -52,6 +55,7 @@ enum
 
 static void          gimp_brush_tagged_iface_init     (GimpTaggedInterface  *iface);
 
+static void          gimp_brush_finalize              (GObject              *object);
 static void          gimp_brush_set_property          (GObject              *object,
                                                        guint                 property_id,
                                                        const GValue         *value,
@@ -60,7 +64,6 @@ static void          gimp_brush_get_property          (GObject              *obj
                                                        guint                 property_id,
                                                        GValue               *value,
                                                        GParamSpec           *pspec);
-static void          gimp_brush_finalize              (GObject              *object);
 
 static gint64        gimp_brush_get_memsize           (GimpObject           *object,
                                                        gint64               *gui_size);
@@ -74,6 +77,8 @@ static TempBuf     * gimp_brush_get_new_preview       (GimpViewable         *vie
                                                        gint                  height);
 static gchar       * gimp_brush_get_description       (GimpViewable         *viewable,
                                                        gchar               **tooltip);
+
+static void          gimp_brush_dirty                 (GimpData             *data);
 static const gchar * gimp_brush_get_extension         (GimpData             *data);
 
 static GimpBrush   * gimp_brush_real_select_brush     (GimpBrush            *brush,
@@ -112,9 +117,9 @@ gimp_brush_class_init (GimpBrushClass *klass)
                   gimp_marshal_VOID__VOID,
                   G_TYPE_NONE, 0);
 
+  object_class->finalize           = gimp_brush_finalize;
   object_class->get_property       = gimp_brush_get_property;
   object_class->set_property       = gimp_brush_set_property;
-  object_class->finalize           = gimp_brush_finalize;
 
   gimp_object_class->get_memsize   = gimp_brush_get_memsize;
 
@@ -123,6 +128,7 @@ gimp_brush_class_init (GimpBrushClass *klass)
   viewable_class->get_new_preview  = gimp_brush_get_new_preview;
   viewable_class->get_description  = gimp_brush_get_description;
 
+  data_class->dirty                = gimp_brush_dirty;
   data_class->get_extension        = gimp_brush_get_extension;
 
   klass->select_brush              = gimp_brush_real_select_brush;
@@ -161,6 +167,44 @@ gimp_brush_init (GimpBrush *brush)
 }
 
 static void
+gimp_brush_finalize (GObject *object)
+{
+  GimpBrush *brush = GIMP_BRUSH (object);
+
+  if (brush->mask)
+    {
+      temp_buf_free (brush->mask);
+      brush->mask = NULL;
+    }
+
+  if (brush->pixmap)
+    {
+      temp_buf_free (brush->pixmap);
+      brush->pixmap = NULL;
+    }
+
+  if (brush->mask_cache)
+    {
+      g_object_unref (brush->mask_cache);
+      brush->mask_cache = NULL;
+    }
+
+  if (brush->pixmap_cache)
+    {
+      g_object_unref (brush->pixmap_cache);
+      brush->pixmap_cache = NULL;
+    }
+
+  if (brush->boundary_cache)
+    {
+      g_object_unref (brush->boundary_cache);
+      brush->boundary_cache = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
 gimp_brush_set_property (GObject      *object,
                          guint         property_id,
                          const GValue *value,
@@ -200,26 +244,6 @@ gimp_brush_get_property (GObject    *object,
     }
 }
 
-static void
-gimp_brush_finalize (GObject *object)
-{
-  GimpBrush *brush = GIMP_BRUSH (object);
-
-  if (brush->mask)
-    {
-      temp_buf_free (brush->mask);
-      brush->mask = NULL;
-    }
-
-  if (brush->pixmap)
-    {
-      temp_buf_free (brush->pixmap);
-      brush->pixmap = NULL;
-    }
-
-  G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
 static gint64
 gimp_brush_get_memsize (GimpObject *object,
                         gint64     *gui_size)
@@ -253,17 +277,18 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
                             gint          width,
                             gint          height)
 {
-  GimpBrush *brush      = GIMP_BRUSH (viewable);
-  TempBuf   *mask_buf   = NULL;
-  TempBuf   *pixmap_buf = NULL;
-  TempBuf   *return_buf = NULL;
-  gint       mask_width;
-  gint       mask_height;
-  guchar     transp[4]  = { 0, 0, 0, 0 };
-  guchar    *mask;
-  guchar    *buf;
-  gint       x, y;
-  gboolean   scaled = FALSE;
+  GimpBrush     *brush       = GIMP_BRUSH (viewable);
+  const TempBuf *mask_buf    = NULL;
+  gboolean       free_mask   = FALSE;
+  const TempBuf *pixmap_buf  = NULL;
+  TempBuf       *return_buf  = NULL;
+  gint           mask_width;
+  gint           mask_height;
+  guchar         transp[4]   = { 0, 0, 0, 0 };
+  guchar        *mask;
+  guchar        *buf;
+  gint           x, y;
+  gboolean       scaled = FALSE;
 
   mask_buf   = brush->mask;
   pixmap_buf = brush->pixmap;
@@ -279,13 +304,20 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
 
       if (scale != 1.0)
         {
-          mask_buf = gimp_brush_transform_mask (brush, scale, 0.0, 0.0, 1.0);
+          gimp_brush_start_use (brush);
+
+          mask_buf = gimp_brush_transform_mask (brush, scale,
+                                                0.0, 0.0, 1.0);
 
           if (! mask_buf)
-            mask_buf = temp_buf_new (1, 1, 1, 0, 0, transp);
+            {
+              mask_buf = temp_buf_new (1, 1, 1, 0, 0, transp);
+              free_mask = TRUE;
+            }
 
           if (pixmap_buf)
-            pixmap_buf = gimp_brush_transform_pixmap (brush, scale, 0.0, 0.0, 1.0);
+            pixmap_buf = gimp_brush_transform_pixmap (brush, scale,
+                                                      0.0, 0.0, 1.0);
 
           mask_width  = mask_buf->width;
           mask_height = mask_buf->height;
@@ -330,10 +362,10 @@ gimp_brush_get_new_preview (GimpViewable *viewable,
 
   if (scaled)
     {
-      temp_buf_free (mask_buf);
+      if (free_mask)
+        temp_buf_free ((TempBuf *) mask_buf);
 
-      if (pixmap_buf)
-        temp_buf_free (pixmap_buf);
+      gimp_brush_end_use (brush);
     }
 
   return return_buf;
@@ -351,6 +383,23 @@ gimp_brush_get_description (GimpViewable  *viewable,
                           brush->mask->height);
 }
 
+static void
+gimp_brush_dirty (GimpData *data)
+{
+  GimpBrush *brush = GIMP_BRUSH (data);
+
+  if (brush->mask_cache)
+    gimp_brush_cache_clear (brush->mask_cache);
+
+  if (brush->pixmap_cache)
+    gimp_brush_cache_clear (brush->pixmap_cache);
+
+  if (brush->boundary_cache)
+    gimp_brush_cache_clear (brush->boundary_cache);
+
+  GIMP_DATA_CLASS (parent_class)->dirty (data);
+}
+
 static const gchar *
 gimp_brush_get_extension (GimpData *data)
 {
@@ -486,54 +535,106 @@ gimp_brush_transform_size (GimpBrush     *brush,
                                                 width, height);
 }
 
-TempBuf *
+const TempBuf *
 gimp_brush_transform_mask (GimpBrush *brush,
                            gdouble    scale,
                            gdouble    aspect_ratio,
                            gdouble    angle,
                            gdouble    hardness)
 {
+  const TempBuf *mask;
+  gint           width;
+  gint           height;
+
   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
   g_return_val_if_fail (scale > 0.0, NULL);
 
-  if (scale        == 1.0 &&
-      aspect_ratio == 0.0 &&
-      angle        == 0.0 &&
-      hardness     == 1.0)
+  gimp_brush_transform_size (brush,
+                             scale, aspect_ratio, angle,
+                             &width, &height);
+
+  mask = gimp_brush_cache_get (brush->mask_cache,
+                               width, height,
+                               scale, aspect_ratio, angle, hardness);
+
+  if (! mask)
     {
-      return temp_buf_copy (brush->mask, NULL);
+      if (scale        == 1.0 &&
+          aspect_ratio == 0.0 &&
+          angle        == 0.0 &&
+          hardness     == 1.0)
+        {
+          mask = temp_buf_copy (brush->mask, NULL);
+        }
+      else
+        {
+          mask = GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush,
+                                                               scale,
+                                                               aspect_ratio,
+                                                               angle,
+                                                               hardness);
+        }
+
+      gimp_brush_cache_add (brush->mask_cache,
+                            (gpointer) mask,
+                            width, height,
+                            scale, aspect_ratio, angle, hardness);
     }
 
-  return GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush,
-                                                       scale, aspect_ratio,
-                                                       angle, hardness);
+  return mask;
 }
 
-TempBuf *
+const TempBuf *
 gimp_brush_transform_pixmap (GimpBrush *brush,
                              gdouble    scale,
                              gdouble    aspect_ratio,
                              gdouble    angle,
                              gdouble    hardness)
 {
+  const TempBuf *pixmap;
+  gint           width;
+  gint           height;
+
   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
   g_return_val_if_fail (brush->pixmap != NULL, NULL);
   g_return_val_if_fail (scale > 0.0, NULL);
 
-  if (scale        == 1.0 &&
-      aspect_ratio == 0.0 &&
-      angle        == 0.0 &&
-      hardness     == 1.0)
+  gimp_brush_transform_size (brush,
+                             scale, aspect_ratio, angle,
+                             &width, &height);
+
+  pixmap = gimp_brush_cache_get (brush->pixmap_cache,
+                                 width, height,
+                                 scale, aspect_ratio, angle, hardness);
+
+  if (! pixmap)
     {
-      return temp_buf_copy (brush->pixmap, NULL);
+      if (scale        == 1.0 &&
+          aspect_ratio == 0.0 &&
+          angle        == 0.0 &&
+          hardness     == 1.0)
+        {
+          pixmap = temp_buf_copy (brush->pixmap, NULL);
+        }
+      else
+        {
+          pixmap = GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush,
+                                                                   scale,
+                                                                   aspect_ratio,
+                                                                   angle,
+                                                                   hardness);
+        }
+
+      gimp_brush_cache_add (brush->pixmap_cache,
+                            (gpointer) pixmap,
+                            width, height,
+                            scale, aspect_ratio, angle, hardness);
     }
 
-  return GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush,
-                                                         scale, aspect_ratio,
-                                                         angle, hardness);
+  return pixmap;
 }
 
-GimpBezierDesc *
+const GimpBezierDesc *
 gimp_brush_transform_boundary (GimpBrush *brush,
                                gdouble    scale,
                                gdouble    aspect_ratio,
@@ -542,15 +643,38 @@ gimp_brush_transform_boundary (GimpBrush *brush,
                                gint      *width,
                                gint      *height)
 {
+  const GimpBezierDesc *boundary;
+
   g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
   g_return_val_if_fail (scale > 0.0, NULL);
   g_return_val_if_fail (width != NULL, NULL);
   g_return_val_if_fail (height != NULL, NULL);
 
-  return GIMP_BRUSH_GET_CLASS (brush)->transform_boundary (brush,
-                                                           scale, aspect_ratio,
-                                                           angle, hardness,
-                                                           width, height);
+  gimp_brush_transform_size (brush,
+                             scale, aspect_ratio, angle,
+                             width, height);
+
+  boundary = gimp_brush_cache_get (brush->boundary_cache,
+                                   *width, *height,
+                                   scale, aspect_ratio, angle, hardness);
+
+  if (! boundary)
+    {
+      boundary = GIMP_BRUSH_GET_CLASS (brush)->transform_boundary (brush,
+                                                                   scale,
+                                                                   aspect_ratio,
+                                                                   angle,
+                                                                   hardness,
+                                                                   width,
+                                                                   height);
+
+      gimp_brush_cache_add (brush->boundary_cache,
+                            (gpointer) boundary,
+                            *width, *height,
+                            scale, aspect_ratio, angle, hardness);
+    }
+
+  return boundary;
 }
 
 gdouble
@@ -612,6 +736,18 @@ gimp_brush_start_use (GimpBrush *brush)
   g_return_if_fail (GIMP_IS_BRUSH (brush));
 
   brush->use_count++;
+
+  if (brush->use_count == 1)
+    {
+      brush->mask_cache =
+        gimp_brush_cache_new ((GDestroyNotify) temp_buf_free, 'M', 'm');
+
+      brush->pixmap_cache =
+        gimp_brush_cache_new ((GDestroyNotify) temp_buf_free, 'P', 'p');
+
+      brush->boundary_cache =
+        gimp_brush_cache_new ((GDestroyNotify) gimp_bezier_desc_free, 'B', 'b');
+    }
 }
 
 void
@@ -624,6 +760,13 @@ gimp_brush_end_use (GimpBrush *brush)
 
   if (brush->use_count == 0)
     {
-      /* flush caches */
+      g_object_unref (brush->mask_cache);
+      brush->mask_cache = NULL;
+
+      g_object_unref (brush->pixmap_cache);
+      brush->pixmap_cache = NULL;
+
+      g_object_unref (brush->boundary_cache);
+      brush->boundary_cache = NULL;
     }
 }
diff --git a/app/core/gimpbrush.h b/app/core/gimpbrush.h
index 45632fd..f49aa6c 100644
--- a/app/core/gimpbrush.h
+++ b/app/core/gimpbrush.h
@@ -35,16 +35,19 @@ typedef struct _GimpBrushClass GimpBrushClass;
 
 struct _GimpBrush
 {
-  GimpData      parent_instance;
+  GimpData        parent_instance;
 
-  TempBuf      *mask;       /*  the actual mask                */
-  TempBuf      *pixmap;     /*  optional pixmap data           */
+  TempBuf        *mask;       /*  the actual mask                */
+  TempBuf        *pixmap;     /*  optional pixmap data           */
 
-  gint          spacing;    /*  brush's spacing                */
-  GimpVector2   x_axis;     /*  for calculating brush spacing  */
-  GimpVector2   y_axis;     /*  for calculating brush spacing  */
+  gint            spacing;    /*  brush's spacing                */
+  GimpVector2     x_axis;     /*  for calculating brush spacing  */
+  GimpVector2     y_axis;     /*  for calculating brush spacing  */
 
-  gint          use_count;  /*  for keeping the caches alive   */
+  gint            use_count;  /*  for keeping the caches alive   */
+  GimpBrushCache *mask_cache;
+  GimpBrushCache *pixmap_cache;
+  GimpBrushCache *boundary_cache;
 };
 
 struct _GimpBrushClass
@@ -87,58 +90,58 @@ struct _GimpBrushClass
 };
 
 
-GType            gimp_brush_get_type           (void) G_GNUC_CONST;
+GType                  gimp_brush_get_type           (void) G_GNUC_CONST;
 
-GimpData       * gimp_brush_new                (GimpContext      *context,
-                                                const gchar      *name);
-GimpData       * gimp_brush_get_standard       (GimpContext      *context);
+GimpData             * gimp_brush_new                (GimpContext      *context,
+                                                      const gchar      *name);
+GimpData             * gimp_brush_get_standard       (GimpContext      *context);
 
-GimpBrush      * gimp_brush_select_brush       (GimpBrush        *brush,
-                                                const GimpCoords *last_coords,
-                                                const GimpCoords *current_coords);
-gboolean         gimp_brush_want_null_motion   (GimpBrush        *brush,
-                                                const GimpCoords *last_coords,
-                                                const GimpCoords *current_coords);
+GimpBrush            * gimp_brush_select_brush       (GimpBrush        *brush,
+                                                      const GimpCoords *last_coords,
+                                                      const GimpCoords *current_coords);
+gboolean               gimp_brush_want_null_motion   (GimpBrush        *brush,
+                                                      const GimpCoords *last_coords,
+                                                      const GimpCoords *current_coords);
 
 /* Gets width and height of a transformed mask of the brush, for
  * provided parameters.
  */
-void             gimp_brush_transform_size     (GimpBrush        *brush,
-                                                gdouble           scale,
-                                                gdouble           aspect_ratio,
-                                                gdouble           angle,
-                                                gint             *width,
-                                                gint             *height);
-TempBuf        * gimp_brush_transform_mask     (GimpBrush        *brush,
-                                                gdouble           scale,
-                                                gdouble           aspect_ratio,
-                                                gdouble           angle,
-                                                gdouble           hardness);
-TempBuf        * gimp_brush_transform_pixmap   (GimpBrush        *brush,
-                                                gdouble           scale,
-                                                gdouble           aspect_ratio,
-                                                gdouble           angle,
-                                                gdouble           hardness);
-GimpBezierDesc * gimp_brush_transform_boundary (GimpBrush        *brush,
-                                                gdouble           scale,
-                                                gdouble           aspect_ratio,
-                                                gdouble           angle,
-                                                gdouble           hardness,
-                                                gint             *width,
-                                                gint             *height);
-
-gdouble          gimp_brush_clamp_scale        (GimpBrush        *brush,
-                                                gdouble           scale);
-
-TempBuf        * gimp_brush_get_mask           (const GimpBrush  *brush);
-TempBuf        * gimp_brush_get_pixmap         (const GimpBrush  *brush);
-
-gint             gimp_brush_get_spacing        (const GimpBrush  *brush);
-void             gimp_brush_set_spacing        (GimpBrush        *brush,
-                                                gint              spacing);
-
-void             gimp_brush_start_use          (GimpBrush        *brush);
-void             gimp_brush_end_use            (GimpBrush        *brush);
+void                   gimp_brush_transform_size     (GimpBrush        *brush,
+                                                      gdouble           scale,
+                                                      gdouble           aspect_ratio,
+                                                      gdouble           angle,
+                                                      gint             *width,
+                                                      gint             *height);
+const TempBuf        * gimp_brush_transform_mask     (GimpBrush        *brush,
+                                                      gdouble           scale,
+                                                      gdouble           aspect_ratio,
+                                                      gdouble           angle,
+                                                      gdouble           hardness);
+const TempBuf        * gimp_brush_transform_pixmap   (GimpBrush        *brush,
+                                                      gdouble           scale,
+                                                      gdouble           aspect_ratio,
+                                                      gdouble           angle,
+                                                      gdouble           hardness);
+const GimpBezierDesc * gimp_brush_transform_boundary (GimpBrush        *brush,
+                                                      gdouble           scale,
+                                                      gdouble           aspect_ratio,
+                                                      gdouble           angle,
+                                                      gdouble           hardness,
+                                                      gint             *width,
+                                                      gint             *height);
+
+gdouble                gimp_brush_clamp_scale        (GimpBrush        *brush,
+                                                      gdouble           scale);
+
+TempBuf              * gimp_brush_get_mask           (const GimpBrush  *brush);
+TempBuf              * gimp_brush_get_pixmap         (const GimpBrush  *brush);
+
+gint                   gimp_brush_get_spacing        (const GimpBrush  *brush);
+void                   gimp_brush_set_spacing        (GimpBrush        *brush,
+                                                      gint              spacing);
+
+void                   gimp_brush_start_use          (GimpBrush        *brush);
+void                   gimp_brush_end_use            (GimpBrush        *brush);
 
 
 #endif /* __GIMP_BRUSH_H__ */
diff --git a/app/core/gimpbrushcache.c b/app/core/gimpbrushcache.c
new file mode 100644
index 0000000..2afcdc1
--- /dev/null
+++ b/app/core/gimpbrushcache.c
@@ -0,0 +1,232 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpbrushcache.c
+ * Copyright (C) 2011 Michael Natterer <mitch gimp org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+
+#include "core-types.h"
+
+#include "gimpbrushcache.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_DATA_DESTROY
+};
+
+
+static void   gimp_brush_cache_constructed  (GObject      *object);
+static void   gimp_brush_cache_finalize     (GObject      *object);
+static void   gimp_brush_cache_set_property (GObject      *object,
+                                             guint         property_id,
+                                             const GValue *value,
+                                             GParamSpec   *pspec);
+static void   gimp_brush_cache_get_property (GObject      *object,
+                                             guint         property_id,
+                                             GValue       *value,
+                                             GParamSpec   *pspec);
+
+
+G_DEFINE_TYPE (GimpBrushCache, gimp_brush_cache, GIMP_TYPE_OBJECT)
+
+#define parent_class gimp_brush_cache_parent_class
+
+
+static void
+gimp_brush_cache_class_init (GimpBrushCacheClass *klass)
+{
+  GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed  = gimp_brush_cache_constructed;
+  object_class->finalize     = gimp_brush_cache_finalize;
+  object_class->set_property = gimp_brush_cache_set_property;
+  object_class->get_property = gimp_brush_cache_get_property;
+
+  g_object_class_install_property (object_class, PROP_DATA_DESTROY,
+                                   g_param_spec_pointer ("data-destroy",
+                                                         NULL, NULL,
+                                                         GIMP_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gimp_brush_cache_init (GimpBrushCache *brush)
+{
+}
+
+static void
+gimp_brush_cache_constructed (GObject *object)
+{
+  GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
+
+  if (G_OBJECT_CLASS (parent_class)->constructed)
+    G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  g_assert (cache->data_destroy != NULL);
+}
+
+static void
+gimp_brush_cache_finalize (GObject *object)
+{
+  GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
+
+  if (cache->last_data)
+    {
+      cache->data_destroy (cache->last_data);
+      cache->last_data = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_brush_cache_set_property (GObject      *object,
+                               guint         property_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+  GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
+
+  switch (property_id)
+    {
+    case PROP_DATA_DESTROY:
+      cache->data_destroy = g_value_get_pointer (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_brush_cache_get_property (GObject    *object,
+                               guint       property_id,
+                               GValue     *value,
+                               GParamSpec *pspec)
+{
+  GimpBrushCache *cache = GIMP_BRUSH_CACHE (object);
+
+  switch (property_id)
+    {
+    case PROP_DATA_DESTROY:
+      g_value_set_pointer (value, cache->data_destroy);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+
+/*  public functions  */
+
+GimpBrushCache *
+gimp_brush_cache_new (GDestroyNotify  data_destroy,
+                      gchar           debug_hit,
+                      gchar           debug_miss)
+{
+  GimpBrushCache *cache;
+
+  g_return_val_if_fail (data_destroy != NULL, NULL);
+
+  cache =  g_object_new (GIMP_TYPE_BRUSH_CACHE,
+                         "data-destroy", data_destroy,
+                         NULL);
+
+  cache->debug_hit  = debug_hit;
+  cache->debug_miss = debug_miss;
+
+  return cache;
+}
+
+void
+gimp_brush_cache_clear (GimpBrushCache *cache)
+{
+  g_return_if_fail (GIMP_IS_BRUSH_CACHE (cache));
+
+  if (cache->last_data)
+    {
+      cache->data_destroy (cache->last_data);
+      cache->last_data = NULL;
+    }
+}
+
+gconstpointer
+gimp_brush_cache_get (GimpBrushCache *cache,
+                      gint            width,
+                      gint            height,
+                      gdouble         scale,
+                      gdouble         aspect_ratio,
+                      gdouble         angle,
+                      gdouble         hardness)
+{
+  g_return_val_if_fail (GIMP_IS_BRUSH_CACHE (cache), NULL);
+
+  if (cache->last_data                         &&
+      cache->last_width        == width        &&
+      cache->last_height       == height       &&
+      cache->last_scale        == scale        &&
+      cache->last_aspect_ratio == aspect_ratio &&
+      cache->last_angle        == angle        &&
+      cache->last_hardness     == hardness)
+    {
+      g_printerr ("%c", cache->debug_hit);
+
+      return (gconstpointer) cache->last_data;
+    }
+
+  g_printerr ("%c", cache->debug_miss);
+
+  return NULL;
+}
+
+void
+gimp_brush_cache_add (GimpBrushCache *cache,
+                      gpointer        data,
+                      gint            width,
+                      gint            height,
+                      gdouble         scale,
+                      gdouble         aspect_ratio,
+                      gdouble         angle,
+                      gdouble         hardness)
+{
+  g_return_if_fail (GIMP_IS_BRUSH_CACHE (cache));
+  g_return_if_fail (data != NULL);
+
+  if (data == cache->last_data)
+    return;
+
+  if (cache->last_data)
+    cache->data_destroy (cache->last_data);
+
+  cache->last_data         = data;
+  cache->last_width        = width;
+  cache->last_height       = height;
+  cache->last_scale        = scale;
+  cache->last_aspect_ratio = aspect_ratio;
+  cache->last_angle        = angle;
+  cache->last_hardness     = hardness;
+}
diff --git a/app/core/gimpbrushcache.h b/app/core/gimpbrushcache.h
new file mode 100644
index 0000000..5c879cc
--- /dev/null
+++ b/app/core/gimpbrushcache.h
@@ -0,0 +1,87 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpbrushcache.h
+ * Copyright (C) 2011 Michael Natterer <mitch gimp org>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_BRUSH_CACHE_H__
+#define __GIMP_BRUSH_CACHE_H__
+
+
+#include "gimpobject.h"
+
+
+#define GIMP_TYPE_BRUSH_CACHE            (gimp_brush_cache_get_type ())
+#define GIMP_BRUSH_CACHE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_BRUSH_CACHE, GimpBrushCache))
+#define GIMP_BRUSH_CACHE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_BRUSH_CACHE, GimpBrushCacheClass))
+#define GIMP_IS_BRUSH_CACHE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_BRUSH_CACHE))
+#define GIMP_IS_BRUSH_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_BRUSH_CACHE))
+#define GIMP_BRUSH_CACHE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_BRUSH_CACHE, GimpBrushCacheClass))
+
+
+typedef struct _GimpBrushCacheClass GimpBrushCacheClass;
+
+struct _GimpBrushCache
+{
+  GimpObject      parent_instance;
+
+  GDestroyNotify  data_destroy;
+
+  gpointer        last_data;
+  gint            last_width;
+  gint            last_height;
+  gdouble         last_scale;
+  gdouble         last_aspect_ratio;
+  gdouble         last_angle;
+  gdouble         last_hardness;
+
+  gchar           debug_hit;
+  gchar           debug_miss;
+};
+
+struct _GimpBrushCacheClass
+{
+  GimpObjectClass  parent_class;
+};
+
+
+GType            gimp_brush_cache_get_type (void) G_GNUC_CONST;
+
+GimpBrushCache * gimp_brush_cache_new      (GDestroyNotify  data_destory,
+                                            gchar           debug_hit,
+                                            gchar           debug_miss);
+
+void             gimp_brush_cache_clear    (GimpBrushCache *cache);
+
+gconstpointer    gimp_brush_cache_get      (GimpBrushCache *cache,
+                                            gint            width,
+                                            gint            height,
+                                            gdouble         scale,
+                                            gdouble         aspect_ratio,
+                                            gdouble         angle,
+                                            gdouble         hardness);
+void             gimp_brush_cache_add      (GimpBrushCache *cache,
+                                            gpointer        data,
+                                            gint            width,
+                                            gint            height,
+                                            gdouble         scale,
+                                            gdouble         aspect_ratio,
+                                            gdouble         angle,
+                                            gdouble         hardness);
+
+
+#endif  /*  __GIMP_BRUSH_CACHE_H__  */
diff --git a/app/paint/gimpbrushcore.c b/app/paint/gimpbrushcore.c
index 0dcdd22..4c058e7 100644
--- a/app/paint/gimpbrushcore.c
+++ b/app/paint/gimpbrushcore.c
@@ -58,73 +58,70 @@ enum
 
 /*  local function prototypes  */
 
-static void     gimp_brush_core_finalize           (GObject          *object);
+static void      gimp_brush_core_finalize           (GObject          *object);
 
-static gboolean gimp_brush_core_start              (GimpPaintCore    *core,
+static gboolean  gimp_brush_core_start              (GimpPaintCore    *core,
                                                     GimpDrawable     *drawable,
-                                                    GimpPaintOptions *paint_options,
-                                                    const GimpCoords *coords,
-                                                    GError          **error);
-static gboolean gimp_brush_core_pre_paint          (GimpPaintCore    *core,
-                                                    GimpDrawable     *drawable,
-                                                    GimpPaintOptions *paint_options,
-                                                    GimpPaintState    paint_state,
-                                                    guint32           time);
-static void     gimp_brush_core_post_paint         (GimpPaintCore    *core,
-                                                    GimpDrawable     *drawable,
-                                                    GimpPaintOptions *paint_options,
-                                                    GimpPaintState    paint_state,
-                                                    guint32           time);
-static void     gimp_brush_core_interpolate        (GimpPaintCore    *core,
-                                                    GimpDrawable     *drawable,
-                                                    GimpPaintOptions *paint_options,
-                                                    guint32           time);
-
-static TempBuf *gimp_brush_core_get_paint_area     (GimpPaintCore    *paint_core,
-                                                    GimpDrawable     *drawable,
-                                                    GimpPaintOptions *paint_options,
-                                                    const GimpCoords *coords);
-
-static void     gimp_brush_core_real_set_brush     (GimpBrushCore    *core,
-                                                    GimpBrush        *brush);
-static void     gimp_brush_core_real_set_dynamics  (GimpBrushCore    *core,
-                                                    GimpDynamics     *dynamics);
-
-static inline void rotate_pointers                 (gulong          **p,
-                                                    guint32           n);
-static TempBuf * gimp_brush_core_subsample_mask    (GimpBrushCore    *core,
-                                                    TempBuf          *mask,
-                                                    gdouble           x,
-                                                    gdouble           y);
-static TempBuf * gimp_brush_core_pressurize_mask   (GimpBrushCore    *core,
-                                                    TempBuf          *brush_mask,
-                                                    gdouble           x,
-                                                    gdouble           y,
-                                                    gdouble           pressure);
-static TempBuf * gimp_brush_core_solidify_mask     (GimpBrushCore    *core,
-                                                    TempBuf          *brush_mask,
-                                                    gdouble           x,
-                                                    gdouble           y);
-static TempBuf * gimp_brush_core_transform_mask    (GimpBrushCore    *core,
-                                                    GimpBrush        *brush);
-static TempBuf * gimp_brush_core_transform_pixmap  (GimpBrushCore    *core,
-                                                    GimpBrush        *brush);
-
-static void      gimp_brush_core_invalidate_cache  (GimpBrush        *brush,
-                                                    GimpBrushCore    *core);
-
+                                                     GimpPaintOptions *paint_options,
+                                                     const GimpCoords *coords,
+                                                     GError          **error);
+static gboolean  gimp_brush_core_pre_paint          (GimpPaintCore    *core,
+                                                     GimpDrawable     *drawable,
+                                                     GimpPaintOptions *paint_options,
+                                                     GimpPaintState    paint_state,
+                                                     guint32           time);
+static void      gimp_brush_core_post_paint         (GimpPaintCore    *core,
+                                                     GimpDrawable     *drawable,
+                                                     GimpPaintOptions *paint_options,
+                                                     GimpPaintState    paint_state,
+                                                     guint32           time);
+static void      gimp_brush_core_interpolate        (GimpPaintCore    *core,
+                                                     GimpDrawable     *drawable,
+                                                     GimpPaintOptions *paint_options,
+                                                     guint32           time);
+
+static TempBuf * gimp_brush_core_get_paint_area     (GimpPaintCore    *paint_core,
+                                                     GimpDrawable     *drawable,
+                                                     GimpPaintOptions *paint_options,
+                                                     const GimpCoords *coords);
+
+static void      gimp_brush_core_real_set_brush     (GimpBrushCore    *core,
+                                                     GimpBrush        *brush);
+static void      gimp_brush_core_real_set_dynamics  (GimpBrushCore    *core,
+                                                     GimpDynamics     *dynamics);
+
+static const TempBuf * gimp_brush_core_subsample_mask   (GimpBrushCore    *core,
+                                                         const TempBuf    *mask,
+                                                         gdouble           x,
+                                                         gdouble           y);
+static const TempBuf * gimp_brush_core_pressurize_mask  (GimpBrushCore    *core,
+                                                         const TempBuf    *brush_mask,
+                                                         gdouble           x,
+                                                         gdouble           y,
+                                                         gdouble           pressure);
+static const TempBuf * gimp_brush_core_solidify_mask    (GimpBrushCore    *core,
+                                                         const TempBuf    *brush_mask,
+                                                         gdouble           x,
+                                                         gdouble           y);
+static const TempBuf * gimp_brush_core_transform_mask   (GimpBrushCore    *core,
+                                                         GimpBrush        *brush);
+static const TempBuf * gimp_brush_core_transform_pixmap (GimpBrushCore    *core,
+                                                         GimpBrush        *brush);
+
+static void      gimp_brush_core_invalidate_cache       (GimpBrush        *brush,
+                                                         GimpBrushCore    *core);
 
 /*  brush pipe utility functions  */
-static void      paint_line_pixmap_mask            (GimpImage        *dest,
-                                                    GimpDrawable     *drawable,
-                                                    TempBuf          *pixmap_mask,
-                                                    TempBuf          *brush_mask,
-                                                    guchar           *d,
-                                                    gint              x,
-                                                    gint              y,
-                                                    gint              bytes,
-                                                    gint              width,
-                                                    GimpBrushApplicationMode  mode);
+static void      gimp_brush_core_paint_line_pixmap_mask (GimpImage        *dest,
+                                                         GimpDrawable     *drawable,
+                                                         const TempBuf    *pixmap_mask,
+                                                         const TempBuf    *brush_mask,
+                                                         guchar           *d,
+                                                         gint              x,
+                                                         gint              y,
+                                                         gint              bytes,
+                                                         gint              width,
+                                                         GimpBrushApplicationMode  mode);
 
 
 G_DEFINE_TYPE (GimpBrushCore, gimp_brush_core, GIMP_TYPE_PAINT_CORE)
@@ -192,19 +189,12 @@ gimp_brush_core_init (GimpBrushCore *core)
 
   core->pressure_brush               = NULL;
 
-  core->last_solid_brush             = NULL;
+  core->last_solid_brush_mask        = NULL;
   core->solid_cache_invalid          = FALSE;
 
   core->transform_brush              = NULL;
-  core->last_transform_brush         = NULL;
-  core->last_transform_width         = 0;
-  core->last_transform_height        = 0;
-  core->last_scale                   = 1.0;
 
   core->transform_pixmap             = NULL;
-  core->last_transform_pixmap        = NULL;
-  core->last_transform_pixmap_width  = 0;
-  core->last_transform_pixmap_height = 0;
 
   core->last_brush_mask              = NULL;
   core->cache_invalid                = FALSE;
@@ -259,18 +249,6 @@ gimp_brush_core_finalize (GObject *object)
           core->solid_brushes[i][j] = NULL;
         }
 
-  if (core->transform_brush)
-    {
-      temp_buf_free (core->transform_brush);
-      core->transform_brush = NULL;
-    }
-
-  if (core->transform_pixmap)
-    {
-      temp_buf_free (core->transform_pixmap);
-      core->transform_pixmap = NULL;
-    }
-
   if (core->rand)
     {
       g_rand_free (core->rand);
@@ -934,10 +912,10 @@ gimp_brush_core_paste_canvas (GimpBrushCore            *core,
                               gdouble                   dynamic_force,
                               GimpPaintApplicationMode  mode)
 {
-  TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
-                                                        coords,
-                                                        brush_hardness,
-                                                        dynamic_force);
+  const TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
+                                                              coords,
+                                                              brush_hardness,
+                                                              dynamic_force);
 
   if (brush_mask)
     {
@@ -954,7 +932,7 @@ gimp_brush_core_paste_canvas (GimpBrushCore            *core,
       off_x = (x < 0) ? -x : 0;
       off_y = (y < 0) ? -y : 0;
 
-      pixel_region_init_temp_buf (&brush_maskPR, brush_mask,
+      pixel_region_init_temp_buf (&brush_maskPR, (TempBuf *) brush_mask,
                                   off_x, off_y,
                                   paint_core->canvas_buf->width,
                                   paint_core->canvas_buf->height);
@@ -980,10 +958,10 @@ gimp_brush_core_replace_canvas (GimpBrushCore            *core,
                                 gdouble                   dynamic_force,
                                 GimpPaintApplicationMode  mode)
 {
-  TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
-                                                        coords,
-                                                        brush_hardness,
-                                                        dynamic_force);
+  const TempBuf *brush_mask = gimp_brush_core_get_brush_mask (core,
+                                                              coords,
+                                                              brush_hardness,
+                                                              dynamic_force);
 
   if (brush_mask)
     {
@@ -1000,7 +978,7 @@ gimp_brush_core_replace_canvas (GimpBrushCore            *core,
       off_x = (x < 0) ? -x : 0;
       off_y = (y < 0) ? -y : 0;
 
-      pixel_region_init_temp_buf (&brush_maskPR, brush_mask,
+      pixel_region_init_temp_buf (&brush_maskPR, (TempBuf *) brush_mask,
                                   off_x, off_y,
                                   paint_core->canvas_buf->width,
                                   paint_core->canvas_buf->height);
@@ -1047,9 +1025,9 @@ rotate_pointers (gulong  **p,
   p[i] = tmp;
 }
 
-static TempBuf *
+static const TempBuf *
 gimp_brush_core_subsample_mask (GimpBrushCore *core,
-                                TempBuf       *mask,
+                                const TempBuf *mask,
                                 gdouble        x,
                                 gdouble        y)
 {
@@ -1181,9 +1159,9 @@ gimp_brush_core_subsample_mask (GimpBrushCore *core,
 
 /* #define FANCY_PRESSURE */
 
-static TempBuf *
+static const TempBuf *
 gimp_brush_core_pressurize_mask (GimpBrushCore *core,
-                                 TempBuf       *brush_mask,
+                                 const TempBuf *brush_mask,
                                  gdouble        x,
                                  gdouble        y,
                                  gdouble        pressure)
@@ -1191,7 +1169,7 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core,
   static guchar  mapi[256];
   const guchar  *source;
   guchar        *dest;
-  TempBuf       *subsample_mask;
+  const TempBuf *subsample_mask;
   const guchar   empty = TRANSPARENT_OPACITY;
   gint           i;
 
@@ -1296,9 +1274,9 @@ gimp_brush_core_pressurize_mask (GimpBrushCore *core,
   return core->pressure_brush;
 }
 
-static TempBuf *
+static const TempBuf *
 gimp_brush_core_solidify_mask (GimpBrushCore *core,
-                               TempBuf       *brush_mask,
+                               const TempBuf *brush_mask,
                                gdouble        x,
                                gdouble        y)
 {
@@ -1329,7 +1307,7 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core,
     }
 
   if (! core->solid_cache_invalid &&
-      brush_mask == core->last_solid_brush)
+      brush_mask == core->last_solid_brush_mask)
     {
       if (core->solid_brushes[dest_offset_y][dest_offset_x])
         return core->solid_brushes[dest_offset_y][dest_offset_x];
@@ -1344,8 +1322,8 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core,
               core->solid_brushes[i][j] = NULL;
             }
 
-      core->last_solid_brush    = brush_mask;
-      core->solid_cache_invalid = FALSE;
+      core->last_solid_brush_mask = brush_mask;
+      core->solid_cache_invalid   = FALSE;
     }
 
   dest = temp_buf_new (brush_mask->width  + 2,
@@ -1370,123 +1348,62 @@ gimp_brush_core_solidify_mask (GimpBrushCore *core,
   return dest;
 }
 
-static TempBuf *
+static const TempBuf *
 gimp_brush_core_transform_mask (GimpBrushCore *core,
                                 GimpBrush     *brush)
 {
-  gint width;
-  gint height;
+  const TempBuf *mask;
 
   if (core->scale <= 0.0)
     return NULL; /* Should never happen now, with scale clamping. */
 
-  if ((core->scale == 1.0) &&
-      (core->angle == 0.0) &&
-      (core->hardness == 1.0) &&
-      (core->aspect_ratio == 0.0))
-    return brush->mask;
+  mask = gimp_brush_transform_mask (brush,
+                                    core->scale,
+                                    core->aspect_ratio,
+                                    core->angle,
+                                    core->hardness);
 
-  gimp_brush_transform_size (brush,
-                             core->scale, core->aspect_ratio, core->angle,
-                             &width, &height);
-
-  if (! core->cache_invalid                             &&
-      core->transform_brush                             &&
-      brush->mask        == core->last_transform_brush  &&
-      width              == core->last_transform_width  &&
-      height             == core->last_transform_height &&
-      core->scale        == core->last_scale            &&
-      core->angle        == core->last_angle            &&
-      core->hardness     == core->last_hardness         &&
-      core->aspect_ratio == core->last_aspect_ratio)
-    {
-      return core->transform_brush;
-    }
-
-  core->last_transform_brush  = brush->mask;
-  core->last_transform_width  = width;
-  core->last_transform_height = height;
-  core->last_scale        = core->scale;
-  core->last_angle        = core->angle;
-  core->last_hardness     = core->hardness;
-  core->last_aspect_ratio = core->aspect_ratio;
-
-  if (core->transform_brush)
-    temp_buf_free (core->transform_brush);
-
-  core->transform_brush = gimp_brush_transform_mask (brush,
-                                                     core->scale,
-                                                     core->aspect_ratio,
-                                                     core->angle,
-                                                     core->hardness);
+  if (mask == core->transform_brush)
+    return mask;
 
+  core->transform_brush     = mask;
   core->cache_invalid       = TRUE;
   core->solid_cache_invalid = TRUE;
 
   return core->transform_brush;
 }
 
-static TempBuf *
+static const TempBuf *
 gimp_brush_core_transform_pixmap (GimpBrushCore *core,
                                   GimpBrush     *brush)
 {
-  gint width;
-  gint height;
+  const TempBuf *pixmap;
 
   if (core->scale <= 0.0)
     return NULL;
 
-  if ((core->scale        == 1.0) &&
-      (core->angle        == 0.0) &&
-      (core->hardness     == 1.0) &&
-      (core->aspect_ratio == 0.0))
-    return brush->pixmap;
-
-  gimp_brush_transform_size (brush,
-                             core->scale, core->aspect_ratio, core->angle,
-                             &width, &height);
-
-  if (! core->cache_invalid                                    &&
-      core->transform_pixmap                                   &&
-      brush->pixmap      == core->last_transform_pixmap        &&
-      width              == core->last_transform_pixmap_width  &&
-      height             == core->last_transform_pixmap_height &&
-      core->angle        == core->last_angle                   &&
-      core->hardness     == core->last_hardness                &&
-      core->aspect_ratio == core->last_aspect_ratio)
-    {
-      return core->transform_pixmap;
-    }
-
-  core->last_transform_pixmap        = brush->pixmap;
-  core->last_transform_pixmap_width  = width;
-  core->last_transform_pixmap_height = height;
-  core->last_angle                   = core->angle;
-  core->last_hardness                = core->hardness;
-  core->last_aspect_ratio            = core->aspect_ratio;
-
-  if (core->transform_pixmap)
-    temp_buf_free (core->transform_pixmap);
-
+  pixmap = gimp_brush_transform_pixmap (brush,
+                                        core->scale,
+                                        core->aspect_ratio,
+                                        core->angle,
+                                        core->hardness);
 
-  core->transform_pixmap = gimp_brush_transform_pixmap (brush,
-                                                        core->scale,
-                                                        core->aspect_ratio,
-                                                        core->angle,
-                                                        core->hardness);
+  if (pixmap == core->transform_pixmap)
+    return pixmap;
 
-  core->cache_invalid = TRUE;
+  core->transform_pixmap = pixmap;
+  core->cache_invalid    = TRUE;
 
   return core->transform_pixmap;
 }
 
-TempBuf *
+const TempBuf *
 gimp_brush_core_get_brush_mask (GimpBrushCore            *core,
                                 const GimpCoords         *coords,
                                 GimpBrushApplicationMode  brush_hardness,
                                 gdouble                   dynamic_force)
 {
-  TempBuf *mask;
+  const TempBuf *mask;
 
   mask = gimp_brush_core_transform_mask (core, core->brush);
 
@@ -1496,29 +1413,26 @@ gimp_brush_core_get_brush_mask (GimpBrushCore            *core,
   switch (brush_hardness)
     {
     case GIMP_BRUSH_SOFT:
-      mask = gimp_brush_core_subsample_mask (core, mask,
+      return gimp_brush_core_subsample_mask (core, mask,
                                              coords->x,
                                              coords->y);
       break;
 
     case GIMP_BRUSH_HARD:
-      mask = gimp_brush_core_solidify_mask (core, mask,
+      return gimp_brush_core_solidify_mask (core, mask,
                                             coords->x,
                                             coords->y);
       break;
 
     case GIMP_BRUSH_PRESSURE:
-      mask = gimp_brush_core_pressurize_mask (core, mask,
+      return gimp_brush_core_pressurize_mask (core, mask,
                                               coords->x,
                                               coords->y,
                                               dynamic_force);
       break;
-
-    default:
-      break;
     }
 
-  return mask;
+  g_return_val_if_reached (NULL);
 }
 
 void
@@ -1616,17 +1530,17 @@ gimp_brush_core_color_area_with_pixmap (GimpBrushCore            *core,
                                         TempBuf                  *area,
                                         GimpBrushApplicationMode  mode)
 {
-  GimpImage   *image;
-  PixelRegion  destPR;
-  void        *pr;
-  guchar      *d;
-  gint         ulx;
-  gint         uly;
-  gint         offsetx;
-  gint         offsety;
-  gint         y;
-  TempBuf     *pixmap_mask;
-  TempBuf     *brush_mask;
+  GimpImage     *image;
+  PixelRegion    destPR;
+  void          *pr;
+  guchar        *d;
+  gint           ulx;
+  gint           uly;
+  gint           offsetx;
+  gint           offsety;
+  gint           y;
+  const TempBuf *pixmap_mask;
+  const TempBuf *brush_mask;
 
   g_return_if_fail (GIMP_IS_BRUSH (core->brush));
   g_return_if_fail (core->brush->pixmap != NULL);
@@ -1672,25 +1586,26 @@ gimp_brush_core_color_area_with_pixmap (GimpBrushCore            *core,
 
       for (y = 0; y < destPR.h; y++)
         {
-          paint_line_pixmap_mask (image, drawable, pixmap_mask, brush_mask,
-                                  d, offsetx, y + offsety,
-                                  destPR.bytes, destPR.w, mode);
+          gimp_brush_core_paint_line_pixmap_mask (image, drawable,
+                                                  pixmap_mask, brush_mask,
+                                                  d, offsetx, y + offsety,
+                                                  destPR.bytes, destPR.w, mode);
           d += destPR.rowstride;
         }
     }
 }
 
 static void
-paint_line_pixmap_mask (GimpImage                *dest,
-                        GimpDrawable             *drawable,
-                        TempBuf                  *pixmap_mask,
-                        TempBuf                  *brush_mask,
-                        guchar                   *d,
-                        gint                      x,
-                        gint                      y,
-                        gint                      bytes,
-                        gint                      width,
-                        GimpBrushApplicationMode  mode)
+gimp_brush_core_paint_line_pixmap_mask (GimpImage                *dest,
+                                        GimpDrawable             *drawable,
+                                        const TempBuf            *pixmap_mask,
+                                        const TempBuf            *brush_mask,
+                                        guchar                   *d,
+                                        gint                      x,
+                                        gint                      y,
+                                        gint                      bytes,
+                                        gint                      width,
+                                        GimpBrushApplicationMode  mode)
 {
   const guchar  *mask;
   guchar        *b;
diff --git a/app/paint/gimpbrushcore.h b/app/paint/gimpbrushcore.h
index 2bbd149..d6e86b9 100644
--- a/app/paint/gimpbrushcore.h
+++ b/app/paint/gimpbrushcore.h
@@ -55,26 +55,15 @@ struct _GimpBrushCore
   TempBuf       *pressure_brush;
 
   TempBuf       *solid_brushes[BRUSH_CORE_SOLID_SUBSAMPLE][BRUSH_CORE_SOLID_SUBSAMPLE];
-  TempBuf       *last_solid_brush;
+  const TempBuf *last_solid_brush_mask;
   gboolean       solid_cache_invalid;
 
-  TempBuf       *transform_brush;
-  TempBuf       *last_transform_brush;
-  gint           last_transform_width;
-  gint           last_transform_height;
-  gdouble        last_scale;
-  gdouble        last_angle;
-  gdouble        last_hardness;
-  gdouble        last_aspect_ratio;
-
-  TempBuf       *transform_pixmap;
-  TempBuf       *last_transform_pixmap;
-  gint           last_transform_pixmap_width;
-  gint           last_transform_pixmap_height;
+  const TempBuf *transform_brush;
+  const TempBuf *transform_pixmap;
 
   TempBuf       *kernel_brushes[BRUSH_CORE_SUBSAMPLE + 1][BRUSH_CORE_SUBSAMPLE + 1];
 
-  TempBuf       *last_brush_mask;
+  const TempBuf *last_brush_mask;
   gboolean       cache_invalid;
 
   gdouble        jitter;
@@ -93,6 +82,7 @@ struct _GimpBrushCoreClass
 
   /*  Set for tools that don't mind if the brush scales while painting  */
   gboolean            handles_transforming_brush;
+
   /*  Set for tools that don't mind if the brush scales mid stroke  */
   gboolean            handles_dynamic_transforming_brush;
 
@@ -103,48 +93,50 @@ struct _GimpBrushCoreClass
 };
 
 
-GType   gimp_brush_core_get_type       (void) G_GNUC_CONST;
-
-void    gimp_brush_core_set_brush      (GimpBrushCore            *core,
-                                        GimpBrush                *brush);
-
-void    gimp_brush_core_set_dynamics   (GimpBrushCore            *core,
-                                        GimpDynamics             *dynamics);
-
-void    gimp_brush_core_paste_canvas   (GimpBrushCore            *core,
-                                        GimpDrawable             *drawable,
-                                        const GimpCoords         *coords,
-                                        gdouble                   brush_opacity,
-                                        gdouble                   image_opacity,
-                                        GimpLayerModeEffects      paint_mode,
-                                        GimpBrushApplicationMode  brush_hardness,
-                                        gdouble                   dynamic_hardness,
-                                        GimpPaintApplicationMode  mode);
-void    gimp_brush_core_replace_canvas (GimpBrushCore            *core,
-                                        GimpDrawable             *drawable,
-                                        const GimpCoords         *coords,
-                                        gdouble                   brush_opacity,
-                                        gdouble                   image_opacity,
-                                        GimpBrushApplicationMode  brush_hardness,
-                                        gdouble                   dynamic_hardness,
-                                        GimpPaintApplicationMode  mode);
-
-void    gimp_brush_core_color_area_with_pixmap
-                                         (GimpBrushCore            *core,
-                                          GimpDrawable             *drawable,
-                                          const GimpCoords         *coords,
-                                          TempBuf                  *area,
-                                          GimpBrushApplicationMode  mode);
-
-TempBuf * gimp_brush_core_get_brush_mask (GimpBrushCore            *core,
-                                          const GimpCoords         *coords,
-                                          GimpBrushApplicationMode  brush_hardness,
-                                          gdouble                   dynamic_hardness);
-
-
-void gimp_brush_core_eval_transform_dynamics (GimpPaintCore     *paint_core,
-                                              GimpDrawable      *drawable,
-                                              GimpPaintOptions  *paint_options,
-                                              const GimpCoords  *coords);
+GType  gimp_brush_core_get_type       (void) G_GNUC_CONST;
+
+void   gimp_brush_core_set_brush      (GimpBrushCore            *core,
+                                       GimpBrush                *brush);
+
+void   gimp_brush_core_set_dynamics   (GimpBrushCore            *core,
+                                       GimpDynamics             *dynamics);
+
+void   gimp_brush_core_paste_canvas   (GimpBrushCore            *core,
+                                       GimpDrawable             *drawable,
+                                       const GimpCoords         *coords,
+                                       gdouble                   brush_opacity,
+                                       gdouble                   image_opacity,
+                                       GimpLayerModeEffects      paint_mode,
+                                       GimpBrushApplicationMode  brush_hardness,
+                                       gdouble                   dynamic_hardness,
+                                       GimpPaintApplicationMode  mode);
+void   gimp_brush_core_replace_canvas (GimpBrushCore            *core,
+                                       GimpDrawable             *drawable,
+                                       const GimpCoords         *coords,
+                                       gdouble                   brush_opacity,
+                                       gdouble                   image_opacity,
+                                       GimpBrushApplicationMode  brush_hardness,
+                                       gdouble                   dynamic_hardness,
+                                       GimpPaintApplicationMode  mode);
+
+void   gimp_brush_core_color_area_with_pixmap
+                                      (GimpBrushCore            *core,
+                                       GimpDrawable             *drawable,
+                                       const GimpCoords         *coords,
+                                       TempBuf                  *area,
+                                       GimpBrushApplicationMode  mode);
+
+const TempBuf * gimp_brush_core_get_brush_mask
+                                      (GimpBrushCore            *core,
+                                       const GimpCoords         *coords,
+                                       GimpBrushApplicationMode  brush_hardness,
+                                       gdouble                   dynamic_hardness);
+
+void   gimp_brush_core_eval_transform_dynamics
+                                      (GimpPaintCore            *paint_core,
+                                       GimpDrawable             *drawable,
+                                       GimpPaintOptions         *paint_options,
+                                       const GimpCoords         *coords);
+
 
 #endif  /*  __GIMP_BRUSH_CORE_H__  */
diff --git a/app/paint/gimpheal.c b/app/paint/gimpheal.c
index 3c3c5f6..b0880a7 100644
--- a/app/paint/gimpheal.c
+++ b/app/paint/gimpheal.c
@@ -84,7 +84,7 @@ static void         gimp_heal_laplace_loop       (gdouble          *matrix,
 
 static PixelRegion *gimp_heal_region             (PixelRegion      *tempPR,
                                                   PixelRegion      *srcPR,
-                                                  TempBuf          *mask_buf);
+                                                  const TempBuf    *mask_buf);
 
 static void         gimp_heal_motion             (GimpSourceCore   *source_core,
                                                   GimpDrawable     *drawable,
@@ -387,9 +387,9 @@ gimp_heal_laplace_loop (gdouble *matrix,
  * 2005, http://www.tgeorgiev.net/
  */
 static PixelRegion *
-gimp_heal_region (PixelRegion *tempPR,
-                  PixelRegion *srcPR,
-                  TempBuf     *mask_buf)
+gimp_heal_region (PixelRegion   *tempPR,
+                  PixelRegion   *srcPR,
+                  const TempBuf *mask_buf)
 {
   gdouble *i_1  = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w);
   gdouble *i_2  = g_new (gdouble, tempPR->h * tempPR->bytes * tempPR->w);
@@ -442,7 +442,7 @@ gimp_heal_motion (GimpSourceCore   *source_core,
   PixelRegion         tempPR;
   PixelRegion         destPR;
   GimpImageType       src_type;
-  TempBuf            *mask_buf;
+  const TempBuf      *mask_buf;
   gdouble             fade_point;
   gdouble             hardness;
 
diff --git a/app/tools/gimpbrushtool.c b/app/tools/gimpbrushtool.c
index ed759c1..14c222a 100644
--- a/app/tools/gimpbrushtool.c
+++ b/app/tools/gimpbrushtool.c
@@ -295,13 +295,13 @@ gimp_brush_tool_draw_brush (GimpBrushTool *brush_tool,
                             gdouble        y,
                             gboolean       draw_fallback)
 {
-  GimpDrawTool     *draw_tool;
-  GimpBrushCore    *brush_core;
-  GimpPaintOptions *options;
-  GimpDisplayShell *shell;
-  GimpBezierDesc   *boundary = NULL;
-  gint              width    = 0;
-  gint              height   = 0;
+  GimpDrawTool         *draw_tool;
+  GimpBrushCore        *brush_core;
+  GimpPaintOptions     *options;
+  GimpDisplayShell     *shell;
+  const GimpBezierDesc *boundary = NULL;
+  gint                  width    = 0;
+  gint                  height   = 0;
 
   g_return_if_fail (GIMP_IS_BRUSH_TOOL (brush_tool));
 
@@ -353,9 +353,6 @@ gimp_brush_tool_draw_brush (GimpBrushTool *brush_tool,
                                  x, y,
                                  5, 5, GIMP_HANDLE_ANCHOR_CENTER);
     }
-
-  if (boundary)
-    gimp_bezier_desc_free (boundary);
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]