]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcname.c
Rework cache files to use offsets for all data structures.
[fontconfig.git] / src / fcname.c
index ad78c3db4cb07d5df22e473edac9ae37db0ea91b..96adc62ee34fb14c104b70649c46a85ed68e13c5 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fcname.c,v 1.7 2002/06/03 08:31:15 keithp Exp $
+ * $RCSId: xc/lib/fontconfig/src/fcname.c,v 1.15 2002/09/26 00:17:28 keithp Exp $
  *
- * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2000 Keith Packard
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include "fcint.h"
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include "fcint.h"
 
+/* Please do not revoke any of these bindings. */
+/* The __DUMMY__ object enables callers to distinguish the error return
+ * of FcObjectToPtrLookup from FC_FAMILY's FcObject, which would
+ * otherwise be 0. */
 static const FcObjectType _FcBaseObjectTypes[] = {
+    { "__DUMMY__",      FcTypeVoid, }, 
     { FC_FAMILY,       FcTypeString, },
+    { FC_FAMILYLANG,   FcTypeString, },
     { FC_STYLE,                FcTypeString, },
+    { FC_STYLELANG,    FcTypeString, },
+    { FC_FULLNAME,     FcTypeString, },
+    { FC_FULLNAMELANG, FcTypeString, },
     { FC_SLANT,                FcTypeInteger, },
     { FC_WEIGHT,       FcTypeInteger, },
+    { FC_WIDTH,                FcTypeInteger, },
     { FC_SIZE,         FcTypeDouble, },
     { FC_ASPECT,       FcTypeDouble, },
     { FC_PIXEL_SIZE,   FcTypeDouble, },
     { FC_SPACING,      FcTypeInteger, },
     { FC_FOUNDRY,      FcTypeString, },
-/*    { FC_CORE,               FcTypeBool, }, */
     { FC_ANTIALIAS,    FcTypeBool, },
-/*    { FC_XLFD,               FcTypeString, }, */
+    { FC_HINT_STYLE,    FcTypeInteger, },
+    { FC_HINTING,      FcTypeBool, },
+    { FC_VERTICAL_LAYOUT,   FcTypeBool, },
+    { FC_AUTOHINT,     FcTypeBool, },
+    { FC_GLOBAL_ADVANCE,    FcTypeBool, },
     { FC_FILE,         FcTypeString, },
     { FC_INDEX,                FcTypeInteger, },
     { FC_RASTERIZER,   FcTypeString, },
     { FC_OUTLINE,      FcTypeBool, },
     { FC_SCALABLE,     FcTypeBool, },
+    { FC_DPI,          FcTypeDouble },
     { FC_RGBA,         FcTypeInteger, },
     { FC_SCALE,                FcTypeDouble, },
-/*    { FC_RENDER,     FcTypeBool, },*/
     { FC_MINSPACE,     FcTypeBool, },
     { FC_CHAR_WIDTH,   FcTypeInteger },
     { FC_CHAR_HEIGHT,  FcTypeInteger },
     { FC_MATRIX,       FcTypeMatrix },
     { FC_CHARSET,      FcTypeCharSet },
-    { FC_LANG,         FcTypeString },
+    { FC_LANG,         FcTypeLangSet },
+    { FC_FONTVERSION,  FcTypeInteger },
+    { FC_CAPABILITY,   FcTypeString },
+    { FC_FONTFORMAT,   FcTypeString },
+    { FC_EMBOLDEN,     FcTypeBool },
+    { FC_EMBEDDED_BITMAP,   FcTypeBool },
 };
 
 #define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
 
+static FcObjectType * _FcUserObjectNames = 0;
+static int user_obj_alloc = 0;
+static int next_basic_offset = NUM_OBJECT_TYPES;
+
 typedef struct _FcObjectTypeList    FcObjectTypeList;
 
 struct _FcObjectTypeList {
     const FcObjectTypeList  *next;
     const FcObjectType     *types;
     int                            ntypes;
+    int                            basic_offset;
 };
 
 static const FcObjectTypeList _FcBaseObjectTypesList = {
     0,
     _FcBaseObjectTypes,
-    NUM_OBJECT_TYPES
+    NUM_OBJECT_TYPES,
+    0
 };
 
 static const FcObjectTypeList  *_FcObjectTypes = &_FcBaseObjectTypesList;
