Rewrite TrueType font metric parsing code

Ian Pilcher ian.pilcher at home.com
Thu Jul 26 15:19:55 CDT 2001


This cleans up the mess that was made when the built-in font metric data
was made constant.

Modified files:
    dlls/wineps: afm.c init.c psdrv.h truetype.c

Log message:
    Ian Pilcher <ian.pilcher at home.com>
    WINEPS: rewrite TrueType font metric parsing code
-- 
========================================================================
Ian Pilcher                                         ian.pilcher at home.com
========================================================================
-------------- next part --------------
diff -urN ../wine-20010724cvs/dlls/wineps/afm.c ./dlls/wineps/afm.c
--- ../wine-20010724cvs/dlls/wineps/afm.c	Thu Jul 26 14:37:23 2001
+++ ./dlls/wineps/afm.c	Thu Jul 26 14:36:52 2001
@@ -497,10 +497,13 @@
  *
  *	PSDRV_AddAFMtoList
  *
- * Adds an afm to the list whose head is pointed to by head. Creates new
- * family node if necessary and always creates a new AFMLISTENTRY.
+ *  Adds an afm to the list whose head is pointed to by head. Creates new
+ *  family node if necessary and always creates a new AFMLISTENTRY.
+ *
+ *  Returns FALSE for memory allocation error; returns TRUE, but sets *p_added
+ *  to FALSE, for duplicate.
  */
-BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm)
+BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm, BOOL *p_added)
 {
     FONTFAMILY *family = *head;
     FONTFAMILY **insert = head;
@@ -535,6 +538,7 @@
 	}
 	strcpy( family->FamilyName, afm->FamilyName );
 	family->afmlist = newafmle;
+	*p_added = TRUE;
 	return TRUE;
     }
     else {
@@ -543,6 +547,7 @@
 	    if (!strcmp(tmpafmle->afm->FontName, afm->FontName)) {
 	    	WARN("Ignoring duplicate FontName '%s'\n", afm->FontName);
 		HeapFree(PSDRV_Heap, 0, newafmle);
+		*p_added = FALSE;
 		return TRUE;	    	    	    /* not a fatal error */
 	    }
 	    tmpafmle = tmpafmle->next;
@@ -555,6 +560,7 @@
 
     tmpafmle->next = newafmle;
 
+    *p_added = TRUE;
     return TRUE;
 }
 
@@ -834,14 +840,19 @@
  
 static BOOL AddBuiltinAFMs()
 {
-    int i = 0;
+    const AFM *const	*afm = PSDRV_BuiltinAFMs;
     
-    while (PSDRV_BuiltinAFMs[i] != NULL)
+    while (*afm != NULL)
     {
-    	if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, PSDRV_BuiltinAFMs[i])
-	    	== FALSE)
+    	BOOL	added;
+    
+    	if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, *afm, &added) == FALSE)
 	    return FALSE;
-	++i;
+	    
+	if (added == FALSE)
+	    TRACE("Ignoring built-in font %s\n", (*afm)->FontName);
+	    
+	++afm;
     }
     
     return TRUE;
@@ -861,6 +872,7 @@
 static BOOL PSDRV_ReadAFMDir(const char* afmdir) {
     DIR *dir;
     const AFM	*afm;
+    BOOL added;
 
     dir = opendir(afmdir);
     if (dir) {
@@ -881,7 +893,7 @@
 		TRACE("loading AFM %s\n",afmfn);
 		afm = PSDRV_AFMParse(afmfn);
 		if (afm) {
-		    if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm) == FALSE) {
+		    if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added) == FALSE) {
 		    	closedir(dir);
 			return FALSE;
 		    }
@@ -908,6 +920,7 @@
     char value[256];
     HKEY hkey;
     DWORD type, key_len, value_len;
+    BOOL added;
 
     if (PSDRV_GlyphListInit() != 0)
 	return FALSE;
@@ -924,7 +937,7 @@
         const AFM* afm = PSDRV_AFMParse(value);
 	
         if (afm) {
-            if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm) == FALSE) {
+            if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added) == FALSE) {
 		RegCloseKey(hkey);
 	    	return FALSE;
 	    }
diff -urN ../wine-20010724cvs/dlls/wineps/init.c ./dlls/wineps/init.c
--- ../wine-20010724cvs/dlls/wineps/init.c	Thu Jul 26 14:37:23 2001
+++ ./dlls/wineps/init.c	Thu Jul 26 14:36:52 2001
@@ -620,7 +620,8 @@
 	    	    "ignoring\n", font->Name);
 	}
 	else {
-	    if (PSDRV_AddAFMtoList(&pi->Fonts, afm) == FALSE) {
+	    BOOL added;
+	    if (PSDRV_AddAFMtoList(&pi->Fonts, afm, &added) == FALSE) {
 	    	PSDRV_FreeAFMList(pi->Fonts);
 		goto cleanup;
 	    }
diff -urN ../wine-20010724cvs/dlls/wineps/psdrv.h ./dlls/wineps/psdrv.h
--- ../wine-20010724cvs/dlls/wineps/psdrv.h	Thu Jul 26 14:37:23 2001
+++ ./dlls/wineps/psdrv.h	Thu Jul 26 14:36:52 2001
@@ -298,7 +298,8 @@
 extern PPD *PSDRV_ParsePPD(char *fname);
 extern PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name);
 extern const AFM *PSDRV_FindAFMinList(FONTFAMILY *head, char *name);
-extern BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm);
+extern BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm,
+    	BOOL *p_added);
 extern void PSDRV_FreeAFMList( FONTFAMILY *head );
 
 extern BOOL WINAPI PSDRV_Init(HINSTANCE hinst, DWORD reason, LPVOID reserved);
