]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcfreetype.c
Add instructions for doing a release
[fontconfig.git] / src / fcfreetype.c
index dcbcc56f2cc432902091fb185b54d514bb36e021..816f08ab190f1ca8c5d84fc919ec6ede8a9951f1 100644 (file)
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
+/*
+  Copyright © 2002-2003 by Juliusz Chroboczek
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include "fcint.h"
-#include <freetype/freetype.h>
-#include <freetype/internal/ftobjs.h>
-#include <freetype/tttables.h>
-#include <freetype/ftsnames.h>
-#include <freetype/ttnameid.h>
-#include <freetype/t1tables.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TYPE1_TABLES_H
+
+#if HAVE_FT_GET_BDF_PROPERTY
+#include FT_BDF_H
+#include FT_MODULE_H
+#define HAS_BDF_PROPERTY(f) ((f) && (f)->driver && \
+                            (f)->driver->root.clazz->get_interface)
+#define MY_Get_BDF_Property(f,n,p) (HAS_BDF_PROPERTY(f) ? \
+                                   FT_Get_BDF_Property(f,n,p) : \
+                                   FT_Err_Invalid_Argument)
+#endif
+
+#if !HAVE_FT_GET_BDF_PROPERTY
+#warning "No FT_Get_BDF_Property"
+#endif
+
+#if !HAVE_FT_GET_PS_FONT_INFO
+#warning "No FT_Get_Font_Info"
+#endif
 
 /*
  * Keep Han languages separated by eliminating languages
@@ -90,7 +131,8 @@ FcUcs4IsLatin (FcChar32 ucs4)
        return FcTrue;
     if (page == 0xfb)
        return FcTrue;
-    if (page == 0xff)
+    /* halfwidth forms, don't include kana or white parens */
+    if (0xff01 <= ucs4 && ucs4 <= 0xff5e)
        return FcTrue;
     return FcFalse;
 }
@@ -112,6 +154,220 @@ FcUtf8IsLatin (FcChar8 *str, int len)
     return FcTrue;
 }
 
