]> git.wh0rd.org - fontconfig.git/blob - src/fclang.c
Reimplement FC_LANG as FcTypeLang, freeze patterns, other cleanup
[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 str = (FcChar8 *) lang;
388 }
389 return &ls;
390 }
391
392 FcChar32
393 FcLangSetHash (const FcLangSet *ls)
394 {
395 FcChar32 h = 0;
396 int i;
397
398 for (i = 0; i < NUM_LANG_SET_MAP; i++)
399 h ^= ls->map[i];
400 if (ls->extra)
401 h ^= ls->extra->num;
402 return h;
403 }
404
405 FcLangSet *
406 FcNameParseLangSet (const FcChar8 *string)
407 {
408 FcChar8 lang[32];
409 const FcChar8 *end, *next;
410 FcLangSet *ls;
411
412 ls = FcLangSetCreate ();
413 if (!ls)
414 goto bail0;
415
416 while (string && *string)
417 {
418 end = (FcChar8 *) strchr ((char *) string, '|');
419 if (!end)
420 {
421 end = string + strlen ((char *) string);
422 next = end;
423 }
424 else
425 next = end + 1;
426 if (end - string < sizeof (lang) - 1)
427 {
428 strncpy ((char *) lang, (char *) string, end - string);
429 lang[end-string] = '\0';
430 if (!FcLangSetAdd (ls, lang))
431 goto bail1;
432 }
433 string = next;
434 }
435 return ls;
436 bail1:
437 FcLangSetDestroy (ls);
438 bail0:
439 return 0;
440 }
441
442 FcBool
443 FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
444 {
445 int i, bit;
446 FcChar32 bits;
447 FcBool first = FcTrue;
448
449 for (i = 0; i < NUM_LANG_SET_MAP; i++)
450 {
451 if ((bits = ls->map[i]))
452 {
453 for (bit = 0; bit <= 31; bit++)
454 if (bits & (1 << bit))
455 {
456 int id = (i << 5) | bit;
457 if (!first)
458 if (!FcStrBufChar (buf, '|'))
459 return FcFalse;
460 if (!FcStrBufString (buf, fcLangCharSets[id].lang))
461 return FcFalse;
462 first = FcFalse;
463 }
464 }
465 }
466 if (ls->extra)
467 {
468 FcStrList *list = FcStrListCreate (ls->extra);
469 FcChar8 *extra;
470
471 if (!list)
472 return FcFalse;
473 while ((extra = FcStrListNext (list)))
474 {
475 if (!first)
476 if (!FcStrBufChar (buf, '|'))
477 return FcFalse;
478 if (!FcStrBufString (buf, extra));
479 return FcFalse;
480 first = FcFalse;
481 }
482 }
483 return FcTrue;
484 }
485
486 FcBool
487 FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
488 {
489 int i;
490
491 for (i = 0; i < NUM_LANG_SET_MAP; i++)
492 {
493 if (lsa->map[i] != lsb->map[i])
494 return FcFalse;
495 }
496 if (!lsa->extra && !lsb->extra)
497 return FcTrue;
498 if (lsa->extra && lsb->extra)
499 return FcStrSetEqual (lsa->extra, lsb->extra);
500 return FcFalse;
501 }