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 FcCharSet charset;
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)
47 static FcBool langsets_populated = FcFalse;
50 FcFreeTypeLangSet (const FcCharSet *charset,
51 const FcChar8 *exclusiveLang)
55 const FcCharSet *exclusiveCharset = 0;
58 if (!langsets_populated)
60 FcLangCharSetPopulate ();
61 langsets_populated = FcTrue;
65 exclusiveCharset = FcCharSetForLang (exclusiveLang);
66 ls = FcLangSetCreate ();
69 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
72 * Check for Han charsets to make fonts
73 * which advertise support for a single language
74 * not support other Han languages
76 if (exclusiveCharset &&
77 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
79 if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
82 for (j = 0; j < fcLangCharSets[i].charset.num; j++)
83 if (FcCharSetGetLeaf(&fcLangCharSets[i].charset, j) !=
84 FcCharSetGetLeaf(exclusiveCharset, j))
87 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
88 if (FcDebug() & FC_DBG_SCANV)
90 if (missing && missing < 10)
92 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
95 FcChar32 map[FC_CHARSET_MAP_SIZE];
98 printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
100 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
101 ucs4 != FC_CHARSET_DONE;
102 ucs4 = FcCharSetNextPage (missed, map, &next))
105 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
108 for (j = 0; j < 32; j++)
109 if (map[i] & (1 << j))
110 printf (" %04x", ucs4 + i * 32 + j);
114 FcCharSetDestroy (missed);
117 printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
120 FcLangSetBitSet (ls, i);
123 if (FcDebug() & FC_DBG_SCANV)
130 #define FcLangEnd(c) ((c) == '-' || (c) == '\0')
133 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
136 FcLangResult result = FcLangDifferentLang;
147 if (FcLangEnd (c1) && FcLangEnd (c2))
148 result = FcLangDifferentCountry;
154 result = FcLangDifferentCountry;
159 * Return FcTrue when super contains sub.
161 * super contains sub if super and sub have the same
162 * language and either the same country or one
163 * is missing the country
167 FcLangContains (const FcChar8 *super, const FcChar8 *sub)
180 /* see if super has a country while sub is mising one */
181 if (c1 == '-' && c2 == '\0')
183 /* see if sub has a country while super is mising one */
184 if (c1 == '\0' && c2 == '-')
194 FcCharSetForLang (const FcChar8 *lang)
199 if (!langsets_populated)
201 FcLangCharSetPopulate ();
202 langsets_populated = FcTrue;
205 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
207 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
209 return &fcLangCharSets[i].charset;
210 case FcLangDifferentCountry:
219 return &fcLangCharSets[country].charset;
223 FcLangSetCreate (void)
227 ls = malloc (sizeof (FcLangSet));
230 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
231 memset (ls->map, '\0', sizeof (ls->map));
237 FcLangSetDestroy (FcLangSet *ls)
240 FcStrSetDestroy (ls->extra);
241 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
246 FcLangSetCopy (const FcLangSet *ls)
250 new = FcLangSetCreate ();
253 memcpy (new->map, ls->map, sizeof (new->map));
259 new->extra = FcStrSetCreate ();
263 list = FcStrListCreate (ls->extra);
267 while ((extra = FcStrListNext (list)))
268 if (!FcStrSetAdd (new->extra, extra))
270 FcStrListDone (list);
273 FcStrListDone (list);
277 FcLangSetDestroy (new);
283 FcLangSetIndex (const FcChar8 *lang)
285 int low, high, mid = 0;
287 FcChar8 firstChar = FcToLower(lang[0]);
288 FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
293 high = fcLangCharSetRanges[0].begin;
295 else if(firstChar > 'z')
297 low = fcLangCharSetRanges[25].begin;
298 high = NUM_LANG_CHAR_SET - 1;
302 low = fcLangCharSetRanges[firstChar - 'a'].begin;
303 high = fcLangCharSetRanges[firstChar - 'a'].end;
306 return -low; /* next entry after where it would be */
311 mid = (high + low) >> 1;
312 if(fcLangCharSets[mid].lang[0] != firstChar)
313 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
315 { /* fast path for resolving 2-letter languages (by far the most common) after
316 * finding the first char (probably already true because of the hash table) */
317 cmp = fcLangCharSets[mid].lang[1] - secondChar;
319 (fcLangCharSets[mid].lang[2] != '\0' ||
322 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
339 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
343 id = FcLangSetIndex (lang);
346 FcLangSetBitSet (ls, id);
351 ls->extra = FcStrSetCreate ();
355 return FcStrSetAdd (ls->extra, lang);
359 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
362 FcLangResult best, r;
365 id = FcLangSetIndex (lang);
368 else if (FcLangSetBitGet (ls, id))
370 best = FcLangDifferentLang;
371 for (i = id - 1; i >= 0; i--)
373 r = FcLangCompare (lang, fcLangCharSets[i].lang);
374 if (r == FcLangDifferentLang)
376 if (FcLangSetBitGet (ls, i) && r < best)
379 for (i = id; i < NUM_LANG_CHAR_SET; i++)
381 r = FcLangCompare (lang, fcLangCharSets[i].lang);
382 if (r == FcLangDifferentLang)
384 if (FcLangSetBitGet (ls, i) && r < best)
389 FcStrList *list = FcStrListCreate (ls->extra);
394 while (best > FcLangEqual && (extra = FcStrListNext (list)))
396 r = FcLangCompare (lang, extra);
400 FcStrListDone (list);
407 FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
409 FcStrList *list = FcStrListCreate (set);
410 FcLangResult r, best = FcLangDifferentLang;
415 while (best > FcLangEqual && (extra = FcStrListNext (list)))
417 r = FcLangSetHasLang (ls, extra);
421 FcStrListDone (list);
427 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
430 FcLangResult best, r;
432 for (i = 0; i < NUM_LANG_SET_MAP; i++)
433 if (lsa->map[i] & lsb->map[i])
435 best = FcLangDifferentLang;
436 for (j = 0; j < NUM_COUNTRY_SET; j++)
437 for (i = 0; i < NUM_LANG_SET_MAP; i++)
438 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
439 (lsb->map[i] & fcLangCountrySets[j][i]))
441 best = FcLangDifferentCountry;
446 r = FcLangSetCompareStrSet (lsb, lsa->extra);
450 if (best > FcLangEqual && lsb->extra)
452 r = FcLangSetCompareStrSet (lsa, lsb->extra);
460 * Used in computing values -- mustn't allocate any storage
463 FcLangSetPromote (const FcChar8 *lang)
466 static FcStrSet strs;
470 memset (ls.map, '\0', sizeof (ls.map));
472 id = FcLangSetIndex (lang);
475 FcLangSetBitSet (&ls, id);
484 str = (FcChar8 *) lang;
490 FcLangSetHash (const FcLangSet *ls)
495 for (i = 0; i < NUM_LANG_SET_MAP; i++)
503 FcNameParseLangSet (const FcChar8 *string)
509 ls = FcLangSetCreate ();
515 for(i = 0; i < 31;i++)
518 if(c == '\0' || c == '|')
519 break; /* end of this code */
523 if (!FcLangSetAdd (ls, lang))
530 FcLangSetDestroy (ls);
536 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
540 FcBool first = FcTrue;
542 for (i = 0; i < NUM_LANG_SET_MAP; i++)
544 if ((bits = ls->map[i]))
546 for (bit = 0; bit <= 31; bit++)
547 if (bits & (1 << bit))
549 int id = (i << 5) | bit;
551 if (!FcStrBufChar (buf, '|'))
553 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
561 FcStrList *list = FcStrListCreate (ls->extra);
566 while ((extra = FcStrListNext (list)))
569 if (!FcStrBufChar (buf, '|'))
571 FcStrListDone (list);
574 if (!FcStrBufString (buf, extra))
576 FcStrListDone (list);
581 FcStrListDone (list);
587 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
591 for (i = 0; i < NUM_LANG_SET_MAP; i++)
593 if (lsa->map[i] != lsb->map[i])
596 if (!lsa->extra && !lsb->extra)
598 if (lsa->extra && lsb->extra)
599 return FcStrSetEqual (lsa->extra, lsb->extra);
604 FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
609 id = FcLangSetIndex (lang);
612 else if (FcLangSetBitGet (ls, id))
615 * search up and down among equal languages for a match
617 for (i = id - 1; i >= 0; i--)
619 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
621 if (FcLangSetBitGet (ls, i) &&
622 FcLangContains (fcLangCharSets[i].lang, lang))
625 for (i = id; i < NUM_LANG_CHAR_SET; i++)
627 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
629 if (FcLangSetBitGet (ls, i) &&
630 FcLangContains (fcLangCharSets[i].lang, lang))
635 FcStrList *list = FcStrListCreate (ls->extra);
640 while ((extra = FcStrListNext (list)))
642 if (FcLangContains (extra, lang))
645 FcStrListDone (list);
654 * return FcTrue if lsa contains every language in lsb
657 FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
662 if (FcDebug() & FC_DBG_MATCHV)
664 printf ("FcLangSet "); FcLangSetPrint (lsa);
665 printf (" contains "); FcLangSetPrint (lsb);
669 * check bitmaps for missing language support
671 for (i = 0; i < NUM_LANG_SET_MAP; i++)
673 missing = lsb->map[i] & ~lsa->map[i];
676 for (j = 0; j < 32; j++)
677 if (missing & (1 << j))
679 if (!FcLangSetContainsLang (lsa,
680 fcLangCharSets[i*32 + j].lang))
682 if (FcDebug() & FC_DBG_MATCHV)
683 printf ("\tMissing bitmap %s\n", fcLangCharSets[i*32+j].lang);
691 FcStrList *list = FcStrListCreate (lsb->extra);
696 while ((extra = FcStrListNext (list)))
698 if (!FcLangSetContainsLang (lsa, extra))
700 if (FcDebug() & FC_DBG_MATCHV)
701 printf ("\tMissing string %s\n", extra);
705 FcStrListDone (list);
713 static FcLangSet ** langsets = 0;
714 static int langset_bank_count = 0, langset_ptr = 0, langset_count = 0;
717 FcLangSetNewBank (void)
722 /* ideally, should only write one copy of any particular FcLangSet */
724 FcLangSetNeededBytes (const FcLangSet *l)
727 return sizeof (FcLangSet);
731 FcLangSetNeededBytesAlign (void)
733 return fc_alignof (FcLangSet);
737 FcLangSetEnsureBank (int bi)
739 if (!langsets || bi >= langset_bank_count)
741 int new_count = langset_bank_count + 2;
744 tt = realloc(langsets, new_count * sizeof(FcLangSet *));
749 for (i = langset_bank_count; i < new_count; i++)
751 langset_bank_count = new_count;
758 FcLangSetDistributeBytes (FcCache * metadata, void * block_ptr)
760 int bi = FcCacheBankToIndex(metadata->bank);
761 if (!FcLangSetEnsureBank(bi))
764 block_ptr = ALIGN(block_ptr, FcLangSet);
765 langsets[bi] = block_ptr;
766 block_ptr = (void *)((char *)block_ptr +
767 langset_count * sizeof(FcLangSet));
769 metadata->langset_count = langset_count;
774 FcLangSetSerialize(int bank, FcLangSet *l)
776 int p = langset_ptr, bi = FcCacheBankToIndex(bank);
780 langsets[bi][langset_ptr] = *l;
781 langsets[bi][langset_ptr].extra = 0;
783 return &langsets[bi][p];
787 FcLangSetUnserialize (FcCache * metadata, void *block_ptr)
789 int bi = FcCacheBankToIndex(metadata->bank);
790 if (!FcLangSetEnsureBank(bi))
793 FcMemAlloc (FC_MEM_LANGSET, metadata->langset_count * sizeof(FcLangSet));
794 block_ptr = ALIGN(block_ptr, FcLangSet);
795 langsets[bi] = (FcLangSet *)block_ptr;
796 block_ptr = (void *)((char *)block_ptr +
797 metadata->langset_count * sizeof(FcLangSet));