]> git.wh0rd.org - fontconfig.git/blob - src/fclang.c
FcLangSetHasLang was not actually checking the language set itself
[fontconfig.git] / src / fclang.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fclang.c,v 1.6 2002/08/22 18:53:22 keithp Exp $
3 *
4 * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
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
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.
15 *
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.
23 */
24
25 #include "fcint.h"
26
27 typedef struct {
28 FcChar8 *lang;
29 FcCharSet charset;
30 } FcLangCharSet;
31
32 #include "../fc-lang/fclang.h"
33
34 #define NUM_LANG_CHAR_SET (sizeof (fcLangCharSets) / sizeof (fcLangCharSets[0]))
35 #define NUM_LANG_SET_MAP ((NUM_LANG_CHAR_SET + 31) / 32)
36
37 struct _FcLangSet {
38 FcChar32 map[NUM_LANG_SET_MAP];
39 FcStrSet *extra;
40 };
41
42 #define FcLangSetBitSet(ls, id) ((ls)->map[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
43 #define FcLangSetBitGet(ls, id) (((ls)->map[(id)>>5] >> ((id) & 0x1f)) & 1)
44
45 FcLangSet *
46 FcFreeTypeLangSet (const FcCharSet *charset,
47 const FcChar8 *exclusiveLang)
48 {
49 int i;
50 FcChar32 missing;
51 const FcCharSet *exclusiveCharset = 0;
52 FcLangSet *ls;
53
54
55 if (exclusiveLang)
56 exclusiveCharset = FcCharSetForLang (exclusiveLang);
57 ls = FcLangSetCreate ();
58 if (!ls)
59 return 0;
60 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
61 {
62 /*
63 * Check for Han charsets to make fonts
64 * which advertise support for a single language
65 * not support other Han languages
66 */
67 if (exclusiveCharset &&
68 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang) &&
69 fcLangCharSets[i].charset.leaves != exclusiveCharset->leaves)
70 {
71 continue;
72 }
73 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
74 if (FcDebug() & FC_DBG_SCANV)
75 {
76 if (missing && missing < 10)
77 {
78 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
79 charset);
80 FcChar32 ucs4;
81 FcChar32 map[FC_CHARSET_MAP_SIZE];
82 FcChar32 next;
83
84 printf ("\n%s(%d) ", fcLangCharSets[i].lang, missing);
85 printf ("{");
86 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
87 ucs4 != FC_CHARSET_DONE;
88 ucs4 = FcCharSetNextPage (missed, map, &next))
89 {
90 int i, j;
91 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
92 if (map[i])
93 {
94 for (j = 0; j < 32; j++)
95 if (map[i] & (1 << j))
96 printf (" %04x", ucs4 + i * 32 + j);
97 }
98 }
99 printf (" }\n\t");
100 FcCharSetDestroy (missed);
101 }
102 else
103 printf ("%s(%d) ", fcLangCharSets[i].lang, missing);
104 }
105 if (!missing)
106 FcLangSetBitSet (ls, i);
107 }
108
109 if (FcDebug() & FC_DBG_SCANV)
110 printf ("\n");
111
112
113 return ls;
114 }
115
116 #define FcLangEnd(c) ((c) == '-' || (c) == '\0')
117
118 FcLangResult
119 FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
120 {
121 FcChar8 c1, c2;
122 FcLangResult result = FcLangDifferentLang;
123
124 for (;;)
125 {
126 c1 = *s1++;
127 c2 = *s2++;
128
129 c1 = FcToLower (c1);
130 c2 = FcToLower (c2);
131 if (c1 != c2)
132 {
133 if (FcLangEnd (c1) && FcLangEnd (c2))
134 result = FcLangDifferentCountry;
135 return result;
136 }
137 else if (!c1)
138 return FcLangEqual;
139 else if (c1 == '-')
140 result = FcLangDifferentCountry;
141 }
142 }
143
144 const FcCharSet *
145 FcCharSetForLang (const FcChar8 *lang)
146 {
147 int i;
148 int country = -1;
149 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
150 {
151 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
152 case FcLangEqual:
153 return &fcLangCharSets[i].charset;
154 case FcLangDifferentCountry:
155 if (country == -1)
156 country = i;
157 default:
158 break;
159 }
160 }
161 if (country == -1)
162 return 0;
163 return &fcLangCharSets[i].charset;
164 }
165
166 FcLangSet *
167 FcLangSetCreate (void)
168 {
169 FcLangSet *ls;
170
171 ls = malloc (sizeof (FcLangSet));
172 if (!ls)
173 return 0;
174 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
175 memset (ls->map, '\0', sizeof (ls->map));
176 ls->extra = 0;
177 return ls;
178 }
179
180 void
181 FcLangSetDestroy (FcLangSet *ls)
182 {
183 if (ls->extra)
184 FcStrSetDestroy (ls->extra);
185 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
186 free (ls);
187 }
188
189 FcLangSet *
190 FcLangSetCopy (const FcLangSet *ls)
191 {
192 FcLangSet *new;
193
194 new = FcLangSetCreate ();
195 if (!new)
196 goto bail0;
197 memcpy (new->map, ls->map, sizeof (new->map));
198 if (ls->extra)
199 {
200 FcStrList *list;
201 FcChar8 *extra;
202
203 new->extra = FcStrSetCreate ();
204 if (!new->extra)
205 goto bail1;
206
207 list = FcStrListCreate (ls->extra);
208 if (!list)
209 goto bail1;
210
211 while ((extra = FcStrListNext (list)))
212 if (!FcStrSetAdd (new->extra, extra))
213 {
214 FcStrListDone (list);
215 goto bail1;
216 }
217 FcStrListDone (list);
218 }
219 return new;
220 bail1:
221 FcLangSetDestroy (new);
222 bail0:
223 return 0;
224 }
225
226 static int
227 FcLangSetIndex (const FcChar8 *lang)
228 {
229 int low, high, mid;
230 int cmp;
231
232 low = 0;
233 high = NUM_LANG_CHAR_SET - 1;
234 while (low <= high)
235 {
236 mid = (high + low) >> 1;
237 cmp = FcStrCmpIgnoreCase (fcLangCharSets[mid].lang, lang);
238 if (cmp == 0)
239 return mid;
240 if (cmp < 0)
241 low = mid + 1;
242 else
243 high = mid - 1;
244 }
245 if (cmp < 0)
246 mid++;
247 return -(mid + 1);
248 }
249
250 FcBool
251 FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
252 {
253 int id;
254
255 id = FcLangSetIndex (lang);
256 if (id >= 0)
257 {
258 FcLangSetBitSet (ls, id);
259 return FcTrue;
260 }
261 if (!ls->extra)
262 {
263 ls->extra = FcStrSetCreate ();
264 if (!ls->extra)
265 return FcFalse;
266 }
267 return FcStrSetAdd (ls->extra, lang);
268 }
269
270 FcLangResult
271 FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
272 {
273 int id;
274 FcLangResult best, r;
275 int i;
276
277 id = FcLangSetIndex (lang);
278 if (id < 0)
279 id = -id - 1;
280 else if (FcLangSetBitGet (ls, id))
281 return FcLangEqual;
282 best = FcLangDifferentLang;
283 for (i = id - 1; i >= 0; i--)
284 {
285 r = FcLangCompare (lang, fcLangCharSets[i].lang);
286 if (r == FcLangDifferentLang)
287 break;
288 if (FcLangSetBitGet (ls, i) && r < best)
289 best = r;
290 }
291 for (i = id; i < NUM_LANG_CHAR_SET; i++)
292 {
293 r = FcLangCompare (lang, fcLangCharSets[i].lang);
294 if (r == FcLangDifferentLang)
295 break;
296 if (FcLangSetBitGet (ls, i) && r < best)
297 best = r;
298 }
299 if (ls->extra)
300 {
301 FcStrList *list = FcStrListCreate (ls->extra);
302 FcChar8 *extra;
303 FcLangResult r;
304
305 if (list)
306 {
307 while (best > FcLangEqual && (extra = FcStrListNext (list)))
308 {
309 r = FcLangCompare (lang, extra);
310 if (r < best)
311 best = r;
312 }
313 FcStrListDone (list);
314 }
315 }
316 return best;
317 }
318
319 static FcLangResult
320 FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
321 {
322 FcStrList *list = FcStrListCreate (set);
323 FcLangResult r, best = FcLangDifferentLang;
324 FcChar8 *extra;
325
326 if (list)
327 {
328 while (best > FcLangEqual && (extra = FcStrListNext (list)))
329 {
330 r = FcLangSetHasLang (ls, extra);
331 if (r < best)
332 best = r;
333 }
334 FcStrListDone (list);
335 }
336 return best;
337 }
338
339 FcLangResult
340 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
341 {
342 int i;
343 FcLangResult best, r;
344
345 for (i = 0; i < NUM_LANG_SET_MAP; i++)
346 if (lsa->map[i] & lsb->map[i])
347 return FcLangEqual;
348 best = FcLangDifferentLang;
349 if (lsa->extra)
350 {
351 r = FcLangSetCompareStrSet (lsb, lsa->extra);
352 if (r < best)
353 best = r;
354 }
355 if (best > FcLangEqual && lsb->extra)
356 {
357 r = FcLangSetCompareStrSet (lsa, lsb->extra);
358 if (r < best)
359 best = r;
360 }
361 return best;
362 }
363
364 /*
365 * Used in computing values -- mustn't allocate any storage
366 */
367 FcLangSet *
368 FcLangSetPromote (const FcChar8 *lang)
369 {
370 static FcLangSet ls;
371 static FcStrSet strs;
372 static FcChar8 *str;
373 int id;
374
375 memset (ls.map, '\0', sizeof (ls.map));
376 ls.extra = 0;
377 id = FcLangSetIndex (lang);
378 if (id > 0)
379 {
380 FcLangSetBitSet (&ls, id);
381 }
382 else
383 {
384 ls.extra = &strs;
385 strs.num = 1;
386 strs.size = 1;
387 strs.strs = &str;
388 strs.ref = 1;
389 str = (FcChar8 *) lang;
390 }
391 return &ls;
392 }
393
394 FcChar32
395 FcLangSetHash (const FcLangSet *ls)
396 {
397 FcChar32 h = 0;
398 int i;
399
400 for (i = 0; i < NUM_LANG_SET_MAP; i++)
401 h ^= ls->map[i];
402 if (ls->extra)
403 h ^= ls->extra->num;
404 return h;
405 }
406
407 FcLangSet *
408 FcNameParseLangSet (const FcChar8 *string)
409 {
410 FcChar8 lang[32];
411 const FcChar8 *end, *next;
412 FcLangSet *ls;
413
414 ls = FcLangSetCreate ();
415 if (!ls)
416 goto bail0;
417
418 while (string && *string)
419 {
420 end = (FcChar8 *) strchr ((char *) string, '|');
421 if (!end)
422 {
423 end = string + strlen ((char *) string);
424 next = end;
425 }
426 else
427 next = end + 1;
428 if (end - string < sizeof (lang) - 1)
429 {
430 strncpy ((char *) lang, (char *) string, end - string);
431 lang[end-string] = '\0';
432 if (!FcLangSetAdd (ls, lang))
433 goto bail1;
434 }
435 string = next;
436 }
437 return ls;
438 bail1:
439 FcLangSetDestroy (ls);
440 bail0:
441 return 0;
442 }
443
444 FcBool
445 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
446 {
447 int i, bit;
448 FcChar32 bits;
449 FcBool first = FcTrue;
450
451 for (i = 0; i < NUM_LANG_SET_MAP; i++)
452 {
453 if ((bits = ls->map[i]))
454 {
455 for (bit = 0; bit <= 31; bit++)
456 if (bits & (1 << bit))
457 {
458 int id = (i << 5) | bit;
459 if (!first)
460 if (!FcStrBufChar (buf, '|'))
461 return FcFalse;
462 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
463 return FcFalse;
464 first = FcFalse;
465 }
466 }
467 }
468 if (ls->extra)
469 {
470 FcStrList *list = FcStrListCreate (ls->extra);
471 FcChar8 *extra;
472
473 if (!list)
474 return FcFalse;
475 while ((extra = FcStrListNext (list)))
476 {
477 if (!first)
478 if (!FcStrBufChar (buf, '|'))
479 return FcFalse;
480 if (!FcStrBufString (buf, extra));
481 return FcFalse;
482 first = FcFalse;
483 }
484 }
485 return FcTrue;
486 }
487
488 FcBool
489 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
490 {
491 int i;
492
493 for (i = 0; i < NUM_LANG_SET_MAP; i++)
494 {
495 if (lsa->map[i] != lsb->map[i])
496 return FcFalse;
497 }
498 if (!lsa->extra && !lsb->extra)
499 return FcTrue;
500 if (lsa->extra && lsb->extra)
501 return FcStrSetEqual (lsa->extra, lsb->extra);
502 return FcFalse;
503 }