]> git.wh0rd.org - fontconfig.git/blame - src/fccharset.c
[charset] Grow internal FcCharset arrays exponentially
[fontconfig.git] / src / fccharset.c
CommitLineData
24330d27 1/*
317b8492 2 * fontconfig/src/fccharset.c
24330d27 3 *
46b51147 4 * Copyright © 2001 Keith Packard
24330d27
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
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 *
3074a73b 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24330d27 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
24330d27
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
24330d27 25#include "fcint.h"
f045376c 26#include <stdlib.h>
24330d27
KP
27
28/* #define CHECK */
29
24330d27
KP
30FcCharSet *
31FcCharSetCreate (void)
32{
33 FcCharSet *fcs;
34
35 fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
36 if (!fcs)
37 return 0;
38 FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
39 fcs->ref = 1;
20ac65ab 40 fcs->num = 0;
bc5e487f
KP
41 fcs->leaves_offset = 0;
42 fcs->numbers_offset = 0;
24330d27
KP
43 return fcs;
44}
45
24330d27
KP
46FcCharSet *
47FcCharSetNew (void)
48{
49 return FcCharSetCreate ();
50}
51
24330d27
KP
52void
53FcCharSetDestroy (FcCharSet *fcs)
54{
d8d73958 55 int i;
7ce19673 56
d8d73958 57 if (fcs->ref == FC_REF_CONSTANT)
9e612141
KP
58 {
59 FcCacheObjectDereference (fcs);
d8d73958 60 return;
9e612141 61 }
d8d73958
KP
62 if (--fcs->ref > 0)
63 return;
7ce19673 64 for (i = 0; i < fcs->num; i++)
d8d73958 65 {
7ce19673
KP
66 FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
67 free (FcCharSetLeaf (fcs, i));
68 }
bc5e487f 69 if (fcs->num)
7ce19673 70 {
900723f3 71 /* the numbers here are estimates */
7ce19673
KP
72 FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (intptr_t));
73 free (FcCharSetLeaves (fcs));
7ce19673
KP
74 FcMemFree (FC_MEM_CHARSET, fcs->num * sizeof (FcChar16));
75 free (FcCharSetNumbers (fcs));
d8d73958
KP
76 }
77 FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
78 free (fcs);
24330d27
KP
79}
80
81/*
575ee6cd
KT
82 * Search for the leaf containing with the specified num.
83 * Return its index if it exists, otherwise return negative of
20ac65ab 84 * the (position + 1) where it should be inserted
24330d27
KP
85 */
86
575ee6cd 87
20ac65ab 88static int
575ee6cd 89FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num)
20ac65ab 90{
7ce19673 91 FcChar16 *numbers = FcCharSetNumbers(fcs);
20ac65ab 92 FcChar16 page;
575ee6cd 93 int low = start;
20ac65ab
KP
94 int high = fcs->num - 1;
95
96 if (!numbers)
97 return -1;
20ac65ab
KP
98 while (low <= high)
99 {
100 int mid = (low + high) >> 1;
101 page = numbers[mid];
575ee6cd 102 if (page == num)
20ac65ab 103 return mid;
575ee6cd 104 if (page < num)
20ac65ab
KP
105 low = mid + 1;
106 else
107 high = mid - 1;
108 }
575ee6cd 109 if (high < 0 || (high < fcs->num && numbers[high] < num))
20ac65ab
KP
110 high++;
111 return -(high + 1);
112}
113
575ee6cd
KT
114/*
115 * Locate the leaf containing the specified char, return
116 * its index if it exists, otherwise return negative of
117 * the (position + 1) where it should be inserted
118 */
119
120static int
121FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
122{
123 return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
124}
125
24330d27
KP
126static FcCharLeaf *
127FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
128{
20ac65ab
KP
129 int pos = FcCharSetFindLeafPos (fcs, ucs4);
130 if (pos >= 0)
7ce19673 131 return FcCharSetLeaf(fcs, pos);
20ac65ab
KP
132 return 0;
133}
24330d27 134
900723f3
BE
135#define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
136
20ac65ab
KP
137static FcBool
138FcCharSetPutLeaf (FcCharSet *fcs,
139 FcChar32 ucs4,
140 FcCharLeaf *leaf,
141 int pos)
142{
7ce19673
KP
143 intptr_t *leaves = FcCharSetLeaves (fcs);
144 FcChar16 *numbers = FcCharSetNumbers (fcs);
20ac65ab
KP
145
146 ucs4 >>= 8;
900723f3 147 /* XXX We can't handle Unicode values in Plane 16 */
20ac65ab
KP
148 if (ucs4 >= 0x10000)
149 return FcFalse;
86bdf459 150
900723f3 151 if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
cd2ec1a9 152 {
900723f3
BE
153 if (!fcs->num)
154 {
155 unsigned int alloced = 8;
156 leaves = malloc (alloced * sizeof (*leaves));
157 numbers = malloc (alloced * sizeof (*numbers));
158 FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
159 FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
160 }
161 else
162 {
163 unsigned int alloced = fcs->num;
164 intptr_t *new_leaves, distance;
165
166 FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*leaves));
167 FcMemFree (FC_MEM_CHARSET, alloced * sizeof (*numbers));
168
169 alloced *= 2;
170 new_leaves = realloc (leaves, alloced * sizeof (*leaves));
171 numbers = realloc (numbers, alloced * sizeof (*numbers));
172
173 FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*leaves));
174 FcMemAlloc (FC_MEM_CHARSET, alloced * sizeof (*numbers));
175
176 distance = (intptr_t) new_leaves - (intptr_t) leaves;
7ce19673
KP
177 if (new_leaves && distance)
178 {
179 int i;
7ce19673
KP
180 for (i = 0; i < fcs->num; i++)
181 new_leaves[i] -= distance;
182 }
183 leaves = new_leaves;
900723f3
BE
184 }
185
186 if (!leaves || !numbers)
187 return FcFalse;
188
189 fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
190 fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
cd2ec1a9 191 }
20ac65ab 192
7ce19673
KP
193 memmove (leaves + pos + 1, leaves + pos,
194 (fcs->num - pos) * sizeof (*leaves));
195 memmove (numbers + pos + 1, numbers + pos,
196 (fcs->num - pos) * sizeof (*numbers));
197 numbers[pos] = (FcChar16) ucs4;
198 leaves[pos] = FcPtrToOffset (leaves, leaf);
20ac65ab
KP
199 fcs->num++;
200 return FcTrue;
24330d27
KP
201}
202
203/*
204 * Locate the leaf containing the specified char, creating it
205 * if desired
206 */
207
c647f6f1 208FcCharLeaf *
24330d27
KP
209FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
210{
20ac65ab
KP
211 int pos;
212 FcCharLeaf *leaf;
24330d27 213
20ac65ab
KP
214 pos = FcCharSetFindLeafPos (fcs, ucs4);
215 if (pos >= 0)
7ce19673 216 return FcCharSetLeaf(fcs, pos);
20ac65ab
KP
217
218 leaf = calloc (1, sizeof (FcCharLeaf));
219 if (!leaf)
220 return 0;
221
222 pos = -pos - 1;
223 if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
24330d27 224 {
20ac65ab
KP
225 free (leaf);
226 return 0;
24330d27 227 }
d8d73958 228 FcMemAlloc (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
20ac65ab
KP
229 return leaf;
230}
231
232static FcBool
233FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
234{
235 int pos;
236
237 pos = FcCharSetFindLeafPos (fcs, ucs4);
238 if (pos >= 0)
24330d27 239 {
d8d73958 240 FcMemFree (FC_MEM_CHARLEAF, sizeof (FcCharLeaf));
7ce19673
KP
241 free (FcCharSetLeaf (fcs, pos));
242 FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
243 leaf);
20ac65ab 244 return FcTrue;
24330d27 245 }
20ac65ab
KP
246 pos = -pos - 1;
247 return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
24330d27
KP
248}
249
250FcBool
251FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
252{
253 FcCharLeaf *leaf;
254 FcChar32 *b;
255
d8d73958 256 if (fcs->ref == FC_REF_CONSTANT)
24330d27
KP
257 return FcFalse;
258 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
259 if (!leaf)
260 return FcFalse;
261 b = &leaf->map[(ucs4 & 0xff) >> 5];
262 *b |= (1 << (ucs4 & 0x1f));
263 return FcTrue;
264}
265
266/*
267 * An iterator for the leaves of a charset
268 */
269
270typedef struct _fcCharSetIter {
271 FcCharLeaf *leaf;
272 FcChar32 ucs4;
20ac65ab 273 int pos;
24330d27
KP
274} FcCharSetIter;
275
276/*
20ac65ab 277 * Set iter->leaf to the leaf containing iter->ucs4 or higher
24330d27 278 */
24330d27
KP
279
280static void
281FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
282{
20ac65ab 283 int pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
1412a699 284
20ac65ab 285 if (pos < 0)
1412a699 286 {
20ac65ab
KP
287 pos = -pos - 1;
288 if (pos == fcs->num)
1412a699 289 {
20ac65ab
KP
290 iter->ucs4 = ~0;
291 iter->leaf = 0;
292 return;
1412a699 293 }
7ce19673 294 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
1412a699 295 }
7ce19673 296 iter->leaf = FcCharSetLeaf(fcs, pos);
20ac65ab 297 iter->pos = pos;
24330d27
KP
298}
299
300static void
301FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
302{
20ac65ab
KP
303 int pos = iter->pos + 1;
304 if (pos >= fcs->num)
1412a699
KP
305 {
306 iter->ucs4 = ~0;
307 iter->leaf = 0;
1412a699 308 }
20ac65ab 309 else
1412a699 310 {
7ce19673
KP
311 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
312 iter->leaf = FcCharSetLeaf(fcs, pos);
20ac65ab 313 iter->pos = pos;
1412a699 314 }
1412a699
KP
315}
316
24330d27
KP
317
318static void
319FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
320{
321 iter->ucs4 = 0;
67accef4 322 iter->pos = 0;
24330d27
KP
323 FcCharSetIterSet (fcs, iter);
324}
325
326FcCharSet *
327FcCharSetCopy (FcCharSet *src)
328{
d8d73958
KP
329 if (src->ref != FC_REF_CONSTANT)
330 src->ref++;
9e612141
KP
331 else
332 FcCacheObjectReference (src);
24330d27
KP
333 return src;
334}
335
336FcBool
337FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
338{
339 FcCharSetIter ai, bi;
340 int i;
341
342 if (a == b)
343 return FcTrue;
344 for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
345 ai.leaf && bi.leaf;
346 FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi))
347 {
348 if (ai.ucs4 != bi.ucs4)
349 return FcFalse;
350 for (i = 0; i < 256/32; i++)
351 if (ai.leaf->map[i] != bi.leaf->map[i])
352 return FcFalse;
353 }
354 return ai.leaf == bi.leaf;
355}
356
357static FcBool
358FcCharSetAddLeaf (FcCharSet *fcs,
359 FcChar32 ucs4,
360 FcCharLeaf *leaf)
361{
362 FcCharLeaf *new = FcCharSetFindLeafCreate (fcs, ucs4);
363 if (!new)
364 return FcFalse;
365 *new = *leaf;
366 return FcTrue;
367}
368
369static FcCharSet *
370FcCharSetOperate (const FcCharSet *a,
371 const FcCharSet *b,
372 FcBool (*overlap) (FcCharLeaf *result,
373 const FcCharLeaf *al,
374 const FcCharLeaf *bl),
375 FcBool aonly,
376 FcBool bonly)
377{
378 FcCharSet *fcs;
379 FcCharSetIter ai, bi;
380
381 fcs = FcCharSetCreate ();
382 if (!fcs)
383 goto bail0;
384 FcCharSetIterStart (a, &ai);
385 FcCharSetIterStart (b, &bi);
1412a699 386 while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf)))
24330d27
KP
387 {
388 if (ai.ucs4 < bi.ucs4)
389 {
390 if (aonly)
391 {
392 if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
393 goto bail1;
394 FcCharSetIterNext (a, &ai);
395 }
396 else
397 {
398 ai.ucs4 = bi.ucs4;
399 FcCharSetIterSet (a, &ai);
400 }
401 }
402 else if (bi.ucs4 < ai.ucs4 )
403 {
404 if (bonly)
405 {
406 if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
407 goto bail1;
408 FcCharSetIterNext (b, &bi);
409 }
410 else
411 {
412 bi.ucs4 = ai.ucs4;
413 FcCharSetIterSet (b, &bi);
414 }
415 }
416 else
417 {
418 FcCharLeaf leaf;
419
420 if ((*overlap) (&leaf, ai.leaf, bi.leaf))
421 {
422 if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
423 goto bail1;
424 }
425 FcCharSetIterNext (a, &ai);
426 FcCharSetIterNext (b, &bi);
427 }
428 }
429 return fcs;
430bail1:
431 FcCharSetDestroy (fcs);
432bail0:
433 return 0;
434}
435
436static FcBool
437FcCharSetIntersectLeaf (FcCharLeaf *result,
438 const FcCharLeaf *al,
439 const FcCharLeaf *bl)
440{
441 int i;
442 FcBool nonempty = FcFalse;
443
444 for (i = 0; i < 256/32; i++)
445 if ((result->map[i] = al->map[i] & bl->map[i]))
446 nonempty = FcTrue;
447 return nonempty;
448}
449
450FcCharSet *
451FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
452{
453 return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
454}
455
456static FcBool
457FcCharSetUnionLeaf (FcCharLeaf *result,
458 const FcCharLeaf *al,
459 const FcCharLeaf *bl)
460{
461 int i;
462
463 for (i = 0; i < 256/32; i++)
464 result->map[i] = al->map[i] | bl->map[i];
465 return FcTrue;
466}
467
468FcCharSet *
469FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
470{
471 return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
472}
473
575ee6cd
KT
474FcBool
475FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
311da231 476{
575ee6cd
KT
477 int ai = 0, bi = 0;
478 FcChar16 an, bn;
311da231 479
cce69b07
BE
480 if (a->ref == FC_REF_CONSTANT) {
481 if (changed)
482 *changed = FcFalse;
575ee6cd 483 return FcFalse;
cce69b07 484 }
311da231 485
575ee6cd
KT
486 if (changed) {
487 *changed = !FcCharSetIsSubset(b, a);
488 if (!*changed)
489 return FcTrue;
490 }
25a09eb9 491
575ee6cd 492 while (bi < b->num)
311da231 493 {
575ee6cd
KT
494 an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0;
495 bn = FcCharSetNumbers(b)[bi];
311da231 496
575ee6cd 497 if (an < bn)
311da231 498 {
575ee6cd
KT
499 ai = FcCharSetFindLeafForward (a, ai + 1, bn);
500 if (ai < 0)
501 ai = -ai - 1;
311da231
CW
502 }
503 else
504 {
575ee6cd
KT
505 FcCharLeaf *bl = FcCharSetLeaf(b, bi);
506 if (bn < an)
311da231 507 {
575ee6cd
KT
508 if (!FcCharSetAddLeaf (a, bn << 8, bl))
509 return FcFalse;
510 }
511 else
512 {
513 FcCharLeaf *al = FcCharSetLeaf(a, ai);
514 FcCharSetUnionLeaf (al, al, bl);
311da231
CW
515 }
516
575ee6cd
KT
517 ai++;
518 bi++;
311da231
CW
519 }
520 }
521
575ee6cd 522 return FcTrue;
311da231
CW
523}
524
24330d27
KP
525static FcBool
526FcCharSetSubtractLeaf (FcCharLeaf *result,
527 const FcCharLeaf *al,
528 const FcCharLeaf *bl)
529{
530 int i;
531 FcBool nonempty = FcFalse;
532
533 for (i = 0; i < 256/32; i++)
534 if ((result->map[i] = al->map[i] & ~bl->map[i]))
535 nonempty = FcTrue;
536 return nonempty;
537}
538
539FcCharSet *
540FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
541{
542 return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
543}
544
545FcBool
546FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
547{
548 FcCharLeaf *leaf = FcCharSetFindLeaf (fcs, ucs4);
549 if (!leaf)
550 return FcFalse;
551 return (leaf->map[(ucs4 & 0xff) >> 5] & (1 << (ucs4 & 0x1f))) != 0;
552}
553
554static FcChar32
555FcCharSetPopCount (FcChar32 c1)
556{
350dc5f3
BE
557#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
558 return __builtin_popcount (c1);
559#else
24330d27
KP
560 /* hackmem 169 */
561 FcChar32 c2 = (c1 >> 1) & 033333333333;
562 c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
563 return (((c2 + (c2 >> 3)) & 030707070707) % 077);
350dc5f3 564#endif
24330d27
KP
565}
566
567FcChar32
568FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
569{
570 FcCharSetIter ai, bi;
571 FcChar32 count = 0;
572
573 FcCharSetIterStart (a, &ai);
574 FcCharSetIterStart (b, &bi);
575 while (ai.leaf && bi.leaf)
576 {
577 if (ai.ucs4 == bi.ucs4)
578 {
579 FcChar32 *am = ai.leaf->map;
580 FcChar32 *bm = bi.leaf->map;
581 int i = 256/32;
582 while (i--)
583 count += FcCharSetPopCount (*am++ & *bm++);
584 FcCharSetIterNext (a, &ai);
585 }
586 else if (ai.ucs4 < bi.ucs4)
587 {
588 ai.ucs4 = bi.ucs4;
589 FcCharSetIterSet (a, &ai);
590 }
591 if (bi.ucs4 < ai.ucs4)
592 {
593 bi.ucs4 = ai.ucs4;
594 FcCharSetIterSet (b, &bi);
595 }
596 }
597 return count;
598}
599
600FcChar32
601FcCharSetCount (const FcCharSet *a)
602{
603 FcCharSetIter ai;
604 FcChar32 count = 0;
605
606 for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
607 {
608 int i = 256/32;
609 FcChar32 *am = ai.leaf->map;
610
611 while (i--)
612 count += FcCharSetPopCount (*am++);
613 }
614 return count;
615}
616
617FcChar32
618FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
619{
620 FcCharSetIter ai, bi;
621 FcChar32 count = 0;
622
623 FcCharSetIterStart (a, &ai);
624 FcCharSetIterStart (b, &bi);
625 while (ai.leaf)
626 {
627 if (ai.ucs4 <= bi.ucs4)
628 {
629 FcChar32 *am = ai.leaf->map;
630 int i = 256/32;
631 if (ai.ucs4 == bi.ucs4)
632 {
2de24638 633 FcChar32 *bm = bi.leaf->map;
24330d27
KP
634 while (i--)
635 count += FcCharSetPopCount (*am++ & ~*bm++);
636 }
637 else
638 {
639 while (i--)
640 count += FcCharSetPopCount (*am++);
641 }
642 FcCharSetIterNext (a, &ai);
643 }
644 else if (bi.leaf)
645 {
646 bi.ucs4 = ai.ucs4;
647 FcCharSetIterSet (b, &bi);
648 }
649 }
650 return count;
651}
652
1412a699
KP
653/*
654 * return FcTrue iff a is a subset of b
655 */
656FcBool
657FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
658{
20ac65ab
KP
659 int ai, bi;
660 FcChar16 an, bn;
661
662 if (a == b) return FcTrue;
663 bi = 0;
664 ai = 0;
665 while (ai < a->num && bi < b->num)
bc9469ba 666 {
7ce19673
KP
667 an = FcCharSetNumbers(a)[ai];
668 bn = FcCharSetNumbers(b)[bi];
f45d39b1
KP
669 /*
670 * Check matching pages
671 */
20ac65ab 672 if (an == bn)
1412a699 673 {
7ce19673
KP
674 FcChar32 *am = FcCharSetLeaf(a, ai)->map;
675 FcChar32 *bm = FcCharSetLeaf(b, bi)->map;
20ac65ab
KP
676
677 if (am != bm)
bc9469ba 678 {
20ac65ab 679 int i = 256/32;
f45d39b1
KP
680 /*
681 * Does am have any bits not in bm?
682 */
20ac65ab
KP
683 while (i--)
684 if (*am++ & ~*bm++)
685 return FcFalse;
bc9469ba 686 }
20ac65ab
KP
687 ai++;
688 bi++;
689 }
f45d39b1
KP
690 /*
691 * Does a have any pages not in b?
692 */
20ac65ab
KP
693 else if (an < bn)
694 return FcFalse;
695 else
696 {
575ee6cd
KT
697 bi = FcCharSetFindLeafForward (b, bi + 1, an);
698 if (bi < 0)
699 bi = -bi - 1;
1412a699 700 }
1412a699 701 }
f45d39b1
KP
702 /*
703 * did we look at every page?
704 */
1b16ef20 705 return ai >= a->num;
1412a699
KP
706}
707
36732012
KP
708/*
709 * These two functions efficiently walk the entire charmap for
710 * other software (like pango) that want their own copy
711 */
712
aae6f7d4 713FcChar32
36732012
KP
714FcCharSetNextPage (const FcCharSet *a,
715 FcChar32 map[FC_CHARSET_MAP_SIZE],
716 FcChar32 *next)
aae6f7d4
KP
717{
718 FcCharSetIter ai;
36732012 719 FcChar32 page;
aae6f7d4 720
36732012 721 ai.ucs4 = *next;
aae6f7d4
KP
722 FcCharSetIterSet (a, &ai);
723 if (!ai.leaf)
36732012
KP
724 return FC_CHARSET_DONE;
725
726 /*
727 * Save current information
728 */
729 page = ai.ucs4;
730 memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
731 /*
732 * Step to next page
733 */
734 FcCharSetIterNext (a, &ai);
735 *next = ai.ucs4;
736
aae6f7d4
KP
737 return page;
738}
739
36732012
KP
740FcChar32
741FcCharSetFirstPage (const FcCharSet *a,
742 FcChar32 map[FC_CHARSET_MAP_SIZE],
743 FcChar32 *next)
744{
745 *next = 0;
746 return FcCharSetNextPage (a, map, next);
747}
748
20ac65ab
KP
749/*
750 * old coverage API, rather hard to use correctly
751 */
20ac65ab
KP
752
753FcChar32
754FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
755{
756 FcCharSetIter ai;
757
758 ai.ucs4 = page;
759 FcCharSetIterSet (a, &ai);
760 if (!ai.leaf)
761 {
762 memset (result, '\0', 256 / 8);
763 page = 0;
764 }
765 else
766 {
767 memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
768 FcCharSetIterNext (a, &ai);
769 page = ai.ucs4;
770 }
771 return page;
772}
773
24330d27
KP
774/*
775 * ASCII representation of charsets.
776 *
777 * Each leaf is represented as 9 32-bit values, the code of the first character followed
778 * by 8 32 bit values for the leaf itself. Each value is encoded as 5 ASCII characters,
779 * only 85 different values are used to avoid control characters as well as the other
780 * characters used to encode font names. 85**5 > 2^32 so things work out, but
781 * it's not exactly human readable output. As a special case, 0 is encoded as a space
782 */
783
82f4243f 784static const unsigned char charToValue[256] = {
24330d27
KP
785 /* "" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
786 /* "\b" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
787 /* "\020" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
788 /* "\030" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
789 /* " " */ 0xff, 0x00, 0xff, 0x01, 0x02, 0x03, 0x04, 0xff,
790 /* "(" */ 0x05, 0x06, 0x07, 0x08, 0xff, 0xff, 0x09, 0x0a,
791 /* "0" */ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
792 /* "8" */ 0x13, 0x14, 0xff, 0x15, 0x16, 0xff, 0x17, 0x18,
793 /* "@" */ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
794 /* "H" */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
795 /* "P" */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
796 /* "X" */ 0x31, 0x32, 0x33, 0x34, 0xff, 0x35, 0x36, 0xff,
797 /* "`" */ 0xff, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
798 /* "h" */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
799 /* "p" */ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d,
800 /* "x" */ 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0xff,
801 /* "\200" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
802 /* "\210" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
803 /* "\220" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
804 /* "\230" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
805 /* "\240" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
806 /* "\250" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
807 /* "\260" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
808 /* "\270" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
809 /* "\300" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
810 /* "\310" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
811 /* "\320" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
812 /* "\330" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
813 /* "\340" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
814 /* "\350" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
815 /* "\360" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
816 /* "\370" */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
817};
818
82f4243f 819static const FcChar8 valueToChar[0x55] = {
24330d27
KP
820 /* 0x00 */ '!', '#', '$', '%', '&', '(', ')', '*',
821 /* 0x08 */ '+', '.', '/', '0', '1', '2', '3', '4',
822 /* 0x10 */ '5', '6', '7', '8', '9', ';', '<', '>',
823 /* 0x18 */ '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
824 /* 0x20 */ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
825 /* 0x28 */ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
826 /* 0x30 */ 'W', 'X', 'Y', 'Z', '[', ']', '^', 'a',
827 /* 0x38 */ 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
828 /* 0x40 */ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
829 /* 0x48 */ 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
830 /* 0x50 */ 'z', '{', '|', '}', '~',
831};
832
833static FcChar8 *
834FcCharSetParseValue (FcChar8 *string, FcChar32 *value)
835{
836 int i;
837 FcChar32 v;
ccb3e93b 838 FcChar32 c;
24330d27
KP
839
840 if (*string == ' ')
841 {
842 v = 0;
843 string++;
844 }
845 else
846 {
847 v = 0;
848 for (i = 0; i < 5; i++)
849 {
ccb3e93b 850 if (!(c = (FcChar32) (unsigned char) *string++))
24330d27
KP
851 return 0;
852 c = charToValue[c];
853 if (c == 0xff)
854 return 0;
855 v = v * 85 + c;
856 }
857 }
858 *value = v;
859 return string;
860}
861
862static FcBool
c2e7c611 863FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value)
24330d27
KP
864{
865 int i;
866 if (value == 0)
867 {
c2e7c611 868 return FcStrBufChar (buf, ' ');
24330d27
KP
869 }
870 else
871 {
872 FcChar8 string[6];
873 FcChar8 *s = string + 5;
874 string[5] = '\0';
875 for (i = 0; i < 5; i++)
876 {
877 *--s = valueToChar[value % 85];
878 value /= 85;
879 }
880 for (i = 0; i < 5; i++)
c2e7c611 881 if (!FcStrBufChar (buf, *s++))
24330d27
KP
882 return FcFalse;
883 }
884 return FcTrue;
885}
886
bc5e487f
KP
887FcCharSet *
888FcNameParseCharSet (FcChar8 *string)
889{
890 FcCharSet *c;
891 FcChar32 ucs4;
892 FcCharLeaf *leaf;
893 FcCharLeaf temp;
894 FcChar32 bits;
895 int i;
896
897 c = FcCharSetCreate ();
898 if (!c)
899 goto bail0;
900 while (*string)
901 {
902 string = FcCharSetParseValue (string, &ucs4);
903 if (!string)
904 goto bail1;
905 bits = 0;
906 for (i = 0; i < 256/32; i++)
907 {
908 string = FcCharSetParseValue (string, &temp.map[i]);
909 if (!string)
910 goto bail1;
911 bits |= temp.map[i];
912 }
913 if (bits)
914 {
915 leaf = malloc (sizeof (FcCharLeaf));
916 if (!leaf)
917 goto bail1;
918 *leaf = temp;
919 if (!FcCharSetInsertLeaf (c, ucs4, leaf))
920 goto bail1;
921 }
922 }
923 return c;
924bail1:
925 if (c->num)
926 {
927 FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcCharLeaf *));
928 free (FcCharSetLeaves (c));
929 }
930 if (c->num)
931 {
932 FcMemFree (FC_MEM_CHARSET, c->num * sizeof (FcChar16));
933 free (FcCharSetNumbers (c));
934 }
935 FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
936 free (c);
937bail0:
938 return NULL;
939}
940
941FcBool
942FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
943{
944 FcCharSetIter ci;
945 int i;
946#ifdef CHECK
947 int len = buf->len;
948#endif
949
950 for (FcCharSetIterStart (c, &ci);
951 ci.leaf;
952 FcCharSetIterNext (c, &ci))
953 {
954 if (!FcCharSetUnparseValue (buf, ci.ucs4))
955 return FcFalse;
956 for (i = 0; i < 256/32; i++)
957 if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
958 return FcFalse;
959 }
960#ifdef CHECK
961 {
962 FcCharSet *check;
963 FcChar32 missing;
964 FcCharSetIter ci, checki;
965
966 /* null terminate for parser */
967 FcStrBufChar (buf, '\0');
968 /* step back over null for life after test */
969 buf->len--;
970 check = FcNameParseCharSet (buf->buf + len);
971 FcCharSetIterStart (c, &ci);
972 FcCharSetIterStart (check, &checki);
973 while (ci.leaf || checki.leaf)
974 {
975 if (ci.ucs4 < checki.ucs4)
976 {
977 printf ("Missing leaf node at 0x%x\n", ci.ucs4);
978 FcCharSetIterNext (c, &ci);
979 }
980 else if (checki.ucs4 < ci.ucs4)
981 {
982 printf ("Extra leaf node at 0x%x\n", checki.ucs4);
983 FcCharSetIterNext (check, &checki);
984 }
985 else
986 {
987 int i = 256/32;
988 FcChar32 *cm = ci.leaf->map;
989 FcChar32 *checkm = checki.leaf->map;
990
991 for (i = 0; i < 256; i += 32)
992 {
993 if (*cm != *checkm)
994 printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
995 ci.ucs4 + i, *cm, *checkm);
996 cm++;
997 checkm++;
998 }
999 FcCharSetIterNext (c, &ci);
1000 FcCharSetIterNext (check, &checki);
1001 }
1002 }
1003 if ((missing = FcCharSetSubtractCount (c, check)))
1004 printf ("%d missing in reparsed result\n", missing);
1005 if ((missing = FcCharSetSubtractCount (check, c)))
1006 printf ("%d extra in reparsed result\n", missing);
1007 FcCharSetDestroy (check);
1008 }
1009#endif
1010
1011 return FcTrue;
1012}
1013
20ac65ab
KP
1014typedef struct _FcCharLeafEnt FcCharLeafEnt;
1015
1016struct _FcCharLeafEnt {
1017 FcCharLeafEnt *next;
1018 FcChar32 hash;
1019 FcCharLeaf leaf;
1020};
1021
1022#define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt))
bc5e487f
KP
1023#define FC_CHAR_LEAF_HASH_SIZE 257
1024
1025typedef struct _FcCharSetEnt FcCharSetEnt;
1026
1027struct _FcCharSetEnt {
1028 FcCharSetEnt *next;
1029 FcChar32 hash;
1030 FcCharSet set;
1031};
1032
1033typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
1034
1035struct _FcCharSetOrigEnt {
1036 FcCharSetOrigEnt *next;
1037 const FcCharSet *orig;
1038 const FcCharSet *frozen;
1039};
1040
1041#define FC_CHAR_SET_HASH_SIZE 67
1042
1043struct _FcCharSetFreezer {
1044 FcCharLeafEnt *leaf_hash_table[FC_CHAR_LEAF_HASH_SIZE];
1045 FcCharLeafEnt **leaf_blocks;
1046 int leaf_block_count;
1047 FcCharSetEnt *set_hash_table[FC_CHAR_SET_HASH_SIZE];
1048 FcCharSetOrigEnt *orig_hash_table[FC_CHAR_SET_HASH_SIZE];
1049 FcCharLeafEnt *current_block;
1050 int leaf_remain;
1051 int leaves_seen;
1052 int charsets_seen;
1053 int leaves_allocated;
1054 int charsets_allocated;
1055};
20ac65ab
KP
1056
1057static FcCharLeafEnt *
bc5e487f 1058FcCharLeafEntCreate (FcCharSetFreezer *freezer)
20ac65ab 1059{
bc5e487f 1060 if (!freezer->leaf_remain)
20ac65ab 1061 {
34cd0514
CW
1062 FcCharLeafEnt **newBlocks;
1063
bc5e487f
KP
1064 freezer->leaf_block_count++;
1065 newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
34cd0514
CW
1066 if (!newBlocks)
1067 return 0;
bc5e487f
KP
1068 freezer->leaf_blocks = newBlocks;
1069 freezer->current_block = freezer->leaf_blocks[freezer->leaf_block_count-1] = malloc (FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
1070 if (!freezer->current_block)
20ac65ab 1071 return 0;
d8d73958 1072 FcMemAlloc (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
bc5e487f 1073 freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
20ac65ab 1074 }
bc5e487f
KP
1075 freezer->leaf_remain--;
1076 freezer->leaves_allocated++;
1077 return freezer->current_block++;
20ac65ab
KP
1078}
1079
20ac65ab
KP
1080static FcChar32
1081FcCharLeafHash (FcCharLeaf *leaf)
1082{
1083 FcChar32 hash = 0;
1084 int i;
1085
1086 for (i = 0; i < 256/32; i++)
1087 hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
1088 return hash;
1089}
1090
20ac65ab 1091static FcCharLeaf *
bc5e487f 1092FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
20ac65ab 1093{
20ac65ab 1094 FcChar32 hash = FcCharLeafHash (leaf);
bc5e487f 1095 FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
20ac65ab
KP
1096 FcCharLeafEnt *ent;
1097
20ac65ab
KP
1098 for (ent = *bucket; ent; ent = ent->next)
1099 {
1100 if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
1101 return &ent->leaf;
1102 }
1103
bc5e487f 1104 ent = FcCharLeafEntCreate(freezer);
20ac65ab
KP
1105 if (!ent)
1106 return 0;
20ac65ab
KP
1107 ent->leaf = *leaf;
1108 ent->hash = hash;
1109 ent->next = *bucket;
1110 *bucket = ent;
1111 return &ent->leaf;
1112}
1113
20ac65ab
KP
1114static FcChar32
1115FcCharSetHash (FcCharSet *fcs)
1116{
1117 FcChar32 hash = 0;
20ac65ab
KP
1118 int i;
1119
1120 /* hash in leaves */
c3796ac6
KP
1121 for (i = 0; i < fcs->num; i++)
1122 hash = ((hash << 1) | (hash >> 31)) ^ FcCharLeafHash (FcCharSetLeaf(fcs,i));
20ac65ab
KP
1123 /* hash in numbers */
1124 for (i = 0; i < fcs->num; i++)
7ce19673 1125 hash = ((hash << 1) | (hash >> 31)) ^ *FcCharSetNumbers(fcs);
20ac65ab
KP
1126 return hash;
1127}
1128
bc5e487f
KP
1129static FcBool
1130FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
1131{
1132 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
1133 FcCharSetOrigEnt *ent;
1134
1135 ent = malloc (sizeof (FcCharSetOrigEnt));
1136 if (!ent)
1137 return FcFalse;
1138 ent->orig = orig;
1139 ent->frozen = frozen;
1140 ent->next = *bucket;
1141 *bucket = ent;
1142 return FcTrue;
1143}
34cd0514 1144
20ac65ab 1145static FcCharSet *
bc5e487f 1146FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs, const FcCharSet *orig)
20ac65ab 1147{
20ac65ab 1148 FcChar32 hash = FcCharSetHash (fcs);
bc5e487f 1149 FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
20ac65ab 1150 FcCharSetEnt *ent;
d8d73958 1151 int size;
7ce19673 1152 int i;
20ac65ab 1153
20ac65ab
KP
1154 for (ent = *bucket; ent; ent = ent->next)
1155 {
1156 if (ent->hash == hash &&
1157 ent->set.num == fcs->num &&
7ce19673
KP
1158 !memcmp (FcCharSetNumbers(&ent->set),
1159 FcCharSetNumbers(fcs),
20ac65ab
KP
1160 fcs->num * sizeof (FcChar16)))
1161 {
cd2ec1a9
PL
1162 FcBool ok = FcTrue;
1163 int i;
1164
1165 for (i = 0; i < fcs->num; i++)
7ce19673 1166 if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
cd2ec1a9
PL
1167 ok = FcFalse;
1168 if (ok)
1169 return &ent->set;
20ac65ab
KP
1170 }
1171 }
1172
d8d73958
KP
1173 size = (sizeof (FcCharSetEnt) +
1174 fcs->num * sizeof (FcCharLeaf *) +
1175 fcs->num * sizeof (FcChar16));
1176 ent = malloc (size);
20ac65ab
KP
1177 if (!ent)
1178 return 0;
d8d73958 1179 FcMemAlloc (FC_MEM_CHARSET, size);
bc5e487f
KP
1180
1181 freezer->charsets_allocated++;
20ac65ab 1182
d8d73958 1183 ent->set.ref = FC_REF_CONSTANT;
20ac65ab 1184 ent->set.num = fcs->num;
7ce19673 1185 if (fcs->num)
5c7fb827 1186 {
7ce19673
KP
1187 intptr_t *ent_leaves;
1188
1189 ent->set.leaves_offset = sizeof (ent->set);
1190 ent->set.numbers_offset = (ent->set.leaves_offset +
1191 fcs->num * sizeof (intptr_t));
1192
1193 ent_leaves = FcCharSetLeaves (&ent->set);
1194 for (i = 0; i < fcs->num; i++)
1195 ent_leaves[i] = FcPtrToOffset (ent_leaves,
1196 FcCharSetLeaf (fcs, i));
1197 memcpy (FcCharSetNumbers (&ent->set),
1198 FcCharSetNumbers (fcs),
1199 fcs->num * sizeof (FcChar16));
5c7fb827
KP
1200 }
1201 else
1202 {
7ce19673
KP
1203 ent->set.leaves_offset = 0;
1204 ent->set.numbers_offset = 0;
5c7fb827 1205 }
20ac65ab
KP
1206
1207 ent->hash = hash;
1208 ent->next = *bucket;
1209 *bucket = ent;
bc5e487f 1210
20ac65ab
KP
1211 return &ent->set;
1212}
1213
bc5e487f
KP
1214static const FcCharSet *
1215FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
34cd0514 1216{
bc5e487f
KP
1217 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) & FC_CHAR_SET_HASH_SIZE];
1218 FcCharSetOrigEnt *ent;
1219
1220 for (ent = *bucket; ent; ent = ent->next)
1221 if (ent->orig == orig)
1222 return ent->frozen;
1223 return NULL;
34cd0514
CW
1224}
1225
18b6857c 1226const FcCharSet *
bc5e487f 1227FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
4c003605 1228{
bc5e487f
KP
1229 FcCharSet *b;
1230 const FcCharSet *n = 0;
1231 FcCharLeaf *l;
1232 int i;
4c003605
KP
1233
1234 b = FcCharSetCreate ();
1235 if (!b)
1236 goto bail0;
1237 for (i = 0; i < fcs->num; i++)
1238 {
bc5e487f 1239 l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
4c003605
KP
1240 if (!l)
1241 goto bail1;
7ce19673 1242 if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
4c003605
KP
1243 goto bail1;
1244 }
bc5e487f
KP
1245 n = FcCharSetFreezeBase (freezer, b, fcs);
1246 if (!FcCharSetFreezeOrig (freezer, fcs, n))
1247 {
1248 n = NULL;
1249 goto bail1;
1250 }
1251 freezer->charsets_seen++;
1252 freezer->leaves_seen += fcs->num;
4c003605 1253bail1:
bc5e487f 1254 if (b->num)
d8d73958 1255 {
7ce19673
KP
1256 FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcCharLeaf *));
1257 free (FcCharSetLeaves (b));
1258 }
bc5e487f 1259 if (b->num)
7ce19673
KP
1260 {
1261 FcMemFree (FC_MEM_CHARSET, b->num * sizeof (FcChar16));
1262 free (FcCharSetNumbers (b));
d8d73958
KP
1263 }
1264 FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
4c003605
KP
1265 free (b);
1266bail0:
1267 return n;
1268}
1269
18b6857c 1270FcCharSetFreezer *
bc5e487f 1271FcCharSetFreezerCreate (void)
24330d27 1272{
bc5e487f 1273 FcCharSetFreezer *freezer;
24330d27 1274
bc5e487f
KP
1275 freezer = calloc (1, sizeof (FcCharSetFreezer));
1276 return freezer;
24330d27
KP
1277}
1278
bc5e487f
KP
1279void
1280FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
24330d27 1281{
bc5e487f 1282 int i;
24330d27 1283
bc5e487f 1284 if (FcDebug() & FC_DBG_CACHE)
24330d27 1285 {
bc5e487f
KP
1286 printf ("\ncharsets %d -> %d leaves %d -> %d\n",
1287 freezer->charsets_seen, freezer->charsets_allocated,
1288 freezer->leaves_seen, freezer->leaves_allocated);
24330d27 1289 }
bc5e487f 1290 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
24330d27 1291 {
bc5e487f
KP
1292 FcCharSetEnt *ent, *next;
1293 for (ent = freezer->set_hash_table[i]; ent; ent = next)
24330d27 1294 {
bc5e487f 1295 next = ent->next;
13a14cbf
KP
1296 FcMemFree (FC_MEM_CHARSET, (sizeof (FcCharSetEnt) +
1297 ent->set.num * sizeof (FcCharLeaf *) +
1298 ent->set.num * sizeof (FcChar16)));
bc5e487f
KP
1299 free (ent);
1300 }
1301 }
24330d27 1302
bc5e487f
KP
1303 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
1304 {
1305 FcCharSetOrigEnt *ent, *next;
1306 for (ent = freezer->orig_hash_table[i]; ent; ent = next)
1307 {
1308 next = ent->next;
1309 free (ent);
24330d27 1310 }
24330d27 1311 }
bc5e487f
KP
1312
1313 for (i = 0; i < freezer->leaf_block_count; i++)
13a14cbf 1314 {
bc5e487f 1315 free (freezer->leaf_blocks[i]);
13a14cbf
KP
1316 FcMemFree (FC_MEM_CHARLEAF, FC_CHAR_LEAF_BLOCK * sizeof (FcCharLeafEnt));
1317 }
bc5e487f
KP
1318
1319 free (freezer->leaf_blocks);
1320 free (freezer);
24330d27 1321}
cd2ec1a9 1322
7ce19673
KP
1323FcBool
1324FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
4262e0b3 1325{
bc5e487f
KP
1326 intptr_t *leaves;
1327 FcChar16 *numbers;
7ce19673
KP
1328 int i;
1329
bc5e487f
KP
1330 if (cs->ref != FC_REF_CONSTANT)
1331 {
1332 if (!serialize->cs_freezer)
1333 {
1334 serialize->cs_freezer = FcCharSetFreezerCreate ();
1335 if (!serialize->cs_freezer)
1336 return FcFalse;
1337 }
18b6857c
KP
1338 if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
1339 return FcTrue;
1340
bc5e487f
KP
1341 cs = FcCharSetFreeze (serialize->cs_freezer, cs);
1342 }
1343
1344 leaves = FcCharSetLeaves (cs);
1345 numbers = FcCharSetNumbers (cs);
1346
7ce19673
KP
1347 if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
1348 return FcFalse;
1349 if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
1350 return FcFalse;
1351 if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
1352 return FcFalse;
1353 for (i = 0; i < cs->num; i++)
1354 if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i),
1355 sizeof (FcCharLeaf)))
1356 return FcFalse;
cd2ec1a9
PL
1357 return FcTrue;
1358}
7ce19673
KP
1359
1360FcCharSet *
1361FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
4262e0b3 1362{
bc5e487f 1363 FcCharSet *cs_serialized;
7ce19673
KP
1364 intptr_t *leaves, *leaves_serialized;
1365 FcChar16 *numbers, *numbers_serialized;
1366 FcCharLeaf *leaf, *leaf_serialized;
1367 int i;
4262e0b3 1368
bc5e487f
KP
1369 if (cs->ref != FC_REF_CONSTANT && serialize->cs_freezer)
1370 {
1371 cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
1372 if (!cs)
1373 return NULL;
1374 }
1375
1376 cs_serialized = FcSerializePtr (serialize, cs);
7ce19673
KP
1377 if (!cs_serialized)
1378 return NULL;
1379
1380 cs_serialized->ref = FC_REF_CONSTANT;
1381 cs_serialized->num = cs->num;
4262e0b3 1382
2d3387fd 1383 if (cs->num)
cd2ec1a9 1384 {
2d3387fd
KP
1385 leaves = FcCharSetLeaves (cs);
1386 leaves_serialized = FcSerializePtr (serialize, leaves);
1387 if (!leaves_serialized)
1388 return NULL;
1389
1390 cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
1391 leaves_serialized);
1392
1393 numbers = FcCharSetNumbers (cs);
1394 numbers_serialized = FcSerializePtr (serialize, numbers);
1395 if (!numbers)
7ce19673 1396 return NULL;
2d3387fd
KP
1397
1398 cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
1399 numbers_serialized);
1400
1401 for (i = 0; i < cs->num; i++)
1402 {
1403 leaf = FcCharSetLeaf (cs, i);
1404 leaf_serialized = FcSerializePtr (serialize, leaf);
1405 if (!leaf_serialized)
1406 return NULL;
1407 *leaf_serialized = *leaf;
1408 leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
1409 leaf_serialized);
1410 numbers_serialized[i] = numbers[i];
1411 }
1412 }
1413 else
1414 {
1415 cs_serialized->leaves_offset = 0;
1416 cs_serialized->numbers_offset = 0;
cd2ec1a9 1417 }
7ce19673
KP
1418
1419 return cs_serialized;
cd2ec1a9 1420}
23816bf9
KP
1421#define __fccharset__
1422#include "fcaliastail.h"
1423#undef __fccharset__