]> git.wh0rd.org - fontconfig.git/blame - src/fclist.c
Destroy the global cache file if it's terminally broken. (reported by Mike
[fontconfig.git] / src / fclist.c
CommitLineData
24330d27 1/*
793e946c 2 * $RCSId: xc/lib/fontconfig/src/fclist.c,v 1.11tsi Exp $
24330d27 3 *
46b51147 4 * Copyright © 2000 Keith Packard
24330d27
KP
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
28FcObjectSet *
29FcObjectSetCreate (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
43FcBool
44FcObjectSetAdd (FcObjectSet *os, const char *object)
45{
46 int s;
4262e0b3 47 const char **objects;
e9be9cd1 48 int high, low, mid, c;
24330d27
KP
49
50 if (os->nobject == os->sobject)
51 {
52 s = os->sobject + 4;
53 if (os->objects)
4262e0b3
PL
54 objects = (const char **) realloc ((void *) os->objects,
55 s * sizeof (const char *));
24330d27 56 else
4262e0b3 57 objects = (const char **) malloc (s * sizeof (const char *));
24330d27
KP
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 }
e9be9cd1
KP
66 high = os->nobject - 1;
67 low = 0;
68 mid = 0;
69 c = 1;
8245771d 70 object = (char *)FcStrStaticName ((FcChar8 *)object);
e9be9cd1
KP
71 while (low <= high)
72 {
73 mid = (low + high) >> 1;
4262e0b3 74 c = os->objects[mid] - object;
e9be9cd1
KP
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++;
5b1bfa5d 84 memmove (os->objects + mid + 1, os->objects + mid,
4262e0b3
PL
85 (os->nobject - mid) * sizeof (const char *));
86 os->objects[mid] = object;
e9be9cd1 87 os->nobject++;
24330d27
KP
88 return FcTrue;
89}
90
91void
92FcObjectSetDestroy (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
103FcObjectSet *
104FcObjectSetVaBuild (const char *first, va_list va)
105{
106 FcObjectSet *ret;
107
108 FcObjectSetVapBuild (ret, first, va);
109 return ret;
110}
111
112FcObjectSet *
113FcObjectSetBuild (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
74a623e0
KP
124/*
125 * Font must have a containing value for every value in the pattern
126 */
24330d27 127static FcBool
cd2ec1a9
PL
128FcListValueListMatchAny (FcValueListPtr patOrig, /* pattern */
129 FcValueListPtr fntOrig) /* font */
24330d27 130{
cd2ec1a9 131 FcValueListPtr pat, fnt;
24330d27 132
cd2ec1a9
PL
133 for (pat = patOrig; FcValueListPtrU(pat);
134 pat = FcValueListPtrU(pat)->next)
74a623e0 135 {
cd2ec1a9
PL
136 for (fnt = fntOrig; FcValueListPtrU(fnt);
137 fnt = FcValueListPtrU(fnt)->next)
74a623e0
KP
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 */
4262e0b3 144 if (FcConfigCompareValue (&FcValueListPtrU(fnt)->value,
74a623e0 145 FcOpListing,
4262e0b3 146 &FcValueListPtrU(pat)->value))
74a623e0
KP
147 break;
148 }
cd2ec1a9 149 if (!FcValueListPtrU(fnt))
74a623e0
KP
150 return FcFalse;
151 }
152 return FcTrue;
24330d27
KP
153}
154
155static FcBool
cd2ec1a9
PL
156FcListValueListEqual (FcValueListPtr v1orig,
157 FcValueListPtr v2orig)
24330d27 158{
cd2ec1a9 159 FcValueListPtr v1, v2;
24330d27 160
cd2ec1a9
PL
161 for (v1 = v1orig; FcValueListPtrU(v1);
162 v1 = FcValueListPtrU(v1)->next)
24330d27 163 {
cd2ec1a9
PL
164 for (v2 = v2orig; FcValueListPtrU(v2);
165 v2 = FcValueListPtrU(v2)->next)
4262e0b3
PL
166 if (FcValueEqual (FcValueCanonicalize(&FcValueListPtrU(v1)->value),
167 FcValueCanonicalize(&FcValueListPtrU(v2)->value)))
24330d27 168 break;
cd2ec1a9 169 if (!FcValueListPtrU(v2))
24330d27
KP
170 return FcFalse;
171 }
cd2ec1a9
PL
172 for (v2 = v2orig; FcValueListPtrU(v2);
173 v2 = FcValueListPtrU(v2)->next)
24330d27 174 {
cd2ec1a9
PL
175 for (v1 = v1orig; FcValueListPtrU(v1);
176 v1 = FcValueListPtrU(v1)->next)
4262e0b3
PL
177 if (FcValueEqual (FcValueCanonicalize(&FcValueListPtrU(v1)->value),
178 FcValueCanonicalize(&FcValueListPtrU(v2)->value)))
24330d27 179 break;
cd2ec1a9 180 if (!FcValueListPtrU(v1))
24330d27
KP
181 return FcFalse;
182 }
183 return FcTrue;
184}
185
24330d27 186static FcBool
e9be9cd1
KP
187FcListPatternEqual (FcPattern *p1,
188 FcPattern *p2,
189 FcObjectSet *os)
24330d27
KP
190{
191 int i;
e9be9cd1 192 FcPatternElt *e1, *e2;
24330d27 193
e9be9cd1 194 for (i = 0; i < os->nobject; i++)
24330d27 195 {
4262e0b3
PL
196 e1 = FcPatternFindElt (p1, os->objects[i]);
197 e2 = FcPatternFindElt (p2, os->objects[i]);
e9be9cd1 198 if (!e1 && !e2)
47d4f950 199 continue;
e9be9cd1 200 if (!e1 || !e2)
24330d27 201 return FcFalse;
e9be9cd1 202 if (!FcListValueListEqual (e1->values, e2->values))
24330d27
KP
203 return FcFalse;
204 }
205 return FcTrue;
206}
207
e9be9cd1
KP
208/*
209 * FcTrue iff all objects in "p" match "font"
210 */
211
4f27c1c0
KP
212FcBool
213FcListPatternMatchAny (const FcPattern *p,
214 const FcPattern *font)
24330d27
KP
215{
216 int i;
e9be9cd1 217 FcPatternElt *e;
24330d27 218
e9be9cd1 219 for (i = 0; i < p->num; i++)
24330d27 220 {
cd2ec1a9
PL
221 e = FcPatternFindElt (font,
222 FcObjectPtrU((FcPatternEltU(p->elts)+i)->object));
e9be9cd1 223 if (!e)
24330d27 224 return FcFalse;
cd2ec1a9 225 if (!FcListValueListMatchAny ((FcPatternEltU(p->elts)+i)->values, /* pat elts */
74a623e0 226 e->values)) /* font elts */
24330d27
KP
227 return FcFalse;
228 }
229 return FcTrue;
230}
231
24330d27
KP
232static FcChar32
233FcListMatrixHash (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
243static FcChar32
4262e0b3 244FcListValueHash (FcValue *value)
24330d27 245{
4262e0b3 246 FcValue v = FcValueCanonicalize(value);
24330d27
KP
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:
4262e0b3 255 return FcStrHashIgnoreCase (v.u.s);
24330d27
KP
256 case FcTypeBool:
257 return (FcChar32) v.u.b;
258 case FcTypeMatrix:
4262e0b3 259 return FcListMatrixHash (v.u.m);
24330d27 260 case FcTypeCharSet:
4262e0b3 261 return FcCharSetCount (v.u.c);
88c747e2 262 case FcTypeFTFace:
d1bec8c6 263 return (long) v.u.f;
d8d73958 264 case FcTypeLangSet:
4262e0b3 265 return FcLangSetHash (v.u.l);
24330d27
KP
266 }
267 return 0;
268}
269
270static FcChar32
cd2ec1a9 271FcListValueListHash (FcValueListPtr list)
24330d27
KP
272{
273 FcChar32 h = 0;
274
cd2ec1a9 275 while (FcValueListPtrU(list))
24330d27 276 {
4262e0b3 277 h = h ^ FcListValueHash (&FcValueListPtrU(list)->value);
cd2ec1a9 278 list = FcValueListPtrU(list)->next;
24330d27
KP
279 }
280 return h;
281}
282
283static FcChar32
284FcListPatternHash (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 {
4262e0b3 293 e = FcPatternFindElt (font, os->objects[n]);
24330d27
KP
294 if (e)
295 h = h ^ FcListValueListHash (e->values);
296 }
297 return h;
298}
299
300typedef struct _FcListBucket {
301 struct _FcListBucket *next;
302 FcChar32 hash;
303 FcPattern *pattern;
304} FcListBucket;
305
306#define FC_LIST_HASH_SIZE 4099
307
308typedef struct _FcListHashTable {
309 int entries;
310 FcListBucket *buckets[FC_LIST_HASH_SIZE];
311} FcListHashTable;
312
313static void
314FcListHashTableInit (FcListHashTable *table)
315{
316 table->entries = 0;
317 memset (table->buckets, '\0', sizeof (table->buckets));
318}
319
320static void
321FcListHashTableCleanup (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
340static FcBool
341FcListAppend (FcListHashTable *table,
342 FcPattern *font,
343 FcObjectSet *os)
344{
345 int o;
346 FcPatternElt *e;
cd2ec1a9 347 FcValueListPtr v;
24330d27
KP
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 {
4262e0b3 371 e = FcPatternFindElt (font, os->objects[o]);
24330d27
KP
372 if (e)
373 {
cd2ec1a9
PL
374 for (v = e->values; FcValueListPtrU(v);
375 v = FcValueListPtrU(v)->next)
24330d27
KP
376 {
377 if (!FcPatternAdd (bucket->pattern,
4262e0b3
PL
378 os->objects[o],
379 FcValueCanonicalize(&FcValueListPtrU(v)->value), FcTrue))
24330d27
KP
380 goto bail2;
381 }
382 }
383 }
384 *prev = bucket;
385 ++table->entries;
386
387 return FcTrue;
388
389bail2:
390 FcPatternDestroy (bucket->pattern);
391bail1:
392 FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
393 free (bucket);
394bail0:
395 return FcFalse;
396}
397
398FcFontSet *
80c053b7
KP
399FcFontSetList (FcConfig *config,
400 FcFontSet **sets,
401 int nsets,
402 FcPattern *p,
403 FcObjectSet *os)
24330d27
KP
404{
405 FcFontSet *ret;
406 FcFontSet *s;
407 int f;
80c053b7 408 int set;
24330d27
KP
409 FcListHashTable table;
410 int i;
411 FcListBucket *bucket;
412
413 if (!config)
414 {
179c3995
KP
415 if (!FcInitBringUptoDate ())
416 goto bail0;
417
24330d27
KP
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 */
80c053b7 427 for (set = 0; set < nsets; set++)
24330d27 428 {
80c053b7 429 s = sets[set];
24330d27
KP
430 if (!s)
431 continue;
432 for (f = 0; f < s->nfont; f++)
74a623e0
KP
433 if (FcListPatternMatchAny (p, /* pattern */
434 s->fonts[f])) /* font */
24330d27
KP
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
482bail2:
483 FcFontSetDestroy (ret);
484bail1:
485 FcListHashTableCleanup (&table);
486bail0:
487 return 0;
488}
80c053b7
KP
489
490FcFontSet *
491FcFontList (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}