diff -urN ../wine-20010724cvs/dlls/wineps/truetype.c ./dlls/wineps/truetype.c
--- ../wine-20010724cvs/dlls/wineps/truetype.c	Thu Jul 26 14:37:23 2001
+++ ./dlls/wineps/truetype.c	Thu Jul 26 14:41:29 2001
@@ -4,6 +4,13 @@
  *
  *  Copyright 2001  Ian Pilcher
  *
+ *
+ *  NOTE:  Many of the functions in this file can return either fatal errors
+ *  	(memory allocation failure or unexpected FreeType error) or non-fatal
+ *  	errors (unusable font file).  Fatal errors are indicated by returning
+ *  	FALSE; see individual function descriptions for how they indicate non-
+ *  	fatal errors.
+ *
  */
 #include "config.h"
 
@@ -37,6 +44,7 @@
 #include <dirent.h>
 #include <string.h>
 #include <stdio.h>
+#include <errno.h>
 
 #include "winnt.h"
 #include "winerror.h"
@@ -46,41 +54,27 @@
 
 DEFAULT_DEBUG_CHANNEL(psdrv);
 
-
 #define REQUIRED_FACE_FLAGS 	(   FT_FACE_FLAG_SCALABLE   |	\
     	    	    	    	    FT_FACE_FLAG_HORIZONTAL |	\
 				    FT_FACE_FLAG_SFNT	    |	\
 				    FT_FACE_FLAG_GLYPH_NAMES	)
 
-static FT_Library   	library;
-static FT_Face	    	face;
-static FT_CharMap   	charmap;
-static TT_Header    	*head;
-static TT_Postscript	*post;
-static TT_OS2	    	*os2;
-static TT_HoriHeader	*hhea;
-
-/* This is now officially a pain in the ass! */
-
-typedef struct
-{
-    LPSTR   FontName;
-    LPSTR   FullName;
-    LPSTR   FamilyName;
-    LPSTR   EncodingScheme;
-} AFMSTRINGS;
-
+#define GLYPH_LOAD_FLAGS    	(   FT_LOAD_NO_SCALE	    	|   \
+    	    	    	    	    FT_LOAD_IGNORE_TRANSFORM	|   \
+				    FT_LOAD_LINEAR_DESIGN   	    )
+				    
 /*******************************************************************************
- *
  *  FindCharMap
  *
- *  Sets charmap and points afm->EncodingScheme to encoding name (in driver
- *  heap).  Leaves both uninitialized if font contains no Windows encoding.
+ *  Finds Windows character map and creates "EncodingScheme" string.  Returns
+ *  FALSE to indicate memory allocation or FreeType error; sets *p_charmap to
+ *  NULL if no Windows encoding is present.
  *
- *  Returns FALSE to indicate memory allocation error.
+ *  Returns Unicode character map if present; otherwise uses the first Windows
+ *  character map found.
  *
  */
-static const char *encoding_names[7] =
+static const LPCSTR encoding_names[7] =
 {
     "WindowsSymbol",	    /* TT_MS_ID_SYMBOL_CS */
     "WindowsUnicode",	    /* TT_MS_ID_UNICODE_CS */
@@ -89,14 +83,14 @@
     "WindowsBig5",  	    /* TT_MS_ID_BIG_5 */
     "WindowsWansung",	    /* TT_MS_ID_WANSUNG */
     "WindowsJohab"  	    /* TT_MS_ID_JOHAB */
+/*  "WindowsUnknown65535"   is the longest possible (encoding_id is a UShort) */
 };
