[pango/wip-bitmatrix: 3/3] Save coverage to a file




commit eacf85d326d85192720fd7668f030abc108e7489
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Aug 23 00:22:06 2020 -0400

    Save coverage to a file
    
    Save coverage order in $XDG_CONFIG_HOME/pango/coverage.order.
    
    We compare the hashes of all fonts to identify when the
    coverage order needs to be recomputed.
    
    Rough numbers show that loading the coverage from a file
    takes < 10ms, while computing it from scratch takes >400ms.
    So this is clearly a win.

 pango/pangofc-coverageorder-private.h |   7 ++
 pango/pangofc-coverageorder.c         | 188 +++++++++++++++++++++++++++++++++-
 pango/pangofc-fontmap.c               |  27 ++++-
 3 files changed, 218 insertions(+), 4 deletions(-)
---
diff --git a/pango/pangofc-coverageorder-private.h b/pango/pangofc-coverageorder-private.h
index 6537ed06..85a06224 100644
--- a/pango/pangofc-coverageorder-private.h
+++ b/pango/pangofc-coverageorder-private.h
@@ -34,6 +34,13 @@ void            coverage_order_free      (CoverageOrder *co);
 gboolean        coverage_order_is_subset (CoverageOrder *co,
                                           FcPattern     *p1,
                                           FcPattern     *p2);
+gboolean        coverage_order_save      (CoverageOrder *co,
+                                          FcFontSet     *fonts,
+                                          const char    *filename,
+                                          GError       **error);
+CoverageOrder * coverage_order_load      (FcFontSet     *fonts,
+                                          const char    *filename,
+                                          GError       **error);
 
 G_END_DECLS
 
diff --git a/pango/pangofc-coverageorder.c b/pango/pangofc-coverageorder.c
index 86114b38..15c4697e 100644
--- a/pango/pangofc-coverageorder.c
+++ b/pango/pangofc-coverageorder.c
@@ -23,6 +23,7 @@
 
 #include "pangofc-coverageorder-private.h"
 #include <glib.h>
+#include <gio/gio.h>
 
 /* BitMatrix is a simple matrix of bits that can be
  * addressed by their row and column.
@@ -43,14 +44,39 @@ bit_matrix_free (BitMatrix *b)
   g_free (b);
 }
 
+static int
+bit_matrix_get_length (BitMatrix *b)
+{
+  return (b->rows * b->cols) / 8 + 1;
+}
+
+static void
+bit_matrix_get_size (BitMatrix *b,
+                     int       *rows,
+                     int       *cols)
+{
+  *rows = b->rows;
+  *cols = b->cols;
+}
+
+static char *
+bit_matrix_get_bits (BitMatrix *b)
+{
+  return b->bits;
+}
+
 static BitMatrix *
-bit_matrix_new (int rows, int cols)
+bit_matrix_new (int rows, int cols, char *bits)
 {
   BitMatrix *b = g_new (BitMatrix, 1);
+  int len;
 
   b->rows = rows;
   b->cols = cols;
-  b->bits = g_new0 (char, (rows * cols) / 8 + 1);
+  len = (rows * cols) / 8 + 1;
+  b->bits = g_new (char, len);
+  if (bits)
+    memcpy (b->bits, bits, len);
 
   return b;
 }
@@ -190,7 +216,7 @@ coverage_order_new (FcFontSet *fonts)
   /* Now compute the full incidence matrix for the
    * remaining charsets.
    */
-  co->order = bit_matrix_new (coverages->len, coverages->len);
+  co->order = bit_matrix_new (coverages->len, coverages->len, NULL);
 
   for (i = 0; i < coverages->len; i++)
     {
@@ -237,3 +263,159 @@ coverage_order_new (FcFontSet *fonts)
 
   return co;
 }
