]> git.0d.be Git - empathy.git/commitdiff
Make sure to not infinite loop when scaling avatar.
authorXavier Claessens <xclaesse@gmail.com>
Thu, 20 May 2010 14:12:57 +0000 (16:12 +0200)
committerXavier Claessens <xclaesse@gmail.com>
Wed, 26 May 2010 09:54:01 +0000 (11:54 +0200)
1) Add a limit of 10 retries, to be sure to never do more in the worst case.
2) Only keep converted data that respect the requirements, make sure to not
accept bigger data than maximum_bytes, even if it is close to the limit.
3) Stop the loop if the new factor does not change the image resolution. That
means we already found the optimal size.

Fixes bug #619701

libempathy-gtk/empathy-avatar-chooser.c

index e9d8485a39f2a0f2241f89ac0820303c81f6d73a..6e6c2831049d3fc751aade43a097a93e403b7ba8 100644 (file)
@@ -411,8 +411,9 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser,
        gchar                    *new_mime_type = NULL;
        gdouble                   min_factor, max_factor;
        gdouble                   factor;
-       gchar                    *converted_image_data = NULL;
-       gsize                     converted_image_size = 0;
+       gchar                    *best_image_data = NULL;
+       gsize                     best_image_size = 0;
+       guint                     count = 0;
 
        req = tp_connection_get_avatar_requirements (priv->connection);
        if (req == NULL) {
@@ -484,10 +485,10 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser,
                GdkPixbuf *pixbuf_scaled = NULL;
                gboolean   saved;
                gint       new_width, new_height;
+               gchar     *converted_image_data;
+               gsize      converted_image_size;
                GError    *error = NULL;
 
-               g_free (converted_image_data);
-
                if (factor != 1) {
                        new_width = width * factor;
                        new_height = height * factor;
@@ -524,8 +525,23 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser,
                DEBUG ("Produced an image data of %"G_GSIZE_FORMAT" bytes.",
                        converted_image_size);
 
-               if (req->maximum_bytes == 0)
-                       break;
+               /* If the new image satisfy the req, keep it as current best */
+               if (req->maximum_bytes == 0 ||
+                   converted_image_size <= req->maximum_bytes) {
+                       if (best_image_data)
+                               g_free (best_image_data);
+
+                       best_image_data = converted_image_data;
+                       best_image_size = converted_image_size;
+
+                       /* If this image is close enough to the optimal size,
+                        * stop searching */
+                       if (req->maximum_bytes == 0 ||
+                           req->maximum_bytes - converted_image_size <= 1024)
+                               break;
+               } else {
+                       g_free (converted_image_data);
+               }
 
                /* Make a binary search for the bigest factor that produce
                 * an image data size less than max_size */
@@ -535,20 +551,23 @@ avatar_chooser_maybe_convert_and_scale (EmpathyAvatarChooser *chooser,
                        min_factor = factor;
                factor = (min_factor + max_factor)/2;
 
-               /* We are done if either:
-                * - min_factor == max_factor. That happens if we resized to
-                *   the max required dimension and the produced data size is
-                *   less than max_size.
-                * - The data size is close enough to max_size. Here we accept
-                *   a difference of 1k.
-                */
-       } while (min_factor != max_factor &&
-                abs (req->maximum_bytes - converted_image_size) > 1024);
+               if ((int) (width * factor) == new_width ||
+                   (int) (height * factor) == new_height) {
+                       /* min_factor and max_factor are too close, so the new
+                        * factor will produce the same image as previous
+                        * iteration. No need to continue, we already found
+                        * the optimal size. */
+                       break;
+               }
+
+               /* Do 10 iterations in the worst case */
+       } while (++count < 10);
+
        g_free (new_format_name);
 
-       /* Takes ownership of new_mime_type and converted_image_data */
-       avatar = empathy_avatar_new ((guchar *) converted_image_data,
-               converted_image_size, new_mime_type, NULL, NULL);
+       /* Takes ownership of new_mime_type and best_image_data */
+       avatar = empathy_avatar_new ((guchar *) best_image_data,
+               best_image_size, new_mime_type, NULL, NULL);
 
        return avatar;
 }