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 *config, char *program, FcBool force, FcBool { if (verbose) { - printf ("%s: \"%s\": ", program, dir); + printf ("%s: ", dir); fflush (stdout); } @@ -164,22 +166,6 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool 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 *config, char *program, FcBool force, FcBool 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 *config, char *program, FcBool force, FcBool perror (""); ret++; - FcFontSetDestroy (set); - FcStrSetDestroy (subdirs); continue; } } @@ -210,44 +192,50 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool { 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); - - if (!FcDirScanConfig (set, subdirs, FcConfigGetBlanks (config), dir, force, config)) - { - fprintf (stderr, "%s: error scanning\n", dir); - FcFontSetDestroy (set); - FcStrSetDestroy (subdirs); - ret++; - continue; + cache = NULL; + was_valid = FcFalse; + if (!force) { + cache = FcDirCacheLoad (dir, config, NULL); + if (cache) + was_valid = FcTrue; } - if (!force && was_valid) + + if (!cache) + { + cache = FcDirCacheRead (dir, FcTrue, config); + if (!cache) + { + fprintf (stderr, "%s: error scanning\n", dir); + ret++; + continue; + } + } + + 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 *config, char *program, FcBool force, FcBool 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, FcChar8 *dir, FcBool verbose) 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, FcChar8 *dir, FcBool verbose) 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 FcChar8 *chars) } 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 long t) } 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 FcChar8 *file) 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, FcStrSet *dirs, char *base_name, FcBool verbose 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, FcStrSet *dirs, char *base_name, FcBool verbose 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, FcConfig *config) } 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, const FcChar8 *dir, 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, const FcChar8 *dir, 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; -#if defined(HAVE_MMAP) || defined(__CYGWIN__) - cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0); -#elif defined(_WIN32) + return NULL; + /* + * For small cache files, just read them into memory + */ + if (size >= FC_CACHE_MIN_MMAP) { - HANDLE hFileMap; - - cache = NULL; - hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL, - PAGE_READONLY, 0, 0, NULL); - if (hFileMap != NULL) +#if defined(HAVE_MMAP) || defined(__CYGWIN__) + cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0); +#elif defined(_WIN32) { - 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 *closure) 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, void *closure) 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.magic != FC_CACHE_MAGIC) + else if (c.version != FC_CACHE_CONTENT_VERSION) + ret = FcFalse; + 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, void *closure) 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 FcChar8 *dir, FcStrSet *dirs) 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, FcStrSet *dirs, const FcChar8 *dir, FcConfig *c 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, FcStrSet *dirs, const FcChar8 *dir, FcConfig *c 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, FcStrSet *dirs, const FcChar8 *dir, FcConfig *c 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, FcStrSet *dirs, const FcChar8 *dir, FcConfig *c 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); } @@ -230,87 +230,121 @@ FcConfigDestroy (FcConfig *config) FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig)); } +/* + * Add cache to configuration, adding fonts and directories + */ + +FcBool +FcConfigAddCache (FcConfig *config, FcCache *cache) +{ + 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; + + /* + * Add fonts + */ + fs = FcCacheSet (cache); + if (fs) + { + for (i = 0; i < fs->nfont; i++) + { + 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); + } + } + + /* + * 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; +} + /* * 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 + * and build the set of available fonts. */ FcBool FcConfigBuildFonts (FcConfig *config) { - FcFontSet *fonts, *cached_fonts; - FcStrList *list; - FcStrSet *oldDirs; + FcFontSet *fonts; + FcStrList *dirlist; FcChar8 *dir; + FcCache *cache; + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return FcFalse; + } + fonts = FcFontSetCreate (); if (!fonts) - goto bail0; + goto bail; - oldDirs = FcStrSetCreate (); - if (!oldDirs) - goto bail2; - - cached_fonts = FcCacheRead(config); - if (!cached_fonts) - { - list = FcConfigGetFontDirs (config); - if (!list) - goto bail3; + FcConfigSetFonts (config, fonts, FcSetSystem); + + dirlist = FcStrListCreate (config->fontDirs); + if (!dirlist) + goto bail; - while ((dir = FcStrListNext (list))) - { - if (FcDebug () & FC_DBG_FONTSET) - printf ("build scan dir %s\n", dir); - FcDirScanConfig (fonts, config->fontDirs, - config->blanks, dir, FcFalse, config); - } - - FcStrListDone (list); - } - else + while ((dir = FcStrListNext (dirlist))) { - 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); - } - - for (i = 0; i < cached_fonts->nfont; i++) - { - FcChar8 *cfn; - FcPattern *font = cached_fonts->fonts[i]; - FcPatternObjectGetString (font, FC_FILE_OBJECT, 0, &cfn); - - if (FcConfigAcceptFont (config, font) && - (cfn && FcConfigAcceptFilename (config, cfn))) - FcFontSetAdd (fonts, font); - - cached_fonts->fonts[i] = 0; /* prevent free in FcFontSetDestroy */ - } - cached_fonts->nfont = 0; - FcFontSetDestroy (cached_fonts); + 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 *config, 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, FcCharSetIter *iter) } 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, FcCharSetIter *iter) } } -#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,271 +830,10 @@ FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value) return FcTrue; } -typedef struct _FcCharLeafEnt FcCharLeafEnt; - -struct _FcCharLeafEnt { - FcCharLeafEnt *next; - FcChar32 hash; - FcCharLeaf leaf; -}; - -#define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt)) -static FcCharLeafEnt **FcCharLeafBlocks; -static int FcCharLeafBlockCount; - -static FcCharLeafEnt * -FcCharLeafEntCreate (void) -{ - static FcCharLeafEnt *block; - static int remain; - - if (!remain) - { - FcCharLeafEnt **newBlocks; - - FcCharLeafBlockCount++; - newBlocks = realloc (FcCharLeafBlocks, FcCharLeafBlockCount * sizeof (FcCharLeafEnt *)); - if (!newBlocks) - return 0; - FcCharLeafBlocks = newBlocks; - block = FcCharLeafBlocks[FcCharLeafBlockCount-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt)); - if (!block) - return 0; - FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt)); - remain = FC_CHAR_LEAF_BLOCK; - } - remain--; - return block++; -} - -#define FC_CHAR_LEAF_HASH_SIZE 257 - -static FcChar32 -FcCharLeafHash (FcCharLeaf *leaf) -{ - FcChar32 hash = 0; - int i; - - for (i = 0; i < 256/32; i++) - hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i]; - return hash; -} - -static int FcCharLeafTotal; -static int FcCharLeafUsed; - -static FcCharLeafEnt *FcCharLeafHashTable[FC_CHAR_LEAF_HASH_SIZE]; - -static FcCharLeaf * -FcCharSetFreezeLeaf (FcCharLeaf *leaf) -{ - FcChar32 hash = FcCharLeafHash (leaf); - FcCharLeafEnt **bucket = &FcCharLeafHashTable[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(); - if (!ent) - return 0; - FcCharLeafUsed++; - ent->leaf = *leaf; - ent->hash = hash; - ent->next = *bucket; - *bucket = ent; - 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) -{ - FcChar32 hash = 0; - int i; - - /* hash in leaves */ - for (i = 0; i < fcs->num * (int) (sizeof (FcCharLeaf *) / sizeof (FcChar32)); i++) - hash = ((hash << 1) | (hash >> 31)) ^ (FcChar32)(FcCharSetLeaf(fcs, i)->map); - /* hash in numbers */ - for (i = 0; i < fcs->num; i++) - hash = ((hash << 1) | (hash >> 31)) ^ *FcCharSetNumbers(fcs); - return hash; -} - -static int FcCharSetTotal; -static int FcCharSetUsed; -static int FcCharSetTotalEnts, FcCharSetUsedEnts; - -static FcCharSetEnt *FcCharSetHashTable[FC_CHAR_SET_HASH_SIZE]; - -static FcCharSet * -FcCharSetFreezeBase (FcCharSet *fcs) -{ - FcChar32 hash = FcCharSetHash (fcs); - FcCharSetEnt **bucket = &FcCharSetHashTable[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 && - ent->set.num == fcs->num && - !memcmp (FcCharSetNumbers(&ent->set), - FcCharSetNumbers(fcs), - fcs->num * sizeof (FcChar16))) - { - FcBool ok = FcTrue; - int i; - - for (i = 0; i < fcs->num; i++) - if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i)) - ok = FcFalse; - if (ok) - return &ent->set; - } - } - - size = (sizeof (FcCharSetEnt) + - fcs->num * sizeof (FcCharLeaf *) + - fcs->num * sizeof (FcChar16)); - ent = malloc (size); - if (!ent) - return 0; - FcMemAlloc (FC_MEM_CHARSET, size); - FcCharSetUsed++; - FcCharSetUsedEnts += fcs->num; - - ent->set.ref = FC_REF_CONSTANT; - ent->set.num = fcs->num; - if (fcs->num) - { - intptr_t *ent_leaves; - - ent->set.leaves_offset = sizeof (ent->set); - ent->set.numbers_offset = (ent->set.leaves_offset + - fcs->num * sizeof (intptr_t)); - - ent_leaves = FcCharSetLeaves (&ent->set); - for (i = 0; i < fcs->num; i++) - ent_leaves[i] = FcPtrToOffset (ent_leaves, - FcCharSetLeaf (fcs, i)); - memcpy (FcCharSetNumbers (&ent->set), - FcCharSetNumbers (fcs), - fcs->num * sizeof (FcChar16)); - } - else - { - ent->set.leaves_offset = 0; - ent->set.numbers_offset = 0; - } - - ent->hash = hash; - ent->next = *bucket; - *bucket = ent; - return &ent->set; -} - -void -FcCharSetThawAll (void) -{ - 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 (); -} - -FcCharSet * -FcCharSetFreeze (FcCharSet *fcs) -{ - FcCharSet *b; - FcCharSet *n = 0; - FcCharLeaf *l; - int i; - - b = FcCharSetCreate (); - if (!b) - goto bail0; - for (i = 0; i < fcs->num; i++) - { - l = FcCharSetFreezeLeaf (FcCharSetLeaf(fcs, i)); - if (!l) - goto bail1; - if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l)) - goto bail1; - } - n = FcCharSetFreezeBase (b); -bail1: - if (FcCharSetLeaves (b)) - { - FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *)); - free (FcCharSetLeaves (b)); - } - if (FcCharSetNumbers (b)) - { - FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16)); - free (FcCharSetNumbers (b)); - } - FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet)); - free (b); -bail0: - return n; -} - FcCharSet * FcNameParseCharSet (FcChar8 *string) { - FcCharSet *c, *n = 0; + FcCharSet *c; FcChar32 ucs4; FcCharLeaf *leaf; FcCharLeaf temp; @@ -1143,42 +858,22 @@ FcNameParseCharSet (FcChar8 *string) } if (bits) { - leaf = FcCharSetFreezeLeaf (&temp); + leaf = malloc (sizeof (FcCharLeaf)); if (!leaf) goto bail1; + *leaf = temp; 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); + return c; bail1: - if (FcCharSetLeaves (c)) + if (c->num) { FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *)); free (FcCharSetLeaves (c)); } - if (FcCharSetNumbers (c)) + if (c->num) { FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16)); free (FcCharSetNumbers (c)); @@ -1186,7 +881,7 @@ bail1: FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet)); free (c); bail0: - return n; + return NULL; } FcBool @@ -1262,13 +957,334 @@ FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c) return FcTrue; } +typedef struct _FcCharLeafEnt FcCharLeafEnt; + +struct _FcCharLeafEnt { + FcCharLeafEnt *next; + FcChar32 hash; + FcCharLeaf leaf; +}; + +#define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt)) +#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 (FcCharSetFreezer *freezer) +{ + if (!freezer->leaf_remain) + { + FcCharLeafEnt **newBlocks; + + freezer->leaf_block_count++; + newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *)); + if (!newBlocks) + return 0; + 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)); + freezer->leaf_remain = FC_CHAR_LEAF_BLOCK; + } + freezer->leaf_remain--; + freezer->leaves_allocated++; + return freezer->current_block++; +} + +static FcChar32 +FcCharLeafHash (FcCharLeaf *leaf) +{ + FcChar32 hash = 0; + int i; + + for (i = 0; i < 256/32; i++) + hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i]; + return hash; +} + +static FcCharLeaf * +FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf) +{ + FcChar32 hash = FcCharLeafHash (leaf); + FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE]; + FcCharLeafEnt *ent; + + for (ent = *bucket; ent; ent = ent->next) + { + if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf))) + return &ent->leaf; + } + + ent = FcCharLeafEntCreate(freezer); + if (!ent) + return 0; + ent->leaf = *leaf; + ent->hash = hash; + ent->next = *bucket; + *bucket = ent; + return &ent->leaf; +} + +static FcChar32 +FcCharSetHash (FcCharSet *fcs) +{ + FcChar32 hash = 0; + int i; + + /* hash in leaves */ + for (i = 0; i < fcs->num * (int) (sizeof (FcCharLeaf *) / sizeof (FcChar32)); i++) + hash = ((hash << 1) | (hash >> 31)) ^ (FcChar32)(FcCharSetLeaf(fcs, i)->map); + /* hash in numbers */ + for (i = 0; i < fcs->num; i++) + hash = ((hash << 1) | (hash >> 31)) ^ *FcCharSetNumbers(fcs); + return hash; +} + +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 (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig) +{ + FcChar32 hash = FcCharSetHash (fcs); + FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE]; + FcCharSetEnt *ent; + int size; + int i; + + for (ent = *bucket; ent; ent = ent->next) + { + if (ent->hash == hash && + ent->set.num == fcs->num && + !memcmp (FcCharSetNumbers(&ent->set), + FcCharSetNumbers(fcs), + fcs->num * sizeof (FcChar16))) + { + FcBool ok = FcTrue; + int i; + + for (i = 0; i < fcs->num; i++) + if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i)) + ok = FcFalse; + if (ok) + return &ent->set; + } + } + + size = (sizeof (FcCharSetEnt) + + fcs->num * sizeof (FcCharLeaf *) + + fcs->num * sizeof (FcChar16)); + ent = malloc (size); + if (!ent) + return 0; + FcMemAlloc (FC_MEM_CHARSET, size); + + freezer->charsets_allocated++; + + ent->set.ref = FC_REF_CONSTANT; + ent->set.num = fcs->num; + if (fcs->num) + { + intptr_t *ent_leaves; + + ent->set.leaves_offset = sizeof (ent->set); + ent->set.numbers_offset = (ent->set.leaves_offset + + fcs->num * sizeof (intptr_t)); + + ent_leaves = FcCharSetLeaves (&ent->set); + for (i = 0; i < fcs->num; i++) + ent_leaves[i] = FcPtrToOffset (ent_leaves, + FcCharSetLeaf (fcs, i)); + memcpy (FcCharSetNumbers (&ent->set), + FcCharSetNumbers (fcs), + fcs->num * sizeof (FcChar16)); + } + else + { + ent->set.leaves_offset = 0; + ent->set.numbers_offset = 0; + } + + ent->hash = hash; + ent->next = *bucket; + *bucket = ent; + + return &ent->set; +} + +static const FcCharSet * +FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig) +{ + 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; +} + +static const FcCharSet * +FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs) +{ + 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 (freezer, FcCharSetLeaf(fcs, i)); + if (!l) + goto bail1; + if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l)) + goto bail1; + } + n = FcCharSetFreezeBase (freezer, b, fcs); + if (!FcCharSetFreezeOrig (freezer, fcs, n)) + { + n = NULL; + goto bail1; + } + freezer->charsets_seen++; + freezer->leaves_seen += fcs->num; +bail1: + if (b->num) + { + FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *)); + free (FcCharSetLeaves (b)); + } + if (b->num) + { + FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16)); + free (FcCharSetNumbers (b)); + } + FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet)); + free (b); +bail0: + return n; +} + +static FcCharSetFreezer * +FcCharSetFreezerCreate (void) +{ + FcCharSetFreezer *freezer; + + freezer = calloc (1, sizeof (FcCharSetFreezer)); + return freezer; +} + +void +FcCharSetFreezerDestroy (FcCharSetFreezer *freezer) +{ + int i; + + if (FcDebug() & FC_DBG_CACHE) + { + printf ("\ncharsets %d -> %d leaves %d -> %d\n", + freezer->charsets_seen, freezer->charsets_allocated, + freezer->leaves_seen, freezer->leaves_allocated); + } + for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++) + { + FcCharSetEnt *ent, *next; + for (ent = freezer->set_hash_table[i]; ent; ent = next) + { + next = ent->next; + free (ent); + } + } + + 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); + } + } + + 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 *serialize, const FcCharSet *cs) 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 *p2) } /* - * 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); - + for (i = 0; i < files->num; i++) + FcFileScanConfig (set, dirs, blanks, files->strs[i], config); + /* - * Add the discovered fonts to our internal non-cache list + * Build the cache object */ - for (i = 0; i < tmpSet->nfont; i++) - FcFontSetAdd (set, tmpSet->fonts[i]); - + cache = FcDirCacheBuild (set, dir, dirs); + if (!cache) + goto bail3; + /* - * the patterns in tmpset now belong to set; don't free them + * Write out the cache file, ignoring any troubles */ - tmpSet->nfont = 0; - - /* - * Add the discovered directories to the list to be scanned - */ - 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); - -FcBool -FcDirCacheConsume (FILE *file, FcFontSet *set, FcStrSet *dirs, - const FcChar8 *dir, char *dirname); - -void -FcDirCacheUnmap (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); - FcBool FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config); +void +FcDirCacheUnload (FcCache *cache); + +FcCache * +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 +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 *serialize, const FcLangSet *l); 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 (FcPattern *p, * 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 *serialize) free (buck); } } + if (serialize->cs_freezer) + FcCharSetFreezerDestroy (serialize->cs_freezer); free (serialize); }