2 * $RCSId: xc/lib/fontconfig/src/fclang.c,v 1.7 2002/08/26 23:34:31 keithp Exp $
4 * Copyright © 2002 Keith Packard
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
37 #include "../fc-lang/fclang.h"
40 FcChar32 map[NUM_LANG_SET_MAP];
44 #define FcLangSetBitSet(ls, id) ((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
45 #define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
48 FcFreeTypeLangSet (const FcCharSet *charset,
49 const FcChar8 *exclusiveLang)
53 const FcCharSet *exclusiveCharset = 0;
58 exclusiveCharset = FcCharSetForLang (exclusiveLang);
59 ls = FcLangSetCreate ();
62 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
65 * Check for Han charsets to make fonts
66 * which advertise support for a single language
67 * not support other Han languages
69 if (exclusiveCharset &&
70 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang) &&
71 fcLangCharSets[i].charset.leaves != exclusiveCharset->leaves)
75 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
76 if (FcDebug() & FC_DBG_SCANV)
78 if (missing && missing < 10)
80 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
83 FcChar32 map[FC_CHARSET_MAP_SIZE];
86 printf ("\n%s(%d) ", fcLangCharSets[i].lang, missing);
88 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
89 ucs4 != FC_CHARSET_DONE;
90 ucs4 = FcCharSetNextPage (missed, map, &next))
93 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
96 for (j = 0; j < 32; j++)
97 if (map[i] & (1 << j))
98 printf (" %04x", ucs4 + i * 32 + j);
102 FcCharSetDestroy (missed);
105 printf ("%s(%d) ", fcLangCharSets[i].lang, missing);
108 FcLangSetBitSet (ls, i);
111 if (FcDebug() & FC_DBG_SCANV)
118 #define FcLangEnd(c) ((c) == '-' || (c) == '\0')
121 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
124 FcLangResult result = FcLangDifferentLang;
135 if (FcLangEnd (c1) && FcLangEnd (c2))
136 result = FcLangDifferentCountry;
142 result = FcLangDifferentCountry;
147 * Return FcTrue when s1 contains s2.
149 * s1 contains s2 if s1 equals s2 or if s1 is a
150 * language with a country and s2 is just a language
154 FcLangContains (const FcChar8 *s1, const FcChar8 *s2)
167 /* see if s1 has a country while s2 is mising one */
168 if (c1 == '-' && c2 == '\0')
178 FcCharSetForLang (const FcChar8 *lang)
182 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
184 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
186 return &fcLangCharSets[i].charset;
187 case FcLangDifferentCountry:
196 return &fcLangCharSets[i].charset;
200 FcLangSetCreate (void)
204 ls = malloc (sizeof (FcLangSet));
207 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
208 memset (ls->map, '\0', sizeof (ls->map));
214 FcLangSetDestroy (FcLangSet *ls)
217 FcStrSetDestroy (ls->extra);
218 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
223 FcLangSetCopy (const FcLangSet *ls)
227 new = FcLangSetCreate ();
230 memcpy (new->map, ls->map, sizeof (new->map));
236 new->extra = FcStrSetCreate ();
240 list = FcStrListCreate (ls->extra);
244 while ((extra = FcStrListNext (list)))
245 if (!FcStrSetAdd (new->extra, extra))
247 FcStrListDone (list);
250 FcStrListDone (list);
254 FcLangSetDestroy (new);
260 FcLangSetIndex (const FcChar8 *lang)
262 int low, high, mid = 0;
264 FcChar8 firstChar = FcToLower(lang[0]);
269 high = fcLangCharSetRanges[0].begin;
271 else if(firstChar > 'z')
273 low = fcLangCharSetRanges[25].begin;
274 high = NUM_LANG_CHAR_SET - 1;
278 low = fcLangCharSetRanges[firstChar - 'a'].begin;
279 high = fcLangCharSetRanges[firstChar - 'a'].end;
282 return -low; /* next entry after where it would be */
287 mid = (high + low) >> 1;
288 if(fcLangCharSets[mid].lang[0] != firstChar)
289 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
291 { /* fast path for resolving 2-letter languages (by far the most common) after
292 * finding the first char (probably already true because of the hash table) */
293 FcChar8 secondChar = FcToLower(lang[1]);
294 if (fcLangCharSets[mid].lang[1] > secondChar) /* check second chars */
299 else if (fcLangCharSets[mid].lang[1] < secondChar)
304 else if (fcLangCharSets[mid].lang[2] == '\0' && lang[2] == '\0')
307 else /* identical through the first two charcters, but at least one string didn't end there */
308 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2, lang+2);
323 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
327 id = FcLangSetIndex (lang);
330 FcLangSetBitSet (ls, id);
335 ls->extra = FcStrSetCreate ();
339 return FcStrSetAdd (ls->extra, lang);
343 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
346 FcLangResult best, r;
349 id = FcLangSetIndex (lang);
352 else if (FcLangSetBitGet (ls, id))
354 best = FcLangDifferentLang;
355 for (i = id - 1; i >= 0; i--)
357 r = FcLangCompare (lang, fcLangCharSets[i].lang);
358 if (r == FcLangDifferentLang)
360 if (FcLangSetBitGet (ls, i) && r < best)
363 for (i = id; i < NUM_LANG_CHAR_SET; i++)
365 r = FcLangCompare (lang, fcLangCharSets[i].lang);
366 if (r == FcLangDifferentLang)
368 if (FcLangSetBitGet (ls, i) && r < best)
373 FcStrList *list = FcStrListCreate (ls->extra);
379 while (best > FcLangEqual && (extra = FcStrListNext (list)))
381 r = FcLangCompare (lang, extra);
385 FcStrListDone (list);
392 FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
394 FcStrList *list = FcStrListCreate (set);
395 FcLangResult r, best = FcLangDifferentLang;
400 while (best > FcLangEqual && (extra = FcStrListNext (list)))
402 r = FcLangSetHasLang (ls, extra);
406 FcStrListDone (list);
412 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
415 FcLangResult best, r;
417 for (i = 0; i < NUM_LANG_SET_MAP; i++)
418 if (lsa->map[i] & lsb->map[i])
420 best = FcLangDifferentLang;
421 for (j = 0; j < NUM_COUNTRY_SET; j++)
422 for (i = 0; i < NUM_LANG_SET_MAP; i++)
423 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
424 (lsb->map[i] & fcLangCountrySets[j][i]))
426 best = FcLangDifferentCountry;
431 r = FcLangSetCompareStrSet (lsb, lsa->extra);
435 if (best > FcLangEqual && lsb->extra)
437 r = FcLangSetCompareStrSet (lsa, lsb->extra);
445 * Used in computing values -- mustn't allocate any storage
448 FcLangSetPromote (const FcChar8 *lang)
451 static FcStrSet strs;
455 memset (ls.map, '\0', sizeof (ls.map));
457 id = FcLangSetIndex (lang);
460 FcLangSetBitSet (&ls, id);
469 str = (FcChar8 *) lang;
475 FcLangSetHash (const FcLangSet *ls)
480 for (i = 0; i < NUM_LANG_SET_MAP; i++)
488 FcNameParseLangSet (const FcChar8 *string)
494 ls = FcLangSetCreate ();
500 for(i = 0; i < 31;i++)
503 if(c == '\0' || c == '|')
504 break; /* end of this code */
508 if (!FcLangSetAdd (ls, lang))
515 FcLangSetDestroy (ls);
521 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
525 FcBool first = FcTrue;
527 for (i = 0; i < NUM_LANG_SET_MAP; i++)
529 if ((bits = ls->map[i]))
531 for (bit = 0; bit <= 31; bit++)
532 if (bits & (1 << bit))
534 int id = (i << 5) | bit;
536 if (!FcStrBufChar (buf, '|'))
538 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
546 FcStrList *list = FcStrListCreate (ls->extra);
551 while ((extra = FcStrListNext (list)))
554 if (!FcStrBufChar (buf, '|'))
556 if (!FcStrBufString (buf, extra))
565 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
569 for (i = 0; i < NUM_LANG_SET_MAP; i++)
571 if (lsa->map[i] != lsb->map[i])
574 if (!lsa->extra && !lsb->extra)
576 if (lsa->extra && lsb->extra)
577 return FcStrSetEqual (lsa->extra, lsb->extra);
582 FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
587 id = FcLangSetIndex (lang);
590 else if (FcLangSetBitGet (ls, id))
593 * search up and down among equal languages for a match
595 for (i = id - 1; i >= 0; i--)
597 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
599 if (FcLangSetBitGet (ls, i) &&
600 FcLangContains (fcLangCharSets[i].lang, lang))
603 for (i = id; i < NUM_LANG_CHAR_SET; i++)
605 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
607 if (FcLangSetBitGet (ls, i) &&
608 FcLangContains (fcLangCharSets[i].lang, lang))
613 FcStrList *list = FcStrListCreate (ls->extra);
618 while ((extra = FcStrListNext (list)))
620 if (FcLangContains (extra, lang))
623 FcStrListDone (list);
632 * return FcTrue if lsa contains every language in lsb
635 FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
640 if (FcDebug() & FC_DBG_MATCHV)
642 printf ("FcLangSet "); FcLangSetPrint (lsa);
643 printf (" contains "); FcLangSetPrint (lsb);
647 * check bitmaps for missing language support
649 for (i = 0; i < NUM_LANG_SET_MAP; i++)
651 missing = lsb->map[i] & ~lsa->map[i];
654 for (j = 0; j < 32; j++)
655 if (missing & (1 << j))
657 if (!FcLangSetContainsLang (lsa,
658 fcLangCharSets[i*32 + j].lang))
660 if (FcDebug() & FC_DBG_MATCHV)
661 printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
669 FcStrList *list = FcStrListCreate (lsb->extra);
674 while ((extra = FcStrListNext (list)))
676 if (!FcLangSetContainsLang (lsa, extra))
678 if (FcDebug() & FC_DBG_MATCHV)
679 printf ("\tMissing string %s\n", extra);
683 FcStrListDone (list);