+/* Order is significant.  For example, some B&H fonts are hinted by
+   URW++, and both strings appear in the notice. */
+
+static const struct {
+    const FT_String *notice;
+    const FcChar8   *foundry;
+} FcNoticeFoundries[] = {
+    { (const FT_String *) "Bigelow",   (const FcChar8 *) "b&h" },
+    { (const FT_String *) "Adobe",     (const FcChar8 *) "adobe" },
+    { (const FT_String *) "Bitstream", (const FcChar8 *) "bitstream" },
+    { (const FT_String *) "Monotype",  (const FcChar8 *) "monotype" },
+    { (const FT_String *) "Linotype",  (const FcChar8 *) "linotype" },
+    { (const FT_String *) "LINOTYPE-HELL",
+                                       (const FcChar8 *) "linotype" },
+    { (const FT_String *) "IBM",       (const FcChar8 *) "ibm" },
+    { (const FT_String *) "URW",       (const FcChar8 *) "urw" },
+    { (const FT_String *) "International Typeface Corporation", 
+                                       (const FcChar8 *) "itc" },
+    { (const FT_String *) "Tiro Typeworks",
+                                       (const FcChar8 *) "tiro" },
+    { (const FT_String *) "XFree86",   (const FcChar8 *) "xfree86" },
+    { (const FT_String *) "Microsoft", (const FcChar8 *) "microsoft" },
+    { (const FT_String *) "Omega",     (const FcChar8 *) "omega" },
+    { (const FT_String *) "Font21",    (const FcChar8 *) "hwan" },
+    { (const FT_String *) "HanYang System",
+                                       (const FcChar8 *) "hanyang" }
+};
+
+#define NUM_NOTICE_FOUNDRIES   (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
+
+static const FcChar8 *
+FcNoticeFoundry(const FT_String *notice)
+{
+    int i;
+
+    if (notice)
+       for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
+           if (strstr ((const char *) notice, (const char *) FcNoticeFoundries[i].notice))
+               return FcNoticeFoundries[i].foundry;
+    return 0;
+}
+
+static FcBool
+FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
+{
+    /* vendor is not necessarily NUL-terminated. */
+    int i, len;
+    
+    len = strlen(vendor_string);
+    if (memcmp(vendor, vendor_string, len) != 0)
+        return FcFalse;
+    for (i = len; i < 4; i++)
+        if (vendor[i] != ' ' && vendor[i] != '\0')
+            return FcFalse;
+    return FcTrue;
+}
+
+/* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
+
+/* It should not contain useless entries (such as UNKN) nor duplicate
+   entries for padding both with spaces and NULs. */
+
+static const struct {
+    const FT_Char   *vendor;
+    const FcChar8   *foundry;
+} FcVendorFoundries[] = {
+    { (const FT_Char *) "ADBE", (const FcChar8 *) "adobe"},
+    { (const FT_Char *) "AGFA", (const FcChar8 *) "agfa"},
+    { (const FT_Char *) "ALTS", (const FcChar8 *) "altsys"},
+    { (const FT_Char *) "APPL", (const FcChar8 *) "apple"},
+    { (const FT_Char *) "ARPH", (const FcChar8 *) "arphic"},
+    { (const FT_Char *) "ATEC", (const FcChar8 *) "alltype"},
+    { (const FT_Char *) "B&H",  (const FcChar8 *) "b&h"},
+    { (const FT_Char *) "BITS", (const FcChar8 *) "bitstream"},
+    { (const FT_Char *) "CANO", (const FcChar8 *) "cannon"},
+    { (const FT_Char *) "DYNA", (const FcChar8 *) "dynalab"},
+    { (const FT_Char *) "EPSN", (const FcChar8 *) "epson"},
+    { (const FT_Char *) "FJ",   (const FcChar8 *) "fujitsu"},
+    { (const FT_Char *) "IBM",  (const FcChar8 *) "ibm"},
+    { (const FT_Char *) "ITC",  (const FcChar8 *) "itc"},
+    { (const FT_Char *) "IMPR", (const FcChar8 *) "impress"},
+    { (const FT_Char *) "LARA", (const FcChar8 *) "larabiefonts"},
+    { (const FT_Char *) "LEAF", (const FcChar8 *) "interleaf"},
+    { (const FT_Char *) "LETR", (const FcChar8 *) "letraset"},
+    { (const FT_Char *) "LINO", (const FcChar8 *) "linotype"},
+    { (const FT_Char *) "MACR", (const FcChar8 *) "macromedia"},
+    { (const FT_Char *) "MONO", (const FcChar8 *) "monotype"},
+    { (const FT_Char *) "MS",   (const FcChar8 *) "microsoft"},
+    { (const FT_Char *) "MT",   (const FcChar8 *) "monotype"},
+    { (const FT_Char *) "NEC",  (const FcChar8 *) "nec"},
+    { (const FT_Char *) "PARA", (const FcChar8 *) "paratype"},
+    { (const FT_Char *) "QMSI", (const FcChar8 *) "qms"},
+    { (const FT_Char *) "RICO", (const FcChar8 *) "ricoh"},
+    { (const FT_Char *) "URW",  (const FcChar8 *) "urw"},
+    { (const FT_Char *) "Y&Y",  (const FcChar8 *) "y&y"}
+};
+
+#define NUM_VENDOR_FOUNDRIES   (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
+
+static const FcChar8 *
+FcVendorFoundry(const FT_Char vendor[4])
+{
+    int i;
+    
+    if (vendor)
+       for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
+           if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
+               return FcVendorFoundries[i].foundry;
+    return 0;
+}
+
+typedef struct _FcStringConst {
+    const FcChar8   *name;
+    int                    value;
+} FcStringConst;
+
+static int
+FcStringIsConst (const FcChar8         *string,
+                const FcStringConst    *c,
+                int                    nc)
+{
+    int        i;
+
+    for (i = 0; i < nc; i++)
+       if (FcStrCmpIgnoreBlanksAndCase (string, c[i].name) == 0)
+           return c[i].value;
+    return -1;
+}
+
+static int
+FcStringContainsConst (const FcChar8       *string,
+                      const FcStringConst  *c,
+                      int                  nc)
+{
+    int        i;
+
+    for (i = 0; i < nc; i++)
+       if (FcStrContainsIgnoreBlanksAndCase (string, c[i].name))
+           return c[i].value;
+    return -1;
+}
+
+static const FcStringConst  weightConsts[] = {
+    { "thin",          FC_WEIGHT_THIN },
+    { "extralight",    FC_WEIGHT_EXTRALIGHT },
+    { "ultralight",    FC_WEIGHT_ULTRALIGHT },
+    { "light",         FC_WEIGHT_LIGHT },
+    { "book",          FC_WEIGHT_BOOK },
+    { "regular",       FC_WEIGHT_REGULAR },
+    { "normal",                FC_WEIGHT_NORMAL },
+    { "medium",                FC_WEIGHT_MEDIUM },
+    { "demibold",      FC_WEIGHT_DEMIBOLD },
+    { "demi",          FC_WEIGHT_DEMIBOLD },
+    { "semibold",      FC_WEIGHT_SEMIBOLD },
+    { "bold",          FC_WEIGHT_BOLD },
+    { "extrabold",     FC_WEIGHT_EXTRABOLD },
+    { "ultrabold",     FC_WEIGHT_ULTRABOLD },
+    { "black",         FC_WEIGHT_BLACK },
+    { "heavy",         FC_WEIGHT_HEAVY },
+};
+
+#define NUM_WEIGHT_CONSTS  (sizeof (weightConsts) / sizeof (weightConsts[0]))
+
+#define FcIsWeight(s)      FcStringIsConst(s,weightConsts,NUM_WEIGHT_CONSTS)
+#define FcContainsWeight(s) FcStringContainsConst (s,weightConsts,NUM_WEIGHT_CONSTS)
+
+static const FcStringConst  widthConsts[] = {
+    { "ultracondensed",        FC_WIDTH_ULTRACONDENSED },
+    { "extracondensed",        FC_WIDTH_EXTRACONDENSED },
+    { "semicondensed",  FC_WIDTH_SEMICONDENSED },
+    { "condensed",     FC_WIDTH_CONDENSED },   /* must be after *condensed */
+    { "normal",                FC_WIDTH_NORMAL },
+    { "semiexpanded",  FC_WIDTH_SEMIEXPANDED },
+    { "extraexpanded", FC_WIDTH_EXTRAEXPANDED },
+    { "ultraexpanded", FC_WIDTH_ULTRAEXPANDED },
+    { "expanded",      FC_WIDTH_EXPANDED },    /* must be after *expanded */
+};
+
+#define NUM_WIDTH_CONSTS    (sizeof (widthConsts) / sizeof (widthConsts[0]))
+
+#define FcIsWidth(s)       FcStringIsConst(s,widthConsts,NUM_WIDTH_CONSTS)
+#define FcContainsWidth(s)  FcStringContainsConst (s,widthConsts,NUM_WIDTH_CONSTS)
+
+static const FcStringConst  slantConsts[] = {
+    { "italic",                FC_SLANT_ITALIC },
+    { "oblique",       FC_SLANT_OBLIQUE },
+};
+
+#define NUM_SLANT_CONSTS    (sizeof (slantConsts) / sizeof (slantConsts[0]))
+
+#define FcIsSlant(s)       FcStringIsConst(s,slantConsts,NUM_SLANT_CONSTS)
+#define FcContainsSlant(s)  FcStringContainsConst (s,slantConsts,NUM_SLANT_CONSTS)
+
+static double
+FcGetPixelSize (FT_Face face, int i)
+{
+#if HAVE_FT_GET_BDF_PROPERTY
+    if (face->num_fixed_sizes == 1)
+    {
+       BDF_PropertyRec prop;
+       int             rc;
+
+       rc = MY_Get_BDF_Property (face, "PIXEL_SIZE", &prop);
+       if (rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
+           return (double) prop.u.integer;
+    }
+#endif
+#if HAVE_FT_BITMAP_SIZE_Y_PPEM
+    return (double) face->available_sizes[i].y_ppem / 64.0;
+#else
+    return (double) face->available_sizes[i].height;
+#endif
+}
+
 FcPattern *
 FcFreeTypeQuery (const FcChar8 *file,
                 int            id,
@@ -120,18 +376,24 @@ FcFreeTypeQuery (const FcChar8    *file,
 {
     FT_Face        face;
     FcPattern      *pat;
-    int                    slant;
-    int                    weight;
+    int                    slant = -1;
+    int                    weight = -1;
     int                    width = -1;
     int                    i;
     FcCharSet      *cs;
     FcLangSet      *ls;
     FT_Library     ftLibrary;
-    FcChar8        *family;
-    FcChar8        *style;
+    FcChar8        *family = 0;
+    FcChar8        *style = 0;
+    const FcChar8   *foundry = 0;
     int                    spacing;
     TT_OS2         *os2;
+#if HAVE_FT_GET_PS_FONT_INFO
     PS_FontInfoRec  psfontinfo;
+#endif
+#if HAVE_FT_GET_BDF_PROPERTY
+    BDF_PropertyRec prop;
+#endif
     TT_Header      *head;
     const FcChar8   *exclusiveLang = 0;
     FT_SfntName            sname;
@@ -162,22 +424,27 @@ FcFreeTypeQuery (const FcChar8    *file,
        goto bail1;
 
 
-    slant = FC_SLANT_ROMAN;
-    if (face->style_flags & FT_STYLE_FLAG_ITALIC)
-       slant = FC_SLANT_ITALIC;
-
+    /*
+     * Get the OS/2 table
+     */
+    os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
 
-    weight = FC_WEIGHT_MEDIUM;
-    if (face->style_flags & FT_STYLE_FLAG_BOLD)
-       weight = FC_WEIGHT_BOLD;
+    /*
+     * Look first in the OS/2 table for the foundry, if
+     * not found here, the various notices will be searched for
+     * that information, either from the sfnt name tables or
+     * the Postscript FontInfo dictionary.  Finally, the
+     * BDF properties will queried.
+     */
+    
+    if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
+        foundry = FcVendorFoundry(os2->achVendID);
 
     /*
      * Grub through the name table looking for family
      * and style names.  FreeType makes quite a hash
      * of them
      */
-    family = 0;
-    style = 0;
     snamec = FT_Get_Sfnt_Name_Count (face);
     for (snamei = 0; snamei < snamec; snamei++)
     {
@@ -287,7 +554,9 @@ FcFreeTypeQuery (const FcChar8      *file,
            prio |= FC_NAME_PRIO_NAME_PS;
            break;
        case TT_NAME_ID_FONT_SUBFAMILY:
-           break;
+        case TT_NAME_ID_TRADEMARK:
+        case TT_NAME_ID_MANUFACTURER:
+            break;
        default:
            continue;
        }
@@ -400,6 +669,12 @@ FcFreeTypeQuery (const FcChar8     *file,
                style_prio = prio;
            }
            break;
+        case TT_NAME_ID_TRADEMARK:
+        case TT_NAME_ID_MANUFACTURER:
+           /* If the foundry wasn't found in the OS/2 table, look here */
+            if(!foundry)
+                foundry = FcNoticeFoundry((FT_String *) utf8);
+            break;
        }
        if (utf8)
            free (utf8);
@@ -431,30 +706,15 @@ FcFreeTypeQuery (const FcChar8    *file,
     }
 
     if (FcDebug() & FC_DBG_SCAN)
-       printf ("\"%s\" \"%s\" ", family, style ? style : (FcChar8 *) "<none>");
+       printf ("\n\"%s\" \"%s\"\n", family, style ? style : (FcChar8 *) "<none>");
 
     if (!FcPatternAddString (pat, FC_FAMILY, family))
-    {
-       if (family_allocated)
-           free (family);
-       if (style_allocated)
-           free (style);
        goto bail1;
-    }
-
-    if (family_allocated)
-       free (family);
 
     if (style)
     {
        if (!FcPatternAddString (pat, FC_STYLE, style))
-       {
-           if (style_allocated)
-               free (style);
            goto bail1;
-       }
-       if (style_allocated)
-           free (style);
     }
 
     if (!FcPatternAddString (pat, FC_FILE, file))
@@ -492,10 +752,6 @@ FcFreeTypeQuery (const FcChar8     *file,
            goto bail1;
     }
 
-    /*
-     * Get the OS/2 table and poke about
-     */
-    os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
     {
        for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
@@ -532,7 +788,7 @@ FcFreeTypeQuery (const FcChar8      *file,
     if (os2 && os2->version != 0xffff)
     {
        if (os2->usWeightClass == 0)
-           weight = -1;
+           ;
        else if (os2->usWeightClass < 150)
            weight = FC_WEIGHT_THIN;
        else if (os2->usWeightClass < 250)
@@ -551,8 +807,6 @@ FcFreeTypeQuery (const FcChar8      *file,
            weight = FC_WEIGHT_EXTRABOLD;
        else if (os2->usWeightClass < 950)
            weight = FC_WEIGHT_BLACK;
-       else
-           weight = FC_WEIGHT_MEDIUM;
 
        switch (os2->usWidthClass) {
        case 1: width = FC_WIDTH_ULTRACONDENSED; break;
@@ -572,52 +826,142 @@ FcFreeTypeQuery (const FcChar8   *file,
      * Code from g2@magestudios.net (Gerard Escalante)
      */
     
+#if HAVE_FT_GET_PS_FONT_INFO
     if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
     {
-        if (FcStrCmpIgnoreCase((FcChar8 *)"thin", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_THIN; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"extralight", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_EXTRALIGHT; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"ultralight", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_ULTRALIGHT; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"light", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_LIGHT; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"regular", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_REGULAR; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"normal", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_NORMAL; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"medium", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_MEDIUM; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"demibold", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_DEMIBOLD; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"semibold", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_SEMIBOLD; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"extrabold", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_EXTRABOLD; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"ultrabold", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_EXTRABOLD; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"bold", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_BOLD; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"black", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_BLACK; 
-        else if (FcStrCmpIgnoreCase((FcChar8 *)"heavy", (FcChar8 *) psfontinfo.weight) == 0) 
-            weight = FC_WEIGHT_BLACK; 
+       if (weight == -1 && psfontinfo.weight)
+       {
+           weight = FcIsWeight (psfontinfo.weight);
+           if (FcDebug() & FC_DBG_SCANV)
+               printf ("\tType1 weight %s maps to %d\n",
+                       psfontinfo.weight, weight);
+       }
      
-        if (psfontinfo.italic_angle < 0) 
+#if 0
+       /* 
+        * Don't bother with italic_angle; FreeType already extracts that
+        * information for us and sticks it into style_flags
+        */
+        if (psfontinfo.italic_angle)
             slant = FC_SLANT_ITALIC; 
-        else if (psfontinfo.italic_angle >= 0) 
+        else
             slant = FC_SLANT_ROMAN; 
+#endif
+
+        if(!foundry)
+            foundry = FcNoticeFoundry(psfontinfo.notice);
     }
+#endif /* HAVE_FT_GET_PS_FONT_INFO */
     
+#if HAVE_FT_GET_BDF_PROPERTY
+    /*
+     * Finally, look for a FOUNDRY BDF property if no other
+     * mechanism has managed to locate a foundry
+     */
+
+    if (!foundry)
+    {
+       int             rc;
+       BDF_PropertyRec prop;
+       rc = MY_Get_BDF_Property(face, "FOUNDRY", &prop);
+       if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
+           foundry = prop.u.atom;
+    }
+
+    if (width == -1)
+    {
+       if (MY_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
+           (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
+            prop.type == BDF_PROPERTY_TYPE_CARDINAL))
+       {
+           FT_Int32    value;
+           
+           if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
+               value = prop.u.integer;
+           else
+               value = (FT_Int32) prop.u.cardinal;
+           switch ((value + 5) / 10) {
+           case 1: width = FC_WIDTH_ULTRACONDENSED; break;
+           case 2: width = FC_WIDTH_EXTRACONDENSED; break;
+           case 3: width = FC_WIDTH_CONDENSED; break;
+           case 4: width = FC_WIDTH_SEMICONDENSED; break;
+           case 5: width = FC_WIDTH_NORMAL; break;
+           case 6: width = FC_WIDTH_SEMIEXPANDED; break;
+           case 7: width = FC_WIDTH_EXPANDED; break;
+           case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
+           case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
+           }
+       }
+       if (width == -1 &&
+           MY_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
+           prop.type == BDF_PROPERTY_TYPE_ATOM)
+       {
+           width = FcIsWidth (prop.u.atom);
+           if (FcDebug () & FC_DBG_SCANV)
+               printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
+       }
+    }
+#endif
+
+    /*
+     * Look for weight, width and slant names in the style value
+     */
+    if (style)
+    {
+       if (weight == -1)
+       {
+           weight = FcContainsWeight (style);
+           if (FcDebug() & FC_DBG_SCANV)
+               printf ("\tStyle %s maps to weight %d\n", style, weight);
+       }
+       if (width == -1)
+       {
+           width = FcContainsWidth (style);
+           if (FcDebug() & FC_DBG_SCANV)
+               printf ("\tStyle %s maps to width %d\n", style, width);
+       }
+       if (slant == -1)
+       {
+           slant = FcContainsSlant (style);
+           if (FcDebug() & FC_DBG_SCANV)
+               printf ("\tStyle %s maps to slant %d\n", style, slant);
+       }
+    }
+    /*
+     * Pull default values from the FreeType flags if more
+     * specific values not found above
+     */
+    if (slant == -1)
+    {
+       slant = FC_SLANT_ROMAN;
+       if (face->style_flags & FT_STYLE_FLAG_ITALIC)
+           slant = FC_SLANT_ITALIC;
+    }
+
+    if (weight == -1)
+    {
+       weight = FC_WEIGHT_MEDIUM;
+       if (face->style_flags & FT_STYLE_FLAG_BOLD)
+           weight = FC_WEIGHT_BOLD;
+    }
+
+    if (width == -1)
+       width = FC_WIDTH_NORMAL;
+
+    if (foundry == 0)
+       foundry = "unknown";
+
     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
        goto bail1;
 
     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
        goto bail1;
 
-    if (width != -1)
-       if (!FcPatternAddInteger (pat, FC_WIDTH, width))
-           goto bail1;
+    if (!FcPatternAddInteger (pat, FC_WIDTH, width))
+       goto bail1;
+
+    if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
+       goto bail1;
 
     /*
      * Compute the unicode coverage for the font
@@ -626,6 +970,20 @@ FcFreeTypeQuery (const FcChar8     *file,
     if (!cs)
        goto bail1;
 
+#if HAVE_FT_GET_BDF_PROPERTY
+    /* For PCF fonts, override the computed spacing with the one from
+       the property */
+    if(MY_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
+       prop.type == BDF_PROPERTY_TYPE_ATOM) {
+        if(!strcmp(prop.u.atom, "c") || !strcmp(prop.u.atom, "C"))
+            spacing = FC_CHARCELL;
+        else if(!strcmp(prop.u.atom, "m") || !strcmp(prop.u.atom, "M"))
+            spacing = FC_MONO;
+        else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
+            spacing = FC_PROPORTIONAL;
+    }
+#endif
+
     /*
      * Skip over PCF fonts that have no encoded characters; they're
      * usually just Unicode fonts transcoded to some legacy encoding
@@ -644,27 +1002,71 @@ FcFreeTypeQuery (const FcChar8   *file,
        goto bail2;
 
     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
+    {
+       FcLangSetDestroy (ls);
        goto bail2;
+    }
+
+    FcLangSetDestroy (ls);
 
     if (spacing != FC_PROPORTIONAL)
        if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
            goto bail2;
 
-    /*
-     * Drop our reference to the charset
-     */
-    FcCharSetDestroy (cs);
-    
     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
     {
        for (i = 0; i < face->num_fixed_sizes; i++)
            if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
-                                    (double) face->available_sizes[i].height))
+                                    FcGetPixelSize (face, i)))
                goto bail1;
        if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
            goto bail1;
+#if HAVE_FT_GET_BDF_PROPERTY
+        if(face->num_fixed_sizes == 1) {
+            int rc;
+            int value;
+            BDF_PropertyRec prop;
+
+            rc = MY_Get_BDF_Property(face, "POINT_SIZE", &prop);
+            if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
+                value = prop.u.integer;
+            else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
+                value = prop.u.cardinal;
+            else
+                goto nevermind;
+            if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
+                goto nevermind;
+
+            rc = MY_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
+            if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
+                value = prop.u.integer;
+            else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
+                value = prop.u.cardinal;
+            else
+                goto nevermind;
+            if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
+                goto nevermind;
+
+        }
+    nevermind:
+        ;
+#endif
     }
 
+    /*
+     * Drop our reference to the charset
+     */
+    FcCharSetDestroy (cs);
+    
+    /*
+     * Deallocate family/style values
+     */
+    
+    if (family_allocated)
+       free (family);
+    if (style_allocated)
+       free (style);
+    
     FT_Done_Face (face);
     FT_Done_FreeType (ftLibrary);
     return pat;
@@ -673,6 +1075,10 @@ bail2:
     FcCharSetDestroy (cs);
 bail1:
     FcPatternDestroy (pat);
+    if (family_allocated)
+       free (family);
+    if (style_allocated)
+       free (style);
 bail0:
     FT_Done_Face (face);
 bail:
@@ -681,31 +1087,10 @@ bail:
 }
 
 
-/*
- * Figure out whether the available freetype has FT_Get_Next_Char
- */
-
-#if FREETYPE_MAJOR > 2
-# define HAS_NEXT_CHAR
-#else
-# if FREETYPE_MAJOR == 2
-#  if FREETYPE_MINOR > 0
-#   define HAS_NEXT_CHAR
-#  else
-#   if FREETYPE_MINOR == 0
-#    if FREETYPE_PATCH >= 9
-#     define HAS_NEXT_CHAR
-#    endif
-#   endif
-#  endif
-# endif
-#endif
-
 /*
  * For our purposes, this approximation is sufficient
  */
-#ifndef HAS_NEXT_CHAR
-#define FT_Get_First_Char(face, gi) ((*(gi) = 1), 1)
+#if !HAVE_FT_GET_NEXT_CHAR
 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
                                          (*(gi) = 0), 0 : \
                                          (*(gi) = 1), (ucs4) + 1)
@@ -1215,6 +1600,109 @@ FcFreeTypeGetPrivateMap (FT_Encoding encoding)
     return 0;
 }
 
+#include "../fc-glyphname/fcglyphname.h"
+
+static FcChar32
+FcHashGlyphName (const FcChar8 *name)
+{
+    FcChar32   h = 0;
+    FcChar8    c;
+
+    while ((c = *name++))
+    {
+       h = ((h << 1) | (h >> 31)) ^ c;
+    }
+    return h;
+}
+
+#if HAVE_FT_HAS_PS_GLYPH_NAMES
+/*
+ * Use Type1 glyph names for fonts which have reliable names
+ * and which export an Adobe Custom mapping
+ */
+static FcBool
+FcFreeTypeUseNames (FT_Face face)
+{
+    FT_Int  map;
+    
+    if (!FT_Has_PS_Glyph_Names (face))
+       return FcFalse;
+    for (map = 0; map < face->num_charmaps; map++)
+       if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
+           return FcTrue;
+    return FcFalse;
+}
+
+static FcChar8 *
+FcUcs4ToGlyphName (FcChar32 ucs4)
+{
+    int                i = (int) (ucs4 % FC_GLYPHNAME_HASH);
+    int                r = 0;
+    FcGlyphName        *gn;
+
+    while ((gn = ucs_to_name[i]))
+    {
+       if (gn->ucs == ucs4)
+           return gn->name;
+       if (!r) 
+       {
+           r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
+           if (!r)
+               r = 1;
+       }
+       i += r;
+       if (i >= FC_GLYPHNAME_HASH)
+           i -= FC_GLYPHNAME_HASH;
+    }
+    return 0;
+}
+
+static FcChar32
+FcGlyphNameToUcs4 (FcChar8 *name)
+{
+    FcChar32   h = FcHashGlyphName (name);
+    int                i = (int) (h % FC_GLYPHNAME_HASH);
+    int                r = 0;
+    FcGlyphName        *gn;
+
+    while ((gn = name_to_ucs[i]))
+    {
+       if (!strcmp ((char *) name, (char *) gn->name))
+           return gn->ucs;
+       if (!r) 
+       {
+           r = (int) (h % FC_GLYPHNAME_REHASH);
+           if (!r)
+               r = 1;
+       }
+       i += r;
+       if (i >= FC_GLYPHNAME_HASH)
+           i -= FC_GLYPHNAME_HASH;
+    }
+    return 0xffff;
+}
+
+/*
+ * Search through a font for a glyph by name.  This is
+ * currently a linear search as there doesn't appear to be
+ * any defined order within the font
+ */
+static FT_UInt
+FcFreeTypeGlyphNameIndex (FT_Face face, FcChar8 *name)
+{
+    FT_UInt gindex;
+    FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
+
+    for (gindex = 0; gindex < face->num_glyphs; gindex++)
+    {
+       if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
+           if (!strcmp ((char *) name, (char *) name_buf))
+               return gindex;
+    }
+    return 0;
+}
+#endif
+
 /*
  * Map a UCS4 glyph to a glyph index.  Use all available encoding
  * tables to try and find one that works.  This information is expected
@@ -1261,6 +1749,21 @@ FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
        if (glyphindex)
            return glyphindex;
     }
+#if HAVE_FT_HAS_PS_GLYPH_NAMES
+    /*
+     * Check postscript name table if present
+     */
+    if (FcFreeTypeUseNames (face))
+    {
+       FcChar8 *name = FcUcs4ToGlyphName (ucs4);
+       if (name)
+       {
+           glyphindex = FcFreeTypeGlyphNameIndex (face, name);
+           if (glyphindex)
+               return glyphindex;
+       }
+    }
+#endif
     return 0;
 }
 
@@ -1269,9 +1772,15 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
                      FT_UInt glyph, FcBlanks *blanks,
                      FT_Pos *advance)
 {
-    FT_Int         load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+    FT_Int         load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
     FT_GlyphSlot    slot;
     
+    /*
+     * For bitmap-only fonts, assume that they're OK.
+     */
+    if ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
+       return FcTrue;
+
     /*
      * When using scalable fonts, only report those glyphs
      * which can be scaled; otherwise those fonts will
@@ -1320,6 +1829,8 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
     return FcFalse;
 }
 
+#define APPROXIMATELY_EQUAL(x,y) (ABS ((x) - (y)) <= MAX (ABS (x), ABS (y)) / 33)
+
 FcCharSet *
 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
 {
@@ -1333,13 +1844,16 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
     int                    o;
     int                    i;
     FT_UInt        glyph;
-    FT_Pos         advance, all_advance = 0;
-    FcBool         has_advance = FcFalse, fixed_advance = FcTrue;
+    FT_Pos         advance, advance_one = 0, advance_two = 0;
+    FcBool         has_advance = FcFalse, fixed_advance = FcTrue, dual_advance = FcFalse;
 
     fcs = FcCharSetCreate ();
     if (!fcs)
        goto bail0;
     
+#ifdef CHECK
+    printf ("Family %s style %s\n", face->family_name, face->style_name);
+#endif
     for (o = 0; o < NUM_DECODE; o++)
     {
        if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
@@ -1361,10 +1875,20 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
                    if (!has_advance)
                    {
                        has_advance = FcTrue;
-                       all_advance = advance;
+                       advance_one = advance;
                    }
-                   else if (advance != all_advance)
-                       fixed_advance = FcFalse;
+                   else if (!APPROXIMATELY_EQUAL (advance, advance_one))
+                    {
+                        if (fixed_advance)
+                        {
+                            dual_advance = FcTrue;
+                            fixed_advance = FcFalse;
+                            advance_two = advance;
+                        }
+                        else if (!APPROXIMATELY_EQUAL (advance, advance_two))
+                            dual_advance = FcFalse;
+                    }
+
                    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
                    if (!leaf)
                        goto bail1;
@@ -1409,10 +1933,20 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
                        if (!has_advance)
                        {
                            has_advance = FcTrue;
-                           all_advance = advance;
+                           advance_one = advance;
                        }
-                       else if (advance != all_advance)
-                           fixed_advance = FcFalse;
+                       else if (!APPROXIMATELY_EQUAL (advance, advance_one))
+                        {
+                            if (fixed_advance)
+                            {
+                                dual_advance = FcTrue;
+                                fixed_advance = FcFalse;
+                                advance_two = advance;
+                            }
+                            else if (!APPROXIMATELY_EQUAL (advance, advance_two))
+                                dual_advance = FcFalse;
+                        }
+
                        if (!leaf)
                        {
                            leaf = FcCharSetFindLeafCreate (fcs, ucs4);
@@ -1447,21 +1981,73 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
 #endif
        }
     }
+#if HAVE_FT_HAS_PS_GLYPH_NAMES
+    /*
+     * Add mapping from PS glyph names if available
+     */
+    if (FcFreeTypeUseNames (face))
+    {
+       FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
+
+       for (glyph = 0; glyph < face->num_glyphs; glyph++)
+       {
+           if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
+           {
+               ucs4 = FcGlyphNameToUcs4 (name_buf);
+               if (ucs4 != 0xffff && 
+                   FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
+               {
+                   if (!has_advance)
+                   {
+                       has_advance = FcTrue;
+                       advance_one = advance;
+                   }
+                   else if (!APPROXIMATELY_EQUAL (advance, advance_one))
+                    {
+                        if (fixed_advance)
+                        {
+                            dual_advance = FcTrue;
+                            fixed_advance = FcFalse;
+                            advance_two = advance;
+                        }
+                        else if (!APPROXIMATELY_EQUAL (advance, advance_two))
+                            dual_advance = FcFalse;
+                    }
+                   leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+                   if (!leaf)
+                       goto bail1;
+                   leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
+#ifdef CHECK
+                   if (ucs4 > font_max)
+                       font_max = ucs4;
+#endif
+               }
+           }
+       }
+    }
+#endif
 #ifdef CHECK
     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
     {
-       FcBool  has_char = FcFreeTypeCharIndex (face, ucs4) != 0;
+       FcBool  has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
        FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
 
        if (has_char && !has_bit)
-           printf ("Bitmap missing char 0x%x\n", ucs4);
+       {
+           if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
+               printf ("Bitmap missing broken char 0x%x\n", ucs4);
+           else
+               printf ("Bitmap missing char 0x%x\n", ucs4);
+       }
        else if (!has_char && has_bit)
            printf ("Bitmap extra char 0x%x\n", ucs4);
     }
 #endif
     if (fixed_advance)
        *spacing = FC_MONO;
+    else if (dual_advance && APPROXIMATELY_EQUAL (2 * MIN (advance_one, advance_two), MAX (advance_one, advance_two)))
+        *spacing = FC_DUAL;
     else
        *spacing = FC_PROPORTIONAL;
     return fcs;