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