2 * fontconfig/src/fccharset.c
4 * Copyright © 2001 Keith Packard
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.
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.
31 FcCharSetCreate (void)
35 fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
38 FcRefInit (&fcs->ref, 1);
40 fcs->leaves_offset = 0;
41 fcs->numbers_offset = 0;
46 FcCharSetPromote (FcValuePromotionBuffer *vbuf)
48 FcCharSet *fcs = (FcCharSet *) vbuf;
50 FC_ASSERT_STATIC (sizeof (FcCharSet) <= sizeof (FcValuePromotionBuffer));
52 FcRefSetConst (&fcs->ref);
54 fcs->leaves_offset = 0;
55 fcs->numbers_offset = 0;
63 return FcCharSetCreate ();
67 FcCharSetDestroy (FcCharSet *fcs)
73 if (FcRefIsConst (&fcs->ref))
75 FcCacheObjectDereference (fcs);
78 if (FcRefDec (&fcs->ref) != 1)
80 for (i = 0; i < fcs->num; i++)
81 free (FcCharSetLeaf (fcs, i));
84 free (FcCharSetLeaves (fcs));
85 free (FcCharSetNumbers (fcs));
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
99 FcCharSetFindLeafForward (const FcCharSet *fcs, int start, FcChar16 num)
101 FcChar16 *numbers = FcCharSetNumbers(fcs);
104 int high = fcs->num - 1;
110 int mid = (low + high) >> 1;
119 if (high < 0 || (high < fcs->num && numbers[high] < num))
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
131 FcCharSetFindLeafPos (const FcCharSet *fcs, FcChar32 ucs4)
133 return FcCharSetFindLeafForward (fcs, 0, ucs4 >> 8);
137 FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
139 int pos = FcCharSetFindLeafPos (fcs, ucs4);
141 return FcCharSetLeaf(fcs, pos);
145 #define FC_IS_ZERO_OR_POWER_OF_TWO(x) (!((x) & ((x)-1)))
148 FcCharSetPutLeaf (FcCharSet *fcs,
153 intptr_t *leaves = FcCharSetLeaves (fcs);
154 FcChar16 *numbers = FcCharSetNumbers (fcs);
160 if (FC_IS_ZERO_OR_POWER_OF_TWO (fcs->num))
164 unsigned int alloced = 8;
165 leaves = malloc (alloced * sizeof (*leaves));
166 numbers = malloc (alloced * sizeof (*numbers));
167 if (!leaves || !numbers)
179 unsigned int alloced = fcs->num;
180 intptr_t *new_leaves;
184 numbers = realloc (numbers, alloced * sizeof (*numbers));
187 new_leaves = realloc (leaves, alloced * sizeof (*leaves));
191 * Revert the reallocation of numbers. We update numbers_offset
192 * first in case realloc() fails.
194 fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
195 numbers = realloc (numbers, (alloced / 2) * sizeof (*numbers));
196 /* unlikely to fail though */
199 fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
202 distance = (char *) new_leaves - (char *) leaves;
203 for (i = 0; i < fcs->num; i++) {
204 new_leaves[i] -= distance;
209 fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
210 fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
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);
224 * Locate the leaf containing the specified char, creating it
229 FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
234 pos = FcCharSetFindLeafPos (fcs, ucs4);
236 return FcCharSetLeaf(fcs, pos);
238 leaf = calloc (1, sizeof (FcCharLeaf));
243 if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
252 FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
256 pos = FcCharSetFindLeafPos (fcs, ucs4);
259 free (FcCharSetLeaf (fcs, pos));
260 FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
265 return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
269 FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
274 if (fcs == NULL || FcRefIsConst (&fcs->ref))
276 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
279 b = &leaf->map[(ucs4 & 0xff) >> 5];
280 *b |= (1U << (ucs4 & 0x1f));
285 FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
290 if (fcs == NULL || FcRefIsConst (&fcs->ref))
292 leaf = FcCharSetFindLeaf (fcs, ucs4);
295 b = &leaf->map[(ucs4 & 0xff) >> 5];
296 *b &= ~(1U << (ucs4 & 0x1f));
297 /* We don't bother removing the leaf if it's empty */
302 * An iterator for the leaves of a charset
305 typedef struct _fcCharSetIter {
312 * Set iter->leaf to the leaf containing iter->ucs4 or higher
316 FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
318 int pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
329 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
331 iter->leaf = FcCharSetLeaf(fcs, pos);
336 FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
338 int pos = iter->pos + 1;
346 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
347 iter->leaf = FcCharSetLeaf(fcs, pos);
354 FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
358 FcCharSetIterSet (fcs, iter);
362 FcCharSetCopy (FcCharSet *src)
366 if (!FcRefIsConst (&src->ref))
367 FcRefInc (&src->ref);
369 FcCacheObjectReference (src);
375 FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
377 FcCharSetIter ai, bi;
384 for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
386 FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi))
388 if (ai.ucs4 != bi.ucs4)
390 for (i = 0; i < 256/32; i++)
391 if (ai.leaf->map[i] != bi.leaf->map[i])
394 return ai.leaf == bi.leaf;
398 FcCharSetAddLeaf (FcCharSet *fcs,
402 FcCharLeaf *new = FcCharSetFindLeafCreate (fcs, ucs4);
410 FcCharSetOperate (const FcCharSet *a,
412 FcBool (*overlap) (FcCharLeaf *result,
413 const FcCharLeaf *al,
414 const FcCharLeaf *bl),
419 FcCharSetIter ai, bi;
423 fcs = FcCharSetCreate ();
426 FcCharSetIterStart (a, &ai);
427 FcCharSetIterStart (b, &bi);
428 while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf)))
430 if (ai.ucs4 < bi.ucs4)
434 if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
436 FcCharSetIterNext (a, &ai);
441 FcCharSetIterSet (a, &ai);
444 else if (bi.ucs4 < ai.ucs4 )
448 if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
450 FcCharSetIterNext (b, &bi);
455 FcCharSetIterSet (b, &bi);
462 if ((*overlap) (&leaf, ai.leaf, bi.leaf))
464 if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
467 FcCharSetIterNext (a, &ai);
468 FcCharSetIterNext (b, &bi);
473 FcCharSetDestroy (fcs);
479 FcCharSetIntersectLeaf (FcCharLeaf *result,
480 const FcCharLeaf *al,
481 const FcCharLeaf *bl)
484 FcBool nonempty = FcFalse;
486 for (i = 0; i < 256/32; i++)
487 if ((result->map[i] = al->map[i] & bl->map[i]))
493 FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
495 return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
499 FcCharSetUnionLeaf (FcCharLeaf *result,
500 const FcCharLeaf *al,
501 const FcCharLeaf *bl)
505 for (i = 0; i < 256/32; i++)
506 result->map[i] = al->map[i] | bl->map[i];
511 FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
513 return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
517 FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
525 if (FcRefIsConst (&a->ref)) {
532 *changed = !FcCharSetIsSubset(b, a);
539 an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0;
540 bn = FcCharSetNumbers(b)[bi];
544 ai = FcCharSetFindLeafForward (a, ai + 1, bn);
550 FcCharLeaf *bl = FcCharSetLeaf(b, bi);
553 if (!FcCharSetAddLeaf (a, bn << 8, bl))
558 FcCharLeaf *al = FcCharSetLeaf(a, ai);
559 FcCharSetUnionLeaf (al, al, bl);
571 FcCharSetSubtractLeaf (FcCharLeaf *result,
572 const FcCharLeaf *al,
573 const FcCharLeaf *bl)
576 FcBool nonempty = FcFalse;
578 for (i = 0; i < 256/32; i++)
579 if ((result->map[i] = al->map[i] & ~bl->map[i]))
585 FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
587 return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
591 FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
597 leaf = FcCharSetFindLeaf (fcs, ucs4);
600 return (leaf->map[(ucs4 & 0xff) >> 5] & (1U << (ucs4 & 0x1f))) != 0;
604 FcCharSetPopCount (FcChar32 c1)
606 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
607 return __builtin_popcount (c1);
610 FcChar32 c2 = (c1 >> 1) & 033333333333;
611 c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
612 return (((c2 + (c2 >> 3)) & 030707070707) % 077);
617 FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
619 FcCharSetIter ai, bi;
624 FcCharSetIterStart (a, &ai);
625 FcCharSetIterStart (b, &bi);
626 while (ai.leaf && bi.leaf)
628 if (ai.ucs4 == bi.ucs4)
630 FcChar32 *am = ai.leaf->map;
631 FcChar32 *bm = bi.leaf->map;
634 count += FcCharSetPopCount (*am++ & *bm++);
635 FcCharSetIterNext (a, &ai);
637 else if (ai.ucs4 < bi.ucs4)
640 FcCharSetIterSet (a, &ai);
642 if (bi.ucs4 < ai.ucs4)
645 FcCharSetIterSet (b, &bi);
653 FcCharSetCount (const FcCharSet *a)
660 for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
663 FcChar32 *am = ai.leaf->map;
666 count += FcCharSetPopCount (*am++);
673 FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
675 FcCharSetIter ai, bi;
680 FcCharSetIterStart (a, &ai);
681 FcCharSetIterStart (b, &bi);
684 if (ai.ucs4 <= bi.ucs4)
686 FcChar32 *am = ai.leaf->map;
688 if (ai.ucs4 == bi.ucs4)
690 FcChar32 *bm = bi.leaf->map;
692 count += FcCharSetPopCount (*am++ & ~*bm++);
697 count += FcCharSetPopCount (*am++);
699 FcCharSetIterNext (a, &ai);
704 FcCharSetIterSet (b, &bi);
712 * return FcTrue iff a is a subset of b
715 FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
726 while (ai < a->num && bi < b->num)
728 an = FcCharSetNumbers(a)[ai];
729 bn = FcCharSetNumbers(b)[bi];
731 * Check matching pages
735 FcChar32 *am = FcCharSetLeaf(a, ai)->map;
736 FcChar32 *bm = FcCharSetLeaf(b, bi)->map;
742 * Does am have any bits not in bm?
752 * Does a have any pages not in b?
758 bi = FcCharSetFindLeafForward (b, bi + 1, an);
764 * did we look at every page?
770 * These two functions efficiently walk the entire charmap for
771 * other software (like pango) that want their own copy
775 FcCharSetNextPage (const FcCharSet *a,
776 FcChar32 map[FC_CHARSET_MAP_SIZE],
783 return FC_CHARSET_DONE;
785 FcCharSetIterSet (a, &ai);
787 return FC_CHARSET_DONE;
790 * Save current information
793 memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
797 FcCharSetIterNext (a, &ai);
804 FcCharSetFirstPage (const FcCharSet *a,
805 FcChar32 map[FC_CHARSET_MAP_SIZE],
809 return FcCharSetNextPage (a, map, next);
813 * old coverage API, rather hard to use correctly
817 FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
822 FcCharSetIterSet (a, &ai);
825 memset (result, '\0', 256 / 8);
830 memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
831 FcCharSetIterNext (a, &ai);
838 FcNameParseRange (FcChar8 **string, FcChar32 *pfirst, FcChar32 *plast)
840 char *s = (char *) *string;
844 while (isspace((unsigned char) *s))
848 first = last = strtol (s, &s, 16);
851 while (isspace((unsigned char) *s))
857 last = strtol (s, &s, 16);
862 if (s == t || first < 0 || last < 0 || last < first || last > 0x10ffff)
865 *string = (FcChar8 *) s;
872 FcNameParseCharSet (FcChar8 *string)
875 FcChar32 first, last;
877 c = FcCharSetCreate ();
884 if (!FcNameParseRange (&string, &first, &last))
887 for (u = first; u < last + 1; u++)
888 FcCharSetAddChar (c, u);
892 FcCharSetDestroy (c);
898 FcNameUnparseUnicode (FcStrBuf *buf, FcChar32 u)
900 FcChar8 buf_static[64];
901 snprintf ((char *) buf_static, sizeof (buf_static), "%x", u);
902 FcStrBufString (buf, buf_static);
906 FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
909 FcChar32 first, last;
915 first = last = 0x7FFFFFFF;
917 for (FcCharSetIterStart (c, &ci);
919 FcCharSetIterNext (c, &ci))
921 for (i = 0; i < 256/32; i++)
923 FcChar32 bits = ci.leaf->map[i];
924 FcChar32 u = ci.ucs4 + i * 32;
934 FcStrBufChar (buf, '-');
935 FcNameUnparseUnicode (buf, last);
937 if (last != 0x7FFFFFFF)
938 FcStrBufChar (buf, ' ');
939 /* Start new range. */
941 FcNameUnparseUnicode (buf, u);
952 FcStrBufChar (buf, '-');
953 FcNameUnparseUnicode (buf, last);
959 FcCharSetIter ci, checki;
961 /* null terminate for parser */
962 FcStrBufChar (buf, '\0');
963 /* step back over null for life after test */
965 check = FcNameParseCharSet (buf->buf + len);
966 FcCharSetIterStart (c, &ci);
967 FcCharSetIterStart (check, &checki);
968 while (ci.leaf || checki.leaf)
970 if (ci.ucs4 < checki.ucs4)
972 printf ("Missing leaf node at 0x%x\n", ci.ucs4);
973 FcCharSetIterNext (c, &ci);
975 else if (checki.ucs4 < ci.ucs4)
977 printf ("Extra leaf node at 0x%x\n", checki.ucs4);
978 FcCharSetIterNext (check, &checki);
983 FcChar32 *cm = ci.leaf->map;
984 FcChar32 *checkm = checki.leaf->map;
986 for (i = 0; i < 256; i += 32)
989 printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
990 ci.ucs4 + i, *cm, *checkm);
994 FcCharSetIterNext (c, &ci);
995 FcCharSetIterNext (check, &checki);
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);
1009 typedef struct _FcCharLeafEnt FcCharLeafEnt;
1011 struct _FcCharLeafEnt {
1012 FcCharLeafEnt *next;
1017 #define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt))
1018 #define FC_CHAR_LEAF_HASH_SIZE 257
1020 typedef struct _FcCharSetEnt FcCharSetEnt;
1022 struct _FcCharSetEnt {
1028 typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
1030 struct _FcCharSetOrigEnt {
1031 FcCharSetOrigEnt *next;
1032 const FcCharSet *orig;
1033 const FcCharSet *frozen;
1036 #define FC_CHAR_SET_HASH_SIZE 67
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;
1048 int leaves_allocated;
1049 int charsets_allocated;
1052 static FcCharLeafEnt *
1053 FcCharLeafEntCreate (FcCharSetFreezer *freezer)
1055 if (!freezer->leaf_remain)
1057 FcCharLeafEnt **newBlocks;
1059 freezer->leaf_block_count++;
1060 newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
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)
1067 freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
1069 freezer->leaf_remain--;
1070 freezer->leaves_allocated++;
1071 return freezer->current_block++;
1075 FcCharLeafHash (FcCharLeaf *leaf)
1080 for (i = 0; i < 256/32; i++)
1081 hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
1086 FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
1088 FcChar32 hash = FcCharLeafHash (leaf);
1089 FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
1092 for (ent = *bucket; ent; ent = ent->next)
1094 if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
1098 ent = FcCharLeafEntCreate(freezer);
1103 ent->next = *bucket;
1109 FcCharSetHash (FcCharSet *fcs)
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];
1124 FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
1126 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
1127 FcCharSetOrigEnt *ent;
1129 ent = malloc (sizeof (FcCharSetOrigEnt));
1133 ent->frozen = frozen;
1134 ent->next = *bucket;
1140 FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs)
1142 FcChar32 hash = FcCharSetHash (fcs);
1143 FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
1148 for (ent = *bucket; ent; ent = ent->next)
1150 if (ent->hash == hash &&
1151 ent->set.num == fcs->num &&
1152 !memcmp (FcCharSetNumbers(&ent->set),
1153 FcCharSetNumbers(fcs),
1154 fcs->num * sizeof (FcChar16)))
1159 for (i = 0; i < fcs->num; i++)
1160 if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
1167 size = (sizeof (FcCharSetEnt) +
1168 fcs->num * sizeof (FcCharLeaf *) +
1169 fcs->num * sizeof (FcChar16));
1170 ent = malloc (size);
1174 freezer->charsets_allocated++;
1176 FcRefSetConst (&ent->set.ref);
1177 ent->set.num = fcs->num;
1180 intptr_t *ent_leaves;
1182 ent->set.leaves_offset = sizeof (ent->set);
1183 ent->set.numbers_offset = (ent->set.leaves_offset +
1184 fcs->num * sizeof (intptr_t));
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));
1196 ent->set.leaves_offset = 0;
1197 ent->set.numbers_offset = 0;
1201 ent->next = *bucket;
1207 static const FcCharSet *
1208 FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
1210 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
1211 FcCharSetOrigEnt *ent;
1213 for (ent = *bucket; ent; ent = ent->next)
1214 if (ent->orig == orig)
1220 FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
1223 const FcCharSet *n = 0;
1227 b = FcCharSetCreate ();
1230 for (i = 0; i < fcs->num; i++)
1232 l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
1235 if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
1238 n = FcCharSetFreezeBase (freezer, b);
1239 if (!FcCharSetFreezeOrig (freezer, fcs, n))
1244 freezer->charsets_seen++;
1245 freezer->leaves_seen += fcs->num;
1248 free (FcCharSetLeaves (b));
1250 free (FcCharSetNumbers (b));
1257 FcCharSetFreezerCreate (void)
1259 FcCharSetFreezer *freezer;
1261 freezer = calloc (1, sizeof (FcCharSetFreezer));
1266 FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
1270 if (FcDebug() & FC_DBG_CACHE)
1272 printf ("\ncharsets %d -> %d leaves %d -> %d\n",
1273 freezer->charsets_seen, freezer->charsets_allocated,
1274 freezer->leaves_seen, freezer->leaves_allocated);
1276 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
1278 FcCharSetEnt *ent, *next;
1279 for (ent = freezer->set_hash_table[i]; ent; ent = next)
1286 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
1288 FcCharSetOrigEnt *ent, *next;
1289 for (ent = freezer->orig_hash_table[i]; ent; ent = next)
1296 for (i = 0; i < freezer->leaf_block_count; i++)
1297 free (freezer->leaf_blocks[i]);
1299 free (freezer->leaf_blocks);
1304 FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
1310 if (!FcRefIsConst (&cs->ref))
1312 if (!serialize->cs_freezer)
1314 serialize->cs_freezer = FcCharSetFreezerCreate ();
1315 if (!serialize->cs_freezer)
1318 if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
1321 cs = FcCharSetFreeze (serialize->cs_freezer, cs);
1324 leaves = FcCharSetLeaves (cs);
1325 numbers = FcCharSetNumbers (cs);
1327 if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
1329 if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
1331 if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
1333 for (i = 0; i < cs->num; i++)
1334 if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i),
1335 sizeof (FcCharLeaf)))
1341 FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
1343 FcCharSet *cs_serialized;
1344 intptr_t *leaves, *leaves_serialized;
1345 FcChar16 *numbers, *numbers_serialized;
1346 FcCharLeaf *leaf, *leaf_serialized;
1349 if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer)
1351 cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
1356 cs_serialized = FcSerializePtr (serialize, cs);
1360 FcRefSetConst (&cs_serialized->ref);
1361 cs_serialized->num = cs->num;
1365 leaves = FcCharSetLeaves (cs);
1366 leaves_serialized = FcSerializePtr (serialize, leaves);
1367 if (!leaves_serialized)
1370 cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
1373 numbers = FcCharSetNumbers (cs);
1374 numbers_serialized = FcSerializePtr (serialize, numbers);
1378 cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
1379 numbers_serialized);
1381 for (i = 0; i < cs->num; i++)
1383 leaf = FcCharSetLeaf (cs, i);
1384 leaf_serialized = FcSerializePtr (serialize, leaf);
1385 if (!leaf_serialized)
1387 *leaf_serialized = *leaf;
1388 leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
1390 numbers_serialized[i] = numbers[i];
1395 cs_serialized->leaves_offset = 0;
1396 cs_serialized->numbers_offset = 0;
1399 return cs_serialized;
1401 #define __fccharset__
1402 #include "fcaliastail.h"
1403 #undef __fccharset__