- 
-static BOOL FindCharMap(AFM *afm, AFMSTRINGS *str)
+
+static BOOL FindCharMap(FT_Face face, FT_CharMap *p_charmap, LPSTR *p_sz)
 {
     FT_Int  	i;
     FT_Error	error;
-    
-    charmap = NULL;
+    FT_CharMap	charmap = NULL;
     
     for (i = 0; i < face->num_charmaps; ++i)
     {
@@ -104,82 +98,72 @@
 	    continue;
 	    
 	if (face->charmaps[i]->encoding_id == TT_MS_ID_UNICODE_CS)
-    	{
+	{
 	    charmap = face->charmaps[i];
 	    break;
 	}
-	    
+	
 	if (charmap == NULL)
 	    charmap = face->charmaps[i];
     }
     
+    *p_charmap = charmap;
+    
     if (charmap == NULL)
-    	return TRUE;
-	
+    {
+    	WARN("No Windows character map found\n");
+	return TRUE;
+    }
+    
     error = FT_Set_Charmap(face, charmap);
     if (error != FT_Err_Ok)
     {
-    	ERR("%s returned %i\n", "FT_Set_CharMap", error);
+    	ERR("%s returned %i\n", "FT_Set_Charmap", error);
 	return FALSE;
     }
+    
+    *p_sz = HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
+    if (*p_sz == NULL)
+    	return FALSE;
 	
     if (charmap->encoding_id < 7)
-    {
-        if (!(str->EncodingScheme = HeapAlloc(PSDRV_Heap, 0,
-                                              strlen(encoding_names[charmap->encoding_id])+1 )))
-	    return FALSE;
-        strcpy( str->EncodingScheme, encoding_names[charmap->encoding_id] );
-    }
+    	strcpy(*p_sz, encoding_names[charmap->encoding_id]);
     else
-    {
-    	str->EncodingScheme =
-	    	HeapAlloc(PSDRV_Heap, 0, sizeof("WindowsUnknown65535"));
-	if (str->EncodingScheme == NULL)
-	    return FALSE;
-	    
-	sprintf(str->EncodingScheme, "%s%u", "WindowsUnknown",
-	    	charmap->encoding_id);
-    }
-    
-    afm->EncodingScheme = str->EncodingScheme;
-    
+    	sprintf(*p_sz, "%s%u", "WindowsUnknown", charmap->encoding_id);
+	
     return TRUE;
 }
 
 /*******************************************************************************
- *  NameTableString
+ *  MSTTStrToSz
  *
- *  Converts a name table string to a null-terminated character string.  The
- *  space for the character string is allocated from the driver heap.
+ *  Converts a string in the TrueType NAME table to a null-terminated ASCII
+ *  character string.  Space for the string is allocated from the driver heap.
+ *  Only handles platform_id = 3 (TT_PLATFORM_MICROSOFT) strings (16-bit, big
+ *  endian).  It also only handles ASCII character codes (< 128).
  *
- *  This function handles only platform_id = 3 (TT_PLATFORM_MICROSOFT) -- 16-bit
- *  big-endian strings.  It also only handles ASCII character codes (< 128).
- *
- *  This function will set *sz to NULL if it cannot parse the string, but it
- *  will only return FALSE in the event of an unexpected error (memory
- *  allocation failure).
+ *  Sets *p_sz to NULL if string cannot be converted; only returns FALSE for
+ *  memory allocation failure.
  *
  */
-static BOOL NameTableString(LPSTR *sz, const FT_SfntName *name)
-{    
-    FT_UShort 	i, len, *ws;
-    LPSTR   	s;
+static BOOL MSTTStrToSz(const FT_SfntName *name, LPSTR *p_sz)
+{
+    FT_UShort	i;
+    INT     	len;
+    USHORT  	*wsz;
+    LPSTR   	sz;
     
-    if (name->platform_id != TT_PLATFORM_MICROSOFT)
-    {
-    	ERR("Unsupported encoding %i\n", name->platform_id);
-	return FALSE;	    /* should never get here */
-    }
+    len = name->string_len / 2;     	    	    /* # of 16-bit chars */
     
-    len = name->string_len / 2;
-    *sz = s = HeapAlloc(PSDRV_Heap, 0, len + 1);
-    if (s == NULL)
+    *p_sz = sz = HeapAlloc(PSDRV_Heap, 0, len + 1);
+    if (sz == NULL)
     	return FALSE;
-    ws = (FT_UShort *)(name->string);
 	
-    for (i = 0; i < len; ++i, ++s, ++ws)
+    wsz = (USHORT *)(name->string);
+    
+    for (i = 0; i < len; ++i, ++sz, ++wsz)
     {
-    	FT_UShort   wc = *ws;
+    	USHORT	wc = *wsz;
 	
 #ifndef WORDS_BIGENDIAN
     	wc = (wc >> 8) | (wc << 8);
@@ -188,39 +172,42 @@
     	if (wc > 127)
 	{
 	    WARN("Non-ASCII character 0x%.4x\n", wc);
-	    HeapFree(PSDRV_Heap, 0, *sz);
-	    *sz = NULL;
+	    HeapFree(PSDRV_Heap, 0, *p_sz);
+	    *p_sz = NULL;
 	    return TRUE;
 	}
 	
-	*s = (CHAR)wc;
+	*sz = (CHAR)wc;
     }
     
-    *s = '\0';
+    *sz = '\0';
+    
     return TRUE;
 }
 
 /*******************************************************************************
- *  ReadNameTable
+ *  FindMSTTString
  *
- *  Reads various font names from the TrueType 'NAME' table.  Currently looks
- *  for U.S. English names only,
+ *  Finds the requested Microsoft platform string in the TrueType NAME table and
+ *  converts it to a null-terminated ASCII string.  Currently looks for U.S.
+ *  English names only.
  *
- *  May leave a pointer uninitialized if the desired string is not present;
- *  returns FALSE only in the event of an unexpected error.
+ *  Sets string to NULL if not present or cannot be converted; returns FALSE
+ *  only for memory allocation failure.
  *
  */
-static BOOL ReadNameTable(AFM *afm, AFMSTRINGS *str)
+static BOOL FindMSTTString(FT_Face face, FT_CharMap charmap, FT_UShort name_id,
+    	LPSTR *p_sz)
 {
-    FT_UInt 	numStrings, stringIndex;
-    FT_SfntName name;
-    FT_Error	error;
-
-    numStrings = FT_Get_Sfnt_Name_Count(face);
+    FT_UInt 	    num_strings, string_index;
+    FT_SfntName     name;
+    FT_Error	    error;
+    
+    num_strings = FT_Get_Sfnt_Name_Count(face);
     
-    for (stringIndex = 0; stringIndex < numStrings; ++stringIndex)
+    for (string_index = 0; string_index < num_strings; ++string_index)
     {
-	error = FT_Get_Sfnt_Name(face, stringIndex, &name);
+    	error = FT_Get_Sfnt_Name(face, string_index, &name);
 	if (error != FT_Err_Ok)
 	{
 	    ERR("%s returned %i\n", "FT_Get_Sfnt_Name", error);
@@ -229,36 +216,22 @@
 	
 	/* FIXME - Handle other languages? */
 	
-	if (name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES ||
-	    	name.platform_id != charmap->platform_id ||
-	    	name.encoding_id != charmap->encoding_id)
+	if (name.platform_id != TT_PLATFORM_MICROSOFT ||
+	    	name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES)
 	    continue;
-	
-    	switch (name.name_id)
-	{
-	    case TT_NAME_ID_FONT_FAMILY:
 	    
-	    	if (NameTableString(&(str->FamilyName), &name) == FALSE)
-		    return FALSE;
-		afm->FamilyName = str->FamilyName;
-		break;
-	    
-	    case TT_NAME_ID_FULL_NAME:
-	    
-	    	if (NameTableString(&(str->FullName), &name) == FALSE)
-		    return FALSE;
-		afm->FullName = str->FullName;
-		break;
+	if (name.platform_id != charmap->platform_id ||
+	    	name.encoding_id != charmap->encoding_id)
+	    continue;
 	    
-	    case TT_NAME_ID_PS_NAME:
+	if (name.name_id != name_id)
+	    continue;
 	    
-	    	if (NameTableString(&(str->FontName), &name) == FALSE)
-		    return FALSE;
-		afm->FontName = str->FontName;
-		break;
-	}
+	return MSTTStrToSz(&name, p_sz);
     }
     
+    *p_sz = NULL;   	    	    /* didn't find it */
+    
     return TRUE;
 }
 
@@ -266,50 +239,49 @@
  *  PSUnits
  *
  *  Convert TrueType font units (relative to font em square) to PostScript
- *  units.  This is defined as a macro, so it can handle different TrueType
- *  data types as inputs.
+ *  units.
  *
  */
-#define PSUnits(x)  (((float)(x)) * 1000.0 / ((float)(head->Units_Per_EM)))
+inline static float PSUnits(LONG x, USHORT em_size)
+{
+    return 1000.0 * (float)x / (float)em_size;
+}
 
 /*******************************************************************************
- *  ReadMetricsTables
+ *  StartAFM
  *
- *  Reads basic font metrics from the 'head', 'post', and 'OS/2' tables.
- *  Returns FALSE if any table is missing.
+ *  Allocates space for the AFM on the driver heap and reads basic font metrics
+ *  from the HEAD, POST, HHEA, and OS/2 tables.  Returns FALSE for memory
+ *  allocation error; sets *p_afm to NULL if required information is missing.
  *
- */ 
-static BOOL ReadMetricsTables(AFM *afm)
+ */
+static BOOL StartAFM(FT_Face face, AFM **p_afm)
 {
+    TT_Header	    *head;
+    TT_Postscript   *post;
+    TT_OS2  	    *os2;
+    TT_HoriHeader   *hhea;
+    USHORT  	    em_size;
+    AFM     	    *afm;
+    
     head = FT_Get_Sfnt_Table(face, ft_sfnt_head);
     post = FT_Get_Sfnt_Table(face, ft_sfnt_post);
-    hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
     os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
+    hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
     
-    if (head == NULL || post == NULL || hhea == NULL || os2 == NULL)
-	return FALSE;
-    
-    if (os2->version == 0xffff)     	    /* Old Macintosh font */
-	return FALSE;
-    
-    afm->Weight = os2->usWeightClass;
-    afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
-    afm->IsFixedPitch = (post->isFixedPitch == 0) ? FALSE : TRUE;
-    afm->UnderlinePosition = PSUnits(post->underlinePosition);
-    afm->UnderlineThickness = PSUnits(post->underlineThickness);
-	    
-    afm->FontBBox.llx = PSUnits(head->xMin);
-    afm->FontBBox.lly = PSUnits(head->yMin);
-    afm->FontBBox.urx = PSUnits(head->xMax);
-    afm->FontBBox.ury = PSUnits(head->yMax);
-    
-    /* CapHeight & XHeight set by ReadCharMetrics */
+    if (head == NULL || post == NULL || os2 == NULL || hhea == NULL ||
+    	    os2->version == 0xffff) 	    	    	/* old Macintosh font */
+    {
+    	WARN("Required table(s) missing\n");
+	*p_afm = NULL;
+	return TRUE;
+    }
     
-    afm->Ascender = PSUnits(os2->sTypoAscender);
-    afm->Descender = PSUnits(os2->sTypoDescender);
-    afm->FullAscender = afm->FontBBox.ury;  	    /* get rid of this */
+    *p_afm = afm = HeapAlloc(PSDRV_Heap, 0, sizeof(*afm));
+    if (afm == NULL)
+    	return FALSE;
     
-    afm->WinMetrics.usUnitsPerEm = head->Units_Per_EM;
+    afm->WinMetrics.usUnitsPerEm = em_size = head->Units_Per_EM;
     afm->WinMetrics.sAscender = hhea->Ascender;
     afm->WinMetrics.sDescender = hhea->Descender;
     afm->WinMetrics.sLineGap = hhea->Line_Gap;
@@ -319,6 +291,23 @@
     afm->WinMetrics.usWinAscent = os2->usWinAscent;
     afm->WinMetrics.usWinDescent = os2->usWinDescent;
     afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
+        
+    afm->Weight = os2->usWeightClass;
+    afm->ItalicAngle = ((float)(post->italicAngle)) / 65536.0;
+    afm->IsFixedPitch = (post-> isFixedPitch == 0) ? FALSE : TRUE;
+    afm->UnderlinePosition = PSUnits(post->underlinePosition, em_size);
+    afm->UnderlineThickness = PSUnits(post->underlineThickness, em_size);
+
+    afm->FontBBox.llx = PSUnits(head->xMin, em_size);
+    afm->FontBBox.lly = PSUnits(head->yMin, em_size);
+    afm->FontBBox.urx = PSUnits(head->xMax, em_size);
+    afm->FontBBox.ury = PSUnits(head->yMax, em_size);
+    
+    afm->Ascender = PSUnits(os2->sTypoAscender, em_size);
+    afm->Descender = PSUnits(os2->sTypoDescender, em_size);
+    afm->FullAscender = afm->FontBBox.ury;  	    	/* get rid of this */
+    
+    /* CapHeight & XHeight set by ReadCharMetrics */
     
     return TRUE;
 }
@@ -326,43 +315,38 @@
 /*******************************************************************************
  *  ReadCharMetrics
  *
- *  Reads metrics for each glyph in a TrueType font.
+ *  Reads metrics for each glyph in a TrueType font.  Returns false for memory
+ *  allocation or FreeType error; sets *p_metrics to NULL for non-fatal error.
  *
  */
-static AFMMETRICS *ReadCharMetrics(AFM *afm)
+static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics)
 {
-    FT_ULong	    charcode, index;
-    AFMMETRICS	    *metrics;
+    FT_ULong	charcode, index;
+    AFMMETRICS	*metrics;
+    USHORT  	em_size = afm->WinMetrics.usUnitsPerEm;
     
-    /*
-     *	There does not seem to be an easy way to get the number of characters
-     *	in an encoding out of a TrueType font.
-     */
     for (charcode = 0, index = 0; charcode < 65536; ++charcode)
-    {
     	if (FT_Get_Char_Index(face, charcode) != 0)
-	    ++index;
-    }
-    
+	    ++index;	    	    	    	    	/* count # of glyphs */
+	    
     afm->NumofMetrics = index;
     
-    metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(AFMMETRICS));
+    *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics));
     if (metrics == NULL)