@@ -83,15 +107,19 @@ FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
     l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
     if (!l)
        return FcFalse;
+    FcMemAlloc (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
     l->types = types;
     l->ntypes = ntypes;
     l->next = _FcObjectTypes;
+    l->basic_offset = next_basic_offset;
+    next_basic_offset += ntypes;
     _FcObjectTypes = l;
     return FcTrue;
 }
 
-FcBool
-FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
+static FcBool
+FcNameUnregisterObjectTypesFree (const FcObjectType *types, int ntypes, 
+                                FcBool do_free)
 {
     const FcObjectTypeList     *l, **prev;
 
@@ -102,13 +130,22 @@ FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
        if (l->types == types && l->ntypes == ntypes)
        {
            *prev = l->next;
-           free ((void *) l);
+           if (do_free) {
+               FcMemFree (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
+               free ((void *) l);
+           }
            return FcTrue;
        }
     }
     return FcFalse;
 }
 
+FcBool
+FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
+{
+    return FcNameUnregisterObjectTypesFree (types, ntypes, FcTrue);
+}
+
 const FcObjectType *
 FcNameGetObjectType (const char *object)
 {
@@ -118,6 +155,9 @@ FcNameGetObjectType (const char *object)
     
     for (l = _FcObjectTypes; l; l = l->next)
     {
+        if (l == (FcObjectTypeList*)_FcUserObjectNames)
+            continue;
+
        for (i = 0; i < l->ntypes; i++)
        {
            t = &l->types[i];
@@ -128,26 +168,204 @@ FcNameGetObjectType (const char *object)
     return 0;
 }
 
+#define OBJECT_HASH_SIZE    31
+struct objectBucket {
+    struct objectBucket        *next;
+    FcChar32           hash;
+    int                        id;
+};
+static struct objectBucket *FcObjectBuckets[OBJECT_HASH_SIZE];
+
+/* Design constraint: biggest_known_ntypes must never change
+ * after any call to FcNameRegisterObjectTypes. */
+static const FcObjectType *biggest_known_types = _FcBaseObjectTypes; 
+static int biggest_known_ntypes = NUM_OBJECT_TYPES;
+
+
+static FcObject
+FcObjectToPtrLookup (const char * object)
+{
+    FcObject               i = 0, n;
+    const FcObjectTypeList  *l;
+    FcObjectType           *t = _FcUserObjectNames;
+    FcBool                 replace;
+
+    for (l = _FcObjectTypes; l; l = l->next)
+    {
+       for (i = 0; i < l->ntypes; i++)
+       {
+           t = (FcObjectType *)&l->types[i];
+           if (!strcmp (object, t->object))
+           {
+               if (l->types == _FcUserObjectNames)
+                    return -i;
+               else
+                   return l->basic_offset + i;
+           }
+       }
+    }
+
+    /* We didn't match.  Look for the application's FcObjectTypeList
+     * and replace it in-place. */
+    for (l = _FcObjectTypes; l; l = l->next)
+    {
+       if (l->types == _FcUserObjectNames)
+           break;
+    }
+
+    replace = l && l->types == _FcUserObjectNames;
+    if (!_FcUserObjectNames || 
+        (replace && user_obj_alloc <= l->ntypes))
+    {
+       int nt = user_obj_alloc + 4;
+        FcObjectType * tt = realloc (_FcUserObjectNames, 
+                                   nt * sizeof (FcObjectType));
+        if (!tt)
+            return 0;
+       _FcUserObjectNames = tt;
+       user_obj_alloc = nt;
+    }
+
+    if (replace)
+    {
+       n = l->ntypes;
+       FcNameUnregisterObjectTypesFree (l->types, l->ntypes, FcFalse);
+    }
+    else
+       n = 0;
+
+    FcNameRegisterObjectTypes (_FcUserObjectNames, n+1);
+
+    if (!_FcUserObjectNames)
+       return 0;
+
+    _FcUserObjectNames[n].object = object;
+    _FcUserObjectNames[n].type = FcTypeVoid;
+
+    return -n;
+}
+
+FcBool
+FcObjectValidType (FcObject object, FcType type)
+{
+    if (object < NUM_OBJECT_TYPES && _FcBaseObjectTypes[object].type != type)
+       return FcFalse;
+    return FcTrue;
+}
+
+FcObject
+FcObjectFromName (const char * name)
+{
+    FcChar32            hash = FcStringHash ((const FcChar8 *) name);
+    struct objectBucket **p;
+    struct objectBucket *b;
+    int                 size;
+
+    for (p = &FcObjectBuckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)
+)
+        if (b->hash == hash && !strcmp (name, (char *) (b + 1)))
+            return b->id;
+    size = sizeof (struct objectBucket) + strlen (name) + 1;
+    /* workaround glibc bug which reads strlen in groups of 4 */
+    b = malloc (size + sizeof (int));
+    FcMemAlloc (FC_MEM_STATICSTR, size + sizeof(int));
+    if (!b)
+        return 0;
+    b->next = 0;
+    b->hash = hash;
+    b->id = FcObjectToPtrLookup (name);
+    strcpy ((char *) (b + 1), name);
+    *p = b;
+    return b->id;
+}
+
+void
+FcObjectStaticNameFini (void)
+{
+    int i, size;
+    struct objectBucket *b, *next;
+    char *name;
+
+    for (i = 0; i < OBJECT_HASH_SIZE; i++)
+    {
+       for (b = FcObjectBuckets[i]; b; b = next)
+       {
+           next = b->next;
+           name = (char *) (b + 1);
+           size = sizeof (struct objectBucket) + strlen (name) + 1;
+           FcMemFree (FC_MEM_STATICSTR, size);
+           free (b);
+       }
+       FcObjectBuckets[i] = 0;
+    }
+}
+
+const char *
+FcObjectName (FcObject object)
+{
+    const FcObjectTypeList  *l;
+    int i, j;
+
+    if (object > 0)
+    {
+        if (object < biggest_known_ntypes)
+            return biggest_known_types[object].object;
+
+        j = 0;
+        for (l = _FcObjectTypes; l; l = l->next)
+            for (i = 0; i < l->ntypes; i++, j++)
+                if (j == object)
+                    return l->types[i].object;
+    }
+
+    return _FcUserObjectNames[-object].object;
+}
+
 static const FcConstant _FcBaseConstants[] = {
+    { (FcChar8 *) "thin",          "weight",   FC_WEIGHT_THIN, },
+    { (FcChar8 *) "extralight",            "weight",   FC_WEIGHT_EXTRALIGHT, },
+    { (FcChar8 *) "ultralight",            "weight",   FC_WEIGHT_EXTRALIGHT, },
     { (FcChar8 *) "light",         "weight",   FC_WEIGHT_LIGHT, },
+    { (FcChar8 *) "book",          "weight",   FC_WEIGHT_BOOK, },
+    { (FcChar8 *) "regular",       "weight",   FC_WEIGHT_REGULAR, },
     { (FcChar8 *) "medium",        "weight",   FC_WEIGHT_MEDIUM, },
     { (FcChar8 *) "demibold",      "weight",   FC_WEIGHT_DEMIBOLD, },
+    { (FcChar8 *) "semibold",      "weight",   FC_WEIGHT_DEMIBOLD, },
     { (FcChar8 *) "bold",          "weight",   FC_WEIGHT_BOLD, },
+    { (FcChar8 *) "extrabold",     "weight",   FC_WEIGHT_EXTRABOLD, },
+    { (FcChar8 *) "ultrabold",     "weight",   FC_WEIGHT_EXTRABOLD, },
     { (FcChar8 *) "black",         "weight",   FC_WEIGHT_BLACK, },
 
     { (FcChar8 *) "roman",         "slant",    FC_SLANT_ROMAN, },
     { (FcChar8 *) "italic",        "slant",    FC_SLANT_ITALIC, },
     { (FcChar8 *) "oblique",       "slant",    FC_SLANT_OBLIQUE, },
 
+    { (FcChar8 *) "ultracondensed", "width",   FC_WIDTH_ULTRACONDENSED },
+    { (FcChar8 *) "extracondensed", "width",   FC_WIDTH_EXTRACONDENSED },
+    { (FcChar8 *) "condensed",     "width",    FC_WIDTH_CONDENSED },
+    { (FcChar8 *) "semicondensed", "width",    FC_WIDTH_SEMICONDENSED },
+    { (FcChar8 *) "normal",        "width",    FC_WIDTH_NORMAL },
+    { (FcChar8 *) "semiexpanded",   "width",   FC_WIDTH_SEMIEXPANDED },
+    { (FcChar8 *) "expanded",      "width",    FC_WIDTH_EXPANDED },
+    { (FcChar8 *) "extraexpanded",  "width",   FC_WIDTH_EXTRAEXPANDED },
+    { (FcChar8 *) "ultraexpanded",  "width",   FC_WIDTH_ULTRAEXPANDED },
+    
     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
+    { (FcChar8 *) "dual",          "spacing",  FC_DUAL, },
     { (FcChar8 *) "mono",          "spacing",  FC_MONO, },
     { (FcChar8 *) "charcell",      "spacing",  FC_CHARCELL, },
 
-    { (FcChar8 *) "none",          "rgba",         FC_RGBA_NONE },
+    { (FcChar8 *) "unknown",       "rgba",         FC_RGBA_UNKNOWN },
     { (FcChar8 *) "rgb",           "rgba",         FC_RGBA_RGB, },
     { (FcChar8 *) "bgr",           "rgba",         FC_RGBA_BGR, },
     { (FcChar8 *) "vrgb",          "rgba",         FC_RGBA_VRGB },
     { (FcChar8 *) "vbgr",          "rgba",         FC_RGBA_VBGR },
+    { (FcChar8 *) "none",          "rgba",         FC_RGBA_NONE },
+
+    { (FcChar8 *) "hintnone",      "hintstyle",   FC_HINT_NONE },
+    { (FcChar8 *) "hintslight",            "hintstyle",   FC_HINT_SLIGHT },
+    { (FcChar8 *) "hintmedium",            "hintstyle",   FC_HINT_MEDIUM },
+    { (FcChar8 *) "hintfull",      "hintstyle",   FC_HINT_FULL },
 };
 
 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
@@ -176,6 +394,7 @@ FcNameRegisterConstants (const FcConstant *consts, int nconsts)
     l = (FcConstantList *) malloc (sizeof (FcConstantList));
     if (!l)
        return FcFalse;
+    FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
     l->consts = consts;
     l->nconsts = nconsts;
     l->next = _FcConstants;
@@ -195,6 +414,7 @@ FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
        if (l->consts == consts && l->nconsts == nconsts)
        {
            *prev = l->next;
+           FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
            free ((void *) l);
            return FcTrue;
        }
@@ -207,7 +427,7 @@ FcNameGetConstant (FcChar8 *string)
 {
     const FcConstantList    *l;
     int                            i;
-    
+
     for (l = _FcConstants; l; l = l->next)
     {
        for (i = 0; i < l->nconsts; i++)
@@ -231,13 +451,12 @@ FcNameConstant (FcChar8 *string, int *result)
 }
 
 FcBool
-FcNameBool (FcChar8 *v, FcBool *result)
+FcNameBool (const FcChar8 *v, FcBool *result)
 {
     char    c0, c1;
 
     c0 = *v;
-    if (isupper (c0))
-       c0 = tolower (c0);
+    c0 = FcToLower (c0);
     if (c0 == 't' || c0 == 'y' || c0 == '1')
     {
        *result = FcTrue;
@@ -251,8 +470,7 @@ FcNameBool (FcChar8 *v, FcBool *result)
     if (c0 == 'o')
     {
        c1 = v[1];
-       if (isupper (c1))
-           c1 = tolower (c1);
+       c1 = FcToLower (c1);
        if (c1 == 'n')
        {
            *result = FcTrue;
@@ -279,7 +497,7 @@ FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
            v.u.i = atoi ((char *) string);
        break;
     case FcTypeString:
-       v.u.s = string;
+       v.u.s = FcStrStaticName(string);
        break;
     case FcTypeBool:
        if (!FcNameBool (string, &v.u.b))
@@ -295,6 +513,9 @@ FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
     case FcTypeCharSet:
        v.u.c = FcNameParseCharSet (string);
        break;
+    case FcTypeLangSet:
+       v.u.l = FcNameParseLangSet (string);
+       break;
     default:
        break;
     }
@@ -339,6 +560,7 @@ FcNameParse (const FcChar8 *name)
     const FcObjectType *t;
     const FcConstant   *c;
 
+    /* freed below */
     save = malloc (strlen ((char *) name) + 1);
     if (!save)
        goto bail0;
@@ -383,17 +605,33 @@ FcNameParse (const FcChar8 *name)
                for (;;)
                {
                    name = FcNameFindNext (name, ":,", save, &delim);
-                   if (save[0] && t)
+                   if (t && strcmp (t->object, _FcBaseObjectTypes[0].object))
                    {
                        v = FcNameConvert (t->type, save, &m);
                        if (!FcPatternAdd (pat, t->object, v, FcTrue))
                        {
-                           if (v.type == FcTypeCharSet)
+                           switch (v.type) {
+                           case FcTypeCharSet:
                                FcCharSetDestroy ((FcCharSet *) v.u.c);
+                               break;
+                           case FcTypeLangSet:
+                               FcLangSetDestroy ((FcLangSet *) v.u.l);
+                               break;
+                           default:
+                               break;
+                           }
                            goto bail2;
                        }
-                       if (v.type == FcTypeCharSet)
+                       switch (v.type) {
+                       case FcTypeCharSet:
                            FcCharSetDestroy ((FcCharSet *) v.u.c);
+                           break;
+                       case FcTypeLangSet:
+                           FcLangSetDestroy ((FcLangSet *) v.u.l);
+                           break;
+                       default:
+                           break;
+                       }
                    }
                    if (delim != ',')
                        break;
@@ -441,10 +679,11 @@ FcNameUnparseString (FcStrBuf         *buf,
 
 static FcBool
 FcNameUnparseValue (FcStrBuf   *buf,
-                   FcValue     v,
+                   FcValue     *v0,
                    FcChar8     *escape)
 {
     FcChar8    temp[1024];
+    FcValue v = FcValueCanonicalize(v0);
     
     switch (v.type) {
     case FcTypeVoid:
@@ -465,6 +704,8 @@ FcNameUnparseValue (FcStrBuf        *buf,
        return FcNameUnparseString (buf, temp, 0);
     case FcTypeCharSet:
        return FcNameUnparseCharSet (buf, v.u.c);
+    case FcTypeLangSet:
+       return FcNameUnparseLangSet (buf, v.u.l);
     case FcTypeFTFace:
        return FcTrue;
     }
@@ -473,14 +714,14 @@ FcNameUnparseValue (FcStrBuf      *buf,
 
 static FcBool
 FcNameUnparseValueList (FcStrBuf       *buf,
-                       FcValueList     *v,
+                       FcValueListPtr  v,
                        FcChar8         *escape)
 {
     while (v)
     {
-       if (!FcNameUnparseValue (buf, v->value, escape))
+       if (!FcNameUnparseValue (buf, &v->value, escape))
            return FcFalse;
-       if ((v = v->next))
+       if ((v = FcValueListNext(v)) != NULL)
            if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
                return FcFalse;
     }
@@ -492,6 +733,12 @@ FcNameUnparseValueList (FcStrBuf   *buf,
 
 FcChar8 *
 FcNameUnparse (FcPattern *pat)
+{
+    return FcNameUnparseEscaped (pat, FcTrue);
+}
+
+FcChar8 *
+FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
 {
     FcStrBuf               buf;
     FcChar8                buf_static[8192];
@@ -501,18 +748,18 @@ FcNameUnparse (FcPattern *pat)
     const FcObjectType     *o;
 
     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
-    e = FcPatternFindElt (pat, FC_FAMILY);
+    e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
     if (e)
     {
-       if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
+        if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
            goto bail0;
     }
-    e = FcPatternFindElt (pat, FC_SIZE);
+    e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
     if (e)
     {
        if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
            goto bail0;
-       if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
+       if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
            goto bail0;
     }
     for (l = _FcObjectTypes; l; l = l->next)
@@ -525,17 +772,17 @@ FcNameUnparse (FcPattern *pat)
                !strcmp (o->object, FC_FILE))
                continue;
            
-           e = FcPatternFindElt (pat, o->object);
+           e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object));
            if (e)
            {
                if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
                    goto bail0;
-               if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, (FcChar8 *) FC_ESCAPE_VARIABLE))
+               if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
                    goto bail0;
                if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
                    goto bail0;
-               if (!FcNameUnparseValueList (&buf, e->values, 
-                                            (FcChar8 *) FC_ESCAPE_VARIABLE))
+               if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? 
+                                            (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
                    goto bail0;
            }
        }