From 3eb35308fe591be425e291ace900c969a879abf0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 23 Aug 2020 00:22:06 -0400 Subject: 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 | 190 +++++++++++++++++++++++++++++++++- pango/pangofc-fontmap.c | 27 ++++- 3 files changed, 220 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..9ada6976 100644 --- a/pango/pangofc-coverageorder.c +++ b/pango/pangofc-coverageorder.c @@ -23,6 +23,7 @@ #include "pangofc-coverageorder-private.h" #include +#include /* BitMatrix is a simple matrix of bits that can be * addressed by their row and column. @@ -43,14 +44,41 @@ 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); + else + memset (b->bits, 0, len); return b; } @@ -190,7 +218,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 +265,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 68a642cd..f1eae391 100644 --- a/pango/pangofc-fontmap.c +++ b/pango/pangofc-fontmap.c @@ -2431,8 +2431,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 (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) + g_debug ("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_debug ("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); -- cgit v1.2.1