-    	return NULL;
+    	return FALSE;
 	
-    for (charcode = 0, index = 0; charcode <= 65536; ++charcode)
+    for (charcode = 0, index = 0; charcode < 65536; ++charcode)
     {
     	FT_UInt     glyph_index = FT_Get_Char_Index(face, charcode);
 	FT_Error    error;
 	FT_Glyph    glyph;
 	FT_BBox     bbox;
-	char	    buffer[256];
+	CHAR	    buffer[128];  	    	/* for glyph names */
 	
 	if (glyph_index == 0)
 	    continue;
 	    
-	error = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE |
-	    	FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_LINEAR_DESIGN);
+	error = FT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS);
 	if (error != FT_Err_Ok)
 	{
 	    ERR("%s returned %i\n", "FT_Load_Glyph", error);
@@ -378,278 +362,256 @@
 	
 	FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
 	
-	error = FT_Get_Glyph_Name(face, glyph_index, buffer, 255);
+	error = FT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer));
 	if (error != FT_Err_Ok)
 	{
 	    ERR("%s returned %i\n", "FT_Get_Glyph_Name", error);
 	    goto cleanup;
-	}
+    	}
 	
 	metrics[index].N = PSDRV_GlyphName(buffer);
 	if (metrics[index].N == NULL)
