Use a hash table for families in FcConfigSubstitute
Use the same approach we used for FcFontMatch, and keep a hash table of family names. We only speed up the no-match case, for now.
This commit is contained in:
parent
7deb07e38e
commit
13015a0a6e
190
src/fccfg.c
190
src/fccfg.c
|
@ -1579,12 +1579,128 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The bulk of the time in FcConfigSubstitute is spent walking
|
||||||
|
* lists of family names. We speed this up with a hash table.
|
||||||
|
* Since we need to take the ignore-blanks option into account,
|
||||||
|
* we use two separate hash tables.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
} FamilyTableEntry;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FcHashTable *family_blank_hash;
|
||||||
|
FcHashTable *family_hash;
|
||||||
|
} FamilyTable;
|
||||||
|
|
||||||
|
static FcBool
|
||||||
|
FamilyTableLookup (FamilyTable *table,
|
||||||
|
FcOp _op,
|
||||||
|
const FcChar8 *s)
|
||||||
|
{
|
||||||
|
FamilyTableEntry *fe;
|
||||||
|
int flags = FC_OP_GET_FLAGS (_op);
|
||||||
|
FcHashTable *hash;
|
||||||
|
|
||||||
|
if (flags & FcOpFlagIgnoreBlanks)
|
||||||
|
hash = table->family_blank_hash;
|
||||||
|
else
|
||||||
|
hash = table->family_hash;
|
||||||
|
|
||||||
|
return FcHashTableFind (hash, (const void *)s, (void **)&fe);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FamilyTableAdd (FamilyTable *table,
|
||||||
|
FcValueListPtr values)
|
||||||
|
{
|
||||||
|
FcValueListPtr ll;
|
||||||
|
for (ll = values; ll; ll = FcValueListNext (ll))
|
||||||
|
{
|
||||||
|
const FcChar8 *s = FcValueString (&ll->value);
|
||||||
|
FamilyTableEntry *fe;
|
||||||
|
|
||||||
|
if (!FcHashTableFind (table->family_hash, (const void *)s, (void **)&fe))
|
||||||
|
{
|
||||||
|
fe = malloc (sizeof (FamilyTableEntry));
|
||||||
|
fe->count = 0;
|
||||||
|
FcHashTableAdd (table->family_hash, (void *)s, fe);
|
||||||
|
}
|
||||||
|
fe->count++;
|
||||||
|
|
||||||
|
if (!FcHashTableFind (table->family_blank_hash, (const void *)s, (void **)&fe))
|
||||||
|
{
|
||||||
|
fe = malloc (sizeof (FamilyTableEntry));
|
||||||
|
fe->count = 0;
|
||||||
|
FcHashTableAdd (table->family_blank_hash, (void *)s, fe);
|
||||||
|
}
|
||||||
|
fe->count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FamilyTableDel (FamilyTable *table,
|
||||||
|
const FcChar8 *s)
|
||||||
|
{
|
||||||
|
FamilyTableEntry *fe;
|
||||||
|
|
||||||
|
if (FcHashTableFind (table->family_hash, (void *)s, (void **)&fe))
|
||||||
|
{
|
||||||
|
fe->count--;
|
||||||
|
if (fe->count == 0)
|
||||||
|
FcHashTableRemove (table->family_hash, (void *)s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FcHashTableFind (table->family_blank_hash, (void *)s, (void **)&fe))
|
||||||
|
{
|
||||||
|
fe->count--;
|
||||||
|
if (fe->count == 0)
|
||||||
|
FcHashTableRemove (table->family_blank_hash, (void *)s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FamilyTableInit (FamilyTable *table,
|
||||||
|
FcPattern *p)
|
||||||
|
{
|
||||||
|
FcPatternElt *e;
|
||||||
|
|
||||||
|
table->family_blank_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
|
||||||
|
(FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
free);
|
||||||
|
table->family_hash = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreCase,
|
||||||
|
(FcCompareFunc)FcStrCmpIgnoreCase,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
free);
|
||||||
|
e = FcPatternObjectFindElt (p, FC_FAMILY_OBJECT);
|
||||||
|
if (e)
|
||||||
|
FamilyTableAdd (table, FcPatternEltValues (e));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FamilyTableClear (FamilyTable *table)
|
||||||
|
{
|
||||||
|
if (table->family_blank_hash)
|
||||||
|
FcHashTableDestroy (table->family_blank_hash);
|
||||||
|
if (table->family_hash)
|
||||||
|
FcHashTableDestroy (table->family_hash);
|
||||||
|
}
|
||||||
|
|
||||||
static FcValueList *
|
static FcValueList *
|
||||||
FcConfigMatchValueList (FcPattern *p,
|
FcConfigMatchValueList (FcPattern *p,
|
||||||
FcPattern *p_pat,
|
FcPattern *p_pat,
|
||||||
FcMatchKind kind,
|
FcMatchKind kind,
|
||||||
FcTest *t,
|
FcTest *t,
|
||||||
FcValueList *values)
|
FcValueList *values,
|
||||||
|
FamilyTable *table)
|
||||||
{
|
{
|
||||||
FcValueList *ret = 0;
|
FcValueList *ret = 0;
|
||||||
FcExpr *e = t->expr;
|
FcExpr *e = t->expr;
|
||||||
|
@ -1605,6 +1721,14 @@ FcConfigMatchValueList (FcPattern *p,
|
||||||
e = 0;
|
e = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t->object == FC_FAMILY_OBJECT && table)
|
||||||
|
{
|
||||||
|
if (!FamilyTableLookup (table, t->op, FcValueString (&value)))
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (v = values; v; v = FcValueListNext(v))
|
for (v = values; v; v = FcValueListNext(v))
|
||||||
{
|
{
|
||||||
/* Compare the pattern value to the match expression value */
|
/* Compare the pattern value to the match expression value */
|
||||||
|
@ -1624,6 +1748,7 @@ FcConfigMatchValueList (FcPattern *p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
FcValueDestroy (value);
|
FcValueDestroy (value);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1666,7 +1791,8 @@ FcConfigAdd (FcValueListPtr *head,
|
||||||
FcValueList *position,
|
FcValueList *position,
|
||||||
FcBool append,
|
FcBool append,
|
||||||
FcValueList *new,
|
FcValueList *new,
|
||||||
FcObject object)
|
FcObject object,
|
||||||
|
FamilyTable *table)
|
||||||
{
|
{
|
||||||
FcValueListPtr *prev, l, last, v;
|
FcValueListPtr *prev, l, last, v;
|
||||||
FcValueBinding sameBinding;
|
FcValueBinding sameBinding;
|
||||||
|
@ -1692,6 +1818,11 @@ FcConfigAdd (FcValueListPtr *head,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (object == FC_FAMILY_OBJECT && table)
|
||||||
|
{
|
||||||
|
FamilyTableAdd (table, new);
|
||||||
|
}
|
||||||
|
|
||||||
if (position)
|
if (position)
|
||||||
sameBinding = position->binding;
|
sameBinding = position->binding;
|
||||||
else
|
else
|
||||||
|
@ -1758,10 +1889,17 @@ FcConfigAdd (FcValueListPtr *head,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FcConfigDel (FcValueListPtr *head,
|
FcConfigDel (FcValueListPtr *head,
|
||||||
FcValueList *position)
|
FcValueList *position,
|
||||||
|
FcObject object,
|
||||||
|
FamilyTable *table)
|
||||||
{
|
{
|
||||||
FcValueListPtr *prev;
|
FcValueListPtr *prev;
|
||||||
|
|
||||||
|
if (object == FC_FAMILY_OBJECT && table)
|
||||||
|
{
|
||||||
|
FamilyTableDel (table, FcValueString (&position->value));
|
||||||
|
}
|
||||||
|
|
||||||
for (prev = head; *prev != NULL; prev = &(*prev)->next)
|
for (prev = head; *prev != NULL; prev = &(*prev)->next)
|
||||||
{
|
{
|
||||||
if (*prev == position)
|
if (*prev == position)
|
||||||
|
@ -1778,7 +1916,8 @@ static void
|
||||||
FcConfigPatternAdd (FcPattern *p,
|
FcConfigPatternAdd (FcPattern *p,
|
||||||
FcObject object,
|
FcObject object,
|
||||||
FcValueList *list,
|
FcValueList *list,
|
||||||
FcBool append)
|
FcBool append,
|
||||||
|
FamilyTable *table)
|
||||||
{
|
{
|
||||||
if (list)
|
if (list)
|
||||||
{
|
{
|
||||||
|
@ -1786,7 +1925,7 @@ FcConfigPatternAdd (FcPattern *p,
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return;
|
return;
|
||||||
FcConfigAdd (&e->values, 0, append, list, object);
|
FcConfigAdd (&e->values, 0, append, list, object, table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1795,13 +1934,14 @@ FcConfigPatternAdd (FcPattern *p,
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
FcConfigPatternDel (FcPattern *p,
|
FcConfigPatternDel (FcPattern *p,
|
||||||
FcObject object)
|
FcObject object,
|
||||||
|
FamilyTable *table)
|
||||||
{
|
{
|
||||||
FcPatternElt *e = FcPatternObjectFindElt (p, object);
|
FcPatternElt *e = FcPatternObjectFindElt (p, object);
|
||||||
if (!e)
|
if (!e)
|
||||||
return;
|
return;
|
||||||
while (e->values != NULL)
|
while (e->values != NULL)
|
||||||
FcConfigDel (&e->values, e->values);
|
FcConfigDel (&e->values, e->values, object, table);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1834,6 +1974,8 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
int i, nobjs;
|
int i, nobjs;
|
||||||
FcBool retval = FcTrue;
|
FcBool retval = FcTrue;
|
||||||
FcTest **tst = NULL;
|
FcTest **tst = NULL;
|
||||||
|
FamilyTable data;
|
||||||
|
FamilyTable *table = &data;
|
||||||
|
|
||||||
if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
|
if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
|
||||||
return FcFalse;
|
return FcFalse;
|
||||||
|
@ -1931,6 +2073,9 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
printf ("FcConfigSubstitute ");
|
printf ("FcConfigSubstitute ");
|
||||||
FcPatternPrint (p);
|
FcPatternPrint (p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FamilyTableInit (&data, p);
|
||||||
|
|
||||||
FcPtrListIterInit (s, &iter);
|
FcPtrListIterInit (s, &iter);
|
||||||
for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
|
for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
|
||||||
{
|
{
|
||||||
|
@ -1967,9 +2112,15 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
FcTestPrint (r->u.test);
|
FcTestPrint (r->u.test);
|
||||||
}
|
}
|
||||||
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
|
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
|
||||||
|
{
|
||||||
m = p_pat;
|
m = p_pat;
|
||||||
|
table = NULL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
m = p;
|
m = p;
|
||||||
|
table = &data;
|
||||||
|
}
|
||||||
if (m)
|
if (m)
|
||||||
e = FcPatternObjectFindElt (m, r->u.test->object);
|
e = FcPatternObjectFindElt (m, r->u.test->object);
|
||||||
else
|
else
|
||||||
|
@ -2002,7 +2153,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
* Check to see if there is a match, mark the location
|
* Check to see if there is a match, mark the location
|
||||||
* to apply match-relative edits
|
* to apply match-relative edits
|
||||||
*/
|
*/
|
||||||
vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
|
vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values, table);
|
||||||
/* different 'kind' won't be the target of edit */
|
/* different 'kind' won't be the target of edit */
|
||||||
if (!value[object] && kind == r->u.test->kind)
|
if (!value[object] && kind == r->u.test->kind)
|
||||||
value[object] = vl;
|
value[object] = vl;
|
||||||
|
@ -2026,7 +2177,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
/*
|
/*
|
||||||
* Evaluate the list of expressions
|
* Evaluate the list of expressions
|
||||||
*/
|
*/
|
||||||
l = FcConfigValues (p, p_pat,kind, r->u.edit->expr, r->u.edit->binding);
|
l = FcConfigValues (p, p_pat, kind, r->u.edit->expr, r->u.edit->binding);
|
||||||
if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
|
if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
|
||||||
elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
|
elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
|
||||||
|
|
||||||
|
@ -2044,12 +2195,12 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
/*
|
/*
|
||||||
* Append the new list of values after the current value
|
* Append the new list of values after the current value
|
||||||
*/
|
*/
|
||||||
FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
|
FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object, table);
|
||||||
/*
|
/*
|
||||||
* Delete the marked value
|
* Delete the marked value
|
||||||
*/
|
*/
|
||||||
if (thisValue)
|
if (thisValue)
|
||||||
FcConfigDel (&elt[object]->values, thisValue);
|
FcConfigDel (&elt[object]->values, thisValue, object, table);
|
||||||
/*
|
/*
|
||||||
* Adjust a pointer into the value list to ensure
|
* Adjust a pointer into the value list to ensure
|
||||||
* future edits occur at the same place
|
* future edits occur at the same place
|
||||||
|
@ -2063,8 +2214,8 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
* Delete all of the values and insert
|
* Delete all of the values and insert
|
||||||
* the new set
|
* the new set
|
||||||
*/
|
*/
|
||||||
FcConfigPatternDel (p, r->u.edit->object);
|
FcConfigPatternDel (p, r->u.edit->object, table);
|
||||||
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
|
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
|
||||||
/*
|
/*
|
||||||
* Adjust a pointer into the value list as they no
|
* Adjust a pointer into the value list as they no
|
||||||
* longer point to anything valid
|
* longer point to anything valid
|
||||||
|
@ -2074,33 +2225,33 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
case FcOpPrepend:
|
case FcOpPrepend:
|
||||||
if (value[object])
|
if (value[object])
|
||||||
{
|
{
|
||||||
FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
|
FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object, table);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fall through ... */
|
/* fall through ... */
|
||||||
case FcOpPrependFirst:
|
case FcOpPrependFirst:
|
||||||
FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
|
FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table);
|
||||||
break;
|
break;
|
||||||
case FcOpAppend:
|
case FcOpAppend:
|
||||||
if (value[object])
|
if (value[object])
|
||||||
{
|
{
|
||||||
FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
|
FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object, table);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fall through ... */
|
/* fall through ... */
|
||||||
case FcOpAppendLast:
|
case FcOpAppendLast:
|
||||||
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
|
FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
|
||||||
break;
|
break;
|
||||||
case FcOpDelete:
|
case FcOpDelete:
|
||||||
if (value[object])
|
if (value[object])
|
||||||
{
|
{
|
||||||
FcConfigDel (&elt[object]->values, value[object]);
|
FcConfigDel (&elt[object]->values, value[object], object, table);
|
||||||
FcValueListDestroy (l);
|
FcValueListDestroy (l);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fall through ... */
|
/* fall through ... */
|
||||||
case FcOpDeleteAll:
|
case FcOpDeleteAll:
|
||||||
FcConfigPatternDel (p, r->u.edit->object);
|
FcConfigPatternDel (p, r->u.edit->object, table);
|
||||||
FcValueListDestroy (l);
|
FcValueListDestroy (l);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -2130,6 +2281,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
|
||||||
FcPatternPrint (p);
|
FcPatternPrint (p);
|
||||||
}
|
}
|
||||||
bail1:
|
bail1:
|
||||||
|
FamilyTableClear (&data);
|
||||||
if (elt)
|
if (elt)
|
||||||
free (elt);
|
free (elt);
|
||||||
if (value)
|
if (value)
|
||||||
|
|
Loading…
Reference in New Issue