]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcfreetype.c
Add demi and book postscript weight names. Allow spaces in postscript and X
[fontconfig.git] / src / fcfreetype.c
index c4d4cfc627f5f029826b81fcd53b7246328ebc04..f46e1394ecae5794761f6dfc38b34a4b76f7260e 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 <freetype/tttables.h>
 #include <freetype/ftsnames.h>
 #include <freetype/ttnameid.h>
+#include <freetype/t1tables.h>
+
+#if (FREETYPE_MINOR > 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH >= 4))
+#include <freetype/ftbdf.h>
+#include <freetype/ftmodule.h>
+#define USE_FTBDF
+#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
+
 
 /*
  * Keep Han languages separated by eliminating languages
@@ -89,7 +124,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;
 }
@@ -111,6 +147,115 @@ 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 FcChar8   *notice;
+    const FcChar8   *foundry;
+} FcNoticeFoundries[] = {
+    { (const FcChar8*) "Bigelow",      (const FcChar8 *) "b&h" },
+    { (const FcChar8*) "Adobe",                (const FcChar8 *) "adobe" },
+    { (const FcChar8*) "Bitstream",    (const FcChar8 *) "bitstream" },
+    { (const FcChar8*) "Monotype",     (const FcChar8 *) "monotype" },
+    { (const FcChar8*) "Linotype",     (const FcChar8 *) "linotype" },
+    { (const FcChar8*) "LINOTYPE-HELL", (const FcChar8 *) "linotype" },
+    { (const FcChar8*) "IBM",          (const FcChar8 *) "ibm" },
+    { (const FcChar8*) "URW",          (const FcChar8 *) "urw" },
+    { (const FcChar8*) "International Typeface Corporation", 
+                                       (const FcChar8 *) "itc" },
+    { (const FcChar8*) "Tiro Typeworks",(const FcChar8 *) "tiro" },
+    { (const FcChar8*) "XFree86",      (const FcChar8 *) "xfree86" },
+    { (const FcChar8*) "Microsoft",    (const FcChar8 *) "microsoft" },
+    { (const FcChar8*) "Omega",                (const FcChar8 *) "omega" },
+    { (const FcChar8*) "Font21",       (const FcChar8 *) "hwan" },
+    { (const FcChar8*) "HanYang System",(const FcChar8 *) "hanyang" }
+};
+
+#define NUM_NOTICE_FOUNDRIES   (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
+
+static const FcChar8 *
+FcNoticeFoundry(const char *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 char *vendor, const 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 FcChar8   *vendor;
+    const FcChar8   *foundry;
+} FcVendorFoundries[] = {
+    { (const FcChar8*) "ADBE", (const FcChar8 *) "adobe"},
+    { (const FcChar8*) "AGFA", (const FcChar8 *) "agfa"},
+    { (const FcChar8*) "ALTS", (const FcChar8 *) "altsys"},
+    { (const FcChar8*) "APPL", (const FcChar8 *) "apple"},
+    { (const FcChar8*) "ARPH", (const FcChar8 *) "arphic"},
+    { (const FcChar8*) "ATEC", (const FcChar8 *) "alltype"},
+    { (const FcChar8*) "B&H",  (const FcChar8 *) "b&h"},
+    { (const FcChar8*) "BITS", (const FcChar8 *) "bitstream"},
+    { (const FcChar8*) "CANO", (const FcChar8 *) "cannon"},
+    { (const FcChar8*) "DYNA", (const FcChar8 *) "dynalab"},
+    { (const FcChar8*) "EPSN", (const FcChar8 *) "epson"},
+    { (const FcChar8*) "FJ",   (const FcChar8 *) "fujitsu"},
+    { (const FcChar8*) "IBM",  (const FcChar8 *) "ibm"},
+    { (const FcChar8*) "ITC",  (const FcChar8 *) "itc"},
+    { (const FcChar8*) "IMPR", (const FcChar8 *) "impress"},
+    { (const FcChar8*) "LARA", (const FcChar8 *) "larabiefonts"},
+    { (const FcChar8*) "LEAF", (const FcChar8 *) "interleaf"},
+    { (const FcChar8*) "LETR", (const FcChar8 *) "letraset"},
+    { (const FcChar8*) "LINO", (const FcChar8 *) "linotype"},
+    { (const FcChar8*) "MACR", (const FcChar8 *) "macromedia"},
+    { (const FcChar8*) "MONO", (const FcChar8 *) "monotype"},
+    { (const FcChar8*) "MS",   (const FcChar8 *) "microsoft"},
+    { (const FcChar8*) "MT",   (const FcChar8 *) "monotype"},
+    { (const FcChar8*) "NEC",  (const FcChar8 *) "nec"},
+    { (const FcChar8*) "PARA", (const FcChar8 *) "paratype"},
+    { (const FcChar8*) "QMSI", (const FcChar8 *) "qms"},
+    { (const FcChar8*) "RICO", (const FcChar8 *) "ricoh"},
+    { (const FcChar8*) "URW",  (const FcChar8 *) "urw"},
+    { (const FcChar8*) "Y&Y",  (const FcChar8 *) "y&y"}
+};
+
+#define NUM_VENDOR_FOUNDRIES   (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
+
+static const FcChar8 *
+FcVendorFoundry(const char *vendor)
+{
+    int i;
+    
+    if (vendor)
+       for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
+           if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
+               return FcVendorFoundries[i].foundry;
+    return 0;
+}
+
+
 FcPattern *
 FcFreeTypeQuery (const FcChar8 *file,
                 int            id,
@@ -126,9 +271,12 @@ FcFreeTypeQuery (const FcChar8     *file,
     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;
+    PS_FontInfoRec  psfontinfo;
     TT_Header      *head;
     const FcChar8   *exclusiveLang = 0;
     FT_SfntName            sname;
@@ -168,13 +316,27 @@ FcFreeTypeQuery (const FcChar8    *file,
     if (face->style_flags & FT_STYLE_FLAG_BOLD)
        weight = FC_WEIGHT_BOLD;
 
+    /*
+     * Get the OS/2 table
+     */
+    os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
+
+    /*
+     * 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++)
     {
@@ -284,7 +446,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;
        }
@@ -397,6 +561,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(utf8);
+            break;
        }
        if (utf8)
            free (utf8);
@@ -489,10 +659,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++)
@@ -563,7 +729,135 @@ FcFreeTypeQuery (const FcChar8    *file,
        case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
        }
     }
+
+    /*
+     * Type 1: Check for FontInfo dictionary information
+     * Code from g2@magestudios.net (Gerard Escalante)
+     */
+    
+    if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
+    {
+       if (psfontinfo.weight)
+       {
+           static struct {
+               char    *name;
+               int     value;
+           } ps_weights[] = {
+               { "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_PS_WEIGHTS (sizeof (ps_weights) / sizeof (ps_weights[0]))
+           int w;
+           for (w = 0; w < NUM_PS_WEIGHTS; w++)
+               if (!FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) ps_weights[w].name,
+                                        (FcChar8 *) psfontinfo.weight))
+               {
+                   weight = ps_weights[w].value;
+                   break;
+               }
+           if (FcDebug () & FC_DBG_SCANV)
+           {
+               if (w == NUM_PS_WEIGHTS)
+                   printf ("\tunknown PS weight name %s\n", psfontinfo.weight);
+           }
+       }
+     
+#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
+            slant = FC_SLANT_ROMAN; 
+#endif
+
+        if(!foundry)
+            foundry = FcNoticeFoundry(psfontinfo.notice);
+    }
     
