fccfg.c 39.4 KB
Newer Older
Keith Packard's avatar
Keith Packard committed
1
/*
2
 * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
Keith Packard's avatar
Keith Packard committed
3
 *
4
 * Copyright © 2000 Keith Packard
Keith Packard's avatar
Keith Packard committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

25
#include "fcint.h"
26
27
#include <dirent.h>
#include <sys/types.h>
Keith Packard's avatar
Keith Packard committed
28

Tor Lillqvist's avatar
Tor Lillqvist committed
29
#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
Tor Lillqvist's avatar
Tor Lillqvist committed
30
31
32
33
34
#define STRICT
#include <windows.h>
#undef STRICT
#endif

35
36
37
38
#if defined (_WIN32) && !defined (R_OK)
#define R_OK 4
#endif

39
FcConfig    *_fcConfig;
Keith Packard's avatar
Keith Packard committed
40
41
42
43
44
45
46
47
48
49

FcConfig *
FcConfigCreate (void)
{
    FcSetName	set;
    FcConfig	*config;

    config = malloc (sizeof (FcConfig));
    if (!config)
	goto bail0;
50
    FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
Keith Packard's avatar
Keith Packard committed
51
    
52
53
    config->configDirs = FcStrSetCreate ();
    if (!config->configDirs)
Keith Packard's avatar
Keith Packard committed
54
55
	goto bail1;
    
56
    config->configFiles = FcStrSetCreate ();
Keith Packard's avatar
Keith Packard committed
57
58
    if (!config->configFiles)
	goto bail2;
59
60
61
62
    
    config->fontDirs = FcStrSetCreate ();
    if (!config->fontDirs)
	goto bail3;
Keith Packard's avatar
Keith Packard committed
63
    
64
65
66
67
68
69
70
71
    config->acceptGlobs = FcStrSetCreate ();
    if (!config->acceptGlobs)
	goto bail4;

    config->rejectGlobs = FcStrSetCreate ();
    if (!config->rejectGlobs)
	goto bail5;

72
73
74
75
76
77
78
79
    config->acceptPatterns = FcFontSetCreate ();
    if (!config->acceptPatterns)
	goto bail6;
    
    config->rejectPatterns = FcFontSetCreate ();
    if (!config->rejectPatterns)
	goto bail7;

80
81
    config->cacheDirs = FcStrSetCreate ();
    if (!config->cacheDirs)
82
	goto bail8;
83
    
Keith Packard's avatar
Keith Packard committed
84
85
86
87
    config->blanks = 0;

    config->substPattern = 0;
    config->substFont = 0;
88
    config->substScan = 0;
Keith Packard's avatar
Keith Packard committed
89
90
91
    config->maxObjects = 0;
    for (set = FcSetSystem; set <= FcSetApplication; set++)
	config->fonts[set] = 0;
92
93
94

    config->rescanTime = time(0);
    config->rescanInterval = 30;    
Keith Packard's avatar
Keith Packard committed
95
96
97
    
    return config;

98
99
100
101
bail8:
    FcFontSetDestroy (config->rejectPatterns);
bail7:
    FcFontSetDestroy (config->acceptPatterns);
102
103
104
105
bail6:
    FcStrSetDestroy (config->rejectGlobs);
bail5:
    FcStrSetDestroy (config->acceptGlobs);
106
107
bail4:
    FcStrSetDestroy (config->fontDirs);
Keith Packard's avatar
Keith Packard committed
108
bail3:
109
    FcStrSetDestroy (config->configFiles);
Keith Packard's avatar
Keith Packard committed
110
bail2:
111
    FcStrSetDestroy (config->configDirs);
Keith Packard's avatar
Keith Packard committed
112
113
bail1:
    free (config);
114
    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
Keith Packard's avatar
Keith Packard committed
115
116
117
118
bail0:
    return 0;
}

119
static FcFileTime
120
121
122
FcConfigNewestFile (FcStrSet *files)
{
    FcStrList	    *list = FcStrListCreate (files);
123
    FcFileTime	    newest = { 0, FcFalse };
124
125
126
127
128
129
130
    FcChar8	    *file;
    struct  stat    statb;

    if (list)
    {
	while ((file = FcStrListNext (list)))
	    if (stat ((char *) file, &statb) == 0)
131
		if (!newest.set || statb.st_mtime - newest.time > 0)
132
133
		{
		    newest.set = FcTrue;
134
		    newest.time = statb.st_mtime;
135
		}
136
137
138
139
140
141
142
143
	FcStrListDone (list);
    }
    return newest;
}

FcBool
FcConfigUptoDate (FcConfig *config)
{
144
    FcFileTime	config_time, config_dir_time, font_time;
145
    time_t	now = time(0);
146
147
148
149
150
151
152
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }
    config_time = FcConfigNewestFile (config->configFiles);
153
    config_dir_time = FcConfigNewestFile (config->configDirs);
154
    font_time = FcConfigNewestFile (config->fontDirs);
155
    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
156
	(config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
157
	(font_time.set && (font_time.time - config->rescanTime) > 0))
158
159
160
161
162
163
164
    {
	return FcFalse;
    }
    config->rescanTime = now;
    return FcTrue;
}

Keith Packard's avatar
Keith Packard committed
165
166
167
168
169
170
171
172
static void
FcSubstDestroy (FcSubst *s)
{
    FcSubst *n;
    
    while (s)
    {
	n = s->next;
173
174
175
176
	if (s->test)
	    FcTestDestroy (s->test);
	if (s->edit)
	    FcEditDestroy (s->edit);
177
178
	free (s);
	FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
Keith Packard's avatar
Keith Packard committed
179
180
181
182
183
184
185
186
187
	s = n;
    }
}

void
FcConfigDestroy (FcConfig *config)
{
    FcSetName	set;

188
189
190
191
192
    if (config == _fcConfig)
	_fcConfig = 0;

    FcStrSetDestroy (config->configDirs);
    FcStrSetDestroy (config->fontDirs);
193
    FcStrSetDestroy (config->cacheDirs);
194
    FcStrSetDestroy (config->configFiles);
195
196
    FcStrSetDestroy (config->acceptGlobs);
    FcStrSetDestroy (config->rejectGlobs);
197
198
    FcFontSetDestroy (config->acceptPatterns);
    FcFontSetDestroy (config->rejectPatterns);
199

200
201
202
    if (config->blanks)
	FcBlanksDestroy (config->blanks);

Keith Packard's avatar
Keith Packard committed
203
204
    FcSubstDestroy (config->substPattern);
    FcSubstDestroy (config->substFont);
205
    FcSubstDestroy (config->substScan);
Keith Packard's avatar
Keith Packard committed
206
207
208
    for (set = FcSetSystem; set <= FcSetApplication; set++)
	if (config->fonts[set])
	    FcFontSetDestroy (config->fonts[set]);
209

210
211
    free (config);
    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
Keith Packard's avatar
Keith Packard committed
212
213
214
}

/*
215
 * Add cache to configuration, adding fonts and directories
Keith Packard's avatar
Keith Packard committed
216
217
218
 */