-	    goto cleanup;;
-	
-	metrics[index].C = charcode;
-	metrics[index].UV = charcode;
-	metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance);
-	metrics[index].B.llx = PSUnits(bbox.xMin);
-	metrics[index].B.lly = PSUnits(bbox.yMin);
-	metrics[index].B.urx = PSUnits(bbox.xMax);
-	metrics[index].B.ury = PSUnits(bbox.yMax);
+	    goto cleanup;
+	    
+	metrics[index].C = metrics[index].UV = charcode;
+	metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size);
+	metrics[index].B.llx = PSUnits(bbox.xMin, em_size);
+	metrics[index].B.lly = PSUnits(bbox.yMin, em_size);
+	metrics[index].B.urx = PSUnits(bbox.xMax, em_size);
+	metrics[index].B.ury = PSUnits(bbox.yMax, em_size);
 	metrics[index].L = NULL;
 	
-	TRACE("Metrics for '%s' WX = %f B = %f,%f - %f,%f\n",
-	    	metrics[index].N->sz, metrics[index].WX,
-		metrics[index].B.llx, metrics[index].B.lly,
-		metrics[index].B.urx, metrics[index].B.ury);
-	
 	if (charcode == 0x0048)     	    	    /* 'H' */
-	    afm->CapHeight = PSUnits(bbox.yMax);
+	    afm->CapHeight = metrics[index].B.ury;
 	if (charcode == 0x0078)     	    	    /* 'x' */
