[Fontconfig] fontconfig: Branch 'fc-2_4-keithp' - 2 commits

Keith Packard keithp at kemper.freedesktop.org
Fri Sep 1 01:16:50 PDT 2006


 fc-arch/fcarch.tmpl.h       |    7 
 fc-cache/fc-cache.c         |  109 +++-----
 fc-cat/fc-cat.c             |   83 +-----
 fc-glyphname/fc-glyphname.c |   13 -
 src/fccache.c               |  300 +++++++++---------------
 src/fccfg.c                 |  173 +++++++------
 src/fccharset.c             |  550 ++++++++++++++++++++++----------------------
 src/fcdir.c                 |  177 ++++++--------
 src/fcinit.c                |    1 
 src/fcint.h                 |   60 ++--
 src/fcpat.c                 |    8 
 src/fcserialize.c           |    3 
 12 files changed, 707 insertions(+), 777 deletions(-)

New commits:
diff-tree bc5e487f2a1ad9946aa5c6e19cd75794fc38d530 (from aec8c90b450c115718fd87bc270e35ee6b605967)
Author: Keith Packard <keithp at neko.keithp.com>
Date:   Fri Sep 1 01:15:14 2006 -0700

    Pass directory information around in FcCache structure. Freeze charsets.
    
    Instead of passing directory information around in separate variables,
    collect it all in an FcCache structure. Numerous internal and tool
    interfaces changed as a result of this.
    
    Charsets are now pre-frozen before being serialized. This causes them to
    share across multiple fonts in the same cache.

diff --git a/fc-cache/fc-cache.c b/fc-cache/fc-cache.c
index 5fc4092..6957a65 100644
--- a/fc-cache/fc-cache.c
+++ b/fc-cache/fc-cache.c
@@ -128,15 +128,17 @@ nsubdirs (FcStrSet *set)
 }
 
 static int
-scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool really_force, FcBool verbose)
+scanDirs (FcStrList *list, FcConfig *config, FcBool force, FcBool really_force, FcBool verbose)
 {
     int		ret = 0;
     const FcChar8 *dir;
     FcFontSet	*set;
     FcStrSet	*subdirs;
     FcStrList	*sublist;
+    FcCache	*cache;
     struct stat	statb;
     FcBool	was_valid;
+    int		i;
     
     /*
      * Now scan all of the directories into separate databases
@@ -146,7 +148,7 @@ scanDirs (FcStrList *list, FcConfig *con
     {
 	if (verbose)
 	{
-	    printf ("%s: \"%s\": ", program, dir);
+	    printf ("%s: ", dir);
 	    fflush (stdout);
 	}
 	
@@ -164,22 +166,6 @@ scanDirs (FcStrList *list, FcConfig *con
 	    continue;
 	}
 
-	set = FcFontSetCreate ();
-	if (!set)
-	{
-	    fprintf (stderr, "%s: Can't create font set\n", dir);
-	    ret++;
-	    continue;
-	}
-	subdirs = FcStrSetCreate ();
-	if (!subdirs)
-	{
-	    fprintf (stderr, "%s: Can't create directory set\n", dir);
-	    ret++;
-	    FcFontSetDestroy (set);
-	    continue;
-	}
-	
 	if (access ((char *) dir, W_OK) < 0)
 	{
 	    switch (errno) {
@@ -187,8 +173,6 @@ scanDirs (FcStrList *list, FcConfig *con
 	    case ENOTDIR:
 		if (verbose)
 		    printf ("skipping, no such directory\n");
-		FcFontSetDestroy (set);
-		FcStrSetDestroy (subdirs);
 		continue;
 	    case EACCES:
 	    case EROFS:
@@ -201,8 +185,6 @@ scanDirs (FcStrList *list, FcConfig *con
 		perror ("");
 		ret++;
 
-		FcFontSetDestroy (set);
-		FcStrSetDestroy (subdirs);
 		continue;
 	    }
 	}
@@ -210,44 +192,50 @@ scanDirs (FcStrList *list, FcConfig *con
 	{
 	    fprintf (stderr, "\"%s\": ", dir);
 	    perror ("");
-	    FcFontSetDestroy (set);
-	    FcStrSetDestroy (subdirs);
 	    ret++;
 	    continue;
 	}
 	if (!S_ISDIR (statb.st_mode))
 	{
 	    fprintf (stderr, "\"%s\": not a directory, skipping\n", dir);
-	    FcFontSetDestroy (set);
-	    FcStrSetDestroy (subdirs);
 	    continue;
 	}
 
 	if (really_force)
 	    FcDirCacheUnlink (dir, config);
 
-	if (!force)
-	    was_valid = FcDirCacheValid (dir);
+	cache = NULL;
+	was_valid = FcFalse;
+	if (!force) {
+	    cache = FcDirCacheLoad (dir, config, NULL);
+	    if (cache)
+		was_valid = FcTrue;
+	}
 	
-	if (!FcDirScanConfig (set, subdirs, FcConfigGetBlanks (config), dir, force, config))
+	if (!cache)
 	{
-	    fprintf (stderr, "%s: error scanning\n", dir);
-	    FcFontSetDestroy (set);
-	    FcStrSetDestroy (subdirs);
-	    ret++;
-	    continue;
+	    cache = FcDirCacheRead (dir, FcTrue, config);
+	    if (!cache)
+	    {
+		fprintf (stderr, "%s: error scanning\n", dir);
+		ret++;
+		continue;
+	    }
 	}
-	if (!force && was_valid)
+
+	set = FcCacheSet (cache);
+
+	if (was_valid)
 	{
 	    if (verbose)
 		printf ("skipping, %d fonts, %d dirs\n",
-			set->nfont, nsubdirs(subdirs));
+			set->nfont, cache->dirs_count);
 	}
 	else
 	{
 	    if (verbose)
 		printf ("caching, %d fonts, %d dirs\n", 
-			set->nfont, nsubdirs (subdirs));
+			set->nfont, cache->dirs_count);
 
 	    if (!FcDirCacheValid (dir))
 	    {
@@ -256,43 +244,36 @@ scanDirs (FcStrList *list, FcConfig *con
 		ret++;
 	    }
 	}
-	FcFontSetDestroy (set);
+	
+	subdirs = FcStrSetCreate ();
+	if (!subdirs)
+	{
+	    fprintf (stderr, "%s: Can't create subdir set\n", dir);
+	    ret++;
+	    FcDirCacheUnload (cache);
+	    continue;
+	}
+	for (i = 0; i < cache->dirs_count; i++)
+	    FcStrSetAdd (subdirs, FcCacheSubdir (cache, i));
+	
+	FcDirCacheUnload (cache);
+	
 	sublist = FcStrListCreate (subdirs);
 	FcStrSetDestroy (subdirs);
 	if (!sublist)
 	{
 	    fprintf (stderr, "%s: Can't create subdir list\n", dir);
 	    ret++;
+	    FcDirCacheUnload (cache);
 	    continue;
 	}
 	FcStrSetAdd (processed_dirs, dir);
-	ret += scanDirs (sublist, config, program, force, really_force, verbose);
+	ret += scanDirs (sublist, config, force, really_force, verbose);
     }
     FcStrListDone (list);
     return ret;
 }
 
-FcCache *
-FcCacheFileMap (const FcChar8 *file, struct stat *file_stat)
-{
-    FcCache *cache;
-    int	    fd;
-
-    fd = open (file, O_RDONLY | O_BINARY);
-    if (fd < 0)
-	return NULL;
-    if (fstat (fd, file_stat) < 0) {
-	close (fd);
-	return NULL;
-    }
-    if (FcDirCacheLoad (fd, file_stat->st_size, &cache)) {
-	close (fd);
-	return cache;
-    }
-    close (fd);
-    return NULL;
-}
-
 static FcBool
 cleanCacheDirectory (FcConfig *config, FcChar8 *dir, FcBool verbose)
 {
@@ -309,9 +290,11 @@ cleanCacheDirectory (FcConfig *config, F
     if (access ((char *) dir, W_OK|X_OK) != 0)
     {
 	if (verbose)
-	    printf ("%s: skipping unwritable cache directory\n", dir);
+	    printf ("%s: not cleaning unwritable cache directory\n", dir);
 	return FcTrue;
     }
+    if (verbose)
+	printf ("%s: cleaning cache directory\n", dir);
     d = opendir (dir);
     if (!d)
     {
@@ -332,7 +315,7 @@ cleanCacheDirectory (FcConfig *config, F
 	    ret = FcFalse;
 	    break;
 	}
-	cache = FcCacheFileMap (file_name, &file_stat);
+	cache = FcDirCacheLoadFile (file_name, &file_stat);
 	if (!cache)
 	{
 	    fprintf (stderr, "%s: invalid cache file: %s\n", dir, ent->d_name);
@@ -478,7 +461,7 @@ main (int argc, char **argv)
 	return 1;
     }
 	
-    ret = scanDirs (list, config, argv[0], force, really_force, verbose);
+    ret = scanDirs (list, config, force, really_force, verbose);
 
     FcStrSetDestroy (processed_dirs);
 
diff --git a/fc-cat/fc-cat.c b/fc-cat/fc-cat.c
index 6074f1d..71b416f 100644
--- a/fc-cat/fc-cat.c
+++ b/fc-cat/fc-cat.c
@@ -81,7 +81,7 @@ extern int optind, opterr, optopt;
 #endif
 
 static FcBool
-FcCacheWriteChars (FILE *f, const FcChar8 *chars)
+write_chars (FILE *f, const FcChar8 *chars)
 {
     FcChar8    c;
     while ((c = *chars++))
@@ -101,7 +101,7 @@ FcCacheWriteChars (FILE *f, const FcChar
 }
 
 static FcBool
-FcCacheWriteUlong (FILE *f, unsigned long t)
+write_ulong (FILE *f, unsigned long t)
 {
     int	    pow;
     unsigned long   temp, digit;
@@ -126,18 +126,18 @@ FcCacheWriteUlong (FILE *f, unsigned lon
 }
 
 static FcBool
-FcCacheWriteInt (FILE *f, int i)
+write_int (FILE *f, int i)
 {
-    return FcCacheWriteUlong (f, (unsigned long) i);
+    return write_ulong (f, (unsigned long) i);
 }
 
 static FcBool
-FcCacheWriteStringOld (FILE *f, const FcChar8 *string)
+write_string (FILE *f, const FcChar8 *string)
 {
 
     if (PUTC ('"', f) == EOF)
 	return FcFalse;
-    if (!FcCacheWriteChars (f, string))
+    if (!write_chars (f, string))
 	return FcFalse;
     if (PUTC ('"', f) == EOF)
 	return FcFalse;
@@ -168,30 +168,12 @@ usage (char *program)
     exit (1);
 }
 
-static int
-FcCacheFileOpen (char *cache_file, off_t *size)
-{
-    int fd;
-    struct stat file_stat;
-
-    fd = open(cache_file, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-
-    if (fstat (fd, &file_stat) < 0) {
-	close (fd); 
-	return -1;
-    }
-    *size = file_stat.st_size;
-    return fd;
-}
-
 /*
  * return the path from the directory containing 'cache' to 'file'
  */
 
 static const FcChar8 *
-FcFileBaseName (const char *cache, const FcChar8 *file)
+file_base_name (const char *cache, const FcChar8 *file)
 {
     const FcChar8   *cache_slash;
     int		    cache_len = strlen (cache);
@@ -201,8 +183,8 @@ FcFileBaseName (const char *cache, const
     return file;
 }
 
-FcBool
-FcCachePrintSet (FcFontSet *set, FcStrSet *dirs, char *base_name, FcBool verbose)
+static FcBool
+cache_print_set (FcFontSet *set, FcStrSet *dirs, char *base_name, FcBool verbose)
 {
     FcPattern	    *font;
     FcChar8	    *name, *dir;
@@ -219,16 +201,16 @@ FcCachePrintSet (FcFontSet *set, FcStrSe
     
     while ((dir = FcStrListNext (list)))
     {
-	base = FcFileBaseName (base_name, dir);
-	if (!FcCacheWriteStringOld (stdout, base))
+	base = file_base_name (base_name, dir);
+	if (!write_string (stdout, base))
 	    goto bail3;
 	if (PUTC (' ', stdout) == EOF)
 	    goto bail3;
-	if (!FcCacheWriteInt (stdout, 0))
+	if (!write_int (stdout, 0))
 	    goto bail3;
         if (PUTC (' ', stdout) == EOF)
 	    goto bail3;
-	if (!FcCacheWriteStringOld (stdout, FC_FONT_FILE_DIR))
+	if (!write_string (stdout, FC_FONT_FILE_DIR))
 	    goto bail3;
 	if (PUTC ('\n', stdout) == EOF)
 	    goto bail3;
@@ -243,21 +225,21 @@ FcCachePrintSet (FcFontSet *set, FcStrSe
 
 	if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
 	    goto bail3;
-	base = FcFileBaseName (base_name, file);
+	base = file_base_name (base_name, file);
 	if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
 	    goto bail3;
-	if (!FcCacheWriteStringOld (stdout, base))
+	if (!write_string (stdout, base))
 	    goto bail3;
 	if (PUTC (' ', stdout) == EOF)
 	    goto bail3;
-	if (!FcCacheWriteInt (stdout, id))
+	if (!write_int (stdout, id))
 	    goto bail3;
         if (PUTC (' ', stdout) == EOF)
 	    goto bail3;
 	name = FcNameUnparse (font);
 	if (!name)
 	    goto bail3;
-	ret = FcCacheWriteStringOld (stdout, name);
+	ret = write_string (stdout, name);
 	FcStrFree (name);
 	if (!ret)
 	    goto bail3;
@@ -277,28 +259,6 @@ bail2:
     return FcFalse;
 }
 
-FcCache *
-FcCacheFileMap (const FcChar8 *file)
-{
-    FcCache *cache;
-    int	    fd;
-    struct stat file_stat;
-
-    fd = open (file, O_RDONLY | O_BINARY);
-    if (fd < 0)
-	return NULL;
-    if (fstat (fd, &file_stat) < 0) {
-	close (fd);
-	return NULL;
-    }
-    if (!FcDirCacheLoad (fd, file_stat.st_size, &cache)) {
-	close (fd);
-	return NULL;
-    }
-    close (fd);
-    return cache;
-}
-
 int
 main (int argc, char **argv)
 {
@@ -399,11 +359,12 @@ main (int argc, char **argv)
 	off_t	    size;
 	intptr_t    *cache_dirs;
 	FcChar8	    *cache_file = NULL;
+	struct stat file_stat;
 	
 	if (FcFileIsDir (arg))
-	    cache = FcDirCacheMap (arg, config, &cache_file);
+	    cache = FcDirCacheLoad (arg, config, &cache_file);
 	else
-	    cache = FcCacheFileMap (arg);
+	    cache = FcDirCacheLoadFile (arg, &file_stat);
 	if (!cache)
 	{
 	    perror ((char *) arg);
@@ -433,11 +394,11 @@ main (int argc, char **argv)
 		    FcCacheDir(cache), cache_file ? cache_file : arg);
 	    first = FcFalse;
 	}
-        FcCachePrintSet (fs, dirs, FcCacheDir (cache), verbose);
+        cache_print_set (fs, dirs, FcCacheDir (cache), verbose);
 
 	FcStrSetDestroy (dirs);
 
-	FcDirCacheUnmap (cache);
+	FcDirCacheUnload (cache);
 	if (cache_file)
 	    FcStrFree (cache_file);
     }
diff --git a/fc-glyphname/fc-glyphname.c b/fc-glyphname/fc-glyphname.c
index 8b265e4..faaa63b 100644
--- a/fc-glyphname/fc-glyphname.c
+++ b/fc-glyphname/fc-glyphname.c
@@ -24,19 +24,6 @@
 
 #include "fcint.h"
 
-/* stub definitions for declarations from fcint.h.. */
-int * _fcBankId = 0, * _fcBankIdx = 0;
-FcValueList ** _fcValueLists = 0;
-FcPatternElt ** _fcPatternElts = 0;
-int FcDebugVal = 0;
-
-int
-FcCacheBankToIndexMTF (int bank)
-{
-    return 0;
-}
-/* end stub definitions */
-
 static int
 rawindex (const FcGlyphName *gn);
 
diff --git a/src/fccache.c b/src/fccache.c
index dd0896b..af2c68f 100644
--- a/src/fccache.c
+++ b/src/fccache.c
@@ -112,81 +112,19 @@ FcDirCacheUnlink (const FcChar8 *dir, Fc
 }
 
 static int
-FcCacheReadDirs (FcConfig * config,
-		 FcStrList *list, FcFontSet * set, FcStrSet *processed_dirs)
+FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat)
 {
-    int			ret = 0;
-    FcChar8		*dir;
-    FcStrSet		*subdirs;
-    FcStrList		*sublist;
+    int	fd;
 
-    /*
-     * Read in the results from 'list'.
-     */
-    while ((dir = FcStrListNext (list)))
+    fd = open((char *) cache_file, O_RDONLY | O_BINARY);
+    if (fd < 0)
+	return fd;
+    if (fstat (fd, file_stat) < 0)
     {
-	if (!FcConfigAcceptFilename (config, dir))
-	    continue;
-
-	/* Skip this directory if already updated
-	 * to avoid the looped directories via symlinks
-	 * Clearly a dir not in fonts.conf shouldn't be globally cached.
-	 */
-
-	if (FcStrSetMember (processed_dirs, dir))
-	    continue;
-	if (!FcStrSetAdd (processed_dirs, dir))
-	    continue;
-
-	subdirs = FcStrSetCreate ();
-	if (!subdirs)
-	{
-	    fprintf (stderr, "Can't create directory set\n");
-	    ret++;
-	    continue;
-	}
-	
-	FcDirScanConfig (set, subdirs,
-			 config->blanks, dir, FcFalse, config);
-	
-	sublist = FcStrListCreate (subdirs);
-	FcStrSetDestroy (subdirs);
-	if (!sublist)
-	{
-	    fprintf (stderr, "Can't create subdir list in \"%s\"\n", dir);
-	    ret++;
-	    continue;
-	}
-	ret += FcCacheReadDirs (config, sublist, set, processed_dirs);
+	close (fd);
+	return -1;
     }
-    FcStrListDone (list);
-    return ret;
-}
-
-FcFontSet *
-FcCacheRead (FcConfig *config)
-{
-    FcFontSet 	*s = FcFontSetCreate();
-    FcStrSet 	*processed_dirs;
-
-    if (!s) 
-	return 0;
-
-    processed_dirs = FcStrSetCreate();
-    if (!processed_dirs)
-	goto bail;
-
-    if (FcCacheReadDirs (config, FcConfigGetConfigDirs (config), s, processed_dirs))
-	goto bail1;
-
-    FcStrSetDestroy (processed_dirs);
-    return s;
-
- bail1:
-    FcStrSetDestroy (processed_dirs);
- bail:
-    FcFontSetDestroy (s);
-    return 0;
+    return fd;
 }
 
 /* 
@@ -220,10 +158,9 @@ FcDirCacheProcess (FcConfig *config, con
         FcChar8	*cache_hashed = FcStrPlus (cache_dir, cache_base);
         if (!cache_hashed)
 	    break;
-        fd = open((char *) cache_hashed, O_RDONLY | O_BINARY);
+        fd = FcDirCacheOpenFile (cache_hashed, &file_stat);
         if (fd >= 0) {
-	    if (fstat (fd, &file_stat) >= 0 &&
-		dir_stat.st_mtime <= file_stat.st_mtime)
+	    if (dir_stat.st_mtime <= file_stat.st_mtime)
 	    {
 		ret = (*callback) (fd, file_stat.st_size, closure);
 		if (ret)
@@ -245,44 +182,56 @@ FcDirCacheProcess (FcConfig *config, con
     return ret;
 }
 
-FcBool
-FcDirCacheLoad (int fd, off_t size, void *closure)
+#define FC_CACHE_MIN_MMAP   1024
+
+/*
+ * Map a cache file into memory
+ */
+static FcCache *
+FcDirCacheMapFd (int fd, off_t size)
 {
-    FcCache	*cache;
+    FcCache	*cache = NULL;
     FcBool	allocated = FcFalse;
 
     if (size < sizeof (FcCache))
-	return FcFalse;
+	return NULL;
+    /*
+     * For small cache files, just read them into memory
+     */
+    if (size >= FC_CACHE_MIN_MMAP)
+    {
 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
-    cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
+	cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
 #elif defined(_WIN32)
-    {
-	HANDLE hFileMap;
-
-	cache = NULL;
-	hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
-				     PAGE_READONLY, 0, 0, NULL);
-	if (hFileMap != NULL)
 	{
-	    cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0, size);
-	    CloseHandle (hFileMap);
+	    HANDLE hFileMap;
+
+	    cache = NULL;
+	    hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
+					 PAGE_READONLY, 0, 0, NULL);
+	    if (hFileMap != NULL)
+	    {
+		cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0, size);
+		CloseHandle (hFileMap);
+	    }
 	}
-    }
 #endif
+    }
     if (!cache)
     {
 	cache = malloc (size);
 	if (!cache)
-	    return FcFalse;
+	    return NULL;
 
 	if (read (fd, cache, size) != size)
 	{
 	    free (cache);
-	    return FcFalse;
+	    return NULL;
 	}
 	allocated = FcTrue;
     } 
