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.
29 const FcChar8 lang[8];
30 const FcCharSet charset;
38 #include "../fc-lang/fclang.h"
41 FcChar32 map[NUM_LANG_SET_MAP];
45 #define FcLangSetBitSet(ls, id) ((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
46 #define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
49 FcFreeTypeLangSet (const FcCharSet *charset,
50 const FcChar8 *exclusiveLang)
54 const FcCharSet *exclusiveCharset = 0;
58 exclusiveCharset = FcLangGetCharSet (exclusiveLang);
59 ls = FcLangSetCreate ();
62 if (FcDebug() & FC_DBG_LANGSET)
64 printf ("font charset\n");
65 FcCharSetPrint (charset);
68 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
70 if (FcDebug() & FC_DBG_LANGSET)
72 printf ("%s charset\n", fcLangCharSets[i].lang);
73 FcCharSetPrint (&fcLangCharSets[i].charset);
78 * Check for Han charsets to make fonts
79 * which advertise support for a single language
80 * not support other Han languages
82 if (exclusiveCharset &&
83 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
85 if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
88 for (j = 0; j < fcLangCharSets[i].charset.num; j++)
89 if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) !=
90 FcCharSetLeaf(exclusiveCharset, j))
93 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
94 if (FcDebug() & FC_DBG_SCANV)
96 if (missing && missing < 10)
98 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
101 FcChar32 map[FC_CHARSET_MAP_SIZE];
104 printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
106 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
107 ucs4 != FC_CHARSET_DONE;
108 ucs4 = FcCharSetNextPage (missed, map, &next))
111 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
114 for (j = 0; j < 32; j++)
115 if (map[i] & (1 << j))
116 printf (" %04x", ucs4 + i * 32 + j);
120 FcCharSetDestroy (missed);
123 printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
126 FcLangSetBitSet (ls, i);
129 if (FcDebug() & FC_DBG_SCANV)
136 #define FcLangEnd(c) ((c) == '-' || (c) == '\0')
139 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
142 FcLangResult result = FcLangDifferentLang;
153 if (FcLangEnd (c1) && FcLangEnd (c2))
154 result = FcLangDifferentTerritory;
160 result = FcLangDifferentTerritory;
165 * Return FcTrue when super contains sub.
167 * super contains sub if super and sub have the same
168 * language and either the same country or one
169 * is missing the country
173 FcLangContains (const FcChar8 *super, const FcChar8 *sub)
186 /* see if super has a country while sub is mising one */
187 if (c1 == '-' && c2 == '\0')
189 /* see if sub has a country while super is mising one */
190 if (c1 == '\0' && c2 == '-')
200 FcLangGetCharSet (const FcChar8 *lang)
205 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
207 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
209 return &fcLangCharSets[i].charset;
210 case FcLangDifferentTerritory:
219 return &fcLangCharSets[country].charset;
228 langs = FcStrSetCreate();
232 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
233 FcStrSetAdd (langs, fcLangCharSets[i].lang);
239 FcLangSetCreate (void)
243 ls = malloc (sizeof (FcLangSet));
246 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
247 memset (ls->map, '\0', sizeof (ls->map));
253 FcLangSetDestroy (FcLangSet *ls)
256 FcStrSetDestroy (ls->extra);
257 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
262 FcLangSetCopy (const FcLangSet *ls)
266 new = FcLangSetCreate ();
269 memcpy (new->map, ls->map, sizeof (new->map));
275 new->extra = FcStrSetCreate ();
279 list = FcStrListCreate (ls->extra);
283 while ((extra = FcStrListNext (list)))
284 if (!FcStrSetAdd (new->extra, extra))
286 FcStrListDone (list);
289 FcStrListDone (list);
293 FcLangSetDestroy (new);
299 FcLangSetIndex (const FcChar8 *lang)
301 int low, high, mid = 0;
303 FcChar8 firstChar = FcToLower(lang[0]);
304 FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
309 high = fcLangCharSetRanges[0].begin;
311 else if(firstChar > 'z')
313 low = fcLangCharSetRanges[25].begin;
314 high = NUM_LANG_CHAR_SET - 1;
318 low = fcLangCharSetRanges[firstChar - 'a'].begin;
319 high = fcLangCharSetRanges[firstChar - 'a'].end;
322 return -low; /* next entry after where it would be */
327 mid = (high + low) >> 1;
328 if(fcLangCharSets[mid].lang[0] != firstChar)
329 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
331 { /* fast path for resolving 2-letter languages (by far the most common) after
332 * finding the first char (probably already true because of the hash table) */
333 cmp = fcLangCharSets[mid].lang[1] - secondChar;
335 (fcLangCharSets[mid].lang[2] != '\0' ||
338 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
355 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
359 id = FcLangSetIndex (lang);
362 FcLangSetBitSet (ls, id);
367 ls->extra = FcStrSetCreate ();
371 return FcStrSetAdd (ls->extra, lang);
375 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
378 FcLangResult best, r;
381 id = FcLangSetIndex (lang);
384 else if (FcLangSetBitGet (ls, id))
386 best = FcLangDifferentLang;
387 for (i = id - 1; i >= 0; i--)
389 r = FcLangCompare (lang, fcLangCharSets[i].lang);
390 if (r == FcLangDifferentLang)
392 if (FcLangSetBitGet (ls, i) && r < best)
395 for (i = id; i < NUM_LANG_CHAR_SET; i++)
397 r = FcLangCompare (lang, fcLangCharSets[i].lang);
398 if (r == FcLangDifferentLang)
400 if (FcLangSetBitGet (ls, i) && r < best)
405 FcStrList *list = FcStrListCreate (ls->extra);
410 while (best > FcLangEqual && (extra = FcStrListNext (list)))
412 r = FcLangCompare (lang, extra);
416 FcStrListDone (list);
423 FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
425 FcStrList *list = FcStrListCreate (set);
426 FcLangResult r, best = FcLangDifferentLang;
431 while (best > FcLangEqual && (extra = FcStrListNext (list)))
433 r = FcLangSetHasLang (ls, extra);
437 FcStrListDone (list);
443 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
446 FcLangResult best, r;
448 for (i = 0; i < NUM_LANG_SET_MAP; i++)
449 if (lsa->map[i] & lsb->map[i])
451 best = FcLangDifferentLang;
452 for (j = 0; j < NUM_COUNTRY_SET; j++)
453 for (i = 0; i < NUM_LANG_SET_MAP; i++)
454 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
455 (lsb->map[i] & fcLangCountrySets[j][i]))
457 best = FcLangDifferentTerritory;
462 r = FcLangSetCompareStrSet (lsb, lsa->extra);
466 if (best > FcLangEqual && lsb->extra)
468 r = FcLangSetCompareStrSet (lsa, lsb->extra);
476 * Used in computing values -- mustn't allocate any storage
479 FcLangSetPromote (const FcChar8 *lang)
482 static FcStrSet strs;
486 memset (ls.map, '\0', sizeof (ls.map));
488 id = FcLangSetIndex (lang);
491 FcLangSetBitSet (&ls, id);
500 str = (FcChar8 *) lang;
506 FcLangSetHash (const FcLangSet *ls)
511 for (i = 0; i < NUM_LANG_SET_MAP; i++)
519 FcNameParseLangSet (const FcChar8 *string)
525 ls = FcLangSetCreate ();
531 for(i = 0; i < 31;i++)
534 if(c == '\0' || c == '|')
535 break; /* end of this code */
539 if (!FcLangSetAdd (ls, lang))
546 FcLangSetDestroy (ls);
552 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
556 FcBool first = FcTrue;
558 for (i = 0; i < NUM_LANG_SET_MAP; i++)
560 if ((bits = ls->map[i]))
562 for (bit = 0; bit <= 31; bit++)
563 if (bits & (1 << bit))
565 int id = (i << 5) | bit;
567 if (!FcStrBufChar (buf, '|'))
569 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
577 FcStrList *list = FcStrListCreate (ls->extra);
582 while ((extra = FcStrListNext (list)))
585 if (!FcStrBufChar (buf, '|'))
587 FcStrListDone (list);
590 if (!FcStrBufString (buf, extra))
592 FcStrListDone (list);
597 FcStrListDone (list);
603 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
607 for (i = 0; i < NUM_LANG_SET_MAP; i++)
609 if (lsa->map[i] != lsb->map[i])
612 if (!lsa->extra && !lsb->extra)
614 if (lsa->extra && lsb->extra)
615 return FcStrSetEqual (lsa->extra, lsb->extra);
620 FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
625 id = FcLangSetIndex (lang);
628 else if (FcLangSetBitGet (ls, id))
631 * search up and down among equal languages for a match
633 for (i = id - 1; i >= 0; i--)
635 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
637 if (FcLangSetBitGet (ls, i) &&
638 FcLangContains (fcLangCharSets[i].lang, lang))
641 for (i = id; i < NUM_LANG_CHAR_SET; i++)
643 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
645 if (FcLangSetBitGet (ls, i) &&
646 FcLangContains (fcLangCharSets[i].lang, lang))
651 FcStrList *list = FcStrListCreate (ls->extra);
656 while ((extra = FcStrListNext (list)))
658 if (FcLangContains (extra, lang))
661 FcStrListDone (list);
670 * return FcTrue if lsa contains every language in lsb
673 FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
678 if (FcDebug() & FC_DBG_MATCHV)
680 printf ("FcLangSet "); FcLangSetPrint (lsa);
681 printf (" contains "); FcLangSetPrint (lsb);
685 * check bitmaps for missing language support
687 for (i = 0; i < NUM_LANG_SET_MAP; i++)
689 missing = lsb->map[i] & ~lsa->map[i];
692 for (j = 0; j < 32; j++)
693 if (missing & (1 << j))
695 if (!FcLangSetContainsLang (lsa,
696 fcLangCharSets[i*32 + j].lang))
698 if (FcDebug() & FC_DBG_MATCHV)
699 printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
707 FcStrList *list = FcStrListCreate (lsb->extra);
712 while ((extra = FcStrListNext (list)))
714 if (!FcLangSetContainsLang (lsa, extra))
716 if (FcDebug() & FC_DBG_MATCHV)
717 printf ("\tMissing string %s\n", extra);
721 FcStrListDone (list);
730 FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l)
732 if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet)))
738 FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l)
740 FcLangSet *l_serialize = FcSerializePtr (serialize, l);
748 #include "fcaliastail.h"