+#ifdef USE_FTBDF
+    /*
+     * 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)
+    {
+       BDF_PropertyRec prop;
+       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;
+           }
+       }
+       else if (MY_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
+                prop.type == BDF_PROPERTY_TYPE_ATOM)
+       {
+           static struct {
+               FcChar8     *width_name;
+               int         width;
+           } FcSetWidths[] = {
+               { "Condensed",      FC_WIDTH_CONDENSED },
+               { "SemiCondensed",  FC_WIDTH_SEMICONDENSED },
+               { "Normal",         FC_WIDTH_NORMAL },
+           };
+           int i;
+
+           if (FcDebug () & FC_DBG_SCANV)
+               printf ("\nsetwidth: %s\n", prop.u.atom);
+           for (i = 0; i < sizeof (FcSetWidths) / sizeof (FcSetWidths[0]); i++)
+               if (!FcStrCmpIgnoreBlanksAndCase ((FcChar8 *) prop.u.atom,
+                                        FcSetWidths[i].width_name))
+               {
+                   width = FcSetWidths[i].width;
+                   break;
+               }
+       }
+    }
+
+#endif
+
     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
        goto bail1;
 
@@ -574,10 +868,16 @@ FcFreeTypeQuery (const FcChar8    *file,
        if (!FcPatternAddInteger (pat, FC_WIDTH, width))
            goto bail1;
 
+    if(foundry) 
+    {
+        if(!FcPatternAddString (pat, FC_FOUNDRY, foundry))
+            goto bail1;
+    }
+
     /*
      * Compute the unicode coverage for the font
      */