-    if (cache->magic != FC_CACHE_MAGIC ||
+    if (cache->magic != FC_CACHE_MAGIC_MMAP || 
+	cache->version != FC_CACHE_CONTENT_VERSION ||
 	cache->size != size)
     {
 	if (allocated)
@@ -295,74 +244,76 @@ FcDirCacheLoad (int fd, off_t size, void
 	    UnmapViewOfFile (cache);
 #endif
 	}
-	return FcFalse;
+	return NULL;
     }
 
     /* Mark allocated caches so they're freed rather than unmapped */
     if (allocated)
-	cache->magic = FC_CACHE_MAGIC_COPY;
+	cache->magic = FC_CACHE_MAGIC_ALLOC;
 	
+    return cache;
+}
+
+void
+FcDirCacheUnload (FcCache *cache)
+{
+    switch (cache->magic) {
+    case FC_CACHE_MAGIC_ALLOC:
+	free (cache);
+	break;
+    case FC_CACHE_MAGIC_MMAP:
+#if defined(HAVE_MMAP) || defined(__CYGWIN__)
+	munmap (cache, cache->size);
+#elif defined(_WIN32)
+	UnmapViewOfFile (cache);
+#endif
+	break;
+    }
+}
+
+static FcBool
+FcDirCacheMapHelper (int fd, off_t size, void *closure)
+{
+    FcCache *cache = FcDirCacheMapFd (fd, size);
+
+    if (!cache)
+	return FcFalse;
     *((FcCache **) closure) = cache;
     return FcTrue;
 }
 
 FcCache *
