[gimp] app: add gimp_histogram_calculate_async()



commit 9ea560d4a9d0208172a67858a9843df0592bd9f7
Author: Ell <ell_se yahoo com>
Date:   Fri May 11 11:51:30 2018 -0400

    app: add gimp_histogram_calculate_async()
    
    ... which is similar to gimp_histogram_calculate(), calculating the
    histogram asynchronously on a separate thread.

 app/core/gimphistogram.c |  760 ++++++++++++++++++++++++++++++----------------
 app/core/gimphistogram.h |   93 +++---
 2 files changed, 548 insertions(+), 305 deletions(-)
---
diff --git a/app/core/gimphistogram.c b/app/core/gimphistogram.c
index 8ae8aaa..4314d50 100644
--- a/app/core/gimphistogram.c
+++ b/app/core/gimphistogram.c
@@ -31,6 +31,8 @@
 
 #include "gegl/gimp-babl.h"
 
+#include "gimp-parallel.h"
+#include "gimpasync.h"
 #include "gimphistogram.h"
 
 
@@ -44,31 +46,55 @@ enum
 
 struct _GimpHistogramPrivate
 {
-  gboolean  linear;
-  gint      n_channels;
-  gint      n_bins;
-  gdouble  *values;
+  gboolean   linear;
+  gint       n_channels;
+  gint       n_bins;
+  gdouble   *values;
+  GimpAsync *calculate_async;
 };
 
+typedef struct
+{
+  GimpHistogram *histogram;
+  GeglBuffer    *buffer;
+  GeglRectangle  buffer_rect;
+  GeglBuffer    *mask;
+  GeglRectangle  mask_rect;
 
-/*  local function prototypes  */
+  gint           n_components;
+  gint           n_bins;
+  gdouble       *values;
+} CalculateContext;
 
-static void     gimp_histogram_finalize     (GObject       *object);
-static void     gimp_histogram_set_property (GObject       *object,
-                                             guint          property_id,
-                                             const GValue  *value,
-                                             GParamSpec    *pspec);
-static void     gimp_histogram_get_property (GObject       *object,
-                                             guint          property_id,
-                                             GValue        *value,
-                                             GParamSpec    *pspec);
 
-static gint64   gimp_histogram_get_memsize  (GimpObject    *object,
-                                             gint64        *gui_size);
+/*  local function prototypes  */
 
-static void     gimp_histogram_alloc_values (GimpHistogram *histogram,
-                                             gint           n_components,
-                                             gint           n_bins);
+static void      gimp_histogram_dispose                  (GObject             *object);
+static void      gimp_histogram_finalize                 (GObject             *object);
+static void      gimp_histogram_set_property             (GObject             *object,
+                                                          guint                property_id,
+                                                          const GValue        *value,
+                                                          GParamSpec          *pspec);
+static void      gimp_histogram_get_property             (GObject             *object,
+                                                          guint                property_id,
+                                                          GValue              *value,
+                                                          GParamSpec          *pspec);
+
+static gint64    gimp_histogram_get_memsize              (GimpObject          *object,
+                                                          gint64              *gui_size);
+
+static gdouble * gimp_histogram_alloc_values             (GimpHistogram       *histogram,
+                                                          gint                 n_components,
+                                                          gint                 n_bins);
+static void      gimp_histogram_set_values               (GimpHistogram       *histogram,
+                                                          gint                 n_components,
+                                                          gint                 n_bins,
+                                                          gdouble             *values);
+
+static void      gimp_histogram_calculate_internal       (GimpAsync           *async,
+                                                          CalculateContext    *context);
+static void      gimp_histogram_calculate_async_callback (GimpAsync           *async,
+                                                          CalculateContext    *context);
 
 
 G_DEFINE_TYPE (GimpHistogram, gimp_histogram, GIMP_TYPE_OBJECT)