+
+gboolean
+coverage_order_save (CoverageOrder  *co,
+                     FcFontSet      *fonts,
+                     const char     *filename,
+                     GError        **error)
+{
+  char *prefix;
+  gsize prefix_len;
+  gsize idx_len;
+  gsize len;
+  char *contents;
+  gboolean retval;
+  guint32 *idx;
+  int i;
+  int rows, cols;
+
+  bit_matrix_get_size (co->order, &rows, &cols);
+
+  prefix = g_strdup_printf ("%d %d\n", rows, fonts->nfont);
+  prefix_len = strlen (prefix);
+
+  idx_len = sizeof (guint32) * fonts->nfont * 2;
+  idx = g_new (guint32, idx_len);
+  for (i = 0; i < fonts->nfont; i++)
+    {
+      FcPattern *p = fonts->fonts[i];
+      idx[2*i] = FcPatternHash (p);
+      idx[2*i+1] = GPOINTER_TO_UINT (g_hash_table_lookup (co->idx, p)) - 1;
+    }
+
+  len = prefix_len + idx_len + bit_matrix_get_length (co->order);
+  contents = malloc (len);
+
+  memcpy (contents, prefix, prefix_len);
+  memcpy (contents + prefix_len, idx, idx_len);
+  memcpy (contents + prefix_len + idx_len, bit_matrix_get_bits (co->order), bit_matrix_get_length 
(co->order));
+
+  retval = g_file_set_contents (filename, contents, len, error);
+
+  g_free (contents);
+  g_free (prefix);
+  g_free (idx);
+
+  g_debug ("Wrote %ld bytes to %s.", len, filename);
+  if (g_getenv ("EXIT")) exit (0);
+
+  return retval;
+}
+
+CoverageOrder *
+coverage_order_load (FcFontSet   *fonts,
+                     const char  *filename,
+                     GError     **error)
+{
+  CoverageOrder *co = NULL;
+  GMappedFile *file;
+  char *contents;
+  char *prefix;
+  char **parts;
+  int size;
+  int nfont;
+  int prefix_len;
+  int idx_len;
+  guint32 *idx;
+  GHashTable *table;
+  int i;
+
+  file = g_mapped_file_new (filename, FALSE, error);
+  if (!file)
+    return NULL;
+
+  contents = g_mapped_file_get_contents (file);
+
+  prefix = NULL;
+  for (i = 0; i < 100; i++)
+    {
+      if (contents[i] == '\n')
+        prefix = g_strndup (contents, i);
+    }
+
+  if (prefix == NULL)
+    {
+      g_set_error (error,
+                   G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "%s: Didn't find prefix", filename);
+      goto out;
+    }
+
+  parts = g_strsplit (prefix, " ", -1);
+  if (g_strv_length (parts) != 2)
+    {
+      g_set_error (error,
+                   G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "%s: Prefix looks bad", filename);
+      g_free (prefix);
+      g_strfreev (parts);
+      goto out;
+    }
+
+  prefix_len = strlen (prefix) + 1;
+
+  size = (int) g_ascii_strtoll (parts[0], NULL, 10);
+  nfont = (int) g_ascii_strtoll (parts[1], NULL, 10);
+
+  g_strfreev (parts);
+  g_free (prefix);
+
+  if (size <= 0 || nfont <= size)
+    {
+      g_set_error (error,
+                   G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "%s: Numbers don't add up", filename);
+      goto out;
+    }
+
+  if (nfont != fonts->nfont)
+    {
+      g_set_error (error,
+                   G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "%s: Wrong number of fonts", filename);
+      goto out;
+    }
+
+  table = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  idx_len = sizeof (guint32) * nfont * 2;
+  idx = (guint32 *)(contents + prefix_len);
+
+  for (i = 0; i < fonts->nfont; i++)
+    {
+      FcPattern *p = fonts->fonts[i];
+      guint32 hash = idx[2*i];
+      guint32 index = idx[2*i+1];
+
+      if (hash != FcPatternHash (p))
+        {
+          g_set_error (error,
+                       G_IO_ERROR, G_IO_ERROR_FAILED,
+                       "%s: Fonts changed", filename);
+          g_hash_table_unref (table);
+          goto out;
+        }
+
+      g_hash_table_insert (table, p, GUINT_TO_POINTER (index + 1));
+    }
+
+  co = g_new (CoverageOrder, 1);
+  co->idx = table;
+  co->order = bit_matrix_new (size, size, contents + prefix_len + idx_len);
+
+out:
+  g_mapped_file_unref (file);
+
+  return co;
+}
diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
index 46cedd8d..2a9c8732 100644
--- a/pango/pangofc-fontmap.c
+++ b/pango/pangofc-fontmap.c
@@ -2404,8 +2404,33 @@ compute_coverage_order_in_thread (GTask        *task,
   FcFontSet *fonts = task_data;
   CoverageOrder *coverage_order;
   gint64 before = PANGO_TRACE_CURRENT_TIME;
+  char *parentdir;
+  char *filename;
+  GError *error = NULL;
+
+  parentdir = g_build_filename (g_get_user_cache_dir (), "pango", NULL);
+  filename = g_build_filename (parentdir, "coverage.order", NULL);
+
+  coverage_order = coverage_order_load (fonts, filename, &error);
+
+  if (!coverage_order)
+    {
+      if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+        g_warning ("Failed to load coverage order: %s", error->message);
+      g_clear_error (&error);
+
+      coverage_order = coverage_order_new (fonts);
+
+      if (g_mkdir_with_parents (parentdir, 0700) != 0 ||
+          !coverage_order_save (coverage_order, fonts, filename, &error))
+        {
+          g_warning ("Failed to save coverage order: %s", error->message);
+          g_error_free (error);
+        }
+    }
 
-  coverage_order = coverage_order_new (fonts);
+  g_free (filename);
+  g_free (parentdir);
 
   pango_trace_mark (before, "compute_coverage_order", NULL);
 


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