-FcDirCacheMap (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
+FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
 {
     FcCache *cache = NULL;
 
     if (!FcDirCacheProcess (config, dir,
-			    FcDirCacheLoad,
+			    FcDirCacheMapHelper,
 			    &cache, cache_file))
 	return NULL;
     return cache;
 }
 
-FcBool
-FcDirCacheRead (FcFontSet * set, FcStrSet * dirs, 
-		const FcChar8 *dir, FcConfig *config)
+FcCache *
+FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
 {
-    FcCache	*cache;
-    int		i;
-    FcFontSet	*cache_set;
-    intptr_t	*cache_dirs;
-    FcPattern   **cache_fonts;
+    int	fd;
+    FcCache *cache;
 
-    cache = FcDirCacheMap (dir, config, NULL);
-    if (!cache)
-	return FcFalse;
-    
-    cache_set = FcCacheSet (cache);
-    cache_fonts = FcFontSetFonts(cache_set);
-    if (FcDebug() & FC_DBG_CACHE)
-        printf ("FcDirCacheRead mapped cache for %s (%d fonts %d subdirs)\n",
-		dir, cache_set->nfont, cache->dirs_count);
-    for (i = 0; i < cache_set->nfont; i++)
-    {
-	FcPattern   *font = FcEncodedOffsetToPtr (cache_set,
-						  cache_fonts[i],
-						  FcPattern);
-	if (FcDebug() & FC_DBG_CACHEV) {
-	    printf ("Mapped font %d\n", i);
-	    FcPatternPrint (font);
-	}
-	FcFontSetAdd (set, font);
-    }
-    
-    cache_dirs = FcCacheDirs (cache);
-    for (i = 0; i < cache->dirs_count; i++) 
-	FcStrSetAdd (dirs, FcOffsetToPtr (cache_dirs,
-					  cache_dirs[i],
-					  FcChar8));
-	 
-    if (config)
-	FcConfigAddFontDir (config, (FcChar8 *)dir);
-    
-    return FcTrue;
+    fd = FcDirCacheOpenFile (cache_file, file_stat);
+    if (fd < 0)
+	return NULL;
+    cache = FcDirCacheMapFd (fd, file_stat->st_size);
+    close (fd);
+    return cache;
 }
-    
+
+/*
+ * Validate a cache file by reading the header and checking
+ * the magic number and the size field
+ */
 static FcBool
-FcDirCacheValidate (int fd, off_t size, void *closure)
+FcDirCacheValidateHelper (int fd, off_t size, void *closure)
 {
     FcBool  ret = FcTrue;
     FcCache	c;
@@ -370,9 +321,11 @@ FcDirCacheValidate (int fd, off_t size, 
     
     if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
 	ret = FcFalse;
-    else if (fstat (fd, &file_stat) < 0)
+    else if (c.magic != FC_CACHE_MAGIC_MMAP)
+	ret = FcFalse;
+    else if (c.version != FC_CACHE_CONTENT_VERSION)
 	ret = FcFalse;
-    else if (c.magic != FC_CACHE_MAGIC)
+    else if (fstat (fd, &file_stat) < 0)
 	ret = FcFalse;
     else if (file_stat.st_size != c.size)
 	ret = FcFalse;
@@ -382,7 +335,9 @@ FcDirCacheValidate (int fd, off_t size, 
 static FcBool
 FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config)
 {
-    return FcDirCacheProcess (config, dir, FcDirCacheValidate, NULL, NULL);
+    return FcDirCacheProcess (config, dir, 
+			      FcDirCacheValidateHelper,
+			      NULL, NULL);
 }
 
 FcBool
@@ -397,32 +352,11 @@ FcDirCacheValid (const FcChar8 *dir)
     return FcDirCacheValidConfig (dir, config);
 }
 
-void
-FcDirCacheUnmap (FcCache *cache)
-{
-    if (cache->magic == FC_CACHE_MAGIC_COPY)
-    {
-	free (cache);
-	return;
-    }
-#if defined(HAVE_MMAP) || defined(__CYGWIN__)
-    munmap (cache, cache->size);
-#elif defined(_WIN32)
-    UnmapViewOfFile (cache);
-#endif
-}
-
 /*
- * Cache file is:
- *
- * FcCache
- * dir name
- * subdirs
- * FcFontSet
+ * Build a cache structure from the given contents
  */
-
-static FcCache *
-FcDirCacheProduce (FcFontSet *set, const FcChar8 *dir, FcStrSet *dirs)
+FcCache *
+FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, FcStrSet *dirs)
 {
     FcSerialize	*serialize = FcSerializeCreate ();
     FcCache *cache;
@@ -467,7 +401,8 @@ FcDirCacheProduce (FcFontSet *set, const
 
     serialize->linear = cache;
 
-    cache->magic = FC_CACHE_MAGIC;
+    cache->magic = FC_CACHE_MAGIC_ALLOC;
+    cache->version = FC_CACHE_CONTENT_VERSION;
     cache->size = serialize->size;
 
     /*
@@ -537,16 +472,18 @@ FcMakeDirectory (const FcChar8 *dir)
 
 /* write serialized state to the cache file */
 FcBool
-FcDirCacheWrite (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir, FcConfig *config)
+FcDirCacheWrite (FcCache *cache, FcConfig *config)
 {
+    FcChar8	    *dir = FcCacheDir (cache);
     FcChar8	    cache_base[CACHEBASE_LEN];
     FcChar8	    *cache_hashed;
     int 	    fd;
     FcAtomic 	    *atomic;
-    FcCache	    *cache;
     FcStrList	    *list;
     FcChar8	    *cache_dir = NULL;
     FcChar8	    *test_dir;
+    int		    magic;
+    int		    written;
 
     /*
      * Write it to the first directory in the list which is writable
@@ -584,18 +521,13 @@ FcDirCacheWrite (FcFontSet *set, FcStrSe
     if (!cache_hashed)
         return FcFalse;
 
-    cache = FcDirCacheProduce (set, dir, dirs);
-
-    if (!cache)
-	goto bail1;
-
     if (FcDebug () & FC_DBG_CACHE)
         printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
 		dir, cache_hashed);
 
     atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
     if (!atomic)
-	goto bail2;
+	goto bail1;
 
     if (!FcAtomicLock (atomic))
 	goto bail3;
@@ -604,7 +536,21 @@ FcDirCacheWrite (FcFontSet *set, FcStrSe
     if (fd == -1)
 	goto bail4;
     
-    if (write (fd, cache, cache->size) != cache->size)
+    /* Temporarily switch magic to MMAP while writing to file */
+    magic = cache->magic;
+    if (magic != FC_CACHE_MAGIC_MMAP)
+	cache->magic = FC_CACHE_MAGIC_MMAP;
+    
+    /*
+     * Write cache contents to file
+     */
+    written = write (fd, cache, cache->size);
+    
+    /* Switch magic back */
+    if (magic != FC_CACHE_MAGIC_MMAP)
+	cache->magic = magic;
+    
+    if (written != cache->size)
     {
 	perror ("write cache");
 	goto bail5;
@@ -613,7 +559,7 @@ FcDirCacheWrite (FcFontSet *set, FcStrSe
     close(fd);
     if (!FcAtomicReplaceOrig(atomic))
         goto bail4;
-    FcStrFree ((FcChar8 *)cache_hashed);
+    FcStrFree (cache_hashed);
     FcAtomicUnlock (atomic);
     FcAtomicDestroy (atomic);
     return FcTrue;
@@ -624,10 +570,8 @@ FcDirCacheWrite (FcFontSet *set, FcStrSe
     FcAtomicUnlock (atomic);
  bail3:
     FcAtomicDestroy (atomic);
- bail2:
-    free (cache);
  bail1:
-    FcStrFree ((FcChar8 *)cache_hashed);
+    FcStrFree (cache_hashed);
     return FcFalse;
 }
 
diff --git a/src/fccfg.c b/src/fccfg.c
index bcc3bd2..cec0e4a 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -222,7 +222,7 @@ FcConfigDestroy (FcConfig *config)
     for (cl = config->caches; cl; cl = cl_next)
     {
 	cl_next = cl->next;
-	FcDirCacheUnmap (cl->cache);
+	FcDirCacheUnload (cl->cache);
 	free (cl);
     }
 
@@ -231,86 +231,120 @@ FcConfigDestroy (FcConfig *config)
 }
 
 /*
- * Scan the current list of directories in the configuration
- * and build the set of available fonts. Update the
- * per-user cache file to reflect the new configuration
+ * Add cache to configuration, adding fonts and directories
  */
 
 FcBool
-FcConfigBuildFonts (FcConfig *config)
+FcConfigAddCache (FcConfig *config, FcCache *cache)
 {
-    FcFontSet	    *fonts, *cached_fonts;
-    FcStrList	    *list;
-    FcStrSet	    *oldDirs;
-    FcChar8	    *dir;
+    FcCacheList	*cl = malloc (sizeof (FcCacheList));
+    FcFontSet	*fs;
+    intptr_t	*dirs;
+    int		i;
+
+    /*
+     * Add to cache list
+     */
+    if (!cl)
+	return FcFalse;
+    cl->cache = cache;
+    cl->next = config->caches;
+    config->caches = cl;
 
-    fonts = FcFontSetCreate ();
-    if (!fonts)
-	goto bail0;
-    
-    oldDirs = FcStrSetCreate ();
-    if (!oldDirs)
-        goto bail2;
-
-    cached_fonts = FcCacheRead(config);
-    if (!cached_fonts)
-    {
-	list = FcConfigGetFontDirs (config);
-	if (!list)
-	    goto bail3;
-	
-	while ((dir = FcStrListNext (list)))
+    /*
+     * Add fonts
+     */
+    fs = FcCacheSet (cache);
+    if (fs)
+    {
+	for (i = 0; i < fs->nfont; i++)
 	{
-	    if (FcDebug () & FC_DBG_FONTSET)
-		printf ("build scan dir %s\n", dir);
-	    FcDirScanConfig (fonts, config->fontDirs,
-			     config->blanks, dir, FcFalse, config);
+	    FcPattern	*font = FcFontSetFont (fs, i);
+	    FcChar8	*font_file;
+
+	    /*
+	     * Check to see if font is banned by filename
+	     */
+	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
+					  0, &font_file) == FcResultMatch &&
+		!FcConfigAcceptFilename (config, font_file))
+	    {
+		continue;
+	    }
+		
+	    /*
+	     * Check to see if font is banned by pattern
+	     */
+	    if (!FcConfigAcceptFont (config, font))
+		continue;
+		
+	    FcFontSetAdd (config->fonts[FcSetSystem], font);
 	}
-	
-	FcStrListDone (list);
     }
-    else
-    {
-	int i;
 
-        for (i = 0; i < oldDirs->num; i++)
-        {
-	    if (FcDebug () & FC_DBG_FONTSET)
-		printf ("scan dir %s\n", oldDirs->strs[i]);
-	    FcDirScanConfig (fonts, config->fontDirs,
-			     config->blanks, oldDirs->strs[i], 
-                             FcFalse, config);
+    /*
+     * Add directories
+     */
+    dirs = FcCacheDirs (cache);
+    if (dirs)
+    {
+	for (i = 0; i < cache->dirs_count; i++)
+	{
+	    FcChar8	*dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
+	    if (FcConfigAcceptFilename (config, dir))
+		FcConfigAddFontDir (config, dir);
 	}
+    }
+    return FcTrue;
+}
 
-	for (i = 0; i < cached_fonts->nfont; i++)
-	{
-	    FcChar8 	*cfn; 
-	    FcPattern	*font = cached_fonts->fonts[i];
-	    FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &cfn);
+/*
+ * Scan the current list of directories in the configuration
+ * and build the set of available fonts.
+ */
 
-	    if (FcConfigAcceptFont (config, font) &&
-                (cfn && FcConfigAcceptFilename (config, cfn)))
-		FcFontSetAdd (fonts, font);
+FcBool
+FcConfigBuildFonts (FcConfig *config)
+{
+    FcFontSet	    *fonts;
+    FcStrList	    *dirlist;
+    FcChar8	    *dir;
+    FcCache	    *cache;
 
-	    cached_fonts->fonts[i] = 0; /* prevent free in FcFontSetDestroy */
-	}
-	cached_fonts->nfont = 0;
-	FcFontSetDestroy (cached_fonts);
+    if (!config)
+    {
+	config = FcConfigGetCurrent ();
+	if (!config)
+	    return FcFalse;
+    }
+	
+    fonts = FcFontSetCreate ();
+    if (!fonts)
+	goto bail;
+    
+    FcConfigSetFonts (config, fonts, FcSetSystem);
+    
+    dirlist = FcStrListCreate (config->fontDirs);
+    if (!dirlist)
+        goto bail;
+	
+    while ((dir = FcStrListNext (dirlist)))
+    {
+	if (FcDebug () & FC_DBG_FONTSET)
+	    printf ("adding fonts from%s\n", dir);
+	cache = FcDirCacheRead (dir, FcFalse, config);
+	if (!cache)
+	    continue;
+	FcConfigAddCache (config, cache);
     }
     
+    FcStrListDone (dirlist);
+    
     if (FcDebug () & FC_DBG_FONTSET)
 	FcFontSetPrint (fonts);
 
-    FcStrSetDestroy (oldDirs);
-
-    FcConfigSetFonts (config, fonts, FcSetSystem);
-    
     return FcTrue;
-bail3:
-    FcStrSetDestroy (oldDirs);
-bail2:
-    FcFontSetDestroy (fonts);
-bail0:
+bail:
     return FcFalse;
 }
 
@@ -457,19 +491,6 @@ FcConfigSetFonts (FcConfig	*config,
     config->fonts[set] = fonts;
 }
 
-FcBool
-FcConfigAddCache (FcConfig *config, FcCache *cache)
-{
-    FcCacheList	*cl = malloc (sizeof (FcCacheList));
-
-    if (!cl)
-	return FcFalse;
-    cl->cache = cache;
-    cl->next = config->caches;
-    config->caches = cl;
-    return FcTrue;
-}
-
 FcBlanks *
 FcConfigGetBlanks (FcConfig	*config)
 {
@@ -1750,7 +1771,7 @@ FcConfigAppFontAddFile (FcConfig    *con
 	FcConfigSetFonts (config, set, FcSetApplication);
     }
 	
-    if (!FcFileScanConfig (set, subdirs, config->blanks, file, FcFalse, config))
+    if (!FcFileScanConfig (set, subdirs, config->blanks, file, config))
     {
 	FcStrSetDestroy (subdirs);
 	return FcFalse;
diff --git a/src/fccharset.c b/src/fccharset.c
index 3a93c4a..43aa22c 100644
--- a/src/fccharset.c
+++ b/src/fccharset.c
@@ -27,8 +27,6 @@
 
 /* #define CHECK */
 
-/* #define CHATTY */
-
 FcCharSet *
 FcCharSetCreate (void)
 {
@@ -40,8 +38,8 @@ FcCharSetCreate (void)
     FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
     fcs->ref = 1;
     fcs->num = 0;
-    fcs->leaves_offset = FcPtrToOffset (fcs, NULL);
-    fcs->numbers_offset = FcPtrToOffset (fcs, NULL);
+    fcs->leaves_offset = 0;
+    fcs->numbers_offset = 0;
     return fcs;
 }
 
@@ -68,12 +66,12 @@ FcCharSetDestroy (FcCharSet *fcs)
 	FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
 	free (FcCharSetLeaf (fcs, i));
     }
-    if (FcCharSetLeaves (fcs))
+    if (fcs->num)
     {
 	FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t));
 	free (FcCharSetLeaves (fcs));
     }
-    if (FcCharSetNumbers (fcs))
+    if (fcs->num)
     {
 	FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16));
 	free (FcCharSetNumbers (fcs));
@@ -136,7 +134,7 @@ FcCharSetPutLeaf (FcCharSet	*fcs, 
     ucs4 >>= 8;
     if (ucs4 >= 0x10000)
 	return FcFalse;
-    if (!leaves)
+    if (!fcs->num)
 	leaves = malloc (sizeof (*leaves));
     else
     {
@@ -161,7 +159,7 @@ FcCharSetPutLeaf (FcCharSet	*fcs, 
     FcMemAlloc (FC_MEM_CHARSET, (fcs->num + 1) * sizeof (intptr_t));
     fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
     
-    if (!numbers)
+    if (!fcs->num)
 	numbers = malloc (sizeof (FcChar16));
     else
 	numbers = realloc (numbers, (fcs->num + 1) * sizeof (FcChar16));
@@ -278,9 +276,6 @@ FcCharSetIterSet (const FcCharSet *fcs, 
     }
     iter->leaf = FcCharSetLeaf(fcs, pos);
     iter->pos = pos;
-#ifdef CHATTY
-    printf ("set %08x: %08x\n", iter->ucs4, (FcChar32) iter->leaf);
-#endif
 }
 
 static void
@@ -300,29 +295,10 @@ FcCharSetIterNext (const FcCharSet *fcs,
     }
 }
 
-#ifdef CHATTY
-static void
-FcCharSetDump (const FcCharSet *fcs)
-{
-    int		pos;
-
-    printf ("fcs %08x:\n", (FcChar32) fcs);
-    for (pos = 0; pos < fcs->num; pos++)
-    {
-	FcCharLeaf	*leaf = fcs->leaves[pos];
-	FcChar32	ucs4 = (FcChar32) fcs->numbers[pos] << 8;
-	
-	printf ("    %08x: %08x\n", ucs4, (FcChar32) leaf);
-    }
-}
-#endif
 
 static void
 FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
 {
-#ifdef CHATTY
-    FcCharSetDump (fcs);
-#endif
     iter->ucs4 = 0;
     iter->pos = 0;
     FcCharSetIterSet (fcs, iter);
@@ -854,6 +830,133 @@ FcCharSetUnparseValue (FcStrBuf *buf, Fc
     return FcTrue;
 }
 
+FcCharSet *
+FcNameParseCharSet (FcChar8 *string)
+{
+    FcCharSet	*c;
+    FcChar32	ucs4;
+    FcCharLeaf	*leaf;
+    FcCharLeaf	temp;
+    FcChar32	bits;
+    int		i;
+
+    c = FcCharSetCreate ();
+    if (!c)
+	goto bail0;
+    while (*string)
+    {
+	string = FcCharSetParseValue (string, &ucs4);
+	if (!string)
+	    goto bail1;
+	bits = 0;
+	for (i = 0; i < 256/32; i++)
+	{
+	    string = FcCharSetParseValue (string, &temp.map[i]);
+	    if (!string)
+		goto bail1;
+	    bits |= temp.map[i];
+	}
+	if (bits)
+	{
+	    leaf = malloc (sizeof (FcCharLeaf));
+	    if (!leaf)
+		goto bail1;
+	    *leaf = temp;
+	    if (!FcCharSetInsertLeaf (c, ucs4, leaf))
+		goto bail1;
+	}
+    }
+    return c;
+bail1:
+    if (c->num)
+    {
+	FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *));
+	free (FcCharSetLeaves (c));
+    }
+    if (c->num)
+    {
+	FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16));
+	free (FcCharSetNumbers (c));
+    }
+    FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
+    free (c);
+bail0:
+    return NULL;
+}
+
+FcBool
+FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
+{
+    FcCharSetIter   ci;
+    int		    i;
+#ifdef CHECK
+    int		    len = buf->len;
+#endif
+
+    for (FcCharSetIterStart (c, &ci);
+	 ci.leaf;
+	 FcCharSetIterNext (c, &ci))
+    {
+	if (!FcCharSetUnparseValue (buf, ci.ucs4))
+	    return FcFalse;
+	for (i = 0; i < 256/32; i++)
+	    if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
+		return FcFalse;
+    }
+#ifdef CHECK
+    {
+	FcCharSet	*check;
+	FcChar32	missing;
+	FcCharSetIter	ci, checki;
+	
+	/* null terminate for parser */
+	FcStrBufChar (buf, '\0');
+	/* step back over null for life after test */
+	buf->len--;
+	check = FcNameParseCharSet (buf->buf + len);
+	FcCharSetIterStart (c, &ci);
+	FcCharSetIterStart (check, &checki);
+	while (ci.leaf || checki.leaf)
+	{
+	    if (ci.ucs4 < checki.ucs4)
+	    {
+		printf ("Missing leaf node at 0x%x\n", ci.ucs4);
+		FcCharSetIterNext (c, &ci);
+	    }
+	    else if (checki.ucs4 < ci.ucs4)
+	    {
+		printf ("Extra leaf node at 0x%x\n", checki.ucs4);
+		FcCharSetIterNext (check, &checki);
+	    }
+	    else
+	    {
+		int	    i = 256/32;
+		FcChar32    *cm = ci.leaf->map;
+		FcChar32    *checkm = checki.leaf->map;
+
+		for (i = 0; i < 256; i += 32)
+		{
+		    if (*cm != *checkm)
+			printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
+				ci.ucs4 + i, *cm, *checkm);
+		    cm++;
+		    checkm++;
+		}
+		FcCharSetIterNext (c, &ci);
+		FcCharSetIterNext (check, &checki);
+	    }
+	}
+	if ((missing = FcCharSetSubtractCount (c, check)))
+	    printf ("%d missing in reparsed result\n", missing);
+	if ((missing = FcCharSetSubtractCount (check, c)))
+	    printf ("%d extra in reparsed result\n", missing);
+	FcCharSetDestroy (check);
+    }
+#endif
+    
+    return FcTrue;
+}
+
 typedef struct _FcCharLeafEnt FcCharLeafEnt;
 
 struct _FcCharLeafEnt {
@@ -863,36 +966,63 @@ struct _FcCharLeafEnt {
 };
 
 #define FC_CHAR_LEAF_BLOCK	(4096 / sizeof (FcCharLeafEnt))
-static FcCharLeafEnt **FcCharLeafBlocks;
-static int FcCharLeafBlockCount;
+#define FC_CHAR_LEAF_HASH_SIZE	257
+
+typedef struct _FcCharSetEnt FcCharSetEnt;
+
+struct _FcCharSetEnt {
+    FcCharSetEnt	*next;
+    FcChar32		hash;
+    FcCharSet		set;
+};
+
+typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
+
+struct _FcCharSetOrigEnt {
+    FcCharSetOrigEnt	*next;
+    const FcCharSet    	*orig;
+    const FcCharSet    	*frozen;
+};
+
+#define FC_CHAR_SET_HASH_SIZE    67
+
+struct _FcCharSetFreezer {
+    FcCharLeafEnt   *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE];
+    FcCharLeafEnt   **leaf_blocks;
+    int		    leaf_block_count;
+    FcCharSetEnt    *set_hash_table[FC_CHAR_SET_HASH_SIZE];
+    FcCharSetOrigEnt	*orig_hash_table[FC_CHAR_SET_HASH_SIZE];
+    FcCharLeafEnt   *current_block;
+    int		    leaf_remain;
+    int		    leaves_seen;
+    int		    charsets_seen;
+    int		    leaves_allocated;
+    int		    charsets_allocated;
+};
 
 static FcCharLeafEnt *