-    cs = FcFreeTypeCharSet (face, blanks);
+    cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
     if (!cs)
        goto bail1;
 
@@ -601,6 +901,10 @@ FcFreeTypeQuery (const FcChar8     *file,
     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
        goto bail2;
 
+    if (spacing != FC_PROPORTIONAL)
+       if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
+           goto bail2;
+
     /*
      * Drop our reference to the charset
      */
@@ -1217,7 +1521,8 @@ FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
 
 static FcBool
 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, 
-                     FT_UInt glyph, FcBlanks *blanks)
+                     FT_UInt glyph, FcBlanks *blanks,
+                     FT_Pos *advance)
 {
     FT_Int         load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
     FT_GlyphSlot    slot;
@@ -1239,6 +1544,8 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
     if (!glyph)
        return FcFalse;
     
+    *advance = slot->metrics.horiAdvance;
+
     switch (slot->format) {
     case ft_glyph_format_bitmap:
        /*
@@ -1269,7 +1576,7 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
 }
 
 FcCharSet *
-FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
+FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
 {
     FcChar32       page, off, max, ucs4;
 #ifdef CHECK
@@ -1281,6 +1588,8 @@ FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
     int                    o;
     int                    i;
     FT_UInt        glyph;
+    FT_Pos         advance, all_advance = 0;
+    FcBool         has_advance = FcFalse, fixed_advance = FcTrue;
 
     fcs = FcCharSetCreate ();
     if (!fcs)
@@ -1301,8 +1610,16 @@ FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
            {
                ucs4 = map->ent[i].bmp;
                glyph = FT_Get_Char_Index (face, map->ent[i].encode);
-               if (glyph && FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks))
+               if (glyph && 
+                   FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
                {
+                   if (!has_advance)
+                   {
+                       has_advance = FcTrue;
+                       all_advance = advance;
+                   }
+                   else if (advance != all_advance)
+                       fixed_advance = FcFalse;
                    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
                    if (!leaf)
                        goto bail1;
@@ -1342,8 +1659,15 @@ FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
                {
                    glyph = FT_Get_Char_Index (face, ucs4);
                    if (glyph && FcFreeTypeCheckGlyph (face, ucs4, 
-                                                      glyph, blanks))
+                                                      glyph, blanks, &advance))
                    {
+                       if (!has_advance)
+                       {
+                           has_advance = FcTrue;
+                           all_advance = advance;
+                       }
+                       else if (advance != all_advance)
+                           fixed_advance = FcFalse;
                        if (!leaf)
                        {
                            leaf = FcCharSetFindLeafCreate (fcs, ucs4);
@@ -1391,6 +1715,10 @@ FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
            printf ("Bitmap extra char 0x%x\n", ucs4);
     }
 #endif
+    if (fixed_advance)
+       *spacing = FC_MONO;
+    else
+       *spacing = FC_PROPORTIONAL;
     return fcs;
 bail1:
     FcCharSetDestroy (fcs);
@@ -1398,3 +1726,10 @@ bail0:
     return 0;
 }
 
+FcCharSet *
+FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
+{
+    int spacing;
+
+    return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
+}