]>
git.wh0rd.org - fontconfig.git/blob - src/fcmatch.c
2 * $RCSId: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp 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 FcCompareNumber (const char *object
, FcValue
*value1
, FcValue
*value2
)
35 switch (value1
->type
) {
37 v1
= (double) value1
->u
.i
;
45 switch (value2
->type
) {
47 v2
= (double) value2
->u
.i
;
62 FcCompareString (const char *object
, FcValue
*v1
, FcValue
*v2
)
64 FcValue value1
= FcValueCanonicalize(v1
), value2
= FcValueCanonicalize(v2
);
65 if (value2
.type
!= FcTypeString
|| value1
.type
!= FcTypeString
)
67 return (double) FcStrCmpIgnoreCase (value1
.u
.s
, value2
.u
.s
) != 0;
71 FcCompareFamily (const char *object
, FcValue
*v1
, FcValue
*v2
)
73 FcValue value1
= FcValueCanonicalize(v1
), value2
= FcValueCanonicalize(v2
);
74 if (value2
.type
!= FcTypeString
|| value1
.type
!= FcTypeString
)
76 return (double) FcStrCmpIgnoreBlanksAndCase (value1
.u
.s
, value2
.u
.s
) != 0;
80 FcCompareLang (const char *object
, FcValue
*v1
, FcValue
*v2
)
83 FcValue value1
= FcValueCanonicalize(v1
), value2
= FcValueCanonicalize(v2
);
85 switch (value1
.type
) {
87 switch (value2
.type
) {
89 result
= FcLangSetCompare (value1
.u
.l
, value2
.u
.l
);
92 result
= FcLangSetHasLang (value1
.u
.l
,
100 switch (value2
.type
) {
102 result
= FcLangSetHasLang (value2
.u
.l
, value1
.u
.s
);
105 result
= FcLangCompare (value1
.u
.s
,
118 case FcLangDifferentCountry
:
120 case FcLangDifferentLang
:
127 FcCompareBool (const char *object
, FcValue
*value1
, FcValue
*value2
)
129 if (value2
->type
!= FcTypeBool
|| value1
->type
!= FcTypeBool
)
131 return (double) value2
->u
.b
!= value1
->u
.b
;
135 FcCompareCharSet (const char *object
, FcValue
*v1
, FcValue
*v2
)
137 FcValue value1
= FcValueCanonicalize(v1
), value2
= FcValueCanonicalize(v2
);
139 if (value2
.type
!= FcTypeCharSet
|| value1
.type
!= FcTypeCharSet
)
141 return (double) FcCharSetSubtractCount (value1
.u
.c
, value2
.u
.c
);
145 FcCompareSize (const char *object
, FcValue
*value1
, FcValue
*value2
)
149 switch (value1
->type
) {
159 switch (value2
->type
) {
177 typedef struct _FcMatcher
{
179 double (*compare
) (const char *object
, FcValue
*value1
, FcValue
*value2
);
184 * Order is significant, it defines the precedence of
185 * each value, earlier values are more significant than
188 static FcMatcher _FcMatchers
[] = {
189 { FC_FOUNDRY
, FcCompareString
, 0, 0 },
190 #define MATCH_FOUNDRY 0
191 #define MATCH_FOUNDRY_INDEX 0
193 { FC_CHARSET
, FcCompareCharSet
, 1, 1 },
194 #define MATCH_CHARSET 1
195 #define MATCH_CHARSET_INDEX 1
197 { FC_FAMILY
, FcCompareFamily
, 2, 4 },
198 #define MATCH_FAMILY 2
199 #define MATCH_FAMILY_STRONG_INDEX 2
200 #define MATCH_FAMILY_WEAK_INDEX 4
202 { FC_LANG
, FcCompareLang
, 3, 3 },
204 #define MATCH_LANG_INDEX 3
206 { FC_SPACING
, FcCompareNumber
, 5, 5 },
207 #define MATCH_SPACING 4
208 #define MATCH_SPACING_INDEX 5
210 { FC_PIXEL_SIZE
, FcCompareSize
, 6, 6 },
211 #define MATCH_PIXEL_SIZE 5
212 #define MATCH_PIXEL_SIZE_INDEX 6
214 { FC_STYLE
, FcCompareString
, 7, 7 },
215 #define MATCH_STYLE 6
216 #define MATCH_STYLE_INDEX 7
218 { FC_SLANT
, FcCompareNumber
, 8, 8 },
219 #define MATCH_SLANT 7
220 #define MATCH_SLANT_INDEX 8
222 { FC_WEIGHT
, FcCompareNumber
, 9, 9 },
223 #define MATCH_WEIGHT 8
224 #define MATCH_WEIGHT_INDEX 9
226 { FC_WIDTH
, FcCompareNumber
, 10, 10 },
227 #define MATCH_WIDTH 9
228 #define MATCH_WIDTH_INDEX 10
230 { FC_ANTIALIAS
, FcCompareBool
, 11, 11 },
231 #define MATCH_ANTIALIAS 10
232 #define MATCH_ANTIALIAS_INDEX 11
234 { FC_RASTERIZER
, FcCompareString
, 12, 12 },
235 #define MATCH_RASTERIZER 11
236 #define MATCH_RASTERIZER_INDEX 12
238 { FC_OUTLINE
, FcCompareBool
, 13, 13 },
239 #define MATCH_OUTLINE 12
240 #define MATCH_OUTLINE_INDEX 13
242 { FC_FONTVERSION
, FcCompareNumber
, 14, 14 },
243 #define MATCH_FONTVERSION 13
244 #define MATCH_FONTVERSION_INDEX 14
247 #define NUM_MATCH_VALUES 15
250 FcCompareValueList (const char *object
,
251 FcValueListPtr v1orig
, /* pattern */
252 FcValueListPtr v2orig
, /* target */
257 FcValueListPtr v1
, v2
;
258 FcValueList
*v1_ptrU
, *v2_ptrU
;
259 double v
, best
, bestStrong
, bestWeak
;
264 * Locate the possible matching entry by examining the
265 * first few characters in object
268 switch (FcToLower (object
[0])) {
270 switch (FcToLower (object
[1])) {
272 switch (FcToLower (object
[2])) {
274 i
= MATCH_FOUNDRY
; break;
276 i
= MATCH_FONTVERSION
; break;
280 i
= MATCH_FAMILY
; break;
284 i
= MATCH_CHARSET
; break;
286 i
= MATCH_ANTIALIAS
; break;
288 i
= MATCH_LANG
; break;
290 switch (FcToLower (object
[1])) {
292 i
= MATCH_SPACING
; break;
294 i
= MATCH_STYLE
; break;
296 i
= MATCH_SLANT
; break;
300 i
= MATCH_PIXEL_SIZE
; break;
302 switch (FcToLower (object
[1])) {
304 i
= MATCH_WIDTH
; break;
306 i
= MATCH_WEIGHT
; break;
310 i
= MATCH_RASTERIZER
; break;
312 i
= MATCH_OUTLINE
; break;
315 FcStrCmpIgnoreCase ((FcChar8
*) _FcMatchers
[i
].object
,
316 (FcChar8
*) object
) != 0)
319 *bestValue
= FcValueCanonicalize(&FcValueListPtrU(v2orig
)->value
);
323 for (i
= 0; i
< NUM_MATCHER
; i
++)
325 if (!FcStrCmpIgnoreCase ((FcChar8
*) _FcMatchers
[i
].object
,
329 if (i
== NUM_MATCHER
)
332 *bestValue
= v2orig
->value
;
340 for (v1
= v1orig
, v1_ptrU
= FcValueListPtrU(v1
); v1_ptrU
;
341 v1
= FcValueListPtrU(v1
)->next
, v1_ptrU
= FcValueListPtrU(v1
))
343 for (v2
= v2orig
, v2_ptrU
= FcValueListPtrU(v2
); FcValueListPtrU(v2
);
344 v2
= FcValueListPtrU(v2
)->next
)
346 v
= (*_FcMatchers
[i
].compare
) (_FcMatchers
[i
].object
,
351 *result
= FcResultTypeMismatch
;
354 if (FcDebug () & FC_DBG_MATCHV
)
355 printf (" v %g j %d ", v
, j
);
360 *bestValue
= FcValueCanonicalize(&v2_ptrU
->value
);
363 if (v1_ptrU
->binding
== FcValueBindingStrong
)
376 if (FcDebug () & FC_DBG_MATCHV
)
378 printf (" %s: %g ", object
, best
);
379 FcValueListPrint (v1orig
);
381 FcValueListPrint (v2orig
);
386 int weak
= _FcMatchers
[i
].weak
;
387 int strong
= _FcMatchers
[i
].strong
;
389 value
[strong
] += best
;
392 value
[weak
] += bestWeak
;
393 value
[strong
] += bestStrong
;
400 * Return a value indicating the distance between the two lists of
405 FcCompare (FcPattern
*pat
,
412 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
417 while (i1
< pat
->num
&& i2
< fnt
->num
)
419 i
= FcObjectPtrCompare((FcPatternEltU(pat
->elts
)+i1
)->object
,
420 (FcPatternEltU(fnt
->elts
)+i2
)->object
);
427 if (!FcCompareValueList (FcObjectPtrU((FcPatternEltU(pat
->elts
)+i1
)->object
),
428 (FcPatternEltU(pat
->elts
)+i1
)->values
,
429 (FcPatternEltU(fnt
->elts
)+i2
)->values
,
440 for (i1
= 0; i1
< pat
->num
; i1
++)
442 for (i2
= 0; i2
< fnt
->num
; i2
++)
444 if (!strcmp (pat
->elts
[i1
].object
, fnt
->elts
[i2
].object
))
455 FcFontRenderPrepare (FcConfig
*config
,
461 FcPatternElt
*fe
, *pe
;
465 new = FcPatternCreate ();
468 for (i
= 0; i
< font
->num
; i
++)
470 fe
= FcPatternEltU(font
->elts
)+i
;
471 pe
= FcPatternFindElt (pat
, FcObjectPtrU(fe
->object
));
474 if (!FcCompareValueList (FcObjectPtrU(pe
->object
), pe
->values
,
475 fe
->values
, &v
, 0, &result
))
477 FcPatternDestroy (new);
482 v
= FcValueCanonicalize(&FcValueListPtrU(fe
->values
)->value
);
483 FcPatternAdd (new, FcObjectPtrU(fe
->object
), v
, FcFalse
);
485 for (i
= 0; i
< pat
->num
; i
++)
487 pe
= FcPatternEltU(pat
->elts
)+i
;
488 fe
= FcPatternFindElt (font
, FcObjectPtrU(pe
->object
));
490 FcPatternAdd (new, FcObjectPtrU(pe
->object
),
491 FcValueCanonicalize(&FcValueListPtrU(pe
->values
)->value
), FcTrue
);
494 if (FcPatternFindElt (font
, FC_FILE
))
495 FcPatternTransferFullFname (new, font
);
497 FcConfigSubstituteWithPat (config
, new, pat
, FcMatchFont
);
502 FcFontSetMatch (FcConfig
*config
,
508 double score
[NUM_MATCH_VALUES
], bestscore
[NUM_MATCH_VALUES
];
515 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
518 if (FcDebug () & FC_DBG_MATCH
)
525 config
= FcConfigGetCurrent ();
528 *result
= FcResultOutOfMemory
;
532 for (set
= 0; set
< nsets
; set
++)
537 for (f
= 0; f
< s
->nfont
; f
++)
539 if (FcDebug () & FC_DBG_MATCHV
)
541 printf ("Font %d ", f
);
542 FcPatternPrint (s
->fonts
[f
]);
544 if (!FcCompare (p
, s
->fonts
[f
], score
, result
))
546 if (FcDebug () & FC_DBG_MATCHV
)
549 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
551 printf (" %g", score
[i
]);
555 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
557 if (best
&& bestscore
[i
] < score
[i
])
559 if (!best
|| score
[i
] < bestscore
[i
])
561 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
562 bestscore
[i
] = score
[i
];
569 if (FcDebug () & FC_DBG_MATCH
)
571 printf ("Best score");
572 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
573 printf (" %g", bestscore
[i
]);
574 FcPatternPrint (best
);
578 *result
= FcResultNoMatch
;
581 return FcFontRenderPrepare (config
, p
, best
);
585 FcFontMatch (FcConfig
*config
,
594 config
= FcConfigGetCurrent ();
599 if (config
->fonts
[FcSetSystem
])
600 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
601 if (config
->fonts
[FcSetApplication
])
602 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
603 return FcFontSetMatch (config
, sets
, nsets
, p
, result
);
606 typedef struct _FcSortNode
{
608 double score
[NUM_MATCH_VALUES
];
612 FcSortCompare (const void *aa
, const void *ab
)
614 FcSortNode
*a
= *(FcSortNode
**) aa
;
615 FcSortNode
*b
= *(FcSortNode
**) ab
;
616 double *as
= &a
->score
[0];
617 double *bs
= &b
->score
[0];
618 double ad
= 0, bd
= 0;
621 i
= NUM_MATCH_VALUES
;
622 while (i
-- && (ad
= *as
++) == (bd
= *bs
++))
624 return ad
< bd
? -1 : ad
> bd
? 1 : 0;
628 FcSortWalk (FcSortNode
**n
, int nnode
, FcFontSet
*fs
, FcCharSet
**cs
, FcBool trim
)
636 if (FcPatternGetCharSet (node
->pattern
, FC_CHARSET
, 0, &ncs
) ==
640 * If this font isn't a subset of the previous fonts,
643 if (!trim
|| !*cs
|| !FcCharSetIsSubset (ncs
, *cs
))
647 ncs
= FcCharSetUnion (ncs
, *cs
);
650 FcCharSetDestroy (*cs
);
653 ncs
= FcCharSetCopy (ncs
);
655 FcPatternReference (node
->pattern
);
656 if (FcDebug () & FC_DBG_MATCH
)
659 FcPatternPrint (node
->pattern
);
661 if (!FcFontSetAdd (fs
, node
->pattern
))
663 FcPatternDestroy (node
->pattern
);
673 FcFontSetSortDestroy (FcFontSet
*fs
)
675 FcFontSetDestroy (fs
);
679 FcFontSetSort (FcConfig
*config
,
690 FcSortNode
**nodeps
, **nodep
;
698 FcBool
*patternLangSat
;
701 if (FcDebug () & FC_DBG_MATCH
)
707 for (set
= 0; set
< nsets
; set
++)
717 for (nPatternLang
= 0;
718 FcPatternGet (p
, FC_LANG
, nPatternLang
, &patternLang
) == FcResultMatch
;
723 nodes
= malloc (nnodes
* sizeof (FcSortNode
) +
724 nnodes
* sizeof (FcSortNode
*) +
725 nPatternLang
* sizeof (FcBool
));
728 nodeps
= (FcSortNode
**) (nodes
+ nnodes
);
729 patternLangSat
= (FcBool
*) (nodeps
+ nnodes
);
733 for (set
= 0; set
< nsets
; set
++)
738 for (f
= 0; f
< s
->nfont
; f
++)
740 if (FcDebug () & FC_DBG_MATCHV
)
742 printf ("Font %d ", f
);
743 FcPatternPrint (s
->fonts
[f
]);
745 new->pattern
= s
->fonts
[f
];
746 if (!FcCompare (p
, new->pattern
, new->score
, result
))
748 if (FcDebug () & FC_DBG_MATCHV
)
751 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
753 printf (" %g", new->score
[i
]);
763 nnodes
= new - nodes
;
765 qsort (nodeps
, nnodes
, sizeof (FcSortNode
*),
768 for (i
= 0; i
< nPatternLang
; i
++)
769 patternLangSat
[i
] = FcFalse
;
771 for (f
= 0; f
< nnodes
; f
++)
773 FcBool satisfies
= FcFalse
;
775 * If this node matches any language, go check
776 * which ones and satisfy those entries
778 if (nodeps
[f
]->score
[MATCH_LANG_INDEX
] < nPatternLang
)
780 for (i
= 0; i
< nPatternLang
; i
++)
784 if (!patternLangSat
[i
] &&
785 FcPatternGet (p
, FC_LANG
, i
, &patternLang
) == FcResultMatch
&&
786 FcPatternGet (nodeps
[f
]->pattern
, FC_LANG
, 0, &nodeLang
) == FcResultMatch
)
788 double compare
= FcCompareLang (FC_LANG
, &patternLang
,
790 if (compare
>= 0 && compare
< 2)
792 if (FcDebug () & FC_DBG_MATCHV
)
797 if (FcPatternGetString (nodeps
[f
]->pattern
, FC_FAMILY
, 0, &family
) == FcResultMatch
&&
798 FcPatternGetString (nodeps
[f
]->pattern
, FC_STYLE
, 0, &style
) == FcResultMatch
)
799 printf ("Font %s:%s matches language %d\n", family
, style
, i
);
801 patternLangSat
[i
] = FcTrue
;
809 nodeps
[f
]->score
[MATCH_LANG_INDEX
] = 1000.0;
813 * Re-sort once the language issues have been settled
815 qsort (nodeps
, nnodes
, sizeof (FcSortNode
*),
818 ret
= FcFontSetCreate ();
824 if (!FcSortWalk (nodeps
, nnodes
, ret
, &cs
, trim
))
830 FcCharSetDestroy (cs
);
838 FcCharSetDestroy (cs
);
839 FcFontSetDestroy (ret
);
847 FcFontSort (FcConfig
*config
,
858 config
= FcConfigGetCurrent ();
863 if (config
->fonts
[FcSetSystem
])
864 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
865 if (config
->fonts
[FcSetApplication
])
866 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
867 return FcFontSetSort (config
, sets
, nsets
, p
, trim
, csp
, result
);