From 42e052d40580eaba09aab41e805f9ed710d72257 Mon Sep 17 00:00:00 2001 From: Ian Pilcher Date: Thu, 26 Jul 2001 21:42:45 +0000 Subject: [PATCH] Rewrite TrueType font metric parsing code. --- dlls/wineps/afm.c | 33 ++- dlls/wineps/init.c | 3 +- dlls/wineps/ps.c | 2 + dlls/wineps/psdrv.h | 3 +- dlls/wineps/truetype.c | 664 +++++++++++++++++++++++-------------------------- 5 files changed, 342 insertions(+), 363 deletions(-) diff --git a/dlls/wineps/afm.c b/dlls/wineps/afm.c index 861ce3fc859..6ca61f2d01b 100644 --- a/dlls/wineps/afm.c +++ b/dlls/wineps/afm.c @@ -497,10 +497,13 @@ const AFM *PSDRV_FindAFMinList(FONTFAMILY *head, char *name) * * 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 @@ BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm) } strcpy( family->FamilyName, afm->FamilyName ); family->afmlist = newafmle; + *p_added = TRUE; return TRUE; } else { @@ -543,6 +547,7 @@ BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm) 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 @@ BOOL PSDRV_AddAFMtoList(FONTFAMILY **head, const AFM *afm) tmpafmle->next = newafmle; + *p_added = TRUE; return TRUE; } @@ -834,14 +840,19 @@ static VOID CalcWindowsMetrics(AFM *afm) 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 AddBuiltinAFMs() static BOOL PSDRV_ReadAFMDir(const char* afmdir) { DIR *dir; const AFM *afm; + BOOL added; dir = opendir(afmdir); if (dir) { @@ -881,7 +893,7 @@ static BOOL PSDRV_ReadAFMDir(const char* afmdir) { 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 @@ BOOL PSDRV_GetFontMetrics(void) char value[256]; HKEY hkey; DWORD type, key_len, value_len; + BOOL added; if (PSDRV_GlyphListInit() != 0) return FALSE; @@ -924,7 +937,7 @@ BOOL PSDRV_GetFontMetrics(void) 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 --git a/dlls/wineps/init.c b/dlls/wineps/init.c index 0d45106b016..00f28040667 100644 --- a/dlls/wineps/init.c +++ b/dlls/wineps/init.c @@ -620,7 +620,8 @@ PRINTERINFO *PSDRV_FindPrinterInfo(LPCSTR name) "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 --git a/dlls/wineps/ps.c b/dlls/wineps/ps.c index dd613186a78..64e27b0cb9c 100644 --- a/dlls/wineps/ps.c +++ b/dlls/wineps/ps.c @@ -112,8 +112,10 @@ static char psrrectangle[] = /* x, y, width, height, -width */ "%d 0 rlineto\n" "closepath\n"; +#if 0 static char psshow[] = /* string */ "(%s) show\n"; +#endif static const char psglyphshow[] = /* glyph name */ "/%s glyphshow\n"; diff --git a/dlls/wineps/psdrv.h b/dlls/wineps/psdrv.h index 4d0e3933113..8aa1f35b368 100644 --- a/dlls/wineps/psdrv.h +++ b/dlls/wineps/psdrv.h @@ -298,7 +298,8 @@ extern BOOL PSDRV_GetFontMetrics(void); 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 --git a/dlls/wineps/truetype.c b/dlls/wineps/truetype.c index fa3d5d08776..8da8b0cfffe 100644 --- a/dlls/wineps/truetype.c +++ b/dlls/wineps/truetype.c @@ -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 #include #include +#include #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 @@ static const char *encoding_names[7] = "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 @@ static BOOL FindCharMap(AFM *afm, AFMSTRINGS *str) 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 - * - * Converts a name table string to a null-terminated character string. The - * space for the character string is allocated from the driver heap. + * MSTTStrToSz * - * This function handles only platform_id = 3 (TT_PLATFORM_MICROSOFT) -- 16-bit - * big-endian strings. It also only handles ASCII character codes (< 128). + * 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 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 @@ static BOOL NameTableString(LPSTR *sz, const FT_SfntName *name) 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; - for (stringIndex = 0; stringIndex < numStrings; ++stringIndex) + num_strings = FT_Get_Sfnt_Name_Count(face); + + 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 @@ static BOOL ReadNameTable(AFM *afm, AFMSTRINGS *str) /* 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 @@ static BOOL ReadNameTable(AFM *afm, AFMSTRINGS *str) * 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 @@ static BOOL ReadMetricsTables(AFM *afm) 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 @@ static BOOL ReadMetricsTables(AFM *afm) /******************************************************************************* * 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 @@ static AFMMETRICS *ReadCharMetrics(AFM *afm) 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; - if (FindCharMap(afm, &str) == FALSE) - return FALSE; + 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; - if (charmap == NULL) + 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; + + /* clean up after fatal or non-fatal errors */ + + 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) + while ((dent = readdir(dir)) != NULL) { - HeapFree(PSDRV_Heap, 0, afm); - FT_Done_Face(face); - return FALSE; - } - - error = FT_Done_Face(face); - if (error != FT_Err_Ok) - { - 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. + * 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, the driver will fail to initialize and the driver - * heap will be destroyed, so it's not necessary to HeapFree everything in - * that event. + * 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; - } + value_buf[sizeof(value_buf) - 1] = '\0'; - dnlen = strlen(namebuf); - namebuf[dnlen] = '/'; /* 2 slashes is OK, 0 is not */ - ++dnlen; - - 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; } -- 2.11.4.GIT