@@ -82,6 +108,7 @@ gimp_histogram_class_init (GimpHistogramClass *klass)
   GObjectClass      *object_class      = G_OBJECT_CLASS (klass);
   GimpObjectClass   *gimp_object_class = GIMP_OBJECT_CLASS (klass);
 
+  object_class->dispose          = gimp_histogram_dispose;
   object_class->finalize         = gimp_histogram_finalize;
   object_class->set_property     = gimp_histogram_set_property;
   object_class->get_property     = gimp_histogram_get_property;
@@ -118,6 +145,20 @@ gimp_histogram_init (GimpHistogram *histogram)
 }
 
 static void
+gimp_histogram_dispose (GObject *object)
+{
+  GimpHistogram *histogram = GIMP_HISTOGRAM (object);
+
+  if (histogram->priv->calculate_async)
+    {
+      gimp_async_cancel (histogram->priv->calculate_async);
+      gimp_async_wait (histogram->priv->calculate_async);
+    }
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
 gimp_histogram_finalize (GObject *object)
 {
   GimpHistogram *histogram = GIMP_HISTOGRAM (object);
@@ -213,6 +254,9 @@ gimp_histogram_duplicate (GimpHistogram *histogram)
 
   g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), NULL);
 
+  if (histogram->priv->calculate_async)
+    gimp_async_wait (histogram->priv->calculate_async);
+
   dup = gimp_histogram_new (histogram->priv->linear);
 
   dup->priv->n_channels = histogram->priv->n_channels;