FcBool
219
220
FcConfigAddCache (FcConfig *config, FcCache *cache, 
		  FcSetName set, FcStrSet *dirSet)
Keith Packard's avatar
Keith Packard committed
221
{
222
223
224
    FcFontSet	*fs;
    intptr_t	*dirs;
    int		i;
Keith Packard's avatar
Keith Packard committed
225

226
227
228
229
230
    /*
     * Add fonts
     */
    fs = FcCacheSet (cache);
    if (fs)
231
    {
232
233
	int	nref = 0;
	
234
	for (i = 0; i < fs->nfont; i++)
235
	{
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	    FcPattern	*font = FcFontSetFont (fs, i);
	    FcChar8	*font_file;

	    /*
	     * Check to see if font is banned by filename
	     */
	    if (FcPatternObjectGetString (font, FC_FILE_OBJECT,
					  0, &font_file) == FcResultMatch &&
		!FcConfigAcceptFilename (config, font_file))
	    {
		continue;
	    }
		
	    /*
	     * Check to see if font is banned by pattern
	     */
	    if (!FcConfigAcceptFont (config, font))
		continue;
		
255
	    nref++;
256
	    FcFontSetAdd (config->fonts[set], font);
257
	}
258
	FcDirCacheReference (cache, nref);
259
    }
260
261
262
263
264
265

    /*
     * Add directories
     */
    dirs = FcCacheDirs (cache);
    if (dirs)
Keith Packard's avatar
Keith Packard committed
266
    {
267
268
269
270
	for (i = 0; i < cache->dirs_count; i++)
	{
	    FcChar8	*dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
	    if (FcConfigAcceptFilename (config, dir))
271
		FcStrSetAddFilename (dirSet, dir);
272
	}
273
274
275
    }
    return FcTrue;
}
276

277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
static FcBool
FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
{
    FcStrList	    *dirlist;
    FcChar8	    *dir;
    FcCache	    *cache;
    
    dirlist = FcStrListCreate (dirSet);
    if (!dirlist)
        return FcFalse;
	
    while ((dir = FcStrListNext (dirlist)))
    {
	if (FcDebug () & FC_DBG_FONTSET)
	    printf ("adding fonts from%s\n", dir);
	cache = FcDirCacheRead (dir, FcFalse, config);
	if (!cache)
	    continue;
	FcConfigAddCache (config, cache, set, dirSet);
	FcDirCacheUnload (cache);
    }
    FcStrListDone (dirlist);
    return FcTrue;
}

302
303
304
305
/*
 * Scan the current list of directories in the configuration
 * and build the set of available fonts.
 */
Patrick Lam's avatar
Patrick Lam committed
306

307
308
309
310
FcBool
FcConfigBuildFonts (FcConfig *config)
{
    FcFontSet	    *fonts;
311

312
313
314
315
316
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
Keith Packard's avatar
Keith Packard committed
317
    }
318
319
320
	
    fonts = FcFontSetCreate ();
    if (!fonts)
321
	return FcFalse;
322
323
324
    
    FcConfigSetFonts (config, fonts, FcSetSystem);
    
325
326
    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
	return FcFalse;
Keith Packard's avatar
Keith Packard committed
327
328
329
330
331
332
333
334
335
336
337
338
    if (FcDebug () & FC_DBG_FONTSET)
	FcFontSetPrint (fonts);
    return FcTrue;
}

