2 * $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi Exp $
4 * Copyright © 2000 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 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.
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.
31 FcPatternCreate (void)
35 p
= (FcPattern
*) malloc (sizeof (FcPattern
));
38 FcMemAlloc (FC_MEM_PATTERN
, sizeof (FcPattern
));
47 FcValueDestroy (FcValue v
)
51 FcStrFree ((FcChar8
*) v
.u
.s
);
54 FcMatrixFree ((FcMatrix
*) v
.u
.m
);
57 FcCharSetDestroy ((FcCharSet
*) v
.u
.c
);
60 FcLangSetDestroy ((FcLangSet
*) v
.u
.l
);
68 FcValueSave (FcValue v
)
72 v
.u
.s
= FcStrCopy (v
.u
.s
);
77 v
.u
.m
= FcMatrixCopy (v
.u
.m
);
82 v
.u
.c
= FcCharSetCopy ((FcCharSet
*) v
.u
.c
);
87 v
.u
.l
= FcLangSetCopy (v
.u
.l
);
98 FcValueListDestroy (FcValueList
*l
)
103 switch (l
->value
.type
) {
105 FcStrFree ((FcChar8
*) l
->value
.u
.s
);
108 FcMatrixFree ((FcMatrix
*) l
->value
.u
.m
);
111 FcCharSetDestroy ((FcCharSet
*) l
->value
.u
.c
);
114 FcLangSetDestroy ((FcLangSet
*) l
->value
.u
.l
);
120 FcMemFree (FC_MEM_VALLIST
, sizeof (FcValueList
));
126 FcValueEqual (FcValue va
, FcValue vb
)
128 if (va
.type
!= vb
.type
)
130 if (va
.type
== FcTypeInteger
)
132 va
.type
= FcTypeDouble
;
135 if (vb
.type
== FcTypeInteger
)
137 vb
.type
= FcTypeDouble
;
140 if (va
.type
!= vb
.type
)
147 return va
.u
.i
== vb
.u
.i
;
149 return va
.u
.d
== vb
.u
.d
;
151 return FcStrCmpIgnoreCase (va
.u
.s
, vb
.u
.s
) == 0;
153 return va
.u
.b
== vb
.u
.b
;
155 return FcMatrixEqual (va
.u
.m
, vb
.u
.m
);
157 return FcCharSetEqual (va
.u
.c
, vb
.u
.c
);
159 return va
.u
.f
== vb
.u
.f
;
161 return FcLangSetEqual (va
.u
.l
, vb
.u
.l
);
167 FcDoubleHash (double d
)
177 FcStringHash (const FcChar8
*s
)
184 h
= ((h
<< 1) | (h
>> 31)) ^ c
;
189 FcValueHash (FcValue v
)
195 return (FcChar32
) v
.u
.i
;
197 return FcDoubleHash (v
.u
.d
);
199 return FcStringHash (v
.u
.s
);
201 return (FcChar32
) v
.u
.b
;
203 return (FcDoubleHash (v
.u
.m
->xx
) ^
204 FcDoubleHash (v
.u
.m
->xy
) ^
205 FcDoubleHash (v
.u
.m
->yx
) ^
206 FcDoubleHash (v
.u
.m
->yy
));
208 return (FcChar32
) v
.u
.c
->num
;
210 return FcStringHash ((const FcChar8
*) ((FT_Face
) v
.u
.f
)->family_name
) ^
211 FcStringHash ((const FcChar8
*) ((FT_Face
) v
.u
.f
)->style_name
);
213 return FcLangSetHash (v
.u
.l
);
219 FcValueListEqual (FcValueList
*la
, FcValueList
*lb
)
226 if (!FcValueEqual (la
->value
, lb
->value
))
237 FcValueListHash (FcValueList
*l
)
243 hash
= ((hash
<< 1) | (hash
>> 31)) ^ FcValueHash (l
->value
);
250 FcPatternDestroy (FcPattern
*p
)
254 if (p
->ref
== FC_REF_CONSTANT
|| --p
->ref
> 0)
257 for (i
= 0; i
< p
->num
; i
++)
258 FcValueListDestroy (p
->elts
[i
].values
);
263 FcMemFree (FC_MEM_PATELT
, p
->size
* sizeof (FcPatternElt
));
268 FcMemFree (FC_MEM_PATTERN
, sizeof (FcPattern
));
272 #define FC_VALUE_LIST_HASH_SIZE 257
273 #define FC_PATTERN_HASH_SIZE 67
275 typedef struct _FcValueListEnt FcValueListEnt
;
277 struct _FcValueListEnt
{
278 FcValueListEnt
*next
;
283 typedef union _FcValueListAlign
{
288 static int FcValueListFrozenCount
[FcTypeLangSet
+ 1];
289 static int FcValueListFrozenBytes
[FcTypeLangSet
+ 1];
290 static char *FcValueListFrozenName
[] = {
303 FcValueListReport (void);
306 FcValueListReport (void)
310 printf ("Fc Frozen Values:\n");
311 printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
312 for (t
= FcTypeVoid
; t
<= FcTypeLangSet
; t
++)
313 printf ("\t%8s %9d %9d\n", FcValueListFrozenName
[t
],
314 FcValueListFrozenCount
[t
], FcValueListFrozenBytes
[t
]);
317 static FcValueListEnt
*
318 FcValueListEntCreate (FcValueList
*h
)
320 FcValueListAlign
*ea
;
322 FcValueList
*l
, *new;
329 for (l
= h
; l
; l
= l
->next
)
331 if (l
->value
.type
== FcTypeString
)
332 string_size
+= strlen ((char *) l
->value
.u
.s
) + 1;
335 size
= sizeof (FcValueListAlign
) + n
* sizeof (FcValueList
) + string_size
;
336 FcValueListFrozenCount
[h
->value
.type
]++;
337 FcValueListFrozenBytes
[h
->value
.type
] += size
;
341 FcMemAlloc (FC_MEM_VALLIST
, size
);
343 e
->list
= (FcValueList
*) (ea
+ 1);
344 strs
= (FcChar8
*) (e
->list
+ n
);
346 for (l
= h
; l
; l
= l
->next
, new++)
348 if (l
->value
.type
== FcTypeString
)
350 new->value
.type
= FcTypeString
;
351 new->value
.u
.s
= strs
;
352 strcpy ((char *) strs
, (char *) l
->value
.u
.s
);
353 strs
+= strlen ((char *) strs
) + 1;
357 new->value
= l
->value
;
358 new->value
= FcValueSave (new->value
);
360 new->binding
= l
->binding
;
370 FcValueListEntDestroy (FcValueListEnt
*e
)
374 FcValueListFrozenCount
[e
->list
->value
.type
]--;
376 /* XXX: We should perform these two operations with "size" as
377 computed in FcValueListEntCreate, but we don't have access to
378 that value here. Without this, the FcValueListFrozenBytes
379 values will be wrong as will the FcMemFree counts.
381 FcValueListFrozenBytes[e->list->value.type] -= size;
382 FcMemFree (FC_MEM_VALLIST, size);
385 for (l
= e
->list
; l
; l
= l
->next
)
387 if (l
->value
.type
!= FcTypeString
)
388 FcValueDestroy (l
->value
);
390 /* XXX: Are we being too chummy with the implementation here to
391 free(e) when it was actually the enclosing FcValueListAlign
392 that was allocated? */
396 static int FcValueListTotal
;
397 static int FcValueListUsed
;
399 static FcValueListEnt
*FcValueListHashTable
[FC_VALUE_LIST_HASH_SIZE
];
402 FcValueListFreeze (FcValueList
*l
)
404 FcChar32 hash
= FcValueListHash (l
);
405 FcValueListEnt
**bucket
= &FcValueListHashTable
[hash
% FC_VALUE_LIST_HASH_SIZE
];
409 for (ent
= *bucket
; ent
; ent
= ent
->next
)
411 if (ent
->hash
== hash
&& FcValueListEqual (ent
->list
, l
))
415 ent
= FcValueListEntCreate (l
);
427 FcValueListThawAll (void)
430 FcValueListEnt
*ent
, *next
;
432 for (i
= 0; i
< FC_VALUE_LIST_HASH_SIZE
; i
++)
434 for (ent
= FcValueListHashTable
[i
]; ent
; ent
= next
)
437 FcValueListEntDestroy (ent
);
439 FcValueListHashTable
[i
] = 0;
442 FcValueListTotal
= 0;
447 FcPatternBaseHash (FcPattern
*b
)
449 FcChar32 hash
= b
->num
;
452 for (i
= 0; i
< b
->num
; i
++)
453 hash
= ((hash
<< 1) | (hash
>> 31)) ^ ((long) b
->elts
[i
].values
);
457 typedef struct _FcPatternEnt FcPatternEnt
;
459 struct _FcPatternEnt
{
465 static int FcPatternTotal
;
466 static int FcPatternUsed
;
468 static FcPatternEnt
*FcPatternHashTable
[FC_VALUE_LIST_HASH_SIZE
];
471 FcPatternBaseFreeze (FcPattern
*b
)
473 FcChar32 hash
= FcPatternBaseHash (b
);
474 FcPatternEnt
**bucket
= &FcPatternHashTable
[hash
% FC_VALUE_LIST_HASH_SIZE
];
482 for (ent
= *bucket
; ent
; ent
= ent
->next
)
484 if (ent
->hash
== hash
&& b
->num
== ent
->pattern
.num
)
486 for (i
= 0; i
< b
->num
; i
++)
488 if (strcmp (b
->elts
[i
].object
, ent
->pattern
.elts
[i
].object
))
490 if (b
->elts
[i
].values
!= ent
->pattern
.elts
[i
].values
)
494 return &ent
->pattern
;
499 * Compute size of pattern + elts + object names
502 for (i
= 0; i
< b
->num
; i
++)
503 size_objects
+= strlen (b
->elts
[i
].object
) + 1;
505 size
= sizeof (FcPatternEnt
) + b
->num
*sizeof (FcPatternElt
) + size_objects
;
510 FcMemAlloc (FC_MEM_PATTERN
, size
);
513 ent
->pattern
.elts
= (FcPatternElt
*) (ent
+ 1);
514 ent
->pattern
.num
= b
->num
;
515 ent
->pattern
.size
= b
->num
;
516 ent
->pattern
.ref
= FC_REF_CONSTANT
;
518 objects
= (char *) (ent
->pattern
.elts
+ b
->num
);
519 for (i
= 0; i
< b
->num
; i
++)
521 ent
->pattern
.elts
[i
].values
= b
->elts
[i
].values
;
522 strcpy (objects
, b
->elts
[i
].object
);
523 ent
->pattern
.elts
[i
].object
= objects
;
524 objects
+= strlen (objects
) + 1;
530 return &ent
->pattern
;
534 FcPatternBaseThawAll (void)
537 FcPatternEnt
*ent
, *next
;
539 for (i
= 0; i
< FC_VALUE_LIST_HASH_SIZE
; i
++)
541 for (ent
= FcPatternHashTable
[i
]; ent
; ent
= next
)
546 FcPatternHashTable
[i
] = 0;
554 FcPatternFreeze (FcPattern
*p
)
556 FcPattern
*b
, *n
= 0;
560 size
= sizeof (FcPattern
) + p
->num
* sizeof (FcPatternElt
);
561 b
= (FcPattern
*) malloc (size
);
564 FcMemAlloc (FC_MEM_PATTERN
, size
);
568 b
->elts
= (FcPatternElt
*) (b
+ 1);
570 * Freeze object lists
572 for (i
= 0; i
< p
->num
; i
++)
574 b
->elts
[i
].object
= p
->elts
[i
].object
;
575 b
->elts
[i
].values
= FcValueListFreeze (p
->elts
[i
].values
);
576 if (!b
->elts
[i
].values
)
582 n
= FcPatternBaseFreeze (b
);
584 if (FcDebug() & FC_DBG_MEMORY
)
586 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal
, FcValueListUsed
);
587 printf ("Patterns: total %9d used %9d\n", FcPatternTotal
, FcPatternUsed
);
593 assert (FcPatternEqual (n
, p
));
599 FcPatternThawAll (void)
601 FcPatternBaseThawAll ();
602 FcValueListThawAll ();
606 FcPatternPosition (const FcPattern
*p
, const char *object
)
608 int low
, high
, mid
, c
;
616 mid
= (low
+ high
) >> 1;
617 c
= strcmp (p
->elts
[mid
].object
, object
);
631 FcPatternFindElt (const FcPattern
*p
, const char *object
)
633 int i
= FcPatternPosition (p
, object
);
640 FcPatternInsertElt (FcPattern
*p
, const char *object
)
645 i
= FcPatternPosition (p
, object
);
651 if (p
->num
+ 1 >= p
->size
)
653 int s
= p
->size
+ 16;
655 e
= (FcPatternElt
*) realloc (p
->elts
, s
* sizeof (FcPatternElt
));
657 e
= (FcPatternElt
*) malloc (s
* sizeof (FcPatternElt
));
662 FcMemFree (FC_MEM_PATELT
, p
->size
* sizeof (FcPatternElt
));
663 FcMemAlloc (FC_MEM_PATELT
, s
* sizeof (FcPatternElt
));
666 p
->elts
[p
->size
].object
= 0;
667 p
->elts
[p
->size
].values
= 0;
673 memmove (p
->elts
+ i
+ 1,
675 sizeof (FcPatternElt
) *
681 p
->elts
[i
].object
= object
;
682 p
->elts
[i
].values
= 0;
689 FcPatternEqual (const FcPattern
*pa
, const FcPattern
*pb
)
696 if (pa
->num
!= pb
->num
)
698 for (i
= 0; i
< pa
->num
; i
++)
700 if (strcmp (pa
->elts
[i
].object
, pb
->elts
[i
].object
) != 0)
702 if (!FcValueListEqual (pa
->elts
[i
].values
, pb
->elts
[i
].values
))
709 FcPatternHash (const FcPattern
*p
)
714 for (i
= 0; i
< p
->num
; i
++)
716 h
= (((h
<< 1) | (h
>> 31)) ^
717 FcStringHash ((const FcChar8
*) p
->elts
[i
].object
) ^
718 FcValueListHash (p
->elts
[i
].values
));
724 FcPatternEqualSubset (const FcPattern
*pa
, const FcPattern
*pb
, const FcObjectSet
*os
)
726 FcPatternElt
*ea
, *eb
;
729 for (i
= 0; i
< os
->nobject
; i
++)
731 ea
= FcPatternFindElt (pa
, os
->objects
[i
]);
732 eb
= FcPatternFindElt (pb
, os
->objects
[i
]);
737 if (!FcValueListEqual (ea
->values
, eb
->values
))
750 FcPatternAddWithBinding (FcPattern
*p
,
753 FcValueBinding binding
,
757 FcValueList
*new, **prev
;
759 if (p
->ref
== FC_REF_CONSTANT
)
762 new = (FcValueList
*) malloc (sizeof (FcValueList
));
766 FcMemAlloc (FC_MEM_VALLIST
, sizeof (FcValueList
));
768 value
= FcValueSave (value
);
769 if (value
.type
== FcTypeVoid
)
773 new->binding
= binding
;
776 e
= FcPatternInsertElt (p
, object
);
782 for (prev
= &e
->values
; *prev
; prev
= &(*prev
)->next
);
787 new->next
= e
->values
;
794 switch (value
.type
) {
796 FcStrFree ((FcChar8
*) value
.u
.s
);
799 FcMatrixFree ((FcMatrix
*) value
.u
.m
);
802 FcCharSetDestroy ((FcCharSet
*) value
.u
.c
);
805 FcLangSetDestroy ((FcLangSet
*) value
.u
.l
);
811 FcMemFree (FC_MEM_VALLIST
, sizeof (FcValueList
));
818 FcPatternAdd (FcPattern
*p
, const char *object
, FcValue value
, FcBool append
)
820 return FcPatternAddWithBinding (p
, object
, value
, FcValueBindingStrong
, append
);
824 FcPatternAddWeak (FcPattern
*p
, const char *object
, FcValue value
, FcBool append
)
826 return FcPatternAddWithBinding (p
, object
, value
, FcValueBindingWeak
, append
);
830 FcPatternDel (FcPattern
*p
, const char *object
)
835 e
= FcPatternFindElt (p
, object
);
842 FcValueListDestroy (e
->values
);
844 /* shuffle existing ones down */
845 memmove (e
, e
+1, (p
->elts
+ p
->num
- (e
+ 1)) * sizeof (FcPatternElt
));
847 p
->elts
[p
->num
].object
= 0;
848 p
->elts
[p
->num
].values
= 0;
853 FcPatternAddInteger (FcPattern
*p
, const char *object
, int i
)
857 v
.type
= FcTypeInteger
;
859 return FcPatternAdd (p
, object
, v
, FcTrue
);
863 FcPatternAddDouble (FcPattern
*p
, const char *object
, double d
)
867 v
.type
= FcTypeDouble
;
869 return FcPatternAdd (p
, object
, v
, FcTrue
);
874 FcPatternAddString (FcPattern
*p
, const char *object
, const FcChar8
*s
)
878 v
.type
= FcTypeString
;
880 return FcPatternAdd (p
, object
, v
, FcTrue
);
884 FcPatternAddMatrix (FcPattern
*p
, const char *object
, const FcMatrix
*s
)
888 v
.type
= FcTypeMatrix
;
889 v
.u
.m
= (FcMatrix
*) s
;
890 return FcPatternAdd (p
, object
, v
, FcTrue
);
895 FcPatternAddBool (FcPattern
*p
, const char *object
, FcBool b
)
901 return FcPatternAdd (p
, object
, v
, FcTrue
);
905 FcPatternAddCharSet (FcPattern
*p
, const char *object
, const FcCharSet
*c
)
909 v
.type
= FcTypeCharSet
;
910 v
.u
.c
= (FcCharSet
*) c
;
911 return FcPatternAdd (p
, object
, v
, FcTrue
);
915 FcPatternAddFTFace (FcPattern
*p
, const char *object
, const FT_Face f
)
919 v
.type
= FcTypeFTFace
;
921 return FcPatternAdd (p
, object
, v
, FcTrue
);
925 FcPatternAddLangSet (FcPattern
*p
, const char *object
, const FcLangSet
*ls
)
929 v
.type
= FcTypeLangSet
;
930 v
.u
.l
= (FcLangSet
*) ls
;
931 return FcPatternAdd (p
, object
, v
, FcTrue
);
935 FcPatternGet (const FcPattern
*p
, const char *object
, int id
, FcValue
*v
)
940 e
= FcPatternFindElt (p
, object
);
942 return FcResultNoMatch
;
943 for (l
= e
->values
; l
; l
= l
->next
)
948 return FcResultMatch
;
956 FcPatternGetInteger (const FcPattern
*p
, const char *object
, int id
, int *i
)
961 r
= FcPatternGet (p
, object
, id
, &v
);
962 if (r
!= FcResultMatch
)
972 return FcResultTypeMismatch
;
974 return FcResultMatch
;
978 FcPatternGetDouble (const FcPattern
*p
, const char *object
, int id
, double *d
)
983 r
= FcPatternGet (p
, object
, id
, &v
);
984 if (r
!= FcResultMatch
)
994 return FcResultTypeMismatch
;
996 return FcResultMatch
;
1000 FcPatternGetString (const FcPattern
*p
, const char *object
, int id
, FcChar8
** s
)
1005 r
= FcPatternGet (p
, object
, id
, &v
);
1006 if (r
!= FcResultMatch
)
1008 if (v
.type
!= FcTypeString
)
1009 return FcResultTypeMismatch
;
1010 *s
= (FcChar8
*) v
.u
.s
;
1011 return FcResultMatch
;
1015 FcPatternGetMatrix(const FcPattern
*p
, const char *object
, int id
, FcMatrix
**m
)
1020 r
= FcPatternGet (p
, object
, id
, &v
);
1021 if (r
!= FcResultMatch
)
1023 if (v
.type
!= FcTypeMatrix
)
1024 return FcResultTypeMismatch
;
1025 *m
= (FcMatrix
*) v
.u
.m
;
1026 return FcResultMatch
;
1031 FcPatternGetBool(const FcPattern
*p
, const char *object
, int id
, FcBool
*b
)
1036 r
= FcPatternGet (p
, object
, id
, &v
);
1037 if (r
!= FcResultMatch
)
1039 if (v
.type
!= FcTypeBool
)
1040 return FcResultTypeMismatch
;
1042 return FcResultMatch
;
1046 FcPatternGetCharSet(const FcPattern
*p
, const char *object
, int id
, FcCharSet
**c
)
1051 r
= FcPatternGet (p
, object
, id
, &v
);
1052 if (r
!= FcResultMatch
)
1054 if (v
.type
!= FcTypeCharSet
)
1055 return FcResultTypeMismatch
;
1056 *c
= (FcCharSet
*) v
.u
.c
;
1057 return FcResultMatch
;
1061 FcPatternGetFTFace(const FcPattern
*p
, const char *object
, int id
, FT_Face
*f
)
1066 r
= FcPatternGet (p
, object
, id
, &v
);
1067 if (r
!= FcResultMatch
)
1069 if (v
.type
!= FcTypeFTFace
)
1070 return FcResultTypeMismatch
;
1071 *f
= (FT_Face
) v
.u
.f
;
1072 return FcResultMatch
;
1076 FcPatternGetLangSet(const FcPattern
*p
, const char *object
, int id
, FcLangSet
**ls
)
1081 r
= FcPatternGet (p
, object
, id
, &v
);
1082 if (r
!= FcResultMatch
)
1084 if (v
.type
!= FcTypeLangSet
)
1085 return FcResultTypeMismatch
;
1086 *ls
= (FcLangSet
*) v
.u
.l
;
1087 return FcResultMatch
;
1091 FcPatternDuplicate (const FcPattern
*orig
)
1097 new = FcPatternCreate ();
1101 for (i
= 0; i
< orig
->num
; i
++)
1103 for (l
= orig
->elts
[i
].values
; l
; l
= l
->next
)
1104 if (!FcPatternAdd (new, orig
->elts
[i
].object
, l
->value
, FcTrue
))
1111 FcPatternDestroy (new);
1117 FcPatternReference (FcPattern
*p
)
1119 if (p
->ref
!= FC_REF_CONSTANT
)
1124 FcPatternVaBuild (FcPattern
*orig
, va_list va
)
1128 FcPatternVapBuild (ret
, orig
, va
);
1133 FcPatternBuild (FcPattern
*orig
, ...)
1137 va_start (va
, orig
);
1138 FcPatternVapBuild (orig
, orig
, va
);