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