2 * fontconfig/src/fclang.c
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 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) 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"
43 FcChar32 map[NUM_LANG_SET_MAP];
47 FcLangSetBitSet (FcLangSet *ls,
52 id = fcLangCharSetIndices[id];
54 if (bucket >= ls->map_size)
55 return; /* shouldn't happen really */
57 ls->map[bucket] |= ((FcChar32) 1 << (id & 0x1f));
61 FcLangSetBitGet (const FcLangSet *ls,
66 id = fcLangCharSetIndices[id];
68 if (bucket >= ls->map_size)
71 return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse;
75 FcFreeTypeLangSet (const FcCharSet *charset,
76 const FcChar8 *exclusiveLang)
80 const FcCharSet *exclusiveCharset = 0;
84 exclusiveCharset = FcLangGetCharSet (exclusiveLang);
85 ls = FcLangSetCreate ();
88 if (FcDebug() & FC_DBG_LANGSET)
90 printf ("font charset");
91 FcCharSetPrint (charset);
94 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
96 if (FcDebug() & FC_DBG_LANGSET)
98 printf ("%s charset", fcLangCharSets[i].lang);
99 FcCharSetPrint (&fcLangCharSets[i].charset);
104 * Check for Han charsets to make fonts
105 * which advertise support for a single language
106 * not support other Han languages
108 if (exclusiveCharset &&
109 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
111 if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
114 for (j = 0; j < fcLangCharSets[i].charset.num; j++)
115 if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) !=
116 FcCharSetLeaf(exclusiveCharset, j))
119 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
120 if (FcDebug() & FC_DBG_SCANV)
122 if (missing && missing < 10)
124 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
127 FcChar32 map[FC_CHARSET_MAP_SIZE];
130 printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
132 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
133 ucs4 != FC_CHARSET_DONE;
134 ucs4 = FcCharSetNextPage (missed, map, &next))
137 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
140 for (j = 0; j < 32; j++)
141 if (map[i] & (1 << j))
142 printf (" %04x", ucs4 + i * 32 + j);
146 FcCharSetDestroy (missed);
149 printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
152 FcLangSetBitSet (ls, i);
155 if (FcDebug() & FC_DBG_SCANV)
162 #define FcLangEnd(c) ((c) == '-' || (c) == '\0')
165 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
168 FcLangResult result = FcLangDifferentLang;
179 if (FcLangEnd (c1) && FcLangEnd (c2))
180 result = FcLangDifferentTerritory;
186 result = FcLangDifferentTerritory;
191 * Return FcTrue when super contains sub.
193 * super contains sub if super and sub have the same
194 * language and either the same country or one
195 * is missing the country
199 FcLangContains (const FcChar8 *super, const FcChar8 *sub)
212 /* see if super has a country while sub is mising one */
213 if (c1 == '-' && c2 == '\0')
215 /* see if sub has a country while super is mising one */
216 if (c1 == '\0' && c2 == '-')
226 FcLangGetCharSet (const FcChar8 *lang)
231 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
233 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
235 return &fcLangCharSets[i].charset;
236 case FcLangDifferentTerritory:
239 case FcLangDifferentLang:
246 return &fcLangCharSets[country].charset;
255 langs = FcStrSetCreate();
259 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
260 FcStrSetAdd (langs, fcLangCharSets[i].lang);
266 FcLangSetCreate (void)
270 ls = malloc (sizeof (FcLangSet));
273 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
274 memset (ls->map, '\0', sizeof (ls->map));
275 ls->map_size = NUM_LANG_SET_MAP;
281 FcLangSetDestroy (FcLangSet *ls)
284 FcStrSetDestroy (ls->extra);
285 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
290 FcLangSetCopy (const FcLangSet *ls)
294 new = FcLangSetCreate ();
297 memset (new->map, '\0', sizeof (new->map));
298 memcpy (new->map, ls->map, FC_MIN (sizeof (new->map), ls->map_size * sizeof (ls->map[0])));
304 new->extra = FcStrSetCreate ();
308 list = FcStrListCreate (ls->extra);
312 while ((extra = FcStrListNext (list)))
313 if (!FcStrSetAdd (new->extra, extra))
315 FcStrListDone (list);
318 FcStrListDone (list);
322 FcLangSetDestroy (new);
328 FcLangSetIndex (const FcChar8 *lang)
330 int low, high, mid = 0;
332 FcChar8 firstChar = FcToLower(lang[0]);
333 FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
338 high = fcLangCharSetRanges[0].begin;
340 else if(firstChar > 'z')
342 low = fcLangCharSetRanges[25].begin;
343 high = NUM_LANG_CHAR_SET - 1;
347 low = fcLangCharSetRanges[firstChar - 'a'].begin;
348 high = fcLangCharSetRanges[firstChar - 'a'].end;
351 return -low; /* next entry after where it would be */
356 mid = (high + low) >> 1;
357 if(fcLangCharSets[mid].lang[0] != firstChar)
358 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
360 { /* fast path for resolving 2-letter languages (by far the most common) after
361 * finding the first char (probably already true because of the hash table) */
362 cmp = fcLangCharSets[mid].lang[1] - secondChar;
364 (fcLangCharSets[mid].lang[2] != '\0' ||
367 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
384 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
388 id = FcLangSetIndex (lang);
391 FcLangSetBitSet (ls, id);
396 ls->extra = FcStrSetCreate ();
400 return FcStrSetAdd (ls->extra, lang);
404 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
407 FcLangResult best, r;
410 id = FcLangSetIndex (lang);
413 else if (FcLangSetBitGet (ls, id))
415 best = FcLangDifferentLang;
416 for (i = id - 1; i >= 0; i--)
418 r = FcLangCompare (lang, fcLangCharSets[i].lang);
419 if (r == FcLangDifferentLang)
421 if (FcLangSetBitGet (ls, i) && r < best)
424 for (i = id; i < NUM_LANG_CHAR_SET; i++)
426 r = FcLangCompare (lang, fcLangCharSets[i].lang);
427 if (r == FcLangDifferentLang)
429 if (FcLangSetBitGet (ls, i) && r < best)
434 FcStrList *list = FcStrListCreate (ls->extra);
439 while (best > FcLangEqual && (extra = FcStrListNext (list)))
441 r = FcLangCompare (lang, extra);
445 FcStrListDone (list);
452 FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
454 FcStrList *list = FcStrListCreate (set);
455 FcLangResult r, best = FcLangDifferentLang;
460 while (best > FcLangEqual && (extra = FcStrListNext (list)))
462 r = FcLangSetHasLang (ls, extra);
466 FcStrListDone (list);
472 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
475 FcLangResult best, r;
477 count = FC_MIN (lsa->map_size, lsb->map_size);
478 count = FC_MIN (NUM_LANG_SET_MAP, count);
479 for (i = 0; i < count; i++)
480 if (lsa->map[i] & lsb->map[i])
482 best = FcLangDifferentLang;
483 for (j = 0; j < NUM_COUNTRY_SET; j++)
484 for (i = 0; i < count; i++)
485 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
486 (lsb->map[i] & fcLangCountrySets[j][i]))
488 best = FcLangDifferentTerritory;
493 r = FcLangSetCompareStrSet (lsb, lsa->extra);
497 if (best > FcLangEqual && lsb->extra)
499 r = FcLangSetCompareStrSet (lsa, lsb->extra);
507 * Used in computing values -- mustn't allocate any storage
510 FcLangSetPromote (const FcChar8 *lang)
513 static FcStrSet strs;
517 memset (ls.map, '\0', sizeof (ls.map));
519 id = FcLangSetIndex (lang);
522 FcLangSetBitSet (&ls, id);
531 str = (FcChar8 *) lang;
537 FcLangSetHash (const FcLangSet *ls)
542 for (i = 0; i < ls->map_size; i++)
550 FcNameParseLangSet (const FcChar8 *string)
552 FcChar8 lang[32], c = 0;
556 ls = FcLangSetCreate ();
562 for(i = 0; i < 31;i++)
565 if(c == '\0' || c == '|')
566 break; /* end of this code */
570 if (!FcLangSetAdd (ls, lang))
577 FcLangSetDestroy (ls);
583 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
587 FcBool first = FcTrue;
589 count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
590 for (i = 0; i < count; i++)
592 if ((bits = ls->map[i]))
594 for (bit = 0; bit <= 31; bit++)
595 if (bits & (1 << bit))
597 int id = (i << 5) | bit;
599 if (!FcStrBufChar (buf, '|'))
601 if (!FcStrBufString (buf, fcLangCharSets[fcLangCharSetIndicesInv[id]].lang))
609 FcStrList *list = FcStrListCreate (ls->extra);
614 while ((extra = FcStrListNext (list)))
617 if (!FcStrBufChar (buf, '|'))
619 FcStrListDone (list);
622 if (!FcStrBufString (buf, extra))
624 FcStrListDone (list);
629 FcStrListDone (list);
635 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
639 count = FC_MIN (lsa->map_size, lsb->map_size);
640 count = FC_MIN (NUM_LANG_SET_MAP, count);
641 for (i = 0; i < count; i++)
643 if (lsa->map[i] != lsb->map[i])
646 if (!lsa->extra && !lsb->extra)
648 if (lsa->extra && lsb->extra)
649 return FcStrSetEqual (lsa->extra, lsb->extra);
654 FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
659 id = FcLangSetIndex (lang);
662 else if (FcLangSetBitGet (ls, id))
665 * search up and down among equal languages for a match
667 for (i = id - 1; i >= 0; i--)
669 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
671 if (FcLangSetBitGet (ls, i) &&
672 FcLangContains (fcLangCharSets[i].lang, lang))
675 for (i = id; i < NUM_LANG_CHAR_SET; i++)
677 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
679 if (FcLangSetBitGet (ls, i) &&
680 FcLangContains (fcLangCharSets[i].lang, lang))
685 FcStrList *list = FcStrListCreate (ls->extra);
690 while ((extra = FcStrListNext (list)))
692 if (FcLangContains (extra, lang))
695 FcStrListDone (list);
704 * return FcTrue if lsa contains every language in lsb
707 FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
712 if (FcDebug() & FC_DBG_MATCHV)
714 printf ("FcLangSet "); FcLangSetPrint (lsa);
715 printf (" contains "); FcLangSetPrint (lsb);
719 * check bitmaps for missing language support
721 count = FC_MIN (lsa->map_size, lsb->map_size);
722 count = FC_MIN (NUM_LANG_SET_MAP, count);
723 for (i = 0; i < count; i++)
725 missing = lsb->map[i] & ~lsa->map[i];
728 for (j = 0; j < 32; j++)
729 if (missing & (1 << j))
731 if (!FcLangSetContainsLang (lsa,
732 fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang))
734 if (FcDebug() & FC_DBG_MATCHV)
735 printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[i*32+j]].lang);
743 FcStrList *list = FcStrListCreate (lsb->extra);
748 while ((extra = FcStrListNext (list)))
750 if (!FcLangSetContainsLang (lsa, extra))
752 if (FcDebug() & FC_DBG_MATCHV)
753 printf ("\tMissing string %s\n", extra);
757 FcStrListDone (list);
766 FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l)
768 if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet)))
774 FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l)
776 FcLangSet *l_serialize = FcSerializePtr (serialize, l);
781 l_serialize->extra = NULL; /* We don't serialize ls->extra */
786 FcLangSetGetLangs (const FcLangSet *ls)
791 langs = FcStrSetCreate();
795 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
796 if (FcLangSetBitGet (ls, i))
797 FcStrSetAdd (langs, fcLangCharSets[i].lang);
801 FcStrList *list = FcStrListCreate (ls->extra);
806 while ((extra = FcStrListNext (list)))
807 FcStrSetAdd (langs, extra);
809 FcStrListDone (list);
817 #include "fcaliastail.h"
818 #include "fcftaliastail.h"