* 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 <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: Please install freetype 2.1.4 or later"
+#endif
+
+#if !HAVE_FT_GET_PS_FONT_INFO
+#warning "No FT_Get_PS_Font_Info: Please install freetype 2.1.1 or later"
+#endif
/*
* Keep Han languages separated by eliminating languages
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;
}
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,
{
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;
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++)
{
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;
}
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);
}
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))
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++)
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)
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;
case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
}
}
+
+ /*
+ * Type 1: Check for FontInfo dictionary information
+ * Code from g2@magestudios.net (Gerard Escalante)
+ */
+
+#if HAVE_FT_GET_PS_FONT_INFO
+ if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
+ {
+ 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 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);
+ }
+#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
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
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;
FcCharSetDestroy (cs);
bail1:
FcPatternDestroy (pat);
+ if (family_allocated)
+ free (family);
+ if (style_allocated)
+ free (style);
bail0:
FT_Done_Face (face);
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)
-#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 {
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
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;
}
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
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)
{
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)
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;
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);
#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 * FC_MIN (advance_one, advance_two), FC_MAX (advance_one, advance_two)))
+ *spacing = FC_DUAL;
else
*spacing = FC_PROPORTIONAL;
return fcs;