[gimp] app: add gimp_drawable_{start,end,flush}_paint()



commit ce9ca03ed47eb2e2fe6cd18a467d02e1bcff5fe2
Author: Ell <ell_se yahoo com>
Date:   Sun Apr 8 09:21:46 2018 -0400

    app: add gimp_drawable_{start,end,flush}_paint()
    
    gimp_drawable_start/end_paint() are used to enter/exit paint mode
    for a given drawable.  While the drawable is in paint mode,
    gimp_drawable_get_buffer() returns a copy of the real drawable's
    buffer, referred to as the paint buffer, so that modifications to
    the returned buffer don't immediately affect the projection, and
    calls to gimp_drawable_update() queue the updated region, instead
    of emitting an "update" signal.
    
    gimp_drawable_flush_paint() can be called while the drawable is in
    paint mode, in order to copy the updated region of the paint buffer
    back to the drawable's real buffer, and to emit "update" signals
    for the queued region.
    
    We use these functions in the next commit, to move painting to a
    separate thread in the paint tools.

 app/core/gimpdrawable-filters.c |    1 +
 app/core/gimpdrawable-private.h |    5 +
 app/core/gimpdrawable-shadow.c  |    1 +
 app/core/gimpdrawable.c         |  169 ++++++++++++++++++++++++++++++++++++++-
 app/core/gimpdrawable.h         |    4 +
 app/text/gimptextlayer-xcf.c    |    1 +
 6 files changed, 178 insertions(+), 3 deletions(-)
---
diff --git a/app/core/gimpdrawable-filters.c b/app/core/gimpdrawable-filters.c
index a1c7288..08c20f6 100644
--- a/app/core/gimpdrawable-filters.c
+++ b/app/core/gimpdrawable-filters.c
@@ -21,6 +21,7 @@
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
+#include <cairo.h>
 
 #include "core-types.h"
 
diff --git a/app/core/gimpdrawable-private.h b/app/core/gimpdrawable-private.h
index c821e7d..c84c665 100644
--- a/app/core/gimpdrawable-private.h
+++ b/app/core/gimpdrawable-private.h
@@ -33,6 +33,11 @@ struct _GimpDrawablePrivate
   GimpApplicator *fs_applicator;
 
   GeglNode       *mode_node;
+
+  gint            paint_count;
+  GeglBuffer     *paint_buffer;
+  cairo_region_t *paint_copy_region;
+  cairo_region_t *paint_update_region;
 };
 
 #endif /* __GIMP_DRAWABLE_PRIVATE_H__ */
diff --git a/app/core/gimpdrawable-shadow.c b/app/core/gimpdrawable-shadow.c
index 25b8dc9..e826e6f 100644
--- a/app/core/gimpdrawable-shadow.c
+++ b/app/core/gimpdrawable-shadow.c
@@ -19,6 +19,7 @@
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
+#include <cairo.h>
 
 #include "core-types.h"
 
diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c
index abdd285..39c470b 100644
--- a/app/core/gimpdrawable.c
+++ b/app/core/gimpdrawable.c
@@ -23,6 +23,7 @@
 
 #include "libgimpbase/gimpbase.h"
 #include "libgimpcolor/gimpcolor.h"
+#include "libgimpmath/gimpmath.h"
 
 #include "core-types.h"
 
@@ -54,6 +55,13 @@
 #include "gimp-intl.h"
 
 