-	    afm->XHeight = PSUnits(bbox.yMax);
-		
+	    afm->XHeight = metrics[index].B.ury;
+	    
 	++index;
     }
     
-    return metrics;
+    if (afm->WinMetrics.sAvgCharWidth == 0)
+    	afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
+	
+    return TRUE;
     
     cleanup:
-    
     	HeapFree(PSDRV_Heap, 0, metrics);
-	return NULL;
+    
+    return FALSE;
 }
 
 /*******************************************************************************
- *  ReadTrueTypeAFM
+ *  BuildTrueTypeAFM
  *
- *  Fills in AFM structure for opened TrueType font file.  Returns FALSE only on
- *  an unexpected error (memory allocation failure or FreeType error); otherwise
- *  returns TRUE.
+ *  Builds the AFM for a TrueType font and adds it to the driver font list.
+ *  Returns FALSE only on an unexpected error (memory allocation failure or
+ *  FreeType error).
  *
  */
-static BOOL ReadTrueTypeAFM(AFM *afm)
+static BOOL BuildTrueTypeAFM(FT_Face face)
 {
-    AFMSTRINGS	str = { NULL, NULL, NULL, NULL };
+    AFM     	*afm;
     AFMMETRICS	*metrics;
-
-    if ((face->face_flags & REQUIRED_FACE_FLAGS) != REQUIRED_FACE_FLAGS)
-    {
-    	WARN("Font flags do not match requirements\n");
-	return TRUE;
-    }
+    LPSTR   	font_name, full_name, family_name, encoding_scheme;
+    FT_CharMap	charmap;
+    BOOL    	retval, added;
+    
+    retval = StartAFM(face, &afm);
+    if (retval == FALSE || afm == NULL)
+    	return retval;
+    
+    retval = FindCharMap(face, &charmap, &encoding_scheme);
+    if (retval == FALSE || charmap == NULL)
+    	goto cleanup_afm;
+	
+    retval = FindMSTTString(face, charmap, TT_NAME_ID_PS_NAME, &font_name);
+    if (retval == FALSE || font_name == NULL)
+    	goto cleanup_encoding_scheme;
+	
+    retval = FindMSTTString(face, charmap, TT_NAME_ID_FULL_NAME, &full_name);
+    if (retval == FALSE || full_name == NULL)
+    	goto cleanup_font_name;
+	
+    retval = FindMSTTString(face, charmap, TT_NAME_ID_FONT_FAMILY,
+    	    &family_name);
+    if (retval == FALSE || family_name == NULL)
+    	goto cleanup_full_name;
+	
+    retval = ReadCharMetrics(face, afm, &metrics);
+    if (retval == FALSE || metrics == NULL)
+    	goto cleanup_family_name;
+	
+    afm->EncodingScheme = encoding_scheme; afm->FontName = font_name;
+    afm->FullName = full_name; afm->FamilyName = family_name;
+    afm->Metrics = metrics;
+	
+    retval = PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm, &added);
+    if (retval == FALSE || added == FALSE)
+    	goto cleanup_family_name;
+	
+    return TRUE;
     
-    if (FindCharMap(afm, &str) == FALSE)
-    	return FALSE;
+    /* clean up after fatal or non-fatal errors */
 	
