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