FcBool
FcConfigSetCurrent (FcConfig *config)
{
    if (!config->fonts)
	if (!FcConfigBuildFonts (config))
	    return FcFalse;

339
340
341
    if (_fcConfig)
	FcConfigDestroy (_fcConfig);
    _fcConfig = config;
Keith Packard's avatar
Keith Packard committed
342
343
344
345
346
347
    return FcTrue;
}

FcConfig *
FcConfigGetCurrent (void)
{
348
349
350
351
    if (!_fcConfig)
	if (!FcInit ())
	    return 0;
    return _fcConfig;
Keith Packard's avatar
Keith Packard committed
352
353
354
}

FcBool
355
356
FcConfigAddConfigDir (FcConfig	    *config,
		      const FcChar8 *d)
Keith Packard's avatar
Keith Packard committed
357
{
358
359
    return FcStrSetAddFilename (config->configDirs, d);
}
Keith Packard's avatar
Keith Packard committed
360

361
362
363
364
FcStrList *
FcConfigGetConfigDirs (FcConfig   *config)
{
    if (!config)
Keith Packard's avatar
Keith Packard committed
365
    {
366
367
368
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
Keith Packard's avatar
Keith Packard committed
369
    }
370
371
372
373
374
375
376
377
    return FcStrListCreate (config->configDirs);
}

FcBool
FcConfigAddFontDir (FcConfig	    *config,
		    const FcChar8   *d)
{
    return FcStrSetAddFilename (config->fontDirs, d);
Keith Packard's avatar
Keith Packard committed
378
379
}

380
381
382
383
384
385
386
387
388
389
FcBool
FcConfigAddDir (FcConfig	    *config,
		const FcChar8	    *d)
{
    return (FcConfigAddConfigDir (config, d) && 
	    FcConfigAddFontDir (config, d));
}

FcStrList *
FcConfigGetFontDirs (FcConfig	*config)
Keith Packard's avatar
Keith Packard committed
390
391
392
393
394
395
396
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
397
    return FcStrListCreate (config->fontDirs);
Keith Packard's avatar
Keith Packard committed
398
399
}

400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
FcBool
FcConfigAddCacheDir (FcConfig	    *config,
		     const FcChar8  *d)
{
    return FcStrSetAddFilename (config->cacheDirs, d);
}

FcStrList *
FcConfigGetCacheDirs (FcConfig	*config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return FcStrListCreate (config->cacheDirs);
}
    
Keith Packard's avatar
Keith Packard committed
419
420
FcBool
FcConfigAddConfigFile (FcConfig	    *config,
421
		       const FcChar8   *f)
Keith Packard's avatar
Keith Packard committed
422
{
423
424
425
    FcBool	ret;
    FcChar8	*file = FcConfigFilename (f);
    
Keith Packard's avatar
Keith Packard committed
426
427
    if (!file)
	return FcFalse;
428
429
430
431
    
    ret = FcStrSetAdd (config->configFiles, file);
    FcStrFree (file);
    return ret;
Keith Packard's avatar
Keith Packard committed
432
433
}

434
FcStrList *
Keith Packard's avatar
Keith Packard committed
435
436
437
438
439
440
441
442
FcConfigGetConfigFiles (FcConfig    *config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
443
    return FcStrListCreate (config->configFiles);
Keith Packard's avatar
Keith Packard committed
444
445
}

446
FcChar8 *
Keith Packard's avatar
Keith Packard committed
447
448
FcConfigGetCache (FcConfig  *config)
{
449
    return NULL;
Keith Packard's avatar
Keith Packard committed
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
}

FcFontSet *
FcConfigGetFonts (FcConfig	*config,
		  FcSetName	set)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->fonts[set];
}

void
FcConfigSetFonts (FcConfig	*config,
		  FcFontSet	*fonts,
		  FcSetName	set)
{
    if (config->fonts[set])
	FcFontSetDestroy (config->fonts[set]);
    config->fonts[set] = fonts;
}

FcBlanks *
FcConfigGetBlanks (FcConfig	*config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->blanks;
}

FcBool
FcConfigAddBlank (FcConfig	*config,
		  FcChar32    	blank)
{
491
    FcBlanks	*b, *freeme = 0;
Keith Packard's avatar
Keith Packard committed
492
493
494
495
    
    b = config->blanks;
    if (!b)
    {
496
	freeme = b = FcBlanksCreate ();
Keith Packard's avatar
Keith Packard committed
497
498
499
500
	if (!b)
	    return FcFalse;
    }
    if (!FcBlanksAdd (b, blank))
501
502
503
    {
        if (freeme)
            FcBlanksDestroy (freeme);
Keith Packard's avatar
Keith Packard committed
504
	return FcFalse;
505
    }
Keith Packard's avatar
Keith Packard committed
506
507
508
509
    config->blanks = b;
    return FcTrue;
}

510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
int
FcConfigGetRescanInverval (FcConfig *config)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return 0;
    }
    return config->rescanInterval;
}

FcBool
FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
{
    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }
    config->rescanInterval = rescanInterval;
    return FcTrue;
}