@@ -232,264 +276,92 @@ gimp_histogram_calculate (GimpHistogram       *histogram,
                           GeglBuffer          *mask,
                           const GeglRectangle *mask_rect)
 {
-  GimpHistogramPrivate *priv;
-  GeglBufferIterator   *iter;
-  const Babl           *format;
-  gint                  n_components;
-  gint                  n_bins;
-  gfloat                n_bins_1f;
-  gfloat                temp;
+  CalculateContext context = {};
 
   g_return_if_fail (GIMP_IS_HISTOGRAM (histogram));
   g_return_if_fail (GEGL_IS_BUFFER (buffer));
   g_return_if_fail (buffer_rect != NULL);
 
-  priv = histogram->priv;
-
-  format = gegl_buffer_get_format (buffer);
-
-  if (babl_format_get_type (format, 0) == babl_type ("u8"))
-    n_bins = 256;
-  else
-    n_bins = 1024;
-
-  if (babl_format_is_palette (format))
+  if (histogram->priv->calculate_async)
     {
-      if (babl_format_has_alpha (format))
-        {
-          if (priv->linear)
-            format = babl_format ("RGB float");
-          else
-            format = babl_format ("R'G'B' float");
-        }
-      else
-        {
-          if (priv->linear)
-            format = babl_format ("RGBA float");
-          else
-            format = babl_format ("R'G'B'A float");
-        }
-    }
-  else
-    {
-      const Babl *model = babl_format_get_model (format);
-
-      if (model == babl_model ("Y") ||
-          model == babl_model ("Y'"))
-        {
-          if (priv->linear)
-            format = babl_format ("Y float");
-          else
-            format = babl_format ("Y' float");
-        }
-      else if (model == babl_model ("YA") ||
-               model == babl_model ("Y'A"))
-        {
-          if (priv->linear)
-            format = babl_format ("YA float");
-          else
-            format = babl_format ("Y'A float");
-        }
-      else if (model == babl_model ("RGB") ||
-               model == babl_model ("R'G'B'"))
-        {
-          if (priv->linear)
-            format = babl_format ("RGB float");
-          else
-            format = babl_format ("R'G'B' float");
-        }
-      else if (model == babl_model ("RGBA") ||
-               model == babl_model ("R'G'B'A"))
-        {
-          if (priv->linear)
-            format = babl_format ("RGBA float");
-          else
-            format = babl_format ("R'G'B'A float");
-        }
-      else
-        {
-          g_return_if_reached ();
-        }
+      gimp_async_cancel (histogram->priv->calculate_async);
+      gimp_async_wait (histogram->priv->calculate_async);
     }
 
-  n_components = babl_format_get_n_components (format);
-
-  g_object_freeze_notify (G_OBJECT (histogram));
-
-  gimp_histogram_alloc_values (histogram, n_components, n_bins);
-
-  iter = gegl_buffer_iterator_new (buffer, buffer_rect, 0, format,
-                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+  context.histogram   = histogram;
+  context.buffer      = buffer;
+  context.buffer_rect = *buffer_rect;
 
   if (mask)
-    gegl_buffer_iterator_add (iter, mask, mask_rect, 0,
-                              babl_format ("Y float"),
-                              GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
-
-  n_bins_1f = priv->n_bins - 1;
-
-#define VALUE(c,i) (*(temp = (i) * n_bins_1f,                                  \
-                      &priv->values[(c) * priv->n_bins +                       \
-                                    SIGNED_ROUND (SAFE_CLAMP (temp,            \
-                                                              0.0f,            \
-                                                              n_bins_1f))]))
-
-  while (gegl_buffer_iterator_next (iter))
     {
-      const gfloat *data   = iter->data[0];
-      gint          length = iter->length;
-      gfloat        max;
-      gfloat        luminance;
-
-      if (mask)
-        {
-          const gfloat *mask_data = iter->data[1];
-
-          switch (n_components)
-            {
-            case 1:
-              while (length--)
-                {
-                  const gdouble masked = *mask_data;
-
-                  VALUE (0, data[0]) += masked;
-
-                  data += n_components;
-                  mask_data += 1;
-                }
-              break;
-
-            case 2:
-              while (length--)
-                {
-                  const gdouble masked = *mask_data;
-                  const gdouble weight = data[1];
-
-                  VALUE (0, data[0]) += weight * masked;
-                  VALUE (1, data[1]) += masked;
-
-                  data += n_components;
-                  mask_data += 1;
-                }
-              break;
-
-            case 3: /* calculate separate value values */
-              while (length--)
-                {
-                  const gdouble masked = *mask_data;
-
-                  VALUE (1, data[0]) += masked;
-                  VALUE (2, data[1]) += masked;
-                  VALUE (3, data[2]) += masked;
-
-                  max = MAX (data[0], data[1]);
-                  max = MAX (data[2], max);
-                  VALUE (0, max) += masked;
-
-                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
-                  VALUE (4, luminance) += masked;
-
-                  data += n_components;
-                  mask_data += 1;
-                }
-              break;
+      context.mask = mask;
 
-            case 4: /* calculate separate value values */
-              while (length--)
-                {
-                  const gdouble masked = *mask_data;
-                  const gdouble weight = data[3];
-
-                  VALUE (1, data[0]) += weight * masked;
-                  VALUE (2, data[1]) += weight * masked;
-                  VALUE (3, data[2]) += weight * masked;
-                  VALUE (4, data[3]) += masked;
-
-                  max = MAX (data[0], data[1]);
-                  max = MAX (data[2], max);
-                  VALUE (0, max) += weight * masked;
-
-                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
-                  VALUE (5, luminance) += weight * masked;
-
-                  data += n_components;
-                  mask_data += 1;
-                }
-              break;
-            }
-        }
-      else /* no mask */
-        {
-          switch (n_components)
-            {
-            case 1:
-              while (length--)
-                {
-                  VALUE (0, data[0]) += 1.0;
-
-                  data += n_components;
-                }
-              break;
-
-            case 2:
-              while (length--)
-                {
-                  const gdouble weight = data[1];
+      if (mask_rect)
+        context.mask_rect = *mask_rect;
+      else
+        context.mask_rect = *gegl_buffer_get_extent (mask);
+    }
 
-                  VALUE (0, data[0]) += weight;
-                  VALUE (1, data[1]) += 1.0;
+  gimp_histogram_calculate_internal (NULL, &context);
 
-                  data += n_components;
-                }
-              break;
+  gimp_histogram_set_values (histogram,
+                             context.n_components, context.n_bins,
+                             context.values);
+}
 
-            case 3: /* calculate separate value values */
-              while (length--)
-                {
-                  VALUE (1, data[0]) += 1.0;
-                  VALUE (2, data[1]) += 1.0;
-                  VALUE (3, data[2]) += 1.0;
+GimpAsync *
+gimp_histogram_calculate_async (GimpHistogram       *histogram,
+                                GeglBuffer          *buffer,
+                                const GeglRectangle *buffer_rect,
+                                GeglBuffer          *mask,
+                                const GeglRectangle *mask_rect)
+{
+  CalculateContext *context;
 
-                  max = MAX (data[0], data[1]);
-                  max = MAX (data[2], max);
-                  VALUE (0, max) += 1.0;
+  g_return_val_if_fail (GIMP_IS_HISTOGRAM (histogram), NULL);
+  g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
+  g_return_val_if_fail (buffer_rect != NULL, NULL);
 
-                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
-                  VALUE (4, luminance) += 1.0;
+  if (histogram->priv->calculate_async)
+    {
+      gimp_async_cancel (histogram->priv->calculate_async);
+      gimp_async_wait (histogram->priv->calculate_async);
+    }
 
-                  data += n_components;
-                }
-              break;
+  context = g_slice_new0 (CalculateContext);
 
-            case 4: /* calculate separate value values */
-              while (length--)
-                {
-                  const gdouble weight = data[3];
+  context->histogram   = histogram;
+  context->buffer      = gegl_buffer_new (buffer_rect,
+                                          gegl_buffer_get_format (buffer));
+  context->buffer_rect = *buffer_rect;
 
-                  VALUE (1, data[0]) += weight;
-                  VALUE (2, data[1]) += weight;
-                  VALUE (3, data[2]) += weight;
-                  VALUE (4, data[3]) += 1.0;
+  gegl_buffer_copy (buffer, buffer_rect, GEGL_ABYSS_NONE,
+                    context->buffer, NULL);
 
-                  max = MAX (data[0], data[1]);
-                  max = MAX (data[2], max);
-                  VALUE (0, max) += weight;
+  if (mask)
+    {
+      if (mask_rect)
+        context->mask_rect = *mask_rect;
+      else
+        context->mask_rect = *gegl_buffer_get_extent (mask);
 
-                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
-                  VALUE (5, luminance) += weight;
+      context->mask = gegl_buffer_new (&context->mask_rect,
+                                       gegl_buffer_get_format (mask));
 
-                  data += n_components;
-                }
-              break;
-            }
-        }
+      gegl_buffer_copy (mask, &context->mask_rect, GEGL_ABYSS_NONE,
+                        context->mask, NULL);
     }
 
-  g_object_notify (G_OBJECT (histogram), "values");
+  histogram->priv->calculate_async = gimp_parallel_run_async (
+    (GimpParallelRunAsyncFunc) gimp_histogram_calculate_internal,
+    context);
 
-  g_object_thaw_notify (G_OBJECT (histogram));
+  gimp_async_add_callback (
+    histogram->priv->calculate_async,
+    (GimpAsyncCallback) gimp_histogram_calculate_async_callback,
+    context);
 
-#undef VALUE
+  return histogram->priv->calculate_async;
 }
 
 void
