]> git.wh0rd.org - fontconfig.git/blob - src/fcname.c
Add FcPatternEqualSubset for Pango, clean up some internal FcPattern
[fontconfig.git] / src / fcname.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcname.c,v 1.6 2002/06/02 21:07:57 keithp Exp $
3 *
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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 <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include "fcint.h"
30
31 static const FcObjectType _FcBaseObjectTypes[] = {
32 { FC_FAMILY, FcTypeString, },
33 { FC_STYLE, FcTypeString, },
34 { FC_SLANT, FcTypeInteger, },
35 { FC_WEIGHT, FcTypeInteger, },
36 { FC_SIZE, FcTypeDouble, },
37 { FC_ASPECT, FcTypeDouble, },
38 { FC_PIXEL_SIZE, FcTypeDouble, },
39 { FC_SPACING, FcTypeInteger, },
40 { FC_FOUNDRY, FcTypeString, },
41 /* { FC_CORE, FcTypeBool, }, */
42 { FC_ANTIALIAS, FcTypeBool, },
43 /* { FC_XLFD, FcTypeString, }, */
44 { FC_FILE, FcTypeString, },
45 { FC_INDEX, FcTypeInteger, },
46 { FC_RASTERIZER, FcTypeString, },
47 { FC_OUTLINE, FcTypeBool, },
48 { FC_SCALABLE, FcTypeBool, },
49 { FC_RGBA, FcTypeInteger, },
50 { FC_SCALE, FcTypeDouble, },
51 /* { FC_RENDER, FcTypeBool, },*/
52 { FC_MINSPACE, FcTypeBool, },
53 { FC_CHAR_WIDTH, FcTypeInteger },
54 { FC_CHAR_HEIGHT, FcTypeInteger },
55 { FC_MATRIX, FcTypeMatrix },
56 { FC_CHARSET, FcTypeCharSet },
57 { FC_LANG, FcTypeString },
58 };
59
60 #define NUM_OBJECT_TYPES (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
61
62 typedef struct _FcObjectTypeList FcObjectTypeList;
63
64 struct _FcObjectTypeList {
65 const FcObjectTypeList *next;
66 const FcObjectType *types;
67 int ntypes;
68 };
69
70 static const FcObjectTypeList _FcBaseObjectTypesList = {
71 0,
72 _FcBaseObjectTypes,
73 NUM_OBJECT_TYPES
74 };
75
76 static const FcObjectTypeList *_FcObjectTypes = &_FcBaseObjectTypesList;
77
78 FcBool
79 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
80 {
81 FcObjectTypeList *l;
82
83 l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
84 if (!l)
85 return FcFalse;
86 l->types = types;
87 l->ntypes = ntypes;
88 l->next = _FcObjectTypes;
89 _FcObjectTypes = l;
90 return FcTrue;
91 }
92
93 FcBool
94 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
95 {
96 const FcObjectTypeList *l, **prev;
97
98 for (prev = &_FcObjectTypes;
99 (l = *prev);
100 prev = (const FcObjectTypeList **) &(l->next))
101 {
102 if (l->types == types && l->ntypes == ntypes)
103 {
104 *prev = l->next;
105 free ((void *) l);
106 return FcTrue;
107 }
108 }
109 return FcFalse;
110 }
111
112 const FcObjectType *
113 FcNameGetObjectType (const char *object)
114 {
115 int i;
116 const FcObjectTypeList *l;
117 const FcObjectType *t;
118
119 for (l = _FcObjectTypes; l; l = l->next)
120 {
121 for (i = 0; i < l->ntypes; i++)
122 {
123 t = &l->types[i];
124 if (!strcmp (object, t->object))
125 return t;
126 }
127 }
128 return 0;
129 }
130
131 static const FcConstant _FcBaseConstants[] = {
132 { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, },
133 { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, },
134 { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, },
135 { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, },
136 { (FcChar8 *) "black", "weight", FC_WEIGHT_BLACK, },
137
138 { (FcChar8 *) "roman", "slant", FC_SLANT_ROMAN, },
139 { (FcChar8 *) "italic", "slant", FC_SLANT_ITALIC, },
140 { (FcChar8 *) "oblique", "slant", FC_SLANT_OBLIQUE, },
141
142 { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, },
143 { (FcChar8 *) "mono", "spacing", FC_MONO, },
144 { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, },
145
146 { (FcChar8 *) "rgb", "rgba", FC_RGBA_RGB, },
147 { (FcChar8 *) "bgr", "rgba", FC_RGBA_BGR, },
148 { (FcChar8 *) "vrgb", "rgba", FC_RGBA_VRGB },
149 { (FcChar8 *) "vbgr", "rgba", FC_RGBA_VBGR },
150 };
151
152 #define NUM_FC_CONSTANTS (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
153
154 typedef struct _FcConstantList FcConstantList;
155
156 struct _FcConstantList {
157 const FcConstantList *next;
158 const FcConstant *consts;
159 int nconsts;
160 };
161
162 static const FcConstantList _FcBaseConstantList = {
163 0,
164 _FcBaseConstants,
165 NUM_FC_CONSTANTS
166 };
167
168 static const FcConstantList *_FcConstants = &_FcBaseConstantList;
169
170 FcBool
171 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
172 {
173 FcConstantList *l;
174
175 l = (FcConstantList *) malloc (sizeof (FcConstantList));
176 if (!l)
177 return FcFalse;
178 l->consts = consts;
179 l->nconsts = nconsts;
180 l->next = _FcConstants;
181 _FcConstants = l;
182 return FcTrue;
183 }
184
185 FcBool
186 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
187 {
188 const FcConstantList *l, **prev;
189
190 for (prev = &_FcConstants;
191 (l = *prev);
192 prev = (const FcConstantList **) &(l->next))
193 {
194 if (l->consts == consts && l->nconsts == nconsts)
195 {
196 *prev = l->next;
197 free ((void *) l);
198 return FcTrue;
199 }
200 }
201 return FcFalse;
202 }
203
204 const FcConstant *
205 FcNameGetConstant (FcChar8 *string)
206 {
207 const FcConstantList *l;
208 int i;
209
210 for (l = _FcConstants; l; l = l->next)
211 {
212 for (i = 0; i < l->nconsts; i++)
213 if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
214 return &l->consts[i];
215 }
216 return 0;
217 }
218
219 FcBool
220 FcNameConstant (FcChar8 *string, int *result)
221 {
222 const FcConstant *c;
223
224 if ((c = FcNameGetConstant(string)))
225 {
226 *result = c->value;
227 return FcTrue;
228 }
229 return FcFalse;
230 }
231
232 FcBool
233 FcNameBool (FcChar8 *v, FcBool *result)
234 {
235 char c0, c1;
236
237 c0 = *v;
238 if (isupper (c0))
239 c0 = tolower (c0);
240 if (c0 == 't' || c0 == 'y' || c0 == '1')
241 {
242 *result = FcTrue;
243 return FcTrue;
244 }
245 if (c0 == 'f' || c0 == 'n' || c0 == '0')
246 {
247 *result = FcFalse;
248 return FcTrue;
249 }
250 if (c0 == 'o')
251 {
252 c1 = v[1];
253 if (isupper (c1))
254 c1 = tolower (c1);
255 if (c1 == 'n')
256 {
257 *result = FcTrue;
258 return FcTrue;
259 }
260 if (c1 == 'f')
261 {
262 *result = FcFalse;
263 return FcTrue;
264 }
265 }
266 return FcFalse;
267 }
268
269 static FcValue
270 FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
271 {
272 FcValue v;
273
274 v.type = type;
275 switch (v.type) {
276 case FcTypeInteger:
277 if (!FcNameConstant (string, &v.u.i))
278 v.u.i = atoi ((char *) string);
279 break;
280 case FcTypeString:
281 v.u.s = string;
282 break;
283 case FcTypeBool:
284 if (!FcNameBool (string, &v.u.b))
285 v.u.b = FcFalse;
286 break;
287 case FcTypeDouble:
288 v.u.d = strtod ((char *) string, 0);
289 break;
290 case FcTypeMatrix:
291 v.u.m = m;
292 sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
293 break;
294 case FcTypeCharSet:
295 v.u.c = FcNameParseCharSet (string);
296 break;
297 default:
298 break;
299 }
300 return v;
301 }
302
303 static const FcChar8 *
304 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
305 {
306 FcChar8 c;
307
308 while ((c = *cur))
309 {
310 if (c == '\\')
311 {
312 ++cur;
313 if (!(c = *cur))
314 break;
315 }
316 else if (strchr (delim, c))
317 break;
318 ++cur;
319 *save++ = c;
320 }
321 *save = 0;
322 *last = *cur;
323 if (*cur)
324 cur++;
325 return cur;
326 }
327
328 FcPattern *
329 FcNameParse (const FcChar8 *name)
330 {
331 FcChar8 *save;
332 FcPattern *pat;
333 double d;
334 FcChar8 *e;
335 FcChar8 delim;
336 FcValue v;
337 FcMatrix m;
338 const FcObjectType *t;
339 const FcConstant *c;
340
341 save = malloc (strlen ((char *) name) + 1);
342 if (!save)
343 goto bail0;
344 pat = FcPatternCreate ();
345 if (!pat)
346 goto bail1;
347
348 for (;;)
349 {
350 name = FcNameFindNext (name, "-,:", save, &delim);
351 if (save[0])
352 {
353 if (!FcPatternAddString (pat, FC_FAMILY, save))
354 goto bail2;
355 }
356 if (delim != ',')
357 break;
358 }
359 if (delim == '-')
360 {
361 for (;;)
362 {
363 name = FcNameFindNext (name, "-,:", save, &delim);
364 d = strtod ((char *) save, (char **) &e);
365 if (e != save)
366 {
367 if (!FcPatternAddDouble (pat, FC_SIZE, d))
368 goto bail2;
369 }
370 if (delim != ',')
371 break;
372 }
373 }
374 while (delim == ':')
375 {
376 name = FcNameFindNext (name, "=_:", save, &delim);
377 if (save[0])
378 {
379 if (delim == '=' || delim == '_')
380 {
381 t = FcNameGetObjectType ((char *) save);
382 for (;;)
383 {
384 name = FcNameFindNext (name, ":,", save, &delim);
385 if (save[0] && t)
386 {
387 v = FcNameConvert (t->type, save, &m);
388 if (!FcPatternAdd (pat, t->object, v, FcTrue))
389 {
390 if (v.type == FcTypeCharSet)
391 FcCharSetDestroy ((FcCharSet *) v.u.c);
392 goto bail2;
393 }
394 if (v.type == FcTypeCharSet)
395 FcCharSetDestroy ((FcCharSet *) v.u.c);
396 }
397 if (delim != ',')
398 break;
399 }
400 }
401 else
402 {
403 if ((c = FcNameGetConstant (save)))
404 {
405 if (!FcPatternAddInteger (pat, c->object, c->value))
406 goto bail2;
407 }
408 }
409 }
410 }
411
412 free (save);
413 return pat;
414
415 bail2:
416 FcPatternDestroy (pat);
417 bail1:
418 free (save);
419 bail0:
420 return 0;
421 }
422 static FcBool
423 FcNameUnparseString (FcStrBuf *buf,
424 const FcChar8 *string,
425 const FcChar8 *escape)
426 {
427 FcChar8 c;
428 while ((c = *string++))
429 {
430 if (escape && strchr ((char *) escape, (char) c))
431 {
432 if (!FcStrBufChar (buf, escape[0]))
433 return FcFalse;
434 }
435 if (!FcStrBufChar (buf, c))
436 return FcFalse;
437 }
438 return FcTrue;
439 }
440
441 static FcBool
442 FcNameUnparseValue (FcStrBuf *buf,
443 FcValue v,
444 FcChar8 *escape)
445 {
446 FcChar8 temp[1024];
447
448 switch (v.type) {
449 case FcTypeVoid:
450 return FcTrue;
451 case FcTypeInteger:
452 sprintf ((char *) temp, "%d", v.u.i);
453 return FcNameUnparseString (buf, temp, 0);
454 case FcTypeDouble:
455 sprintf ((char *) temp, "%g", v.u.d);
456 return FcNameUnparseString (buf, temp, 0);
457 case FcTypeString:
458 return FcNameUnparseString (buf, v.u.s, escape);
459 case FcTypeBool:
460 return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
461 case FcTypeMatrix:
462 sprintf ((char *) temp, "%g %g %g %g",
463 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
464 return FcNameUnparseString (buf, temp, 0);
465 case FcTypeCharSet:
466 return FcNameUnparseCharSet (buf, v.u.c);
467 case FcTypeFTFace:
468 return FcTrue;
469 }
470 return FcFalse;
471 }
472
473 static FcBool
474 FcNameUnparseValueList (FcStrBuf *buf,
475 FcValueList *v,
476 FcChar8 *escape)
477 {
478 while (v)
479 {
480 if (!FcNameUnparseValue (buf, v->value, escape))
481 return FcFalse;
482 if ((v = v->next))
483 if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
484 return FcFalse;
485 }
486 return FcTrue;
487 }
488
489 #define FC_ESCAPE_FIXED "\\-:,"
490 #define FC_ESCAPE_VARIABLE "\\=_:,"
491
492 FcChar8 *
493 FcNameUnparse (FcPattern *pat)
494 {
495 FcStrBuf buf;
496 FcChar8 buf_static[8192];
497 int i;
498 FcPatternElt *e;
499 const FcObjectTypeList *l;
500 const FcObjectType *o;
501
502 FcStrBufInit (&buf, buf_static, sizeof (buf_static));
503 e = FcPatternFindElt (pat, FC_FAMILY);
504 if (e)
505 {
506 if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
507 goto bail0;
508 }
509 e = FcPatternFindElt (pat, FC_SIZE);
510 if (e)
511 {
512 if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
513 goto bail0;
514 if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
515 goto bail0;
516 }
517 for (l = _FcObjectTypes; l; l = l->next)
518 {
519 for (i = 0; i < l->ntypes; i++)
520 {
521 o = &l->types[i];
522 if (!strcmp (o->object, FC_FAMILY) ||
523 !strcmp (o->object, FC_SIZE) ||
524 !strcmp (o->object, FC_FILE))
525 continue;
526
527 e = FcPatternFindElt (pat, o->object);
528 if (e)
529 {
530 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
531 goto bail0;
532 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, (FcChar8 *) FC_ESCAPE_VARIABLE))
533 goto bail0;
534 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
535 goto bail0;
536 if (!FcNameUnparseValueList (&buf, e->values,
537 (FcChar8 *) FC_ESCAPE_VARIABLE))
538 goto bail0;
539 }
540 }
541 }
542 return FcStrBufDone (&buf);
543 bail0:
544 FcStrBufDestroy (&buf);
545 return 0;
546 }