From 793e946c2f90b5617ec39c64679630b4e2f2d3ad Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 5 Mar 2003 05:52:31 +0000 Subject: [PATCH] AddFcLangSetContains for font listing, add first-letter table for language lookups, change RCS tag --- src/fccfg.c | 8 +- src/fcint.h | 7 +- src/fclang.c | 231 +++++++++++++++++++++++++++++++++++++++++++++------ src/fclist.c | 6 +- 4 files changed, 219 insertions(+), 33 deletions(-) diff --git a/src/fccfg.c b/src/fccfg.c index adf179e..d8bbe8d 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -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 * documentation for any purpose is hereby granted without fee, provided that @@ -590,10 +590,10 @@ FcConfigCompareValue (const FcValue m_o, case FcTypeLangSet: switch (op) { case FcOpContains: - ret = FcLangSetCompare (v.u.l, m.u.l) != FcLangDifferentLang; + ret = FcLangSetContains (v.u.l, m.u.l); break; case FcOpNotContains: - ret = FcLangSetCompare (v.u.l, m.u.l) == FcLangDifferentLang; + ret = FcLangSetContains (v.u.l, m.u.l); break; case FcOpEqual: ret = FcLangSetEqual (v.u.l, m.u.l); diff --git a/src/fcint.h b/src/fcint.h index 1a9ee54..ba5d9a4 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -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 * documentation for any purpose is hereby granted without fee, provided that @@ -446,6 +446,9 @@ FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4); void FcValueListPrint (const FcValueList *l); +void +FcLangSetPrint (const FcLangSet *ls); + void FcOpPrint (FcOp op); diff --git a/src/fclang.c b/src/fclang.c index 00d2651..521aa91 100644 --- a/src/fclang.c +++ b/src/fclang.c @@ -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 * documentation for any purpose is hereby granted without fee, provided that @@ -29,6 +29,11 @@ typedef struct { FcCharSet charset; } FcLangCharSet; +typedef struct { + int begin; + int end; +} FcLangCharSetRange; + #include "../fc-lang/fclang.h" 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 * FcCharSetForLang (const FcChar8 *lang) { @@ -225,14 +261,53 @@ FcLangSetIndex (const FcChar8 *lang) { int low, high, mid; int cmp; + FcChar8 firstChar = FcToLower(lang[0]); + + if (firstChar < 'a') + { + low = 0; + high = fcLangCharSetRanges[0].begin; + } + else if(firstChar > 'z') + { + low = fcLangCharSetRanges[25].begin; + 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 */ + } - low = 0; - high = NUM_LANG_CHAR_SET - 1; while (low <= high) { mid = (high + low) >> 1; - cmp = FcStrCmpIgnoreCase (fcLangCharSets[mid].lang, lang); - if (cmp == 0) + 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) return mid; if (cmp < 0) low = mid + 1; @@ -412,32 +487,28 @@ FcLangSetHash (const FcLangSet *ls) FcLangSet * FcNameParseLangSet (const FcChar8 *string) { - FcChar8 lang[32]; - const FcChar8 *end, *next; + FcChar8 lang[32],c; + int i; FcLangSet *ls; ls = FcLangSetCreate (); if (!ls) goto bail0; - while (string && *string) + for(;;) { - end = (FcChar8 *) strchr ((char *) string, '|'); - if (!end) + for(i = 0; i < 31;i++) { - end = string + strlen ((char *) string); - next = end; + c = *string++; + if(c == '\0' || c == '|') + break; /* end of this code */ + lang[i] = c; } - else - next = end + 1; - if (end - string < sizeof (lang) - 1) - { - strncpy ((char *) lang, (char *) string, end - string); - lang[end-string] = '\0'; - if (!FcLangSetAdd (ls, lang)) - goto bail1; - } - string = next; + lang[i] = '\0'; + if (!FcLangSetAdd (ls, lang)) + goto bail1; + if(c == '\0') + break; } return ls; bail1: @@ -482,7 +553,7 @@ FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls) if (!first) if (!FcStrBufChar (buf, '|')) return FcFalse; - if (!FcStrBufString (buf, extra)); + if (!FcStrBufString (buf, extra)) return FcFalse; first = FcFalse; } @@ -506,3 +577,115 @@ FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb) return FcStrSetEqual (lsa->extra, lsb->extra); 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; +} diff --git a/src/fclist.c b/src/fclist.c index 39d1729..47a2f04 100644 --- a/src/fclist.c +++ b/src/fclist.c @@ -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 * 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 (v2 = v2orig; v2; v2 = v2->next) - if (FcConfigCompareValue (v2->value, FcOpContains, v1->value)) + if (FcConfigCompareValue (v1->value, FcOpContains, v2->value)) return FcTrue; return FcFalse; }