[empathy] Make sure to not infinite loop when scaling avatar.



commit 4ba1a8de87f108ad073e388711c4d6b05009851e
Author: Xavier Claessens <xclaesse gmail com>
Date:   Thu May 20 16:12:57 2010 +0200

    Make sure to not infinite loop when scaling avatar.
    
    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 |   55 +++++++++++++++++++++----------
 1 files changed, 37 insertions(+), 18 deletions(-)
---
diff --git a/libempathy-gtk/empathy-avatar-chooser.c b/libempathy-gtk/empathy-avatar-chooser.c
index e9d8485..6e6c283 100644
--- a/libempathy-gtk/empathy-avatar-chooser.c
+++ b/libempathy-gtk/empathy-avatar-chooser.c
@@ -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;
 }



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