-FcCharLeafEntCreate (void)
+FcCharLeafEntCreate (FcCharSetFreezer *freezer)
 {
-    static FcCharLeafEnt    *block;
-    static int		    remain;
-
-    if (!remain)
+    if (!freezer->leaf_remain)
     {
 	FcCharLeafEnt **newBlocks;
 
-	FcCharLeafBlockCount++;
-	newBlocks = realloc (FcCharLeafBlocks, FcCharLeafBlockCount * sizeof (FcCharLeafEnt *));
+	freezer->leaf_block_count++;
+	newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
 	if (!newBlocks)
 	    return 0;
-	FcCharLeafBlocks = newBlocks;
-	block = FcCharLeafBlocks[FcCharLeafBlockCount-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
-	if (!block)
+	freezer->leaf_blocks = newBlocks;
+	freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
+	if (!freezer->current_block)
 	    return 0;
 	FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
-	remain = FC_CHAR_LEAF_BLOCK;
+	freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
     }
-    remain--;
-    return block++;
+    freezer->leaf_remain--;
+    freezer->leaves_allocated++;
+    return freezer->current_block++;
 }
 
-#define FC_CHAR_LEAF_HASH_SIZE	257
-
 static FcChar32
 FcCharLeafHash (FcCharLeaf *leaf)
 {
@@ -904,29 +1034,22 @@ FcCharLeafHash (FcCharLeaf *leaf)
     return hash;
 }
 
-static int	FcCharLeafTotal;
-static int	FcCharLeafUsed;
-
-static FcCharLeafEnt	*FcCharLeafHashTable[FC_CHAR_LEAF_HASH_SIZE];
-
 static FcCharLeaf *
-FcCharSetFreezeLeaf (FcCharLeaf *leaf)
+FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
 {
     FcChar32			hash = FcCharLeafHash (leaf);
-    FcCharLeafEnt		**bucket = &FcCharLeafHashTable[hash % FC_CHAR_LEAF_HASH_SIZE];
+    FcCharLeafEnt		**bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
     FcCharLeafEnt		*ent;
     
-    FcCharLeafTotal++;
     for (ent = *bucket; ent; ent = ent->next)
     {
 	if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
 	    return &ent->leaf;
     }
 
-    ent = FcCharLeafEntCreate();
+    ent = FcCharLeafEntCreate(freezer);
     if (!ent)
 	return 0;
-    FcCharLeafUsed++;
     ent->leaf = *leaf;
     ent->hash = hash;
     ent->next = *bucket;
@@ -934,35 +1057,6 @@ FcCharSetFreezeLeaf (FcCharLeaf *leaf)
     return &ent->leaf;
 }
 
-static void
-FcCharSetThawAllLeaf (void)
-{
-    int i;
-
-    for (i = 0; i < FC_CHAR_LEAF_HASH_SIZE; i++)
-	FcCharLeafHashTable[i] = 0;
-
-    FcCharLeafTotal = 0;
-    FcCharLeafUsed = 0;
-
-    for (i = 0; i < FcCharLeafBlockCount; i++)
-	free (FcCharLeafBlocks[i]);
-
-    free (FcCharLeafBlocks);
-    FcCharLeafBlocks = 0;
-    FcCharLeafBlockCount = 0;
-}
-
-typedef struct _FcCharSetEnt FcCharSetEnt;
-
-struct _FcCharSetEnt {
-    FcCharSetEnt	*next;
-    FcChar32		hash;
-    FcCharSet		set;
-};
-
-#define FC_CHAR_SET_HASH_SIZE    67
-
 static FcChar32
 FcCharSetHash (FcCharSet *fcs)
 {
@@ -978,23 +1072,31 @@ FcCharSetHash (FcCharSet *fcs)
     return hash;
 }
 
-static int	FcCharSetTotal;
-static int	FcCharSetUsed;
-static int	FcCharSetTotalEnts, FcCharSetUsedEnts;
-
-static FcCharSetEnt	*FcCharSetHashTable[FC_CHAR_SET_HASH_SIZE];
+static FcBool
+FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
+{
+    FcCharSetOrigEnt	**bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
+    FcCharSetOrigEnt	*ent;
+    
+    ent = malloc (sizeof (FcCharSetOrigEnt));
+    if (!ent)
+	return FcFalse;
+    ent->orig = orig;
+    ent->frozen = frozen;
+    ent->next = *bucket;
+    *bucket = ent;
+    return FcTrue;
+}
 
 static FcCharSet *
-FcCharSetFreezeBase (FcCharSet *fcs)
+FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig)
 {
     FcChar32		hash = FcCharSetHash (fcs);
-    FcCharSetEnt	**bucket = &FcCharSetHashTable[hash % FC_CHAR_SET_HASH_SIZE];
+    FcCharSetEnt	**bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
     FcCharSetEnt	*ent;
     int			size;
     int			i;
 
-    FcCharSetTotal++;
-    FcCharSetTotalEnts += fcs->num;
     for (ent = *bucket; ent; ent = ent->next)
     {
 	if (ent->hash == hash &&
@@ -1021,8 +1123,8 @@ FcCharSetFreezeBase (FcCharSet *fcs)
     if (!ent)
 	return 0;
     FcMemAlloc (FC_MEM_CHARSET, size);
-    FcCharSetUsed++;
-    FcCharSetUsedEnts += fcs->num;
+    
+    freezer->charsets_allocated++;
     
     ent->set.ref = FC_REF_CONSTANT;
     ent->set.num = fcs->num;
@@ -1051,60 +1153,60 @@ FcCharSetFreezeBase (FcCharSet *fcs)
     ent->hash = hash;
     ent->next = *bucket;
     *bucket = ent;
+
     return &ent->set;
 }
 
-void
-FcCharSetThawAll (void)
+static const FcCharSet *
+FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
 {
-    int i;
-    FcCharSetEnt	*ent, *next;
-
-    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
-    {
-	for (ent = FcCharSetHashTable[i]; ent; ent = next)
-	{
-	    next = ent->next;
-	    free (ent);
-	}
-	FcCharSetHashTable[i] = 0;
-    }
-
-    FcCharSetTotal = 0;
-    FcCharSetTotalEnts = 0;
-    FcCharSetUsed = 0;
-    FcCharSetUsedEnts = 0;
-
-    FcCharSetThawAllLeaf ();
+    FcCharSetOrigEnt    **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
+    FcCharSetOrigEnt	*ent;
+    
+    for (ent = *bucket; ent; ent = ent->next)
+	if (ent->orig == orig)
+	    return ent->frozen;
+    return NULL;
 }
 
-FcCharSet *
-FcCharSetFreeze (FcCharSet *fcs)
+static const FcCharSet *
+FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
 {
-    FcCharSet	*b;
-    FcCharSet	*n = 0;
-    FcCharLeaf	*l;
-    int		i;
+    FcCharSet	    *b;
+    const FcCharSet *n = 0;
+    FcCharLeaf	    *l;
+    int		    i;
 
+    n = FcCharSetFindFrozen (freezer, fcs);
+    if (n)
+	return n;
+    
     b = FcCharSetCreate ();
     if (!b)
 	goto bail0;
     for (i = 0; i < fcs->num; i++)
     {
-	l = FcCharSetFreezeLeaf (FcCharSetLeaf(fcs, i));
+	l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
 	if (!l)
 	    goto bail1;
 	if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
 	    goto bail1;
     }
-    n = FcCharSetFreezeBase (b);
+    n = FcCharSetFreezeBase (freezer, b, fcs);
+    if (!FcCharSetFreezeOrig (freezer, fcs, n))
+    {
+	n = NULL;
+	goto bail1;
+    }
+    freezer->charsets_seen++;
+    freezer->leaves_seen += fcs->num;
 bail1:
-    if (FcCharSetLeaves (b))
+    if (b->num)
     {
 	FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *));
 	free (FcCharSetLeaves (b));
     }
-    if (FcCharSetNumbers (b))
+    if (b->num)
     {
 	FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16));
 	free (FcCharSetNumbers (b));
