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)
178 unsigned int alloced = fcs->num;
179 intptr_t *new_leaves, distance;
182 new_leaves = realloc (leaves, alloced * sizeof (*leaves));
185 numbers = realloc (numbers, alloced * sizeof (*numbers));
188 /* Revert the reallocation of leaves */
189 leaves = realloc (new_leaves, (alloced / 2) * sizeof (*new_leaves));
190 /* unlikely to fail though */
193 fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
196 distance = (intptr_t) new_leaves - (intptr_t) leaves;
197 if (new_leaves && distance)
200 for (i = 0; i < fcs->num; i++)
201 new_leaves[i] -= distance;
206 fcs->leaves_offset = FcPtrToOffset (fcs, leaves);
207 fcs->numbers_offset = FcPtrToOffset (fcs, numbers);
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);
221 * Locate the leaf containing the specified char, creating it
226 FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
231 pos = FcCharSetFindLeafPos (fcs, ucs4);
233 return FcCharSetLeaf(fcs, pos);
235 leaf = calloc (1, sizeof (FcCharLeaf));
240 if (!FcCharSetPutLeaf (fcs, ucs4, leaf, pos))
249 FcCharSetInsertLeaf (FcCharSet *fcs, FcChar32 ucs4, FcCharLeaf *leaf)
253 pos = FcCharSetFindLeafPos (fcs, ucs4);
256 free (FcCharSetLeaf (fcs, pos));
257 FcCharSetLeaves(fcs)[pos] = FcPtrToOffset (FcCharSetLeaves(fcs),
262 return FcCharSetPutLeaf (fcs, ucs4, leaf, pos);
266 FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
271 if (fcs == NULL || FcRefIsConst (&fcs->ref))
273 leaf = FcCharSetFindLeafCreate (fcs, ucs4);
276 b = &leaf->map[(ucs4 & 0xff) >> 5];
277 *b |= (1U << (ucs4 & 0x1f));
282 FcCharSetDelChar (FcCharSet *fcs, FcChar32 ucs4)
287 if (fcs == NULL || FcRefIsConst (&fcs->ref))
289 leaf = FcCharSetFindLeaf (fcs, ucs4);
292 b = &leaf->map[(ucs4 & 0xff) >> 5];
293 *b &= ~(1U << (ucs4 & 0x1f));
294 /* We don't bother removing the leaf if it's empty */
299 * An iterator for the leaves of a charset
302 typedef struct _fcCharSetIter {
309 * Set iter->leaf to the leaf containing iter->ucs4 or higher
313 FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
315 int pos = FcCharSetFindLeafPos (fcs, iter->ucs4);
326 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
328 iter->leaf = FcCharSetLeaf(fcs, pos);
333 FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
335 int pos = iter->pos + 1;
343 iter->ucs4 = (FcChar32) FcCharSetNumbers(fcs)[pos] << 8;
344 iter->leaf = FcCharSetLeaf(fcs, pos);
351 FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
355 FcCharSetIterSet (fcs, iter);
359 FcCharSetCopy (FcCharSet *src)
363 if (!FcRefIsConst (&src->ref))
364 FcRefInc (&src->ref);
366 FcCacheObjectReference (src);
372 FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
374 FcCharSetIter ai, bi;
381 for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
383 FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi))
385 if (ai.ucs4 != bi.ucs4)
387 for (i = 0; i < 256/32; i++)
388 if (ai.leaf->map[i] != bi.leaf->map[i])
391 return ai.leaf == bi.leaf;
395 FcCharSetAddLeaf (FcCharSet *fcs,
399 FcCharLeaf *new = FcCharSetFindLeafCreate (fcs, ucs4);
407 FcCharSetOperate (const FcCharSet *a,
409 FcBool (*overlap) (FcCharLeaf *result,
410 const FcCharLeaf *al,
411 const FcCharLeaf *bl),
416 FcCharSetIter ai, bi;
420 fcs = FcCharSetCreate ();
423 FcCharSetIterStart (a, &ai);
424 FcCharSetIterStart (b, &bi);
425 while ((ai.leaf || (bonly && bi.leaf)) && (bi.leaf || (aonly && ai.leaf)))
427 if (ai.ucs4 < bi.ucs4)
431 if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
433 FcCharSetIterNext (a, &ai);
438 FcCharSetIterSet (a, &ai);
441 else if (bi.ucs4 < ai.ucs4 )
445 if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
447 FcCharSetIterNext (b, &bi);
452 FcCharSetIterSet (b, &bi);
459 if ((*overlap) (&leaf, ai.leaf, bi.leaf))
461 if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
464 FcCharSetIterNext (a, &ai);
465 FcCharSetIterNext (b, &bi);
470 FcCharSetDestroy (fcs);
476 FcCharSetIntersectLeaf (FcCharLeaf *result,
477 const FcCharLeaf *al,
478 const FcCharLeaf *bl)
481 FcBool nonempty = FcFalse;
483 for (i = 0; i < 256/32; i++)
484 if ((result->map[i] = al->map[i] & bl->map[i]))
490 FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
492 return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
496 FcCharSetUnionLeaf (FcCharLeaf *result,
497 const FcCharLeaf *al,
498 const FcCharLeaf *bl)
502 for (i = 0; i < 256/32; i++)
503 result->map[i] = al->map[i] | bl->map[i];
508 FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
510 return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
514 FcCharSetMerge (FcCharSet *a, const FcCharSet *b, FcBool *changed)
522 if (FcRefIsConst (&a->ref)) {
529 *changed = !FcCharSetIsSubset(b, a);
536 an = ai < a->num ? FcCharSetNumbers(a)[ai] : ~0;
537 bn = FcCharSetNumbers(b)[bi];
541 ai = FcCharSetFindLeafForward (a, ai + 1, bn);
547 FcCharLeaf *bl = FcCharSetLeaf(b, bi);
550 if (!FcCharSetAddLeaf (a, bn << 8, bl))
555 FcCharLeaf *al = FcCharSetLeaf(a, ai);
556 FcCharSetUnionLeaf (al, al, bl);
568 FcCharSetSubtractLeaf (FcCharLeaf *result,
569 const FcCharLeaf *al,
570 const FcCharLeaf *bl)
573 FcBool nonempty = FcFalse;
575 for (i = 0; i < 256/32; i++)
576 if ((result->map[i] = al->map[i] & ~bl->map[i]))
582 FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
584 return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
588 FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
594 leaf = FcCharSetFindLeaf (fcs, ucs4);
597 return (leaf->map[(ucs4 & 0xff) >> 5] & (1U << (ucs4 & 0x1f))) != 0;
601 FcCharSetPopCount (FcChar32 c1)
603 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
604 return __builtin_popcount (c1);
607 FcChar32 c2 = (c1 >> 1) & 033333333333;
608 c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
609 return (((c2 + (c2 >> 3)) & 030707070707) % 077);
614 FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
616 FcCharSetIter ai, bi;
621 FcCharSetIterStart (a, &ai);
622 FcCharSetIterStart (b, &bi);
623 while (ai.leaf && bi.leaf)
625 if (ai.ucs4 == bi.ucs4)
627 FcChar32 *am = ai.leaf->map;
628 FcChar32 *bm = bi.leaf->map;
631 count += FcCharSetPopCount (*am++ & *bm++);
632 FcCharSetIterNext (a, &ai);
634 else if (ai.ucs4 < bi.ucs4)
637 FcCharSetIterSet (a, &ai);
639 if (bi.ucs4 < ai.ucs4)
642 FcCharSetIterSet (b, &bi);
650 FcCharSetCount (const FcCharSet *a)
657 for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
660 FcChar32 *am = ai.leaf->map;
663 count += FcCharSetPopCount (*am++);
670 FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
672 FcCharSetIter ai, bi;
677 FcCharSetIterStart (a, &ai);
678 FcCharSetIterStart (b, &bi);
681 if (ai.ucs4 <= bi.ucs4)
683 FcChar32 *am = ai.leaf->map;
685 if (ai.ucs4 == bi.ucs4)
687 FcChar32 *bm = bi.leaf->map;
689 count += FcCharSetPopCount (*am++ & ~*bm++);
694 count += FcCharSetPopCount (*am++);
696 FcCharSetIterNext (a, &ai);
701 FcCharSetIterSet (b, &bi);
709 * return FcTrue iff a is a subset of b
712 FcCharSetIsSubset (const FcCharSet *a, const FcCharSet *b)
723 while (ai < a->num && bi < b->num)
725 an = FcCharSetNumbers(a)[ai];
726 bn = FcCharSetNumbers(b)[bi];
728 * Check matching pages
732 FcChar32 *am = FcCharSetLeaf(a, ai)->map;
733 FcChar32 *bm = FcCharSetLeaf(b, bi)->map;
739 * Does am have any bits not in bm?
749 * Does a have any pages not in b?
755 bi = FcCharSetFindLeafForward (b, bi + 1, an);
761 * did we look at every page?
767 * These two functions efficiently walk the entire charmap for
768 * other software (like pango) that want their own copy
772 FcCharSetNextPage (const FcCharSet *a,
773 FcChar32 map[FC_CHARSET_MAP_SIZE],
780 return FC_CHARSET_DONE;
782 FcCharSetIterSet (a, &ai);
784 return FC_CHARSET_DONE;
787 * Save current information
790 memcpy (map, ai.leaf->map, sizeof (ai.leaf->map));
794 FcCharSetIterNext (a, &ai);
801 FcCharSetFirstPage (const FcCharSet *a,
802 FcChar32 map[FC_CHARSET_MAP_SIZE],
806 return FcCharSetNextPage (a, map, next);
810 * old coverage API, rather hard to use correctly
814 FcCharSetCoverage (const FcCharSet *a, FcChar32 page, FcChar32 *result)
819 FcCharSetIterSet (a, &ai);
822 memset (result, '\0', 256 / 8);
827 memcpy (result, ai.leaf->map, sizeof (ai.leaf->map));
828 FcCharSetIterNext (a, &ai);
835 FcNameParseRange (FcChar8 **string, FcChar32 *pfirst, FcChar32 *plast)
837 char *s = (char *) *string;
845 first = last = strtol (s, &s, 16);
854 last = strtol (s, &s, 16);
859 if (s == t || first < 0 || last < 0 || last < first || last > 0x10ffff)
862 *string = (FcChar8 *) s;
869 FcNameParseCharSet (FcChar8 *string)
872 FcChar32 first, last;
874 c = FcCharSetCreate ();
881 if (!FcNameParseRange (&string, &first, &last))
884 for (u = first; u < last + 1; u++)
885 FcCharSetAddChar (c, u);
889 FcCharSetDestroy (c);
895 FcNameUnparseUnicode (FcStrBuf *buf, FcChar32 u)
897 FcChar8 buf_static[64];
898 snprintf ((char *) buf_static, sizeof (buf_static), "%x", u);
899 FcStrBufString (buf, buf_static);
903 FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c)
906 FcChar32 first, last;
912 first = last = 0x7FFFFFFF;
914 for (FcCharSetIterStart (c, &ci);
916 FcCharSetIterNext (c, &ci))
918 for (i = 0; i < 256/32; i++)
920 FcChar32 bits = ci.leaf->map[i];
921 FcChar32 u = ci.ucs4 + i * 32;
931 FcStrBufChar (buf, '-');
932 FcNameUnparseUnicode (buf, last);
934 if (last != 0x7FFFFFFF)
935 FcStrBufChar (buf, ' ');
936 /* Start new range. */
938 FcNameUnparseUnicode (buf, u);
949 FcStrBufChar (buf, '-');
950 FcNameUnparseUnicode (buf, last);
956 FcCharSetIter ci, checki;
958 /* null terminate for parser */
959 FcStrBufChar (buf, '\0');
960 /* step back over null for life after test */
962 check = FcNameParseCharSet (buf->buf + len);
963 FcCharSetIterStart (c, &ci);
964 FcCharSetIterStart (check, &checki);
965 while (ci.leaf || checki.leaf)
967 if (ci.ucs4 < checki.ucs4)
969 printf ("Missing leaf node at 0x%x\n", ci.ucs4);
970 FcCharSetIterNext (c, &ci);
972 else if (checki.ucs4 < ci.ucs4)
974 printf ("Extra leaf node at 0x%x\n", checki.ucs4);
975 FcCharSetIterNext (check, &checki);
980 FcChar32 *cm = ci.leaf->map;
981 FcChar32 *checkm = checki.leaf->map;
983 for (i = 0; i < 256; i += 32)
986 printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
987 ci.ucs4 + i, *cm, *checkm);
991 FcCharSetIterNext (c, &ci);
992 FcCharSetIterNext (check, &checki);
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);
1006 typedef struct _FcCharLeafEnt FcCharLeafEnt;
1008 struct _FcCharLeafEnt {
1009 FcCharLeafEnt *next;
1014 #define FC_CHAR_LEAF_BLOCK (4096 / sizeof (FcCharLeafEnt))
1015 #define FC_CHAR_LEAF_HASH_SIZE 257
1017 typedef struct _FcCharSetEnt FcCharSetEnt;
1019 struct _FcCharSetEnt {
1025 typedef struct _FcCharSetOrigEnt FcCharSetOrigEnt;
1027 struct _FcCharSetOrigEnt {
1028 FcCharSetOrigEnt *next;
1029 const FcCharSet *orig;
1030 const FcCharSet *frozen;
1033 #define FC_CHAR_SET_HASH_SIZE 67
1035 struct _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;
1045 int leaves_allocated;
1046 int charsets_allocated;
1049 static FcCharLeafEnt *
1050 FcCharLeafEntCreate (FcCharSetFreezer *freezer)
1052 if (!freezer->leaf_remain)
1054 FcCharLeafEnt **newBlocks;
1056 freezer->leaf_block_count++;
1057 newBlocks = realloc (freezer->leaf_blocks, freezer->leaf_block_count * sizeof (FcCharLeafEnt *));
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)
1064 freezer->leaf_remain = FC_CHAR_LEAF_BLOCK;
1066 freezer->leaf_remain--;
1067 freezer->leaves_allocated++;
1068 return freezer->current_block++;
1072 FcCharLeafHash (FcCharLeaf *leaf)
1077 for (i = 0; i < 256/32; i++)
1078 hash = ((hash << 1) | (hash >> 31)) ^ leaf->map[i];
1083 FcCharSetFreezeLeaf (FcCharSetFreezer *freezer, FcCharLeaf *leaf)
1085 FcChar32 hash = FcCharLeafHash (leaf);
1086 FcCharLeafEnt **bucket = &freezer->leaf_hash_table[hash % FC_CHAR_LEAF_HASH_SIZE];
1089 for (ent = *bucket; ent; ent = ent->next)
1091 if (ent->hash == hash && !memcmp (&ent->leaf, leaf, sizeof (FcCharLeaf)))
1095 ent = FcCharLeafEntCreate(freezer);
1100 ent->next = *bucket;
1106 FcCharSetHash (FcCharSet *fcs)
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];
1121 FcCharSetFreezeOrig (FcCharSetFreezer *freezer, const FcCharSet *orig, const FcCharSet *frozen)
1123 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
1124 FcCharSetOrigEnt *ent;
1126 ent = malloc (sizeof (FcCharSetOrigEnt));
1130 ent->frozen = frozen;
1131 ent->next = *bucket;
1137 FcCharSetFreezeBase (FcCharSetFreezer *freezer, FcCharSet *fcs)
1139 FcChar32 hash = FcCharSetHash (fcs);
1140 FcCharSetEnt **bucket = &freezer->set_hash_table[hash % FC_CHAR_SET_HASH_SIZE];
1145 for (ent = *bucket; ent; ent = ent->next)
1147 if (ent->hash == hash &&
1148 ent->set.num == fcs->num &&
1149 !memcmp (FcCharSetNumbers(&ent->set),
1150 FcCharSetNumbers(fcs),
1151 fcs->num * sizeof (FcChar16)))
1156 for (i = 0; i < fcs->num; i++)
1157 if (FcCharSetLeaf(&ent->set, i) != FcCharSetLeaf(fcs, i))
1164 size = (sizeof (FcCharSetEnt) +
1165 fcs->num * sizeof (FcCharLeaf *) +
1166 fcs->num * sizeof (FcChar16));
1167 ent = malloc (size);
1171 freezer->charsets_allocated++;
1173 FcRefSetConst (&ent->set.ref);
1174 ent->set.num = fcs->num;
1177 intptr_t *ent_leaves;
1179 ent->set.leaves_offset = sizeof (ent->set);
1180 ent->set.numbers_offset = (ent->set.leaves_offset +
1181 fcs->num * sizeof (intptr_t));
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));
1193 ent->set.leaves_offset = 0;
1194 ent->set.numbers_offset = 0;
1198 ent->next = *bucket;
1204 static const FcCharSet *
1205 FcCharSetFindFrozen (FcCharSetFreezer *freezer, const FcCharSet *orig)
1207 FcCharSetOrigEnt **bucket = &freezer->orig_hash_table[((uintptr_t) orig) % FC_CHAR_SET_HASH_SIZE];
1208 FcCharSetOrigEnt *ent;
1210 for (ent = *bucket; ent; ent = ent->next)
1211 if (ent->orig == orig)
1217 FcCharSetFreeze (FcCharSetFreezer *freezer, const FcCharSet *fcs)
1220 const FcCharSet *n = 0;
1224 b = FcCharSetCreate ();
1227 for (i = 0; i < fcs->num; i++)
1229 l = FcCharSetFreezeLeaf (freezer, FcCharSetLeaf(fcs, i));
1232 if (!FcCharSetInsertLeaf (b, FcCharSetNumbers(fcs)[i] << 8, l))
1235 n = FcCharSetFreezeBase (freezer, b);
1236 if (!FcCharSetFreezeOrig (freezer, fcs, n))
1241 freezer->charsets_seen++;
1242 freezer->leaves_seen += fcs->num;
1245 free (FcCharSetLeaves (b));
1247 free (FcCharSetNumbers (b));
1254 FcCharSetFreezerCreate (void)
1256 FcCharSetFreezer *freezer;
1258 freezer = calloc (1, sizeof (FcCharSetFreezer));
1263 FcCharSetFreezerDestroy (FcCharSetFreezer *freezer)
1267 if (FcDebug() & FC_DBG_CACHE)
1269 printf ("\ncharsets %d -> %d leaves %d -> %d\n",
1270 freezer->charsets_seen, freezer->charsets_allocated,
1271 freezer->leaves_seen, freezer->leaves_allocated);
1273 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
1275 FcCharSetEnt *ent, *next;
1276 for (ent = freezer->set_hash_table[i]; ent; ent = next)
1283 for (i = 0; i < FC_CHAR_SET_HASH_SIZE; i++)
1285 FcCharSetOrigEnt *ent, *next;
1286 for (ent = freezer->orig_hash_table[i]; ent; ent = next)
1293 for (i = 0; i < freezer->leaf_block_count; i++)
1294 free (freezer->leaf_blocks[i]);
1296 free (freezer->leaf_blocks);
1301 FcCharSetSerializeAlloc (FcSerialize *serialize, const FcCharSet *cs)
1307 if (!FcRefIsConst (&cs->ref))
1309 if (!serialize->cs_freezer)
1311 serialize->cs_freezer = FcCharSetFreezerCreate ();
1312 if (!serialize->cs_freezer)
1315 if (FcCharSetFindFrozen (serialize->cs_freezer, cs))
1318 cs = FcCharSetFreeze (serialize->cs_freezer, cs);
1321 leaves = FcCharSetLeaves (cs);
1322 numbers = FcCharSetNumbers (cs);
1324 if (!FcSerializeAlloc (serialize, cs, sizeof (FcCharSet)))
1326 if (!FcSerializeAlloc (serialize, leaves, cs->num * sizeof (intptr_t)))
1328 if (!FcSerializeAlloc (serialize, numbers, cs->num * sizeof (FcChar16)))
1330 for (i = 0; i < cs->num; i++)
1331 if (!FcSerializeAlloc (serialize, FcCharSetLeaf(cs, i),
1332 sizeof (FcCharLeaf)))
1338 FcCharSetSerialize(FcSerialize *serialize, const FcCharSet *cs)
1340 FcCharSet *cs_serialized;
1341 intptr_t *leaves, *leaves_serialized;
1342 FcChar16 *numbers, *numbers_serialized;
1343 FcCharLeaf *leaf, *leaf_serialized;
1346 if (!FcRefIsConst (&cs->ref) && serialize->cs_freezer)
1348 cs = FcCharSetFindFrozen (serialize->cs_freezer, cs);
1353 cs_serialized = FcSerializePtr (serialize, cs);
1357 FcRefSetConst (&cs_serialized->ref);
1358 cs_serialized->num = cs->num;
1362 leaves = FcCharSetLeaves (cs);
1363 leaves_serialized = FcSerializePtr (serialize, leaves);
1364 if (!leaves_serialized)
1367 cs_serialized->leaves_offset = FcPtrToOffset (cs_serialized,
1370 numbers = FcCharSetNumbers (cs);
1371 numbers_serialized = FcSerializePtr (serialize, numbers);
1375 cs_serialized->numbers_offset = FcPtrToOffset (cs_serialized,
1376 numbers_serialized);
1378 for (i = 0; i < cs->num; i++)
1380 leaf = FcCharSetLeaf (cs, i);
1381 leaf_serialized = FcSerializePtr (serialize, leaf);
1382 if (!leaf_serialized)
1384 *leaf_serialized = *leaf;
1385 leaves_serialized[i] = FcPtrToOffset (leaves_serialized,
1387 numbers_serialized[i] = numbers[i];
1392 cs_serialized->leaves_offset = 0;
1393 cs_serialized->numbers_offset = 0;
1396 return cs_serialized;
1398 #define __fccharset__
1399 #include "fcaliastail.h"
1400 #undef __fccharset__