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