@@ -1115,160 +1217,74 @@ bail0:
     return n;
 }
 
-FcCharSet *
-FcNameParseCharSet (FcChar8 *string)
+static FcCharSetFreezer *
+FcCharSetFreezerCreate (void)
 {
-    FcCharSet	*c, *n = 0;
-    FcChar32	ucs4;
-    FcCharLeaf	*leaf;
-    FcCharLeaf	temp;
-    FcChar32	bits;
-    int		i;
+    FcCharSetFreezer	*freezer;
 
-    c = FcCharSetCreate ();
-    if (!c)
-	goto bail0;
-    while (*string)
-    {
-	string = FcCharSetParseValue (string, &ucs4);
-	if (!string)
-	    goto bail1;
-	bits = 0;
-	for (i = 0; i < 256/32; i++)
-	{
-	    string = FcCharSetParseValue (string, &temp.map[i]);
-	    if (!string)
-		goto bail1;
-	    bits |= temp.map[i];
-	}
-	if (bits)
-	{
-	    leaf = FcCharSetFreezeLeaf (&temp);
-	    if (!leaf)
-		goto bail1;
-	    if (!FcCharSetInsertLeaf (c, ucs4, leaf))
-		goto bail1;
-	}
-    }
-#ifdef CHATTY
-    printf ("          %8s %8s %8s %8s\n", "total", "totalmem", "new", "newmem");
-    printf ("Leaves:   %8d %8d %8d %8d\n",
-	    FcCharLeafTotal, sizeof (FcCharLeaf) * FcCharLeafTotal,
-	    FcCharLeafUsed, sizeof (FcCharLeaf) * FcCharLeafUsed);
-    printf ("Charsets: %8d %8d %8d %8d\n",
-	    FcCharSetTotal, sizeof (FcCharSet) * FcCharSetTotal,
-	    FcCharSetUsed, sizeof (FcCharSet) * FcCharSetUsed);
-    printf ("Tables:   %8d %8d %8d %8d\n",
-	    FcCharSetTotalEnts, FcCharSetTotalEnts * (sizeof (FcCharLeaf *) + sizeof (FcChar16)),
-	    FcCharSetUsedEnts, FcCharSetUsedEnts * (sizeof (FcCharLeaf *) + sizeof (FcChar16)));
-    printf ("Total:    %8s %8d %8s %8d\n", 
-	    "", 
-	    sizeof (FcCharLeaf) * FcCharLeafTotal +
-	    sizeof (FcCharSet) * FcCharSetTotal +
-	    FcCharSetTotalEnts * (sizeof (FcCharLeaf *) + sizeof (FcChar16)),
-	    "",
-	    sizeof (FcCharLeaf) * FcCharLeafUsed +
-	    sizeof (FcCharSet) * FcCharSetUsed +
-	    FcCharSetUsedEnts * (sizeof (FcCharLeaf *) + sizeof (FcChar16)));
-#endif
-    n = FcCharSetFreezeBase (c);
-bail1:
-    if (FcCharSetLeaves (c))
-    {
-	FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *));
-	free (FcCharSetLeaves (c));
-    }
-    if (FcCharSetNumbers (c))
-    {
-	FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16));
-	free (FcCharSetNumbers (c));
-    }
-    FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
-    free (c);
-bail0:
-    return n;
+    freezer = calloc (1, sizeof (FcCharSetFreezer));
+    return freezer;
 }
 
-FcBool
-FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
+void
+FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
 {
-    FcCharSetIter   ci;
-    int		    i;
-#ifdef CHECK
-    int		    len = buf->len;
-#endif
+    int i;
 
-    for (FcCharSetIterStart (c, &ci);
-	 ci.leaf;
-	 FcCharSetIterNext (c, &ci))
+    if (FcDebug() & FC_DBG_CACHE)
     {
-	if (!FcCharSetUnparseValue (buf, ci.ucs4))
-	    return FcFalse;
-	for (i = 0; i < 256/32; i++)
-	    if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
-		return FcFalse;
+	printf ("\ncharsets %d -> %d leaves %d -> %d\n",
+		freezer->charsets_seen, freezer->charsets_allocated,
+		freezer->leaves_seen, freezer->leaves_allocated);
     }
-#ifdef CHECK
+    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
     {
-	FcCharSet	*check;
-	FcChar32	missing;
-	FcCharSetIter	ci, checki;
-	
-	/* null terminate for parser */
-	FcStrBufChar (buf, '\0');
-	/* step back over null for life after test */
-	buf->len--;
-	check = FcNameParseCharSet (buf->buf + len);
-	FcCharSetIterStart (c, &ci);
-	FcCharSetIterStart (check, &checki);
-	while (ci.leaf || checki.leaf)
+	FcCharSetEnt	*ent, *next;
+	for (ent = freezer->set_hash_table[i]; ent; ent = next)
 	{
-	    if (ci.ucs4 < checki.ucs4)
-	    {
-		printf ("Missing leaf node at 0x%x\n", ci.ucs4);
-		FcCharSetIterNext (c, &ci);
-	    }
-	    else if (checki.ucs4 < ci.ucs4)
-	    {
-		printf ("Extra leaf node at 0x%x\n", checki.ucs4);
-		FcCharSetIterNext (check, &checki);
-	    }
-	    else
-	    {
-		int	    i = 256/32;
-		FcChar32    *cm = ci.leaf->map;
-		FcChar32    *checkm = checki.leaf->map;
+	    next = ent->next;
+	    free (ent);
+	}
+    }
 
-		for (i = 0; i < 256; i += 32)
-		{
-		    if (*cm != *checkm)
-			printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
-				ci.ucs4 + i, *cm, *checkm);
-		    cm++;
-		    checkm++;
-		}
-		FcCharSetIterNext (c, &ci);
-		FcCharSetIterNext (check, &checki);
-	    }
+    for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
+    {
+	FcCharSetOrigEnt	*ent, *next;
+	for (ent = freezer->orig_hash_table[i]; ent; ent = next)
+	{
+	    next = ent->next;
+	    free (ent);
 	}
-	if ((missing = FcCharSetSubtractCount (c, check)))
-	    printf ("%d missing in reparsed result\n", missing);
-	if ((missing = FcCharSetSubtractCount (check, c)))
-	    printf ("%d extra in reparsed result\n", missing);
-	FcCharSetDestroy (check);
     }
