AddFcLangSetContains for font listing, add first-letter table for language

lookups, change RCS tag
This commit is contained in:
Keith Packard 2003-03-05 05:52:31 +00:00
parent 4bd4418ab5
commit 793e946c2f
4 changed files with 219 additions and 33 deletions

View File

@ -1,7 +1,7 @@
/* /*
* $XFree86: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $ * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
* *
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * Copyright © 2000 Keith Packard
* *
* Permission to use, copy, modify, distribute, and sell this software and its * Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that * documentation for any purpose is hereby granted without fee, provided that
@ -590,10 +590,10 @@ FcConfigCompareValue (const FcValue m_o,
case FcTypeLangSet: case FcTypeLangSet:
switch (op) { switch (op) {
case FcOpContains: case FcOpContains:
ret = FcLangSetCompare (v.u.l, m.u.l) != FcLangDifferentLang; ret = FcLangSetContains (v.u.l, m.u.l);
break; break;
case FcOpNotContains: case FcOpNotContains:
ret = FcLangSetCompare (v.u.l, m.u.l) == FcLangDifferentLang; ret = FcLangSetContains (v.u.l, m.u.l);
break; break;
case FcOpEqual: case FcOpEqual:
ret = FcLangSetEqual (v.u.l, m.u.l); ret = FcLangSetEqual (v.u.l, m.u.l);

View File

@ -1,7 +1,7 @@
/* /*
* $XFree86: xc/lib/fontconfig/src/fcint.h,v 1.27 2002/08/31 22:17:32 keithp Exp $ * $RCSId: xc/lib/fontconfig/src/fcint.h,v 1.27 2002/08/31 22:17:32 keithp Exp $
* *
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * Copyright © 2000 Keith Packard
* *
* Permission to use, copy, modify, distribute, and sell this software and its * Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that * documentation for any purpose is hereby granted without fee, provided that
@ -446,6 +446,9 @@ FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4);
void void
FcValueListPrint (const FcValueList *l); FcValueListPrint (const FcValueList *l);
void
FcLangSetPrint (const FcLangSet *ls);
void void
FcOpPrint (FcOp op); FcOpPrint (FcOp op);

View File

@ -1,7 +1,7 @@
/* /*
* $XFree86: xc/lib/fontconfig/src/fclang.c,v 1.7 2002/08/26 23:34:31 keithp Exp $ * $RCSId: xc/lib/fontconfig/src/fclang.c,v 1.7 2002/08/26 23:34:31 keithp Exp $
* *
* Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. * Copyright © 2002 Keith Packard
* *
* Permission to use, copy, modify, distribute, and sell this software and its * Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that * documentation for any purpose is hereby granted without fee, provided that
@ -29,6 +29,11 @@ typedef struct {
FcCharSet charset; FcCharSet charset;
} FcLangCharSet; } FcLangCharSet;
typedef struct {
int begin;
int end;
} FcLangCharSetRange;
#include "../fc-lang/fclang.h" #include "../fc-lang/fclang.h"
struct _FcLangSet { struct _FcLangSet {
@ -138,6 +143,37 @@ FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
} }
} }
/*
* Return FcTrue when s1 contains s2.
*
* s1 contains s2 if s1 equals s2 or if s1 is a
* language with a country and s2 is just a language
*/
static FcBool
FcLangContains (const FcChar8 *s1, const FcChar8 *s2)
{
FcChar8 c1, c2;
for (;;)
{
c1 = *s1++;
c2 = *s2++;
c1 = FcToLower (c1);
c2 = FcToLower (c2);
if (c1 != c2)
{
/* see if s1 has a country while s2 is mising one */
if (c1 == '-' && c2 == '\0')
return FcTrue;
return FcFalse;
}
else if (!c1)
return FcTrue;
}
}
const FcCharSet * const FcCharSet *
FcCharSetForLang (const FcChar8 *lang) FcCharSetForLang (const FcChar8 *lang)
{ {
@ -225,13 +261,52 @@ FcLangSetIndex (const FcChar8 *lang)
{ {
int low, high, mid; int low, high, mid;
int cmp; int cmp;
FcChar8 firstChar = FcToLower(lang[0]);
if (firstChar < 'a')
{
low = 0; low = 0;
high = fcLangCharSetRanges[0].begin;
}
else if(firstChar > 'z')
{
low = fcLangCharSetRanges[25].begin;
high = NUM_LANG_CHAR_SET - 1; high = NUM_LANG_CHAR_SET - 1;
}
else
{
low = fcLangCharSetRanges[firstChar - 'a'].begin;
high = fcLangCharSetRanges[firstChar - 'a'].end;
/* no matches */
if (low > high)
return -low; /* next entry after where it would be */
}
while (low <= high) while (low <= high)
{ {
mid = (high + low) >> 1; mid = (high + low) >> 1;
cmp = FcStrCmpIgnoreCase (fcLangCharSets[mid].lang, lang); if(fcLangCharSets[mid].lang[0] != firstChar)
cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
else
{ /* fast path for resolving 2-letter languages (by far the most common) after
* finding the first char (probably already true because of the hash table) */
FcChar8 secondChar = FcToLower(lang[1]);
if (fcLangCharSets[mid].lang[1] > secondChar) // check second chars
{
high = mid - 1;
continue;
}
else if (fcLangCharSets[mid].lang[1] < secondChar)
{
low = mid + 1;
continue;
}
else if (fcLangCharSets[mid].lang[2] == '\0' && lang[2] == '\0')
return mid;
else /* identical through the first two charcters, but at least one string didn't end there */
cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2, lang+2);
}
if (cmp == 0) if (cmp == 0)
return mid; return mid;
if (cmp < 0) if (cmp < 0)
@ -412,32 +487,28 @@ FcLangSetHash (const FcLangSet *ls)
FcLangSet * FcLangSet *
FcNameParseLangSet (const FcChar8 *string) FcNameParseLangSet (const FcChar8 *string)
{ {
FcChar8 lang[32]; FcChar8 lang[32],c;
const FcChar8 *end, *next; int i;
FcLangSet *ls; FcLangSet *ls;
ls = FcLangSetCreate (); ls = FcLangSetCreate ();
if (!ls) if (!ls)
goto bail0; goto bail0;
while (string && *string) for(;;)
{ {
end = (FcChar8 *) strchr ((char *) string, '|'); for(i = 0; i < 31;i++)
if (!end)
{ {
end = string + strlen ((char *) string); c = *string++;
next = end; if(c == '\0' || c == '|')
break; /* end of this code */
lang[i] = c;
} }
else lang[i] = '\0';
next = end + 1;
if (end - string < sizeof (lang) - 1)
{
strncpy ((char *) lang, (char *) string, end - string);
lang[end-string] = '\0';
if (!FcLangSetAdd (ls, lang)) if (!FcLangSetAdd (ls, lang))
goto bail1; goto bail1;
} if(c == '\0')
string = next; break;
} }
return ls; return ls;
bail1: bail1:
@ -482,7 +553,7 @@ FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
if (!first) if (!first)
if (!FcStrBufChar (buf, '|')) if (!FcStrBufChar (buf, '|'))
return FcFalse; return FcFalse;
if (!FcStrBufString (buf, extra)); if (!FcStrBufString (buf, extra))
return FcFalse; return FcFalse;
first = FcFalse; first = FcFalse;
} }
@ -506,3 +577,115 @@ FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
return FcStrSetEqual (lsa->extra, lsb->extra); return FcStrSetEqual (lsa->extra, lsb->extra);
return FcFalse; return FcFalse;
} }
static FcBool
FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
{
int id;
FcLangResult r;
int i;
id = FcLangSetIndex (lang);
if (id < 0)
id = -id - 1;
else if (FcLangSetBitGet (ls, id))
return FcTrue;
/*
* search up and down among equal languages for a match
*/
for (i = id - 1; i >= 0; i--)
{
if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
break;
if (FcLangSetBitGet (ls, i) &&
FcLangContains (fcLangCharSets[i].lang, lang))
return FcTrue;
}
for (i = id; i < NUM_LANG_CHAR_SET; i++)
{
if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
break;
if (FcLangSetBitGet (ls, i) &&
FcLangContains (fcLangCharSets[i].lang, lang))
return FcTrue;
}
if (ls->extra)
{
FcStrList *list = FcStrListCreate (ls->extra);
FcChar8 *extra;
FcLangResult r;
if (list)
{
while ((extra = FcStrListNext (list)))
{
if (FcLangContains (extra, lang))
break;
}
FcStrListDone (list);
if (extra)
return FcTrue;
}
}
return FcFalse;
}
/*
* return FcTrue if lsa contains every language in lsb
*/
FcBool
FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
{
int i, j;
FcChar32 missing;
if (FcDebug() & FC_DBG_MATCHV)
{
printf ("FcLangSet "); FcLangSetPrint (lsa);
printf (" contains "); FcLangSetPrint (lsb);
printf ("\n");
}
/*
* check bitmaps for missing language support
*/
for (i = 0; i < NUM_LANG_SET_MAP; i++)
{
missing = lsb->map[i] & ~lsa->map[i];
if (missing)
{
for (j = 0; j < 32; j++)
if (missing & (1 << j))
{
if (!FcLangSetContainsLang (lsa,
fcLangCharSets[i*32 + j].lang))
{
if (FcDebug() & FC_DBG_MATCHV)
printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
return FcFalse;
}
}
}
}
if (lsb->extra)
{
FcStrList *list = FcStrListCreate (lsb->extra);
FcChar8 *extra;
if (list)
{
while ((extra = FcStrListNext (list)))
{
if (!FcLangSetContainsLang (lsa, extra))
{
if (FcDebug() & FC_DBG_MATCHV)
printf ("\tMissing string %s\n", extra);
break;
}
}
FcStrListDone (list);
if (extra)
return FcFalse;
}
}
return FcTrue;
}

View File

@ -1,7 +1,7 @@
/* /*
* $XFree86: xc/lib/fontconfig/src/fclist.c,v 1.11tsi Exp $ * $RCSId: xc/lib/fontconfig/src/fclist.c,v 1.11tsi Exp $
* *
* Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * Copyright © 2000 Keith Packard
* *
* Permission to use, copy, modify, distribute, and sell this software and its * Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that * documentation for any purpose is hereby granted without fee, provided that
@ -128,7 +128,7 @@ FcListValueListMatchAny (FcValueList *v1orig,
for (v1 = v1orig; v1; v1 = v1->next) for (v1 = v1orig; v1; v1 = v1->next)
for (v2 = v2orig; v2; v2 = v2->next) for (v2 = v2orig; v2; v2 = v2->next)
if (FcConfigCompareValue (v2->value, FcOpContains, v1->value)) if (FcConfigCompareValue (v1->value, FcOpContains, v2->value))
return FcTrue; return FcTrue;
return FcFalse; return FcFalse;
} }