[clutter/wip/actor-content: 7/22] image: Implement asynchronous loading



commit 5110f108209af715d1ae8e69fcfbb452694ccc99
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Tue Dec 7 14:41:09 2010 +0000

    image: Implement asynchronous loading
    
    We use a GIO-style API to fit in with the rest of the platform.

 clutter/clutter-image.c           |  204 +++++++++++++++++++++++++++++++++---
 tests/conform/test-conform-main.c |    1 +
 tests/conform/test-image.c        |   54 ++++++++++-
 3 files changed, 241 insertions(+), 18 deletions(-)
---
diff --git a/clutter/clutter-image.c b/clutter/clutter-image.c
index 7ca97ed..ed6ab66 100644
--- a/clutter/clutter-image.c
+++ b/clutter/clutter-image.c
@@ -13,8 +13,6 @@
 
 struct _ClutterImagePrivate
 {
-  ClutterImageLoader *loader;
-
   gint image_width;
   gint image_height;
 
@@ -226,6 +224,7 @@ clutter_image_load (ClutterImage  *image,
                     gint          *height,
                     GError       **error)
 {
+  ClutterImageLoader *loader;
   ClutterImagePrivate *priv;
   GFileInputStream *stream;
   CoglHandle texture;
@@ -238,21 +237,15 @@ clutter_image_load (ClutterImage  *image,
 
   priv = image->priv;
 
-  if (priv->loader == NULL)
-    {
-      priv->loader = _clutter_image_loader_new ();
-      if (priv->loader == NULL)
-        return FALSE;
-
-      CLUTTER_NOTE (MISC, "Image loader type: %s",
-                    G_OBJECT_TYPE_NAME (priv->loader));
-    }
+  loader = _clutter_image_loader_new ();
+  if (loader == NULL)
+    return FALSE;
 
   stream = g_file_read (gfile, cancellable, error);
   if (stream == NULL)
     return FALSE;
 
-  res = _clutter_image_loader_load_stream (priv->loader,
+  res = _clutter_image_loader_load_stream (loader,
                                            G_INPUT_STREAM (stream),
                                            cancellable,
                                            error);
@@ -262,11 +255,11 @@ clutter_image_load (ClutterImage  *image,
       return FALSE;
     }
 
-  _clutter_image_loader_get_image_size (priv->loader,
+  _clutter_image_loader_get_image_size (loader,
                                         &priv->image_width,
                                         &priv->image_height);
 
-  texture = _clutter_image_loader_get_texture_handle (priv->loader);
+  texture = _clutter_image_loader_get_texture_handle (loader);
   if (texture == COGL_INVALID_HANDLE)
     {
       g_object_unref (stream);
@@ -285,14 +278,125 @@ clutter_image_load (ClutterImage  *image,
   if (height)
     *height = priv->image_height;
 
-  g_object_unref (priv->loader);
-  priv->loader = NULL;
-
+  g_object_unref (loader);
   g_object_unref (stream);
 
   return TRUE;
 }
 
+typedef struct {
+  ClutterImageLoader *loader;
+  ClutterImage *image;
+  GAsyncReadyCallback callback;
+  gpointer user_data;
+  GInputStream *stream;
+  GError *error;
+  GCancellable *cancellable;
+} AsyncReadClosure;
+
+static void
+async_read_closure_free (gpointer data)
+{
+  if (data != NULL)
+    {
+      AsyncReadClosure *closure = data;
+
+      if (closure->loader != NULL)
+        g_object_unref (closure->loader);
+
+      if (closure->image != NULL)
+        g_object_unref (closure->image);
+
+      if (closure->stream != NULL)
+        g_object_unref (closure->stream);
+
+      if (closure->cancellable != NULL)
+        g_object_unref (closure->cancellable);
+
+      if (closure->error != NULL)
+        g_error_free (closure->error);
+
+      g_free (data);
+    }
+}
+
+static void
+async_load_complete (GObject      *gobject,
+                     GAsyncResult *result,
+                     gpointer      user_data)
+{
+  AsyncReadClosure *closure = user_data;
+  GSimpleAsyncResult *res;
+  GError *error = NULL;
+
+  CLUTTER_NOTE (MISC, "Async loading finished");
+  _clutter_image_loader_load_stream_finish (closure->loader,
+                                            result,
+                                            &error);
+  if (error)
+    closure->error = error;
+
+  res = g_simple_async_result_new (G_OBJECT (closure->image),
+                                   closure->callback,
+                                   closure->user_data,
+                                   clutter_image_load_async);
+
+  g_simple_async_result_set_op_res_gpointer (res,
+                                             closure,
+                                             async_read_closure_free);
+
+  g_simple_async_result_complete (res);
+  g_object_unref (res);
+}
+
+static void
+async_read_complete (GObject      *gobject,
+                     GAsyncResult *result,
+                     gpointer      user_data)
+{
+  AsyncReadClosure *closure = user_data;
+  GFileInputStream *stream;
+  GError *error = NULL;
+
+  stream = g_file_read_finish (G_FILE (gobject), result, &error);
+  if (stream == NULL)
+    {
+      GSimpleAsyncResult *res =
+        g_simple_async_result_new (G_OBJECT (closure->image),
+                                   closure->callback,
+                                   closure->user_data,
+                                   clutter_image_load_async);
+
+      if (error)
+        closure->error = error;
+
+      g_simple_async_result_set_op_res_gpointer (res,
+                                                 closure,
+                                                 async_read_closure_free);
+      g_simple_async_result_complete (res);
+      g_object_unref (res);
+      return;
+    }
+
+  if (g_cancellable_is_cancelled (closure->cancellable))
+    {
+      CLUTTER_NOTE (MISC, "Async image loading cancelled");
+      async_read_closure_free (closure);
+      return;
+    }
+
+  closure->stream = G_INPUT_STREAM (stream);
+  g_object_ref (closure->stream);
+
+  CLUTTER_NOTE (MISC, "Loading stream with '%s'",
+                G_OBJECT_TYPE_NAME (closure->loader));
+  _clutter_image_loader_load_stream_async (closure->loader,
+                                           closure->stream,
+                                           closure->cancellable,
+                                           async_load_complete,
+                                           closure);
+}
+
 void
 clutter_image_load_async (ClutterImage        *image,
                           GFile               *gfile,
@@ -300,10 +404,30 @@ clutter_image_load_async (ClutterImage        *image,
                           GAsyncReadyCallback  callback,
                           gpointer             user_data)
 {
+  AsyncReadClosure *closure;
+  ClutterImageLoader *loader;
+
   g_return_if_fail (CLUTTER_IS_IMAGE (image));
   g_return_if_fail (G_IS_FILE (gfile));
   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
   g_return_if_fail (callback != NULL);
+
+  loader = _clutter_image_loader_new ();
+  if (loader == NULL)
+    return;
+
+  closure = g_new0 (AsyncReadClosure, 1);
+  closure->loader = loader;
+  closure->image = g_object_ref (image);
+  closure->cancellable = (cancellable != NULL)
+                       ? g_object_ref (cancellable)
+                       : NULL;
+  closure->callback = callback;
+  closure->user_data = user_data;
+
+  g_file_read_async (gfile, G_PRIORITY_DEFAULT, cancellable,
+                     async_read_complete,
+                     closure);
 }
 
 gboolean
@@ -313,9 +437,55 @@ clutter_image_load_finish (ClutterImage  *image,
                            gint          *height,
                            GError       **error)
 {
+  AsyncReadClosure *closure;
+  GSimpleAsyncResult *simple;
+  ClutterImagePrivate *priv;
+  CoglHandle texture;
+
   g_return_val_if_fail (CLUTTER_IS_IMAGE (image), FALSE);
   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
 
+  simple = G_SIMPLE_ASYNC_RESULT (res);
+
+  if (g_simple_async_result_propagate_error (simple, error))
+    return FALSE;
+
+  g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == clutter_image_load_async);
+
+  closure = g_simple_async_result_get_op_res_gpointer (simple);
+  if (closure->error != NULL)
+    {
+      if (width)
+        *width = 0;
+
+      if (height)
+        *height = 0;
+
+      g_propagate_error (error, closure->error);
+      closure->error = NULL;
+
+      return FALSE;
+    }
+
+  priv = image->priv;
+
+  _clutter_image_loader_get_image_size (closure->loader,
+                                        &priv->image_width,
+                                        &priv->image_height);
+
+  texture = _clutter_image_loader_get_texture_handle (closure->loader);
+  cogl_material_set_layer (priv->material, 0, texture);
+
+  g_signal_emit (image, image_signals[SIZE_CHANGED], 0,
+                 priv->image_width,
+                 priv->image_height);
+
+  if (width)
+    *width = priv->image_width;
+
+  if (height)
+    *height = priv->image_height;
+
   return TRUE;
 }
 
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index ba44c3d..a0314cf 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -210,6 +210,7 @@ main (int argc, char **argv)
   TEST_CONFORM_SIMPLE ("/behaviours", test_behaviours);
 
   TEST_CONFORM_SIMPLE ("/image", image_sync_loading);
+  TEST_CONFORM_SIMPLE ("/image", image_async_loading);
 
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_object);
   TEST_CONFORM_SIMPLE ("/cogl", test_cogl_fixed);
diff --git a/tests/conform/test-image.c b/tests/conform/test-image.c
index efccd24..5a89b6c 100644
--- a/tests/conform/test-image.c
+++ b/tests/conform/test-image.c
@@ -27,8 +27,60 @@ image_sync_loading (void)
 
   g_assert (error == NULL);
   g_assert (res);
-  g_assert (width > 0 && height > 0);
+  g_assert_cmpint (width, >, 0);
+  g_assert_cmpint (height, >, 0);
 
   g_object_unref (gfile);
   g_object_unref (image);
 }
+
+static void
+async_load_done_cb (GObject      *gobject,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+  GMainLoop *main_loop = user_data;
+  GError *error = NULL;
+  gint width, height;
+  gboolean res;
+
+  width = height = 0;
+  res = clutter_image_load_finish (CLUTTER_IMAGE (gobject), result,
+                                   &width,
+                                   &height,
+                                   &error);
+
+  if (g_test_verbose () && error != NULL)
+    g_print ("Unexpected error: %s\n", error->message);
+
+  g_assert (res);
+  g_assert (error == NULL);
+  g_assert_cmpint (width, >, 0);
+  g_assert_cmpint (height, >, 0);
+
+  g_main_loop_quit (main_loop);
+}
+
+void
+image_async_loading (void)
+{
+  ClutterImage *image = clutter_image_new ();
+  GMainLoop *main_loop;
+  GFile *gfile;
+
+  g_assert (CLUTTER_IS_IMAGE (image));
+
+  gfile = g_file_new_for_path (TESTS_DATADIR "/redhand.png");
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+
+  clutter_image_load_async (image, gfile, NULL,
+                            async_load_done_cb,
+                            main_loop);
+
+  g_main_loop_run (main_loop);
+
+  g_main_loop_unref (main_loop);
+  g_object_unref (gfile);
+  g_object_unref (image);
+}



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