-#endif
-    
-    return FcTrue;
+
+    for (i = 0; i < freezer->leaf_block_count; i++)
+	free (freezer->leaf_blocks[i]);
+
+    free (freezer->leaf_blocks);
+    free (freezer);
 }
 
 FcBool
 FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
 {
-    intptr_t	    *leaves = FcCharSetLeaves (cs);
-    FcChar16	    *numbers = FcCharSetNumbers (cs);
+    intptr_t	    *leaves;
+    FcChar16	    *numbers;
     int		    i;
     
+    if (cs->ref != FC_REF_CONSTANT)
+    {
+	if (!serialize->cs_freezer)
+	{
+	    serialize->cs_freezer = FcCharSetFreezerCreate ();
+	    if (!serialize->cs_freezer)
+		return FcFalse;
+	}
+        cs = FcCharSetFreeze (serialize->cs_freezer, cs);
+    }
+    
+    leaves = FcCharSetLeaves (cs);
+    numbers = FcCharSetNumbers (cs);
+    
     if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
 	return FcFalse;
     if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
@@ -1285,12 +1301,20 @@ FcCharSetSerializeAlloc (FcSerialize *se
 FcCharSet *
 FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
 {
-    FcCharSet	*cs_serialized = FcSerializePtr (serialize, cs);
+    FcCharSet	*cs_serialized;
     intptr_t	*leaves, *leaves_serialized;
     FcChar16	*numbers, *numbers_serialized;
     FcCharLeaf	*leaf, *leaf_serialized;
     int		i;
 
+    if (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer)
+    {
+	cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
+	if (!cs)
+	    return NULL;
+    }
+		    
+    cs_serialized = FcSerializePtr (serialize, cs);
     if (!cs_serialized)
 	return NULL;
     
diff --git a/src/fcdir.c b/src/fcdir.c
index 3aeb4c9..0b7c8d8 100644
--- a/src/fcdir.c
+++ b/src/fcdir.c
@@ -85,12 +85,8 @@ FcFileScanConfig (FcFontSet	*set,
 		  FcStrSet	*dirs,
 		  FcBlanks	*blanks,
 		  const FcChar8	*file,
-		  FcBool	force,
 		  FcConfig	*config)
 {
-    if (config && !FcConfigAcceptFilename (config, file))
-	return FcTrue;
-
     if (FcFileIsDir (file))
 	return FcStrSetAdd (dirs, file);
     else
@@ -105,13 +101,12 @@ FcFileScan (FcFontSet	    *set,
 	    const FcChar8   *file,
 	    FcBool	    force)
 {
-    return FcFileScanConfig (set, dirs, blanks, file, force, 0);
+    return FcFileScanConfig (set, dirs, blanks, file, NULL);
 }
 
 /*
  * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
  */
-
 static int
 cmpstringp(const void *p1, const void *p2)
 {
@@ -119,62 +114,41 @@ cmpstringp(const void *p1, const void *p
 }
 
 /*
- * Scan 'dir', adding font files to 'set' and
- * subdirectories to 'dirs'
+ * Scan the specified directory and construct a cache of its contents
  */
-
-FcBool
-FcDirScanConfig (FcFontSet	*set,
-		 FcStrSet	*dirs,
-		 FcBlanks	*blanks,
-		 const FcChar8  *dir,
-		 FcBool		force,
-		 FcConfig	*config)
+FcCache *
+FcDirCacheScan (const FcChar8 *dir, FcConfig *config)
 {
     DIR			*d;
-    FcChar8		*canon_dir;
     struct dirent	*e;
-    FcStrSet		*dirlist, *filelist;
+    FcStrSet		*files;
+    FcStrSet		*dirs;
     FcChar8		*file;
     FcChar8		*base;
     FcBool		ret = FcTrue;
-    FcFontSet		*tmpSet;
+    FcFontSet		*set;
     int			i;
+    FcBlanks		*blanks = FcConfigGetBlanks (config);
+    FcCache		*cache = NULL;
 
-    canon_dir = FcStrCanonFilename (dir);
-    if (!canon_dir) canon_dir = (FcChar8 *) dir;
-    
-    if (config && !FcConfigAcceptFilename (config, canon_dir)) {
-	ret = FcTrue;
-	goto bail;
-    }
-
-    if (!force)
-    {
-	if (FcDirCacheRead (set, dirs, canon_dir, config)) {
-	    ret = FcTrue;
-	    goto bail;
-	}
-    }
-    
     if (FcDebug () & FC_DBG_FONTSET)
-    	printf ("cache scan dir %s\n", canon_dir);
+    	printf ("cache scan dir %s\n", dir);
 
     /* freed below */
-    file = (FcChar8 *) malloc (strlen ((char *) canon_dir) + 1 + FC_MAX_FILE_LEN + 1);
+    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
     if (!file) {
 	ret = FcFalse;
 	goto bail;
     }
 
-    strcpy ((char *) file, (char *) canon_dir);
+    strcpy ((char *) file, (char *) dir);
     strcat ((char *) file, "/");
     base = file + strlen ((char *) file);
     
     if (FcDebug () & FC_DBG_SCAN)
-	printf ("\tScanning dir %s\n", canon_dir);
+	printf ("\tScanning dir %s\n", dir);
 	
-    d = opendir ((char *) canon_dir);
+    d = opendir ((char *) dir);
     if (!d)
     {
 	/* Don't complain about missing directories */
@@ -185,84 +159,64 @@ FcDirScanConfig (FcFontSet	*set,
 	goto bail_1;
     }
 
-    tmpSet = FcFontSetCreate();
-    if (!tmpSet) 
+    set = FcFontSetCreate();
+    if (!set) 
     {
 	ret = FcFalse;
 	goto bail0;
     }
 
-    dirlist = FcStrSetCreate ();
-    if (!dirlist) 
+    files = FcStrSetCreate ();
+    if (!files)
     {
 	ret = FcFalse;
 	goto bail1;
     }
-    filelist = FcStrSetCreate ();
-    if (!filelist)
-    {
-	ret = FcFalse;
-	goto bail2;
-    }
     while ((e = readdir (d)))
     {
 	if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
 	{
 	    strcpy ((char *) base, (char *) e->d_name);
-	    if (FcFileIsDir (file)) {
-		if (!FcStrSetAdd (dirlist, file)) {
-		    ret = FcFalse;
-		    goto bail3;
-		}
-	    } else {
-		if (!FcStrSetAdd (filelist, file)) {
-		    ret = FcFalse;
-		    goto bail3;
-		}
+	    if (!FcStrSetAdd (files, file)) {
+		ret = FcFalse;
+		goto bail2;
 	    }
 	}
     }
+
     /*
-     * Sort files and dirs to make things prettier
+     * Sort files to make things prettier
      */
-    qsort(dirlist->strs, dirlist->num, sizeof(FcChar8 *), cmpstringp);
-    qsort(filelist->strs, filelist->num, sizeof(FcChar8 *), cmpstringp);
+    qsort(files->strs, files->num, sizeof(FcChar8 *), cmpstringp);
     
-    for (i = 0; i < filelist->num; i++)
-	FcFileScanFontConfig (tmpSet, blanks, filelist->strs[i], config);
+    dirs = FcStrSetCreate ();
+    if (!dirs)
+	goto bail2;
     
     /*
-     * Now that the directory has been scanned,
-     * write out the cache file
+     * Scan file files to build font patterns
      */
-    FcDirCacheWrite (tmpSet, dirlist, canon_dir, config);
-
-    /*
-     * Add the discovered fonts to our internal non-cache list
-     */
-    for (i = 0; i < tmpSet->nfont; i++)
-	FcFontSetAdd (set, tmpSet->fonts[i]);
-
+    for (i = 0; i < files->num; i++)
+	FcFileScanConfig (set, dirs, blanks, files->strs[i], config);
+    
     /*
-     * the patterns in tmpset now belong to set; don't free them 
+     * Build the cache object
      */
-    tmpSet->nfont = 0;
-
+    cache = FcDirCacheBuild (set, dir, dirs);
+    if (!cache)
+	goto bail3;
+    
     /*
-     * Add the discovered directories to the list to be scanned
+     * Write out the cache file, ignoring any troubles
      */
-    for (i = 0; i < dirlist->num; i++)
-	if (!FcStrSetAdd (dirs, dirlist->strs[i])) {
-	    ret = FcFalse;
-	    goto bail3;
-	}
+    FcDirCacheWrite (cache, config);
     
  bail3:
-    FcStrSetDestroy (filelist);
+    FcStrSetDestroy (dirs);
  bail2:
-    FcStrSetDestroy (dirlist);
+    FcStrSetDestroy (files);
  bail1:
-    FcFontSetDestroy (tmpSet);
+    FcFontSetDestroy (set);
     
  bail0:
     closedir (d);
@@ -270,8 +224,49 @@ FcDirScanConfig (FcFontSet	*set,
  bail_1:
     free (file);
  bail:
-    if (canon_dir != dir) free (canon_dir);
-    return ret;
+    return cache;
+}
+
+/*
+ * Read (or construct) the cache for a directory
+ */
+FcCache *
+FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config)
+{
+    FcCache		*cache = NULL;
+    FcChar8		*canon_dir;
+
+    canon_dir = FcStrCanonFilename (dir);
+    if (!canon_dir) canon_dir = (FcChar8 *) dir;
+    
+    if (config && !FcConfigAcceptFilename (config, canon_dir)) {
+	goto bail;
+    }
+
+    /* Try to use existing cache file */
+    if (!force)
+	cache = FcDirCacheLoad (canon_dir, config, NULL);
+    
+    /* Not using existing cache file, construct new cache */
+    if (!cache)
+	cache = FcDirCacheScan (canon_dir, config);
+    
+bail:
+    if (canon_dir != dir) 
+	free (canon_dir);
+    
+    return cache;
+}
+
+FcBool
+FcDirScanConfig (FcFontSet	*set,
+		 FcStrSet	*dirs,
+		 FcBlanks	*blanks,
+		 const FcChar8	*dir,
+		 FcBool		force,
+		 FcConfig	*config)
+{
+    return FcFalse; /* XXX fixme */
 }
 
 FcBool
@@ -282,11 +277,11 @@ FcDirScan (FcFontSet	    *set,
 	   const FcChar8    *dir,
 	   FcBool	    force)
 {
-    return FcDirScanConfig (set, dirs, blanks, dir, force, 0);
+    return FcDirScanConfig (set, dirs, blanks, dir, force, NULL);
 }
 
 FcBool
 FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
 {
-    return FcFalse;
+    return FcFalse; /* XXX deprecated */
 }
diff --git a/src/fcinit.c b/src/fcinit.c
index 8f60cd8..65702b4 100644
--- a/src/fcinit.c
+++ b/src/fcinit.c
@@ -121,7 +121,6 @@ FcFini (void)
 	FcConfigDestroy (_fcConfig);
 
     FcPatternFini ();
-    FcCharSetThawAll ();
 }
 
 /*
diff --git a/src/fcint.h b/src/fcint.h
index 0bc5df2..ce0ac7c 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -55,7 +55,6 @@
 
 #define FC_FONT_FILE_INVALID	((FcChar8 *) ".")
 #define FC_FONT_FILE_DIR	((FcChar8 *) ".dir")
-#define FC_GLOBAL_MAGIC_COOKIE	"GLOBAL"
 
 #ifdef _WIN32
 #define FC_SEARCH_PATH_SEPARATOR ';'
@@ -75,6 +74,7 @@
 #define FC_DBG_MEMORY	512
 #define FC_DBG_CONFIG	1024
 #define FC_DBG_LANGSET	2048
+#define FC_DBG_OBJTYPES	4096
 
 #define FC_MEM_CHARSET	    0
 #define FC_MEM_CHARLEAF	    1
@@ -307,7 +307,8 @@ typedef struct _FcStrBuf {
 } FcStrBuf;
 
 typedef struct _FcCache {
-    int		magic;              /* FC_CACHE_MAGIC */
+    int		magic;              /* FC_CACHE_MAGIC_MMAP or FC_CACHE_ALLOC */
+    int		version;	    /* FC_CACHE_CONTENT_VERSION */
     intptr_t	size;		    /* size of file */
     intptr_t	dir;		    /* offset to dir name */
     intptr_t	dirs;		    /* offset to subdirs */
@@ -318,6 +319,9 @@ typedef struct _FcCache {
 #define FcCacheDir(c)	FcOffsetMember(c,dir,FcChar8)
 #define FcCacheDirs(c)	FcOffsetMember(c,dirs,intptr_t)
 #define FcCacheSet(c)	FcOffsetMember(c,set,FcFontSet)
+#define FcCacheSubdir(c,i)  FcOffsetToPtr (FcCacheDirs(cache),\
+					   FcCacheDirs(cache)[i], \
+					   FcChar8)
 
 /*
  * Used while constructing a directory cache object
@@ -331,8 +335,11 @@ typedef struct _FcSerializeBucket {
     intptr_t	offset;
 } FcSerializeBucket;
 
+typedef struct _FcCharSetFreezer FcCharSetFreezer;
+
 typedef struct _FcSerialize {
     intptr_t		size;
+    FcCharSetFreezer	*cs_freezer;
     void		*linear;
     FcSerializeBucket	*buckets[FC_SERIALIZE_HASH_SIZE];
 } FcSerialize;
@@ -389,8 +396,9 @@ typedef struct _FcCaseFold {
 
 #define fc_alignof(type) offsetof (struct { char c; type member; }, member)
 
-#define FC_CACHE_MAGIC	    0xFC02FC04
-#define FC_CACHE_MAGIC_COPY 0xFC02FC05
+#define FC_CACHE_MAGIC_MMAP	    0xFC02FC04
+#define FC_CACHE_MAGIC_ALLOC	    0xFC02FC05
+#define FC_CACHE_CONTENT_VERSION    1
 
 struct _FcAtomic {
     FcChar8	*file;		/* original file name */
@@ -490,31 +498,30 @@ typedef struct _FcCharMap FcCharMap;
 
 /* fccache.c */
 
-FcFontSet *
-FcCacheRead (FcConfig *config);
-
 FcBool
-FcDirCacheWrite (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir, FcConfig *config);
+FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config);
 
-FcBool
-FcDirCacheConsume (FILE *file, FcFontSet *set, FcStrSet *dirs,
-		   const FcChar8 *dir, char *dirname);
-    
 void
-FcDirCacheUnmap (FcCache *cache);
+FcDirCacheUnload (FcCache *cache);
 
-FcBool
-FcDirCacheRead (FcFontSet * set, FcStrSet * dirs, const FcChar8 *dir, FcConfig *config);
- 
 FcCache *
-FcDirCacheMap (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file);
-    
-FcBool
-FcDirCacheLoad (int fd, off_t size, void *closure);
+FcDirCacheScan (const FcChar8 *dir, FcConfig *config);
+
+FcCache *
+FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file);
     
+FcCache *
+FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat);
+
 FcBool
-FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config);
+FcDirCacheValid (const FcChar8 *dir);
 
+FcCache *
+FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, FcStrSet *dirs);
+
+FcBool
+FcDirCacheWrite (FcCache *cache, FcConfig *config);
+    
 /* fccfg.c */
 
 FcBool
@@ -616,11 +623,8 @@ FcLangSetSerialize(FcSerialize *serializ
 void
 FcLangCharSetPopulate (void);
 
-FcCharSet *
-FcCharSetFreeze (FcCharSet *cs);
-
 void
-FcCharSetThawAll (void);
+FcCharSetFreezerDestroy (FcCharSetFreezer *freezer);
 
 FcBool
 FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c);
@@ -687,17 +691,19 @@ FcFileScanConfig (FcFontSet	*set,
 		  FcStrSet	*dirs,
 		  FcBlanks	*blanks,
 		  const FcChar8 *file,
-		  FcBool	force,
 		  FcConfig	*config);
 
 FcBool
 FcDirScanConfig (FcFontSet	*set,
 		 FcStrSet	*dirs,
 		 FcBlanks	*blanks,
-		 const FcChar8  *dir,
+		 const FcChar8	*dir,
 		 FcBool		force,
 		 FcConfig	*config);
 
+FcCache *
+FcDirCacheRead (const FcChar8 *dir, FcBool force, FcConfig *config);
+
 /* fcfont.c */
 int
 FcFontDebug (void);
diff --git a/src/fcpat.c b/src/fcpat.c
index b40d3c0..9cd01a0 100644
--- a/src/fcpat.c
+++ b/src/fcpat.c
@@ -491,7 +491,15 @@ FcPatternObjectAddWithBinding  (FcPatter
      * Make sure the stored type is valid for built-in objects
      */
     if (!FcObjectValidType (object, value.type))
+    {
+	if (FcDebug() & FC_DBG_OBJTYPES)
+	{
+	    printf ("FcPattern object %s does not accept value ",
+		    FcObjectName (object));
+	    FcValuePrint (value);
+	}
 	goto bail1;
+    }
 
     new->value = value;
     new->binding = binding;
diff --git a/src/fcserialize.c b/src/fcserialize.c
index a8c10b8..d0d35e3 100644
--- a/src/fcserialize.c
+++ b/src/fcserialize.c
@@ -54,6 +54,7 @@ FcSerializeCreate (void)
 	return NULL;
     serialize->size = 0;
     serialize->linear = NULL;
+    serialize->cs_freezer = NULL;
     memset (serialize->buckets, '\0', sizeof (serialize->buckets));
     return serialize;
 }
@@ -72,6 +73,8 @@ FcSerializeDestroy (FcSerialize *seriali
 	    free (buck);
 	}
     }