Keith Packard's avatar
Keith Packard committed
535
536
537
538
539
540
541
542
543
544
FcBool
FcConfigAddEdit (FcConfig	*config,
		 FcTest		*test,
		 FcEdit		*edit,
		 FcMatchKind	kind)
{
    FcSubst	*subst, **prev;
    FcTest	*t;
    int		num;

545
546
547
548
549
550
551
552
553
554
555
556
557
    switch (kind) {
    case FcMatchPattern:
	prev = &config->substPattern;
	break;
    case FcMatchFont:
	prev = &config->substFont;
	break;
    case FcMatchScan:
	prev = &config->substScan;
	break;
    default:
	return FcFalse;
    }
Keith Packard's avatar
Keith Packard committed
558
559
560
    subst = (FcSubst *) malloc (sizeof (FcSubst));
    if (!subst)
	return FcFalse;
561
    FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
Keith Packard's avatar
Keith Packard committed
562
563
564
565
566
567
568
    for (; *prev; prev = &(*prev)->next);
    *prev = subst;
    subst->next = 0;
    subst->test = test;
    subst->edit = edit;
    num = 0;
    for (t = test; t; t = t->next)
569
570
571
    {
	if (t->kind == FcMatchDefault)
	    t->kind = kind;
Keith Packard's avatar
Keith Packard committed
572
	num++;
573
    }
Keith Packard's avatar
Keith Packard committed
574
575
    if (config->maxObjects < num)
	config->maxObjects = num;
576
577
578
579
580
    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("Add Subst ");
	FcSubstPrint (subst);
    }
Keith Packard's avatar
Keith Packard committed
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
    return FcTrue;
}

typedef struct _FcSubState {
    FcPatternElt   *elt;
    FcValueList    *value;
} FcSubState;

static FcValue
FcConfigPromote (FcValue v, FcValue u)
{
    if (v.type == FcTypeInteger)
    {
	v.type = FcTypeDouble;
	v.u.d = (double) v.u.i;
    }
    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
    {
599
	v.u.m = &FcIdentityMatrix;
600
	v.type = FcTypeMatrix;
Keith Packard's avatar
Keith Packard committed
601
    }
602
603
    else if (v.type == FcTypeString && u.type == FcTypeLangSet)
    {
604
	v.u.l = FcLangSetPromote (v.u.s);
605
606
	v.type = FcTypeLangSet;
    }
Keith Packard's avatar
Keith Packard committed
607
608
609
610
    return v;
}

FcBool
611
FcConfigCompareValue (const FcValue	*left_o,
612
		      FcOp		op,
613
		      const FcValue	*right_o)
