]> git.wh0rd.org - fontconfig.git/blob - src/fclist.c
Eliminate .so PLT entries for local symbols. (thanks to Arjan van de Ven)
[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 "fcint.h"
26 #include <stdlib.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 = (char *)FcStrStaticName ((FcChar8 *)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; pat != NULL; pat = FcValueListNext(pat))
134 {
135 for (fnt = fntOrig; fnt != NULL; fnt = FcValueListNext(fnt))
136 {
137 /*
138 * make sure the font 'contains' the pattern.
139 * (OpListing is OpContains except for strings
140 * where it requires an exact match)
141 */
142 if (FcConfigCompareValue (&fnt->value,
143 FcOpListing,
144 &pat->value))
145 break;
146 }
147 if (fnt == NULL)
148 return FcFalse;
149 }
150 return FcTrue;
151 }
152
153 static FcBool
154 FcListValueListEqual (FcValueListPtr v1orig,
155 FcValueListPtr v2orig)
156 {
157 FcValueListPtr v1, v2;
158
159 for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
160 {
161 for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
162 if (FcValueEqual (FcValueCanonicalize(&(v1)->value),
163 FcValueCanonicalize(&(v2)->value)))
164 break;
165 if (v2 == NULL)
166 return FcFalse;
167 }
168 for (v2 = v2orig; v2 != NULL; v2 = FcValueListNext(v2))
169 {
170 for (v1 = v1orig; v1 != NULL; v1 = FcValueListNext(v1))
171 if (FcValueEqual (FcValueCanonicalize(&v1->value),
172 FcValueCanonicalize(&v2->value)))
173 break;
174 if (v1 == NULL)
175 return FcFalse;
176 }
177 return FcTrue;
178 }
179
180 static FcBool
181 FcListPatternEqual (FcPattern *p1,
182 FcPattern *p2,
183 FcObjectSet *os)
184 {
185 int i;
186 FcPatternElt *e1, *e2;
187
188 for (i = 0; i < os->nobject; i++)
189 {
190 e1 = FcPatternObjectFindElt (p1, FcObjectFromName (os->objects[i]));
191 e2 = FcPatternObjectFindElt (p2, FcObjectFromName (os->objects[i]));
192 if (!e1 && !e2)
193 continue;
194 if (!e1 || !e2)
195 return FcFalse;
196 if (!FcListValueListEqual (FcPatternEltValues(e1),
197 FcPatternEltValues(e2)))
198 return FcFalse;
199 }
200 return FcTrue;
201 }
202
203 /*
204 * FcTrue iff all objects in "p" match "font"
205 */
206
207 FcBool
208 FcListPatternMatchAny (const FcPattern *p,
209 const FcPattern *font)
210 {
211 int i;
212
213 for (i = 0; i < p->num; i++)
214 {
215 FcPatternElt *pe = &FcPatternElts(p)[i];
216 FcPatternElt *fe = FcPatternObjectFindElt (font, pe->object);
217 if (!fe)
218 return FcFalse;
219 if (!FcListValueListMatchAny (FcPatternEltValues(pe), /* pat elts */
220 FcPatternEltValues(fe))) /* font elts */
221 return FcFalse;
222 }
223 return FcTrue;
224 }
225
226 static FcChar32
227 FcListMatrixHash (const FcMatrix *m)
228 {
229 int xx = (int) (m->xx * 100),
230 xy = (int) (m->xy * 100),
231 yx = (int) (m->yx * 100),
232 yy = (int) (m->yy * 100);
233
234 return ((FcChar32) xx) ^ ((FcChar32) xy) ^ ((FcChar32) yx) ^ ((FcChar32) yy);
235 }
236
237 static FcChar32
238 FcListValueHash (FcValue *value)
239 {
240 FcValue v = FcValueCanonicalize(value);
241 switch (v.type) {
242 case FcTypeVoid:
243 return 0;
244 case FcTypeInteger:
245 return (FcChar32) v.u.i;
246 case FcTypeDouble:
247 return (FcChar32) (int) v.u.d;
248 case FcTypeString:
249 return FcStrHashIgnoreCase (v.u.s);
250 case FcTypeBool:
251 return (FcChar32) v.u.b;
252 case FcTypeMatrix:
253 return FcListMatrixHash (v.u.m);
254 case FcTypeCharSet:
255 return FcCharSetCount (v.u.c);
256 case FcTypeFTFace:
257 return (long) v.u.f;
258 case FcTypeLangSet:
259 return FcLangSetHash (v.u.l);
260 }
261 return 0;
262 }
263
264 static FcChar32
265 FcListValueListHash (FcValueListPtr list)
266 {
267 FcChar32 h = 0;
268
269 while (list != NULL)
270 {
271 h = h ^ FcListValueHash (&list->value);
272 list = FcValueListNext(list);
273 }
274 return h;
275 }
276
277 static FcChar32
278 FcListPatternHash (FcPattern *font,
279 FcObjectSet *os)
280 {
281 int n;
282 FcPatternElt *e;
283 FcChar32 h = 0;
284
285 for (n = 0; n < os->nobject; n++)
286 {
287 e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[n]));
288 if (e)
289 h = h ^ FcListValueListHash (FcPatternEltValues(e));
290 }
291 return h;
292 }
293
294 typedef struct _FcListBucket {
295 struct _FcListBucket *next;
296 FcChar32 hash;
297 FcPattern *pattern;
298 } FcListBucket;
299
300 #define FC_LIST_HASH_SIZE 4099
301
302 typedef struct _FcListHashTable {
303 int entries;
304 FcListBucket *buckets[FC_LIST_HASH_SIZE];
305 } FcListHashTable;
306
307 static void
308 FcListHashTableInit (FcListHashTable *table)
309 {
310 table->entries = 0;
311 memset (table->buckets, '\0', sizeof (table->buckets));
312 }
313
314 static void
315 FcListHashTableCleanup (FcListHashTable *table)
316 {
317 int i;
318 FcListBucket *bucket, *next;
319
320 for (i = 0; i < FC_LIST_HASH_SIZE; i++)
321 {
322 for (bucket = table->buckets[i]; bucket; bucket = next)
323 {
324 next = bucket->next;
325 FcPatternDestroy (bucket->pattern);
326 FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
327 free (bucket);
328 }
329 table->buckets[i] = 0;
330 }
331 table->entries = 0;
332 }
333
334 static int
335 FcGetDefaultObjectLangIndex (FcPattern *font, FcObject object)
336 {
337 FcChar8 *lang = FcGetDefaultLang ();
338 FcPatternElt *e = FcPatternObjectFindElt (font, object);
339 FcValueListPtr v;
340 FcValue value;
341 int idx = -1;
342 int i;
343
344 if (e)
345 {
346 for (v = FcPatternEltValues(e), i = 0; v; v = FcValueListNext(v), ++i)
347 {
348 value = FcValueCanonicalize (&v->value);
349
350 if (value.type == FcTypeString)
351 {
352 FcLangResult res = FcLangCompare (value.u.s, lang);
353 if (res == FcLangEqual || (res == FcLangDifferentCountry && idx < 0))
354 idx = i;
355 }
356 }
357 }
358
359 return (idx > 0) ? idx : 0;
360 }
361
362 static FcBool
363 FcListAppend (FcListHashTable *table,
364 FcPattern *font,
365 FcObjectSet *os)
366 {
367 int o;
368 FcPatternElt *e;
369 FcValueListPtr v;
370 FcChar32 hash;
371 FcListBucket **prev, *bucket;
372 int familyidx = -1;
373 int fullnameidx = -1;
374 int styleidx = -1;
375 int defidx = 0;
376 int idx;
377
378 hash = FcListPatternHash (font, os);
379 for (prev = &table->buckets[hash % FC_LIST_HASH_SIZE];
380 (bucket = *prev); prev = &(bucket->next))
381 {
382 if (bucket->hash == hash &&
383 FcListPatternEqual (bucket->pattern, font, os))
384 return FcTrue;
385 }
386 bucket = (FcListBucket *) malloc (sizeof (FcListBucket));
387 if (!bucket)
388 goto bail0;
389 FcMemAlloc (FC_MEM_LISTBUCK, sizeof (FcListBucket));
390 bucket->next = 0;
391 bucket->hash = hash;
392 bucket->pattern = FcPatternCreate ();
393 if (!bucket->pattern)
394 goto bail1;
395
396 for (o = 0; o < os->nobject; o++)
397 {
398 if (!strcmp (os->objects[o], FC_FAMILY) || !strcmp (os->objects[o], FC_FAMILYLANG))
399 {
400 if (familyidx < 0)
401 familyidx = FcGetDefaultObjectLangIndex (font, FC_FAMILYLANG_OBJECT);
402 defidx = familyidx;
403 }
404 else if (!strcmp (os->objects[o], FC_FULLNAME) || !strcmp (os->objects[o], FC_FULLNAMELANG))
405 {
406 if (fullnameidx < 0)
407 fullnameidx = FcGetDefaultObjectLangIndex (font, FC_FULLNAMELANG_OBJECT);
408 defidx = fullnameidx;
409 }
410 else if (!strcmp (os->objects[o], FC_STYLE) || !strcmp (os->objects[o], FC_STYLELANG))
411 {
412 if (styleidx < 0)
413 styleidx = FcGetDefaultObjectLangIndex (font, FC_STYLELANG_OBJECT);
414 defidx = styleidx;
415 }
416 else
417 defidx = 0;
418
419 e = FcPatternObjectFindElt (font, FcObjectFromName (os->objects[o]));
420 if (e)
421 {
422 for (v = FcPatternEltValues(e), idx = 0; v;
423 v = FcValueListNext(v), ++idx)
424 {
425 if (!FcPatternAdd (bucket->pattern,
426 os->objects[o],
427 FcValueCanonicalize(&v->value), defidx != idx))
428 goto bail2;
429 }
430 }
431 }
432 *prev = bucket;
433 ++table->entries;
434
435 return FcTrue;
436
437 bail2:
438 FcPatternDestroy (bucket->pattern);
439 bail1:
440 FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
441 free (bucket);
442 bail0:
443 return FcFalse;
444 }
445
446 FcFontSet *
447 FcFontSetList (FcConfig *config,
448 FcFontSet **sets,
449 int nsets,
450 FcPattern *p,
451 FcObjectSet *os)
452 {
453 FcFontSet *ret;
454 FcFontSet *s;
455 int f;
456 int set;
457 FcListHashTable table;
458 int i;
459 FcListBucket *bucket;
460
461 if (!config)
462 {
463 if (!FcInitBringUptoDate ())
464 goto bail0;
465
466 config = FcConfigGetCurrent ();
467 if (!config)
468 goto bail0;
469 }
470 FcListHashTableInit (&table);
471 /*
472 * Walk all available fonts adding those that
473 * match to the hash table
474 */
475 for (set = 0; set < nsets; set++)
476 {
477 s = sets[set];
478 if (!s)
479 continue;
480 for (f = 0; f < s->nfont; f++)
481 if (FcListPatternMatchAny (p, /* pattern */
482 s->fonts[f])) /* font */
483 if (!FcListAppend (&table, s->fonts[f], os))
484 goto bail1;
485 }
486 #if 0
487 {
488 int max = 0;
489 int full = 0;
490 int ents = 0;
491 int len;
492 for (i = 0; i < FC_LIST_HASH_SIZE; i++)
493 {
494 if ((bucket = table.buckets[i]))
495 {
496 len = 0;
497 for (; bucket; bucket = bucket->next)
498 {
499 ents++;
500 len++;
501 }
502 if (len > max)
503 max = len;
504 full++;
505 }
506 }
507 printf ("used: %d max: %d avg: %g\n", full, max,
508 (double) ents / FC_LIST_HASH_SIZE);
509 }
510 #endif
511 /*
512 * Walk the hash table and build
513 * a font set
514 */
515 ret = FcFontSetCreate ();
516 if (!ret)
517 goto bail0;
518 for (i = 0; i < FC_LIST_HASH_SIZE; i++)
519 while ((bucket = table.buckets[i]))
520 {
521 if (!FcFontSetAdd (ret, bucket->pattern))
522 goto bail2;
523 table.buckets[i] = bucket->next;
524 FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
525 free (bucket);
526 }
527
528 return ret;
529
530 bail2:
531 FcFontSetDestroy (ret);
532 bail1:
533 FcListHashTableCleanup (&table);
534 bail0:
535 return 0;
536 }
537
538 FcFontSet *
539 FcFontList (FcConfig *config,
540 FcPattern *p,
541 FcObjectSet *os)
542 {
543 FcFontSet *sets[2];
544 int nsets;
545
546 if (!config)
547 {
548 config = FcConfigGetCurrent ();
549 if (!config)
550 return 0;
551 }
552 nsets = 0;
553 if (config->fonts[FcSetSystem])
554 sets[nsets++] = config->fonts[FcSetSystem];
555 if (config->fonts[FcSetApplication])
556 sets[nsets++] = config->fonts[FcSetApplication];
557 return FcFontSetList (config, sets, nsets, p, os);
558 }
559 #define __fclist__
560 #include "fcaliastail.h"
561 #undef __fclist__