+#define PAINT_COPY_CHUNK_WIDTH    128
+#define PAINT_COPY_CHUNK_HEIGHT   128
+
+#define PAINT_UPDATE_CHUNK_WIDTH   32
+#define PAINT_UPDATE_CHUNK_HEIGHT  32
+
+
 enum
 {
   UPDATE,
@@ -312,6 +320,9 @@ gimp_drawable_finalize (GObject *object)
 {
   GimpDrawable *drawable = GIMP_DRAWABLE (object);
 
+  while (drawable->private->paint_count)
+    gimp_drawable_end_paint (drawable);
+
   g_clear_object (&drawable->private->buffer);
 
   gimp_drawable_free_shadow_buffer (drawable);
@@ -944,8 +955,59 @@ gimp_drawable_update (GimpDrawable *drawable,
   if (height == -1)
     height = gimp_item_get_height (GIMP_ITEM (drawable));
 
-  g_signal_emit (drawable, gimp_drawable_signals[UPDATE], 0,
-                 x, y, width, height);
+  if (drawable->private->paint_count == 0)
+    {
+      g_signal_emit (drawable, gimp_drawable_signals[UPDATE], 0,
+                     x, y, width, height);
+    }
+  else
+    {
+      GeglRectangle rect;
+
+      rect.x      = floor ((gdouble) x            / PAINT_COPY_CHUNK_WIDTH)  * PAINT_COPY_CHUNK_WIDTH;
+      rect.y      = floor ((gdouble) y            / PAINT_COPY_CHUNK_HEIGHT) * PAINT_COPY_CHUNK_HEIGHT;
+      rect.width  = ceil  ((gdouble) (x + width)  / PAINT_COPY_CHUNK_WIDTH)  * PAINT_COPY_CHUNK_WIDTH  - 
rect.x;
+      rect.height = ceil  ((gdouble) (y + height) / PAINT_COPY_CHUNK_HEIGHT) * PAINT_COPY_CHUNK_HEIGHT - 
rect.y;
+
+      if (gegl_rectangle_intersect (
+            &rect,
+            &rect,
+            GEGL_RECTANGLE (0, 0,
+                            gimp_item_get_width  (GIMP_ITEM (drawable)),
+                            gimp_item_get_height (GIMP_ITEM (drawable)))))
+        {
+          if (drawable->private->paint_copy_region)
+            {
+              cairo_region_union_rectangle (
+                drawable->private->paint_copy_region,
+                (const cairo_rectangle_int_t *) &rect);
+            }
+          else
+            {
+              drawable->private->paint_copy_region =
+                cairo_region_create_rectangle (
+                  (const cairo_rectangle_int_t *) &rect);
+            }
+
+            rect.x      = floor ((gdouble) x            / PAINT_UPDATE_CHUNK_WIDTH)  * 
PAINT_UPDATE_CHUNK_WIDTH;
+            rect.y      = floor ((gdouble) y            / PAINT_UPDATE_CHUNK_HEIGHT) * 
PAINT_UPDATE_CHUNK_HEIGHT;
+            rect.width  = ceil  ((gdouble) (x + width)  / PAINT_UPDATE_CHUNK_WIDTH)  * 
PAINT_UPDATE_CHUNK_WIDTH  - rect.x;
+            rect.height = ceil  ((gdouble) (y + height) / PAINT_UPDATE_CHUNK_HEIGHT) * 
PAINT_UPDATE_CHUNK_HEIGHT - rect.y;
+
+            if (drawable->private->paint_update_region)
+              {
+                cairo_region_union_rectangle (
+                  drawable->private->paint_update_region,
+                  (const cairo_rectangle_int_t *) &rect);
+              }
+            else
+              {
+                drawable->private->paint_update_region =
+                  cairo_region_create_rectangle (
+                    (const cairo_rectangle_int_t *) &rect);
+              }
+        }
+    }
 }
 
 void
@@ -1123,7 +1185,10 @@ gimp_drawable_get_buffer (GimpDrawable *drawable)
 {
   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
 
-  return GIMP_DRAWABLE_GET_CLASS (drawable)->get_buffer (drawable);
+  if (drawable->private->paint_count == 0)
+    return GIMP_DRAWABLE_GET_CLASS (drawable)->get_buffer (drawable);
+  else
+    return drawable->private->paint_buffer;
 }
 
 void
@@ -1506,3 +1571,101 @@ gimp_drawable_get_colormap (GimpDrawable *drawable)
 
   return image ? gimp_image_get_colormap (image) : NULL;
 }
+
+void
+gimp_drawable_start_paint (GimpDrawable *drawable)
+{
+  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
+
+  if (drawable->private->paint_count == 0)
+    {
+      GeglBuffer *buffer = gimp_drawable_get_buffer (drawable);
+
+      g_return_if_fail (buffer != NULL);
+      g_return_if_fail (drawable->private->paint_buffer == NULL);
+      g_return_if_fail (drawable->private->paint_copy_region == NULL);
+      g_return_if_fail (drawable->private->paint_update_region == NULL);
+
+      drawable->private->paint_buffer = gegl_buffer_dup (buffer);
+    }
+
+  drawable->private->paint_count++;
+}
+
+gboolean
+gimp_drawable_end_paint (GimpDrawable *drawable)
+{
+  gboolean result = FALSE;
+
+  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
+  g_return_val_if_fail (drawable->private->paint_count > 0, FALSE);
+
+  if (drawable->private->paint_count == 1)
+    {
+      result = gimp_drawable_flush_paint (drawable);
+
+      g_clear_object (&drawable->private->paint_buffer);
+    }
+
+  drawable->private->paint_count--;
+
+  return result;
+}
+
+gboolean
+gimp_drawable_flush_paint (GimpDrawable *drawable)
+{
+  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
+  g_return_val_if_fail (drawable->private->paint_count > 0, FALSE);
+
+  if (drawable->private->paint_copy_region)
+    {
+      GeglBuffer *buffer;
+      gint        n_rects;
+      gint        i;
+
+      buffer = GIMP_DRAWABLE_GET_CLASS (drawable)->get_buffer (drawable);
+
+      g_return_val_if_fail (buffer != NULL, FALSE);
+      g_return_val_if_fail (drawable->private->paint_buffer != NULL, FALSE);
+
+      n_rects = cairo_region_num_rectangles (
+        drawable->private->paint_copy_region);
+
+      for (i = 0; i < n_rects; i++)
+        {
+          GeglRectangle rect;
+
+          cairo_region_get_rectangle (drawable->private->paint_copy_region,
+                                      i, (cairo_rectangle_int_t *) &rect);
+
+          gegl_buffer_copy (
+            drawable->private->paint_buffer, &rect, GEGL_ABYSS_NONE,
+            buffer, NULL);
+        }
+
+      g_clear_pointer (&drawable->private->paint_copy_region,
+                       cairo_region_destroy);
+
+      n_rects = cairo_region_num_rectangles (
+        drawable->private->paint_update_region);
+
+      for (i = 0; i < n_rects; i++)
+        {
+          GeglRectangle rect;
+
+          cairo_region_get_rectangle (drawable->private->paint_update_region,
+                                      i, (cairo_rectangle_int_t *) &rect);
+
+          g_signal_emit (drawable, gimp_drawable_signals[UPDATE], 0,
+                         rect.x, rect.y, rect.width, rect.height);
+        }
+
+      g_clear_pointer (&drawable->private->paint_update_region,
+                       cairo_region_destroy);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h
index abd1e45..0d69aef 100644
--- a/app/core/gimpdrawable.h
+++ b/app/core/gimpdrawable.h
@@ -228,5 +228,9 @@ gint              gimp_drawable_get_component_index  (GimpDrawable    *drawable,
 
 const guchar    * gimp_drawable_get_colormap         (GimpDrawable    *drawable);
 
+void              gimp_drawable_start_paint          (GimpDrawable    *drawable);
+gboolean          gimp_drawable_end_paint            (GimpDrawable    *drawable);
+gboolean          gimp_drawable_flush_paint          (GimpDrawable    *drawable);
+
 
 #endif /* __GIMP_DRAWABLE_H__ */
diff --git a/app/text/gimptextlayer-xcf.c b/app/text/gimptextlayer-xcf.c
index 8e9734e..abfcd6b 100644
--- a/app/text/gimptextlayer-xcf.c
+++ b/app/text/gimptextlayer-xcf.c
@@ -22,6 +22,7 @@
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
+#include <cairo.h>
 
 #include "libgimpbase/gimpbase.h"
 #include "text-types.h"


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