fcname.c revision 7872e0a1
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	case FcTypeRange:
91	    if (type == FcTypeRange ||
92		type == FcTypeDouble ||
93		type == FcTypeInteger)
94		return FcTrue;
95	    break;
96	default:
97	    if (type == t->type)
98		return FcTrue;
99	    break;
100	}
101	return FcFalse;
102    }
103    return FcTrue;
104}
105
106FcObject
107FcObjectFromName (const char * name)
108{
109    return FcObjectLookupIdByName (name);
110}
111
112FcObjectSet *
113FcObjectGetSet (void)
114{
115    int		i;
116    FcObjectSet	*os = NULL;
117
118
119    os = FcObjectSetCreate ();
120    for (i = 0; i < NUM_OBJECT_TYPES; i++)
121	FcObjectSetAdd (os, FcObjects[i].object);
122
123    return os;
124}
125
126const char *
127FcObjectName (FcObject object)
128{
129    const FcObjectType   *o = FcObjectFindById (object);
130
131    if (o)
132	return o->object;
133
134    return FcObjectLookupOtherNameById (object);
135}
136
137static const FcConstant _FcBaseConstants[] = {
138    { (FcChar8 *) "thin",	    "weight",   FC_WEIGHT_THIN, },
139    { (FcChar8 *) "extralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
140    { (FcChar8 *) "ultralight",	    "weight",   FC_WEIGHT_EXTRALIGHT, },
141    { (FcChar8 *) "demilight",	    "weight",   FC_WEIGHT_DEMILIGHT, },
142    { (FcChar8 *) "semilight",	    "weight",   FC_WEIGHT_DEMILIGHT, },
143    { (FcChar8 *) "light",	    "weight",   FC_WEIGHT_LIGHT, },
144    { (FcChar8 *) "book",	    "weight",	FC_WEIGHT_BOOK, },
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    { (FcChar8 *) "heavy",	    "weight",	FC_WEIGHT_HEAVY, },
154
155    { (FcChar8 *) "roman",	    "slant",    FC_SLANT_ROMAN, },
156    { (FcChar8 *) "italic",	    "slant",    FC_SLANT_ITALIC, },
157    { (FcChar8 *) "oblique",	    "slant",    FC_SLANT_OBLIQUE, },
158
159    { (FcChar8 *) "ultracondensed", "width",	FC_WIDTH_ULTRACONDENSED },
160    { (FcChar8 *) "extracondensed", "width",	FC_WIDTH_EXTRACONDENSED },
161    { (FcChar8 *) "condensed",	    "width",	FC_WIDTH_CONDENSED },
162    { (FcChar8 *) "semicondensed",  "width",	FC_WIDTH_SEMICONDENSED },
163    { (FcChar8 *) "normal",	    "width",	FC_WIDTH_NORMAL },
164    { (FcChar8 *) "semiexpanded",   "width",	FC_WIDTH_SEMIEXPANDED },
165    { (FcChar8 *) "expanded",	    "width",	FC_WIDTH_EXPANDED },
166    { (FcChar8 *) "extraexpanded",  "width",	FC_WIDTH_EXTRAEXPANDED },
167    { (FcChar8 *) "ultraexpanded",  "width",	FC_WIDTH_ULTRAEXPANDED },
168
169    { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
170    { (FcChar8 *) "dual",	    "spacing",  FC_DUAL, },
171    { (FcChar8 *) "mono",	    "spacing",  FC_MONO, },
172    { (FcChar8 *) "charcell",	    "spacing",  FC_CHARCELL, },
173
174    { (FcChar8 *) "unknown",	    "rgba",	    FC_RGBA_UNKNOWN },
175    { (FcChar8 *) "rgb",	    "rgba",	    FC_RGBA_RGB, },
176    { (FcChar8 *) "bgr",	    "rgba",	    FC_RGBA_BGR, },
177    { (FcChar8 *) "vrgb",	    "rgba",	    FC_RGBA_VRGB },
178    { (FcChar8 *) "vbgr",	    "rgba",	    FC_RGBA_VBGR },
179    { (FcChar8 *) "none",	    "rgba",	    FC_RGBA_NONE },
180
181    { (FcChar8 *) "hintnone",	    "hintstyle",   FC_HINT_NONE },
182    { (FcChar8 *) "hintslight",	    "hintstyle",   FC_HINT_SLIGHT },
183    { (FcChar8 *) "hintmedium",	    "hintstyle",   FC_HINT_MEDIUM },
184    { (FcChar8 *) "hintfull",	    "hintstyle",   FC_HINT_FULL },
185
186    { (FcChar8 *) "antialias",	    "antialias",    FcTrue },
187    { (FcChar8 *) "hinting",	    "hinting",	    FcTrue },
188    { (FcChar8 *) "verticallayout", "verticallayout",	FcTrue },
189    { (FcChar8 *) "autohint",	    "autohint",	    FcTrue },
190    { (FcChar8 *) "globaladvance",  "globaladvance",	FcTrue }, /* deprecated */
191    { (FcChar8 *) "outline",	    "outline",	    FcTrue },
192    { (FcChar8 *) "scalable",	    "scalable",	    FcTrue },
193    { (FcChar8 *) "minspace",	    "minspace",	    FcTrue },
194    { (FcChar8 *) "embolden",	    "embolden",	    FcTrue },
195    { (FcChar8 *) "embeddedbitmap", "embeddedbitmap",	FcTrue },
196    { (FcChar8 *) "decorative",	    "decorative",   FcTrue },
197    { (FcChar8 *) "lcdnone",	    "lcdfilter",    FC_LCD_NONE },
198    { (FcChar8 *) "lcddefault",	    "lcdfilter",    FC_LCD_DEFAULT },
199    { (FcChar8 *) "lcdlight",	    "lcdfilter",    FC_LCD_LIGHT },
200    { (FcChar8 *) "lcdlegacy",	    "lcdfilter",    FC_LCD_LEGACY },
201};
202
203#define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
204
205FcBool
206FcNameRegisterConstants (const FcConstant *consts, int nconsts)
207{
208    /* Deprecated. */
209    return FcFalse;
210}
211
212FcBool
213FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
214{
215    /* Deprecated. */
216    return FcFalse;
217}
218
219const FcConstant *
220FcNameGetConstant (const FcChar8 *string)
221{
222    unsigned int	    i;
223
224    for (i = 0; i < NUM_FC_CONSTANTS; i++)
225	if (!FcStrCmpIgnoreCase (string, _FcBaseConstants[i].name))
226	    return &_FcBaseConstants[i];
227
228    return 0;
229}
230
231FcBool
232FcNameConstant (const FcChar8 *string, int *result)
233{
234    const FcConstant	*c;
235
236    if ((c = FcNameGetConstant(string)))
237    {
238	*result = c->value;
239	return FcTrue;
240    }
241    return FcFalse;
242}
243
244FcBool
245FcNameConstantWithObjectCheck (const FcChar8 *string, const char *object, int *result)
246{
247    const FcConstant	*c;
248
249    if ((c = FcNameGetConstant(string)))
250    {
251	if (strcmp (c->object, object) != 0)
252	{
253	    fprintf (stderr, "Fontconfig error: Unexpected constant name `%s' used for object `%s': should be `%s'\n", string, object, c->object);
254	    return FcFalse;
255	}
256	*result = c->value;
257	return FcTrue;
258    }
259    return FcFalse;
260}
261
262FcBool
263FcNameBool (const 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 == 'd' || c0 == 'x' || c0 == '2')
280    {
281	*result = FcDontCare;
282	return FcTrue;
283    }
284    if (c0 == 'o')
285    {
286	c1 = v[1];
287	c1 = FcToLower (c1);
288	if (c1 == 'n')
289	{
290	    *result = FcTrue;
291	    return FcTrue;
292	}
293	if (c1 == 'f')
294	{
295	    *result = FcFalse;
296	    return FcTrue;
297	}
298	if (c1 == 'r')
299	{
300	    *result = FcDontCare;
301	    return FcTrue;
302	}
303    }
304    return FcFalse;
305}
306
307static FcValue
308FcNameConvert (FcType type, const char *object, FcChar8 *string)
309{
310    FcValue	v;
311    FcMatrix	m;
312    double	b, e;
313    char	*p;
314
315    v.type = type;
316    switch ((int) v.type) {
317    case FcTypeInteger:
318	if (!FcNameConstantWithObjectCheck (string, object, &v.u.i))
319	    v.u.i = atoi ((char *) string);
320	break;
321    case FcTypeString:
322	v.u.s = FcStrdup (string);
323	if (!v.u.s)
324	    v.type = FcTypeVoid;
325	break;
326    case FcTypeBool:
327	if (!FcNameBool (string, &v.u.b))
328	    v.u.b = FcFalse;
329	break;
330    case FcTypeDouble:
331	v.u.d = strtod ((char *) string, 0);
332	break;
333    case FcTypeMatrix:
334	FcMatrixInit (&m);
335	sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
336	v.u.m = FcMatrixCopy (&m);
337	break;
338    case FcTypeCharSet:
339	v.u.c = FcNameParseCharSet (string);
340	if (!v.u.c)
341	    v.type = FcTypeVoid;
342	break;
343    case FcTypeLangSet:
344	v.u.l = FcNameParseLangSet (string);
345	if (!v.u.l)
346	    v.type = FcTypeVoid;
347	break;
348    case FcTypeRange:
349	if (sscanf ((char *) string, "[%lg %lg]", &b, &e) != 2)
350	{
351	    char *sc, *ec;
352	    size_t len = strlen ((const char *) string);
353	    int si, ei;
354
355	    sc = malloc (len + 1);
356	    ec = malloc (len + 1);
357	    if (sc && ec && sscanf ((char *) string, "[%s %[^]]]", sc, ec) == 2)
358	    {
359		if (FcNameConstantWithObjectCheck ((const FcChar8 *) sc, object, &si) &&
360		    FcNameConstantWithObjectCheck ((const FcChar8 *) ec, object, &ei))
361		    v.u.r =  FcRangeCreateDouble (si, ei);
362		else
363		    goto bail1;
364	    }
365	    else
366	    {
367	    bail1:
368		v.type = FcTypeDouble;
369		if (FcNameConstantWithObjectCheck (string, object, &si))
370		{
371		    v.u.d = (double) si;
372		} else {
373		    v.u.d = strtod ((char *) string, &p);
374		    if (p != NULL && p[0] != 0)
375			v.type = FcTypeVoid;
376		}
377	    }
378	    if (sc)
379		free (sc);
380	    if (ec)
381		free (ec);
382	}
383	else
384	    v.u.r = FcRangeCreateDouble (b, e);
385	break;
386    default:
387	break;
388    }
389    return v;
390}
391
392static const FcChar8 *
393FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
394{
395    FcChar8    c;
396
397    while ((c = *cur))
398    {
399	if (!isspace (c))
400	    break;
401	++cur;
402    }
403    while ((c = *cur))
404    {
405	if (c == '\\')
406	{
407	    ++cur;
408	    if (!(c = *cur))
409		break;
410	}
411	else if (strchr (delim, c))
412	    break;
413	++cur;
414	*save++ = c;
415    }
416    *save = 0;
417    *last = *cur;
418    if (*cur)
419	cur++;
420    return cur;
421}
422
423FcPattern *
424FcNameParse (const FcChar8 *name)
425{
426    FcChar8		*save;
427    FcPattern		*pat;
428    double		d;
429    FcChar8		*e;
430    FcChar8		delim;
431    FcValue		v;
432    const FcObjectType	*t;
433    const FcConstant	*c;
434
435    /* freed below */
436    save = malloc (strlen ((char *) name) + 1);
437    if (!save)
438	goto bail0;
439    pat = FcPatternCreate ();
440    if (!pat)
441	goto bail1;
442
443    for (;;)
444    {
445	name = FcNameFindNext (name, "-,:", save, &delim);
446	if (save[0])
447	{
448	    if (!FcPatternObjectAddString (pat, FC_FAMILY_OBJECT, save))
449		goto bail2;
450	}
451	if (delim != ',')
452	    break;
453    }
454    if (delim == '-')
455    {
456	for (;;)
457	{
458	    name = FcNameFindNext (name, "-,:", save, &delim);
459	    d = strtod ((char *) save, (char **) &e);
460	    if (e != save)
461	    {
462		if (!FcPatternObjectAddDouble (pat, FC_SIZE_OBJECT, d))
463		    goto bail2;
464	    }
465	    if (delim != ',')
466		break;
467	}
468    }
469    while (delim == ':')
470    {
471	name = FcNameFindNext (name, "=_:", save, &delim);
472	if (save[0])
473	{
474	    if (delim == '=' || delim == '_')
475	    {
476		t = FcNameGetObjectType ((char *) save);
477		for (;;)
478		{
479		    name = FcNameFindNext (name, ":,", save, &delim);
480		    if (t)
481		    {
482			v = FcNameConvert (t->type, t->object, save);
483			if (!FcPatternAdd (pat, t->object, v, FcTrue))
484			{
485			    FcValueDestroy (v);
486			    goto bail2;
487			}
488			FcValueDestroy (v);
489		    }
490		    if (delim != ',')
491			break;
492		}
493	    }
494	    else
495	    {
496		if ((c = FcNameGetConstant (save)))
497		{
498		    t = FcNameGetObjectType ((char *) c->object);
499		    if (t == NULL)
500			goto bail2;
501		    switch ((int) t->type) {
502		    case FcTypeInteger:
503		    case FcTypeDouble:
504			if (!FcPatternAddInteger (pat, c->object, c->value))
505			    goto bail2;
506			break;
507		    case FcTypeBool:
508			if (!FcPatternAddBool (pat, c->object, c->value))
509			    goto bail2;
510			break;
511		    case FcTypeRange:
512			if (!FcPatternAddInteger (pat, c->object, c->value))
513			    goto bail2;
514			break;
515		    default:
516			break;
517		    }
518		}
519	    }
520	}
521    }
522
523    free (save);
524    return pat;
525
526bail2:
527    FcPatternDestroy (pat);
528bail1:
529    free (save);
530bail0:
531    return 0;
532}
533static FcBool
534FcNameUnparseString (FcStrBuf	    *buf,
535		     const FcChar8  *string,
536		     const FcChar8  *escape)
537{
538    FcChar8 c;
539    while ((c = *string++))
540    {
541	if (escape && strchr ((char *) escape, (char) c))
542	{
543	    if (!FcStrBufChar (buf, escape[0]))
544		return FcFalse;
545	}
546	if (!FcStrBufChar (buf, c))
547	    return FcFalse;
548    }
549    return FcTrue;
550}
551
552FcBool
553FcNameUnparseValue (FcStrBuf	*buf,
554		    FcValue	*v0,
555		    FcChar8	*escape)
556{
557    FcChar8	temp[1024];
558    FcValue v = FcValueCanonicalize(v0);
559
560    switch (v.type) {
561    case FcTypeUnknown:
562    case FcTypeVoid:
563	return FcTrue;
564    case FcTypeInteger:
565	sprintf ((char *) temp, "%d", v.u.i);
566	return FcNameUnparseString (buf, temp, 0);
567    case FcTypeDouble:
568	sprintf ((char *) temp, "%g", v.u.d);
569	return FcNameUnparseString (buf, temp, 0);
570    case FcTypeString:
571	return FcNameUnparseString (buf, v.u.s, escape);
572    case FcTypeBool:
573	return FcNameUnparseString (buf,
574				    v.u.b == FcTrue  ? (FcChar8 *) "True" :
575				    v.u.b == FcFalse ? (FcChar8 *) "False" :
576				                       (FcChar8 *) "DontCare", 0);
577    case FcTypeMatrix:
578	sprintf ((char *) temp, "%g %g %g %g",
579		 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
580	return FcNameUnparseString (buf, temp, 0);
581    case FcTypeCharSet:
582	return FcNameUnparseCharSet (buf, v.u.c);
583    case FcTypeLangSet:
584	return FcNameUnparseLangSet (buf, v.u.l);
585    case FcTypeFTFace:
586	return FcTrue;
587    case FcTypeRange:
588	sprintf ((char *) temp, "[%g %g]", v.u.r->begin, v.u.r->end);
589	return FcNameUnparseString (buf, temp, 0);
590    }
591    return FcFalse;
592}
593
594FcBool
595FcNameUnparseValueList (FcStrBuf	*buf,
596			FcValueListPtr	v,
597			FcChar8		*escape)
598{
599    while (v)
600    {
601	if (!FcNameUnparseValue (buf, &v->value, escape))
602	    return FcFalse;
603	if ((v = FcValueListNext(v)) != NULL)
604	    if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
605		return FcFalse;
606    }
607    return FcTrue;
608}
609
610#define FC_ESCAPE_FIXED    "\\-:,"
611#define FC_ESCAPE_VARIABLE "\\=_:,"
612
613FcChar8 *
614FcNameUnparse (FcPattern *pat)
615{
616    return FcNameUnparseEscaped (pat, FcTrue);
617}
618
619FcChar8 *
620FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
621{
622    FcStrBuf		    buf, buf2;
623    FcChar8		    buf_static[8192], buf2_static[256];
624    int			    i;
625    FcPatternElt	    *e;
626
627    FcStrBufInit (&buf, buf_static, sizeof (buf_static));
628    FcStrBufInit (&buf2, buf2_static, sizeof (buf2_static));
629    e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
630    if (e)
631    {
632        if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
633	    goto bail0;
634    }
635    e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
636    if (e)
637    {
638	FcChar8 *p;
639
640	if (!FcNameUnparseString (&buf2, (FcChar8 *) "-", 0))
641	    goto bail0;
642	if (!FcNameUnparseValueList (&buf2, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
643	    goto bail0;
644	p = FcStrBufDoneStatic (&buf2);
645	FcStrBufDestroy (&buf2);
646	if (strlen ((const char *)p) > 1)
647	    if (!FcStrBufString (&buf, p))
648		goto bail0;
649    }
650    for (i = 0; i < NUM_OBJECT_TYPES; i++)
651    {
652	FcObject id = i + 1;
653	const FcObjectType	    *o;
654	o = &FcObjects[i];
655	if (!strcmp (o->object, FC_FAMILY) ||
656	    !strcmp (o->object, FC_SIZE))
657	    continue;
658
659	e = FcPatternObjectFindElt (pat, id);
660	if (e)
661	{
662	    if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
663		goto bail0;
664	    if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
665		goto bail0;
666	    if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
667		goto bail0;
668	    if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
669					 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
670		goto bail0;
671	}
672    }
673    return FcStrBufDone (&buf);
674bail0:
675    FcStrBufDestroy (&buf);
676    return 0;
677}
678#define __fcname__
679#include "fcaliastail.h"
680#undef __fcname__
681