Stephan Kulow <coolo@suse.de> Michael Matz <matz@suse.de> reviewed by: plam
Rewrite FcFontSetMatch to a path-finding based algorithm, i.e. inline FcCompare into FcFontSetMatch and reorder the loops, adding a boolean array which blocks patterns from future consideration if they're known to not be best on some past criterion.
This commit is contained in:
parent
200a44fed0
commit
aa472e5f1a
224
src/fcmatch.c
224
src/fcmatch.c
|
@ -267,25 +267,12 @@ FcMatchObjectPtrsInit (void)
|
||||||
matchObjectPtrsInit = FcTrue;
|
matchObjectPtrsInit = FcTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FcBool
|
static FcMatcher*
|
||||||
FcCompareValueList (FcObjectPtr o,
|
FcObjectPtrToMatcher (FcObjectPtr o)
|
||||||
FcValueListPtr v1orig, /* pattern */
|
|
||||||
FcValueListPtr v2orig, /* target */
|
|
||||||
FcValue *bestValue,
|
|
||||||
double *value,
|
|
||||||
FcResult *result)
|
|
||||||
{
|
{
|
||||||
FcValueListPtr v1, v2;
|
int i;
|
||||||
FcValueList *v1_ptrU, *v2_ptrU;
|
const char *object = FcObjectPtrU(o);
|
||||||
double v, best, bestStrong, bestWeak;
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
const char *object = FcObjectPtrU(o);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Locate the possible matching entry by examining the
|
|
||||||
* first few characters in object
|
|
||||||
*/
|
|
||||||
i = -1;
|
i = -1;
|
||||||
switch (object[0]) {
|
switch (object[0]) {
|
||||||
case 'f':
|
case 'f':
|
||||||
|
@ -334,18 +321,40 @@ FcCompareValueList (FcObjectPtr o,
|
||||||
i = MATCH_OUTLINE; break;
|
i = MATCH_OUTLINE; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!matchObjectPtrsInit)
|
if (!matchObjectPtrsInit)
|
||||||
FcMatchObjectPtrsInit();
|
FcMatchObjectPtrsInit();
|
||||||
if (_FcMatchers[i].objectPtr != o) i = -1;
|
|
||||||
|
|
||||||
if (i == -1 ||
|
if (o != _FcMatchers[i].objectPtr)
|
||||||
FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
|
return 0;
|
||||||
(FcChar8 *) object) != 0)
|
|
||||||
|
return _FcMatchers+i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FcBool
|
||||||
|
FcCompareValueList (FcObjectPtr o,
|
||||||
|
FcValueListPtr v1orig, /* pattern */
|
||||||
|
FcValueListPtr v2orig, /* target */
|
||||||
|
FcValue *bestValue,
|
||||||
|
double *value,
|
||||||
|
FcResult *result)
|
||||||
|
{
|
||||||
|
FcValueListPtr v1, v2;
|
||||||
|
FcValueList *v1_ptrU, *v2_ptrU;
|
||||||
|
double v, best, bestStrong, bestWeak;
|
||||||
|
int j;
|
||||||
|
const char *object = FcObjectPtrU(o);
|
||||||
|
FcMatcher *match = FcObjectPtrToMatcher(o);
|
||||||
|
|
||||||
|
if (!match)
|
||||||
{
|
{
|
||||||
if (bestValue)
|
if (bestValue)
|
||||||
*bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
|
*bestValue = FcValueCanonicalize(&FcValueListPtrU(v2orig)->value);
|
||||||
return FcTrue;
|
return FcTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
best = 1e99;
|
best = 1e99;
|
||||||
bestStrong = 1e99;
|
bestStrong = 1e99;
|
||||||
bestWeak = 1e99;
|
bestWeak = 1e99;
|
||||||
|
@ -356,8 +365,7 @@ FcCompareValueList (FcObjectPtr o,
|
||||||
for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); v2_ptrU;
|
for (v2 = v2orig, v2_ptrU = FcValueListPtrU(v2); v2_ptrU;
|
||||||
v2 = v2_ptrU->next, v2_ptrU = FcValueListPtrU(v2))
|
v2 = v2_ptrU->next, v2_ptrU = FcValueListPtrU(v2))
|
||||||
{
|
{
|
||||||
v = (*_FcMatchers[i].compare) (&v1_ptrU->value,
|
v = (match->compare) (&v1_ptrU->value, &v2_ptrU->value);
|
||||||
&v2_ptrU->value);
|
|
||||||
if (v < 0)
|
if (v < 0)
|
||||||
{
|
{
|
||||||
*result = FcResultTypeMismatch;
|
*result = FcResultTypeMismatch;
|
||||||
|
@ -393,8 +401,8 @@ FcCompareValueList (FcObjectPtr o,
|
||||||
}
|
}
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
int weak = _FcMatchers[i].weak;
|
int weak = match->weak;
|
||||||
int strong = _FcMatchers[i].strong;
|
int strong = match->strong;
|
||||||
if (weak == strong)
|
if (weak == strong)
|
||||||
value[strong] += best;
|
value[strong] += best;
|
||||||
else
|
else
|
||||||
|
@ -501,15 +509,14 @@ FcFontSetMatch (FcConfig *config,
|
||||||
FcPattern *p,
|
FcPattern *p,
|
||||||
FcResult *result)
|
FcResult *result)
|
||||||
{
|
{
|
||||||
double score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
|
double score;
|
||||||
|
double bestscore;
|
||||||
int f;
|
int f;
|
||||||
FcFontSet *s;
|
FcFontSet *s;
|
||||||
FcPattern *best;
|
FcPattern *best;
|
||||||
int i;
|
int scoring_index;
|
||||||
int set;
|
int set;
|
||||||
|
|
||||||
for (i = 0; i < NUM_MATCH_VALUES; i++)
|
|
||||||
bestscore[i] = 0;
|
|
||||||
best = 0;
|
best = 0;
|
||||||
if (FcDebug () & FC_DBG_MATCH)
|
if (FcDebug () & FC_DBG_MATCH)
|
||||||
{
|
{
|
||||||
|
@ -530,44 +537,131 @@ FcFontSetMatch (FcConfig *config,
|
||||||
s = sets[set];
|
s = sets[set];
|
||||||
if (!s)
|
if (!s)
|
||||||
continue;
|
continue;
|
||||||
for (f = 0; f < s->nfont; f++)
|
|
||||||
{
|
char* matchBlocked = (char*)calloc(s->nfont, sizeof(FcBool));
|
||||||
if (FcDebug () & FC_DBG_MATCHV)
|
|
||||||
{
|
/* The old algorithm checked if each font beat 'best',
|
||||||
printf ("Font %d ", f);
|
* scanning all of the value lists for all of the pattern elts. */
|
||||||
FcPatternPrint (s->fonts[f]);
|
/* This algorithm checks each font on a element-by-element basis
|
||||||
|
* and blocks fonts that have already lost on some element from
|
||||||
|
* further consideration from being best. Basically, we've
|
||||||
|
* swapped the order of loops and short-circuited fonts that
|
||||||
|
* are out of contention right away.
|
||||||
|
* This saves a lot of time! */
|
||||||
|
for (scoring_index = 0; scoring_index < NUM_MATCH_VALUES;
|
||||||
|
scoring_index++)
|
||||||
|
{
|
||||||
|
int pat_elt;
|
||||||
|
FcPatternElt *pat_elts = FcPatternEltU(p->elts);
|
||||||
|
FcMatcher *match = 0;
|
||||||
|
FcValueListPtr v1;
|
||||||
|
FcValueList *v1_ptrU;
|
||||||
|
int v1_offset = 0;
|
||||||
|
|
||||||
|
|
||||||
|
for (pat_elt = 0; pat_elt < p->num; pat_elt++)
|
||||||
|
{
|
||||||
|
match = FcObjectPtrToMatcher
|
||||||
|
((FcPatternEltU(p->elts)+pat_elt)->object);
|
||||||
|
|
||||||
|
if (match &&
|
||||||
|
(match->strong == scoring_index ||
|
||||||
|
match->weak == scoring_index))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
match = 0;
|
||||||
}
|
}
|
||||||
if (!FcCompare (p, s->fonts[f], score, result))
|
|
||||||
return 0;
|
if (!match)
|
||||||
if (FcDebug () & FC_DBG_MATCHV)
|
continue;
|
||||||
{
|
|
||||||
printf ("Score");
|
bestscore = 1e99;
|
||||||
for (i = 0; i < NUM_MATCH_VALUES; i++)
|
|
||||||
{
|
|
||||||
printf (" %g", score[i]);
|
for (v1 = pat_elts[pat_elt].values, v1_ptrU = FcValueListPtrU(v1);
|
||||||
|
v1_ptrU;
|
||||||
|
v1 = FcValueListPtrU(v1)->next,
|
||||||
|
v1_ptrU = FcValueListPtrU(v1), v1_offset++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (v1_ptrU->binding == FcValueBindingWeak
|
||||||
|
&& scoring_index != match->weak)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (f = 0; f < s->nfont; f++)
|
||||||
|
{
|
||||||
|
int cand_elt;
|
||||||
|
FcPatternElt *cand_elts;
|
||||||
|
|
||||||
|
if (matchBlocked[f])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
score = 0.0;
|
||||||
|
cand_elts = FcPatternEltU(s->fonts[f]->elts);
|
||||||
|
|
||||||
|
/* Look for the appropriate element in this candidate
|
||||||
|
* pattern 'f' and evaluate its score wrt 'p'. */
|
||||||
|
for (cand_elt = 0; cand_elt < s->fonts[f]->num; cand_elt++)
|
||||||
|
{
|
||||||
|
if (cand_elts[cand_elt].object ==
|
||||||
|
pat_elts[pat_elt].object)
|
||||||
|
{
|
||||||
|
FcValueListPtr v2;
|
||||||
|
FcValueList *v2_ptrU;
|
||||||
|
double v2_best_score = 1e99;
|
||||||
|
|
||||||
|
for (v2 = cand_elts[cand_elt].values,
|
||||||
|
v2_ptrU = FcValueListPtrU(v2);
|
||||||
|
FcValueListPtrU(v2);
|
||||||
|
v2 = FcValueListPtrU(v2)->next)
|
||||||
|
{
|
||||||
|
double v = (match->compare)
|
||||||
|
(&v1_ptrU->value, &v2_ptrU->value);
|
||||||
|
|
||||||
|
if (v < 0)
|
||||||
|
{
|
||||||
|
*result = FcResultTypeMismatch;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* I'm actually kind of surprised that
|
||||||
|
* this isn't v + 100 * v1_offset. -PL */
|
||||||
|
v = v * 100 + v1_offset;
|
||||||
|
if (v < v2_best_score)
|
||||||
|
v2_best_score = v;
|
||||||
|
}
|
||||||
|
score += v2_best_score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there's a previous champion, and current score
|
||||||
|
* beats previous best score, on this element, then
|
||||||
|
* knock out the previous champion and anything
|
||||||
|
* else that we would have visited previous to f;
|
||||||
|
* clearly anything previous to f would have been
|
||||||
|
* less than f on this score. */
|
||||||
|
if (!best || score < bestscore)
|
||||||
|
{
|
||||||
|
if (best)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
for (b = 0; b < f; ++b)
|
||||||
|
matchBlocked[b] = FcTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bestscore = score;
|
||||||
|
best = s->fonts[f];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If f loses, then it's out too. */
|
||||||
|
if (best && score > bestscore)
|
||||||
|
matchBlocked[f] = FcTrue;
|
||||||
|
|
||||||
|
/* Otherwise, f is equal to best on this element.
|
||||||
|
* Carry on to next pattern element. */
|
||||||
}
|
}
|
||||||
printf ("\n");
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < NUM_MATCH_VALUES; i++)
|
free (matchBlocked);
|
||||||
{
|
|
||||||
if (best && bestscore[i] < score[i])
|
|
||||||
break;
|
|
||||||
if (!best || score[i] < bestscore[i])
|
|
||||||
{
|
|
||||||
for (i = 0; i < NUM_MATCH_VALUES; i++)
|
|
||||||
bestscore[i] = score[i];
|
|
||||||
best = s->fonts[f];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (FcDebug () & FC_DBG_MATCH)
|
|
||||||
{
|
|
||||||
printf ("Best score");
|
|
||||||
for (i = 0; i < NUM_MATCH_VALUES; i++)
|
|
||||||
printf (" %g", bestscore[i]);
|
|
||||||
FcPatternPrint (best);
|
|
||||||
}
|
}
|
||||||
if (!best)
|
if (!best)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue