]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcfreetype.c
Add FcResultOutOfMemory to provide an accurate error when FcFontSetMatch
[fontconfig.git] / src / fcfreetype.c
index 60e067662ba46fe948d519e25e04419d752063c6..daaba28bbb4ff8ee9ead029c7641632e39a14329 100644 (file)
 #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 <freetype/ftbdf.h>
-#include <freetype/ftmodule.h>
+#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) ? \
 #endif
 
 #if !HAVE_FT_GET_BDF_PROPERTY
-#warning "No FT_Get_BDF_Property"
+#warning "No FT_Get_BDF_Property: Please install freetype 2.1.4 or later"
 #endif
 
 #if !HAVE_FT_GET_PS_FONT_INFO
-#warning "No FT_Get_Font_Info"
+#warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
 #endif
 
 /*
@@ -157,31 +158,34 @@ FcUtf8IsLatin (FcChar8 *str, int len)
    URW++, and both strings appear in the notice. */
 
 static const struct {
-    const FcChar8   *notice;
+    const FT_String *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 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 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" }
+    { (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 char *notice)
+FcNoticeFoundry(const FT_String *notice)
 {
     int i;
 
@@ -193,7 +197,7 @@ FcNoticeFoundry(const char *notice)
 }
 
 static FcBool
-FcVendorMatch(const char *vendor, const char *vendor_string)
+FcVendorMatch(const FT_Char vendor[4], const FT_Char *vendor_string)
 {
     /* vendor is not necessarily NUL-terminated. */
     int i, len;
@@ -213,44 +217,44 @@ FcVendorMatch(const char *vendor, const char *vendor_string)
    entries for padding both with spaces and NULs. */
 
 static const struct {
-    const FcChar8   *vendor;
+    const FT_Char   *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"}
+    { (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 char *vendor)
+FcVendorFoundry(const FT_Char vendor[4])
 {
     int i;
     
@@ -262,8 +266,8 @@ FcVendorFoundry(const char *vendor)
 }
 
 typedef struct _FcStringConst {
-    const char *name;
-    int                value;
+    const FcChar8   *name;
+    int                    value;
 } FcStringConst;
 
 static int
@@ -343,6 +347,27 @@ static const FcStringConst  slantConsts[] = {
 #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,
@@ -648,7 +673,7 @@ FcFreeTypeQuery (const FcChar8      *file,
         case TT_NAME_ID_MANUFACTURER:
            /* If the foundry wasn't found in the OS/2 table, look here */
             if(!foundry)
-                foundry = FcNoticeFoundry(utf8);
+                foundry = FcNoticeFoundry((FT_String *) utf8);
             break;
        }
        if (utf8)
@@ -920,21 +945,23 @@ FcFreeTypeQuery (const FcChar8    *file,
            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(foundry) 
-    {
-        if(!FcPatternAddString (pat, FC_FOUNDRY, foundry))
-            goto bail1;
-    }
+    if (!FcPatternAddString (pat, FC_FOUNDRY, foundry))
+       goto bail1;
 
     /*
      * Compute the unicode coverage for the font
@@ -948,11 +975,11 @@ FcFreeTypeQuery (const FcChar8    *file,
        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"))
+        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"))
+        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"))
+        else if(!strcmp(prop.u.atom, "p") || !strcmp(prop.u.atom, "P"))
             spacing = FC_PROPORTIONAL;
     }
 #endif
@@ -990,7 +1017,7 @@ FcFreeTypeQuery (const FcChar8     *file,
     {
        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;
@@ -1000,17 +1027,6 @@ FcFreeTypeQuery (const FcChar8   *file,
             int value;
             BDF_PropertyRec prop;
 
-            rc = MY_Get_BDF_Property(face, "PIXEL_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(value != face->available_sizes[0].height)
-                /* ``impossible'' */
-                goto nevermind;
-
             rc = MY_Get_BDF_Property(face, "POINT_SIZE", &prop);
             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
                 value = prop.u.integer;
@@ -1078,7 +1094,7 @@ bail:
 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
                                          (*(gi) = 0), 0 : \
                                          (*(gi) = 1), (ucs4) + 1)
-#warning "No FT_Get_Next_Char"
+#warning "No FT_Get_Next_Char: Please install freetype version 2.1.0 or newer"
 #endif
 
 typedef struct _FcCharEnt {
@@ -1599,6 +1615,7 @@ FcHashGlyphName (const FcChar8 *name)
     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
@@ -1684,6 +1701,7 @@ FcFreeTypeGlyphNameIndex (FT_Face face, FcChar8 *name)
     }
     return 0;
 }
+#endif
 
 /*
  * Map a UCS4 glyph to a glyph index.  Use all available encoding
@@ -1731,6 +1749,7 @@ FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
        if (glyphindex)
            return glyphindex;
     }
+#if HAVE_FT_HAS_PS_GLYPH_NAMES
     /*
      * Check postscript name table if present
      */
@@ -1744,6 +1763,7 @@ FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
                return glyphindex;
        }
     }
+#endif
     return 0;
 }
 
@@ -1755,6 +1775,12 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
     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
@@ -1803,6 +1829,11 @@ FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4,
     return FcFalse;
 }
 
+#define FC_MIN(a,b) ((a) < (b) ? (a) : (b))
+#define FC_MAX(a,b) ((a) > (b) ? (a) : (b))
+#define FC_ABS(a)   ((a) < 0 ? -(a) : (a))
+#define APPROXIMATELY_EQUAL(x,y) (FC_ABS ((x) - (y)) <= FC_MAX (FC_ABS (x), FC_ABS (y)) / 33)
+
 FcCharSet *
 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
 {
@@ -1816,8 +1847,8 @@ 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)
@@ -1847,10 +1878,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;
@@ -1895,10 +1936,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);
@@ -1933,6 +1984,7 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
 #endif
        }
     }
+#if HAVE_FT_HAS_PS_GLYPH_NAMES
     /*
      * Add mapping from PS glyph names if available
      */
@@ -1951,10 +2003,19 @@ 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;
@@ -1967,6 +2028,7 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
            }
        }
     }
+#endif
 #ifdef CHECK
     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
@@ -1987,6 +2049,8 @@ FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
 #endif
     if (fixed_advance)
        *spacing = FC_MONO;
+    else if (dual_advance && APPROXIMATELY_EQUAL (2 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
+        *spacing = FC_DUAL;
     else
        *spacing = FC_PROPORTIONAL;
     return fcs;