]> git.wh0rd.org - fontconfig.git/blob - src/fclist.c
Overhaul the serialization system to create one mmapable file per directory
[fontconfig.git] / src / fclist.c
1 /*
2 * $RCSId: xc/lib/fontconfig/src/fclist.c,v 1.11tsi Exp $
3 *
4 * Copyright © 2000 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 FcObjectSet *
29 FcObjectSetCreate (void)
30 {
31 FcObjectSet *os;
32
33 os = (FcObjectSet *) malloc (sizeof (FcObjectSet));
34 if (!os)
35 return 0;
36 FcMemAlloc (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
37 os->nobject = 0;
38 os->sobject = 0;
39 os->objects = 0;
40 return os;
41 }
42
43 FcBool
44 FcObjectSetAdd (FcObjectSet *os, const char *object)
45 {
46 int s;
47 const char **objects;
48 int high, low, mid, c;
49
50 if (os->nobject == os->sobject)
51 {
52 s = os->sobject + 4;
53 if (os->objects)
54 objects = (const char **) realloc ((void *) os->objects,
55 s * sizeof (const char *));
56 else
57 objects = (const char **) malloc (s * sizeof (const char *));
58 if (!objects)
59 return FcFalse;
60 if (os->sobject)
61 FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
62 FcMemAlloc (FC_MEM_OBJECTPTR, s * sizeof (const char *));
63 os->objects = objects;
64 os->sobject = s;
65 }
66 high = os->nobject - 1;
67 low = 0;
68 mid = 0;
69 c = 1;
70 object = FcObjectStaticName (object);
71 while (low <= high)
72 {
73 mid = (low + high) >> 1;
74 c = os->objects[mid] - object;
75 if (c == 0)
76 return FcTrue;
77 if (c < 0)
78 low = mid + 1;
79 else
80 high = mid - 1;
81 }
82 if (c < 0)
83 mid++;
84 memmove (os->objects + mid + 1, os->objects + mid,
85 (os->nobject - mid) * sizeof (const char *));
86 os->objects[mid] = object;
87 os->nobject++;
88 return FcTrue;
89 }
90
91 void
92 FcObjectSetDestroy (FcObjectSet *os)
93 {
94 if (os->objects)
95 {
96 FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
97 free ((void *) os->objects);
98 }
99 FcMemFree (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
100 free (os);
101 }
102
103 FcObjectSet *
104 FcObjectSetVaBuild (const char *first, va_list va)
105 {
106 FcObjectSet *ret;
107
108 FcObjectSetVapBuild (ret, first, va);
109 return ret;
110 }
111
112 FcObjectSet *
113 FcObjectSetBuild (const char *first, ...)
114 {
115 va_list va;
116 FcObjectSet *os;
117
118 va_start (va, first);
119 FcObjectSetVapBuild (os, first, va);
120 va_end (va);
121 return os;
122 }
123
124 /*
125 * Font must have a containing value for every value in the pattern
126 */
127 static FcBool
128 FcListValueListMatchAny (FcValueListPtr patOrig, /* pattern */
129 FcValueListPtr fntOrig) /* font */
130 {
131 FcValueListPtr pat, fnt;
132
133 for (pat = patOrig; FcValueListPtrU(pat);
134 pat = FcValueListPtrU(pat)->next)
135 {
136 for (fnt = fntOrig; FcValueListPtrU(fnt);
137 fnt = FcValueListPtrU(fnt)->next)
138 {
139 /*
140 * make sure the font 'contains' the pattern.
141 * (OpListing is OpContains except for strings
142 * where it requires an exact match)
143 */
144 if (FcConfigCompareValue (&FcValueListPtrU(fnt)->value,
145 FcOpListing,
146 &FcValueListPtrU(pat)->value))
147 break;
148 }
149 if (!FcValueListPtrU(fnt))
150 return FcFalse;
151 }
152 return FcTrue;
153 }
154
155 static FcBool
156 FcListValueListEqual (FcValueListPtr v1orig,
157 FcValueListPtr v2orig)
158 {
159 FcValueListPtr v1, v2;
160
161 for (v1 = v1orig; FcValueListPtrU(v1);
162 v1 = FcValueListPtrU(v1)->next)
163 {
164 for (v2 = v2orig; FcValueListPtrU(v2);
165 v2 = FcValueListPtrU(v2)->next)
166 if (FcValueEqual (FcValueCanonicalize(&FcValueListPtrU(v1)->value),
167 FcValueCanonicalize(&FcValueListPtrU(v2)->value)))
168 break;
169 if (!FcValueListPtrU(v2))
170 return FcFalse;
171 }
172 for (v2 = v2orig; FcValueListPtrU(v2);
173 v2 = FcValueListPtrU(v2)->next)
174 {
175 for (v1 = v1orig; FcValueListPtrU(v1);
176 v1 = FcValueListPtrU(v1)->next)
177 if (FcValueEqual (FcValueCanonicalize(&FcValueListPtrU(v1)->value),
178 FcValueCanonicalize(&FcValueListPtrU(v2)->value)))
179 break;
180 if (!FcValueListPtrU(v1))
181 return FcFalse;
182 }
183 return FcTrue;
184 }
185
186 static FcBool
187 FcListPatternEqual (FcPattern *p1,
188 FcPattern *p2,
189 FcObjectSet *os)
190 {
191 int i;
192 FcPatternElt *e1, *e2;
193
194 for (i = 0; i < os->nobject; i++)
195 {
196 e1 = FcPatternFindElt (p1, os->objects[i]);
197 e2 = FcPatternFindElt (p2, os->objects[i]);
198 if (!e1 && !e2)
199 continue;
200 if (!e1 || !e2)
201 return FcFalse;
202 if (!FcListValueListEqual (e1->values, e2->values))
203 return FcFalse;
204 }
205 return FcTrue;
206 }
207
208 /*
209 * FcTrue iff all objects in "p" match "font"
210 */
211
212 FcBool
213 FcListPatternMatchAny (const FcPattern *p,
214 const FcPattern *font)
215 {
216 int i;
217 FcPatternElt *e;
218
219 for (i = 0; i < p->num; i++)
220 {
221 e = FcPatternFindElt (font,
222 FcObjectPtrU((FcPatternEltU(p->elts)+i)->object));
223 if (!e)
224 return FcFalse;
225 if (!FcListValueListMatchAny ((FcPatternEltU(p->elts)+i)->values, /* pat elts */
226 e->values)) /* font elts */
227 return FcFalse;
228 }
229 return FcTrue;
230 }
231
232 static FcChar32
233 FcListMatrixHash (const FcMatrix *m)
234 {
235 int xx = (int) (m->xx * 100),
236 xy = (int) (m->xy * 100),
237 yx = (int) (m->yx * 100),
238 yy = (int) (m->yy * 100);
239
240 return ((FcChar32) xx) ^ ((FcChar32) xy) ^ ((FcChar32) yx) ^ ((FcChar32) yy);
241 }
242
243 static FcChar32
244 FcListValueHash (FcValue *value)
245 {
246 FcValue v = FcValueCanonicalize(value);
247 switch (v.type) {
248 case FcTypeVoid:
249 return 0;
250 case FcTypeInteger:
251 return (FcChar32) v.u.i;
252 case FcTypeDouble:
253 return (FcChar32) (int) v.u.d;
254 case FcTypeString:
255 return FcStrHashIgnoreCase (v.u.s);
256 case FcTypeBool:
257 return (FcChar32) v.u.b;
258 case FcTypeMatrix:
259 return FcListMatrixHash (v.u.m);
260 case FcTypeCharSet:
261 return FcCharSetCount (v.u.c);
262 case FcTypeFTFace:
263 return (long) v.u.f;
264 case FcTypeLangSet:
265 return FcLangSetHash (v.u.l);
266 }
267 return 0;
268 }
269
270 static FcChar32
271 FcListValueListHash (FcValueListPtr list)
272 {
273 FcChar32 h = 0;
274
275 while (FcValueListPtrU(list))
276 {
277 h = h ^ FcListValueHash (&FcValueListPtrU(list)->value);
278 list = FcValueListPtrU(list)->next;
279 }
280 return h;
281 }
282
283 static FcChar32
284 FcListPatternHash (FcPattern *font,
285 FcObjectSet *os)
286 {
287 int n;
288 FcPatternElt *e;
289 FcChar32 h = 0;
290
291 for (n = 0; n < os->nobject; n++)
292 {
293 e = FcPatternFindElt (font, os->objects[n]);
294 if (e)
295 h = h ^ FcListValueListHash (e->values);
296 }
297 return h;
298 }
299
300 typedef struct _FcListBucket {
301 struct _FcListBucket *next;
302 FcChar32 hash;
303 FcPattern *pattern;
304 } FcListBucket;
305
306 #define FC_LIST_HASH_SIZE 4099
307
308 typedef struct _FcListHashTable {
309 int entries;
310 FcListBucket *buckets[FC_LIST_HASH_SIZE];
311 } FcListHashTable;
312
313 static void
314 FcListHashTableInit (FcListHashTable *table)
315 {
316 table->entries = 0;
317 memset (table->buckets, '\0', sizeof (table->buckets));
318 }
319
320 static void
321 FcListHashTableCleanup (FcListHashTable *table)
322 {
323 int i;
324 FcListBucket *bucket, *next;
325
326 for (i = 0; i < FC_LIST_HASH_SIZE; i++)
327 {
328 for (bucket = table->buckets[i]; bucket; bucket = next)
329 {
330 next = bucket->next;
331 FcPatternDestroy (bucket->pattern);
332 FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
333 free (bucket);
334 }
335 table->buckets[i] = 0;
336 }
337 table->entries = 0;
338 }
339
340 static FcBool
341 FcListAppend (FcListHashTable *table,
342 FcPattern *font,
343 FcObjectSet *os)
344 {
345 int o;
346 FcPatternElt *e;
347 FcValueListPtr v;
348 FcChar32 hash;
349 FcListBucket **prev, *bucket;
350
351 hash = FcListPatternHash (font, os);
352 for (prev = &table->buckets[hash % FC_LIST_HASH_SIZE];
353 (bucket = *prev); prev = &(bucket->next))
354 {
355 if (bucket->hash == hash &&
356 FcListPatternEqual (bucket->pattern, font, os))
357 return FcTrue;
358 }
359 bucket = (FcListBucket *) malloc (sizeof (FcListBucket));
360 if (!bucket)
361 goto bail0;
362 FcMemAlloc (FC_MEM_LISTBUCK, sizeof (FcListBucket));
363 bucket->next = 0;
364 bucket->hash = hash;
365 bucket->pattern = FcPatternCreate ();
366 if (!bucket->pattern)
367 goto bail1;
368
369 for (o = 0; o < os->nobject; o++)
370 {
371 e = FcPatternFindElt (font, os->objects[o]);
372 if (e)
373 {
374 for (v = e->values; FcValueListPtrU(v);
375 v = FcValueListPtrU(v)->next)
376 {
377 if (!FcPatternAdd (bucket->pattern,
378 os->objects[o],
379 FcValueCanonicalize(&FcValueListPtrU(v)->value), FcTrue))
380 goto bail2;
381 }
382 }
383 }
384 *prev = bucket;
385 ++table->entries;
386
387 return FcTrue;
388
389 bail2:
390 FcPatternDestroy (bucket->pattern);
391 bail1:
392 FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
393 free (bucket);
394 bail0:
395 return FcFalse;
396 }
397
398 FcFontSet *
399 FcFontSetList (FcConfig *config,
400 FcFontSet **sets,
401 int nsets,
402 FcPattern *p,
403 FcObjectSet *os)
404 {
405 FcFontSet *ret;
406 FcFontSet *s;
407 int f;
408 int set;
409 FcListHashTable table;
410 int i;
411 FcListBucket *bucket;
412
413 if (!config)
414 {
415 if (!FcInitBringUptoDate ())
416 goto bail0;
417
418 config = FcConfigGetCurrent ();
419 if (!config)
420 goto bail0;
421 }
422 FcListHashTableInit (&table);
423 /*
424 * Walk all available fonts adding those that
425 * match to the hash table
426 */
427 for (set = 0; set < nsets; set++)
428 {
429 s = sets[set];
430 if (!s)
431 continue;
432 for (f = 0; f < s->nfont; f++)
433 if (FcListPatternMatchAny (p, /* pattern */
434 s->fonts[f])) /* font */
435 if (!FcListAppend (&table, s->fonts[f], os))
436 goto bail1;
437 }
438 #if 0
439 {
440 int max = 0;
441 int full = 0;
442 int ents = 0;
443 int len;
444 for (i = 0; i < FC_LIST_HASH_SIZE; i++)
445 {
446 if ((bucket = table.buckets[i]))
447 {
448 len = 0;
449 for (; bucket; bucket = bucket->next)
450 {
451 ents++;
452 len++;
453 }
454 if (len > max)
455 max = len;
456 full++;
457 }
458 }
459 printf ("used: %d max: %d avg: %g\n", full, max,
460 (double) ents / FC_LIST_HASH_SIZE);
461 }
462 #endif
463 /*
464 * Walk the hash table and build
465 * a font set
466 */
467 ret = FcFontSetCreate ();
468 if (!ret)
469 goto bail0;
470 for (i = 0; i < FC_LIST_HASH_SIZE; i++)
471 while ((bucket = table.buckets[i]))
472 {
473 if (!FcFontSetAdd (ret, bucket->pattern))
474 goto bail2;
475 table.buckets[i] = bucket->next;
476 FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
477 free (bucket);
478 }
479
480 return ret;
481
482 bail2:
483 FcFontSetDestroy (ret);
484 bail1:
485 FcListHashTableCleanup (&table);
486 bail0:
487 return 0;
488 }
489
490 FcFontSet *
491 FcFontList (FcConfig *config,
492 FcPattern *p,
493 FcObjectSet *os)
494 {
495 FcFontSet *sets[2];
496 int nsets;
497
498 if (!config)
499 {
500 config = FcConfigGetCurrent ();
501 if (!config)
502 return 0;
503 }
504 nsets = 0;
505 if (config->fonts[FcSetSystem])
506 sets[nsets++] = config->fonts[FcSetSystem];
507 if (config->fonts[FcSetApplication])
508 sets[nsets++] = config->fonts[FcSetApplication];
509 return FcFontSetList (config, sets, nsets, p, os);
510 }