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
;
369 static int FcValueListTotal
;
370 static int FcValueListUsed
;
373 FcValueListFreeze (FcValueList
*l
)
375 static FcValueListEnt
*hashTable
[FC_VALUE_LIST_HASH_SIZE
];
376 FcChar32 hash
= FcValueListHash (l
);
377 FcValueListEnt
**bucket
= &hashTable
[hash
% FC_VALUE_LIST_HASH_SIZE
];
381 for (ent
= *bucket
; ent
; ent
= ent
->next
)
383 if (ent
->hash
== hash
&& FcValueListEqual (ent
->list
, l
))
387 ent
= FcValueListEntCreate (l
);
399 FcPatternBaseHash (FcPattern
*b
)
401 FcChar32 hash
= b
->num
;
404 for (i
= 0; i
< b
->num
; i
++)
405 hash
= ((hash
<< 1) | (hash
>> 31)) ^ ((long) b
->elts
[i
].values
);
409 typedef struct _FcPatternEnt FcPatternEnt
;
411 struct _FcPatternEnt
{
417 static int FcPatternTotal
;
418 static int FcPatternUsed
;
421 FcPatternBaseFreeze (FcPattern
*b
)
423 static FcPatternEnt
*hashTable
[FC_VALUE_LIST_HASH_SIZE
];
424 FcChar32 hash
= FcPatternBaseHash (b
);
425 FcPatternEnt
**bucket
= &hashTable
[hash
% FC_VALUE_LIST_HASH_SIZE
];
433 for (ent
= *bucket
; ent
; ent
= ent
->next
)
435 if (ent
->hash
== hash
&& b
->num
== ent
->pattern
.num
)
437 for (i
= 0; i
< b
->num
; i
++)
439 if (strcmp (b
->elts
[i
].object
, ent
->pattern
.elts
[i
].object
))
441 if (b
->elts
[i
].values
!= ent
->pattern
.elts
[i
].values
)
445 return &ent
->pattern
;
450 * Compute size of pattern + elts + object names
453 for (i
= 0; i
< b
->num
; i
++)
454 size_objects
+= strlen (b
->elts
[i
].object
) + 1;
456 size
= sizeof (FcPatternEnt
) + b
->num
*sizeof (FcPatternElt
) + size_objects
;
461 FcMemAlloc (FC_MEM_PATTERN
, size
);
464 ent
->pattern
.elts
= (FcPatternElt
*) (ent
+ 1);
465 ent
->pattern
.num
= b
->num
;
466 ent
->pattern
.size
= b
->num
;
467 ent
->pattern
.ref
= FC_REF_CONSTANT
;
469 objects
= (char *) (ent
->pattern
.elts
+ b
->num
);
470 for (i
= 0; i
< b
->num
; i
++)
472 ent
->pattern
.elts
[i
].values
= b
->elts
[i
].values
;
473 strcpy (objects
, b
->elts
[i
].object
);
474 ent
->pattern
.elts
[i
].object
= objects
;
475 objects
+= strlen (objects
) + 1;
481 return &ent
->pattern
;
485 FcPatternFreeze (FcPattern
*p
)
487 FcPattern
*b
, *n
= 0;
491 size
= sizeof (FcPattern
) + p
->num
* sizeof (FcPatternElt
);
492 b
= (FcPattern
*) malloc (size
);
495 FcMemAlloc (FC_MEM_PATTERN
, size
);
499 b
->elts
= (FcPatternElt
*) (b
+ 1);
501 * Freeze object lists
503 for (i
= 0; i
< p
->num
; i
++)
505 b
->elts
[i
].object
= p
->elts
[i
].object
;
506 b
->elts
[i
].values
= FcValueListFreeze (p
->elts
[i
].values
);
507 if (!b
->elts
[i
].values
)
513 n
= FcPatternBaseFreeze (b
);
515 if (FcDebug() & FC_DBG_MEMORY
)
517 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal
, FcValueListUsed
);
518 printf ("Patterns: total %9d used %9d\n", FcPatternTotal
, FcPatternUsed
);
524 assert (FcPatternEqual (n
, p
));
530 FcPatternPosition (const FcPattern
*p
, const char *object
)
532 int low
, high
, mid
, c
;
540 mid
= (low
+ high
) >> 1;
541 c
= strcmp (p
->elts
[mid
].object
, object
);
555 FcPatternFindElt (const FcPattern
*p
, const char *object
)
557 int i
= FcPatternPosition (p
, object
);
564 FcPatternInsertElt (FcPattern
*p
, const char *object
)
569 i
= FcPatternPosition (p
, object
);
575 if (p
->num
+ 1 >= p
->size
)
577 int s
= p
->size
+ 16;
579 e
= (FcPatternElt
*) realloc (p
->elts
, s
* sizeof (FcPatternElt
));
581 e
= (FcPatternElt
*) malloc (s
* sizeof (FcPatternElt
));
586 FcMemFree (FC_MEM_PATELT
, p
->size
* sizeof (FcPatternElt
));
587 FcMemAlloc (FC_MEM_PATELT
, s
* sizeof (FcPatternElt
));
590 p
->elts
[p
->size
].object
= 0;
591 p
->elts
[p
->size
].values
= 0;
597 memmove (p
->elts
+ i
+ 1,
599 sizeof (FcPatternElt
) *
605 p
->elts
[i
].object
= object
;
606 p
->elts
[i
].values
= 0;
613 FcPatternEqual (const FcPattern
*pa
, const FcPattern
*pb
)
620 if (pa
->num
!= pb
->num
)
622 for (i
= 0; i
< pa
->num
; i
++)
624 if (strcmp (pa
->elts
[i
].object
, pb
->elts
[i
].object
) != 0)
626 if (!FcValueListEqual (pa
->elts
[i
].values
, pb
->elts
[i
].values
))
633 FcPatternHash (const FcPattern
*p
)
638 for (i
= 0; i
< p
->num
; i
++)
640 h
= (((h
<< 1) | (h
>> 31)) ^
641 FcStringHash ((const FcChar8
*) p
->elts
[i
].object
) ^
642 FcValueListHash (p
->elts
[i
].values
));
648 FcPatternEqualSubset (const FcPattern
*pa
, const FcPattern
*pb
, const FcObjectSet
*os
)
650 FcPatternElt
*ea
, *eb
;
653 for (i
= 0; i
< os
->nobject
; i
++)
655 ea
= FcPatternFindElt (pa
, os
->objects
[i
]);
656 eb
= FcPatternFindElt (pb
, os
->objects
[i
]);
661 if (!FcValueListEqual (ea
->values
, eb
->values
))
674 FcPatternAddWithBinding (FcPattern
*p
,
677 FcValueBinding binding
,
681 FcValueList
*new, **prev
;
683 if (p
->ref
== FC_REF_CONSTANT
)
686 new = (FcValueList
*) malloc (sizeof (FcValueList
));
690 FcMemAlloc (FC_MEM_VALLIST
, sizeof (FcValueList
));
692 value
= FcValueSave (value
);
693 if (value
.type
== FcTypeVoid
)
697 new->binding
= binding
;
700 e
= FcPatternInsertElt (p
, object
);
706 for (prev
= &e
->values
; *prev
; prev
= &(*prev
)->next
);
711 new->next
= e
->values
;
718 switch (value
.type
) {
720 FcStrFree ((FcChar8
*) value
.u
.s
);
723 FcMatrixFree ((FcMatrix
*) value
.u
.m
);
726 FcCharSetDestroy ((FcCharSet
*) value
.u
.c
);
729 FcLangSetDestroy ((FcLangSet
*) value
.u
.l
);
735 FcMemFree (FC_MEM_VALLIST
, sizeof (FcValueList
));
742 FcPatternAdd (FcPattern
*p
, const char *object
, FcValue value
, FcBool append
)
744 return FcPatternAddWithBinding (p
, object
, value
, FcValueBindingStrong
, append
);
748 FcPatternAddWeak (FcPattern
*p
, const char *object
, FcValue value
, FcBool append
)
750 return FcPatternAddWithBinding (p
, object
, value
, FcValueBindingWeak
, append
);
754 FcPatternDel (FcPattern
*p
, const char *object
)
759 e
= FcPatternFindElt (p
, object
);
766 FcValueListDestroy (e
->values
);
768 /* shuffle existing ones down */
769 memmove (e
, e
+1, (p
->elts
+ p
->num
- (e
+ 1)) * sizeof (FcPatternElt
));
771 p
->elts
[p
->num
].object
= 0;
772 p
->elts
[p
->num
].values
= 0;
777 FcPatternAddInteger (FcPattern
*p
, const char *object
, int i
)
781 v
.type
= FcTypeInteger
;
783 return FcPatternAdd (p
, object
, v
, FcTrue
);
787 FcPatternAddDouble (FcPattern
*p
, const char *object
, double d
)
791 v
.type
= FcTypeDouble
;
793 return FcPatternAdd (p
, object
, v
, FcTrue
);
798 FcPatternAddString (FcPattern
*p
, const char *object
, const FcChar8
*s
)
802 v
.type
= FcTypeString
;
804 return FcPatternAdd (p
, object
, v
, FcTrue
);
808 FcPatternAddMatrix (FcPattern
*p
, const char *object
, const FcMatrix
*s
)
812 v
.type
= FcTypeMatrix
;
813 v
.u
.m
= (FcMatrix
*) s
;
814 return FcPatternAdd (p
, object
, v
, FcTrue
);
819 FcPatternAddBool (FcPattern
*p
, const char *object
, FcBool b
)
825 return FcPatternAdd (p
, object
, v
, FcTrue
);
829 FcPatternAddCharSet (FcPattern
*p
, const char *object
, const FcCharSet
*c
)
833 v
.type
= FcTypeCharSet
;
834 v
.u
.c
= (FcCharSet
*) c
;
835 return FcPatternAdd (p
, object
, v
, FcTrue
);
839 FcPatternAddFTFace (FcPattern
*p
, const char *object
, const FT_Face f
)
843 v
.type
= FcTypeFTFace
;
845 return FcPatternAdd (p
, object
, v
, FcTrue
);
849 FcPatternAddLangSet (FcPattern
*p
, const char *object
, const FcLangSet
*ls
)
853 v
.type
= FcTypeLangSet
;
854 v
.u
.l
= (FcLangSet
*) ls
;
855 return FcPatternAdd (p
, object
, v
, FcTrue
);
859 FcPatternGet (const FcPattern
*p
, const char *object
, int id
, FcValue
*v
)
864 e
= FcPatternFindElt (p
, object
);
866 return FcResultNoMatch
;
867 for (l
= e
->values
; l
; l
= l
->next
)
872 return FcResultMatch
;
880 FcPatternGetInteger (const FcPattern
*p
, const char *object
, int id
, int *i
)
885 r
= FcPatternGet (p
, object
, id
, &v
);
886 if (r
!= FcResultMatch
)
896 return FcResultTypeMismatch
;
898 return FcResultMatch
;
902 FcPatternGetDouble (const FcPattern
*p
, const char *object
, int id
, double *d
)
907 r
= FcPatternGet (p
, object
, id
, &v
);
908 if (r
!= FcResultMatch
)
918 return FcResultTypeMismatch
;
920 return FcResultMatch
;
924 FcPatternGetString (const FcPattern
*p
, const char *object
, int id
, FcChar8
** s
)
929 r
= FcPatternGet (p
, object
, id
, &v
);
930 if (r
!= FcResultMatch
)
932 if (v
.type
!= FcTypeString
)
933 return FcResultTypeMismatch
;
934 *s
= (FcChar8
*) v
.u
.s
;
935 return FcResultMatch
;
939 FcPatternGetMatrix(const FcPattern
*p
, const char *object
, int id
, FcMatrix
**m
)
944 r
= FcPatternGet (p
, object
, id
, &v
);
945 if (r
!= FcResultMatch
)
947 if (v
.type
!= FcTypeMatrix
)
948 return FcResultTypeMismatch
;
949 *m
= (FcMatrix
*) v
.u
.m
;
950 return FcResultMatch
;
955 FcPatternGetBool(const FcPattern
*p
, const char *object
, int id
, FcBool
*b
)
960 r
= FcPatternGet (p
, object
, id
, &v
);
961 if (r
!= FcResultMatch
)
963 if (v
.type
!= FcTypeBool
)
964 return FcResultTypeMismatch
;
966 return FcResultMatch
;
970 FcPatternGetCharSet(const FcPattern
*p
, const char *object
, int id
, FcCharSet
**c
)
975 r
= FcPatternGet (p
, object
, id
, &v
);
976 if (r
!= FcResultMatch
)
978 if (v
.type
!= FcTypeCharSet
)
979 return FcResultTypeMismatch
;
980 *c
= (FcCharSet
*) v
.u
.c
;
981 return FcResultMatch
;
985 FcPatternGetFTFace(const FcPattern
*p
, const char *object
, int id
, FT_Face
*f
)
990 r
= FcPatternGet (p
, object
, id
, &v
);
991 if (r
!= FcResultMatch
)
993 if (v
.type
!= FcTypeFTFace
)
994 return FcResultTypeMismatch
;
995 *f
= (FT_Face
) v
.u
.f
;
996 return FcResultMatch
;
1000 FcPatternGetLangSet(const FcPattern
*p
, const char *object
, int id
, FcLangSet
**ls
)
1005 r
= FcPatternGet (p
, object
, id
, &v
);
1006 if (r
!= FcResultMatch
)
1008 if (v
.type
!= FcTypeLangSet
)
1009 return FcResultTypeMismatch
;
1010 *ls
= (FcLangSet
*) v
.u
.l
;
1011 return FcResultMatch
;
1015 FcPatternDuplicate (const FcPattern
*orig
)
1021 new = FcPatternCreate ();
1025 for (i
= 0; i
< orig
->num
; i
++)
1027 for (l
= orig
->elts
[i
].values
; l
; l
= l
->next
)
1028 if (!FcPatternAdd (new, orig
->elts
[i
].object
, l
->value
, FcTrue
))
1035 FcPatternDestroy (new);
1041 FcPatternReference (FcPattern
*p
)
1043 if (p
->ref
!= FC_REF_CONSTANT
)
1048 FcPatternVaBuild (FcPattern
*orig
, va_list va
)
1052 FcPatternVapBuild (ret
, orig
, va
);
1057 FcPatternBuild (FcPattern
*orig
, ...)
1061 va_start (va
, orig
);
1062 FcPatternVapBuild (orig
, orig
, va
);