@@ -951,7 +823,7 @@ gimp_histogram_get_std_dev (GimpHistogram        *histogram,
 
 /*  private functions  */
 
-static void
+static gdouble *
 gimp_histogram_alloc_values (GimpHistogram *histogram,
                              gint           n_components,
                              gint           n_bins)
@@ -961,27 +833,393 @@ gimp_histogram_alloc_values (GimpHistogram *histogram,
   if (n_components + 2 != priv->n_channels ||
       n_bins           != priv->n_bins)
     {
-      gimp_histogram_clear_values (histogram);
+      return g_new0 (gdouble, (n_components + 2) * n_bins);
+    }
+  else
+    {
+      memset (priv->values, 0,
+              priv->n_channels * priv->n_bins * sizeof (gdouble));
+
+      return priv->values;
+    }
+}
+
+static void
+gimp_histogram_set_values (GimpHistogram *histogram,
+                           gint           n_components,
+                           gint           n_bins,
+                           gdouble       *values)
+{
+  GimpHistogramPrivate *priv              = histogram->priv;
+  gboolean              notify_n_channels = FALSE;
+  gboolean              notify_n_bins     = FALSE;
+
+  if (n_components + 2 != priv->n_channels)
+    {
+      priv->n_channels = n_components + 2;
+
+      notify_n_channels = TRUE;
+    }
+
+  if (n_bins != priv->n_bins)
+    {
+      priv->n_bins = n_bins;
+
+      notify_n_bins = TRUE;
+    }
+
+  if (values != priv->values)
+    {
+      if (priv->values)
+        g_free (priv->values);
+
+      priv->values = values;
+    }
+
+  if (notify_n_channels)
+    g_object_notify (G_OBJECT (histogram), "n-channels");
+
+  if (notify_n_bins)
+    g_object_notify (G_OBJECT (histogram), "n-bins");
 
-      if (n_components + 2 != priv->n_channels)
+  g_object_notify (G_OBJECT (histogram), "values");
+}
+
+static void
+gimp_histogram_calculate_internal (GimpAsync        *async,
+                                   CalculateContext *context)
+{
+  GimpHistogramPrivate *priv;
+  GeglBufferIterator   *iter;
+  const Babl           *format;
+  gdouble              *values;
+  gint                  n_components;
+  gint                  n_bins;
+  gfloat                n_bins_1f;
+  gfloat                temp;
+
+  priv = context->histogram->priv;
+
+  format = gegl_buffer_get_format (context->buffer);
+
+  if (babl_format_get_type (format, 0) == babl_type ("u8"))
+    n_bins = 256;
+  else
+    n_bins = 1024;
+
+  if (babl_format_is_palette (format))
+    {
+      if (babl_format_has_alpha (format))
+        {
+          if (priv->linear)
+            format = babl_format ("RGB float");
+          else
+            format = babl_format ("R'G'B' float");
+        }
+      else
+        {
+          if (priv->linear)
+            format = babl_format ("RGBA float");
+          else
+            format = babl_format ("R'G'B'A float");
+        }
+    }
+  else
+    {
+      const Babl *model = babl_format_get_model (format);
+
+      if (model == babl_model ("Y") ||
+          model == babl_model ("Y'"))
+        {
+          if (priv->linear)
+            format = babl_format ("Y float");
+          else
+            format = babl_format ("Y' float");
+        }
+      else if (model == babl_model ("YA") ||
+               model == babl_model ("Y'A"))
+        {
+          if (priv->linear)
+            format = babl_format ("YA float");
+          else
+            format = babl_format ("Y'A float");
+        }
+      else if (model == babl_model ("RGB") ||
+               model == babl_model ("R'G'B'"))
+        {
+          if (priv->linear)
+            format = babl_format ("RGB float");
+          else
+            format = babl_format ("R'G'B' float");
+        }
+      else if (model == babl_model ("RGBA") ||
+               model == babl_model ("R'G'B'A"))
         {
-          priv->n_channels = n_components + 2;
+          if (priv->linear)
+            format = babl_format ("RGBA float");
+          else
+            format = babl_format ("R'G'B'A float");
+        }
+      else
+        {
+          if (async)
+            gimp_async_abort (async);
 
-          g_object_notify (G_OBJECT (histogram), "n-channels");
+          g_return_if_reached ();
         }
+    }
+
+  n_components = babl_format_get_n_components (format);
+
+  if (async)
+    {
+      values = g_new0 (gdouble, (n_components + 2) * n_bins);
+    }
+  else
+    {
+      values = gimp_histogram_alloc_values (context->histogram,
+                                            n_components, n_bins);
+    }
 
-      if (n_bins != priv->n_bins)
+  iter = gegl_buffer_iterator_new (context->buffer, &context->buffer_rect, 0,
+                                   format,
+                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+  if (context->mask)
+    gegl_buffer_iterator_add (iter, context->mask, &context->mask_rect, 0,
+                              babl_format ("Y float"),
+                              GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+
+  n_bins_1f = n_bins - 1;
+
+#define VALUE(c,i) (*(temp = (i) * n_bins_1f,                                  \
+                      &values[(c) * n_bins +                                   \
+                              SIGNED_ROUND (SAFE_CLAMP (temp,                  \
+                                                        0.0f,                  \
+                                                        n_bins_1f))]))
+
+#define CHECK_CANCELED(length)                                                 \
+  G_STMT_START                                                                 \
+    {                                                                          \
+      if ((length) % 32 == 0 && async && gimp_async_is_canceled (async))       \
+        {                                                                      \
+          gegl_buffer_iterator_stop (iter);                                    \
+                                                                               \
+          goto end;                                                            \
+        }                                                                      \
+    }                                                                          \
+  G_STMT_END
+
+  while (gegl_buffer_iterator_next (iter))
+    {
+      const gfloat *data   = iter->data[0];
+      gint          length = iter->length;
+      gfloat        max;
+      gfloat        luminance;
+
+      CHECK_CANCELED (0);
+
+      if (context->mask)
         {
-          priv->n_bins = n_bins;
+          const gfloat *mask_data = iter->data[1];
 
-          g_object_notify (G_OBJECT (histogram), "n-bins");
+          switch (n_components)
+            {
+            case 1:
+              while (length--)
+                {
+                  const gdouble masked = *mask_data;
+
+                  VALUE (0, data[0]) += masked;
+
+                  data += n_components;
+                  mask_data += 1;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+
+            case 2:
+              while (length--)
+                {
+                  const gdouble masked = *mask_data;
+                  const gdouble weight = data[1];
+
+                  VALUE (0, data[0]) += weight * masked;
+                  VALUE (1, data[1]) += masked;
+
+                  data += n_components;
+                  mask_data += 1;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+
+            case 3: /* calculate separate value values */
+              while (length--)
+                {
+                  const gdouble masked = *mask_data;
+
+                  VALUE (1, data[0]) += masked;
+                  VALUE (2, data[1]) += masked;
+                  VALUE (3, data[2]) += masked;
+
+                  max = MAX (data[0], data[1]);
+                  max = MAX (data[2], max);
+                  VALUE (0, max) += masked;
+
+                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
+                  VALUE (4, luminance) += masked;
+
+                  data += n_components;
+                  mask_data += 1;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+
+            case 4: /* calculate separate value values */
+              while (length--)
+                {
+                  const gdouble masked = *mask_data;
+                  const gdouble weight = data[3];
+
+                  VALUE (1, data[0]) += weight * masked;
+                  VALUE (2, data[1]) += weight * masked;
+                  VALUE (3, data[2]) += weight * masked;
+                  VALUE (4, data[3]) += masked;
+
+                  max = MAX (data[0], data[1]);
+                  max = MAX (data[2], max);
+                  VALUE (0, max) += weight * masked;
+
+                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
+                  VALUE (5, luminance) += weight * masked;
+
+                  data += n_components;
+                  mask_data += 1;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+            }
         }
+      else /* no mask */
+        {
+          switch (n_components)
+            {
+            case 1:
+              while (length--)
+                {
+                  VALUE (0, data[0]) += 1.0;
 
-      priv->values = g_new0 (gdouble, priv->n_channels * priv->n_bins);
+                  data += n_components;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+
+            case 2:
+              while (length--)
+                {
+                  const gdouble weight = data[1];
+
+                  VALUE (0, data[0]) += weight;
+                  VALUE (1, data[1]) += 1.0;
+
+                  data += n_components;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+
+            case 3: /* calculate separate value values */
+              while (length--)
+                {
+                  VALUE (1, data[0]) += 1.0;
+                  VALUE (2, data[1]) += 1.0;
+                  VALUE (3, data[2]) += 1.0;
+
+                  max = MAX (data[0], data[1]);
+                  max = MAX (data[2], max);
+                  VALUE (0, max) += 1.0;
+
+                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
+                  VALUE (4, luminance) += 1.0;
+
+                  data += n_components;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+
+            case 4: /* calculate separate value values */
+              while (length--)
+                {
+                  const gdouble weight = data[3];
+
+                  VALUE (1, data[0]) += weight;
+                  VALUE (2, data[1]) += weight;
+                  VALUE (3, data[2]) += weight;
+                  VALUE (4, data[3]) += 1.0;
+
+                  max = MAX (data[0], data[1]);
+                  max = MAX (data[2], max);
+                  VALUE (0, max) += weight;
+
+                  luminance = GIMP_RGB_LUMINANCE (data[0], data[1], data[2]);
+                  VALUE (5, luminance) += weight;
+
+                  data += n_components;
+
+                  CHECK_CANCELED (length);
+                }
+              break;
+            }
+        }
+    }
+end:
+
+  context->n_components = n_components;
+  context->n_bins       = n_bins;
+  context->values       = values;
+
+  if (async)
+    {
+      if (! gimp_async_is_canceled (async))
+        {
+          gimp_async_finish (async, NULL);
+        }
+      else
+        {
+          gimp_async_abort (async);
+        }
+    }
+
+#undef VALUE
+#undef CHECK_CANCELED
+}
+
+static void
+gimp_histogram_calculate_async_callback (GimpAsync        *async,
+                                         CalculateContext *context)
+{
+  context->histogram->priv->calculate_async = NULL;
+
+  if (gimp_async_is_finished (async))
+    {
+      gimp_histogram_set_values (context->histogram,
+                                 context->n_components, context->n_bins,
+                                 context->values);
     }
   else
     {
-      memset (priv->values, 0,
-              priv->n_channels * priv->n_bins * sizeof (gdouble));
+      g_free (context->values);
     }
+
+  g_object_unref (context->buffer);
+  if (context->mask)
+    g_object_unref (context->mask);
+
+  g_slice_free (CalculateContext, context);
 }
diff --git a/app/core/gimphistogram.h b/app/core/gimphistogram.h
index c511e69..1c2a810 100644
--- a/app/core/gimphistogram.h
+++ b/app/core/gimphistogram.h
@@ -48,50 +48,55 @@ struct _GimpHistogramClass
 };
 
 
-GType           gimp_histogram_get_type      (void) G_GNUC_CONST;
-
-GimpHistogram * gimp_histogram_new           (gboolean              linear);
-
-GimpHistogram * gimp_histogram_duplicate     (GimpHistogram        *histogram);
-
-void            gimp_histogram_calculate     (GimpHistogram        *histogram,
-                                              GeglBuffer           *buffer,
-                                              const GeglRectangle  *buffer_rect,
-                                              GeglBuffer           *mask,
-                                              const GeglRectangle  *mask_rect);
-
-void            gimp_histogram_clear_values  (GimpHistogram        *histogram);
-
-gdouble         gimp_histogram_get_maximum   (GimpHistogram        *histogram,
-                                              GimpHistogramChannel  channel);
-gdouble         gimp_histogram_get_count     (GimpHistogram        *histogram,
-                                              GimpHistogramChannel  channel,
-                                              gint                  start,
-                                              gint                  end);
-gdouble         gimp_histogram_get_mean      (GimpHistogram        *histogram,
-                                              GimpHistogramChannel  channel,
-                                              gint                  start,
-                                              gint                  end);
-gdouble         gimp_histogram_get_median    (GimpHistogram        *histogram,
-                                              GimpHistogramChannel  channel,
-                                              gint                  start,
-                                              gint                  end);
-gdouble         gimp_histogram_get_std_dev   (GimpHistogram        *histogram,
-                                              GimpHistogramChannel  channel,
-                                              gint                  start,
-                                              gint                  end);
-gdouble         gimp_histogram_get_threshold (GimpHistogram        *histogram,
-                                              GimpHistogramChannel  channel,
-                                              gint                  start,
-                                              gint                  end);
-gdouble         gimp_histogram_get_value     (GimpHistogram        *histogram,
-                                              GimpHistogramChannel  channel,
-                                              gint                  bin);
-gdouble         gimp_histogram_get_component (GimpHistogram        *histogram,
-                                              gint                  component,
-                                              gint                  bin);
-gint            gimp_histogram_n_channels    (GimpHistogram        *histogram);
-gint            gimp_histogram_n_bins        (GimpHistogram        *histogram);
+GType           gimp_histogram_get_type        (void) G_GNUC_CONST;
+
+GimpHistogram * gimp_histogram_new             (gboolean              linear);
+
+GimpHistogram * gimp_histogram_duplicate       (GimpHistogram        *histogram);
+
+void            gimp_histogram_calculate       (GimpHistogram        *histogram,
+                                                GeglBuffer           *buffer,
+                                                const GeglRectangle  *buffer_rect,
+                                                GeglBuffer           *mask,
+                                                const GeglRectangle  *mask_rect);
+GimpAsync     * gimp_histogram_calculate_async (GimpHistogram        *histogram,
+                                                GeglBuffer           *buffer,
+                                                const GeglRectangle  *buffer_rect,
+                                                GeglBuffer           *mask,
+                                                const GeglRectangle  *mask_rect);
+
+void            gimp_histogram_clear_values    (GimpHistogram        *histogram);
+
+gdouble         gimp_histogram_get_maximum     (GimpHistogram        *histogram,
+                                                GimpHistogramChannel  channel);
+gdouble         gimp_histogram_get_count       (GimpHistogram        *histogram,
+                                                GimpHistogramChannel  channel,
+                                                gint                  start,
+                                                gint                  end);
+gdouble         gimp_histogram_get_mean        (GimpHistogram        *histogram,
+                                                GimpHistogramChannel  channel,
+                                                gint                  start,
+                                                gint                  end);
+gdouble         gimp_histogram_get_median      (GimpHistogram        *histogram,
+                                                GimpHistogramChannel  channel,
+                                                gint                  start,
+                                                gint                  end);
+gdouble         gimp_histogram_get_std_dev     (GimpHistogram        *histogram,
+                                                GimpHistogramChannel  channel,
+                                                gint                  start,
+                                                gint                  end);
+gdouble         gimp_histogram_get_threshold   (GimpHistogram        *histogram,
+                                                GimpHistogramChannel  channel,
+                                                gint                  start,
+                                                gint                  end);
+gdouble         gimp_histogram_get_value       (GimpHistogram        *histogram,
+                                                GimpHistogramChannel  channel,
+                                                gint                  bin);
+gdouble         gimp_histogram_get_component   (GimpHistogram        *histogram,
+                                                gint                  component,
+                                                gint                  bin);
+gint            gimp_histogram_n_channels      (GimpHistogram        *histogram);
+gint            gimp_histogram_n_bins          (GimpHistogram        *histogram);
 
 
 #endif /* __GIMP_HISTOGRAM_H__ */


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