fcname.c revision d91dd368
1/*
2 * fontconfig/src/fcname.c
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 the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission.  The authors make 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 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) 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 "fcint.h"
26#include <ctype.h>
27#include <stdlib.h>
28#include <string.h>
29#include <stdio.h>
30
31static const FcObjectType FcObjects[] = {
32#define FC_OBJECT(NAME, Type, Cmp) { FC_##NAME, Type },
33#include "fcobjs.h"
34#undef FC_OBJECT
35};
36
37#define NUM_OBJECT_TYPES ((int) (sizeof FcObjects / sizeof FcObjects[0]))
38
39static const FcObjectType *
40FcObjectFindById (FcObject object)
41{
42    if (1 <= object && object <= NUM_OBJECT_TYPES)
43	return &FcObjects[object - 1];
44    return FcObjectLookupOtherTypeById (object);
45}
46
47FcBool
48FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
49{
50    /* Deprecated. */
51    return FcFalse;
52}
53
54FcBool
55FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
56{
57    /* Deprecated. */
58    return FcFalse;
59}
60
61const FcObjectType *
62FcNameGetObjectType (const char *object)
63{
64    int id = FcObjectLookupBuiltinIdByName (object);
65
66    if (!id)
67	return FcObjectLookupOtherTypeByName (object);
68
69    return &FcObjects[id - 1];
70}
71
72FcBool
73FcObjectValidType (FcObject object, FcType type)
74{
75    const FcObjectType    *t = FcObjectFindById (object);
76
77    if (t) {
78	switch ((int) t->type) {
79	case FcTypeUnknown:
80	    return FcTrue;
81	case FcTypeDouble:
82	case FcTypeInteger:
83	    if (type == FcTypeDouble || type == FcTypeInteger)
84		return FcTrue;
85	    break;
86	case FcTypeLangSet:
87	    if (type == FcTypeLangSet || type == FcTypeString)
88		return FcTrue;
89	    break;
90	default:
91	    if (type == t->type)
92		return FcTrue;
93	    break;
94	}
95	return FcFalse;
96    }
97    return FcTrue;
98}
99
100FcObject
101FcObjectFromName (const char * name)
102{
103    return FcObjectLookupIdByName (name);
104}
105
106FcObjectSet *
107FcObjectGetSet (void)
108{
109    int		i;
110    FcObjectSet	*os = NULL;
111
112
113    os = FcObjectSetCreate ();
114    for (i = 0; i < NUM_OBJECT_TYPES; i++)
115	FcObjectSetAdd (os, FcObjects[i].object);
116
117    return os;
118}
119
120const char *
121FcObjectName (FcObject object)
122{
123    const FcObjectType   *o = FcObjectFindById (object);
124
125    if (o)
126	return o->object;
127
128    return FcObjectLookupOtherNameById (object);
129}
130
131static const FcConstant _FcBaseConstants[] = {
132    { (FcChar8 *) "thin",	    "weight",   FC_WEIGHT_THIN, },
133    { (FcChar8 *) "extralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
134    { (FcChar8 *) "ultralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
135    { (FcChar8 *) "light",	    "weight",   FC_WEIGHT_LIGHT, },
136    { (FcChar8 *) "book",	    "weight",	FC_WEIGHT_BOOK, },
137    { (FcChar8 *) "regular",	    "weight",   FC_WEIGHT_REGULAR, },
138    { (FcChar8 *) "medium",	    "weight",   FC_WEIGHT_MEDIUM, },
139    { (FcChar8 *) "demibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
140    { (FcChar8 *) "semibold",	    "weight",   FC_WEIGHT_DEMIBOLD, },
141    { (FcChar8 *) "bold",	    "weight",   FC_WEIGHT_BOLD, },
142    { (FcChar8 *) "extrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
143    { (FcChar8 *) "ultrabold",	    "weight",   FC_WEIGHT_EXTRABOLD, },
144    { (FcChar8 *) "black",	    "weight",   FC_WEIGHT_BLACK, },
145    { (FcChar8 *) "heavy",	    "weight",	FC_WEIGHT_HEAVY, },
146
147    { (FcChar8 *) "roman",	    "slant",    FC_SLANT_ROMAN, },
148    { (FcChar8 *) "italic",	    "slant",    FC_SLANT_ITALIC, },
149    { (FcChar8 *) "oblique",	    "slant",    FC_SLANT_OBLIQUE, },
150
151    { (FcChar8 *) "ultracondensed", "width",	FC_WIDTH_ULTRACONDENSED },
152    { (FcChar8 *) "extracondensed", "width",	FC_WIDTH_EXTRACONDENSED },
153    { (FcChar8 *) "condensed",	    "width",	FC_WIDTH_CONDENSED },
154    { (FcChar8 *) "semicondensed",  "width",	FC_WIDTH_SEMICONDENSED },
155    { (FcChar8 *) "normal",	    "width",	FC_WIDTH_NORMAL },
156    { (FcChar8 *) "semiexpanded",   "width",	FC_WIDTH_SEMIEXPANDED },
157    { (FcChar8 *) "expanded",	    "width",	FC_WIDTH_EXPANDED },
158    { (FcChar8 *) "extraexpanded",  "width",	FC_WIDTH_EXTRAEXPANDED },
159    { (FcChar8 *) "ultraexpanded",  "width",	FC_WIDTH_ULTRAEXPANDED },
160
161    { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
162    { (FcChar8 *) "dual",	    "spacing",  FC_DUAL, },
163    { (FcChar8 *) "mono",	    "spacing",  FC_MONO, },
164    { (FcChar8 *) "charcell",	    "spacing",  FC_CHARCELL, },
165
166    { (FcChar8 *) "unknown",	    "rgba",	    FC_RGBA_UNKNOWN },
167    { (FcChar8 *) "rgb",	    "rgba",	    FC_RGBA_RGB, },
168    { (FcChar8 *) "bgr",	    "rgba",	    FC_RGBA_BGR, },
169    { (FcChar8 *) "vrgb",	    "rgba",	    FC_RGBA_VRGB },
170    { (FcChar8 *) "vbgr",	    "rgba",	    FC_RGBA_VBGR },
171    { (FcChar8 *) "none",	    "rgba",	    FC_RGBA_NONE },
172
173    { (FcChar8 *) "hintnone",	    "hintstyle",   FC_HINT_NONE },
174    { (FcChar8 *) "hintslight",	    "hintstyle",   FC_HINT_SLIGHT },
175    { (FcChar8 *) "hintmedium",	    "hintstyle",   FC_HINT_MEDIUM },
176    { (FcChar8 *) "hintfull",	    "hintstyle",   FC_HINT_FULL },
177
178    { (FcChar8 *) "antialias",	    "antialias",    FcTrue },
179    { (FcChar8 *) "hinting",	    "hinting",	    FcTrue },
180    { (FcChar8 *) "verticallayout", "verticallayout",	FcTrue },
181    { (FcChar8 *) "autohint",	    "autohint",	    FcTrue },
182    { (FcChar8 *) "globaladvance",  "globaladvance",	FcTrue }, /* deprecated */
183    { (FcChar8 *) "outline",	    "outline",	    FcTrue },
184    { (FcChar8 *) "scalable",	    "scalable",	    FcTrue },
185    { (FcChar8 *) "minspace",	    "minspace",	    FcTrue },
186    { (FcChar8 *) "embolden",	    "embolden",	    FcTrue },
187    { (FcChar8 *) "embeddedbitmap", "embeddedbitmap",	FcTrue },
188    { (FcChar8 *) "decorative",	    "decorative",   FcTrue },
189    { (FcChar8 *) "lcdnone",	    "lcdfilter",    FC_LCD_NONE },
190    { (FcChar8 *) "lcddefault",	    "lcdfilter",    FC_LCD_DEFAULT },
191    { (FcChar8 *) "lcdlight",	    "lcdfilter",    FC_LCD_LIGHT },
192    { (FcChar8 *) "lcdlegacy",	    "lcdfilter",    FC_LCD_LEGACY },
193};
194
195#define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
196
197FcBool
198FcNameRegisterConstants (const FcConstant *consts, int nconsts)
199{
200    /* Deprecated. */
201    return FcFalse;
202}
203
204FcBool
205FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
206{
207    /* Deprecated. */
208    return FcFalse;
209}
210
211const FcConstant *
212FcNameGetConstant (const FcChar8 *string)
213{
214    unsigned int	    i;
215
216    for (i = 0; i < NUM_FC_CONSTANTS; i++)
217	if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name))
218	    return &_FcBaseConstants[i];
219
220    return 0;
221}
222
223FcBool
224FcNameConstant (const FcChar8 *string, int *result)
225{
226    const FcConstant	*c;
227
228    if ((c = FcNameGetConstant(string)))
229    {
230	*result = c->value;
231	return FcTrue;
232    }
233    return FcFalse;
234}
235
236FcBool
237FcNameBool (const FcChar8 *v, FcBool *result)
238{
239    char    c0, c1;
240
241    c0 = *v;
242    c0 = FcToLower (c0);
243    if (c0 == 't' || c0 == 'y' || c0 == '1')
244    {
245	*result = FcTrue;
246	return FcTrue;
247    }
248    if (c0 == 'f' || c0 == 'n' || c0 == '0')
249    {
250	*result = FcFalse;
251	return FcTrue;
252    }
253    if (c0 == 'o')
254    {
255	c1 = v[1];
256	c1 = FcToLower (c1);
257	if (c1 == 'n')
258	{
259	    *result = FcTrue;
260	    return FcTrue;
261	}
262	if (c1 == 'f')
263	{
264	    *result = FcFalse;
265	    return FcTrue;
266	}
267    }
268    return FcFalse;
269}
270
271static FcValue
272FcNameConvert (FcType type, FcChar8 *string)
273{
274    FcValue	v;
275    FcMatrix	m;
276
277    v.type = type;
278    switch ((int) v.type) {
279    case FcTypeInteger:
280	if (!FcNameConstant (string, &v.u.i))
281	    v.u.i = atoi ((char *) string);
282	break;
283    case FcTypeString:
284	v.u.s = FcStrdup (string);
285	if (!v.u.s)
286	    v.type = FcTypeVoid;
287	break;
288    case FcTypeBool:
289	if (!FcNameBool (string, &v.u.b))
290	    v.u.b = FcFalse;
291	break;
292    case FcTypeDouble:
293	v.u.d = strtod ((char *) string, 0);
294	break;
295    case FcTypeMatrix:
296	FcMatrixInit (&m);
297	sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
298	v.u.m = FcMatrixCopy (&m);
299	break;
300    case FcTypeCharSet:
301	v.u.c = FcNameParseCharSet (string);
302	if (!v.u.c)
303	    v.type = FcTypeVoid;
304	break;
305    case FcTypeLangSet:
306	v.u.l = FcNameParseLangSet (string);
307	if (!v.u.l)
308	    v.type = FcTypeVoid;
309	break;
310    default:
311	break;
312    }
313    return v;
314}
315
316static const FcChar8 *
317FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
318{
319    FcChar8    c;
320
321    while ((c = *cur))
322    {
323	if (!isspace (c))
324	    break;
325	++cur;
326    }
327    while ((c = *cur))
328    {
329	if (c == '\\')
330	{
331	    ++cur;
332	    if (!(c = *cur))
333		break;
334	}
335	else if (strchr (delim, c))
336	    break;
337	++cur;
338	*save++ = c;
339    }
340    *save = 0;
341    *last = *cur;
342    if (*cur)
343	cur++;
344    return cur;
345}
346
347FcPattern *
348FcNameParse (const FcChar8 *name)
349{
350    FcChar8		*save;
351    FcPattern		*pat;
352    double		d;
353    FcChar8		*e;
354    FcChar8		delim;
355    FcValue		v;
356    const FcObjectType	*t;
357    const FcConstant	*c;
358
359    /* freed below */
360    save = malloc (strlen ((char *) name) + 1);
361    if (!save)
362	goto bail0;
363    pat = FcPatternCreate ();
364    if (!pat)
365	goto bail1;
366
367    for (;;)
368    {
369	name = FcNameFindNext (name, "-,:", save, &delim);
370	if (save[0])
371	{
372	    if (!FcPatternAddString (pat, FC_FAMILY, save))
373		goto bail2;
374	}
375	if (delim != ',')
376	    break;
377    }
378    if (delim == '-')
379    {
380	for (;;)
381	{
382	    name = FcNameFindNext (name, "-,:", save, &delim);
383	    d = strtod ((char *) save, (char **) &e);
384	    if (e != save)
385	    {
386		if (!FcPatternAddDouble (pat, FC_SIZE, d))
387		    goto bail2;
388	    }
389	    if (delim != ',')
390		break;
391	}
392    }
393    while (delim == ':')
394    {
395	name = FcNameFindNext (name, "=_:", save, &delim);
396	if (save[0])
397	{
398	    if (delim == '=' || delim == '_')
399	    {
400		t = FcNameGetObjectType ((char *) save);
401		for (;;)
402		{
403		    name = FcNameFindNext (name, ":,", save, &delim);
404		    if (t)
405		    {
406			v = FcNameConvert (t->type, save);
407			if (!FcPatternAdd (pat, t->object, v, FcTrue))
408			{
409			    FcValueDestroy (v);
410			    goto bail2;
411			}
412			FcValueDestroy (v);
413		    }
414		    if (delim != ',')
415			break;
416		}
417	    }
418	    else
419	    {
420		if ((c = FcNameGetConstant (save)))
421		{
422		    t = FcNameGetObjectType ((char *) c->object);
423		    switch ((int) t->type) {
424		    case FcTypeInteger:
425		    case FcTypeDouble:
426			if (!FcPatternAddInteger (pat, c->object, c->value))
427			    goto bail2;
428			break;
429		    case FcTypeBool:
430			if (!FcPatternAddBool (pat, c->object, c->value))
431			    goto bail2;
432			break;
433		    default:
434			break;
435		    }
436		}
437	    }
438	}
439    }
440
441    free (save);
442    return pat;
443
444bail2:
445    FcPatternDestroy (pat);
446bail1:
447    free (save);
448bail0:
449    return 0;
450}
451static FcBool
452FcNameUnparseString (FcStrBuf	    *buf,
453		     const FcChar8  *string,
454		     const FcChar8  *escape)
455{
456    FcChar8 c;
457    while ((c = *string++))
458    {
459	if (escape && strchr ((char *) escape, (char) c))
460	{
461	    if (!FcStrBufChar (buf, escape[0]))
462		return FcFalse;
463	}
464	if (!FcStrBufChar (buf, c))
465	    return FcFalse;
466    }
467    return FcTrue;
468}
469
470FcBool
471FcNameUnparseValue (FcStrBuf	*buf,
472		    FcValue	*v0,
473		    FcChar8	*escape)
474{
475    FcChar8	temp[1024];
476    FcValue v = FcValueCanonicalize(v0);
477
478    switch (v.type) {
479    case FcTypeUnknown:
480    case FcTypeVoid:
481	return FcTrue;
482    case FcTypeInteger:
483	sprintf ((char *) temp, "%d", v.u.i);
484	return FcNameUnparseString (buf, temp, 0);
485    case FcTypeDouble:
486	sprintf ((char *) temp, "%g", v.u.d);
487	return FcNameUnparseString (buf, temp, 0);
488    case FcTypeString:
489	return FcNameUnparseString (buf, v.u.s, escape);
490    case FcTypeBool:
491	return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
492    case FcTypeMatrix:
493	sprintf ((char *) temp, "%g %g %g %g",
494		 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
495	return FcNameUnparseString (buf, temp, 0);
496    case FcTypeCharSet:
497	return FcNameUnparseCharSet (buf, v.u.c);
498    case FcTypeLangSet:
499	return FcNameUnparseLangSet (buf, v.u.l);
500    case FcTypeFTFace:
501	return FcTrue;
502    }
503    return FcFalse;
504}
505
506FcBool
507FcNameUnparseValueList (FcStrBuf	*buf,
508			FcValueListPtr	v,
509			FcChar8		*escape)
510{
511    while (v)
512    {
513	if (!FcNameUnparseValue (buf, &v->value, escape))
514	    return FcFalse;
515	if ((v = FcValueListNext(v)) != NULL)
516	    if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
517		return FcFalse;
518    }
519    return FcTrue;
520}
521
522#define FC_ESCAPE_FIXED    "\\-:,"
523#define FC_ESCAPE_VARIABLE "\\=_:,"
524
525FcChar8 *
526FcNameUnparse (FcPattern *pat)
527{
528    return FcNameUnparseEscaped (pat, FcTrue);
529}
530
531FcChar8 *
532FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
533{
534    FcStrBuf		    buf;
535    FcChar8		    buf_static[8192];
536    int			    i;
537    FcPatternElt	    *e;
538
539    FcStrBufInit (&buf, buf_static, sizeof (buf_static));
540    e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
541    if (e)
542    {
543        if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
544	    goto bail0;
545    }
546    e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
547    if (e)
548    {
549	if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
550	    goto bail0;
551	if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
552	    goto bail0;
553    }
554    for (i = 0; i < NUM_OBJECT_TYPES; i++)
555    {
556	FcObject id = i + 1;
557	const FcObjectType	    *o;
558	o = &FcObjects[i];
559	if (!strcmp (o->object, FC_FAMILY) ||
560	    !strcmp (o->object, FC_SIZE))
561	    continue;
562
563	e = FcPatternObjectFindElt (pat, id);
564	if (e)
565	{
566	    if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
567		goto bail0;
568	    if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
569		goto bail0;
570	    if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
571		goto bail0;
572	    if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
573					 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
574		goto bail0;
575	}
576    }
577    return FcStrBufDone (&buf);
578bail0:
579    FcStrBufDestroy (&buf);
580    return 0;
581}
582#define __fcname__
583#include "fcaliastail.h"
584#undef __fcname__
585