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