diff options
Diffstat (limited to 'fontconfig/src/fclang.c')
-rw-r--r-- | fontconfig/src/fclang.c | 1708 |
1 files changed, 886 insertions, 822 deletions
diff --git a/fontconfig/src/fclang.c b/fontconfig/src/fclang.c index 1d62c4e3f..6a9cf01d6 100644 --- a/fontconfig/src/fclang.c +++ b/fontconfig/src/fclang.c @@ -1,822 +1,886 @@ -/* - * fontconfig/src/fclang.c - * - * 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 - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "fcint.h" -#include "fcftint.h" - -typedef struct { - const FcChar8 lang[8]; - const FcCharSet charset; -} FcLangCharSet; - -typedef struct { - int begin; - int end; -} FcLangCharSetRange; - -#include "../fc-lang/fclang.h" - -struct _FcLangSet { - FcStrSet *extra; - FcChar32 map_size; - FcChar32 map[NUM_LANG_SET_MAP]; -}; - -static void -FcLangSetBitSet (FcLangSet *ls, - unsigned int id) -{ - int bucket; - - id = fcLangCharSetIndices[id]; - bucket = id >> 5; - if (bucket >= ls->map_size) - return; /* shouldn't happen really */ - - ls->map[bucket] |= ((FcChar32) 1 << (id & 0x1f)); -} - -static FcBool -FcLangSetBitGet (const FcLangSet *ls, - unsigned int id) -{ - int bucket; - - id = fcLangCharSetIndices[id]; - bucket = id >> 5; - if (bucket >= ls->map_size) - return FcFalse; - - return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse; -} - -FcLangSet * -FcFreeTypeLangSet (const FcCharSet *charset, - const FcChar8 *exclusiveLang) -{ - int i, j; - FcChar32 missing; - const FcCharSet *exclusiveCharset = 0; - FcLangSet *ls; - - if (exclusiveLang) - exclusiveCharset = FcLangGetCharSet (exclusiveLang); - ls = FcLangSetCreate (); - if (!ls) - return 0; - if (FcDebug() & FC_DBG_LANGSET) - { - printf ("font charset"); - FcCharSetPrint (charset); - printf ("\n"); - } - for (i = 0; i < NUM_LANG_CHAR_SET; i++) - { - if (FcDebug() & FC_DBG_LANGSET) - { - printf ("%s charset", fcLangCharSets[i].lang); - FcCharSetPrint (&fcLangCharSets[i].charset); - printf ("\n"); - } - - /* - * Check for Han charsets to make fonts - * which advertise support for a single language - * not support other Han languages - */ - if (exclusiveCharset && - FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang)) - { - if (fcLangCharSets[i].charset.num != exclusiveCharset->num) - continue; - - for (j = 0; j < fcLangCharSets[i].charset.num; j++) - if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) != - FcCharSetLeaf(exclusiveCharset, j)) - continue; - } - missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset); - if (FcDebug() & FC_DBG_SCANV) - { - if (missing && missing < 10) - { - FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset, - charset); - FcChar32 ucs4; - FcChar32 map[FC_CHARSET_MAP_SIZE]; - FcChar32 next; - - printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing); - printf ("{"); - for (ucs4 = FcCharSetFirstPage (missed, map, &next); - ucs4 != FC_CHARSET_DONE; - ucs4 = FcCharSetNextPage (missed, map, &next)) - { - int i, j; - for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) - if (map[i]) - { - for (j = 0; j < 32; j++) - if (map[i] & (1 << j)) - printf (" %04x", ucs4 + i * 32 + j); - } - } - printf (" }\n\t"); - FcCharSetDestroy (missed); - } - else - printf ("%s(%u) ", fcLangCharSets[i].lang, missing); - } - if (!missing) - FcLangSetBitSet (ls, i); - } - - if (FcDebug() & FC_DBG_SCANV) - printf ("\n"); - - - return ls; -} - -#define FcLangEnd(c) ((c) == '-' || (c) == '\0') - -FcLangResult -FcLangCompare (const FcChar8 *s1, const FcChar8 *s2) -{ - FcChar8 c1, c2; - FcLangResult result = FcLangDifferentLang; - - for (;;) - { - c1 = *s1++; - c2 = *s2++; - - c1 = FcToLower (c1); - c2 = FcToLower (c2); - if (c1 != c2) - { - if (FcLangEnd (c1) && FcLangEnd (c2)) - result = FcLangDifferentTerritory; - return result; - } - else if (!c1) - return FcLangEqual; - else if (c1 == '-') - result = FcLangDifferentTerritory; - } -} - -/* - * Return FcTrue when super contains sub. - * - * super contains sub if super and sub have the same - * language and either the same country or one - * is missing the country - */ - -static FcBool -FcLangContains (const FcChar8 *super, const FcChar8 *sub) -{ - FcChar8 c1, c2; - - for (;;) - { - c1 = *super++; - c2 = *sub++; - - c1 = FcToLower (c1); - c2 = FcToLower (c2); - if (c1 != c2) - { - /* see if super has a country while sub is mising one */ - if (c1 == '-' && c2 == '\0') - return FcTrue; - /* see if sub has a country while super is mising one */ - if (c1 == '\0' && c2 == '-') - return FcTrue; - return FcFalse; - } - else if (!c1) - return FcTrue; - } -} - -const FcCharSet * -FcLangGetCharSet (const FcChar8 *lang) -{ - int i; - int country = -1; - - for (i = 0; i < NUM_LANG_CHAR_SET; i++) - { - switch (FcLangCompare (lang, fcLangCharSets[i].lang)) { - case FcLangEqual: - return &fcLangCharSets[i].charset; - case FcLangDifferentTerritory: - if (country == -1) - country = i; - case FcLangDifferentLang: - default: - break; - } - } - if (country == -1) - return 0; - return &fcLangCharSets[country].charset; -} - -FcStrSet * -FcGetLangs (void) -{ - FcStrSet *langs; - int i; - - langs = FcStrSetCreate(); - if (!langs) - return 0; - - for (i = 0; i < NUM_LANG_CHAR_SET; i++) - FcStrSetAdd (langs, fcLangCharSets[i].lang); - - return langs; -} - -FcLangSet * -FcLangSetCreate (void) -{ - FcLangSet *ls; - - ls = malloc (sizeof (FcLangSet)); - if (!ls) - return 0; - FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet)); - memset (ls->map, '\0', sizeof (ls->map)); - ls->map_size = NUM_LANG_SET_MAP; - ls->extra = 0; - return ls; -} - -void -FcLangSetDestroy (FcLangSet *ls) -{ - if (ls->extra) - FcStrSetDestroy (ls->extra); - FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet)); - free (ls); -} - -FcLangSet * -FcLangSetCopy (const FcLangSet *ls) -{ - FcLangSet *new; - - new = FcLangSetCreate (); - if (!new) - goto bail0; - memset (new->map, '\0', sizeof (new->map)); - memcpy (new->map, ls->map, FC_MIN (sizeof (new->map), ls->map_size * sizeof (ls->map[0]))); - if (ls->extra) - { - FcStrList *list; - FcChar8 *extra; - - new->extra = FcStrSetCreate (); - if (!new->extra) - goto bail1; - - list = FcStrListCreate (ls->extra); - if (!list) - goto bail1; - - while ((extra = FcStrListNext (list))) - if (!FcStrSetAdd (new->extra, extra)) - { - FcStrListDone (list); - goto bail1; - } - FcStrListDone (list); - } - return new; -bail1: - FcLangSetDestroy (new); -bail0: - return 0; -} - -static int -FcLangSetIndex (const FcChar8 *lang) -{ - int low, high, mid = 0; - int cmp = 0; - FcChar8 firstChar = FcToLower(lang[0]); - FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\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 */ - } - - while (low <= high) - { - mid = (high + low) >> 1; - 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) */ - cmp = fcLangCharSets[mid].lang[1] - secondChar; - if (cmp == 0 && - (fcLangCharSets[mid].lang[2] != '\0' || - lang[2] != '\0')) - { - cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2, - lang+2); - } - } - if (cmp == 0) - return mid; - if (cmp < 0) - low = mid + 1; - else - high = mid - 1; - } - if (cmp < 0) - mid++; - return -(mid + 1); -} - -FcBool -FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang) -{ - int id; - - id = FcLangSetIndex (lang); - if (id >= 0) - { - FcLangSetBitSet (ls, id); - return FcTrue; - } - if (!ls->extra) - { - ls->extra = FcStrSetCreate (); - if (!ls->extra) - return FcFalse; - } - return FcStrSetAdd (ls->extra, lang); -} - -FcLangResult -FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang) -{ - int id; - FcLangResult best, r; - int i; - - id = FcLangSetIndex (lang); - if (id < 0) - id = -id - 1; - else if (FcLangSetBitGet (ls, id)) - return FcLangEqual; - best = FcLangDifferentLang; - for (i = id - 1; i >= 0; i--) - { - r = FcLangCompare (lang, fcLangCharSets[i].lang); - if (r == FcLangDifferentLang) - break; - if (FcLangSetBitGet (ls, i) && r < best) - best = r; - } - for (i = id; i < NUM_LANG_CHAR_SET; i++) - { - r = FcLangCompare (lang, fcLangCharSets[i].lang); - if (r == FcLangDifferentLang) - break; - if (FcLangSetBitGet (ls, i) && r < best) - best = r; - } - if (ls->extra) - { - FcStrList *list = FcStrListCreate (ls->extra); - FcChar8 *extra; - - if (list) - { - while (best > FcLangEqual && (extra = FcStrListNext (list))) - { - r = FcLangCompare (lang, extra); - if (r < best) - best = r; - } - FcStrListDone (list); - } - } - return best; -} - -static FcLangResult -FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set) -{ - FcStrList *list = FcStrListCreate (set); - FcLangResult r, best = FcLangDifferentLang; - FcChar8 *extra; - - if (list) - { - while (best > FcLangEqual && (extra = FcStrListNext (list))) - { - r = FcLangSetHasLang (ls, extra); - if (r < best) - best = r; - } - FcStrListDone (list); - } - return best; -} - -FcLangResult -FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb) -{ - int i, j, count; - FcLangResult best, r; - - count = FC_MIN (lsa->map_size, lsb->map_size); - count = FC_MIN (NUM_LANG_SET_MAP, count); - for (i = 0; i < count; i++) - if (lsa->map[i] & lsb->map[i]) - return FcLangEqual; - best = FcLangDifferentLang; - for (j = 0; j < NUM_COUNTRY_SET; j++) - for (i = 0; i < count; i++) - if ((lsa->map[i] & fcLangCountrySets[j][i]) && - (lsb->map[i] & fcLangCountrySets[j][i])) - { - best = FcLangDifferentTerritory; - break; - } - if (lsa->extra) - { - r = FcLangSetCompareStrSet (lsb, lsa->extra); - if (r < best) - best = r; - } - if (best > FcLangEqual && lsb->extra) - { - r = FcLangSetCompareStrSet (lsa, lsb->extra); - if (r < best) - best = r; - } - return best; -} - -/* - * Used in computing values -- mustn't allocate any storage - */ -FcLangSet * -FcLangSetPromote (const FcChar8 *lang) -{ - static FcLangSet ls; - static FcStrSet strs; - static FcChar8 *str; - int id; - - memset (ls.map, '\0', sizeof (ls.map)); - ls.extra = 0; - id = FcLangSetIndex (lang); - if (id > 0) - { - FcLangSetBitSet (&ls, id); - } - else - { - ls.extra = &strs; - strs.num = 1; - strs.size = 1; - strs.strs = &str; - strs.ref = 1; - str = (FcChar8 *) lang; - } - return &ls; -} - -FcChar32 -FcLangSetHash (const FcLangSet *ls) -{ - FcChar32 h = 0; - int i, count; - - count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP); - for (i = 0; i < count; i++) - h ^= ls->map[i]; - if (ls->extra) - h ^= ls->extra->num; - return h; -} - -FcLangSet * -FcNameParseLangSet (const FcChar8 *string) -{ - FcChar8 lang[32], c = 0; - int i; - FcLangSet *ls; - - ls = FcLangSetCreate (); - if (!ls) - goto bail0; - - for(;;) - { - for(i = 0; i < 31;i++) - { - c = *string++; - if(c == '\0' || c == '|') - break; /* end of this code */ - lang[i] = c; - } - lang[i] = '\0'; - if (!FcLangSetAdd (ls, lang)) - goto bail1; - if(c == '\0') - break; - } - return ls; -bail1: - FcLangSetDestroy (ls); -bail0: - return 0; -} - -FcBool -FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls) -{ - int i, bit, count; - FcChar32 bits; - FcBool first = FcTrue; - - count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP); - for (i = 0; i < count; i++) - { - if ((bits = ls->map[i])) - { - for (bit = 0; bit <= 31; bit++) - if (bits & (1 << bit)) - { - int id = (i << 5) | bit; - if (!first) - if (!FcStrBufChar (buf, '|')) - return FcFalse; - if (!FcStrBufString (buf, fcLangCharSets[fcLangCharSetIndicesInv[id]].lang)) - return FcFalse; - first = FcFalse; - } - } - } - if (ls->extra) - { - FcStrList *list = FcStrListCreate (ls->extra); - FcChar8 *extra; - - if (!list) - return FcFalse; - while ((extra = FcStrListNext (list))) - { - if (!first) - if (!FcStrBufChar (buf, '|')) - { - FcStrListDone (list); - return FcFalse; - } - if (!FcStrBufString (buf, extra)) - { - FcStrListDone (list); - return FcFalse; - } - first = FcFalse; - } - FcStrListDone (list); - } - return FcTrue; -} - -FcBool -FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb) -{ - int i, count; - - count = FC_MIN (lsa->map_size, lsb->map_size); - count = FC_MIN (NUM_LANG_SET_MAP, count); - for (i = 0; i < count; i++) - { - if (lsa->map[i] != lsb->map[i]) - return FcFalse; - } - if (!lsa->extra && !lsb->extra) - return FcTrue; - if (lsa->extra && lsb->extra) - return FcStrSetEqual (lsa->extra, lsb->extra); - return FcFalse; -} - -static FcBool -FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang) -{ - int id; - 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; - - 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, count; - FcChar32 missing; - - if (FcDebug() & FC_DBG_MATCHV) - { - printf ("FcLangSet "); FcLangSetPrint (lsa); - printf (" contains "); FcLangSetPrint (lsb); - printf ("\n"); - } - /* - * check bitmaps for missing language support - */ - count = FC_MIN (lsa->map_size, lsb->map_size); - count = FC_MIN (NUM_LANG_SET_MAP, count); - for (i = 0; i < count; i++) - { - missing = lsb->map[i] & ~lsa->map[i]; - if (missing) - { - for (j = 0; j < 32; j++) - if (missing & (1 << j)) - { - if (!FcLangSetContainsLang (lsa, - fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang)) - { - if (FcDebug() & FC_DBG_MATCHV) - printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[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; -} - -FcBool -FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l) -{ - if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet))) - return FcFalse; - return FcTrue; -} - -FcLangSet * -FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l) -{ - FcLangSet *l_serialize = FcSerializePtr (serialize, l); - - if (!l_serialize) - return NULL; - memset (l_serialize->map, '\0', sizeof (l_serialize->map)); - memcpy (l_serialize->map, l->map, FC_MIN (sizeof (l_serialize->map), l->map_size * sizeof (l->map[0]))); - l_serialize->map_size = NUM_LANG_SET_MAP; - l_serialize->extra = NULL; /* We don't serialize ls->extra */ - return l_serialize; -} - -FcStrSet * -FcLangSetGetLangs (const FcLangSet *ls) -{ - FcStrSet *langs; - int i; - - langs = FcStrSetCreate(); - if (!langs) - return 0; - - for (i = 0; i < NUM_LANG_CHAR_SET; i++) - if (FcLangSetBitGet (ls, i)) - FcStrSetAdd (langs, fcLangCharSets[i].lang); - - if (ls->extra) - { - FcStrList *list = FcStrListCreate (ls->extra); - FcChar8 *extra; - - if (list) - { - while ((extra = FcStrListNext (list))) - FcStrSetAdd (langs, extra); - - FcStrListDone (list); - } - } - - return langs; -} - -#define __fclang__ -#include "fcaliastail.h" -#include "fcftaliastail.h" -#undef __fclang__ +/*
+ * fontconfig/src/fclang.c
+ *
+ * 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the author(s) not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. The authors make no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+#include "fcftint.h"
+
+typedef struct {
+ const FcChar8 lang[8];
+ const FcCharSet charset;
+} FcLangCharSet;
+
+typedef struct {
+ int begin;
+ int end;
+} FcLangCharSetRange;
+
+#include "../fc-lang/fclang.h"
+
+struct _FcLangSet {
+ FcStrSet *extra;
+ FcChar32 map_size;
+ FcChar32 map[NUM_LANG_SET_MAP];
+};
+
+static void
+FcLangSetBitSet (FcLangSet *ls,
+ unsigned int id)
+{
+ int bucket;
+
+ id = fcLangCharSetIndices[id];
+ bucket = id >> 5;
+ if (bucket >= ls->map_size)
+ return; /* shouldn't happen really */
+
+ ls->map[bucket] |= ((FcChar32) 1 << (id & 0x1f));
+}
+
+static FcBool
+FcLangSetBitGet (const FcLangSet *ls,
+ unsigned int id)
+{
+ int bucket;
+
+ id = fcLangCharSetIndices[id];
+ bucket = id >> 5;
+ if (bucket >= ls->map_size)
+ return FcFalse;
+
+ return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse;
+}
+
+static void
+FcLangSetBitReset (FcLangSet *ls,
+ unsigned int id)
+{
+ int bucket;
+
+ id = fcLangCharSetIndices[id];
+ bucket = id >> 5;
+ if (bucket >= ls->map_size)
+ return; /* shouldn't happen really */
+
+ ls->map[bucket] &= ~((FcChar32) 1 << (id & 0x1f));
+}
+
+FcLangSet *
+FcFreeTypeLangSet (const FcCharSet *charset,
+ const FcChar8 *exclusiveLang)
+{
+ int i, j;
+ FcChar32 missing;
+ const FcCharSet *exclusiveCharset = 0;
+ FcLangSet *ls;
+
+ if (exclusiveLang)
+ exclusiveCharset = FcLangGetCharSet (exclusiveLang);
+ ls = FcLangSetCreate ();
+ if (!ls)
+ return 0;
+ if (FcDebug() & FC_DBG_LANGSET)
+ {
+ printf ("font charset");
+ FcCharSetPrint (charset);
+ printf ("\n");
+ }
+ for (i = 0; i < NUM_LANG_CHAR_SET; i++)
+ {
+ if (FcDebug() & FC_DBG_LANGSET)
+ {
+ printf ("%s charset", fcLangCharSets[i].lang);
+ FcCharSetPrint (&fcLangCharSets[i].charset);
+ printf ("\n");
+ }
+
+ /*
+ * Check for Han charsets to make fonts
+ * which advertise support for a single language
+ * not support other Han languages
+ */
+ if (exclusiveCharset &&
+ FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
+ {
+ if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
+ continue;
+
+ for (j = 0; j < fcLangCharSets[i].charset.num; j++)
+ if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) !=
+ FcCharSetLeaf(exclusiveCharset, j))
+ continue;
+ }
+ missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
+ if (FcDebug() & FC_DBG_SCANV)
+ {
+ if (missing && missing < 10)
+ {
+ FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
+ charset);
+ FcChar32 ucs4;
+ FcChar32 map[FC_CHARSET_MAP_SIZE];
+ FcChar32 next;
+
+ printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
+ printf ("{");
+ for (ucs4 = FcCharSetFirstPage (missed, map, &next);
+ ucs4 != FC_CHARSET_DONE;
+ ucs4 = FcCharSetNextPage (missed, map, &next))
+ {
+ int i, j;
+ for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
+ if (map[i])
+ {
+ for (j = 0; j < 32; j++)
+ if (map[i] & (1 << j))
+ printf (" %04x", ucs4 + i * 32 + j);
+ }
+ }
+ printf (" }\n\t");
+ FcCharSetDestroy (missed);
+ }
+ else
+ printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
+ }
+ if (!missing)
+ FcLangSetBitSet (ls, i);
+ }
+
+ if (FcDebug() & FC_DBG_SCANV)
+ printf ("\n");
+
+
+ return ls;
+}
+
+#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
+
+FcLangResult
+FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
+{
+ FcChar8 c1, c2;
+ FcLangResult result = FcLangDifferentLang;
+
+ for (;;)
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ c1 = FcToLower (c1);
+ c2 = FcToLower (c2);
+ if (c1 != c2)
+ {
+ if (FcLangEnd (c1) && FcLangEnd (c2))
+ result = FcLangDifferentTerritory;
+ return result;
+ }
+ else if (!c1)
+ return FcLangEqual;
+ else if (c1 == '-')
+ result = FcLangDifferentTerritory;
+ }
+}
+
+/*
+ * Return FcTrue when super contains sub.
+ *
+ * super contains sub if super and sub have the same
+ * language and either the same country or one
+ * is missing the country
+ */
+
+static FcBool
+FcLangContains (const FcChar8 *super, const FcChar8 *sub)
+{
+ FcChar8 c1, c2;
+
+ for (;;)
+ {
+ c1 = *super++;
+ c2 = *sub++;
+
+ c1 = FcToLower (c1);
+ c2 = FcToLower (c2);
+ if (c1 != c2)
+ {
+ /* see if super has a country while sub is mising one */
+ if (c1 == '-' && c2 == '\0')
+ return FcTrue;
+ /* see if sub has a country while super is mising one */
+ if (c1 == '\0' && c2 == '-')
+ return FcTrue;
+ return FcFalse;
+ }
+ else if (!c1)
+ return FcTrue;
+ }
+}
+
+const FcCharSet *
+FcLangGetCharSet (const FcChar8 *lang)
+{
+ int i;
+ int country = -1;
+
+ for (i = 0; i < NUM_LANG_CHAR_SET; i++)
+ {
+ switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
+ case FcLangEqual:
+ return &fcLangCharSets[i].charset;
+ case FcLangDifferentTerritory:
+ if (country == -1)
+ country = i;
+ case FcLangDifferentLang:
+ default:
+ break;
+ }
+ }
+ if (country == -1)
+ return 0;
+ return &fcLangCharSets[country].charset;
+}
+
+FcStrSet *
+FcGetLangs (void)
+{
+ FcStrSet *langs;
+ int i;
+
+ langs = FcStrSetCreate();
+ if (!langs)
+ return 0;
+
+ for (i = 0; i < NUM_LANG_CHAR_SET; i++)
+ FcStrSetAdd (langs, fcLangCharSets[i].lang);
+
+ return langs;
+}
+
+FcLangSet *
+FcLangSetCreate (void)
+{
+ FcLangSet *ls;
+
+ ls = malloc (sizeof (FcLangSet));
+ if (!ls)
+ return 0;
+ FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
+ memset (ls->map, '\0', sizeof (ls->map));
+ ls->map_size = NUM_LANG_SET_MAP;
+ ls->extra = 0;
+ return ls;
+}
+
+void
+FcLangSetDestroy (FcLangSet *ls)
+{
+ if (ls->extra)
+ FcStrSetDestroy (ls->extra);
+ FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
+ free (ls);
+}
+
+FcLangSet *
+FcLangSetCopy (const FcLangSet *ls)
+{
+ FcLangSet *new;
+
+ new = FcLangSetCreate ();
+ if (!new)
+ goto bail0;
+ memset (new->map, '\0', sizeof (new->map));
+ memcpy (new->map, ls->map, FC_MIN (sizeof (new->map), ls->map_size * sizeof (ls->map[0])));
+ if (ls->extra)
+ {
+ FcStrList *list;
+ FcChar8 *extra;
+
+ new->extra = FcStrSetCreate ();
+ if (!new->extra)
+ goto bail1;
+
+ list = FcStrListCreate (ls->extra);
+ if (!list)
+ goto bail1;
+
+ while ((extra = FcStrListNext (list)))
+ if (!FcStrSetAdd (new->extra, extra))
+ {
+ FcStrListDone (list);
+ goto bail1;
+ }
+ FcStrListDone (list);
+ }
+ return new;
+bail1:
+ FcLangSetDestroy (new);
+bail0:
+ return 0;
+}
+
+static int
+FcLangSetIndex (const FcChar8 *lang)
+{
+ int low, high, mid = 0;
+ int cmp = 0;
+ FcChar8 firstChar = FcToLower(lang[0]);
+ FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\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 */
+ }
+
+ while (low <= high)
+ {
+ mid = (high + low) >> 1;
+ 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) */
+ cmp = fcLangCharSets[mid].lang[1] - secondChar;
+ if (cmp == 0 &&
+ (fcLangCharSets[mid].lang[2] != '\0' ||
+ lang[2] != '\0'))
+ {
+ cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
+ lang+2);
+ }
+ }
+ if (cmp == 0)
+ return mid;
+ if (cmp < 0)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+ if (cmp < 0)
+ mid++;
+ return -(mid + 1);
+}
+
+FcBool
+FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
+{
+ int id;
+
+ id = FcLangSetIndex (lang);
+ if (id >= 0)
+ {
+ FcLangSetBitSet (ls, id);
+ return FcTrue;
+ }
+ if (!ls->extra)
+ {
+ ls->extra = FcStrSetCreate ();
+ if (!ls->extra)
+ return FcFalse;
+ }
+ return FcStrSetAdd (ls->extra, lang);
+}
+
+FcBool
+FcLangSetDel (FcLangSet *ls, const FcChar8 *lang)
+{
+ int id;
+
+ id = FcLangSetIndex (lang);
+ if (id >= 0)
+ {
+ FcLangSetBitReset (ls, id);
+ }
+ else if (ls->extra)
+ {
+ FcStrSetDel (ls->extra, lang);
+ }
+ return FcTrue;
+}
+
+FcLangResult
+FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
+{
+ int id;
+ FcLangResult best, r;
+ int i;
+
+ id = FcLangSetIndex (lang);
+ if (id < 0)
+ id = -id - 1;
+ else if (FcLangSetBitGet (ls, id))
+ return FcLangEqual;
+ best = FcLangDifferentLang;
+ for (i = id - 1; i >= 0; i--)
+ {
+ r = FcLangCompare (lang, fcLangCharSets[i].lang);
+ if (r == FcLangDifferentLang)
+ break;
+ if (FcLangSetBitGet (ls, i) && r < best)
+ best = r;
+ }
+ for (i = id; i < NUM_LANG_CHAR_SET; i++)
+ {
+ r = FcLangCompare (lang, fcLangCharSets[i].lang);
+ if (r == FcLangDifferentLang)
+ break;
+ if (FcLangSetBitGet (ls, i) && r < best)
+ best = r;
+ }
+ if (ls->extra)
+ {
+ FcStrList *list = FcStrListCreate (ls->extra);
+ FcChar8 *extra;
+
+ if (list)
+ {
+ while (best > FcLangEqual && (extra = FcStrListNext (list)))
+ {
+ r = FcLangCompare (lang, extra);
+ if (r < best)
+ best = r;
+ }
+ FcStrListDone (list);
+ }
+ }
+ return best;
+}
+
+static FcLangResult
+FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
+{
+ FcStrList *list = FcStrListCreate (set);
+ FcLangResult r, best = FcLangDifferentLang;
+ FcChar8 *extra;
+
+ if (list)
+ {
+ while (best > FcLangEqual && (extra = FcStrListNext (list)))
+ {
+ r = FcLangSetHasLang (ls, extra);
+ if (r < best)
+ best = r;
+ }
+ FcStrListDone (list);
+ }
+ return best;
+}
+
+FcLangResult
+FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
+{
+ int i, j, count;
+ FcLangResult best, r;
+
+ count = FC_MIN (lsa->map_size, lsb->map_size);
+ count = FC_MIN (NUM_LANG_SET_MAP, count);
+ for (i = 0; i < count; i++)
+ if (lsa->map[i] & lsb->map[i])
+ return FcLangEqual;
+ best = FcLangDifferentLang;
+ for (j = 0; j < NUM_COUNTRY_SET; j++)
+ for (i = 0; i < count; i++)
+ if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
+ (lsb->map[i] & fcLangCountrySets[j][i]))
+ {
+ best = FcLangDifferentTerritory;
+ break;
+ }
+ if (lsa->extra)
+ {
+ r = FcLangSetCompareStrSet (lsb, lsa->extra);
+ if (r < best)
+ best = r;
+ }
+ if (best > FcLangEqual && lsb->extra)
+ {
+ r = FcLangSetCompareStrSet (lsa, lsb->extra);
+ if (r < best)
+ best = r;
+ }
+ return best;
+}
+
+/*
+ * Used in computing values -- mustn't allocate any storage
+ * XXX Not thread-safe
+ */
+FcLangSet *
+FcLangSetPromote (const FcChar8 *lang)
+{
+ static FcLangSet ls;
+ static FcStrSet strs;
+ static FcChar8 *str;
+ int id;
+
+ memset (ls.map, '\0', sizeof (ls.map));
+ ls.map_size = NUM_LANG_SET_MAP;
+ ls.extra = 0;
+ id = FcLangSetIndex (lang);
+ if (id > 0)
+ {
+ FcLangSetBitSet (&ls, id);
+ }
+ else
+ {
+ ls.extra = &strs;
+ strs.num = 1;
+ strs.size = 1;
+ strs.strs = &str;
+ strs.ref = 1;
+ str = (FcChar8 *) lang;
+ }
+ return &ls;
+}
+
+FcChar32
+FcLangSetHash (const FcLangSet *ls)
+{
+ FcChar32 h = 0;
+ int i, count;
+
+ count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
+ for (i = 0; i < count; i++)
+ h ^= ls->map[i];
+ if (ls->extra)
+ h ^= ls->extra->num;
+ return h;
+}
+
+FcLangSet *
+FcNameParseLangSet (const FcChar8 *string)
+{
+ FcChar8 lang[32], c = 0;
+ int i;
+ FcLangSet *ls;
+
+ ls = FcLangSetCreate ();
+ if (!ls)
+ goto bail0;
+
+ for(;;)
+ {
+ for(i = 0; i < 31;i++)
+ {
+ c = *string++;
+ if(c == '\0' || c == '|')
+ break; /* end of this code */
+ lang[i] = c;
+ }
+ lang[i] = '\0';
+ if (!FcLangSetAdd (ls, lang))
+ goto bail1;
+ if(c == '\0')
+ break;
+ }
+ return ls;
+bail1:
+ FcLangSetDestroy (ls);
+bail0:
+ return 0;
+}
+
+FcBool
+FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
+{
+ int i, bit, count;
+ FcChar32 bits;
+ FcBool first = FcTrue;
+
+ count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
+ for (i = 0; i < count; i++)
+ {
+ if ((bits = ls->map[i]))
+ {
+ for (bit = 0; bit <= 31; bit++)
+ if (bits & (1 << bit))
+ {
+ int id = (i << 5) | bit;
+ if (!first)
+ if (!FcStrBufChar (buf, '|'))
+ return FcFalse;
+ if (!FcStrBufString (buf, fcLangCharSets[fcLangCharSetIndicesInv[id]].lang))
+ return FcFalse;
+ first = FcFalse;
+ }
+ }
+ }
+ if (ls->extra)
+ {
+ FcStrList *list = FcStrListCreate (ls->extra);
+ FcChar8 *extra;
+
+ if (!list)
+ return FcFalse;
+ while ((extra = FcStrListNext (list)))
+ {
+ if (!first)
+ if (!FcStrBufChar (buf, '|'))
+ {
+ FcStrListDone (list);
+ return FcFalse;
+ }
+ if (!FcStrBufString (buf, extra))
+ {
+ FcStrListDone (list);
+ return FcFalse;
+ }
+ first = FcFalse;
+ }
+ FcStrListDone (list);
+ }
+ return FcTrue;
+}
+
+FcBool
+FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
+{
+ int i, count;
+
+ count = FC_MIN (lsa->map_size, lsb->map_size);
+ count = FC_MIN (NUM_LANG_SET_MAP, count);
+ for (i = 0; i < count; i++)
+ {
+ if (lsa->map[i] != lsb->map[i])
+ return FcFalse;
+ }
+ if (!lsa->extra && !lsb->extra)
+ return FcTrue;
+ if (lsa->extra && lsb->extra)
+ return FcStrSetEqual (lsa->extra, lsb->extra);
+ return FcFalse;
+}
+
+static FcBool
+FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
+{
+ int id;
+ 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;
+
+ 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, count;
+ FcChar32 missing;
+
+ if (FcDebug() & FC_DBG_MATCHV)
+ {
+ printf ("FcLangSet "); FcLangSetPrint (lsa);
+ printf (" contains "); FcLangSetPrint (lsb);
+ printf ("\n");
+ }
+ /*
+ * check bitmaps for missing language support
+ */
+ count = FC_MIN (lsa->map_size, lsb->map_size);
+ count = FC_MIN (NUM_LANG_SET_MAP, count);
+ for (i = 0; i < count; i++)
+ {
+ missing = lsb->map[i] & ~lsa->map[i];
+ if (missing)
+ {
+ for (j = 0; j < 32; j++)
+ if (missing & (1 << j))
+ {
+ if (!FcLangSetContainsLang (lsa,
+ fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang))
+ {
+ if (FcDebug() & FC_DBG_MATCHV)
+ printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[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;
+}
+
+FcBool
+FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l)
+{
+ if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet)))
+ return FcFalse;
+ return FcTrue;
+}
+
+FcLangSet *
+FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l)
+{
+ FcLangSet *l_serialize = FcSerializePtr (serialize, l);
+
+ if (!l_serialize)
+ return NULL;
+ memset (l_serialize->map, '\0', sizeof (l_serialize->map));
+ memcpy (l_serialize->map, l->map, FC_MIN (sizeof (l_serialize->map), l->map_size * sizeof (l->map[0])));
+ l_serialize->map_size = NUM_LANG_SET_MAP;
+ l_serialize->extra = NULL; /* We don't serialize ls->extra */
+ return l_serialize;
+}
+
+FcStrSet *
+FcLangSetGetLangs (const FcLangSet *ls)
+{
+ FcStrSet *langs;
+ int i;
+
+ langs = FcStrSetCreate();
+ if (!langs)
+ return 0;
+
+ for (i = 0; i < NUM_LANG_CHAR_SET; i++)
+ if (FcLangSetBitGet (ls, i))
+ FcStrSetAdd (langs, fcLangCharSets[i].lang);
+
+ if (ls->extra)
+ {
+ FcStrList *list = FcStrListCreate (ls->extra);
+ FcChar8 *extra;
+
+ if (list)
+ {
+ while ((extra = FcStrListNext (list)))
+ FcStrSetAdd (langs, extra);
+
+ FcStrListDone (list);
+ }
+ }
+
+ return langs;
+}
+
+static FcLangSet *
+FcLangSetOperate(const FcLangSet *a,
+ const FcLangSet *b,
+ FcBool (*func) (FcLangSet *ls,
+ const FcChar8 *s))
+{
+ FcLangSet *langset = FcLangSetCopy (a);
+ FcStrList *sl = FcStrListCreate (FcLangSetGetLangs (b));
+ FcChar8 *str;
+
+ while ((str = FcStrListNext (sl)))
+ {
+ func (langset, str);
+ }
+ FcStrListDone (sl);
+
+ return langset;
+}
+
+FcLangSet *
+FcLangSetUnion (const FcLangSet *a, const FcLangSet *b)
+{
+ return FcLangSetOperate(a, b, FcLangSetAdd);
+}
+
+FcLangSet *
+FcLangSetSubtract (const FcLangSet *a, const FcLangSet *b)
+{
+ return FcLangSetOperate(a, b, FcLangSetDel);
+}
+
+#define __fclang__
+#include "fcaliastail.h"
+#include "fcftaliastail.h"
+#undef __fclang__
|