]>
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 (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 (FcValue
*v1
, FcValue
*v2
)
64 return (double) FcStrCmpIgnoreCase (fc_value_string(v1
), fc_value_string(v2
)) != 0;
68 FcCompareFamily (FcValue
*v1
, FcValue
*v2
)
70 /* rely on the guarantee in FcPatternAddWithBinding that
71 * families are always FcTypeString. */
72 const FcChar8
* v1_string
= fc_value_string(v1
);
73 const FcChar8
* v2_string
= fc_value_string(v2
);
75 if (FcToLower(*v1_string
) != FcToLower(*v2_string
))
78 return (double) FcStrCmpIgnoreBlanksAndCase (v1_string
, v2_string
) != 0;
82 FcCompareLang (FcValue
*v1
, FcValue
*v2
)
85 FcValue value1
= FcValueCanonicalize(v1
), value2
= FcValueCanonicalize(v2
);
87 switch (value1
.type
) {
89 switch (value2
.type
) {
91 result
= FcLangSetCompare (value1
.u
.l
, value2
.u
.l
);
94 result
= FcLangSetHasLang (value1
.u
.l
,
102 switch (value2
.type
) {
104 result
= FcLangSetHasLang (value2
.u
.l
, value1
.u
.s
);
107 result
= FcLangCompare (value1
.u
.s
,
120 case FcLangDifferentCountry
:
122 case FcLangDifferentLang
:
129 FcCompareBool (FcValue
*v1
, FcValue
*v2
)
131 if (fc_storage_type(v2
) != FcTypeBool
|| fc_storage_type(v1
) != FcTypeBool
)
133 return (double) v2
->u
.b
!= v1
->u
.b
;
137 FcCompareCharSet (FcValue
*v1
, FcValue
*v2
)
139 return (double) FcCharSetSubtractCount (fc_value_charset(v1
), fc_value_charset(v2
));
143 FcCompareSize (FcValue
*value1
, FcValue
*value2
)
147 switch (value1
->type
) {
157 switch (value2
->type
) {
175 typedef struct _FcMatcher
{
177 double (*compare
) (FcValue
*value1
, FcValue
*value2
);
182 * Order is significant, it defines the precedence of
183 * each value, earlier values are more significant than
186 static FcMatcher _FcMatchers
[] = {
187 { FC_FOUNDRY_OBJECT
, FcCompareString
, 0, 0 },
188 #define MATCH_FOUNDRY 0
189 #define MATCH_FOUNDRY_INDEX 0
191 { FC_CHARSET_OBJECT
, FcCompareCharSet
, 1, 1 },
192 #define MATCH_CHARSET 1
193 #define MATCH_CHARSET_INDEX 1
195 { FC_FAMILY_OBJECT
, FcCompareFamily
, 2, 4 },
196 #define MATCH_FAMILY 2
197 #define MATCH_FAMILY_STRONG_INDEX 2
198 #define MATCH_FAMILY_WEAK_INDEX 4
200 { FC_LANG_OBJECT
, FcCompareLang
, 3, 3 },
202 #define MATCH_LANG_INDEX 3
204 { FC_SPACING_OBJECT
, FcCompareNumber
, 5, 5 },
205 #define MATCH_SPACING 4
206 #define MATCH_SPACING_INDEX 5
208 { FC_PIXEL_SIZE_OBJECT
, FcCompareSize
, 6, 6 },
209 #define MATCH_PIXEL_SIZE 5
210 #define MATCH_PIXEL_SIZE_INDEX 6
212 { FC_STYLE_OBJECT
, FcCompareString
, 7, 7 },
213 #define MATCH_STYLE 6
214 #define MATCH_STYLE_INDEX 7
216 { FC_SLANT_OBJECT
, FcCompareNumber
, 8, 8 },
217 #define MATCH_SLANT 7
218 #define MATCH_SLANT_INDEX 8
220 { FC_WEIGHT_OBJECT
, FcCompareNumber
, 9, 9 },
221 #define MATCH_WEIGHT 8
222 #define MATCH_WEIGHT_INDEX 9
224 { FC_WIDTH_OBJECT
, FcCompareNumber
, 10, 10 },
225 #define MATCH_WIDTH 9
226 #define MATCH_WIDTH_INDEX 10
228 { FC_ANTIALIAS_OBJECT
, FcCompareBool
, 11, 11 },
229 #define MATCH_ANTIALIAS 10
230 #define MATCH_ANTIALIAS_INDEX 11
232 { FC_RASTERIZER_OBJECT
, FcCompareString
, 12, 12 },
233 #define MATCH_RASTERIZER 11
234 #define MATCH_RASTERIZER_INDEX 12
236 { FC_OUTLINE_OBJECT
, FcCompareBool
, 13, 13 },
237 #define MATCH_OUTLINE 12
238 #define MATCH_OUTLINE_INDEX 13
240 { FC_FONTVERSION_OBJECT
, FcCompareNumber
, 14, 14 },
241 #define MATCH_FONTVERSION 13
242 #define MATCH_FONTVERSION_INDEX 14
245 #define NUM_MATCH_VALUES 15
248 FcObjectToMatcher (FcObject object
)
254 case FC_FOUNDRY_OBJECT
:
255 i
= MATCH_FOUNDRY
; break;
256 case FC_FONTVERSION_OBJECT
:
257 i
= MATCH_FONTVERSION
; break;
258 case FC_FAMILY_OBJECT
:
259 i
= MATCH_FAMILY
; break;
260 case FC_CHARSET_OBJECT
:
261 i
= MATCH_CHARSET
; break;
262 case FC_ANTIALIAS_OBJECT
:
263 i
= MATCH_ANTIALIAS
; break;
265 i
= MATCH_LANG
; break;
266 case FC_SPACING_OBJECT
:
267 i
= MATCH_SPACING
; break;
268 case FC_STYLE_OBJECT
:
269 i
= MATCH_STYLE
; break;
270 case FC_SLANT_OBJECT
:
271 i
= MATCH_SLANT
; break;
272 case FC_PIXEL_SIZE_OBJECT
:
273 i
= MATCH_PIXEL_SIZE
; break;
274 case FC_WIDTH_OBJECT
:
275 i
= MATCH_WIDTH
; break;
276 case FC_WEIGHT_OBJECT
:
277 i
= MATCH_WEIGHT
; break;
278 case FC_RASTERIZER_OBJECT
:
279 i
= MATCH_RASTERIZER
; break;
280 case FC_OUTLINE_OBJECT
:
281 i
= MATCH_OUTLINE
; break;
287 return _FcMatchers
+i
;
291 FcCompareValueList (FcObject object
,
292 FcValueListPtr v1orig
, /* pattern */
293 FcValueListPtr v2orig
, /* target */
298 FcValueListPtr v1
, v2
;
299 double v
, best
, bestStrong
, bestWeak
;
301 FcMatcher
*match
= FcObjectToMatcher(object
);
306 *bestValue
= FcValueCanonicalize(&v2orig
->value
);
314 for (v1
= v1orig
; v1
; v1
= FcValueListNext(v1
))
316 for (v2
= v2orig
; v2
; v2
= FcValueListNext(v2
))
318 v
= (match
->compare
) (&v1
->value
, &v2
->value
);
321 *result
= FcResultTypeMismatch
;
328 *bestValue
= FcValueCanonicalize(&v2
->value
);
331 if (v1
->binding
== FcValueBindingStrong
)
344 if (FcDebug () & FC_DBG_MATCHV
)
346 printf (" %s: %g ", FcObjectName (object
), best
);
347 FcValueListPrint (v1orig
);
349 FcValueListPrint (v2orig
);
354 int weak
= match
->weak
;
355 int strong
= match
->strong
;
357 value
[strong
] += best
;
360 value
[weak
] += bestWeak
;
361 value
[strong
] += bestStrong
;
368 * Return a value indicating the distance between the two lists of
373 FcCompare (FcPattern
*pat
,
380 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
385 while (i1
< pat
->num
&& i2
< fnt
->num
)
387 FcPatternElt
*elt_i1
= &FcPatternElts(pat
)[i1
];
388 FcPatternElt
*elt_i2
= &FcPatternElts(fnt
)[i2
];
390 i
= FcObjectCompare(elt_i1
->object
, elt_i2
->object
);
397 if (!FcCompareValueList (elt_i1
->object
,
398 FcPatternEltValues(elt_i1
),
399 FcPatternEltValues(elt_i2
),
410 FcFontRenderPrepare (FcConfig
*config
,
416 FcPatternElt
*fe
, *pe
;
420 new = FcPatternCreate ();
423 for (i
= 0; i
< font
->num
; i
++)
425 fe
= &FcPatternElts(font
)[i
];
426 pe
= FcPatternObjectFindElt (pat
, fe
->object
);
429 if (!FcCompareValueList (pe
->object
, FcPatternEltValues(pe
),
430 FcPatternEltValues(fe
), &v
, 0, &result
))
432 FcPatternDestroy (new);
437 v
= FcValueCanonicalize(&FcPatternEltValues (fe
)->value
);
438 FcPatternObjectAdd (new, fe
->object
, v
, FcFalse
);
440 for (i
= 0; i
< pat
->num
; i
++)
442 pe
= &FcPatternElts(pat
)[i
];
443 fe
= FcPatternObjectFindElt (font
, pe
->object
);
446 v
= FcValueCanonicalize(&FcPatternEltValues(pe
)->value
);
447 FcPatternObjectAdd (new, pe
->object
, v
, FcTrue
);
451 FcConfigSubstituteWithPat (config
, new, pat
, FcMatchFont
);
456 FcFontSetMatch (FcConfig
*config
,
462 double score
[NUM_MATCH_VALUES
], bestscore
[NUM_MATCH_VALUES
];
469 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
472 if (FcDebug () & FC_DBG_MATCH
)
479 config
= FcConfigGetCurrent ();
483 for (set
= 0; set
< nsets
; set
++)
488 for (f
= 0; f
< s
->nfont
; f
++)
490 if (FcDebug () & FC_DBG_MATCHV
)
492 printf ("Font %d ", f
);
493 FcPatternPrint (s
->fonts
[f
]);
495 if (!FcCompare (p
, s
->fonts
[f
], score
, result
))
497 if (FcDebug () & FC_DBG_MATCHV
)
500 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
502 printf (" %g", score
[i
]);
506 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
508 if (best
&& bestscore
[i
] < score
[i
])
510 if (!best
|| score
[i
] < bestscore
[i
])
512 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
513 bestscore
[i
] = score
[i
];
520 if (FcDebug () & FC_DBG_MATCH
)
522 printf ("Best score");
523 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
524 printf (" %g", bestscore
[i
]);
525 FcPatternPrint (best
);
529 *result
= FcResultNoMatch
;
532 return FcFontRenderPrepare (config
, p
, best
);
536 FcFontMatch (FcConfig
*config
,
545 config
= FcConfigGetCurrent ();
550 if (config
->fonts
[FcSetSystem
])
551 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
552 if (config
->fonts
[FcSetApplication
])
553 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
554 return FcFontSetMatch (config
, sets
, nsets
, p
, result
);
557 typedef struct _FcSortNode
{
559 double score
[NUM_MATCH_VALUES
];
563 FcSortCompare (const void *aa
, const void *ab
)
565 FcSortNode
*a
= *(FcSortNode
**) aa
;
566 FcSortNode
*b
= *(FcSortNode
**) ab
;
567 double *as
= &a
->score
[0];
568 double *bs
= &b
->score
[0];
569 double ad
= 0, bd
= 0;
572 i
= NUM_MATCH_VALUES
;
573 while (i
-- && (ad
= *as
++) == (bd
= *bs
++))
575 return ad
< bd
? -1 : ad
> bd
? 1 : 0;
579 FcSortWalk (FcSortNode
**n
, int nnode
, FcFontSet
*fs
, FcCharSet
**cs
, FcBool trim
, FcBool build_cs
)
587 if (FcPatternGetCharSet (node
->pattern
, FC_CHARSET
, 0, &ncs
) ==
591 * If this font isn't a subset of the previous fonts,
594 if (!trim
|| !*cs
|| !FcCharSetIsSubset (ncs
, *cs
))
596 if (trim
|| build_cs
)
600 ncs
= FcCharSetUnion (ncs
, *cs
);
603 FcCharSetDestroy (*cs
);
606 ncs
= FcCharSetCopy (ncs
);
610 FcPatternReference (node
->pattern
);
611 if (FcDebug () & FC_DBG_MATCHV
)
614 FcPatternPrint (node
->pattern
);
616 if (!FcFontSetAdd (fs
, node
->pattern
))
618 FcPatternDestroy (node
->pattern
);
628 FcFontSetSortDestroy (FcFontSet
*fs
)
630 FcFontSetDestroy (fs
);
634 FcFontSetSort (FcConfig
*config
,
645 FcSortNode
**nodeps
, **nodep
;
653 FcBool
*patternLangSat
;
656 if (FcDebug () & FC_DBG_MATCH
)
662 for (set
= 0; set
< nsets
; set
++)
672 for (nPatternLang
= 0;
673 FcPatternGet (p
, FC_LANG
, nPatternLang
, &patternLang
) == FcResultMatch
;
678 nodes
= malloc (nnodes
* sizeof (FcSortNode
) +
679 nnodes
* sizeof (FcSortNode
*) +
680 nPatternLang
* sizeof (FcBool
));
683 nodeps
= (FcSortNode
**) (nodes
+ nnodes
);
684 patternLangSat
= (FcBool
*) (nodeps
+ nnodes
);
688 for (set
= 0; set
< nsets
; set
++)
693 for (f
= 0; f
< s
->nfont
; f
++)
695 if (FcDebug () & FC_DBG_MATCHV
)
697 printf ("Font %d ", f
);
698 FcPatternPrint (s
->fonts
[f
]);
700 new->pattern
= s
->fonts
[f
];
701 if (!FcCompare (p
, new->pattern
, new->score
, result
))
703 if (FcDebug () & FC_DBG_MATCHV
)
706 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
708 printf (" %g", new->score
[i
]);
718 nnodes
= new - nodes
;
720 qsort (nodeps
, nnodes
, sizeof (FcSortNode
*),
723 for (i
= 0; i
< nPatternLang
; i
++)
724 patternLangSat
[i
] = FcFalse
;
726 for (f
= 0; f
< nnodes
; f
++)
728 FcBool satisfies
= FcFalse
;
730 * If this node matches any language, go check
731 * which ones and satisfy those entries
733 if (nodeps
[f
]->score
[MATCH_LANG_INDEX
] < nPatternLang
)
735 for (i
= 0; i
< nPatternLang
; i
++)
739 if (!patternLangSat
[i
] &&
740 FcPatternGet (p
, FC_LANG
, i
, &patternLang
) == FcResultMatch
&&
741 FcPatternGet (nodeps
[f
]->pattern
, FC_LANG
, 0, &nodeLang
) == FcResultMatch
)
743 double compare
= FcCompareLang (&patternLang
, &nodeLang
);
744 if (compare
>= 0 && compare
< 2)
746 if (FcDebug () & FC_DBG_MATCHV
)
751 if (FcPatternGetString (nodeps
[f
]->pattern
, FC_FAMILY
, 0, &family
) == FcResultMatch
&&
752 FcPatternGetString (nodeps
[f
]->pattern
, FC_STYLE
, 0, &style
) == FcResultMatch
)
753 printf ("Font %s:%s matches language %d\n", family
, style
, i
);
755 patternLangSat
[i
] = FcTrue
;
763 nodeps
[f
]->score
[MATCH_LANG_INDEX
] = 1000.0;
767 * Re-sort once the language issues have been settled
769 qsort (nodeps
, nnodes
, sizeof (FcSortNode
*),
772 ret
= FcFontSetCreate ();
778 if (!FcSortWalk (nodeps
, nnodes
, ret
, &cs
, trim
, (csp
!=0)))
786 FcCharSetDestroy (cs
);
791 if (FcDebug() & FC_DBG_MATCH
)
793 printf ("First font ");
794 FcPatternPrint (ret
->fonts
[0]);
800 FcCharSetDestroy (cs
);
801 FcFontSetDestroy (ret
);
809 FcFontSort (FcConfig
*config
,
820 config
= FcConfigGetCurrent ();
825 if (config
->fonts
[FcSetSystem
])
826 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
827 if (config
->fonts
[FcSetApplication
])
828 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
829 return FcFontSetSort (config
, sets
, nsets
, p
, trim
, csp
, result
);