-    if (charmap == NULL)
+    cleanup_family_name:
+    	HeapFree(PSDRV_Heap, 0, family_name);
+    cleanup_full_name:
+    	HeapFree(PSDRV_Heap, 0, full_name);
+    cleanup_font_name:
+    	HeapFree(PSDRV_Heap, 0, font_name);
+    cleanup_encoding_scheme:
+    	HeapFree(PSDRV_Heap, 0, encoding_scheme);
+    cleanup_afm:
+    	HeapFree(PSDRV_Heap, 0, afm);
+	
+    return retval;
+}
+				    
+/*******************************************************************************
+ *  ReadTrueTypeFile
+ *
+ *  Reads font metrics from TrueType font file.  Only returns FALSE for
+ *  unexpected errors (memory allocation failure or FreeType error).
+ *
+ */
+static BOOL ReadTrueTypeFile(FT_Library library, LPCSTR filename)
+{
+    FT_Error	    error;
+    FT_Face 	    face;
+    
+    TRACE("%s\n", filename);
+    
+    error = FT_New_Face(library, filename, 0, &face);
+    if (error != FT_Err_Ok)
     {
-    	WARN("No Windows encodings in font\n");
+    	WARN("FreeType error %i opening %s\n", error, filename);
 	return TRUE;
     }
     
-    TRACE("Using encoding '%s'\n", afm->EncodingScheme);
-
-    if (ReadNameTable(afm, &str) == FALSE)
-    {
-    	if (str.FontName != NULL)   HeapFree(PSDRV_Heap, 0, str.FontName);
-	if (str.FullName != NULL)   HeapFree(PSDRV_Heap, 0, str.FullName);
-	if (str.FamilyName != NULL) HeapFree(PSDRV_Heap, 0, str.FamilyName);
-	HeapFree(PSDRV_Heap, 0, str.EncodingScheme);
-    	return FALSE;
-    }
-   
-    if (str.FamilyName == NULL || str.FullName == NULL || str.FontName == NULL)
+    if ((face->face_flags & REQUIRED_FACE_FLAGS) == REQUIRED_FACE_FLAGS)
     {
-    	WARN("Required strings missing from font\n");
-    	if (str.FontName != NULL)   HeapFree(PSDRV_Heap, 0, str.FontName);
-	if (str.FullName != NULL)   HeapFree(PSDRV_Heap, 0, str.FullName);
-	if (str.FamilyName != NULL) HeapFree(PSDRV_Heap, 0, str.FamilyName);
-	HeapFree(PSDRV_Heap, 0, str.EncodingScheme);
-	return TRUE;
+    	if (BuildTrueTypeAFM(face) == FALSE)
+	{
+	    FT_Done_Face(face);
+	    return FALSE;
+	}
     }
-
-    if (ReadMetricsTables(afm) == FALSE)    /* Non-fatal */
+    else
     {
-    	WARN("Required metrics tables missing from font\n");
-	return TRUE;
+    	WARN("Required information missing from %s\n", filename);
     }
     
-    afm->Metrics = metrics = ReadCharMetrics(afm);
-    if (metrics == NULL)
-    {
-    	HeapFree(PSDRV_Heap, 0, str.FontName);
-	HeapFree(PSDRV_Heap, 0, str.FullName);
-	HeapFree(PSDRV_Heap, 0, str.FamilyName);
-	HeapFree(PSDRV_Heap, 0, str.EncodingScheme);
-    	return FALSE;
-    }
-
-    /* Can't do this check until character metrics are read */
-
-    if (afm->WinMetrics.sAvgCharWidth == 0)
-    	afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
-	
-    if (PSDRV_AddAFMtoList(&PSDRV_AFMFontList, afm) == FALSE)
+    error = FT_Done_Face(face);
+    if (error != FT_Err_Ok)
     {
-    	HeapFree(PSDRV_Heap, 0, str.FontName);
-	HeapFree(PSDRV_Heap, 0, str.FullName);
-	HeapFree(PSDRV_Heap, 0, str.FamilyName);
-	HeapFree(PSDRV_Heap, 0, str.EncodingScheme);
-    	HeapFree(PSDRV_Heap, 0, metrics);
+    	ERR("%s returned %i\n", "FT_Done_Face", error);
 	return FALSE;
     }
-
+    
     return TRUE;
 }
 
 /*******************************************************************************
- *  ReadTrueTypeFile
+ *  ReadTrueTypeDir
  *
- *  Reads PostScript-style font metrics from a TrueType font file.  Only returns
- *  FALSE for unexpected errors (memory allocation, etc.); returns TRUE if it's
- *  just a bad font file.
+ *  Reads all TrueType font files in a directory.
  *
  */
-static BOOL ReadTrueTypeFile(LPCSTR filename)
+static BOOL ReadTrueTypeDir(FT_Library library, LPCSTR dirname)
 {
-    FT_Error	error;
-    AFM  	*afm;
+    struct dirent   *dent;
+    DIR     	    *dir;
+    CHAR    	    filename[256];
     
-    TRACE("'%s'\n", filename);
-
-    afm = HeapAlloc(PSDRV_Heap, HEAP_ZERO_MEMORY, sizeof(AFM));
-    if (afm == NULL)
-    	return FALSE;
-
-    error = FT_New_Face(library, filename, 0, &face);
-    if (error != FT_Err_Ok)
+    dir = opendir(dirname);
+    if (dir == NULL)
     {
-    	WARN("FreeType error %i opening '%s'\n", error, filename);
-	HeapFree(PSDRV_Heap, 0, afm);
-	return TRUE;
+    	WARN("'%s' opening %s\n", strerror(errno), dirname);
+	return TRUE;;
     }
     
-    if (ReadTrueTypeAFM(afm) == FALSE)
-    {
-    	HeapFree(PSDRV_Heap, 0, afm);
-	FT_Done_Face(face);
-	return FALSE;
-    }    
-
-    error = FT_Done_Face(face);
-    if (error != FT_Err_Ok)
+    while ((dent = readdir(dir)) != NULL)
     {
-    	ERR("%s returned %i\n", "FT_Done_Face", error);
-	HeapFree(PSDRV_Heap, 0, afm);
-	return FALSE;
+    	CHAR	    *file_extension = strrchr(dent->d_name, '.');
+	int 	    fn_len;
+	
+	if (file_extension == NULL || strcasecmp(file_extension, ".ttf") != 0)
+	    continue;
+	    
+	fn_len = snprintf(filename, 256, "%s/%s", dirname, dent->d_name);
+	if (fn_len < 0 || fn_len > sizeof(filename) - 1)
+	{
+	    WARN("Path '%s/%s' is too long\n", dirname, dent->d_name);
+	    continue;
+	}
+	
+	if (ReadTrueTypeFile(library, filename) ==  FALSE)
+	{
+	    closedir(dir);
+	    return FALSE;
+	}
     }
     
-    if (afm->Metrics == NULL)	    	    	/* last element to be set */
-    {
-    	HeapFree(PSDRV_Heap, 0, afm);
-	return TRUE;
-    }
+    closedir(dir);
     
     return TRUE;
 }
