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