Keith Packard's avatar
Keith Packard committed
614
{
615
616
    FcValue	left = FcValueCanonicalize(left_o);
    FcValue	right = FcValueCanonicalize(right_o);
617
    FcBool	ret = FcFalse;
Keith Packard's avatar
Keith Packard committed
618
    
619
620
621
    left = FcConfigPromote (left, right);
    right = FcConfigPromote (right, left);
    if (left.type == right.type) 
Keith Packard's avatar
Keith Packard committed
622
    {
623
	switch (left.type) {
Keith Packard's avatar
Keith Packard committed
624
625
626
627
628
629
	case FcTypeInteger:
	    break;	/* FcConfigPromote prevents this from happening */
	case FcTypeDouble:
	    switch (op) {
	    case FcOpEqual:
	    case FcOpContains:
630
631
	    case FcOpListing:
		ret = left.u.d == right.u.d;
Keith Packard's avatar
Keith Packard committed
632
		break;
633
634
	    case FcOpNotEqual:
	    case FcOpNotContains:
635
		ret = left.u.d != right.u.d;
Keith Packard's avatar
Keith Packard committed
636
637
		break;
	    case FcOpLess:    
638
		ret = left.u.d < right.u.d;
Keith Packard's avatar
Keith Packard committed
639
640
		break;
	    case FcOpLessEqual:    
641
		ret = left.u.d <= right.u.d;
Keith Packard's avatar
Keith Packard committed
642
643
		break;
	    case FcOpMore:    
644
		ret = left.u.d > right.u.d;
Keith Packard's avatar
Keith Packard committed
645
646
		break;
	    case FcOpMoreEqual:    
647
		ret = left.u.d >= right.u.d;
Keith Packard's avatar
Keith Packard committed
648
649
650
651
652
653
654
655
656
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeBool:
	    switch (op) {
	    case FcOpEqual:    
	    case FcOpContains:
657
658
	    case FcOpListing:
		ret = left.u.b == right.u.b;
Keith Packard's avatar
Keith Packard committed
659
		break;
660
661
	    case FcOpNotEqual:
	    case FcOpNotContains:
662
		ret = left.u.b != right.u.b;
Keith Packard's avatar
Keith Packard committed
663
664
665
666
667
668
669
670
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeString:
	    switch (op) {
	    case FcOpEqual:    
671
	    case FcOpListing:
672
		ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
Keith Packard's avatar
Keith Packard committed
673
		break;
674
	    case FcOpContains:
675
		ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
676
		break;
677
	    case FcOpNotEqual:
678
		ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
679
		break;
680
	    case FcOpNotContains:
681
		ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
682
		break;
Keith Packard's avatar
Keith Packard committed
683
684
685
686
687
688
689
690
	    default:
		break;
	    }
	    break;
	case FcTypeMatrix:
	    switch (op) {
	    case FcOpEqual:
	    case FcOpContains:
691
	    case FcOpListing:
692
		ret = FcMatrixEqual (left.u.m, right.u.m);
Keith Packard's avatar
Keith Packard committed
693
694
		break;
	    case FcOpNotEqual:
695
	    case FcOpNotContains:
696
		ret = !FcMatrixEqual (left.u.m, right.u.m);
Keith Packard's avatar
Keith Packard committed
697
698
699
700
701
702
703
704
		break;
	    default:
		break;
	    }
	    break;
	case FcTypeCharSet:
	    switch (op) {
	    case FcOpContains:
705
706
	    case FcOpListing:
		/* left contains right if right is a subset of left */
707
		ret = FcCharSetIsSubset (right.u.c, left.u.c);
Keith Packard's avatar
Keith Packard committed
708
		break;
709
	    case FcOpNotContains:
710
		/* left contains right if right is a subset of left */
711
		ret = !FcCharSetIsSubset (right.u.c, left.u.c);
712
		break;
Keith Packard's avatar
Keith Packard committed
713
	    case FcOpEqual:
714
		ret = FcCharSetEqual (left.u.c, right.u.c);
Keith Packard's avatar
Keith Packard committed
715
716
		break;
	    case FcOpNotEqual:
717
		ret = !FcCharSetEqual (left.u.c, right.u.c);
Keith Packard's avatar
Keith Packard committed
718
719
720
721
722
		break;
	    default:
		break;
	    }
	    break;
723
724
725
	case FcTypeLangSet:
	    switch (op) {
	    case FcOpContains:
726
	    case FcOpListing:
727
		ret = FcLangSetContains (left.u.l, right.u.l);
728
		break;
729
	    case FcOpNotContains:
730
		ret = !FcLangSetContains (left.u.l, right.u.l);
731
		break;
732
	    case FcOpEqual:
733
		ret = FcLangSetEqual (left.u.l, right.u.l);
734
735
		break;
	    case FcOpNotEqual:
736
		ret = !FcLangSetEqual (left.u.l, right.u.l);
737
738
739
740
741
		break;
	    default:
		break;
	    }
	    break;
Keith Packard's avatar
Keith Packard committed
742
743
744
745
	case FcTypeVoid:
	    switch (op) {
	    case FcOpEqual:
	    case FcOpContains:
746
	    case FcOpListing:
Keith Packard's avatar
Keith Packard committed
747
748
749
750
751
752
		ret = FcTrue;
		break;
	    default:
		break;
	    }
	    break;
753
754
755
	case FcTypeFTFace:
	    switch (op) {
	    case FcOpEqual:
756
	    case FcOpContains:
757
758
	    case FcOpListing:
		ret = left.u.f == right.u.f;
759
760
		break;
	    case FcOpNotEqual:
761
	    case FcOpNotContains:
762
		ret = left.u.f != right.u.f;
763
764
765
766
		break;
	    default:
		break;
	    }
767
	    break;
Keith Packard's avatar
Keith Packard committed
768
769
770
771
	}
    }
    else
    {
772
	if (op == FcOpNotEqual || op == FcOpNotContains)
Keith Packard's avatar
Keith Packard committed
773
774
775
776
777
778
	    ret = FcTrue;
    }
    return ret;
}


779
780
781
782
783
784
785
#define _FcDoubleFloor(d)	((int) (d))
#define _FcDoubleCeil(d)	((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
#define FcDoubleFloor(d)	((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
#define FcDoubleCeil(d)		((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
#define FcDoubleRound(d)	FcDoubleFloor ((d) + 0.5)
#define FcDoubleTrunc(d)	((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))

Keith Packard's avatar
Keith Packard committed
786
787
788
789
790
791
static FcValue
FcConfigEvaluate (FcPattern *p, FcExpr *e)
{
    FcValue	v, vl, vr;
    FcResult	r;
    FcMatrix	*m;
792
    FcChar8     *str;
Keith Packard's avatar
Keith Packard committed
793
794
795
796
797
798
799
800
801
802
803
804
    
    switch (e->op) {
    case FcOpInteger:
	v.type = FcTypeInteger;
	v.u.i = e->u.ival;
	break;
    case FcOpDouble:
	v.type = FcTypeDouble;
	v.u.d = e->u.dval;
	break;
    case FcOpString:
	v.type = FcTypeString;
805
	v.u.s = FcStrStaticName(e->u.sval);
Keith Packard's avatar
Keith Packard committed
806
807
808
	break;
    case FcOpMatrix:
	v.type = FcTypeMatrix;
809
	v.u.m = e->u.mval;
Keith Packard's avatar
Keith Packard committed
810
811
812
813
	v = FcValueSave (v);
	break;
    case FcOpCharSet:
	v.type = FcTypeCharSet;
814
	v.u.c = e->u.cval;
Keith Packard's avatar
Keith Packard committed
815
816
817
818
819
820
821
	v = FcValueSave (v);
	break;
    case FcOpBool:
	v.type = FcTypeBool;
	v.u.b = e->u.bval;
	break;
    case FcOpField:
822
	r = FcPatternObjectGet (p, e->u.object, 0, &v);
Keith Packard's avatar
Keith Packard committed
823
824
	if (r != FcResultMatch)
	    v.type = FcTypeVoid;
825
	v = FcValueSave (v);
Keith Packard's avatar
Keith Packard committed
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
	break;
    case FcOpConst:
	if (FcNameConstant (e->u.constant, &v.u.i))
	    v.type = FcTypeInteger;
	else
	    v.type = FcTypeVoid;
	break;
    case FcOpQuest:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	if (vl.type == FcTypeBool)
	{
	    if (vl.u.b)
		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
	    else
		v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
	}
	else
	    v.type = FcTypeVoid;
	FcValueDestroy (vl);
	break;
846
    case FcOpEqual:
Keith Packard's avatar
Keith Packard committed
847
848
849
850
851
    case FcOpNotEqual:
    case FcOpLess:
    case FcOpLessEqual:
    case FcOpMore:
    case FcOpMoreEqual:
852
853
    case FcOpContains:
    case FcOpNotContains:
854
    case FcOpListing:
855
856
857
	vl = FcConfigEvaluate (p, e->u.tree.left);
	vr = FcConfigEvaluate (p, e->u.tree.right);
	v.type = FcTypeBool;
858
	v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
859
860
861
862
863
	FcValueDestroy (vl);
	FcValueDestroy (vr);
	break;	
    case FcOpOr:
    case FcOpAnd:
Keith Packard's avatar
Keith Packard committed
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
    case FcOpPlus:
    case FcOpMinus:
    case FcOpTimes:
    case FcOpDivide:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	vr = FcConfigEvaluate (p, e->u.tree.right);
	vl = FcConfigPromote (vl, vr);
	vr = FcConfigPromote (vr, vl);
	if (vl.type == vr.type)
	{
	    switch (vl.type) {
	    case FcTypeDouble:
		switch (e->op) {
		case FcOpPlus:	   
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d + vr.u.d; 
		    break;
		case FcOpMinus:
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d - vr.u.d; 
		    break;
		case FcOpTimes:
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d * vr.u.d; 
		    break;
		case FcOpDivide:
		    v.type = FcTypeDouble;
		    v.u.d = vl.u.d / vr.u.d; 
		    break;
		default:
		    v.type = FcTypeVoid; 
		    break;
		}
		if (v.type == FcTypeDouble &&
		    v.u.d == (double) (int) v.u.d)
		{
		    v.type = FcTypeInteger;
		    v.u.i = (int) v.u.d;
		}
		break;
	    case FcTypeBool:
		switch (e->op) {
		case FcOpOr:
		    v.type = FcTypeBool;
		    v.u.b = vl.u.b || vr.u.b;
		    break;
		case FcOpAnd:
		    v.type = FcTypeBool;
		    v.u.b = vl.u.b && vr.u.b;
		    break;
		default:
		    v.type = FcTypeVoid; 
		    break;
		}
		break;
	    case FcTypeString:
		switch (e->op) {
		case FcOpPlus:
		    v.type = FcTypeString;
923
924
925
		    str = FcStrPlus (vl.u.s, vr.u.s);
		    v.u.s = FcStrStaticName (str);
		    FcStrFree (str);
926
			 
927
		    if (!v.u.s)
Keith Packard's avatar
Keith Packard committed
928
929
930
931
932
933
			v.type = FcTypeVoid;
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
934
		break;
Keith Packard's avatar
Keith Packard committed
935
936
937
938
939
940
941
942
	    case FcTypeMatrix:
		switch (e->op) {
		case FcOpTimes:
		    v.type = FcTypeMatrix;
		    m = malloc (sizeof (FcMatrix));
		    if (m)
		    {
			FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
943
944
			FcMatrixMultiply (m, vl.u.m, vr.u.m);
			v.u.m = m;
Keith Packard's avatar
Keith Packard committed
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
		    }
		    else
		    {
			v.type = FcTypeVoid;
		    }
		    break;
		default:
		    v.type = FcTypeVoid;
		    break;
		}
		break;
	    default:
		v.type = FcTypeVoid;
		break;
	    }
	}
	else
	    v.type = FcTypeVoid;
	FcValueDestroy (vl);
	FcValueDestroy (vr);
	break;
    case FcOpNot:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeBool:
	    v.type = FcTypeBool;
	    v.u.b = !vl.u.b;
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
    case FcOpFloor:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleFloor (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
    case FcOpCeil:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleCeil (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
    case FcOpRound:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleRound (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
    case FcOpTrunc:
	vl = FcConfigEvaluate (p, e->u.tree.left);
	switch (vl.type) {
	case FcTypeInteger:
	    v = vl;
	    break;
	case FcTypeDouble:
	    v.type = FcTypeInteger;
	    v.u.i = FcDoubleTrunc (vl.u.d);
	    break;
	default:
	    v.type = FcTypeVoid;
	    break;
	}
	FcValueDestroy (vl);
	break;
Keith Packard's avatar
Keith Packard committed
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
    default:
	v.type = FcTypeVoid;
	break;
    }
    return v;
}

static FcValueList *
FcConfigMatchValueList (FcPattern	*p,
			FcTest		*t,
1053
			FcValueList	*values)
Keith Packard's avatar
Keith Packard committed
1054
{
1055
1056
1057
    FcValueList	    *ret = 0;
    FcExpr	    *e = t->expr;
    FcValue	    value;
1058
    FcValueList	    *v;
Keith Packard's avatar
Keith Packard committed
1059
    
1060
    while (e)
Keith Packard's avatar
Keith Packard committed
1061
    {
1062
	/* Compute the value of the match expression */
1063
	if (e->op == FcOpComma)
Keith Packard's avatar
Keith Packard committed
1064
	{
1065
1066
	    value = FcConfigEvaluate (p, e->u.tree.left);
	    e = e->u.tree.right;
Keith Packard's avatar
Keith Packard committed
1067
1068
1069
	}
	else
	{
1070
1071
1072
1073
	    value = FcConfigEvaluate (p, e);
	    e = 0;
	}

1074
	for (v = values; v; v = FcValueListNext(v))
1075
	{
1076
	    /* Compare the pattern value to the match expression value */
1077
	    if (FcConfigCompareValue (&v->value, t->op, &value))
Keith Packard's avatar
Keith Packard committed
1078
	    {
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
		if (!ret)
		    ret = v;
	    }
	    else
	    {
		if (t->qual == FcQualAll)
		{
		    ret = 0;
		    break;
		}
Keith Packard's avatar
Keith Packard committed
1089
1090
	    }
	}
1091
	FcValueDestroy (value);
Keith Packard's avatar
Keith Packard committed
1092
1093
1094
1095
1096
    }
    return ret;
}

static FcValueList *
1097
FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
Keith Packard's avatar
Keith Packard committed
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
{
    FcValueList	*l;
    
    if (!e)
	return 0;
    l = (FcValueList *) malloc (sizeof (FcValueList));
    if (!l)
	return 0;
    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
    if (e->op == FcOpComma)
    {
	l->value = FcConfigEvaluate (p, e->u.tree.left);
1110
	l->next = FcConfigValues (p, e->u.tree.right, binding);
Keith Packard's avatar
Keith Packard committed
1111
1112
1113
1114
    }
    else
    {
	l->value = FcConfigEvaluate (p, e);
1115
	l->next = NULL;
Keith Packard's avatar
Keith Packard committed
1116
    }
1117
    l->binding = binding;
1118
    if (l->value.type == FcTypeVoid)
Keith Packard's avatar
Keith Packard committed
1119
    {
1120
	FcValueList  *next = FcValueListNext(l);
1121

1122
1123
1124
	FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
	free (l);
	l = next;
Keith Packard's avatar
Keith Packard committed
1125
    }
1126

Keith Packard's avatar
Keith Packard committed
1127
1128
1129
1130
    return l;
}

static FcBool
1131
FcConfigAdd (FcValueListPtr *head,
Keith Packard's avatar
Keith Packard committed
1132
1133
1134
1135
	     FcValueList    *position,
	     FcBool	    append,
	     FcValueList    *new)
{
1136
    FcValueListPtr  *prev, last, v;
1137
    FcValueBinding  sameBinding;
Keith Packard's avatar
Keith Packard committed
1138
    
1139
1140
1141
1142
    if (position)
	sameBinding = position->binding;
    else
	sameBinding = FcValueBindingWeak;
1143
1144
1145
    for (v = new; v != NULL; v = FcValueListNext(v))
	if (v->binding == FcValueBindingSame)
	    v->binding = sameBinding;
Keith Packard's avatar
Keith Packard committed
1146
1147
1148
1149
1150
    if (append)
    {
	if (position)
	    prev = &position->next;
	else
1151
1152
	    for (prev = head; *prev != NULL; 
		 prev = &(*prev)->next)
Keith Packard's avatar
Keith Packard committed
1153
1154
1155
1156
1157
1158
		;
    }
    else
    {
	if (position)
	{
1159
1160
	    for (prev = head; *prev != NULL; 
		 prev = &(*prev)->next)
Keith Packard's avatar
Keith Packard committed
1161
	    {
1162
		if (*prev == position)
Keith Packard's avatar
Keith Packard committed
1163
1164
1165
1166
1167
1168
1169
1170
		    break;
	    }
	}
	else
	    prev = head;

	if (FcDebug () & FC_DBG_EDIT)
	{
1171
	    if (*prev == NULL)
Keith Packard's avatar
Keith Packard committed
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
		printf ("position not on list\n");
	}
    }

    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("%s list before ", append ? "Append" : "Prepend");
	FcValueListPrint (*head);
	printf ("\n");
    }
    
    if (new)
    {
1185
1186
1187
	last = new;
	while (last->next != NULL)
	    last = last->next;
Keith Packard's avatar
Keith Packard committed
1188
    
1189
1190
	last->next = *prev;
	*prev = new;
Keith Packard's avatar
Keith Packard committed
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
    }
    
    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("%s list after ", append ? "Append" : "Prepend");
	FcValueListPrint (*head);
	printf ("\n");
    }
    
    return FcTrue;
}

static void
1204
FcConfigDel (FcValueListPtr *head,
Keith Packard's avatar
Keith Packard committed
1205
1206
	     FcValueList    *position)
{
1207
    FcValueListPtr *prev;
Keith Packard's avatar
Keith Packard committed
1208

1209
    for (prev = head; *prev != NULL; prev = &(*prev)->next)
Keith Packard's avatar
Keith Packard committed
1210
    {
1211
	if (*prev == position)
Keith Packard's avatar
Keith Packard committed
1212
1213
	{
	    *prev = position->next;
1214
1215
	    position->next = NULL;
	    FcValueListDestroy (position);
Keith Packard's avatar
Keith Packard committed
1216
1217
1218
1219
1220
1221
1222
	    break;
	}
    }
}

static void
FcConfigPatternAdd (FcPattern	*p,
1223
		    FcObject	object,
Keith Packard's avatar
Keith Packard committed
1224
1225
1226
1227
1228
		    FcValueList	*list,
		    FcBool	append)
{
    if (list)
    {
1229
	FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
Keith Packard's avatar
Keith Packard committed
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
    
	if (!e)
	    return;
	FcConfigAdd (&e->values, 0, append, list);
    }
}

/*
 * Delete all values associated with a field
 */
static void
FcConfigPatternDel (FcPattern	*p,
1242
		    FcObject	object)
Keith Packard's avatar
Keith Packard committed
1243
{
1244
    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
Keith Packard's avatar
Keith Packard committed
1245
1246
    if (!e)
	return;
1247
1248
    while (e->values != NULL)
	FcConfigDel (&e->values, e->values);
Keith Packard's avatar
Keith Packard committed
1249
1250
1251
1252
}

static void
FcConfigPatternCanon (FcPattern	    *p,
1253
		      FcObject	    object)
Keith Packard's avatar
Keith Packard committed
1254
{
1255
    FcPatternElt    *e = FcPatternObjectFindElt (p, object);
Keith Packard's avatar
Keith Packard committed
1256
1257
    if (!e)
	return;
1258
1259
    if (e->values == NULL)
	FcPatternObjectDel (p, object);
Keith Packard's avatar
Keith Packard committed
1260
1261
1262
}

FcBool
1263
1264
1265
1266
FcConfigSubstituteWithPat (FcConfig    *config,
			   FcPattern   *p,
			   FcPattern   *p_pat,
			   FcMatchKind kind)
Keith Packard's avatar
Keith Packard committed
1267
1268
1269
1270
1271
1272
1273
{
    FcSubst	    *s;
    FcSubState	    *st;
    int		    i;
    FcTest	    *t;
    FcEdit	    *e;
    FcValueList	    *l;
1274
    FcPattern	    *m;
Keith Packard's avatar
Keith Packard committed
1275
1276
1277
1278
1279
1280
1281
1282

    if (!config)
    {
	config = FcConfigGetCurrent ();
	if (!config)
	    return FcFalse;
    }

1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
    switch (kind) {
    case FcMatchPattern:
	s = config->substPattern;
	break;
    case FcMatchFont:
	s = config->substFont;
	break;
    case FcMatchScan:
	s = config->substScan;
	break;
    default:
	return FcFalse;
    }

Keith Packard's avatar
Keith Packard committed
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
    if (!st && config->maxObjects)
	return FcFalse;
    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));

    if (FcDebug () & FC_DBG_EDIT)
    {
	printf ("FcConfigSubstitute ");
	FcPatternPrint (p);
    }
    for (; s; s = s->next)
    {
	/*
	 * Check the tests to see if
	 * they all match the pattern
	 */
	for (t = s->test, i = 0; t; t = t->next, i++)
	{
	    if (FcDebug () & FC_DBG_EDIT)
	    {
		printf ("FcConfigSubstitute test ");
		FcTestPrint (t);
	    }
1320
1321
1322
1323
1324
1325
	    st[i].elt = 0;
	    if (kind == FcMatchFont && t->kind == FcMatchPattern)
		m = p_pat;
	    else
		m = p;
	    if (m)
1326
		st[i].elt = FcPatternObjectFindElt (m, t->object);
1327
1328
	    else
		st[i].elt = 0;
Keith Packard's avatar
Keith Packard committed
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
	    /*
	     * If there's no such field in the font,
	     * then FcQualAll matches while FcQualAny does not
	     */
	    if (!st[i].elt)
	    {
		if (t->qual == FcQualAll)
		{
		    st[i].value = 0;
		    continue;
		}
		else
		    break;
	    }
	    /*
	     * Check to see if there is a match, mark the location
	     * to apply match-relative edits
	     */
1347
	    st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
Keith Packard's avatar
Keith Packard committed
1348
1349
	    if (!st[i].value)
		break;
1350
	    if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
1351
		break;
1352
	    if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
1353
		break;
Keith Packard's avatar
Keith Packard committed
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
	}
	if (t)
	{
	    if (FcDebug () & FC_DBG_EDIT)
		printf ("No match\n");
	    continue;
	}
	if (FcDebug () & FC_DBG_EDIT)
	{
	    printf ("Substitute ");
	    FcSubstPrint (s);
	}
	for (e = s->edit; e; e = e->next)
	{
	    /*
	     * Evaluate the list of expressions
	     */
1371
	    l = FcConfigValues (p, e->expr, e->binding);
Keith Packard's avatar
Keith Packard committed
1372
	    /*
1373
1374
1375
	     * Locate any test associated with this field, skipping
	     * tests associated with the pattern when substituting in
	     * the font
Keith Packard's avatar
Keith Packard committed
1376
1377
	     */
	    for (t = s->test, i = 0; t; t = t->next, i++)
1378
1379
	    {
		if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1380
		    t->object == e->object)
1381
		{
1382
1383
1384
1385
1386
1387
1388
		    /* 
		     * KLUDGE - the pattern may have been reallocated or
		     * things may have been inserted or deleted above
		     * this element by other edits.  Go back and find
		     * the element again
		     */
		    if (e != s->edit && st[i].elt)
1389
			st[i].elt = FcPatternObjectFindElt (p, t->object);