diff -pruN fontconfig-2.13.0.orig/src/fccache.c fontconfig-2.13.0/src/fccache.c --- fontconfig-2.13.0.orig/src/fccache.c 2017-12-18 21:45:13.000000000 +0900 +++ fontconfig-2.13.0/src/fccache.c 2018-06-08 18:39:33.079539192 +0900 @@ -51,13 +51,23 @@ FcDirCacheCreateUUID (FcChar8 *dir, FcBool force, FcConfig *config) { + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *target; FcBool ret = FcTrue; #ifndef _WIN32 FcChar8 *uuidname; - uuidname = FcStrBuildFilename (dir, ".uuid", NULL); + if (sysroot) + target = FcStrBuildFilename (sysroot, dir, NULL); + else + target = FcStrdup (dir); + uuidname = FcStrBuildFilename (target, ".uuid", NULL); + if (!uuidname) + { + FcStrFree (target); return FcFalse; + } if (force || access ((const char *) uuidname, F_OK) < 0) { @@ -69,7 +79,7 @@ FcDirCacheCreateUUID (FcChar8 *dir, struct stat statb; struct timeval times[2]; - if (FcStat (dir, &statb) != 0) + if (FcStat (target, &statb) != 0) { ret = FcFalse; goto bail1; @@ -96,7 +106,7 @@ FcDirCacheCreateUUID (FcChar8 *dir, hash_add = FcHashTableReplace; else hash_add = FcHashTableAdd; - if (!hash_add (config->uuid_table, dir, uuid)) + if (!hash_add (config->uuid_table, target, uuid)) { ret = FcFalse; goto bail3; @@ -124,14 +134,15 @@ FcDirCacheCreateUUID (FcChar8 *dir, times[0].tv_usec = 0; times[1].tv_usec = 0; #endif - if (utimes ((const char *) dir, times) != 0) + if (utimes ((const char *) target, times) != 0) { - fprintf (stderr, "Unable to revert mtime: %s\n", dir); + fprintf (stderr, "Unable to revert mtime: %s\n", target); } } } - bail1: +bail1: FcStrFree (uuidname); + FcStrFree (target); #endif return ret; @@ -144,10 +155,17 @@ FcDirCacheReadUUID (FcChar8 *dir, { void *u; uuid_t uuid; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *target; - if (!FcHashTableFind (config->uuid_table, dir, &u)) + if (sysroot) + target = FcStrBuildFilename (sysroot, dir, NULL); + else + target = FcStrdup (dir); + + if (!FcHashTableFind (config->uuid_table, target, &u)) { - FcChar8 *uuidname = FcStrBuildFilename (dir, ".uuid", NULL); + FcChar8 *uuidname = FcStrBuildFilename (target, ".uuid", NULL); int fd; if ((fd = FcOpen ((char *) uuidname, O_RDONLY)) >= 0) @@ -162,7 +180,7 @@ FcDirCacheReadUUID (FcChar8 *dir, { if (FcDebug () & FC_DBG_CACHE) printf ("FcDirCacheReadUUID %s -> %s\n", uuidname, suuid); - FcHashTableAdd (config->uuid_table, dir, uuid); + FcHashTableAdd (config->uuid_table, target, uuid); } } close (fd); @@ -176,6 +194,7 @@ FcDirCacheReadUUID (FcChar8 *dir, } else FcHashUuidFree (u); + FcStrFree (target); } #endif @@ -259,19 +278,22 @@ static FcChar8 * FcDirCacheBasenameUUID (const FcChar8 *dir, FcChar8 cache_base[CACHEBASE_LEN], FcConfig *config) { void *u; - FcChar8 *alias; + FcChar8 *target; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); - if (!FcHashTableFind (config->alias_table, dir, (void **)&alias)) - alias = FcStrdup (dir); - if (FcHashTableFind (config->uuid_table, alias, &u)) + if (sysroot) + target = FcStrBuildFilename (sysroot, dir, NULL); + else + target = FcStrdup (dir); + if (FcHashTableFind (config->uuid_table, target, &u)) { uuid_unparse (u, (char *) cache_base); strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX); FcHashUuidFree (u); - FcStrFree (alias); + FcStrFree (target); return cache_base; } - FcStrFree (alias); + FcStrFree (target); return NULL; } #endif @@ -417,6 +439,7 @@ struct _FcCacheSkip { FcCache *cache; FcRef ref; intptr_t size; + void *allocated; dev_t cache_dev; ino_t cache_ino; time_t cache_mtime; @@ -542,6 +565,7 @@ FcCacheInsert (FcCache *cache, struct st s->cache = cache; s->size = cache->size; + s->allocated = NULL; FcRefInit (&s->ref, 1); if (cache_stat) { @@ -616,6 +640,7 @@ FcCacheRemoveUnlocked (FcCache *cache) FcCacheSkip **update[FC_CACHE_MAX_LEVEL]; FcCacheSkip *s, **next; int i; + void *allocated; /* * Find links along each chain @@ -633,6 +658,15 @@ FcCacheRemoveUnlocked (FcCache *cache) *update[i] = s->next[i]; while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL) fcCacheMaxLevel--; + + allocated = s->allocated; + while (allocated) + { + /* First element in allocated chunk is the free list */ + next = *(void **)allocated; + free (allocated); + allocated = next; + } free (s); } @@ -702,6 +736,30 @@ FcCacheObjectDereference (void *object) unlock_cache (); } +void * +FcCacheAllocate (FcCache *cache, size_t len) +{ + FcCacheSkip *skip; + void *allocated = NULL; + + lock_cache (); + skip = FcCacheFindByAddrUnlocked (cache); + if (skip) + { + void *chunk = malloc (sizeof (void *) + len); + if (chunk) + { + /* First element in allocated chunk is the free list */ + *(void **)chunk = skip->allocated; + skip->allocated = chunk; + /* Return the rest */ + allocated = ((FcChar8 *)chunk) + sizeof (void *); + } + } + unlock_cache (); + return allocated; +} + void FcCacheFini (void) { @@ -955,7 +1013,6 @@ FcCache * FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file) { FcCache *cache = NULL; - const FcChar8 *d; #ifndef _WIN32 FcDirCacheReadUUID ((FcChar8 *) dir, config); @@ -965,10 +1022,6 @@ FcDirCacheLoad (const FcChar8 *dir, FcCo &cache, cache_file)) return NULL; - d = FcCacheDir (cache); - if (FcStrCmp (dir, d)) - FcHashTableAdd (config->alias_table, (FcChar8 *) d, (FcChar8 *) dir); - return cache; } diff -pruN fontconfig-2.13.0.orig/src/fccfg.c fontconfig-2.13.0/src/fccfg.c --- fontconfig-2.13.0.orig/src/fccfg.c 2018-06-08 18:34:36.546946321 +0900 +++ fontconfig-2.13.0/src/fccfg.c 2018-06-08 18:39:33.079539192 +0900 @@ -144,12 +144,6 @@ FcConfigCreate (void) FcHashUuidCopy, (FcDestroyFunc) FcStrFree, FcHashUuidFree); - config->alias_table = FcHashTableCreate ((FcHashFunc) FcStrHashIgnoreCase, - (FcCompareFunc) FcStrCmp, - FcHashStrCopy, - FcHashStrCopy, - (FcDestroyFunc) FcStrFree, - (FcDestroyFunc) FcStrFree); FcRefInit (&config->ref, 1); @@ -313,7 +307,6 @@ FcConfigDestroy (FcConfig *config) FcStrFree (config->sysRoot); FcHashTableDestroy (config->uuid_table); - FcHashTableDestroy (config->alias_table); free (config); } @@ -324,11 +317,15 @@ FcConfigDestroy (FcConfig *config) FcBool FcConfigAddCache (FcConfig *config, FcCache *cache, - FcSetName set, FcStrSet *dirSet) + FcSetName set, FcStrSet *dirSet, FcChar8 *forDir) { FcFontSet *fs; intptr_t *dirs; int i; + FcBool relocated = FcFalse; + + if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0) + relocated = FcTrue; /* * Add fonts @@ -342,23 +339,43 @@ FcConfigAddCache (FcConfig *config, FcCa { FcPattern *font = FcFontSetFont (fs, i); FcChar8 *font_file; + FcChar8 *relocated_font_file = NULL; - /* - * Check to see if font is banned by filename - */ if (FcPatternObjectGetString (font, FC_FILE_OBJECT, - 0, &font_file) == FcResultMatch && - !FcConfigAcceptFilename (config, font_file)) + 0, &font_file) == FcResultMatch) { - continue; + if (relocated) + { + FcChar8 *slash = FcStrLastSlash (font_file); + relocated_font_file = FcStrBuildFilename (forDir, slash + 1, NULL); + font_file = relocated_font_file; + } + + /* + * Check to see if font is banned by filename + */ + if (!FcConfigAcceptFilename (config, font_file)) + { + free (relocated_font_file); + continue; + } } - + /* * Check to see if font is banned by pattern */ if (!FcConfigAcceptFont (config, font)) + { + free (relocated_font_file); continue; - + } + + if (relocated_font_file) + { + font = FcPatternCacheRewriteFile (font, cache, relocated_font_file); + free (relocated_font_file); + } + if (FcFontSetAdd (config->fonts[set], font)) nref++; } @@ -374,18 +391,14 @@ FcConfigAddCache (FcConfig *config, FcCa for (i = 0; i < cache->dirs_count; i++) { const FcChar8 *dir = FcCacheSubdir (cache, i); - FcChar8 *alias; - FcChar8 *d = FcStrDirname (dir); FcChar8 *s = NULL; - if (FcHashTableFind (config->alias_table, d, (void **)&alias)) + if (relocated) { FcChar8 *base = FcStrBasename (dir); - dir = s = FcStrBuildFilename (alias, base, NULL); - FcStrFree (alias); + dir = s = FcStrBuildFilename (forDir, base, NULL); FcStrFree (base); } - FcStrFree (d); if (FcConfigAcceptFilename (config, dir)) FcStrSetAddFilename (dirSet, dir); if (s) @@ -413,7 +426,7 @@ FcConfigAddDirList (FcConfig *config, Fc cache = FcDirCacheRead (dir, FcFalse, config); if (!cache) continue; - FcConfigAddCache (config, cache, set, dirSet); + FcConfigAddCache (config, cache, set, dirSet, dir); FcDirCacheUnload (cache); } FcStrListDone (dirlist); diff -pruN fontconfig-2.13.0.orig/src/fcint.h fontconfig-2.13.0/src/fcint.h --- fontconfig-2.13.0.orig/src/fcint.h 2018-02-04 19:20:56.000000000 +0900 +++ fontconfig-2.13.0/src/fcint.h 2018-06-08 18:39:33.080539208 +0900 @@ -566,7 +566,6 @@ struct _FcConfig { FcStrSet *availConfigFiles; /* config files available */ FcPtrList *rulesetList; /* List of rulesets being installed */ FcHashTable *uuid_table; /* UUID table for cachedirs */ - FcHashTable *alias_table; /* alias table for cachedirs */ }; typedef struct _FcFileTime { @@ -617,9 +616,13 @@ FcCacheObjectReference (void *object); FcPrivate void FcCacheObjectDereference (void *object); +FcPrivate void * +FcCacheAllocate (FcCache *cache, size_t len); + FcPrivate void FcCacheFini (void); + FcPrivate void FcDirCacheReference (FcCache *cache, int nref); @@ -708,7 +711,7 @@ FcConfigModifiedTime (FcConfig *config); FcPrivate FcBool FcConfigAddCache (FcConfig *config, FcCache *cache, - FcSetName set, FcStrSet *dirSet); + FcSetName set, FcStrSet *dirSet, FcChar8 *forDir); FcPrivate FcRuleSet * FcRuleSetCreate (const FcChar8 *name); @@ -1150,6 +1153,9 @@ FcPatternAppend (FcPattern *p, FcPattern FcPrivate int FcPatternPosition (const FcPattern *p, const char *object); +FcPrivate FcPattern * +FcPatternCacheRewriteFile (const FcPattern *pat, FcCache *cache, const FcChar8 *relocated_font_file); + FcPrivate FcChar32 FcStringHash (const FcChar8 *s); diff -pruN fontconfig-2.13.0.orig/src/fclist.c fontconfig-2.13.0/src/fclist.c --- fontconfig-2.13.0.orig/src/fclist.c 2017-12-05 21:44:22.000000000 +0900 +++ fontconfig-2.13.0/src/fclist.c 2018-06-08 18:39:33.049538728 +0900 @@ -448,41 +448,6 @@ FcListAppend (FcListHashTable *table, e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o])); if (e) { - if (FcRefIsConst (&font->ref) && !strcmp (os->objects[o], FC_FILE)) - { - FcChar8 *dir, *alias; - FcConfig *config = FcConfigGetCurrent (); /* FIXME: this may need to be exported as API? */ - - for (v = FcPatternEltValues (e); v->value.type != FcTypeString; v = FcValueListNext (v)); - if (!v) - goto bail2; - dir = FcStrDirname (FcValueString (&v->value)); - if (FcHashTableFind (config->alias_table, dir, (void **) &alias)) - { - FcChar8 *base = FcStrBasename (FcValueString (&v->value)); - FcChar8 *s = FcStrBuildFilename (alias, base, NULL); - FcValue vv; - - FcStrFree (alias); - FcStrFree (base); - vv.type = FcTypeString; - vv.u.s = s; - if (!FcPatternAdd (bucket->pattern, - os->objects[o], - FcValueCanonicalize (&vv), - FcTrue)) - { - FcStrFree (s); - FcStrFree (dir); - goto bail2; - } - FcStrFree (s); - FcStrFree (dir); - goto bail3; - } - else - FcStrFree (dir); - } for (v = FcPatternEltValues(e), idx = 0; v; v = FcValueListNext(v), ++idx) { @@ -491,7 +456,6 @@ FcListAppend (FcListHashTable *table, FcValueCanonicalize(&v->value), defidx != idx)) goto bail2; } - bail3:; } } *prev = bucket; diff -pruN fontconfig-2.13.0.orig/src/fcmatch.c fontconfig-2.13.0/src/fcmatch.c --- fontconfig-2.13.0.orig/src/fcmatch.c 2017-12-23 14:06:22.000000000 +0900 +++ fontconfig-2.13.0/src/fcmatch.c 2018-06-08 18:39:33.050538743 +0900 @@ -682,43 +682,9 @@ FcFontRenderPrepare (FcConfig *confi } else { - if (FcRefIsConst (&font->ref) && fe->object == FC_FILE_OBJECT) - { - FcValueListPtr l = FcPatternEltValues (fe); - FcChar8 *dir, *alias; - - while (l->value.type != FcTypeString) - l = FcValueListNext (l); - if (!l) - goto bail0; - dir = FcStrDirname (FcValueString (&l->value)); - if (!config) - config = FcConfigGetCurrent (); - if (config && FcHashTableFind (config->alias_table, dir, (void **) &alias)) - { - FcChar8 *base = FcStrBasename (FcValueString (&l->value)); - FcChar8 *s = FcStrBuildFilename (alias, base, NULL); - FcValue v; - - FcStrFree (alias); - FcStrFree (base); - v.type = FcTypeString; - v.u.s = s; - FcPatternObjectAddWithBinding (new, fe->object, - FcValueCanonicalize (&v), - l->binding, - FcTrue); - FcStrFree (s); - FcStrFree (dir); - goto bail0; - } - else - FcStrFree (dir); - } FcPatternObjectListAdd (new, fe->object, FcValueListDuplicate (FcPatternEltValues (fe)), FcTrue); - bail0:; } } for (i = 0; i < pat->num; i++) diff -pruN fontconfig-2.13.0.orig/src/fcpat.c fontconfig-2.13.0/src/fcpat.c --- fontconfig-2.13.0.orig/src/fcpat.c 2017-12-20 19:20:15.000000000 +0900 +++ fontconfig-2.13.0/src/fcpat.c 2018-06-08 18:39:33.050538743 +0900 @@ -373,6 +373,71 @@ FcValueListHash (FcValueListPtr l) return hash; } +static void * +FcPatternGetCacheObject (FcPattern *p) +{ + /* We use a value to find the cache, instead of the FcPattern object + * because the pattern itself may be a cache allocation if we rewrote the path, + * so the p may not be in the cached region. */ + return FcPatternEltValues(&FcPatternElts (p)[0]); +} + +FcPattern * +FcPatternCacheRewriteFile (const FcPattern *p, + FcCache *cache, + const FcChar8 *relocated_font_file) +{ + FcPatternElt *elts = FcPatternElts (p); + size_t i,j; + FcChar8 *data; + FcPattern *new_p; + FcPatternElt *new_elts; + FcValueList *new_value_list; + size_t new_path_len = strlen ((char *)relocated_font_file); + FcChar8 *new_path; + + /* Allocate space for the patter, the PatternElt headers and + * the FC_FILE FcValueList and path that will be freed with the + * cache */ + data = FcCacheAllocate (cache, + sizeof (FcPattern) + + p->num * sizeof (FcPatternElt) + + sizeof (FcValueList) + + new_path_len + 1); + + new_p = (FcPattern *)data; + data += sizeof (FcPattern); + new_elts = (FcPatternElt *)(data); + data += p->num * sizeof (FcPatternElt); + new_value_list = (FcValueList *)data; + data += sizeof (FcValueList); + new_path = data; + + *new_p = *p; + new_p->elts_offset = FcPtrToOffset (new_p, new_elts); + + /* Copy all but the FILE values from the cache */ + for (i = 0, j = 0; i < p->num; i++) + { + FcPatternElt *elt = &elts[i]; + new_elts[j].object = elt->object; + if (elt->object != FC_FILE_OBJECT) + new_elts[j++].values = FcPatternEltValues(elt); + else + new_elts[j++].values = new_value_list; + } + + new_value_list->next = NULL; + new_value_list->value.type = FcTypeString; + new_value_list->value.u.s = new_path; + new_value_list->binding = FcValueBindingWeak; + + /* Add rewritten path at the end */ + strcpy ((char *)new_path, (char *)relocated_font_file); + + return new_p; +} + void FcPatternDestroy (FcPattern *p) { @@ -384,10 +449,10 @@ FcPatternDestroy (FcPattern *p) if (FcRefIsConst (&p->ref)) { - FcCacheObjectDereference (p); + FcCacheObjectDereference (FcPatternGetCacheObject(p)); return; } - + if (FcRefDec (&p->ref) != 1) return; @@ -1155,7 +1220,7 @@ FcPatternReference (FcPattern *p) if (!FcRefIsConst (&p->ref)) FcRefInc (&p->ref); else - FcCacheObjectReference (p); + FcCacheObjectReference (FcPatternGetCacheObject(p)); } FcPattern * diff -pruN fontconfig-2.13.0.orig/test/run-test.sh fontconfig-2.13.0/test/run-test.sh --- fontconfig-2.13.0.orig/test/run-test.sh 2017-12-18 21:25:18.000000000 +0900 +++ fontconfig-2.13.0/test/run-test.sh 2018-06-08 18:39:33.031538449 +0900 @@ -202,4 +202,29 @@ fi rm -rf $TESTTMPDIR out1 out2 xxx bind-fonts.conf fi +dotest "sysroot option" +prep +mkdir -p $MyPWD/sysroot/$FONTDIR +mkdir -p $MyPWD/sysroot/$CACHEDIR +cp $FONT1 $MyPWD/sysroot/$FONTDIR +cp $MyPWD/fonts.conf $MyPWD/sysroot/$MyPWD/fonts.conf +$FCCACHE -y $MyPWD/sysroot +stat $MyPWD/sysroot/$FONTDIR/.uuid +if test $? != 0; then + echo "*** Test failed: $TEST" + exit 1 +fi + +dotest "creating uuid-based cache file on sysroot" +uuid=`cat $MyPWD/sysroot/$FONTDIR/.uuid` +ls $MyPWD/sysroot/$CACHEDIR/$uuid* +if [ $? != 0 ]; then + echo "*** Test failed: $TEST" + echo "No cache for $uuid" + ls $MyPWD/sysroot/$CACHEDIR + exit 1 +fi + +rm -rf $MyPWD/sysroot + rm -rf $FONTDIR $CACHEFILE $CACHEDIR $FONTCONFIG_FILE out