[Fontconfig] fontconfig: Branch 'master' - 15 commits
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Wed Aug 26 05:14:17 UTC 2020
src/fccfg.c | 682 ++++++++++++++++++++++++++++++++++++++--------------------
src/fcint.h | 11
src/fcmatch.c | 183 +++++++++++++--
src/fcstr.c | 103 ++++++--
4 files changed, 697 insertions(+), 282 deletions(-)
New commits:
commit ff7d314ab5f04d3ad54d5165b81d87894d7a8dfe
Author: Matthias Clasen <mclasen at redhat.com>
Date: Tue Aug 25 18:12:07 2020 -0400
Fix up FC_LIKELY macros
__builtin_expect returns the same type as the expression,
so enforce that we pass in a boolean expression.
Pointed out by Emmanuele Bassi.
diff --git a/src/fcint.h b/src/fcint.h
index fb173b5..a3b192d 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -61,8 +61,8 @@
#define FC_LIKELY(expr) (expr)
#define FC_UNLIKELY(expr) (expr)
#else
-#define FC_LIKELY(expr) (__builtin_expect (expr, 1))
-#define FC_UNLIKELY(expr) (__builtin_expect (expr, 0))
+#define FC_LIKELY(expr) (__builtin_expect (((expr) ? 1 : 0), 1))
+#define FC_UNLIKELY(expr) (__builtin_expect (((expr) ? 1 : 0), 0))
#endif
#ifdef _WIN32
commit e117d6768c5cf5ae37405d03ed6d3b076e713dde
Author: Matthias Clasen <mclasen at redhat.com>
Date: Tue Aug 25 07:26:32 2020 -0400
Fixup: Handle patterns without family
Pointed out by Akira Tagoh.
diff --git a/src/fcmatch.c b/src/fcmatch.c
index 16d03de..df6db71 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -525,25 +525,28 @@ FcCompareDataInit (FcPattern *pat,
free);
elt = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
- for (l = FcPatternEltValues(elt), i = 0; l; l = FcValueListNext(l), i++)
+ if (elt)
{
- key = FcValueString (&l->value);
- if (!FcHashTableFind (table, key, (void **)&e))
+ for (l = FcPatternEltValues(elt), i = 0; l; l = FcValueListNext(l), i++)
{
- e = malloc (sizeof (FamilyEntry));
- e->strong_value = 1e99;
- e->weak_value = 1e99;
- FcHashTableAdd (table, (void *)key, e);
- }
- if (l->binding == FcValueBindingWeak)
- {
- if (i < e->weak_value)
- e->weak_value = i;
- }
- else
- {
- if (i < e->strong_value)
- e->strong_value = i;
+ key = FcValueString (&l->value);
+ if (!FcHashTableFind (table, key, (void **)&e))
+ {
+ e = malloc (sizeof (FamilyEntry));
+ e->strong_value = 1e99;
+ e->weak_value = 1e99;
+ FcHashTableAdd (table, (void *)key, e);
+ }
+ if (l->binding == FcValueBindingWeak)
+ {
+ if (i < e->weak_value)
+ e->weak_value = i;
+ }
+ else
+ {
+ if (i < e->strong_value)
+ e->strong_value = i;
+ }
}
}
commit 51d40491fc483787ba66fb76344ff7d4c13a39b3
Author: Matthias Clasen <mclasen at redhat.com>
Date: Mon Aug 24 07:59:50 2020 -0400
Use FC_UNLIKELY
diff --git a/src/fcstr.c b/src/fcstr.c
index f1f75dc..8971b71 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -164,7 +164,7 @@ FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
{
FcChar8 r;
- if (__builtin_expect (w->read != NULL, 0))
+ if (FC_UNLIKELY (w->read != NULL))
{
if ((r = *w->read++))
return r;
@@ -175,7 +175,7 @@ FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
r = *w->src++;
} while (r != 0 && delims && strchr (delims, r));
- if (__builtin_expect ((r & 0xc0) == 0xc0, 0))
+ if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
@@ -187,7 +187,7 @@ FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
{
FcChar8 r;
- if (__builtin_expect (w->read != NULL, 0))
+ if (FC_UNLIKELY (w->read != NULL))
{
if ((r = *w->read++))
return r;
@@ -198,7 +198,7 @@ FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
r = *w->src++;
} while (r == ' ');
- if (__builtin_expect ((r & 0xc0) == 0xc0, 0))
+ if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
@@ -210,7 +210,7 @@ FcStrCaseWalkerNext (FcCaseWalker *w)
{
FcChar8 r;
- if (__builtin_expect (w->read != NULL, 0))
+ if (FC_UNLIKELY (w->read != NULL))
{
if ((r = *w->read++))
return r;
@@ -219,7 +219,7 @@ FcStrCaseWalkerNext (FcCaseWalker *w)
r = *w->src++;
- if (__builtin_expect ((r & 0xc0) == 0xc0, 0))
+ if (FC_UNLIKELY ((r & 0xc0) == 0xc0))
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
commit 76699a4813a05fd89114a29965d2532adc1553b0
Author: Matthias Clasen <mclasen at redhat.com>
Date: Mon Aug 24 07:59:18 2020 -0400
Add FC_LIKELY and FC_UNLIKELY macros
These wrap __builtin_expect where it exists.
diff --git a/src/fcint.h b/src/fcint.h
index 08a0cd6..fb173b5 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -57,6 +57,14 @@
#define FC_CONFIG_PATH "fonts.conf"
#endif
+#ifdef _WIN32
+#define FC_LIKELY(expr) (expr)
+#define FC_UNLIKELY(expr) (expr)
+#else
+#define FC_LIKELY(expr) (__builtin_expect (expr, 1))
+#define FC_UNLIKELY(expr) (__builtin_expect (expr, 0))
+#endif
+
#ifdef _WIN32
# include "fcwindows.h"
typedef UINT (WINAPI *pfnGetSystemWindowsDirectory)(LPSTR, UINT);
commit 835f9bbdbe7c023bce27f699c8906ace9b62a051
Author: Matthias Clasen <mclasen at redhat.com>
Date: Sat Aug 22 02:35:24 2020 -0400
Fixup: Promote ints to ranges when appropriate
Pointed out by Akira Tagoh.
diff --git a/src/fccfg.c b/src/fccfg.c
index 13bd0ff..f86f680 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -939,6 +939,13 @@ FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
case FcTypeInteger:
v.type = FcTypeDouble;
v.u.d = (double) v.u.i;
+ /* Fallthrough */
+ case FcTypeDouble:
+ if (u.type == FcTypeRange && buf)
+ {
+ v.u.r = FcRangePromote (v.u.d, buf);
+ v.type = FcTypeRange;
+ }
break;
case FcTypeVoid:
if (u.type == FcTypeMatrix)
@@ -964,13 +971,6 @@ FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
v.type = FcTypeLangSet;
}
break;
- case FcTypeDouble:
- if (u.type == FcTypeRange && buf)
- {
- v.u.r = FcRangePromote (v.u.d, buf);
- v.type = FcTypeRange;
- }
- break;
default:
break;
}
commit 148ebf98edb498d786f4c1107ec116e1afdf9541
Author: Matthias Clasen <mclasen at redhat.com>
Date: Sat Aug 22 00:57:25 2020 -0400
Use __builtin_expect in a few places
utf8 is extremely rare in the strings we see in
font configuration, so this seems to be a good
case for __builtin_expect.
diff --git a/src/fcstr.c b/src/fcstr.c
index dc9940a..f1f75dc 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -164,7 +164,7 @@ FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
{
FcChar8 r;
- if (w->read)
+ if (__builtin_expect (w->read != NULL, 0))
{
if ((r = *w->read++))
return r;
@@ -175,7 +175,7 @@ FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
r = *w->src++;
} while (r != 0 && delims && strchr (delims, r));
- if ((r & 0xc0) == 0xc0)
+ if (__builtin_expect ((r & 0xc0) == 0xc0, 0))
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
@@ -187,7 +187,7 @@ FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
{
FcChar8 r;
- if (w->read)
+ if (__builtin_expect (w->read != NULL, 0))
{
if ((r = *w->read++))
return r;
@@ -198,7 +198,7 @@ FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
r = *w->src++;
} while (r == ' ');
- if ((r & 0xc0) == 0xc0)
+ if (__builtin_expect ((r & 0xc0) == 0xc0, 0))
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
@@ -210,7 +210,7 @@ FcStrCaseWalkerNext (FcCaseWalker *w)
{
FcChar8 r;
- if (w->read)
+ if (__builtin_expect (w->read != NULL, 0))
{
if ((r = *w->read++))
return r;
@@ -219,7 +219,7 @@ FcStrCaseWalkerNext (FcCaseWalker *w)
r = *w->src++;
- if ((r & 0xc0) == 0xc0)
+ if (__builtin_expect ((r & 0xc0) == 0xc0, 0))
return FcStrCaseWalkerLong (w, r);
if ('A' <= r && r <= 'Z')
r = r - 'A' + 'a';
commit 13015a0a6ed15ef2e0241a92ef05233dc51ce23b
Author: Matthias Clasen <mclasen at redhat.com>
Date: Tue Aug 18 16:33:57 2020 -0400
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.
diff --git a/src/fccfg.c b/src/fccfg.c
index 803cd68..13bd0ff 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -1579,12 +1579,128 @@ FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
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 *
FcConfigMatchValueList (FcPattern *p,
FcPattern *p_pat,
FcMatchKind kind,
FcTest *t,
- FcValueList *values)
+ FcValueList *values,
+ FamilyTable *table)
{
FcValueList *ret = 0;
FcExpr *e = t->expr;
@@ -1605,6 +1721,14 @@ FcConfigMatchValueList (FcPattern *p,
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))
{
/* Compare the pattern value to the match expression value */
@@ -1624,6 +1748,7 @@ FcConfigMatchValueList (FcPattern *p,
}
}
}
+done:
FcValueDestroy (value);
}
return ret;
@@ -1666,7 +1791,8 @@ FcConfigAdd (FcValueListPtr *head,
FcValueList *position,
FcBool append,
FcValueList *new,
- FcObject object)
+ FcObject object,
+ FamilyTable *table)
{
FcValueListPtr *prev, l, last, v;
FcValueBinding sameBinding;
@@ -1692,6 +1818,11 @@ FcConfigAdd (FcValueListPtr *head,
}
}
+ if (object == FC_FAMILY_OBJECT && table)
+ {
+ FamilyTableAdd (table, new);
+ }
+
if (position)
sameBinding = position->binding;
else
@@ -1758,10 +1889,17 @@ FcConfigAdd (FcValueListPtr *head,
static void
FcConfigDel (FcValueListPtr *head,
- FcValueList *position)
+ FcValueList *position,
+ FcObject object,
+ FamilyTable *table)
{
FcValueListPtr *prev;
+ if (object == FC_FAMILY_OBJECT && table)
+ {
+ FamilyTableDel (table, FcValueString (&position->value));
+ }
+
for (prev = head; *prev != NULL; prev = &(*prev)->next)
{
if (*prev == position)
@@ -1776,9 +1914,10 @@ FcConfigDel (FcValueListPtr *head,
static void
FcConfigPatternAdd (FcPattern *p,
- FcObject object,
+ FcObject object,
FcValueList *list,
- FcBool append)
+ FcBool append,
+ FamilyTable *table)
{
if (list)
{
@@ -1786,7 +1925,7 @@ FcConfigPatternAdd (FcPattern *p,
if (!e)
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
FcConfigPatternDel (FcPattern *p,
- FcObject object)
+ FcObject object,
+ FamilyTable *table)
{
FcPatternElt *e = FcPatternObjectFindElt (p, object);
if (!e)
return;
while (e->values != NULL)
- FcConfigDel (&e->values, e->values);
+ FcConfigDel (&e->values, e->values, object, table);
}
static void
@@ -1834,6 +1974,8 @@ FcConfigSubstituteWithPat (FcConfig *config,
int i, nobjs;
FcBool retval = FcTrue;
FcTest **tst = NULL;
+ FamilyTable data;
+ FamilyTable *table = &data;
if (kind < FcMatchKindBegin || kind >= FcMatchKindEnd)
return FcFalse;
@@ -1931,6 +2073,9 @@ FcConfigSubstituteWithPat (FcConfig *config,
printf ("FcConfigSubstitute ");
FcPatternPrint (p);
}
+
+ FamilyTableInit (&data, p);
+
FcPtrListIterInit (s, &iter);
for (; FcPtrListIterIsValid (s, &iter); FcPtrListIterNext (s, &iter))
{
@@ -1967,9 +2112,15 @@ FcConfigSubstituteWithPat (FcConfig *config,
FcTestPrint (r->u.test);
}
if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
+ {
m = p_pat;
+ table = NULL;
+ }
else
+ {
m = p;
+ table = &data;
+ }
if (m)
e = FcPatternObjectFindElt (m, r->u.test->object);
else
@@ -2002,7 +2153,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
* Check to see if there is a match, mark the location
* 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 */
if (!value[object] && kind == r->u.test->kind)
value[object] = vl;
@@ -2026,7 +2177,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
/*
* 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))
elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
@@ -2044,12 +2195,12 @@ FcConfigSubstituteWithPat (FcConfig *config,
/*
* 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
*/
if (thisValue)
- FcConfigDel (&elt[object]->values, thisValue);
+ FcConfigDel (&elt[object]->values, thisValue, object, table);
/*
* Adjust a pointer into the value list to ensure
* future edits occur at the same place
@@ -2063,8 +2214,8 @@ FcConfigSubstituteWithPat (FcConfig *config,
* Delete all of the values and insert
* the new set
*/
- FcConfigPatternDel (p, r->u.edit->object);
- FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
+ FcConfigPatternDel (p, r->u.edit->object, table);
+ FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
/*
* Adjust a pointer into the value list as they no
* longer point to anything valid
@@ -2074,33 +2225,33 @@ FcConfigSubstituteWithPat (FcConfig *config,
case FcOpPrepend:
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;
}
/* fall through ... */
case FcOpPrependFirst:
- FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
+ FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse, table);
break;
case FcOpAppend:
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;
}
/* fall through ... */
case FcOpAppendLast:
- FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
+ FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue, table);
break;
case FcOpDelete:
if (value[object])
{
- FcConfigDel (&elt[object]->values, value[object]);
+ FcConfigDel (&elt[object]->values, value[object], object, table);
FcValueListDestroy (l);
break;
}
/* fall through ... */
case FcOpDeleteAll:
- FcConfigPatternDel (p, r->u.edit->object);
+ FcConfigPatternDel (p, r->u.edit->object, table);
FcValueListDestroy (l);
break;
default:
@@ -2130,6 +2281,7 @@ FcConfigSubstituteWithPat (FcConfig *config,
FcPatternPrint (p);
}
bail1:
+ FamilyTableClear (&data);
if (elt)
free (elt);
if (value)
commit 7deb07e38e31da787875cb65db2ecb0dc0d5807f
Author: Matthias Clasen <mclasen at redhat.com>
Date: Fri Aug 21 09:12:35 2020 -0400
Speed up FcCompareLang and FcCompareBool
Avoid FcCanonicalize here too.
diff --git a/src/fcmatch.c b/src/fcmatch.c
index 289204e..16d03de 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -104,30 +104,27 @@ static double
FcCompareLang (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
{
FcLangResult result;
- FcValue value1 = FcValueCanonicalize(v1), value2 = FcValueCanonicalize(v2);
- switch ((int) value1.type) {
+ switch ((int) v1->type) {
case FcTypeLangSet:
- switch ((int) value2.type) {
+ switch ((int) v2->type) {
case FcTypeLangSet:
- result = FcLangSetCompare (value1.u.l, value2.u.l);
+ result = FcLangSetCompare (FcValueLangSet (v1), FcValueLangSet (v2));
break;
case FcTypeString:
- result = FcLangSetHasLang (value1.u.l,
- value2.u.s);
+ result = FcLangSetHasLang (FcValueLangSet (v1), FcValueString (v2));
break;
default:
return -1.0;
}
break;
case FcTypeString:
- switch ((int) value2.type) {
+ switch ((int) v2->type) {
case FcTypeLangSet:
- result = FcLangSetHasLang (value2.u.l, value1.u.s);
+ result = FcLangSetHasLang (FcValueLangSet (v2), FcValueString (v1));
break;
case FcTypeString:
- result = FcLangCompare (value1.u.s,
- value2.u.s);
+ result = FcLangCompare (FcValueString (v1), FcValueString (v2));
break;
default:
return -1.0;
@@ -154,10 +151,11 @@ FcCompareBool (const FcValue *v1, const FcValue *v2, FcValue *bestValue)
if (v2->type != FcTypeBool || v1->type != FcTypeBool)
return -1.0;
+ bestValue->type = FcTypeBool;
if (v2->u.b != FcDontCare)
- *bestValue = FcValueCanonicalize (v2);
+ bestValue->u.b = v2->u.b;
else
- *bestValue = FcValueCanonicalize (v1);
+ bestValue->u.b = v1->u.b;
return (double) ((v2->u.b ^ v1->u.b) == 1);
}
commit 09729c9032e66da30c24d8268e444b2e6dd0e0d7
Author: Matthias Clasen <mclasen at redhat.com>
Date: Fri Aug 21 00:49:04 2020 -0400
Speed up FcConfigCompareValue
Avoid FcValueCanonicalize when we can, to avoid
unnecessary copying of FcValue structs.
diff --git a/src/fccfg.c b/src/fccfg.c
index 8e7a682..803cd68 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -982,192 +982,215 @@ FcConfigCompareValue (const FcValue *left_o,
unsigned int op_,
const FcValue *right_o)
{
- FcValue left = FcValueCanonicalize(left_o);
- FcValue right = FcValueCanonicalize(right_o);
+ FcValue left;
+ FcValue right;
FcBool ret = FcFalse;
FcOp op = FC_OP_GET_OP (op_);
int flags = FC_OP_GET_FLAGS (op_);
- if (left.type != right.type)
+ if (left_o->type != right_o->type)
{
+ left = FcValueCanonicalize(left_o);
+ right = FcValueCanonicalize(right_o);
FcValuePromotionBuffer buf1, buf2;
left = FcConfigPromote (left, right, &buf1);
right = FcConfigPromote (right, left, &buf2);
- if (left.type != right.type)
+ left_o = &left;
+ right_o = &right;
+ if (left_o->type != right_o->type)
{
if (op == FcOpNotEqual || op == FcOpNotContains)
ret = FcTrue;
return ret;
}
}
- switch (left.type) {
+ switch (left_o->type) {
case FcTypeUnknown:
break; /* No way to guess how to compare for this object */
- case FcTypeInteger:
+ case FcTypeInteger: {
+ int l = left_o->u.i;
+ int r = right_o->u.i;
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
- ret = left.u.i == right.u.i;
+ ret = l == r;
break;
case FcOpNotEqual:
case FcOpNotContains:
- ret = left.u.i != right.u.i;
+ ret = l != r;
break;
case FcOpLess:
- ret = left.u.i < right.u.i;
+ ret = l < r;
break;
case FcOpLessEqual:
- ret = left.u.i <= right.u.i;
+ ret = l <= r;
break;
case FcOpMore:
- ret = left.u.i > right.u.i;
+ ret = l > r;
break;
case FcOpMoreEqual:
- ret = left.u.i >= right.u.i;
+ ret = l >= r;
break;
default:
break;
}
break;
- case FcTypeDouble:
+ }
+ case FcTypeDouble: {
+ double l = left_o->u.d;
+ double r = right_o->u.d;
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
- ret = left.u.d == right.u.d;
+ ret = l == r;
break;
case FcOpNotEqual:
case FcOpNotContains:
- ret = left.u.d != right.u.d;
+ ret = l != r;
break;
case FcOpLess:
- ret = left.u.d < right.u.d;
+ ret = l < r;
break;
case FcOpLessEqual:
- ret = left.u.d <= right.u.d;
+ ret = l <= r;
break;
case FcOpMore:
- ret = left.u.d > right.u.d;
+ ret = l > r;
break;
case FcOpMoreEqual:
- ret = left.u.d >= right.u.d;
+ ret = l >= r;
break;
default:
break;
}
break;
- case FcTypeBool:
+ }
+ case FcTypeBool: {
+ FcBool l = left_o->u.b;
+ FcBool r = right_o->u.b;
switch ((int) op) {
case FcOpEqual:
- ret = left.u.b == right.u.b;
+ ret = l == r;
break;
case FcOpContains:
case FcOpListing:
- ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
+ ret = l == r || l >= FcDontCare;
break;
case FcOpNotEqual:
- ret = left.u.b != right.u.b;
+ ret = l != r;
break;
case FcOpNotContains:
- ret = !(left.u.b == right.u.b || left.u.b >= FcDontCare);
+ ret = !(l == r || l >= FcDontCare);
break;
case FcOpLess:
- ret = left.u.b != right.u.b && right.u.b >= FcDontCare;
+ ret = l != r && r >= FcDontCare;
break;
case FcOpLessEqual:
- ret = left.u.b == right.u.b || right.u.b >= FcDontCare;
+ ret = l == r || r >= FcDontCare;
break;
case FcOpMore:
- ret = left.u.b != right.u.b && left.u.b >= FcDontCare;
+ ret = l != r && l >= FcDontCare;
break;
case FcOpMoreEqual:
- ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
+ ret = l == r || l >= FcDontCare;
break;
default:
break;
}
break;
- case FcTypeString:
+ }
+ case FcTypeString: {
+ const FcChar8 *l = FcValueString (left_o);
+ const FcChar8 *r = FcValueString (right_o);
switch ((int) op) {
case FcOpEqual:
case FcOpListing:
if (flags & FcOpFlagIgnoreBlanks)
- ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
+ ret = FcStrCmpIgnoreBlanksAndCase (l, r) == 0;
else
- ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
+ ret = FcStrCmpIgnoreCase (l, r) == 0;
break;
case FcOpContains:
- ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
+ ret = FcStrStrIgnoreCase (l, r) != 0;
break;
case FcOpNotEqual:
if (flags & FcOpFlagIgnoreBlanks)
- ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
+ ret = FcStrCmpIgnoreBlanksAndCase (l, r) != 0;
else
- ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
+ ret = FcStrCmpIgnoreCase (l, r) != 0;
break;
case FcOpNotContains:
- ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
+ ret = FcStrStrIgnoreCase (l, r) == 0;
break;
default:
break;
}
break;
- case FcTypeMatrix:
+ }
+ case FcTypeMatrix: {
switch ((int) op) {
case FcOpEqual:
case FcOpContains:
case FcOpListing:
- ret = FcMatrixEqual (left.u.m, right.u.m);
+ ret = FcMatrixEqual (left_o->u.m, right_o->u.m);
break;
case FcOpNotEqual:
case FcOpNotContains:
- ret = !FcMatrixEqual (left.u.m, right.u.m);
+ ret = !FcMatrixEqual (left_o->u.m, right_o->u.m);
break;
default:
break;
}
break;
- case FcTypeCharSet:
+ }
+ case FcTypeCharSet: {
+ const FcCharSet *l = FcValueCharSet (left_o);
+ const FcCharSet *r = FcValueCharSet (right_o);
switch ((int) op) {
case FcOpContains:
case FcOpListing:
/* left contains right if right is a subset of left */
- ret = FcCharSetIsSubset (right.u.c, left.u.c);
+ ret = FcCharSetIsSubset (r, l);
break;
case FcOpNotContains:
/* left contains right if right is a subset of left */
- ret = !FcCharSetIsSubset (right.u.c, left.u.c);
+ ret = !FcCharSetIsSubset (r, l);
break;
case FcOpEqual:
- ret = FcCharSetEqual (left.u.c, right.u.c);
+ ret = FcCharSetEqual (l, r);
break;
case FcOpNotEqual:
- ret = !FcCharSetEqual (left.u.c, right.u.c);
+ ret = !FcCharSetEqual (l, r);
break;
default:
break;
}
break;
- case FcTypeLangSet:
+ }
+ case FcTypeLangSet: {
+ const FcLangSet *l = FcValueLangSet (left_o);
+ const FcLangSet *r = FcValueLangSet (right_o);
switch ((int) op) {
case FcOpContains:
case FcOpListing:
- ret = FcLangSetContains (left.u.l, right.u.l);
+ ret = FcLangSetContains (l, r);
break;
case FcOpNotContains:
- ret = !FcLangSetContains (left.u.l, right.u.l);
+ ret = !FcLangSetContains (l, r);
break;
case FcOpEqual:
- ret = FcLangSetEqual (left.u.l, right.u.l);
+ ret = FcLangSetEqual (l, r);
break;
case FcOpNotEqual:
- ret = !FcLangSetEqual (left.u.l, right.u.l);
+ ret = !FcLangSetEqual (l, r);
break;
default:
break;
}
break;
+ }
case FcTypeVoid:
switch ((int) op) {
case FcOpEqual:
@@ -1184,20 +1207,23 @@ FcConfigCompareValue (const FcValue *left_o,
case FcOpEqual:
case FcOpContains:
case FcOpListing:
- ret = left.u.f == right.u.f;
+ ret = left_o->u.f == right_o->u.f;
break;
case FcOpNotEqual:
case FcOpNotContains:
- ret = left.u.f != right.u.f;
+ ret = left_o->u.f != right_o->u.f;
break;
default:
break;
}
break;
- case FcTypeRange:
- ret = FcRangeCompare (op, left.u.r, right.u.r);
+ case FcTypeRange: {
+ const FcRange *l = FcValueRange (left_o);
+ const FcRange *r = FcValueRange (right_o);
+ ret = FcRangeCompare (op, l, r);
break;
}
+ }
return ret;
}
commit 9d4e5d0f25dd592316d1728f95f40fe5967b120c
Author: Matthias Clasen <mclasen at redhat.com>
Date: Thu Aug 20 23:45:19 2020 -0400
Speed up FcConfigCompareValue
Make FcConfigPromote use a switch instead of
an if-else cascade, and avoid calling it when
we can.
Note that we need to add a case for integers
in FcConfigCompareValue, since we are no longer
promoting integers to doubles unconditionally.
diff --git a/src/fccfg.c b/src/fccfg.c
index cb4d3e0..8e7a682 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -934,35 +934,45 @@ FcConfigAddRule (FcConfig *config,
static FcValue
FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
{
- if (v.type == FcTypeInteger)
- {
- v.type = FcTypeDouble;
- v.u.d = (double) v.u.i;
- }
- else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
- {
- v.u.m = &FcIdentityMatrix;
- v.type = FcTypeMatrix;
- }
- else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
- {
- v.u.l = FcLangSetPromote (v.u.s, buf);
- v.type = FcTypeLangSet;
- }
- else if (buf && v.type == FcTypeVoid && u.type == FcTypeLangSet)
- {
- v.u.l = FcLangSetPromote (NULL, buf);
- v.type = FcTypeLangSet;
- }
- else if (buf && v.type == FcTypeVoid && u.type == FcTypeCharSet)
- {
- v.u.c = FcCharSetPromote (buf);
- v.type = FcTypeCharSet;
- }
- if (buf && v.type == FcTypeDouble && u.type == FcTypeRange)
- {
- v.u.r = FcRangePromote (v.u.d, buf);
- v.type = FcTypeRange;
+ switch (v.type)
+ {
+ case FcTypeInteger:
+ v.type = FcTypeDouble;
+ v.u.d = (double) v.u.i;
+ break;
+ case FcTypeVoid:
+ if (u.type == FcTypeMatrix)
+ {
+ v.u.m = &FcIdentityMatrix;
+ v.type = FcTypeMatrix;
+ }
+ else if (u.type == FcTypeLangSet && buf)
+ {
+ v.u.l = FcLangSetPromote (NULL, buf);
+ v.type = FcTypeLangSet;
+ }
+ else if (u.type == FcTypeCharSet && buf)
+ {
+ v.u.c = FcCharSetPromote (buf);
+ v.type = FcTypeCharSet;
+ }
+ break;
+ case FcTypeString:
+ if (u.type == FcTypeLangSet && buf)
+ {
+ v.u.l = FcLangSetPromote (v.u.s, buf);
+ v.type = FcTypeLangSet;
+ }
+ break;
+ case FcTypeDouble:
+ if (u.type == FcTypeRange && buf)
+ {
+ v.u.r = FcRangePromote (v.u.d, buf);
+ v.type = FcTypeRange;
+ }
+ break;
+ default:
+ break;
}
return v;
}
@@ -972,195 +982,221 @@ FcConfigCompareValue (const FcValue *left_o,
unsigned int op_,
const FcValue *right_o)
{
- FcValue left = FcValueCanonicalize(left_o);
- FcValue right = FcValueCanonicalize(right_o);
+ FcValue left = FcValueCanonicalize(left_o);
+ FcValue right = FcValueCanonicalize(right_o);
FcBool ret = FcFalse;
FcOp op = FC_OP_GET_OP (op_);
int flags = FC_OP_GET_FLAGS (op_);
- FcValuePromotionBuffer buf1, buf2;
- left = FcConfigPromote (left, right, &buf1);
- right = FcConfigPromote (right, left, &buf2);
- if (left.type == right.type)
- {
- switch (left.type) {
- case FcTypeUnknown:
- break; /* No way to guess how to compare for this object */
- case FcTypeInteger:
- break; /* FcConfigPromote prevents this from happening */
- case FcTypeDouble:
- switch ((int) op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = left.u.d == right.u.d;
- break;
- case FcOpNotEqual:
- case FcOpNotContains:
- ret = left.u.d != right.u.d;
- break;
- case FcOpLess:
- ret = left.u.d < right.u.d;
- break;
- case FcOpLessEqual:
- ret = left.u.d <= right.u.d;
- break;
- case FcOpMore:
- ret = left.u.d > right.u.d;
- break;
- case FcOpMoreEqual:
- ret = left.u.d >= right.u.d;
- break;
- default:
- break;
- }
- break;
- case FcTypeBool:
- switch ((int) op) {
- case FcOpEqual:
- ret = left.u.b == right.u.b;
- break;
- case FcOpContains:
- case FcOpListing:
- ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
- break;
- case FcOpNotEqual:
- ret = left.u.b != right.u.b;
- break;
- case FcOpNotContains:
- ret = !(left.u.b == right.u.b || left.u.b >= FcDontCare);
- break;
- case FcOpLess:
- ret = left.u.b != right.u.b && right.u.b >= FcDontCare;
- break;
- case FcOpLessEqual:
- ret = left.u.b == right.u.b || right.u.b >= FcDontCare;
- break;
- case FcOpMore:
- ret = left.u.b != right.u.b && left.u.b >= FcDontCare;
- break;
- case FcOpMoreEqual:
- ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
- break;
- default:
- break;
- }
- break;
- case FcTypeString:
- switch ((int) op) {
- case FcOpEqual:
- case FcOpListing:
- if (flags & FcOpFlagIgnoreBlanks)
- ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
- else
- ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
- break;
- case FcOpContains:
- ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
- break;
- case FcOpNotEqual:
- if (flags & FcOpFlagIgnoreBlanks)
- ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
- else
- ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
- break;
- case FcOpNotContains:
- ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
- break;
- default:
- break;
- }
- break;
- case FcTypeMatrix:
- switch ((int) op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = FcMatrixEqual (left.u.m, right.u.m);
- break;
- case FcOpNotEqual:
- case FcOpNotContains:
- ret = !FcMatrixEqual (left.u.m, right.u.m);
- break;
- default:
- break;
- }
- break;
- case FcTypeCharSet:
- switch ((int) op) {
- case FcOpContains:
- case FcOpListing:
- /* left contains right if right is a subset of left */
- ret = FcCharSetIsSubset (right.u.c, left.u.c);
- break;
- case FcOpNotContains:
- /* left contains right if right is a subset of left */
- ret = !FcCharSetIsSubset (right.u.c, left.u.c);
- break;
- case FcOpEqual:
- ret = FcCharSetEqual (left.u.c, right.u.c);
- break;
- case FcOpNotEqual:
- ret = !FcCharSetEqual (left.u.c, right.u.c);
- break;
- default:
- break;
- }
- break;
- case FcTypeLangSet:
- switch ((int) op) {
- case FcOpContains:
- case FcOpListing:
- ret = FcLangSetContains (left.u.l, right.u.l);
- break;
- case FcOpNotContains:
- ret = !FcLangSetContains (left.u.l, right.u.l);
- break;
- case FcOpEqual:
- ret = FcLangSetEqual (left.u.l, right.u.l);
- break;
- case FcOpNotEqual:
- ret = !FcLangSetEqual (left.u.l, right.u.l);
- break;
- default:
- break;
- }
- break;
- case FcTypeVoid:
- switch ((int) op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = FcTrue;
- break;
- default:
- break;
- }
- break;
- case FcTypeFTFace:
- switch ((int) op) {
- case FcOpEqual:
- case FcOpContains:
- case FcOpListing:
- ret = left.u.f == right.u.f;
- break;
- case FcOpNotEqual:
- case FcOpNotContains:
- ret = left.u.f != right.u.f;
- break;
- default:
- break;
- }
- break;
- case FcTypeRange:
- ret = FcRangeCompare (op, left.u.r, right.u.r);
- break;
- }
- }
- else
- {
- if (op == FcOpNotEqual || op == FcOpNotContains)
- ret = FcTrue;
+ if (left.type != right.type)
+ {
+ FcValuePromotionBuffer buf1, buf2;
+ left = FcConfigPromote (left, right, &buf1);
+ right = FcConfigPromote (right, left, &buf2);
+ if (left.type != right.type)
+ {
+ if (op == FcOpNotEqual || op == FcOpNotContains)
+ ret = FcTrue;
+ return ret;
+ }
+ }
+ switch (left.type) {
+ case FcTypeUnknown:
+ break; /* No way to guess how to compare for this object */
+ case FcTypeInteger:
+ switch ((int) op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = left.u.i == right.u.i;
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = left.u.i != right.u.i;
+ break;
+ case FcOpLess:
+ ret = left.u.i < right.u.i;
+ break;
+ case FcOpLessEqual:
+ ret = left.u.i <= right.u.i;
+ break;
+ case FcOpMore:
+ ret = left.u.i > right.u.i;
+ break;
+ case FcOpMoreEqual:
+ ret = left.u.i >= right.u.i;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeDouble:
+ switch ((int) op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = left.u.d == right.u.d;
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = left.u.d != right.u.d;
+ break;
+ case FcOpLess:
+ ret = left.u.d < right.u.d;
+ break;
+ case FcOpLessEqual:
+ ret = left.u.d <= right.u.d;
+ break;
+ case FcOpMore:
+ ret = left.u.d > right.u.d;
+ break;
+ case FcOpMoreEqual:
+ ret = left.u.d >= right.u.d;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeBool:
+ switch ((int) op) {
+ case FcOpEqual:
+ ret = left.u.b == right.u.b;
+ break;
+ case FcOpContains:
+ case FcOpListing:
+ ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
+ break;
+ case FcOpNotEqual:
+ ret = left.u.b != right.u.b;
+ break;
+ case FcOpNotContains:
+ ret = !(left.u.b == right.u.b || left.u.b >= FcDontCare);
+ break;
+ case FcOpLess:
+ ret = left.u.b != right.u.b && right.u.b >= FcDontCare;
+ break;
+ case FcOpLessEqual:
+ ret = left.u.b == right.u.b || right.u.b >= FcDontCare;
+ break;
+ case FcOpMore:
+ ret = left.u.b != right.u.b && left.u.b >= FcDontCare;
+ break;
+ case FcOpMoreEqual:
+ ret = left.u.b == right.u.b || left.u.b >= FcDontCare;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeString:
+ switch ((int) op) {
+ case FcOpEqual:
+ case FcOpListing:
+ if (flags & FcOpFlagIgnoreBlanks)
+ ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
+ else
+ ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
+ break;
+ case FcOpContains:
+ ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
+ break;
+ case FcOpNotEqual:
+ if (flags & FcOpFlagIgnoreBlanks)
+ ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
+ else
+ ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
+ break;
+ case FcOpNotContains:
+ ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeMatrix:
+ switch ((int) op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = FcMatrixEqual (left.u.m, right.u.m);
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = !FcMatrixEqual (left.u.m, right.u.m);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeCharSet:
+ switch ((int) op) {
+ case FcOpContains:
+ case FcOpListing:
+ /* left contains right if right is a subset of left */
+ ret = FcCharSetIsSubset (right.u.c, left.u.c);
+ break;
+ case FcOpNotContains:
+ /* left contains right if right is a subset of left */
+ ret = !FcCharSetIsSubset (right.u.c, left.u.c);
+ break;
+ case FcOpEqual:
+ ret = FcCharSetEqual (left.u.c, right.u.c);
+ break;
+ case FcOpNotEqual:
+ ret = !FcCharSetEqual (left.u.c, right.u.c);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeLangSet:
+ switch ((int) op) {
+ case FcOpContains:
+ case FcOpListing:
+ ret = FcLangSetContains (left.u.l, right.u.l);
+ break;
+ case FcOpNotContains:
+ ret = !FcLangSetContains (left.u.l, right.u.l);
+ break;
+ case FcOpEqual:
+ ret = FcLangSetEqual (left.u.l, right.u.l);
+ break;
+ case FcOpNotEqual:
+ ret = !FcLangSetEqual (left.u.l, right.u.l);
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeVoid:
+ switch ((int) op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = FcTrue;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeFTFace:
+ switch ((int) op) {
+ case FcOpEqual:
+ case FcOpContains:
+ case FcOpListing:
+ ret = left.u.f == right.u.f;
+ break;
+ case FcOpNotEqual:
+ case FcOpNotContains:
+ ret = left.u.f != right.u.f;
+ break;
+ default:
+ break;
+ }
+ break;
+ case FcTypeRange:
+ ret = FcRangeCompare (op, left.u.r, right.u.r);
+ break;
}
return ret;
}
commit 922168afe8bf48e872dc0a808fadefaa798a42ce
Author: Matthias Clasen <mclasen at redhat.com>
Date: Fri Aug 21 08:19:13 2020 -0400
Speed up fonthashint matching
When we don't need to differentiate between weak and strong,
we can exit the loop in FcCompareValueList once we found a
best match.
This change helps reducing the amount of list walking we do
for fonthashint, where careless config files end up creating
lists with ~100 booleans :( We don't want to walk all those
to the end, over and over again.
We are already special-casing family, and the only other case
where weak != strong, PostScript names, doesn't have long lists
of values, so the limitation to weak == strong doesn't matter
much in practice.
diff --git a/src/fcmatch.c b/src/fcmatch.c
index 969b855..289204e 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -408,6 +408,7 @@ FcCompareValueList (FcObject object,
FcValueListPtr v1, v2;
double v, best, bestStrong, bestWeak;
int j, k, pos = 0;
+ int weak, strong;
if (!match)
{
@@ -418,11 +419,13 @@ FcCompareValueList (FcObject object,
return FcTrue;
}
+ weak = match->weak;
+ strong = match->strong;
+
best = 1e99;
bestStrong = 1e99;
bestWeak = 1e99;
- j = 0;
- for (v1 = v1orig; v1; v1 = FcValueListNext(v1))
+ for (v1 = v1orig, j = 0; v1; v1 = FcValueListNext(v1), j++)
{
for (v2 = v2orig, k = 0; v2; v2 = FcValueListNext(v2), k++)
{
@@ -441,7 +444,13 @@ FcCompareValueList (FcObject object,
best = v;
pos = k;
}
- if (v1->binding == FcValueBindingStrong)
+ if (weak == strong)
+ {
+ /* found the best possible match */
+ if (best < 1000)
+ goto done;
+ }
+ else if (v1->binding == FcValueBindingStrong)
{
if (v < bestStrong)
bestStrong = v;
@@ -452,8 +461,8 @@ FcCompareValueList (FcObject object,
bestWeak = v;
}
}
- j++;
}
+done:
if (FcDebug () & FC_DBG_MATCHV)
{
printf (" %s: %g ", FcObjectName (object), best);
@@ -464,8 +473,6 @@ FcCompareValueList (FcObject object,
}
if (value)
{
- int weak = match->weak;
- int strong = match->strong;
if (weak == strong)
value[strong] += best;
else
commit 1b0cb23adcdf0c2b136b41d805b157f0c6d75ad4
Author: Matthias Clasen <mclasen at redhat.com>
Date: Tue Aug 18 15:02:21 2020 -0400
Add a shortcut for FcQualAny matching
When checking whether a test matches a pattern,
we cut the loop short for FcQualAll when we see
the first non-matching value, but for FcQualAny
we were always walking the full list. This patch
cuts the loop short for FcQualAny when we see the
first matching value.
diff --git a/src/fccfg.c b/src/fccfg.c
index 74e8746..cb4d3e0 100644
--- a/src/fccfg.c
+++ b/src/fccfg.c
@@ -1550,6 +1550,8 @@ FcConfigMatchValueList (FcPattern *p,
{
if (!ret)
ret = v;
+ if (t->qual != FcQualAll)
+ break;
}
else
{
commit 8022ab4aff469a8f095ce3168d879d3e0b3605ef
Author: Matthias Clasen <mclasen at redhat.com>
Date: Tue Aug 18 10:54:43 2020 -0400
Use a hash table for family matching
With the way typical font configurations look, matching the lists
of families is the bottleneck for both FcFontMatch and FcFontSort.
After installing the Noto fonts on my system, an innocent match
pattern like "Cantarell 14" turns into a monster with a list of
300 family names after calling FcConfigSubstitute().
With this setup, every FcFontSort call takes 80-100 ms, which is
entirely incompatible with using FcFontSort for anything interactive.
And many font choosers render every font in itself, causing on average
one FcFontSort call per font.
On my system, it takes more than 20 seconds to open the GTK font
chooser dialog, with frequent stalls when scrolling.
This patch special-cases font families and replaces the list
walking for comparison with a hash table lookup. With this
patch, the FcFontSort time goes to ~10ms per call. Which is
still not good enough for calling it dozens of times when
scrolling, but a significant improvement.
diff --git a/src/fcmatch.c b/src/fcmatch.c
index e370e8b..969b855 100644
--- a/src/fcmatch.c
+++ b/src/fcmatch.c
@@ -480,6 +480,109 @@ FcCompareValueList (FcObject object,
return FcTrue;
}
+/* The bulk of the time in FcFontMatch and FcFontSort goes to
+ * walking long lists of family names. We speed this up with a
+ * hash table.
+ */
+typedef struct
+{
+ double strong_value;
+ double weak_value;
+} FamilyEntry;
+
+typedef struct
+{
+ FcHashTable *family_hash;
+} FcCompareData;
+
+static void
+FcCompareDataClear (FcCompareData *data)
+{
+ FcHashTableDestroy (data->family_hash);
+}
+
+static void
+FcCompareDataInit (FcPattern *pat,
+ FcCompareData *data)
+{
+ FcHashTable *table;
+ FcPatternElt *elt;
+ FcValueListPtr l;
+ int i;
+ const void *key;
+ FamilyEntry *e;
+
+ table = FcHashTableCreate ((FcHashFunc)FcStrHashIgnoreBlanksAndCase,
+ (FcCompareFunc)FcStrCmpIgnoreBlanksAndCase,
+ NULL,
+ NULL,
+ NULL,
+ free);
+
+ elt = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
+ for (l = FcPatternEltValues(elt), i = 0; l; l = FcValueListNext(l), i++)
+ {
+ key = FcValueString (&l->value);
+ if (!FcHashTableFind (table, key, (void **)&e))
+ {
+ e = malloc (sizeof (FamilyEntry));
+ e->strong_value = 1e99;
+ e->weak_value = 1e99;
+ FcHashTableAdd (table, (void *)key, e);
+ }
+ if (l->binding == FcValueBindingWeak)
+ {
+ if (i < e->weak_value)
+ e->weak_value = i;
+ }
+ else
+ {
+ if (i < e->strong_value)
+ e->strong_value = i;
+ }
+ }
+
+ data->family_hash = table;
+}
+
+static FcBool
+FcCompareFamilies (FcPattern *pat,
+ FcValueListPtr v1orig,
+ FcPattern *fnt,
+ FcValueListPtr v2orig,
+ double *value,
+ FcResult *result,
+ FcHashTable *table)
+{
+ FcValueListPtr v2;
+ double strong_value;
+ double weak_value;
+ const void *key;
+ FamilyEntry *e;
+
+ assert (table != NULL);
+
+ strong_value = 1e99;
+ weak_value = 1e99;
+
+ for (v2 = v2orig; v2; v2 = FcValueListNext(v2))
+ {
+ key = FcValueString (&v2->value);
+ if (FcHashTableFind (table, key, (void **)&e))
+ {
+ if (e->strong_value < strong_value)
+ strong_value = e->strong_value;
+ if (e->weak_value < weak_value)
+ weak_value = e->weak_value;
+ }
+ }
+
+ value[PRI_FAMILY_STRONG] = strong_value;
+ value[PRI_FAMILY_WEAK] = weak_value;
+
+ return FcTrue;
+}
+
/*
* Return a value indicating the distance between the two lists of
* values
@@ -489,7 +592,8 @@ static FcBool
FcCompare (FcPattern *pat,
FcPattern *fnt,
double *value,
- FcResult *result)
+ FcResult *result,
+ FcCompareData *data)
{
int i, i1, i2;
@@ -508,8 +612,18 @@ FcCompare (FcPattern *pat,
i2++;
else if (i < 0)
i1++;
- else
- {
+ else if (elt_i1->object == FC_FAMILY_OBJECT && data->family_hash)
+ {
+ if (!FcCompareFamilies (pat, FcPatternEltValues(elt_i1),
+ fnt, FcPatternEltValues(elt_i2),
+ value, result,
+ data->family_hash))
+ return FcFalse;
+ i1++;
+ i2++;
+ }
+ else
+ {
const FcMatcher *match = FcObjectToMatcher (elt_i1->object, FcFalse);
if (!FcCompareValueList (elt_i1->object, match,
FcPatternEltValues(elt_i1),
@@ -734,6 +848,7 @@ FcFontSetMatchInternal (FcFontSet **sets,
FcPattern *best;
int i;
int set;
+ FcCompareData data;
for (i = 0; i < PRI_END; i++)
bestscore[i] = 0;
@@ -743,6 +858,9 @@ FcFontSetMatchInternal (FcFontSet **sets,
printf ("Match ");
FcPatternPrint (p);
}
+
+ FcCompareDataInit (p, &data);
+
for (set = 0; set < nsets; set++)
{
s = sets[set];
@@ -755,8 +873,11 @@ FcFontSetMatchInternal (FcFontSet **sets,
printf ("Font %d ", f);
FcPatternPrint (s->fonts[f]);
}
- if (!FcCompare (p, s->fonts[f], score, result))
+ if (!FcCompare (p, s->fonts[f], score, result, &data))
+ {
+ FcCompareDataClear (&data);
return 0;
+ }
if (FcDebug () & FC_DBG_MATCHV)
{
printf ("Score");
@@ -780,6 +901,9 @@ FcFontSetMatchInternal (FcFontSet **sets,
}
}
}
+
+ FcCompareDataClear (&data);
+
if (FcDebug () & FC_DBG_MATCH)
{
printf ("Best score");
@@ -1015,6 +1139,7 @@ FcFontSetSort (FcConfig *config FC_UNUSED,
int nPatternLang;
FcBool *patternLangSat;
FcValue patternLang;
+ FcCompareData data;
assert (sets != NULL);
assert (p != NULL);
@@ -1059,6 +1184,8 @@ FcFontSetSort (FcConfig *config FC_UNUSED,
nodeps = (FcSortNode **) (nodes + nnodes);
patternLangSat = (FcBool *) (nodeps + nnodes);
+ FcCompareDataInit (p, &data);
+
new = nodes;
nodep = nodeps;
for (set = 0; set < nsets; set++)
@@ -1074,7 +1201,7 @@ FcFontSetSort (FcConfig *config FC_UNUSED,
FcPatternPrint (s->fonts[f]);
}
new->pattern = s->fonts[f];
- if (!FcCompare (p, new->pattern, new->score, result))
+ if (!FcCompare (p, new->pattern, new->score, result, &data))
goto bail1;
if (FcDebug () & FC_DBG_MATCHV)
{
@@ -1091,6 +1218,8 @@ FcFontSetSort (FcConfig *config FC_UNUSED,
}
}
+ FcCompareDataClear (&data);
+
nnodes = new - nodes;
qsort (nodeps, nnodes, sizeof (FcSortNode *),
commit 055843631b995f8acc778c94032c949844e8812b
Author: Matthias Clasen <mclasen at redhat.com>
Date: Fri Aug 21 08:05:18 2020 -0400
Add a hash function for families
Add a hash function that behaves like family
comparison: ignoring case and blanks. This
will be used to replace the list walking for
finding family matches with a hash table.
diff --git a/src/fcint.h b/src/fcint.h
index 88e0701..08a0cd6 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -1328,6 +1328,9 @@ FcStrLastSlash (const FcChar8 *path);
FcPrivate FcChar32
FcStrHashIgnoreCase (const FcChar8 *s);
+FcPrivate FcChar32
+FcStrHashIgnoreBlanksAndCase (const FcChar8 *s);
+
FcPrivate FcChar8 *
FcStrCanonFilename (const FcChar8 *s);
diff --git a/src/fcstr.c b/src/fcstr.c
index 39ecbbb..dc9940a 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -320,6 +320,19 @@ FcStrHashIgnoreCase (const FcChar8 *s)
return h;
}
+FcChar32
+FcStrHashIgnoreBlanksAndCase (const FcChar8 *s)
+{
+ FcChar32 h = 0;
+ FcCaseWalker w;
+ FcChar8 c;
+
+ FcStrCaseWalkerInit (s, &w);
+ while ((c = FcStrCaseWalkerNextNonBlank (&w)))
+ h = ((h << 3) ^ (h >> 3)) ^ c;
+ return h;
+}
+
/*
* Is the head of s1 equal to s2?
*/
commit 46d818df26f3585f9261c735129a606837406875
Author: Matthias Clasen <mclasen at redhat.com>
Date: Fri Aug 21 00:47:09 2020 -0400
Special-case some of the string walking code
Make variants of FcStrCaseWalkerNext for the two
common cases, delim == NULL and delim == " ", to
speed things up.
These are inner loops, and having the conditions
as simple as possible helps.
diff --git a/src/fcstr.c b/src/fcstr.c
index 864d4aa..39ecbbb 100644
--- a/src/fcstr.c
+++ b/src/fcstr.c
@@ -160,7 +160,7 @@ FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r)
}
static FcChar8
-FcStrCaseWalkerNext (FcCaseWalker *w, const char *delims)
+FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims)
{
FcChar8 r;
@@ -182,6 +182,50 @@ FcStrCaseWalkerNext (FcCaseWalker *w, const char *delims)
return r;
}
+static FcChar8
+FcStrCaseWalkerNextNonBlank (FcCaseWalker *w)
+{
+ FcChar8 r;
+
+ if (w->read)
+ {
+ if ((r = *w->read++))
+ return r;
+ w->read = 0;
+ }
+ do
+ {
+ r = *w->src++;
+ } while (r == ' ');
+
+ if ((r & 0xc0) == 0xc0)
+ return FcStrCaseWalkerLong (w, r);
+ if ('A' <= r && r <= 'Z')
+ r = r - 'A' + 'a';
+ return r;
+}
+
+static FcChar8
+FcStrCaseWalkerNext (FcCaseWalker *w)
+{
+ FcChar8 r;
+
+ if (w->read)
+ {
+ if ((r = *w->read++))
+ return r;
+ w->read = 0;
+ }
+
+ r = *w->src++;
+
+ if ((r & 0xc0) == 0xc0)
+ return FcStrCaseWalkerLong (w, r);
+ if ('A' <= r && r <= 'Z')
+ r = r - 'A' + 'a';
+ return r;
+}
+
FcChar8 *
FcStrDowncase (const FcChar8 *s)
{
@@ -190,13 +234,13 @@ FcStrDowncase (const FcChar8 *s)
FcChar8 *dst, *d;
FcStrCaseWalkerInit (s, &w);
- while (FcStrCaseWalkerNext (&w, NULL))
+ while (FcStrCaseWalkerNext (&w))
len++;
d = dst = malloc (len + 1);
if (!d)
return 0;
FcStrCaseWalkerInit (s, &w);
- while ((*d++ = FcStrCaseWalkerNext (&w, NULL)));
+ while ((*d++ = FcStrCaseWalkerNext (&w)));
return dst;
}
@@ -213,8 +257,8 @@ FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
for (;;)
{
- c1 = FcStrCaseWalkerNext (&w1, NULL);
- c2 = FcStrCaseWalkerNext (&w2, NULL);
+ c1 = FcStrCaseWalkerNext (&w1);
+ c2 = FcStrCaseWalkerNext (&w2);
if (!c1 || (c1 != c2))
break;
}
@@ -223,12 +267,6 @@ FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
int
FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
-{
- return FcStrCmpIgnoreCaseAndDelims (s1, s2, (const FcChar8 *)" ");
-}
-
-int
-FcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims)
{
FcCaseWalker w1, w2;
FcChar8 c1, c2;
@@ -240,8 +278,8 @@ FcStrCmpIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8
for (;;)
{
- c1 = FcStrCaseWalkerNext (&w1, (const char *)delims);
- c2 = FcStrCaseWalkerNext (&w2, (const char *)delims);
+ c1 = FcStrCaseWalkerNextNonBlank (&w1);
+ c2 = FcStrCaseWalkerNextNonBlank (&w2);
if (!c1 || (c1 != c2))
break;
}
@@ -277,7 +315,7 @@ FcStrHashIgnoreCase (const FcChar8 *s)
FcChar8 c;
FcStrCaseWalkerInit (s, &w);
- while ((c = FcStrCaseWalkerNext (&w, NULL)))
+ while ((c = FcStrCaseWalkerNext (&w)))
h = ((h << 3) ^ (h >> 3)) ^ c;
return h;
}
@@ -297,8 +335,8 @@ FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2)
for (;;)
{
- c1 = FcStrCaseWalkerNext (&w1, " ");
- c2 = FcStrCaseWalkerNext (&w2, " ");
+ c1 = FcStrCaseWalkerNextNonBlank (&w1);
+ c2 = FcStrCaseWalkerNextNonBlank (&w2);
if (!c1 || (c1 != c2))
break;
}
@@ -356,8 +394,8 @@ FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
for (;;)
{
- c1 = FcStrCaseWalkerNext (&w1, NULL);
- c2 = FcStrCaseWalkerNext (&w2, NULL);
+ c1 = FcStrCaseWalkerNext (&w1);
+ c2 = FcStrCaseWalkerNext (&w2);
if (!c1 || (c1 != c2))
break;
}
@@ -425,8 +463,8 @@ FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcCha
for (;;)
{
- c1 = FcStrCaseWalkerNext (&w1, (const char *)delims);
- c2 = FcStrCaseWalkerNext (&w2, (const char *)delims);
+ c1 = FcStrCaseWalkerNextNonDelim (&w1, (const char *)delims);
+ c2 = FcStrCaseWalkerNextNonDelim (&w2, (const char *)delims);
if (!c1 || (c1 != c2))
break;
}
@@ -493,12 +531,12 @@ FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
FcStrCaseWalkerInit (s1, &w1);
FcStrCaseWalkerInit (s2, &w2);
- c2 = FcStrCaseWalkerNext (&w2, NULL);
+ c2 = FcStrCaseWalkerNext (&w2);
for (;;)
{
cur = w1.src;
- c1 = FcStrCaseWalkerNext (&w1, NULL);
+ c1 = FcStrCaseWalkerNext (&w1);
if (!c1)
break;
if (c1 == c2)
@@ -509,8 +547,8 @@ FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2)
for (;;)
{
- c1t = FcStrCaseWalkerNext (&w1t, NULL);
- c2t = FcStrCaseWalkerNext (&w2t, NULL);
+ c1t = FcStrCaseWalkerNext (&w1t);
+ c2t = FcStrCaseWalkerNext (&w2t);
if (!c2t)
return cur;
More information about the Fontconfig
mailing list