-    
-
-
+			    
 /*******************************************************************************
  *  PSDRV_GetTrueTypeMetrics
  *
- *  Reads PostScript-stype font metrics from TrueType font files in directories
- *  listed in the [TrueType Font Directories] section of the Wine configuration
- *  file.
- *
- *  If this function fails, the driver will fail to initialize and the driver
- *  heap will be destroyed, so it's not necessary to HeapFree everything in
- *  that event.
+ *  Reads font metrics from TrueType font files in directories listed in the
+ *  [TrueType Font Directories] section of the Wine configuration file.
+ *
+ *  If this function fails (returns FALSE), the driver will fail to initialize
+ *  and the driver heap will be destroyed, so it's not necessary to HeapFree
+ *  everything in that event.
  *
  */
 BOOL PSDRV_GetTrueTypeMetrics(void)
 {
-    CHAR    	keybuf[256], namebuf[256];
+    CHAR    	name_buf[256], value_buf[256];
     INT     	i = 0;
     FT_Error	error;
+    FT_Library	library;
     HKEY    	hkey;
-    DWORD   	type, key_len, name_len;
+    DWORD   	type, name_len, value_len;
+
+    if(RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+    	    "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
+	    0, KEY_READ, &hkey) != ERROR_SUCCESS)
+	return TRUE;
 
     error = FT_Init_FreeType(&library);
     if (error != FT_Err_Ok)
     {
     	ERR("%s returned %i\n", "FT_Init_FreeType", error);
+	RegCloseKey(hkey);
 	return FALSE;
     }
 
-    if(RegOpenKeyExA(HKEY_LOCAL_MACHINE,
-    	    "Software\\Wine\\Wine\\Config\\TrueType Font Directories",
-	    0, KEY_READ, &hkey) != ERROR_SUCCESS)
-	goto no_metrics;
-
-    key_len = sizeof(keybuf);
-    name_len = sizeof(namebuf);
+    name_len = sizeof(name_buf);
+    value_len = sizeof(value_buf);
     
-    while(RegEnumValueA(hkey, i++, keybuf, &key_len, NULL, &type, namebuf,
-    	    &name_len) == ERROR_SUCCESS)
+    while(RegEnumValueA(hkey, i++, name_buf, &name_len, NULL, &type, value_buf,
+    	    &value_len) == ERROR_SUCCESS)
     {
-    	struct dirent	*dent;
-    	DIR 	    	*dir;
-	INT 	    	dnlen;	    /* directory name length */
-
-    	namebuf[sizeof(namebuf) - 1] = '\0';
-    	dir = opendir(namebuf);
-	if (dir == NULL)
-	{
-	    WARN("Error opening directory '%s'\n", namebuf);
-	    continue;
-	}
-	
-	dnlen = strlen(namebuf);
-	namebuf[dnlen] = '/';	    	/* 2 slashes is OK, 0 is not */
-	++dnlen;
+    	value_buf[sizeof(value_buf) - 1] = '\0';
 	
-	while ((dent = readdir(dir)) != NULL)
+	if (ReadTrueTypeDir(library, value_buf) == FALSE)
 	{
-	    INT fnlen;	    /* file name length */
-	    
-	    fnlen = strlen(dent->d_name);
-	    
-	    if (fnlen < 5 || strcasecmp(dent->d_name + fnlen - 4, ".ttf") != 0)
-	    {
-	    	TRACE("Skipping filename '%s'\n", dent->d_name);
-		continue;
-	    }
-	    
-	    if (dnlen + fnlen + 1 > sizeof(namebuf))	/* allow for '\0' */
-	    {
-	    	WARN("Path '%s/%s' is too long\n", namebuf, dent->d_name);
-		continue;
-	    }
-	    
-	    memcpy(namebuf + dnlen, dent->d_name, fnlen + 1);
-	    
-	    if (ReadTrueTypeFile(namebuf) == FALSE)
-	    {
-	    	ERR("Error reading '%s'\n", namebuf);
-	    	closedir(dir);
-		RegCloseKey(hkey);
-		FT_Done_FreeType(library);
-		return FALSE;
-	    }
+	    RegCloseKey(hkey);
+	    FT_Done_FreeType(library);
+	    return FALSE;
 	}
 	
-	closedir(dir);
-
 	/* initialize lengths for new iteration */
-	key_len = sizeof(keybuf);
-	name_len = sizeof(namebuf);
+	
+	name_len = sizeof(name_buf);
+	value_len = sizeof(value_buf);
     }
     
     RegCloseKey(hkey);
-
-    no_metrics:
-    
     FT_Done_FreeType(library);
     return TRUE;
 }


More information about the wine-patches mailing list