]> Pileus Git - ~andy/gtk/commitdiff
Store only one copy of the pixel data for symlinked icons. To achieve
authorMatthias Clasen <mclasen@redhat.com>
Mon, 15 Aug 2005 03:52:34 +0000 (03:52 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Mon, 15 Aug 2005 03:52:34 +0000 (03:52 +0000)
2005-08-14  Matthias Clasen  <mclasen@redhat.com>

* gtk/updateiconcache.c: Store only one copy of the pixel data
for symlinked icons. To achieve this, maintain a hashtable
mapping pathnames to pixel data, and share the pixel data for
all symlinks resolving to the same pathname. When writing out
the image data, write out the pixel data only the first time
it is met, and store the offset pointing to the first copy
for use in all later cases.
This reduces the size of the Bluecurve icon cache from 40
to 13MB. (#312972)

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-8
gtk/updateiconcache.c

index af6d34e246ae849271e56bcb9a68274df5e50632..926eb7137467f5c84e6ab67128037a1f0b9a3432 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2005-08-14  Matthias Clasen  <mclasen@redhat.com>
+
+       * gtk/updateiconcache.c: Store only one copy of the pixel data
+       for symlinked icons. To achieve this, maintain a hashtable 
+       mapping pathnames to pixel data, and share the pixel data for
+       all symlinks resolving to the same pathname. When writing out
+       the image data, write out the pixel data only the first time
+       it is met, and store the offset pointing to the first copy
+       for use in all later cases.
+       This reduces the size of the Bluecurve icon cache from 40
+       to 13MB. (#312972)
+
 2005-08-13  Matthias Clasen  <mclasen@redhat.com>
 
        * configure.in: Bump version
index af6d34e246ae849271e56bcb9a68274df5e50632..926eb7137467f5c84e6ab67128037a1f0b9a3432 100644 (file)
@@ -1,3 +1,15 @@
+2005-08-14  Matthias Clasen  <mclasen@redhat.com>
+
+       * gtk/updateiconcache.c: Store only one copy of the pixel data
+       for symlinked icons. To achieve this, maintain a hashtable 
+       mapping pathnames to pixel data, and share the pixel data for
+       all symlinks resolving to the same pathname. When writing out
+       the image data, write out the pixel data only the first time
+       it is met, and store the offset pointing to the first copy
+       for use in all later cases.
+       This reduces the size of the Bluecurve icon cache from 40
+       to 13MB. (#312972)
+
 2005-08-13  Matthias Clasen  <mclasen@redhat.com>
 
        * configure.in: Bump version
index af6d34e246ae849271e56bcb9a68274df5e50632..926eb7137467f5c84e6ab67128037a1f0b9a3432 100644 (file)
@@ -1,3 +1,15 @@
+2005-08-14  Matthias Clasen  <mclasen@redhat.com>
+
+       * gtk/updateiconcache.c: Store only one copy of the pixel data
+       for symlinked icons. To achieve this, maintain a hashtable 
+       mapping pathnames to pixel data, and share the pixel data for
+       all symlinks resolving to the same pathname. When writing out
+       the image data, write out the pixel data only the first time
+       it is met, and store the offset pointing to the first copy
+       for use in all later cases.
+       This reduces the size of the Bluecurve icon cache from 40
+       to 13MB. (#312972)
+
 2005-08-13  Matthias Clasen  <mclasen@redhat.com>
 
        * configure.in: Bump version
index 17b488d2a0a0b91faf20942e5e8b21c65925873f..f38dde7352dec5a3371ab69be433ee6d653ec08d 100644 (file)
@@ -33,6 +33,7 @@
 #else
 #include <utime.h>
 #endif
+#include <libgen.h>
 
 #include <glib.h>
 #include <glib/gstdio.h>
@@ -87,13 +88,23 @@ is_cache_up_to_date (const gchar *path)
   return cache_stat.st_mtime >= path_stat.st_mtime;
 }
 
+typedef struct 
+{
+  gboolean has_pixdata;
+  GdkPixdata pixdata;
+  guint32 offset;
+  guint pixel_data_size;
+} ImageData;
+
+static GHashTable *image_data_hash = NULL;
+
 typedef struct
 {
   int flags;
   int dir_index;
 
-  gboolean has_pixdata;
-  GdkPixdata pixdata;
+  ImageData *image_data;
+  guint pixel_data_size;
 
   int has_embedded_rect;
   int x0, y0, x1, y1;
@@ -245,20 +256,177 @@ load_icon_data (Image *image, const char *path)
   g_key_file_free (icon_file);
 }
 
+/*
+ * This function was copied from gtkfilesystemunix.c, it should
+ * probably go to GLib
+ */
 static void
-maybe_cache_image_data (Image *image, const gchar *path)
+canonicalize_filename (gchar *filename)
 {
-  if (CAN_CACHE_IMAGE_DATA(image->flags) && !image->has_pixdata) 
+  gchar *p, *q;
+  gboolean last_was_slash = FALSE;
+
+  p = filename;
+  q = filename;
+
+  while (*p)
     {
-      GdkPixbuf *pixbuf;
+      if (*p == G_DIR_SEPARATOR)
+       {
+         if (!last_was_slash)
+           *q++ = G_DIR_SEPARATOR;
+
+         last_was_slash = TRUE;
+       }
+      else
+       {
+         if (last_was_slash && *p == '.')
+           {
+             if (*(p + 1) == G_DIR_SEPARATOR ||
+                 *(p + 1) == '\0')
+               {
+                 if (*(p + 1) == '\0')
+                   break;
+
+                 p += 1;
+               }
+             else if (*(p + 1) == '.' &&
+                      (*(p + 2) == G_DIR_SEPARATOR ||
+                       *(p + 2) == '\0'))
+               {
+                 if (q > filename + 1)
+                   {
+                     q--;
+                     while (q > filename + 1 &&
+                            *(q - 1) != G_DIR_SEPARATOR)
+                       q--;
+                   }
+
+                 if (*(p + 2) == '\0')
+                   break;
+
+                 p += 2;
+               }
+             else
+               {
+                 *q++ = *p;
+                 last_was_slash = FALSE;
+               }
+           }
+         else
+           {
+             *q++ = *p;
+             last_was_slash = FALSE;
+           }
+       }
+
+      p++;
+    }
+
+  if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
+    q--;
+
+  *q = '\0';
+}
+
+static gchar *
+follow_links (const gchar *path)
+{
+  gchar *target;
+  gchar *d, *s;
+  gchar *path2 = NULL;
+
+  path2 = g_strdup (path);
+  while (g_file_test (path2, G_FILE_TEST_IS_SYMLINK))
+    {
+      target = g_file_read_link (path2, NULL);
       
-      pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+      if (target)
+       {
+         if (target[0] == '/')
+           path2 =  target;
+         else
+           {
+             d = dirname (path2);
+             s = g_build_path ("/", d, target, NULL);
+             g_free (target);
+             g_free (path2);
+             path2 = s;
+           }
+       }
+      else
+       break;
+    }
+
+  if (strcmp (path, path2) == 0)
+    {
+      g_free (path2);
+      path2 = NULL;
+    }
+
+  return path2;
+}
+
+static void
+maybe_cache_image_data (Image       *image, 
+                       const gchar *path)
+{
+  if (CAN_CACHE_IMAGE_DATA(image->flags) && !image->image_data) 
+    {
+      GdkPixbuf *pixbuf;
+      ImageData *idata;
+      gchar *path2;
+
+      idata = g_hash_table_lookup (image_data_hash, path);
+
+      path2 = follow_links (path);
+
+      if (path2)
+       {
+         ImageData *idata2;
+
+         canonicalize_filename (path2);
+  
+         idata2 = g_hash_table_lookup (image_data_hash, path2);
+
+         if (idata && idata2 && idata != idata2)
+           g_error ("different idatas found for symlinked '%s' and '%s'\n",
+                    path, path2);
+
+         if (idata && !idata2)
+           g_hash_table_insert (image_data_hash, g_strdup (path2), idata);
+
+         if (!idata && idata2)
+           {
+             g_hash_table_insert (image_data_hash, g_strdup (path), idata2);
+             idata = idata2;
+           }
+       }
       
-      if (pixbuf) 
+      if (!idata)
+       {
+         idata = g_new0 (ImageData, 1);
+         g_hash_table_insert (image_data_hash, g_strdup (path), idata);
+         if (path2)
+           g_hash_table_insert (image_data_hash, g_strdup (path2), idata);  
+       }
+
+      if (!idata->has_pixdata)
        {
-         image->has_pixdata = TRUE;
-         gdk_pixdata_from_pixbuf (&image->pixdata, pixbuf, FALSE);
+         pixbuf = gdk_pixbuf_new_from_file (path, NULL);
+         
+         if (pixbuf) 
+           {
+             gdk_pixdata_from_pixbuf (&idata->pixdata, pixbuf, FALSE);
+             idata->pixel_data_size = idata->pixdata.length + 8;
+             idata->has_pixdata = TRUE;
+           }
        }
+
+      image->image_data = idata;
+
+      if (path2)
+       g_free (path2);
     }
 }
 
@@ -312,7 +480,6 @@ scan_directory (const gchar *base_path,
        }
 
       retval = g_file_test (path, G_FILE_TEST_IS_REGULAR);
-
       if (retval)
        {
          if (g_str_has_suffix (name, ".png"))
@@ -366,7 +533,6 @@ scan_directory (const gchar *base_path,
        }
 
       g_free (path);
-
     }
 
   g_dir_close (dir);
@@ -474,9 +640,8 @@ gboolean
 write_pixdata (FILE *cache, GdkPixdata *pixdata)
 {
   guint8 *s;
-  int len;
-  int i;
-
+  guint len;
+  gint i;
 
   /* Type 0 is GdkPixdata */
   if (!write_card32 (cache, 0))
@@ -537,10 +702,17 @@ get_image_meta_data_size (Image *image)
 guint
 get_image_pixel_data_size (Image *image)
 {
-  if (image->has_pixdata)
-    return image->pixdata.length + 8;
+  if (image->pixel_data_size == 0)
+    {
+      if (image->image_data && 
+         image->image_data->has_pixdata)
+       {
+         image->pixel_data_size = image->image_data->pixel_data_size;
+         image->image_data->pixel_data_size = 0;
+       }
+    }
 
-  return 0;
+  return image->pixel_data_size;
 }
 
 guint
@@ -553,7 +725,7 @@ get_image_data_size (Image *image)
   len += get_image_pixel_data_size (image);
   len += get_image_meta_data_size (image);
   
-  if (len > 0)
+  if (len > 0 || (image->image_data && image->image_data->has_pixdata))
     len += 8;
 
   return len;
@@ -579,7 +751,7 @@ get_single_node_size (HashNode *node, gboolean include_image_data)
     for (list = node->image_list; list; list = list->next)
       {
        Image *image = list->data;
-       
+
        len += get_image_data_size (image);
       }
   
@@ -590,7 +762,6 @@ guint
 get_bucket_size (HashNode *node)
 {
   int len = 0;
-
   while (node)
     {
       len += get_single_node_size (node, TRUE);
@@ -652,7 +823,7 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
        {
          Image *image = list->data;
          int image_data_size = get_image_data_size (image);
-         
+
          /* Directory index */
          if (!write_card16 (cache, image->dir_index))
            return FALSE;
@@ -668,7 +839,7 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
                return FALSE;
              data_offset += image_data_size;
            }
-         else
+         else 
            {
              if (!write_card32 (cache, 0))
                return FALSE;
@@ -685,7 +856,7 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
          int pixel_data_size = get_image_pixel_data_size (image);
          int meta_data_size = get_image_meta_data_size (image);
 
-         if (meta_data_size + pixel_data_size == 0)
+         if (get_image_data_size (image) == 0)
            continue;
 
          /* Pixel data */
@@ -693,10 +864,12 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
            {
              if (!write_card32 (cache, image_data_offset + 8))
                return FALSE;
+
+             image->image_data->offset = image_data_offset + 8;
            }
          else
            {
-             if (!write_card32 (cache, 0))
+             if (!write_card32 (cache, image->image_data->offset))
                return FALSE;
            }
 
@@ -713,7 +886,7 @@ write_bucket (FILE *cache, HashNode *node, int *offset)
 
          if (pixel_data_size > 0)
            {
-             if (!write_pixdata (cache, &image->pixdata))
+             if (!write_pixdata (cache, &image->image_data->pixdata))
                return FALSE;
            }
          
@@ -961,6 +1134,7 @@ build_cache (const gchar *path)
     }
 
   files = g_hash_table_new (g_str_hash, g_str_equal);
+  image_data_hash = g_hash_table_new (g_str_hash, g_str_equal);
   
   directories = scan_directory (path, NULL, files, NULL, 0);
 
@@ -1038,6 +1212,6 @@ main (int argc, char **argv)
 
   g_type_init ();
   build_cache (path);
-  
+
   return 0;
 }