source: trunk/poppler/fontconfig-2.3.2-os2/src/fcmatch.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

File size: 18.0 KB
Line 
1/*
2 * $RCSId: xc/lib/fontconfig/src/fcmatch.c,v 1.20 2002/08/31 22:17:32 keithp Exp $
3 *
4 * Copyright © 2000 Keith Packard
5 *
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.
15 *
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.
23 */
24
25#include <string.h>
26#include <ctype.h>
27#include "fcint.h"
28#include <stdio.h>
29
30static double
31FcCompareNumber (char *object, FcValue value1, FcValue value2)
32{
33    double  v1, v2, v;
34   
35    switch (value1.type) {
36    case FcTypeInteger:
37        v1 = (double) value1.u.i;
38        break;
39    case FcTypeDouble:
40        v1 = value1.u.d;
41        break;
42    default:
43        return -1.0;
44    }
45    switch (value2.type) {
46    case FcTypeInteger:
47        v2 = (double) value2.u.i;
48        break;
49    case FcTypeDouble:
50        v2 = value2.u.d;
51        break;
52    default:
53        return -1.0;
54    }
55    v = v2 - v1;
56    if (v < 0)
57        v = -v;
58    return (double) v;
59}
60
61static double
62FcCompareString (char *object, FcValue value1, FcValue value2)
63{
64    if (value2.type != FcTypeString || value1.type != FcTypeString)
65        return -1.0;
66    return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
67}
68
69static double
70FcCompareFamily (char *object, FcValue value1, FcValue value2)
71{
72    if (value2.type != FcTypeString || value1.type != FcTypeString)
73        return -1.0;
74    return (double) FcStrCmpIgnoreBlanksAndCase (value1.u.s, value2.u.s) != 0;
75}
76
77static double
78FcCompareLang (char *object, FcValue value1, FcValue value2)
79{
80    FcLangResult    result;
81   
82    switch (value1.type) {
83    case FcTypeLangSet:
84        switch (value2.type) {
85        case FcTypeLangSet:
86            result = FcLangSetCompare (value1.u.l, value2.u.l);
87            break;
88        case FcTypeString:
89            result = FcLangSetHasLang (value1.u.l, value2.u.s);
90            break;
91        default:
92            return -1.0;
93        }
94        break;
95    case FcTypeString:
96        switch (value2.type) {
97        case FcTypeLangSet:
98            result = FcLangSetHasLang (value2.u.l, value1.u.s);
99            break;
100        case FcTypeString:
101            result = FcLangCompare (value1.u.s, value2.u.s);
102            break;
103        default:
104            return -1.0;
105        }
106        break;
107    default:
108        return -1.0;
109    }
110    switch (result) {
111    case FcLangEqual:
112        return 0;
113    case FcLangDifferentCountry:
114        return 1;
115    case FcLangDifferentLang:
116    default:
117        return 2;
118    }
119}
120
121static double
122FcCompareBool (char *object, FcValue value1, FcValue value2)
123{
124    if (value2.type != FcTypeBool || value1.type != FcTypeBool)
125        return -1.0;
126    return (double) value2.u.b != value1.u.b;
127}
128
129static double
130FcCompareCharSet (char *object, FcValue value1, FcValue value2)
131{
132    if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
133        return -1.0;
134    return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
135}
136
137static double
138FcCompareSize (char *object, FcValue value1, FcValue value2)
139{
140    double  v1, v2, v;
141
142    switch (value1.type) {
143    case FcTypeInteger:
144        v1 = value1.u.i;
145        break;
146    case FcTypeDouble:
147        v1 = value1.u.d;
148        break;
149    default:
150        return -1;
151    }
152    switch (value2.type) {
153    case FcTypeInteger:
154        v2 = value2.u.i;
155        break;
156    case FcTypeDouble:
157        v2 = value2.u.d;
158        break;
159    default:
160        return -1;
161    }
162    if (v2 == 0)
163        return 0;
164    v = v2 - v1;
165    if (v < 0)
166        v = -v;
167    return v;
168}
169
170typedef struct _FcMatcher {
171    char            *object;
172    double          (*compare) (char *object, FcValue value1, FcValue value2);
173    int             strong, weak;
174} FcMatcher;
175
176/*
177 * Order is significant, it defines the precedence of
178 * each value, earlier values are more significant than
179 * later values
180 */
181static FcMatcher _FcMatchers [] = {
182    { FC_FOUNDRY,       FcCompareString,        0, 0 },
183#define MATCH_FOUNDRY       0
184#define MATCH_FOUNDRY_INDEX 0
185   
186    { FC_CHARSET,       FcCompareCharSet,       1, 1 },
187#define MATCH_CHARSET       1
188#define MATCH_CHARSET_INDEX 1
189   
190    { FC_FAMILY,        FcCompareFamily,        2, 4 },
191#define MATCH_FAMILY        2
192#define MATCH_FAMILY_STRONG_INDEX   2
193#define MATCH_FAMILY_WEAK_INDEX     4
194   
195    { FC_LANG,          FcCompareLang,          3, 3 },
196#define MATCH_LANG          3
197#define MATCH_LANG_INDEX    3
198   
199    { FC_SPACING,       FcCompareNumber,        5, 5 },
200#define MATCH_SPACING       4
201#define MATCH_SPACING_INDEX 5
202   
203    { FC_PIXEL_SIZE,    FcCompareSize,          6, 6 },
204#define MATCH_PIXEL_SIZE    5
205#define MATCH_PIXEL_SIZE_INDEX  6
206   
207    { FC_STYLE,         FcCompareString,        7, 7 },
208#define MATCH_STYLE         6
209#define MATCH_STYLE_INDEX   7
210   
211    { FC_SLANT,         FcCompareNumber,        8, 8 },
212#define MATCH_SLANT         7
213#define MATCH_SLANT_INDEX   8
214   
215    { FC_WEIGHT,        FcCompareNumber,        9, 9 },
216#define MATCH_WEIGHT        8
217#define MATCH_WEIGHT_INDEX  9
218   
219    { FC_WIDTH,         FcCompareNumber,        10, 10 },
220#define MATCH_WIDTH         9
221#define MATCH_WIDTH_INDEX   10
222   
223    { FC_ANTIALIAS,     FcCompareBool,          11, 11 },
224#define MATCH_ANTIALIAS     10
225#define MATCH_ANTIALIAS_INDEX       11
226   
227    { FC_RASTERIZER,    FcCompareString,        12, 12 },
228#define MATCH_RASTERIZER    11
229#define MATCH_RASTERIZER_INDEX    12
230
231    { FC_OUTLINE,       FcCompareBool,          13, 13 },
232#define MATCH_OUTLINE       12
233#define MATCH_OUTLINE_INDEX         13
234
235    { FC_FONTVERSION,   FcCompareNumber,        14, 14 },
236#define MATCH_FONTVERSION   13
237#define MATCH_FONTVERSION_INDEX   14
238};
239
240#define NUM_MATCH_VALUES    15
241
242static FcBool
243FcCompareValueList (const char  *object,
244                    FcValueList *v1orig,        /* pattern */
245                    FcValueList *v2orig,        /* target */
246                    FcValue     *bestValue,
247                    double      *value,
248                    FcResult    *result)
249{
250    FcValueList    *v1, *v2;
251    double          v, best, bestStrong, bestWeak;
252    int             i;
253    int             j;
254   
255    /*
256     * Locate the possible matching entry by examining the
257     * first few characters in object
258     */
259    i = -1;
260    switch (FcToLower (object[0])) {
261    case 'f':
262        switch (FcToLower (object[1])) {
263        case 'o':
264            switch (FcToLower (object[2])) {
265            case 'u':
266                i = MATCH_FOUNDRY; break;
267            case 'n':
268                i = MATCH_FONTVERSION; break;
269            }
270            break;
271        case 'a':
272            i = MATCH_FAMILY; break;
273        }
274        break;
275    case 'c':
276        i = MATCH_CHARSET; break;
277    case 'a':
278        i = MATCH_ANTIALIAS; break;
279    case 'l':
280        i = MATCH_LANG; break;
281    case 's':
282        switch (FcToLower (object[1])) {
283        case 'p':
284            i = MATCH_SPACING; break;
285        case 't':
286            i = MATCH_STYLE; break;
287        case 'l':
288            i = MATCH_SLANT; break;
289        }
290        break;
291    case 'p':
292        i = MATCH_PIXEL_SIZE; break;
293    case 'w':
294        switch (FcToLower (object[1])) {
295        case 'i':
296            i = MATCH_WIDTH; break;
297        case 'e':
298            i = MATCH_WEIGHT; break;
299        }
300        break;
301    case 'r':
302        i = MATCH_RASTERIZER; break;
303    case 'o':
304        i = MATCH_OUTLINE; break;
305    }
306    if (i == -1 || 
307        FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
308                            (FcChar8 *) object) != 0)
309    {
310        if (bestValue)
311            *bestValue = v2orig->value;
312        return FcTrue;
313    }
314#if 0
315    for (i = 0; i < NUM_MATCHER; i++)
316    {
317        if (!FcStrCmpIgnoreCase ((FcChar8 *) _FcMatchers[i].object,
318                                 (FcChar8 *) object))
319            break;
320    }
321    if (i == NUM_MATCHER)
322    {
323        if (bestValue)
324            *bestValue = v2orig->value;
325        return FcTrue;
326    }
327#endif
328    best = 1e99;
329    bestStrong = 1e99;
330    bestWeak = 1e99;
331    j = 0;
332    for (v1 = v1orig; v1; v1 = v1->next)
333    {
334        for (v2 = v2orig; v2; v2 = v2->next)
335        {
336            v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
337                                            v1->value,
338                                            v2->value);
339            if (v < 0)
340            {
341                *result = FcResultTypeMismatch;
342                return FcFalse;
343            }
344            if (FcDebug () & FC_DBG_MATCHV)
345                printf (" v %g j %d ", v, j);
346            v = v * 100 + j;
347            if (v < best)
348            {
349                if (bestValue)
350                    *bestValue = v2->value;
351                best = v;
352            }
353            if (v1->binding == FcValueBindingStrong)
354            {
355                if (v < bestStrong)
356                    bestStrong = v;
357            }
358            else
359            {
360                if (v < bestWeak)
361                    bestWeak = v;
362            }
363        }
364        j++;
365    }
366    if (FcDebug () & FC_DBG_MATCHV)
367    {
368        printf (" %s: %g ", object, best);
369        FcValueListPrint (v1orig);
370        printf (", ");
371        FcValueListPrint (v2orig);
372        printf ("\n");
373    }
374    if (value)
375    {
376        int weak    = _FcMatchers[i].weak;
377        int strong  = _FcMatchers[i].strong;
378        if (weak == strong)
379            value[strong] += best;
380        else
381        {
382            value[weak] += bestWeak;
383            value[strong] += bestStrong;
384        }
385    }
386    return FcTrue;
387}
388
389/*
390 * Return a value indicating the distance between the two lists of
391 * values
392 */
393
394static FcBool
395FcCompare (FcPattern    *pat,
396           FcPattern    *fnt,
397           double       *value,
398           FcResult     *result)
399{
400    int             i, i1, i2;
401   
402    for (i = 0; i < NUM_MATCH_VALUES; i++)
403        value[i] = 0.0;
404   
405    i1 = 0;
406    i2 = 0;
407    while (i1 < pat->num && i2 < fnt->num)
408    {
409        i = pat->elts[i1].object - fnt->elts[i2].object;
410        if (i > 0)
411            i2++;
412        else if (i < 0)
413            i1++;
414        else
415        {
416            if (!FcCompareValueList (pat->elts[i1].object,
417                                     pat->elts[i1].values,
418                                     fnt->elts[i2].values,
419                                     0,
420                                     value,
421                                     result))
422                return FcFalse;
423            i1++;
424            i2++;
425        }
426    }
427    return FcTrue;
428#if 0
429    for (i1 = 0; i1 < pat->num; i1++)
430    {
431        for (i2 = 0; i2 < fnt->num; i2++)
432        {
433            if (!strcmp (pat->elts[i1].object, fnt->elts[i2].object))
434            {
435                break;
436            }
437        }
438    }
439    return FcTrue;
440#endif
441}
442
443FcPattern *
444FcFontRenderPrepare (FcConfig       *config,
445                     FcPattern      *pat,
446                     FcPattern      *font)
447{
448    FcPattern       *new;
449    int             i;
450    FcPatternElt    *fe, *pe;
451    FcValue         v;
452    FcResult        result;
453   
454    new = FcPatternCreate ();
455    if (!new)
456        return 0;
457    for (i = 0; i < font->num; i++)
458    {
459        fe = &font->elts[i];
460        pe = FcPatternFindElt (pat, fe->object);
461        if (pe)
462        {
463            if (!FcCompareValueList (pe->object, pe->values, 
464                                     fe->values, &v, 0, &result))
465            {
466                FcPatternDestroy (new);
467                return 0;
468            }
469        }
470        else
471            v = fe->values->value;
472        FcPatternAdd (new, fe->object, v, FcFalse);
473    }
474    for (i = 0; i < pat->num; i++)
475    {
476        pe = &pat->elts[i];
477        fe = FcPatternFindElt (font, pe->object);
478        if (!fe)
479            FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
480    }
481    FcConfigSubstituteWithPat (config, new, pat, FcMatchFont);
482    return new;
483}
484
485FcPattern *
486FcFontSetMatch (FcConfig    *config,
487                FcFontSet   **sets,
488                int         nsets,
489                FcPattern   *p,
490                FcResult    *result)
491{
492    double          score[NUM_MATCH_VALUES], bestscore[NUM_MATCH_VALUES];
493    int             f;
494    FcFontSet       *s;
495    FcPattern       *best;
496    int             i;
497    int             set;
498
499    for (i = 0; i < NUM_MATCH_VALUES; i++)
500        bestscore[i] = 0;
501    best = 0;
502    if (FcDebug () & FC_DBG_MATCH)
503    {
504        printf ("Match ");
505        FcPatternPrint (p);
506    }
507    if (!config)
508    {
509        config = FcConfigGetCurrent ();
510        if (!config)
511        {
512            *result = FcResultOutOfMemory;
513            return 0;
514        }
515    }
516    for (set = 0; set < nsets; set++)
517    {
518        s = sets[set];
519        if (!s)
520            continue;
521        for (f = 0; f < s->nfont; f++)
522        {
523            if (FcDebug () & FC_DBG_MATCHV)
524            {
525                printf ("Font %d ", f);
526                FcPatternPrint (s->fonts[f]);
527            }
528            if (!FcCompare (p, s->fonts[f], score, result))
529                return 0;
530            if (FcDebug () & FC_DBG_MATCHV)
531            {
532                printf ("Score");
533                for (i = 0; i < NUM_MATCH_VALUES; i++)
534                {
535                    printf (" %g", score[i]);
536                }
537                printf ("\n");
538            }
539            for (i = 0; i < NUM_MATCH_VALUES; i++)
540            {
541                if (best && bestscore[i] < score[i])
542                    break;
543                if (!best || score[i] < bestscore[i])
544                {
545                    for (i = 0; i < NUM_MATCH_VALUES; i++)
546                        bestscore[i] = score[i];
547                    best = s->fonts[f];
548                    break;
549                }
550            }
551        }
552    }
553    if (FcDebug () & FC_DBG_MATCH)
554    {
555        printf ("Best score");
556        for (i = 0; i < NUM_MATCH_VALUES; i++)
557            printf (" %g", bestscore[i]);
558        FcPatternPrint (best);
559    }
560    if (!best)
561    {
562        *result = FcResultNoMatch;
563        return 0;
564    }
565    return FcFontRenderPrepare (config, p, best);
566}
567
568FcPattern *
569FcFontMatch (FcConfig   *config,
570             FcPattern  *p, 
571             FcResult   *result)
572{
573    FcFontSet   *sets[2];
574    int         nsets;
575
576    if (!config)
577    {
578        config = FcConfigGetCurrent ();
579        if (!config)
580            return 0;
581    }
582    nsets = 0;
583    if (config->fonts[FcSetSystem])
584        sets[nsets++] = config->fonts[FcSetSystem];
585    if (config->fonts[FcSetApplication])
586        sets[nsets++] = config->fonts[FcSetApplication];
587    return FcFontSetMatch (config, sets, nsets, p, result);
588}
589
590typedef struct _FcSortNode {
591    FcPattern   *pattern;
592    double      score[NUM_MATCH_VALUES];
593} FcSortNode;
594
595static int
596FcSortCompare (const void *aa, const void *ab)
597{
598    FcSortNode  *a = *(FcSortNode **) aa;
599    FcSortNode  *b = *(FcSortNode **) ab;
600    double      *as = &a->score[0];
601    double      *bs = &b->score[0];
602    double      ad = 0, bd = 0;
603    int         i;
604
605    i = NUM_MATCH_VALUES;
606    while (i-- && (ad = *as++) == (bd = *bs++))
607        ;
608    return ad < bd ? -1 : ad > bd ? 1 : 0;
609}
610
611static FcBool
612FcSortWalk (FcSortNode **n, int nnode, FcFontSet *fs, FcCharSet **cs, FcBool trim)
613{
614    FcCharSet   *ncs;
615    FcSortNode  *node;
616
617    while (nnode--)
618    {
619        node = *n++;
620        if (FcPatternGetCharSet (node->pattern, FC_CHARSET, 0, &ncs) == 
621            FcResultMatch)
622        {
623            /*
624             * If this font isn't a subset of the previous fonts,
625             * add it to the list
626             */
627            if (!trim || !*cs || !FcCharSetIsSubset (ncs, *cs))
628            {
629                if (*cs)
630                {
631                    ncs = FcCharSetUnion (ncs, *cs);
632                    if (!ncs)
633                        return FcFalse;
634                    FcCharSetDestroy (*cs);
635                }
636                else
637                    ncs = FcCharSetCopy (ncs);
638                *cs = ncs;
639                FcPatternReference (node->pattern);
640                if (FcDebug () & FC_DBG_MATCH)
641                {
642                    printf ("Add ");
643                    FcPatternPrint (node->pattern);
644                }
645                if (!FcFontSetAdd (fs, node->pattern))
646                {
647                    FcPatternDestroy (node->pattern);
648                    return FcFalse;
649                }
650            }
651        }
652    }
653    return FcTrue;
654}
655
656void
657FcFontSetSortDestroy (FcFontSet *fs)
658{
659    FcFontSetDestroy (fs);
660}
661
662FcFontSet *
663FcFontSetSort (FcConfig     *config,
664               FcFontSet    **sets,
665               int          nsets,
666               FcPattern    *p,
667               FcBool       trim,
668               FcCharSet    **csp,
669               FcResult     *result)
670{
671    FcFontSet       *ret;
672    FcFontSet       *s;
673    FcSortNode      *nodes;
674    FcSortNode      **nodeps, **nodep;
675    int             nnodes;
676    FcSortNode      *new;
677    FcCharSet       *cs;
678    int             set;
679    int             f;
680    int             i;
681    int             nPatternLang;
682    FcBool          *patternLangSat;
683    FcValue         patternLang;
684
685    if (FcDebug () & FC_DBG_MATCH)
686    {
687        printf ("Sort ");
688        FcPatternPrint (p);
689    }
690    nnodes = 0;
691    for (set = 0; set < nsets; set++)
692    {
693        s = sets[set];
694        if (!s)
695            continue;
696        nnodes += s->nfont;
697    }
698    if (!nnodes)
699        goto bail0;
700   
701    for (nPatternLang = 0;
702         FcPatternGet (p, FC_LANG, nPatternLang, &patternLang) == FcResultMatch;
703         nPatternLang++)
704        ;
705       
706    /* freed below */
707    nodes = malloc (nnodes * sizeof (FcSortNode) + 
708                    nnodes * sizeof (FcSortNode *) +
709                    nPatternLang * sizeof (FcBool));
710    if (!nodes)
711        goto bail0;
712    nodeps = (FcSortNode **) (nodes + nnodes);
713    patternLangSat = (FcBool *) (nodeps + nnodes);
714   
715    new = nodes;
716    nodep = nodeps;
717    for (set = 0; set < nsets; set++)
718    {
719        s = sets[set];
720        if (!s)
721            continue;
722        for (f = 0; f < s->nfont; f++)
723        {
724            if (FcDebug () & FC_DBG_MATCHV)
725            {
726                printf ("Font %d ", f);
727                FcPatternPrint (s->fonts[f]);
728            }
729            new->pattern = s->fonts[f];
730            if (!FcCompare (p, new->pattern, new->score, result))
731                goto bail1;
732            if (FcDebug () & FC_DBG_MATCHV)
733            {
734                printf ("Score");
735                for (i = 0; i < NUM_MATCH_VALUES; i++)
736                {
737                    printf (" %g", new->score[i]);
738                }
739                printf ("\n");
740            }
741            *nodep = new;
742            new++;
743            nodep++;
744        }
745    }
746
747    nnodes = new - nodes;
748   
749    qsort (nodeps, nnodes, sizeof (FcSortNode *),
750           FcSortCompare);
751   
752    for (i = 0; i < nPatternLang; i++)
753        patternLangSat[i] = FcFalse;
754   
755    for (f = 0; f < nnodes; f++)
756    {
757        FcBool  satisfies = FcFalse;
758        /*
759         * If this node matches any language, go check
760         * which ones and satisfy those entries
761         */
762        if (nodeps[f]->score[MATCH_LANG_INDEX] < nPatternLang)
763        {
764            for (i = 0; i < nPatternLang; i++)
765            {
766                FcValue     nodeLang;
767               
768                if (!patternLangSat[i] &&
769                    FcPatternGet (p, FC_LANG, i, &patternLang) == FcResultMatch &&
770                    FcPatternGet (nodeps[f]->pattern, FC_LANG, 0, &nodeLang) == FcResultMatch)
771                {
772                    double  compare = FcCompareLang (FC_LANG, patternLang, 
773                                                     nodeLang);
774                    if (compare >= 0 && compare < 2)
775                    {
776                        if (FcDebug () & FC_DBG_MATCHV)
777                        {
778                            FcChar8 *family;
779                            FcChar8 *style;
780
781                            if (FcPatternGetString (nodeps[f]->pattern, FC_FAMILY, 0, &family) == FcResultMatch &&
782                                FcPatternGetString (nodeps[f]->pattern, FC_STYLE, 0, &style) == FcResultMatch)
783                                printf ("Font %s:%s matches language %d\n", family, style, i);
784                        }
785                        patternLangSat[i] = FcTrue;
786                        satisfies = FcTrue;
787                        break;
788                    }
789                }
790            }
791        }
792        if (!satisfies)
793            nodeps[f]->score[MATCH_LANG_INDEX] = 1000.0;
794    }
795
796    /*
797     * Re-sort once the language issues have been settled
798     */
799    qsort (nodeps, nnodes, sizeof (FcSortNode *),
800           FcSortCompare);
801
802    ret = FcFontSetCreate ();
803    if (!ret)
804        goto bail1;
805
806    cs = 0;
807
808    if (!FcSortWalk (nodeps, nnodes, ret, &cs, trim))
809        goto bail2;
810
811    if (csp)
812        *csp = cs;
813    else
814        FcCharSetDestroy (cs);
815
816    free (nodes);
817
818    return ret;
819
820bail2:
821    if (cs)
822        FcCharSetDestroy (cs);
823    FcFontSetDestroy (ret);
824bail1:
825    free (nodes);
826bail0:
827    return 0;
828}
829
830FcFontSet *
831FcFontSort (FcConfig    *config,
832            FcPattern   *p, 
833            FcBool      trim,
834            FcCharSet   **csp,
835            FcResult    *result)
836{
837    FcFontSet   *sets[2];
838    int         nsets;
839
840    if (!config)
841    {
842        config = FcConfigGetCurrent ();
843        if (!config)
844            return 0;
845    }
846    nsets = 0;
847    if (config->fonts[FcSetSystem])
848        sets[nsets++] = config->fonts[FcSetSystem];
849    if (config->fonts[FcSetApplication])
850        sets[nsets++] = config->fonts[FcSetApplication];
851    return FcFontSetSort (config, sets, nsets, p, trim, csp, result);
852}
Note: See TracBrowser for help on using the repository browser.