+    if (serialize->cs_freezer)
+	FcCharSetFreezerDestroy (serialize->cs_freezer);
     free (serialize);
 }
 
diff-tree aec8c90b450c115718fd87bc270e35ee6b605967 (from 551b6b2cd7d94dd90a9eb22bdb752f264afc48ce)
Author: Keith Packard <keithp at neko.keithp.com>
Date:   Fri Sep 1 01:12:13 2006 -0700

    Remove stale architecture signatures.
    
    All but x86 are known to be wrong.

diff --git a/fc-arch/fcarch.tmpl.h b/fc-arch/fcarch.tmpl.h
index b0712e5..5b0afbc 100644
--- a/fc-arch/fcarch.tmpl.h
+++ b/fc-arch/fcarch.tmpl.h
@@ -29,7 +29,6 @@
 @@@ use something reasonable and don't include any spaces
 @@@
 @@@ name    endian   char     char*    int      intptr_t Pattern  EltPtr   Elt *    Elt      ObjPtr   VLPtr    Value    Binding  VL *     CharSet  Leaf**   Char16 * Char16   Leaf     Char32   Cache
-x86	    78563412_00000001_00000004_00000004_00000004_00000010_00000004_00000004_00000008_00000004_00000004_0000000c_00000004_00000004_00000010_00000004_00000004_00000002_00000020_00000004_00000018
-x86-64	    78563412_00000001_00000008_00000004_00000020_00000010_00000008_00000018_00000004_00000010_00000010_00000004_00000008_00000020_00000008_00000008_00000002_00000020_00000004_00000040_00001000
-ppc-4k	    12345678_00000001_00000004_00000004_00000018_00000008_00000004_0000000c_00000004_00000008_00000010_00000004_00000004_00000014_00000004_00000004_00000002_00000020_00000004_00000038_00001000
-ppc-64k     12345678_00000001_00000004_00000004_00000018_00000008_00000004_0000000c_00000004_00000008_00000010_00000004_00000004_00000014_00000004_00000004_00000002_00000020_00000004_00000038_00010000
+x86	    78563412_00000001_00000004_00000004_00000004_00000010_00000004_00000004_00000008_00000004_00000004_0000000c_00000004_00000004_00000010_00000004_00000004_00000002_00000020_00000004_0000001c
+x86-64	    78563412
+ppc	    12345678


More information about the Fontconfig mailing list