]>
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 (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 (char *object
, FcValue value1
, FcValue value2
)
64 if (value2
.type
!= FcTypeString
|| value1
.type
!= FcTypeString
)
66 return (double) FcStrCmpIgnoreCase (value1
.u
.s
, value2
.u
.s
) != 0;
70 FcCompareFamily (char *object
, FcValue value1
, FcValue value2
)
72 if (value2
.type
!= FcTypeString
|| value1
.type
!= FcTypeString
)
74 return (double) FcStrCmpIgnoreBlanksAndCase (value1
.u
.s
, value2
.u
.s
) != 0;
78 FcCompareLang (char *object
, FcValue value1
, FcValue value2
)
82 switch (value1
.type
) {
84 switch (value2
.type
) {
86 result
= FcLangSetCompare (value1
.u
.l
, value2
.u
.l
);
89 result
= FcLangSetHasLang (value1
.u
.l
, value2
.u
.s
);
96 switch (value2
.type
) {
98 result
= FcLangSetHasLang (value2
.u
.l
, value1
.u
.s
);
101 result
= FcLangCompare (value1
.u
.s
, value2
.u
.s
);
113 case FcLangDifferentCountry
:
115 case FcLangDifferentLang
:
122 FcCompareBool (char *object
, FcValue value1
, FcValue value2
)
124 if (value2
.type
!= FcTypeBool
|| value1
.type
!= FcTypeBool
)
126 return (double) value2
.u
.b
!= value1
.u
.b
;
130 FcCompareCharSet (char *object
, FcValue value1
, FcValue value2
)
132 if (value2
.type
!= FcTypeCharSet
|| value1
.type
!= FcTypeCharSet
)
134 return (double) FcCharSetSubtractCount (value1
.u
.c
, value2
.u
.c
);
138 FcCompareSize (char *object
, FcValue value1
, FcValue value2
)
142 switch (value1
.type
) {
152 switch (value2
.type
) {
170 typedef struct _FcMatcher
{
172 double (*compare
) (char *object
, FcValue value1
, FcValue value2
);
177 * Order is significant, it defines the precedence of
178 * each value, earlier values are more significant than
181 static FcMatcher _FcMatchers
[] = {
182 { FC_FOUNDRY
, FcCompareString
, 0, 0 },
183 #define MATCH_FOUNDRY 0
185 { FC_CHARSET
, FcCompareCharSet
, 1, 1 },
186 #define MATCH_CHARSET 1
188 { FC_FAMILY
, FcCompareFamily
, 2, 4 },
189 #define MATCH_FAMILY 2
191 { FC_LANG
, FcCompareLang
, 3, 3 },
194 { FC_SPACING
, FcCompareNumber
, 5, 5 },
195 #define MATCH_SPACING 4
197 { FC_PIXEL_SIZE
, FcCompareSize
, 6, 6 },
198 #define MATCH_PIXEL_SIZE 5
200 { FC_STYLE
, FcCompareString
, 7, 7 },
201 #define MATCH_STYLE 6
203 { FC_SLANT
, FcCompareNumber
, 8, 8 },
204 #define MATCH_SLANT 7
206 { FC_WEIGHT
, FcCompareNumber
, 9, 9 },
207 #define MATCH_WEIGHT 8
209 { FC_WIDTH
, FcCompareNumber
, 10, 10 },
210 #define MATCH_WIDTH 9
212 { FC_ANTIALIAS
, FcCompareBool
, 11, 11 },
213 #define MATCH_ANTIALIAS 10
215 { FC_RASTERIZER
, FcCompareString
, 12, 12 },
216 #define MATCH_RASTERIZER 11
218 { FC_OUTLINE
, FcCompareBool
, 13, 13 },
219 #define MATCH_OUTLINE 12
221 { FC_FONTVERSION
, FcCompareNumber
, 14, 14 },
222 #define MATCH_FONTVERSION 13
225 #define NUM_MATCH_VALUES 15
228 FcCompareValueList (const char *object
,
229 FcValueList
*v1orig
, /* pattern */
230 FcValueList
*v2orig
, /* target */
235 FcValueList
*v1
, *v2
;
236 double v
, best
, bestStrong
, bestWeak
;
241 * Locate the possible matching entry by examining the
242 * first few characters in object
245 switch (FcToLower (object
[0])) {
247 switch (FcToLower (object
[1])) {
249 switch (FcToLower (object
[2])) {
251 i
= MATCH_FOUNDRY
; break;
253 i
= MATCH_FONTVERSION
; break;
257 i
= MATCH_FAMILY
; break;
261 i
= MATCH_CHARSET
; break;
263 i
= MATCH_ANTIALIAS
; break;
265 i
= MATCH_LANG
; break;
267 switch (FcToLower (object
[1])) {
269 i
= MATCH_SPACING
; break;
271 i
= MATCH_STYLE
; break;
273 i
= MATCH_SLANT
; break;
277 i
= MATCH_PIXEL_SIZE
; break;
279 switch (FcToLower (object
[1])) {
281 i
= MATCH_WIDTH
; break;
283 i
= MATCH_WEIGHT
; break;
287 i
= MATCH_RASTERIZER
; break;
289 i
= MATCH_OUTLINE
; break;
292 FcStrCmpIgnoreCase ((FcChar8
*) _FcMatchers
[i
].object
,
293 (FcChar8
*) object
) != 0)
296 *bestValue
= v2orig
->value
;
300 for (i
= 0; i
< NUM_MATCHER
; i
++)
302 if (!FcStrCmpIgnoreCase ((FcChar8
*) _FcMatchers
[i
].object
,
306 if (i
== NUM_MATCHER
)
309 *bestValue
= v2orig
->value
;
317 for (v1
= v1orig
; v1
; v1
= v1
->next
)
319 for (v2
= v2orig
; v2
; v2
= v2
->next
)
321 v
= (*_FcMatchers
[i
].compare
) (_FcMatchers
[i
].object
,
326 *result
= FcResultTypeMismatch
;
329 if (FcDebug () & FC_DBG_MATCHV
)
330 printf (" v %g j %d ", v
, j
);
335 *bestValue
= v2
->value
;
338 if (v1
->binding
== FcValueBindingStrong
)
351 if (FcDebug () & FC_DBG_MATCHV
)
353 printf (" %s: %g ", object
, best
);
354 FcValueListPrint (v1orig
);
356 FcValueListPrint (v2orig
);
361 int weak
= _FcMatchers
[i
].weak
;
362 int strong
= _FcMatchers
[i
].strong
;
364 value
[strong
] += best
;
367 value
[weak
] += bestWeak
;
368 value
[strong
] += bestStrong
;
375 * Return a value indicating the distance between the two lists of
380 FcCompare (FcPattern
*pat
,
387 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
392 while (i1
< pat
->num
&& i2
< fnt
->num
)
394 i
= strcmp (pat
->elts
[i1
].object
, fnt
->elts
[i2
].object
);
401 if (!FcCompareValueList (pat
->elts
[i1
].object
,
402 pat
->elts
[i1
].values
,
403 fnt
->elts
[i2
].values
,
414 for (i1
= 0; i1
< pat
->num
; i1
++)
416 for (i2
= 0; i2
< fnt
->num
; i2
++)
418 if (!strcmp (pat
->elts
[i1
].object
, fnt
->elts
[i2
].object
))
429 FcFontRenderPrepare (FcConfig
*config
,
435 FcPatternElt
*fe
, *pe
;
439 new = FcPatternCreate ();
442 for (i
= 0; i
< font
->num
; i
++)
445 pe
= FcPatternFindElt (pat
, fe
->object
);
448 if (!FcCompareValueList (pe
->object
, pe
->values
,
449 fe
->values
, &v
, 0, &result
))
451 FcPatternDestroy (new);
456 v
= fe
->values
->value
;
457 FcPatternAdd (new, fe
->object
, v
, FcFalse
);
459 for (i
= 0; i
< pat
->num
; i
++)
462 fe
= FcPatternFindElt (font
, pe
->object
);
464 FcPatternAdd (new, pe
->object
, pe
->values
->value
, FcTrue
);
466 FcConfigSubstituteWithPat (config
, new, pat
, FcMatchFont
);
471 FcFontSetMatch (FcConfig
*config
,
477 double score
[NUM_MATCH_VALUES
], bestscore
[NUM_MATCH_VALUES
];
484 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
487 if (FcDebug () & FC_DBG_MATCH
)
494 config
= FcConfigGetCurrent ();
498 for (set
= 0; set
< nsets
; set
++)
503 for (f
= 0; f
< s
->nfont
; f
++)
505 if (FcDebug () & FC_DBG_MATCHV
)
507 printf ("Font %d ", f
);
508 FcPatternPrint (s
->fonts
[f
]);
510 if (!FcCompare (p
, s
->fonts
[f
], score
, result
))
512 if (FcDebug () & FC_DBG_MATCHV
)
515 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
517 printf (" %g", score
[i
]);
521 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
523 if (best
&& bestscore
[i
] < score
[i
])
525 if (!best
|| score
[i
] < bestscore
[i
])
527 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
528 bestscore
[i
] = score
[i
];
535 if (FcDebug () & FC_DBG_MATCH
)
537 printf ("Best score");
538 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
539 printf (" %g", bestscore
[i
]);
540 FcPatternPrint (best
);
544 *result
= FcResultNoMatch
;
547 return FcFontRenderPrepare (config
, p
, best
);
551 FcFontMatch (FcConfig
*config
,
560 config
= FcConfigGetCurrent ();
565 if (config
->fonts
[FcSetSystem
])
566 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
567 if (config
->fonts
[FcSetApplication
])
568 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
569 return FcFontSetMatch (config
, sets
, nsets
, p
, result
);
572 typedef struct _FcSortNode
{
574 double score
[NUM_MATCH_VALUES
];
578 FcSortCompare (const void *aa
, const void *ab
)
580 FcSortNode
*a
= *(FcSortNode
**) aa
;
581 FcSortNode
*b
= *(FcSortNode
**) ab
;
582 double *as
= &a
->score
[0];
583 double *bs
= &b
->score
[0];
584 double ad
= 0, bd
= 0;
587 i
= NUM_MATCH_VALUES
;
588 while (i
-- && (ad
= *as
++) == (bd
= *bs
++))
590 return ad
< bd
? -1 : ad
> bd
? 1 : 0;
594 FcSortWalk (FcSortNode
**n
, int nnode
, FcFontSet
*fs
, FcCharSet
**cs
, FcBool trim
)
602 if (FcPatternGetCharSet (node
->pattern
, FC_CHARSET
, 0, &ncs
) ==
606 * If this font isn't a subset of the previous fonts,
609 if (!trim
|| !*cs
|| !FcCharSetIsSubset (ncs
, *cs
))
613 ncs
= FcCharSetUnion (ncs
, *cs
);
616 FcCharSetDestroy (*cs
);
619 ncs
= FcCharSetCopy (ncs
);
621 FcPatternReference (node
->pattern
);
622 if (FcDebug () & FC_DBG_MATCH
)
625 FcPatternPrint (node
->pattern
);
627 if (!FcFontSetAdd (fs
, node
->pattern
))
629 FcPatternDestroy (node
->pattern
);
639 FcFontSetSortDestroy (FcFontSet
*fs
)
641 FcFontSetDestroy (fs
);
645 FcFontSetSort (FcConfig
*config
,
656 FcSortNode
**nodeps
, **nodep
;
664 if (FcDebug () & FC_DBG_MATCH
)
670 for (set
= 0; set
< nsets
; set
++)
680 nodes
= malloc (nnodes
* sizeof (FcSortNode
) + nnodes
* sizeof (FcSortNode
*));
683 nodeps
= (FcSortNode
**) (nodes
+ nnodes
);
687 for (set
= 0; set
< nsets
; set
++)
692 for (f
= 0; f
< s
->nfont
; f
++)
694 if (FcDebug () & FC_DBG_MATCHV
)
696 printf ("Font %d ", f
);
697 FcPatternPrint (s
->fonts
[f
]);
699 new->pattern
= s
->fonts
[f
];
700 if (!FcCompare (p
, new->pattern
, new->score
, result
))
702 if (FcDebug () & FC_DBG_MATCHV
)
705 for (i
= 0; i
< NUM_MATCH_VALUES
; i
++)
707 printf (" %g", new->score
[i
]);
717 nnodes
= new - nodes
;
719 qsort (nodeps
, nnodes
, sizeof (FcSortNode
*),
722 ret
= FcFontSetCreate ();
728 if (!FcSortWalk (nodeps
, nnodes
, ret
, &cs
, trim
))
734 FcCharSetDestroy (cs
);
742 FcCharSetDestroy (cs
);
743 FcFontSetDestroy (ret
);
751 FcFontSort (FcConfig
*config
,
762 config
= FcConfigGetCurrent ();
767 if (config
->fonts
[FcSetSystem
])
768 sets
[nsets
++] = config
->fonts
[FcSetSystem
];
769 if (config
->fonts
[FcSetApplication
])
770 sets
[nsets
++] = config
->fonts
[FcSetApplication
];
771 return FcFontSetSort (config
, sets
, nsets
, p
, trim
, csp
, result
);