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.
39 #include "../fc-lang/fclang.h"
42 FcChar32 map[NUM_LANG_SET_MAP];
46 #define FcLangSetBitSet(ls, id) ((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
47 #define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
50 FcFreeTypeLangSet (const FcCharSet *charset,
51 const FcChar8 *exclusiveLang)
55 const FcCharSet *exclusiveCharset = 0;
60 exclusiveCharset = FcCharSetForLang (exclusiveLang);
61 ls = FcLangSetCreate ();
64 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
67 * Check for Han charsets to make fonts
68 * which advertise support for a single language
69 * not support other Han languages
71 if (exclusiveCharset &&
72 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
74 if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
77 for (j = 0; j < fcLangCharSets[i].charset.num; j++)
78 if (FcCharSetGetLeaf(&fcLangCharSets[i].charset, j) !=
79 FcCharSetGetLeaf(exclusiveCharset, j))
82 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
83 if (FcDebug() & FC_DBG_SCANV)
85 if (missing && missing < 10)
87 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
90 FcChar32 map[FC_CHARSET_MAP_SIZE];
93 printf ("\n%s(%d) ", fcLangCharSets[i].lang, missing);
95 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
96 ucs4 != FC_CHARSET_DONE;
97 ucs4 = FcCharSetNextPage (missed, map, &next))
100 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
103 for (j = 0; j < 32; j++)
104 if (map[i] & (1 << j))
105 printf (" %04x", ucs4 + i * 32 + j);
109 FcCharSetDestroy (missed);
112 printf ("%s(%d) ", fcLangCharSets[i].lang, missing);
115 FcLangSetBitSet (ls, i);
118 if (FcDebug() & FC_DBG_SCANV)
125 #define FcLangEnd(c) ((c) == '-' || (c) == '\0')
128 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
131 FcLangResult result = FcLangDifferentLang;
142 if (FcLangEnd (c1) && FcLangEnd (c2))
143 result = FcLangDifferentCountry;
149 result = FcLangDifferentCountry;
154 * Return FcTrue when super contains sub.
156 * super contains sub if super and sub have the same
157 * language and either the same country or one
158 * is missing the country
162 FcLangContains (const FcChar8 *super, const FcChar8 *sub)
175 /* see if super has a country while sub is mising one */
176 if (c1 == '-' && c2 == '\0')
178 /* see if sub has a country while super is mising one */
179 if (c1 == '\0' && c2 == '-')
189 FcCharSetForLang (const FcChar8 *lang)
193 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
195 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
197 return &fcLangCharSets[i].charset;
198 case FcLangDifferentCountry:
207 return &fcLangCharSets[i].charset;
211 FcLangSetCreate (void)
215 ls = malloc (sizeof (FcLangSet));
218 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
219 memset (ls->map, '\0', sizeof (ls->map));
220 ls->extra = FcStrSetPtrCreateDynamic(0);
225 FcLangSetPtrDestroy (FcLangSetPtr li)
227 if (li.storage == FcStorageDynamic)
228 FcLangSetDestroy(FcLangSetPtrU(li));
232 FcLangSetDestroy (FcLangSet *ls)
234 if (FcStrSetPtrU(ls->extra))
235 FcStrSetDestroy (FcStrSetPtrU(ls->extra));
236 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
241 FcLangSetCopy (const FcLangSet *ls)
245 new = FcLangSetCreate ();
248 memcpy (new->map, ls->map, sizeof (new->map));
249 if (FcStrSetPtrU(ls->extra))
254 new->extra = FcStrSetPtrCreateDynamic(FcStrSetCreate ());
255 if (!FcStrSetPtrU(new->extra))
258 list = FcStrListCreate (FcStrSetPtrU(ls->extra));
262 while ((extra = FcStrListNext (list)))
263 if (!FcStrSetAdd (FcStrSetPtrU(new->extra), extra))
265 FcStrListDone (list);
268 FcStrListDone (list);
272 FcLangSetDestroy (new);
278 FcLangSetIndex (const FcChar8 *lang)
280 int low, high, mid = 0;
282 FcChar8 firstChar = FcToLower(lang[0]);
283 FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
288 high = fcLangCharSetRanges[0].begin;
290 else if(firstChar > 'z')
292 low = fcLangCharSetRanges[25].begin;
293 high = NUM_LANG_CHAR_SET - 1;
297 low = fcLangCharSetRanges[firstChar - 'a'].begin;
298 high = fcLangCharSetRanges[firstChar - 'a'].end;
301 return -low; /* next entry after where it would be */
306 mid = (high + low) >> 1;
307 if(fcLangCharSets[mid].lang[0] != firstChar)
308 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
310 { /* fast path for resolving 2-letter languages (by far the most common) after
311 * finding the first char (probably already true because of the hash table) */
312 cmp = fcLangCharSets[mid].lang[1] - secondChar;
314 (fcLangCharSets[mid].lang[2] != '\0' ||
317 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
334 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
338 id = FcLangSetIndex (lang);
341 FcLangSetBitSet (ls, id);
344 if (!FcStrSetPtrU(ls->extra))
346 ls->extra = FcStrSetPtrCreateDynamic(FcStrSetCreate ());
347 if (!FcStrSetPtrU(ls->extra))
350 return FcStrSetAdd (FcStrSetPtrU(ls->extra), lang);
354 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
357 FcLangResult best, r;
360 id = FcLangSetIndex (lang);
363 else if (FcLangSetBitGet (ls, id))
365 best = FcLangDifferentLang;
366 for (i = id - 1; i >= 0; i--)
368 r = FcLangCompare (lang, fcLangCharSets[i].lang);
369 if (r == FcLangDifferentLang)
371 if (FcLangSetBitGet (ls, i) && r < best)
374 for (i = id; i < NUM_LANG_CHAR_SET; i++)
376 r = FcLangCompare (lang, fcLangCharSets[i].lang);
377 if (r == FcLangDifferentLang)
379 if (FcLangSetBitGet (ls, i) && r < best)
382 if (FcStrSetPtrU(ls->extra))
384 FcStrList *list = FcStrListCreate (FcStrSetPtrU(ls->extra));
390 while (best > FcLangEqual && (extra = FcStrListNext (list)))
392 r = FcLangCompare (lang, extra);
396 FcStrListDone (list);
403 FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
405 FcStrList *list = FcStrListCreate (set);
406 FcLangResult r, best = FcLangDifferentLang;
411 while (best > FcLangEqual && (extra = FcStrListNext (list)))
413 r = FcLangSetHasLang (ls, extra);
417 FcStrListDone (list);
423 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
426 FcLangResult best, r;
428 for (i = 0; i < NUM_LANG_SET_MAP; i++)
429 if (lsa->map[i] & lsb->map[i])
431 best = FcLangDifferentLang;
432 for (j = 0; j < NUM_COUNTRY_SET; j++)
433 for (i = 0; i < NUM_LANG_SET_MAP; i++)
434 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
435 (lsb->map[i] & fcLangCountrySets[j][i]))
437 best = FcLangDifferentCountry;
440 if (FcStrSetPtrU(lsa->extra))
442 r = FcLangSetCompareStrSet (lsb, FcStrSetPtrU(lsa->extra));
446 if (best > FcLangEqual && FcStrSetPtrU(lsb->extra))
448 r = FcLangSetCompareStrSet (lsa, FcStrSetPtrU(lsb->extra));
456 * Used in computing values -- mustn't allocate any storage
459 FcLangSetPromote (const FcChar8 *lang)
462 static FcStrSet strs;
466 memset (ls.map, '\0', sizeof (ls.map));
467 ls.extra = FcStrSetPtrCreateDynamic(0);
468 id = FcLangSetIndex (lang);
471 FcLangSetBitSet (&ls, id);
475 ls.extra = FcStrSetPtrCreateDynamic(&strs);
478 strs.storage = FcStorageDynamic;
481 str = (FcChar8 *) lang;
487 FcLangSetHash (const FcLangSet *ls)
492 for (i = 0; i < NUM_LANG_SET_MAP; i++)
494 if (FcStrSetPtrU(ls->extra))
495 h ^= FcStrSetPtrU(ls->extra)->num;
500 FcNameParseLangSet (const FcChar8 *string)
506 ls = FcLangSetCreate ();
512 for(i = 0; i < 31;i++)
515 if(c == '\0' || c == '|')
516 break; /* end of this code */
520 if (!FcLangSetAdd (ls, lang))
527 FcLangSetDestroy (ls);
533 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
537 FcBool first = FcTrue;
539 for (i = 0; i < NUM_LANG_SET_MAP; i++)
541 if ((bits = ls->map[i]))
543 for (bit = 0; bit <= 31; bit++)
544 if (bits & (1 << bit))
546 int id = (i << 5) | bit;
548 if (!FcStrBufChar (buf, '|'))
550 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
556 if (FcStrSetPtrU(ls->extra))
558 FcStrList *list = FcStrListCreate (FcStrSetPtrU(ls->extra));
563 while ((extra = FcStrListNext (list)))
566 if (!FcStrBufChar (buf, '|'))
568 if (!FcStrBufString (buf, extra))
577 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
581 for (i = 0; i < NUM_LANG_SET_MAP; i++)
583 if (lsa->map[i] != lsb->map[i])
586 if (!FcStrSetPtrU(lsa->extra) && !FcStrSetPtrU(lsb->extra))
588 if (FcStrSetPtrU(lsa->extra) && FcStrSetPtrU(lsb->extra))
589 return FcStrSetEqual (FcStrSetPtrU(lsa->extra), FcStrSetPtrU(lsb->extra));
594 FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
599 id = FcLangSetIndex (lang);
602 else if (FcLangSetBitGet (ls, id))
605 * search up and down among equal languages for a match
607 for (i = id - 1; i >= 0; i--)
609 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
611 if (FcLangSetBitGet (ls, i) &&
612 FcLangContains (fcLangCharSets[i].lang, lang))
615 for (i = id; i < NUM_LANG_CHAR_SET; i++)
617 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
619 if (FcLangSetBitGet (ls, i) &&
620 FcLangContains (fcLangCharSets[i].lang, lang))
623 if (FcStrSetPtrU(ls->extra))
625 FcStrList *list = FcStrListCreate (FcStrSetPtrU(ls->extra));
630 while ((extra = FcStrListNext (list)))
632 if (FcLangContains (extra, lang))
635 FcStrListDone (list);
644 * return FcTrue if lsa contains every language in lsb
647 FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
652 if (FcDebug() & FC_DBG_MATCHV)
654 printf ("FcLangSet "); FcLangSetPrint (lsa);
655 printf (" contains "); FcLangSetPrint (lsb);
659 * check bitmaps for missing language support
661 for (i = 0; i < NUM_LANG_SET_MAP; i++)
663 missing = lsb->map[i] & ~lsa->map[i];
666 for (j = 0; j < 32; j++)
667 if (missing & (1 << j))
669 if (!FcLangSetContainsLang (lsa,
670 fcLangCharSets[i*32 + j].lang))
672 if (FcDebug() & FC_DBG_MATCHV)
673 printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
679 if (FcStrSetPtrU(lsb->extra))
681 FcStrList *list = FcStrListCreate (FcStrSetPtrU(lsb->extra));
686 while ((extra = FcStrListNext (list)))
688 if (!FcLangSetContainsLang (lsa, extra))
690 if (FcDebug() & FC_DBG_MATCHV)
691 printf ("\tMissing string %s\n", extra);
695 FcStrListDone (list);
703 static FcLangSet * langsets = 0;
704 static int langset_ptr = 0, langset_count = 0;
707 FcLangSetPtrU (FcLangSetPtr li)
711 case FcStorageDynamic:
713 case FcStorageStatic:
714 return &langsets[li.u.stat];
722 FcLangSetPtrCreateDynamic (FcLangSet *li)
725 new.storage = FcStorageDynamic;
731 FcLangSetClearStatic (void)
733 FcStrSetClearStatic();
738 /* should only write one copy of any particular FcLangSet */
740 FcLangSetPrepareSerialize (FcLangSet *l)
743 if (l && FcStrSetPtrU(l->extra))
744 return FcStrSetPrepareSerialize (FcStrSetPtrU(l->extra));
749 FcLangSetSerialize(FcLangSet *l)
754 if (!l) return FcLangSetPtrCreateDynamic(0);
759 t = (FcLangSet *)malloc(langset_count * sizeof(FcLangSet));
761 return FcLangSetPtrCreateDynamic(0);
766 langsets[langset_ptr] = *l;
767 if (FcStrSetPtrU(l->extra))
768 langsets[langset_ptr].extra =
769 FcStrSetSerialize(FcStrSetPtrU(l->extra));
771 langsets[langset_ptr].extra = FcStrSetPtrCreateDynamic(0);
773 new.storage = FcStorageStatic;
779 FcLangSetWrite (int fd, FcCache *metadata)
781 metadata->langsets_length = langset_ptr;
782 metadata->langsets_offset = FcCacheNextOffset(fd);
786 lseek (fd, metadata->langsets_offset, SEEK_SET);
787 return write(fd, langsets,
788 metadata->langsets_length * sizeof(FcLangSet)) != -1;
794 FcLangSetRead (int fd, FcCache metadata)
796 langsets = mmap(NULL,
797 metadata.langsets_length * sizeof (FcLangSet),
799 MAP_SHARED, fd, metadata.langsets_offset);
800 if (langsets == MAP_FAILED)
802 langset_count = langset_ptr = metadata.langsets_length;