Cache: Rewrite relocated paths in earlier
This changes the rewriting of the FC_FILE values for relocated caches to an earlier stage while reading the cache. This is better, because it means all APIs will report the rewritten paths, not just the once that use the list apis. We do this by detecting the relocated case and duplicating the FcPattern and FcPatternElm in an cache allocation (which will die with the cache) and then reusing the FcValueLists from the cache. This means that in the rewritten case we will use some more memory, but not the full size of the cache. In a test here I had 800k of relocated caches, but ~200k of wasted on duplicating the objects. This should fix https://bugs.freedesktop.org/show_bug.cgi?id=106618
This commit is contained in:
parent
a63b9c622e
commit
c42402d0b8
44
src/fccfg.c
44
src/fccfg.c
|
@ -324,11 +324,15 @@ FcConfigDestroy (FcConfig *config)
|
||||||
|
|
||||||
FcBool
|
FcBool
|
||||||
FcConfigAddCache (FcConfig *config, FcCache *cache,
|
FcConfigAddCache (FcConfig *config, FcCache *cache,
|
||||||
FcSetName set, FcStrSet *dirSet)
|
FcSetName set, FcStrSet *dirSet, FcChar8 *forDir)
|
||||||
{
|
{
|
||||||
FcFontSet *fs;
|
FcFontSet *fs;
|
||||||
intptr_t *dirs;
|
intptr_t *dirs;
|
||||||
int i;
|
int i;
|
||||||
|
FcBool relocated = FcFalse;
|
||||||
|
|
||||||
|
if (strcmp ((char *)FcCacheDir(cache), (char *)forDir) != 0)
|
||||||
|
relocated = FcTrue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add fonts
|
* Add fonts
|
||||||
|
@ -342,23 +346,43 @@ FcConfigAddCache (FcConfig *config, FcCache *cache,
|
||||||
{
|
{
|
||||||
FcPattern *font = FcFontSetFont (fs, i);
|
FcPattern *font = FcFontSetFont (fs, i);
|
||||||
FcChar8 *font_file;
|
FcChar8 *font_file;
|
||||||
|
FcChar8 *relocated_font_file = NULL;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check to see if font is banned by filename
|
|
||||||
*/
|
|
||||||
if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
|
if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
|
||||||
0, &font_file) == FcResultMatch &&
|
0, &font_file) == FcResultMatch)
|
||||||
!FcConfigAcceptFilename (config, font_file))
|
|
||||||
{
|
{
|
||||||
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
|
* Check to see if font is banned by pattern
|
||||||
*/
|
*/
|
||||||
if (!FcConfigAcceptFont (config, font))
|
if (!FcConfigAcceptFont (config, font))
|
||||||
|
{
|
||||||
|
free (relocated_font_file);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relocated_font_file)
|
||||||
|
{
|
||||||
|
font = FcPatternCacheRewriteFile (font, cache, relocated_font_file);
|
||||||
|
free (relocated_font_file);
|
||||||
|
}
|
||||||
|
|
||||||
if (FcFontSetAdd (config->fonts[set], font))
|
if (FcFontSetAdd (config->fonts[set], font))
|
||||||
nref++;
|
nref++;
|
||||||
}
|
}
|
||||||
|
@ -413,7 +437,7 @@ FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
|
||||||
cache = FcDirCacheRead (dir, FcFalse, config);
|
cache = FcDirCacheRead (dir, FcFalse, config);
|
||||||
if (!cache)
|
if (!cache)
|
||||||
continue;
|
continue;
|
||||||
FcConfigAddCache (config, cache, set, dirSet);
|
FcConfigAddCache (config, cache, set, dirSet, dir);
|
||||||
FcDirCacheUnload (cache);
|
FcDirCacheUnload (cache);
|
||||||
}
|
}
|
||||||
FcStrListDone (dirlist);
|
FcStrListDone (dirlist);
|
||||||
|
|
|
@ -712,7 +712,7 @@ FcConfigModifiedTime (FcConfig *config);
|
||||||
|
|
||||||
FcPrivate FcBool
|
FcPrivate FcBool
|
||||||
FcConfigAddCache (FcConfig *config, FcCache *cache,
|
FcConfigAddCache (FcConfig *config, FcCache *cache,
|
||||||
FcSetName set, FcStrSet *dirSet);
|
FcSetName set, FcStrSet *dirSet, FcChar8 *forDir);
|
||||||
|
|
||||||
FcPrivate FcRuleSet *
|
FcPrivate FcRuleSet *
|
||||||
FcRuleSetCreate (const FcChar8 *name);
|
FcRuleSetCreate (const FcChar8 *name);
|
||||||
|
@ -1163,6 +1163,9 @@ FcPatternIterGetObjectId (const FcPattern *pat, FcPatternIter *iter);
|
||||||
FcPrivate FcValueListPtr
|
FcPrivate FcValueListPtr
|
||||||
FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter);
|
FcPatternIterGetValues (const FcPattern *pat, FcPatternIter *iter);
|
||||||
|
|
||||||
|
FcPrivate FcPattern *
|
||||||
|
FcPatternCacheRewriteFile (const FcPattern *pat, FcCache *cache, const FcChar8 *relocated_font_file);
|
||||||
|
|
||||||
FcPrivate FcChar32
|
FcPrivate FcChar32
|
||||||
FcStringHash (const FcChar8 *s);
|
FcStringHash (const FcChar8 *s);
|
||||||
|
|
||||||
|
|
36
src/fclist.c
36
src/fclist.c
|
@ -448,41 +448,6 @@ FcListAppend (FcListHashTable *table,
|
||||||
e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o]));
|
e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o]));
|
||||||
if (e)
|
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;
|
for (v = FcPatternEltValues(e), idx = 0; v;
|
||||||
v = FcValueListNext(v), ++idx)
|
v = FcValueListNext(v), ++idx)
|
||||||
{
|
{
|
||||||
|
@ -491,7 +456,6 @@ FcListAppend (FcListHashTable *table,
|
||||||
FcValueCanonicalize(&v->value), defidx != idx))
|
FcValueCanonicalize(&v->value), defidx != idx))
|
||||||
goto bail2;
|
goto bail2;
|
||||||
}
|
}
|
||||||
bail3:;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*prev = bucket;
|
*prev = bucket;
|
||||||
|
|
|
@ -682,43 +682,9 @@ FcFontRenderPrepare (FcConfig *config,
|
||||||
}
|
}
|
||||||
else
|
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,
|
FcPatternObjectListAdd (new, fe->object,
|
||||||
FcValueListDuplicate (FcPatternEltValues (fe)),
|
FcValueListDuplicate (FcPatternEltValues (fe)),
|
||||||
FcTrue);
|
FcTrue);
|
||||||
bail0:;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < pat->num; i++)
|
for (i = 0; i < pat->num; i++)
|
||||||
|
|
71
src/fcpat.c
71
src/fcpat.c
|
@ -373,6 +373,71 @@ FcValueListHash (FcValueListPtr l)
|
||||||
return hash;
|
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
|
void
|
||||||
FcPatternDestroy (FcPattern *p)
|
FcPatternDestroy (FcPattern *p)
|
||||||
{
|
{
|
||||||
|
@ -384,10 +449,10 @@ FcPatternDestroy (FcPattern *p)
|
||||||
|
|
||||||
if (FcRefIsConst (&p->ref))
|
if (FcRefIsConst (&p->ref))
|
||||||
{
|
{
|
||||||
FcCacheObjectDereference (p);
|
FcCacheObjectDereference (FcPatternGetCacheObject(p));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FcRefDec (&p->ref) != 1)
|
if (FcRefDec (&p->ref) != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1164,7 +1229,7 @@ FcPatternReference (FcPattern *p)
|
||||||
if (!FcRefIsConst (&p->ref))
|
if (!FcRefIsConst (&p->ref))
|
||||||
FcRefInc (&p->ref);
|
FcRefInc (&p->ref);
|
||||||
else
|
else
|
||||||
FcCacheObjectReference (p);
|
FcCacheObjectReference (FcPatternGetCacheObject(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
FcPattern *
|
FcPattern *
|
||||||
|
|
Loading…
Reference in New Issue