]> git.wh0rd.org - fontconfig.git/blob - src/fclang.c
Add contains/not_contains, fix LangSet equal operator to use FcLangEqual
[fontconfig.git] / src / fclang.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fclang.c,v 1.4 2002/07/12 21:06:03 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 return FcLangEqual;
280 id = -id - 1;
281 best = FcLangDifferentLang;
282 for (i = id - 1; i >= 0; i--)
283 {
284 r = FcLangCompare (lang, fcLangCharSets[i].lang);
285 if (r == FcLangDifferentLang)
286 break;
287 if (FcLangSetBitGet (ls, i) && r < best)
288 best = r;
289 }
290 for (i = id; i < NUM_LANG_CHAR_SET; i++)
291 {
292 r = FcLangCompare (lang, fcLangCharSets[i].lang);
293 if (r == FcLangDifferentLang)
294 break;
295 if (FcLangSetBitGet (ls, i) && r < best)
296 best = r;
297 }
298 if (ls->extra)
299 {
300 FcStrList *list = FcStrListCreate (ls->extra);
301 FcChar8 *extra;
302 FcLangResult r;
303
304 if (list)
305 {
306 while (best > FcLangEqual && (extra = FcStrListNext (list)))
307 {
308 r = FcLangCompare (lang, extra);
309 if (r < best)
310 best = r;
311 }
312 FcStrListDone (list);
313 }
314 }
315 return best;
316 }
317
318 static FcLangResult
319 FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
320 {
321 FcStrList *list = FcStrListCreate (set);
322 FcLangResult r, best = FcLangDifferentLang;
323 FcChar8 *extra;
324
325 if (list)
326 {
327 while (best > FcLangEqual && (extra = FcStrListNext (list)))
328 {
329 r = FcLangSetHasLang (ls, extra);
330 if (r < best)
331 best = r;
332 }
333 FcStrListDone (list);
334 }
335 return best;
336 }
337
338 FcLangResult
339 FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
340 {
341 int i;
342 FcLangResult best, r;
343
344 for (i = 0; i < NUM_LANG_SET_MAP; i++)
345 if (lsa->map[i] & lsb->map[i])
346 return FcLangEqual;
347 best = FcLangDifferentLang;
348 if (lsa->extra)
349 {
350 r = FcLangSetCompareStrSet (lsb, lsa->extra);
351 if (r < best)
352 best = r;
353 }
354 if (best > FcLangEqual && lsb->extra)
355 {
356 r = FcLangSetCompareStrSet (lsa, lsb->extra);
357 if (r < best)
358 best = r;
359 }
360 return best;
361 }
362
363 /*
364 * Used in computing values -- mustn't allocate any storage
365 */
366 FcLangSet *
367 FcLangSetPromote (const FcChar8 *lang)
368 {
369 static FcLangSet ls;
370 static FcStrSet strs;
371 static FcChar8 *str;
372 int id;
373
374 memset (ls.map, '\0', sizeof (ls.map));
375 ls.extra = 0;
376 id = FcLangSetIndex (lang);
377 if (id > 0)
378 {
379 FcLangSetBitSet (&ls, id);
380 }
381 else
382 {
383 ls.extra = &strs;
384 strs.num = 1;
385 strs.size = 1;
386 strs.strs = &str;
387 strs.ref = 1;
388 str = (FcChar8 *) lang;
389 }
390 return &ls;
391 }
392
393 FcChar32
394 FcLangSetHash (const FcLangSet *ls)
395 {
396 FcChar32 h = 0;
397 int i;
398
399 for (i = 0; i < NUM_LANG_SET_MAP; i++)
400 h ^= ls->map[i];
401 if (ls->extra)
402 h ^= ls->extra->num;
403 return h;
404 }
405
406 FcLangSet *
407 FcNameParseLangSet (const FcChar8 *string)
408 {
409 FcChar8 lang[32];
410 const FcChar8 *end, *next;
411 FcLangSet *ls;
412
413 ls = FcLangSetCreate ();
414 if (!ls)
415 goto bail0;
416
417 while (string && *string)
418 {
419 end = (FcChar8 *) strchr ((char *) string, '|');
420 if (!end)
421 {
422 end = string + strlen ((char *) string);
423 next = end;
424 }
425 else
426 next = end + 1;
427 if (end - string < sizeof (lang) - 1)
428 {
429 strncpy ((char *) lang, (char *) string, end - string);
430 lang[end-string] = '\0';
431 if (!FcLangSetAdd (ls, lang))
432 goto bail1;
433 }
434 string = next;
435 }
436 return ls;
437 bail1:
438 FcLangSetDestroy (ls);
439 bail0:
440 return 0;
441 }
442
443 FcBool
444 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
445 {
446 int i, bit;
447 FcChar32 bits;
448 FcBool first = FcTrue;
449
450 for (i = 0; i < NUM_LANG_SET_MAP; i++)
451 {
452 if ((bits = ls->map[i]))
453 {
454 for (bit = 0; bit <= 31; bit++)
455 if (bits & (1 << bit))
456 {
457 int id = (i << 5) | bit;
458 if (!first)
459 if (!FcStrBufChar (buf, '|'))
460 return FcFalse;
461 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
462 return FcFalse;
463 first = FcFalse;
464 }
465 }
466 }
467 if (ls->extra)
468 {
469 FcStrList *list = FcStrListCreate (ls->extra);
470 FcChar8 *extra;
471
472 if (!list)
473 return FcFalse;
474 while ((extra = FcStrListNext (list)))
475 {
476 if (!first)
477 if (!FcStrBufChar (buf, '|'))
478 return FcFalse;
479 if (!FcStrBufString (buf, extra));
480 return FcFalse;
481 first = FcFalse;
482 }
483 }
484 return FcTrue;
485 }
486
487 FcBool
488 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
489 {
490 int i;
491
492 for (i = 0; i < NUM_LANG_SET_MAP; i++)
493 {
494 if (lsa->map[i] != lsb->map[i])
495 return FcFalse;
496 }
497 if (!lsa->extra && !lsb->extra)
498 return FcTrue;
499 if (lsa->extra && lsb->extra)
500 return FcStrSetEqual (lsa->extra, lsb->extra);
501 return FcFalse;
502 }