]> git.wh0rd.org - fontconfig.git/blame - src/fclang.c
Bug 28958 - lang=en matches other langs
[fontconfig.git] / src / fclang.c
CommitLineData
3de8881e 1/*
317b8492 2 * fontconfig/src/fclang.c
3de8881e 3 *
46b51147 4 * Copyright © 2002 Keith Packard
3de8881e
KP
5 *
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
5aaf466d 10 * documentation, and that the name of the author(s) not be used in
3de8881e 11 * advertising or publicity pertaining to distribution of the software without
5aaf466d 12 * specific, written prior permission. The authors make no
3de8881e
KP
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
3074a73b 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
3de8881e 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
3074a73b 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
3de8881e
KP
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.
23 */
24
25#include "fcint.h"
dbd065ad 26#include "fcftint.h"
3de8881e
KP
27
28typedef struct {
e85789a9 29 const FcChar8 lang[8];
21696e5b 30 const FcCharSet charset;
3de8881e
KP
31} FcLangCharSet;
32
793e946c
KP
33typedef struct {
34 int begin;
35 int end;
36} FcLangCharSetRange;
37
e50b9ae7 38#include "../fc-lang/fclang.h"
3de8881e 39
d8d73958 40struct _FcLangSet {
4262e0b3 41 FcStrSet *extra;
8480c6f8 42 FcChar32 map_size;
1f4e6fec 43 FcChar32 map[NUM_LANG_SET_MAP];
d8d73958
KP
44};
45
1f4e6fec
BE
46static void
47FcLangSetBitSet (FcLangSet *ls,
48 unsigned int id)
49{
50 int bucket;
51
52 id = fcLangCharSetIndices[id];
53 bucket = id >> 5;
54 if (bucket >= ls->map_size)
55 return; /* shouldn't happen really */
56
57 ls->map[bucket] |= ((FcChar32) 1 << (id & 0x1f));
58}
59
60static FcBool
61FcLangSetBitGet (const FcLangSet *ls,
62 unsigned int id)
63{
64 int bucket;
65
66 id = fcLangCharSetIndices[id];
67 bucket = id >> 5;
68 if (bucket >= ls->map_size)
69 return FcFalse;
70
71 return ((ls->map[bucket] >> (id & 0x1f)) & 1) ? FcTrue : FcFalse;
72}
d8d73958
KP
73
74FcLangSet *
594dcef0 75FcFreeTypeLangSet (const FcCharSet *charset,
e50b9ae7 76 const FcChar8 *exclusiveLang)
3de8881e 77{
cd2ec1a9 78 int i, j;
e50b9ae7 79 FcChar32 missing;
e50b9ae7 80 const FcCharSet *exclusiveCharset = 0;
d8d73958 81 FcLangSet *ls;
82f35f8b 82
e50b9ae7 83 if (exclusiveLang)
cf223cc7 84 exclusiveCharset = FcLangGetCharSet (exclusiveLang);
d8d73958
KP
85 ls = FcLangSetCreate ();
86 if (!ls)
87 return 0;
594dcef0 88 if (FcDebug() & FC_DBG_LANGSET)
7ce19673 89 {
7c12181f 90 printf ("font charset");
7ce19673
KP
91 FcCharSetPrint (charset);
92 printf ("\n");
93 }
3de8881e
KP
94 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
95 {
594dcef0 96 if (FcDebug() & FC_DBG_LANGSET)
7ce19673 97 {
7c12181f 98 printf ("%s charset", fcLangCharSets[i].lang);
7ce19673
KP
99 FcCharSetPrint (&fcLangCharSets[i].charset);
100 printf ("\n");
101 }
102
e50b9ae7
KP
103 /*
104 * Check for Han charsets to make fonts
105 * which advertise support for a single language
106 * not support other Han languages
107 */
108 if (exclusiveCharset &&
cd2ec1a9 109 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
e50b9ae7 110 {
cd2ec1a9
PL
111 if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
112 continue;
113
114 for (j = 0; j < fcLangCharSets[i].charset.num; j++)
594dcef0 115 if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) !=
7ce19673 116 FcCharSetLeaf(exclusiveCharset, j))
cd2ec1a9 117 continue;
e50b9ae7 118 }
3de8881e
KP
119 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
120 if (FcDebug() & FC_DBG_SCANV)
c80d2ac4
KP
121 {
122 if (missing && missing < 10)
123 {
594dcef0 124 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
c80d2ac4
KP
125 charset);
126 FcChar32 ucs4;
127 FcChar32 map[FC_CHARSET_MAP_SIZE];
128 FcChar32 next;
129
0d745819 130 printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
c80d2ac4
KP
131 printf ("{");
132 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
133 ucs4 != FC_CHARSET_DONE;
134 ucs4 = FcCharSetNextPage (missed, map, &next))
135 {
136 int i, j;
137 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
138 if (map[i])
139 {
140 for (j = 0; j < 32; j++)
141 if (map[i] & (1 << j))
142 printf (" %04x", ucs4 + i * 32 + j);
143 }
144 }
145 printf (" }\n\t");
146 FcCharSetDestroy (missed);
147 }
148 else
0d745819 149 printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
c80d2ac4 150 }
e50b9ae7 151 if (!missing)
d8d73958 152 FcLangSetBitSet (ls, i);
3de8881e 153 }
e50b9ae7 154
3de8881e
KP
155 if (FcDebug() & FC_DBG_SCANV)
156 printf ("\n");
594dcef0
BE
157
158
d8d73958 159 return ls;
3de8881e
KP
160}
161
d8d73958 162#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
3de8881e
KP
163
164FcLangResult
165FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
166{
3de8881e 167 FcChar8 c1, c2;
d8d73958
KP
168 FcLangResult result = FcLangDifferentLang;
169
3de8881e
KP
170 for (;;)
171 {
172 c1 = *s1++;
173 c2 = *s2++;
d8d73958 174
3de8881e
KP
175 c1 = FcToLower (c1);
176 c2 = FcToLower (c2);
177 if (c1 != c2)
d8d73958
KP
178 {
179 if (FcLangEnd (c1) && FcLangEnd (c2))
c833409f 180 result = FcLangDifferentTerritory;
d8d73958
KP
181 return result;
182 }
183 else if (!c1)
184 return FcLangEqual;
185 else if (c1 == '-')
c833409f 186 result = FcLangDifferentTerritory;
3de8881e 187 }
3de8881e
KP
188}
189
793e946c 190/*
594dcef0 191 * Return FcTrue when super contains sub.
793e946c 192 *
74a623e0
KP
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
793e946c
KP
196 */
197
198static FcBool
74a623e0 199FcLangContains (const FcChar8 *super, const FcChar8 *sub)
793e946c
KP
200{
201 FcChar8 c1, c2;
202
203 for (;;)
204 {
74a623e0
KP
205 c1 = *super++;
206 c2 = *sub++;
793e946c
KP
207
208 c1 = FcToLower (c1);
209 c2 = FcToLower (c2);
210 if (c1 != c2)
211 {
74a623e0 212 /* see if super has a country while sub is mising one */
793e946c
KP
213 if (c1 == '-' && c2 == '\0')
214 return FcTrue;
74a623e0
KP
215 /* see if sub has a country while super is mising one */
216 if (c1 == '\0' && c2 == '-')
217 return FcTrue;
793e946c
KP
218 return FcFalse;
219 }
220 else if (!c1)
221 return FcTrue;
222 }
223}
224
3de8881e 225const FcCharSet *
cf223cc7 226FcLangGetCharSet (const FcChar8 *lang)
3de8881e
KP
227{
228 int i;
229 int country = -1;
82f35f8b 230
3de8881e
KP
231 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
232 {
233 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
234 case FcLangEqual:
235 return &fcLangCharSets[i].charset;
c833409f 236 case FcLangDifferentTerritory:
3de8881e
KP
237 if (country == -1)
238 country = i;
1f4e6fec 239 case FcLangDifferentLang:
3de8881e
KP
240 default:
241 break;
242 }
243 }
244 if (country == -1)
245 return 0;
b36f2a39 246 return &fcLangCharSets[country].charset;
3de8881e 247}
d8d73958 248
cf223cc7
BE
249FcStrSet *
250FcGetLangs (void)
251{
252 FcStrSet *langs;
253 int i;
254
255 langs = FcStrSetCreate();
256 if (!langs)
257 return 0;
258
259 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
260 FcStrSetAdd (langs, fcLangCharSets[i].lang);
261
262 return langs;
263}
264
d8d73958
KP
265FcLangSet *
266FcLangSetCreate (void)
267{
268 FcLangSet *ls;
269
270 ls = malloc (sizeof (FcLangSet));
271 if (!ls)
272 return 0;
273 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
274 memset (ls->map, '\0', sizeof (ls->map));
1f4e6fec 275 ls->map_size = NUM_LANG_SET_MAP;
4262e0b3 276 ls->extra = 0;
d8d73958
KP
277 return ls;
278}
279
280void
281FcLangSetDestroy (FcLangSet *ls)
282{
4262e0b3
PL
283 if (ls->extra)
284 FcStrSetDestroy (ls->extra);
d8d73958
KP
285 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
286 free (ls);
287}
288
289FcLangSet *
290FcLangSetCopy (const FcLangSet *ls)
291{
292 FcLangSet *new;
293
294 new = FcLangSetCreate ();
295 if (!new)
296 goto bail0;
1f4e6fec
BE
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])));
4262e0b3 299 if (ls->extra)
d8d73958
KP
300 {
301 FcStrList *list;
302 FcChar8 *extra;
303
4262e0b3
PL
304 new->extra = FcStrSetCreate ();
305 if (!new->extra)
d8d73958
KP
306 goto bail1;
307
4262e0b3 308 list = FcStrListCreate (ls->extra);
d8d73958
KP
309 if (!list)
310 goto bail1;
311
312 while ((extra = FcStrListNext (list)))
4262e0b3 313 if (!FcStrSetAdd (new->extra, extra))
d8d73958
KP
314 {
315 FcStrListDone (list);
316 goto bail1;
317 }
318 FcStrListDone (list);
319 }
320 return new;
321bail1:
322 FcLangSetDestroy (new);
323bail0:
324 return 0;
325}
326
327static int
328FcLangSetIndex (const FcChar8 *lang)
329{
12d49d3c
CW
330 int low, high, mid = 0;
331 int cmp = 0;
594dcef0 332 FcChar8 firstChar = FcToLower(lang[0]);
947afeb5 333 FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
594dcef0 334
793e946c
KP
335 if (firstChar < 'a')
336 {
337 low = 0;
338 high = fcLangCharSetRanges[0].begin;
339 }
340 else if(firstChar > 'z')
341 {
342 low = fcLangCharSetRanges[25].begin;
343 high = NUM_LANG_CHAR_SET - 1;
344 }
345 else
346 {
347 low = fcLangCharSetRanges[firstChar - 'a'].begin;
348 high = fcLangCharSetRanges[firstChar - 'a'].end;
349 /* no matches */
350 if (low > high)
351 return -low; /* next entry after where it would be */
352 }
d8d73958 353
d8d73958
KP
354 while (low <= high)
355 {
356 mid = (high + low) >> 1;
793e946c
KP
357 if(fcLangCharSets[mid].lang[0] != firstChar)
358 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
359 else
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) */
947afeb5 362 cmp = fcLangCharSets[mid].lang[1] - secondChar;
594dcef0
BE
363 if (cmp == 0 &&
364 (fcLangCharSets[mid].lang[2] != '\0' ||
947afeb5 365 lang[2] != '\0'))
793e946c 366 {
594dcef0 367 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
947afeb5 368 lang+2);
793e946c 369 }
793e946c
KP
370 }
371 if (cmp == 0)
d8d73958
KP
372 return mid;
373 if (cmp < 0)
374 low = mid + 1;
375 else
376 high = mid - 1;
377 }
378 if (cmp < 0)
379 mid++;
380 return -(mid + 1);
381}
382
383FcBool
384FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
385{
386 int id;
387
388 id = FcLangSetIndex (lang);
389 if (id >= 0)
390 {
391 FcLangSetBitSet (ls, id);
392 return FcTrue;
393 }
4262e0b3 394 if (!ls->extra)
d8d73958 395 {
4262e0b3
PL
396 ls->extra = FcStrSetCreate ();
397 if (!ls->extra)
d8d73958
KP
398 return FcFalse;
399 }
4262e0b3 400 return FcStrSetAdd (ls->extra, lang);
d8d73958
KP
401}
402
403FcLangResult
404FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
405{
406 int id;
407 FcLangResult best, r;
408 int i;
409
410 id = FcLangSetIndex (lang);
2458a6d8
KP
411 if (id < 0)
412 id = -id - 1;
413 else if (FcLangSetBitGet (ls, id))
d8d73958 414 return FcLangEqual;
d8d73958
KP
415 best = FcLangDifferentLang;
416 for (i = id - 1; i >= 0; i--)
417 {
418 r = FcLangCompare (lang, fcLangCharSets[i].lang);
419 if (r == FcLangDifferentLang)
420 break;
421 if (FcLangSetBitGet (ls, i) && r < best)
422 best = r;
423 }
424 for (i = id; i < NUM_LANG_CHAR_SET; i++)
425 {
426 r = FcLangCompare (lang, fcLangCharSets[i].lang);
427 if (r == FcLangDifferentLang)
428 break;
429 if (FcLangSetBitGet (ls, i) && r < best)
430 best = r;
431 }
4262e0b3 432 if (ls->extra)
d8d73958 433 {
4262e0b3 434 FcStrList *list = FcStrListCreate (ls->extra);
d8d73958 435 FcChar8 *extra;
d8d73958
KP
436
437 if (list)
438 {
439 while (best > FcLangEqual && (extra = FcStrListNext (list)))
440 {
441 r = FcLangCompare (lang, extra);
442 if (r < best)
443 best = r;
444 }
445 FcStrListDone (list);
446 }
447 }
448 return best;
449}
450
451static FcLangResult
452FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
453{
454 FcStrList *list = FcStrListCreate (set);
455 FcLangResult r, best = FcLangDifferentLang;
456 FcChar8 *extra;
457
458 if (list)
459 {
460 while (best > FcLangEqual && (extra = FcStrListNext (list)))
461 {
462 r = FcLangSetHasLang (ls, extra);
463 if (r < best)
464 best = r;
465 }
466 FcStrListDone (list);
467 }
468 return best;
469}
470
471FcLangResult
472FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
473{
1f4e6fec 474 int i, j, count;
d8d73958
KP
475 FcLangResult best, r;
476
1f4e6fec
BE
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++)
d8d73958
KP
480 if (lsa->map[i] & lsb->map[i])
481 return FcLangEqual;
482 best = FcLangDifferentLang;
234397b4 483 for (j = 0; j < NUM_COUNTRY_SET; j++)
1f4e6fec 484 for (i = 0; i < count; i++)
234397b4
DD
485 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
486 (lsb->map[i] & fcLangCountrySets[j][i]))
487 {
c833409f 488 best = FcLangDifferentTerritory;
234397b4
DD
489 break;
490 }
4262e0b3 491 if (lsa->extra)
d8d73958 492 {
4262e0b3 493 r = FcLangSetCompareStrSet (lsb, lsa->extra);
d8d73958
KP
494 if (r < best)
495 best = r;
496 }
4262e0b3 497 if (best > FcLangEqual && lsb->extra)
d8d73958 498 {
4262e0b3 499 r = FcLangSetCompareStrSet (lsa, lsb->extra);
d8d73958
KP
500 if (r < best)
501 best = r;
502 }
503 return best;
504}
505
506/*
507 * Used in computing values -- mustn't allocate any storage
0d47cfab 508 * XXX Not thread-safe
d8d73958
KP
509 */
510FcLangSet *
511FcLangSetPromote (const FcChar8 *lang)
512{
513 static FcLangSet ls;
514 static FcStrSet strs;
515 static FcChar8 *str;
516 int id;
517
518 memset (ls.map, '\0', sizeof (ls.map));
0d47cfab 519 ls.map_size = NUM_LANG_SET_MAP;
4262e0b3 520 ls.extra = 0;
d8d73958
KP
521 id = FcLangSetIndex (lang);
522 if (id > 0)
523 {
524 FcLangSetBitSet (&ls, id);
525 }
526 else
527 {
4262e0b3 528 ls.extra = &strs;
d8d73958
KP
529 strs.num = 1;
530 strs.size = 1;
4262e0b3 531 strs.strs = &str;
47d4f950 532 strs.ref = 1;
d8d73958
KP
533 str = (FcChar8 *) lang;
534 }
535 return &ls;
536}
537
538FcChar32
539FcLangSetHash (const FcLangSet *ls)
540{
541 FcChar32 h = 0;
a3b24268 542 int i, count;
d8d73958 543
a3b24268
BE
544 count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
545 for (i = 0; i < count; i++)
d8d73958 546 h ^= ls->map[i];
4262e0b3
PL
547 if (ls->extra)
548 h ^= ls->extra->num;
d8d73958
KP
549 return h;
550}
551
552FcLangSet *
553FcNameParseLangSet (const FcChar8 *string)
554{
1f4e6fec 555 FcChar8 lang[32], c = 0;
793e946c 556 int i;
d8d73958
KP
557 FcLangSet *ls;
558
559 ls = FcLangSetCreate ();
560 if (!ls)
561 goto bail0;
562
793e946c 563 for(;;)
d8d73958 564 {
793e946c 565 for(i = 0; i < 31;i++)
d8d73958 566 {
793e946c
KP
567 c = *string++;
568 if(c == '\0' || c == '|')
569 break; /* end of this code */
570 lang[i] = c;
d8d73958 571 }
793e946c
KP
572 lang[i] = '\0';
573 if (!FcLangSetAdd (ls, lang))
574 goto bail1;
575 if(c == '\0')
576 break;
d8d73958
KP
577 }
578 return ls;
579bail1:
580 FcLangSetDestroy (ls);
581bail0:
582 return 0;
583}
584
585FcBool
586FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
587{
1f4e6fec 588 int i, bit, count;
c5f0a65b 589 FcChar32 bits;
d8d73958
KP
590 FcBool first = FcTrue;
591
1f4e6fec
BE
592 count = FC_MIN (ls->map_size, NUM_LANG_SET_MAP);
593 for (i = 0; i < count; i++)
c5f0a65b
BE
594 {
595 if ((bits = ls->map[i]))
596 {
597 for (bit = 0; bit <= 31; bit++)
598 if (bits & (1 << bit))
599 {
600 int id = (i << 5) | bit;
601 if (!first)
602 if (!FcStrBufChar (buf, '|'))
603 return FcFalse;
604 if (!FcStrBufString (buf, fcLangCharSets[fcLangCharSetIndicesInv[id]].lang))
d8d73958 605 return FcFalse;
c5f0a65b
BE
606 first = FcFalse;
607 }
608 }
609 }
4262e0b3 610 if (ls->extra)
d8d73958 611 {
4262e0b3 612 FcStrList *list = FcStrListCreate (ls->extra);
d8d73958
KP
613 FcChar8 *extra;
614
615 if (!list)
616 return FcFalse;
617 while ((extra = FcStrListNext (list)))
618 {
619 if (!first)
620 if (!FcStrBufChar (buf, '|'))
04f7d3e7
PL
621 {
622 FcStrListDone (list);
d8d73958 623 return FcFalse;
04f7d3e7 624 }
793e946c 625 if (!FcStrBufString (buf, extra))
04f7d3e7
PL
626 {
627 FcStrListDone (list);
628 return FcFalse;
629 }
d8d73958
KP
630 first = FcFalse;
631 }
2de24638 632 FcStrListDone (list);
d8d73958
KP
633 }
634 return FcTrue;
635}
636
637FcBool
638FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
639{
1f4e6fec 640 int i, count;
d8d73958 641
1f4e6fec
BE
642 count = FC_MIN (lsa->map_size, lsb->map_size);
643 count = FC_MIN (NUM_LANG_SET_MAP, count);
644 for (i = 0; i < count; i++)
d8d73958
KP
645 {
646 if (lsa->map[i] != lsb->map[i])
647 return FcFalse;
648 }
4262e0b3 649 if (!lsa->extra && !lsb->extra)
d8d73958 650 return FcTrue;
4262e0b3
PL
651 if (lsa->extra && lsb->extra)
652 return FcStrSetEqual (lsa->extra, lsb->extra);
d8d73958
KP
653 return FcFalse;
654}
793e946c
KP
655
656static FcBool
657FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
658{
659 int id;
793e946c
KP
660 int i;
661
662 id = FcLangSetIndex (lang);
663 if (id < 0)
664 id = -id - 1;
665 else if (FcLangSetBitGet (ls, id))
666 return FcTrue;
667 /*
668 * search up and down among equal languages for a match
669 */
670 for (i = id - 1; i >= 0; i--)
671 {
672 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
673 break;
674 if (FcLangSetBitGet (ls, i) &&
675 FcLangContains (fcLangCharSets[i].lang, lang))
676 return FcTrue;
677 }
678 for (i = id; i < NUM_LANG_CHAR_SET; i++)
679 {
680 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
681 break;
682 if (FcLangSetBitGet (ls, i) &&
683 FcLangContains (fcLangCharSets[i].lang, lang))
684 return FcTrue;
685 }
4262e0b3 686 if (ls->extra)
793e946c 687 {
4262e0b3 688 FcStrList *list = FcStrListCreate (ls->extra);
793e946c 689 FcChar8 *extra;
793e946c
KP
690
691 if (list)
692 {
693 while ((extra = FcStrListNext (list)))
694 {
695 if (FcLangContains (extra, lang))
696 break;
697 }
698 FcStrListDone (list);
699 if (extra)
700 return FcTrue;
701 }
702 }
703 return FcFalse;
704}
705
706/*
707 * return FcTrue if lsa contains every language in lsb
708 */
709FcBool
710FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
711{
1f4e6fec 712 int i, j, count;
793e946c
KP
713 FcChar32 missing;
714
715 if (FcDebug() & FC_DBG_MATCHV)
716 {
717 printf ("FcLangSet "); FcLangSetPrint (lsa);
718 printf (" contains "); FcLangSetPrint (lsb);
719 printf ("\n");
720 }
721 /*
722 * check bitmaps for missing language support
723 */
1f4e6fec
BE
724 count = FC_MIN (lsa->map_size, lsb->map_size);
725 count = FC_MIN (NUM_LANG_SET_MAP, count);
726 for (i = 0; i < count; i++)
793e946c
KP
727 {
728 missing = lsb->map[i] & ~lsa->map[i];
729 if (missing)
730 {
731 for (j = 0; j < 32; j++)
594dcef0 732 if (missing & (1 << j))
793e946c
KP
733 {
734 if (!FcLangSetContainsLang (lsa,
d354a321 735 fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang))
793e946c
KP
736 {
737 if (FcDebug() & FC_DBG_MATCHV)
d354a321 738 printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[i*32+j]].lang);
793e946c
KP
739 return FcFalse;
740 }
741 }
742 }
743 }
4262e0b3 744 if (lsb->extra)
793e946c 745 {
4262e0b3 746 FcStrList *list = FcStrListCreate (lsb->extra);
793e946c
KP
747 FcChar8 *extra;
748
749 if (list)
750 {
751 while ((extra = FcStrListNext (list)))
752 {
753 if (!FcLangSetContainsLang (lsa, extra))
754 {
755 if (FcDebug() & FC_DBG_MATCHV)
756 printf ("\tMissing string %s\n", extra);
757 break;
758 }
759 }
760 FcStrListDone (list);
761 if (extra)
762 return FcFalse;
763 }
764 }
765 return FcTrue;
766}
cd2ec1a9 767
7ce19673
KP
768FcBool
769FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l)
cd2ec1a9 770{
7ce19673
KP
771 if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet)))
772 return FcFalse;
4262e0b3 773 return FcTrue;
cd2ec1a9 774}
212c9f43 775
4262e0b3 776FcLangSet *
7ce19673 777FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l)
4262e0b3 778{
7ce19673 779 FcLangSet *l_serialize = FcSerializePtr (serialize, l);
4262e0b3 780
7ce19673
KP
781 if (!l_serialize)
782 return NULL;
a3b24268
BE
783 memset (l_serialize->map, '\0', sizeof (l_serialize->map));
784 memcpy (l_serialize->map, l->map, FC_MIN (sizeof (l_serialize->map), l->map_size * sizeof (l->map[0])));
785 l_serialize->map_size = NUM_LANG_SET_MAP;
1f4e6fec 786 l_serialize->extra = NULL; /* We don't serialize ls->extra */
7ce19673 787 return l_serialize;
212c9f43 788}
d62b85af
BE
789
790FcStrSet *
791FcLangSetGetLangs (const FcLangSet *ls)
792{
793 FcStrSet *langs;
794 int i;
795
796 langs = FcStrSetCreate();
797 if (!langs)
798 return 0;
799
800 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
801 if (FcLangSetBitGet (ls, i))
802 FcStrSetAdd (langs, fcLangCharSets[i].lang);
803
804 if (ls->extra)
805 {
806 FcStrList *list = FcStrListCreate (ls->extra);
807 FcChar8 *extra;
808
809 if (list)
810 {
811 while ((extra = FcStrListNext (list)))
812 FcStrSetAdd (langs, extra);
813
814 FcStrListDone (list);
815 }
816 }
817
818 return langs;
819}
820
23816bf9
KP
821#define __fclang__
822#include "fcaliastail.h"
a0a1da22 823#include "fcftaliastail.h"
23816bf9 824#undef __fclang__