From 657c4afaec46061ebf0be073e84a0164a09bca7f Mon Sep 17 00:00:00 2001 From: Ian Pilcher Date: Wed, 9 May 2001 17:11:59 +0000 Subject: [PATCH] Unicode encodings for PostScript fonts. --- dlls/wineps/afm.c | 201 ++++++++++++++++++++++++++++++++++++++-- dlls/wineps/agl.c | 2 +- dlls/wineps/glyphlist.c | 11 ++- dlls/wineps/psdrv.h | 44 +++++---- 4 files changed, 227 insertions(+), 31 deletions(-) diff --git a/dlls/wineps/afm.c b/dlls/wineps/afm.c index 10b3074c86a..9b78c2ae9a4 100644 --- a/dlls/wineps/afm.c +++ b/dlls/wineps/afm.c @@ -7,6 +7,7 @@ */ #include +#include /* qsort() & bsearch() */ #include #include #include @@ -28,12 +29,13 @@ FONTFAMILY *PSDRV_AFMFontList = NULL; * CheckMetrics * * Check an AFMMETRICS structure to make sure all elements have been properly - * filled in. + * filled in. (Don't check UV or L.) * */ static const AFMMETRICS badMetrics = { INT_MIN, /* C */ + INT_MIN, /* UV */ FLT_MAX, /* WX */ NULL, /* N */ { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX }, /* B */ @@ -55,9 +57,10 @@ inline static BOOL CheckMetrics(const AFMMETRICS *metrics) } /******************************************************************************* - * FreeAFM + * FreeAFM * - * Free an AFM structure and any subsidiary objects that have been allocated + * Free an AFM structure and any subsidiary objects that have been allocated. + * AFM must have been allocated with HEAP_ZERO_MEMORY. * */ static void FreeAFM(AFM *afm) @@ -76,7 +79,6 @@ static void FreeAFM(AFM *afm) HeapFree(PSDRV_Heap, 0, afm); } - /*********************************************************** * * PSDRV_AFMGetCharMetrics @@ -191,6 +193,55 @@ static BOOL PSDRV_AFMGetCharMetrics(AFM *afm, FILE *fp) return TRUE; } +/******************************************************************************* + * BuildEncoding + * + * Builds a custom encoding vector if necessary. Leaves vector in the same + * order as the afm->Metrics array; see SortFontMetrics(). + * + */ +static BOOL BuildEncoding(AFM *afm) +{ + UNICODEVECTOR *uv; + UNICODEGLYPH *ug; + int i; + + if (strcmp(afm->EncodingScheme, "FontSpecific") != 0) + { + afm->Encoding = &PSDRV_AdobeGlyphList; + return TRUE; + } + + uv = HeapAlloc(PSDRV_Heap, 0, sizeof(UNICODEVECTOR) + + afm->NumofMetrics * sizeof(UNICODEGLYPH)); + if (uv == NULL) + return FALSE; + + afm->Encoding = uv; + ug = (UNICODEGLYPH *)(uv + 1); + uv->glyphs = ug; + uv->size = afm->NumofMetrics; + + for (i = 0; i < afm->NumofMetrics; ++i) + { + ug[i].name = afm->Metrics[i].N; + + if (afm->Metrics[i].C < 0) /* unencoded glyph */ + { + WARN("Glyph '%s' in font '%s' has no encoding\n", ug[i].name->sz, + afm->FullName); + ug[i].UV = -1; + } + else + { + ug[i].UV = afm->Metrics[i].C | 0xf000; /* private use area? */ + } + } + + return TRUE; +} + + /*********************************************************** * * PSDRV_AFMParse @@ -410,6 +461,12 @@ static AFM *PSDRV_AFMParse(char const *file) afm->FullAscender = afm->Ascender; if(afm->Weight == 0) afm->Weight = FW_NORMAL; + + if (BuildEncoding(afm) == FALSE) + { + FreeAFM(afm); + return NULL; + } return afm; } @@ -554,18 +611,141 @@ static void PSDRV_ReencodeCharWidths(AFM *afm) */ static void PSDRV_DumpFontList(void) { - FONTFAMILY *family; - AFMLISTENTRY *afmle; + FONTFAMILY *family; + AFMLISTENTRY *afmle; for(family = PSDRV_AFMFontList; family; family = family->next) { TRACE("Family '%s'\n", family->FamilyName); - for(afmle = family->afmlist; afmle; afmle = afmle->next) { - TRACE("\tFontName '%s'\n", afmle->afm->FontName); + for(afmle = family->afmlist; afmle; afmle = afmle->next) + { + INT i; + + TRACE("\tFontName '%s' (%i glyphs):\n", afmle->afm->FontName, + afmle->afm->NumofMetrics); + + for (i = 0; i < afmle->afm->NumofMetrics; ++i) + { + TRACE("\t\tU+%.4lX; C %i; N '%s'\n", afmle->afm->Metrics[i].UV, + afmle->afm->Metrics[i].C, afmle->afm->Metrics[i].N->sz); + } } } return; } +/******************************************************************************* + * SortFontMetrics + * + * Initializes the UV member of each glyph's AFMMETRICS and sorts each font's + * Metrics by Unicode Value. + * + */ +static int UnicodeGlyphByNameIndex(const UNICODEGLYPH *a, const UNICODEGLYPH *b) +{ + return a->name->index - b->name->index; +} + +static int UnicodeGlyphByUV(const UNICODEGLYPH *a, const UNICODEGLYPH *b) +{ + return a->UV - b->UV; +} + +static int AFMMetricsByUV(const AFMMETRICS *a, const AFMMETRICS *b) +{ + return a->UV - b->UV; +} + +static BOOL SortFontMetrics() +{ + UNICODEGLYPH *aglCopy = NULL; + FONTFAMILY *family = PSDRV_AFMFontList; + + while (family != NULL) + { + AFMLISTENTRY *afmle = family->afmlist; + + while (afmle != NULL) + { + AFM *afm = afmle->afm; /* should always be valid */ + INT i; + + if (afm->Encoding == &PSDRV_AdobeGlyphList) + { + if (aglCopy == NULL) /* do this once, if necessary */ + { + aglCopy = HeapAlloc(PSDRV_Heap, 0, + PSDRV_AdobeGlyphList.size * sizeof(UNICODEGLYPH)); + if (aglCopy == NULL) + return FALSE; + + memcpy(aglCopy, PSDRV_AdobeGlyphList.glyphs, + PSDRV_AdobeGlyphList.size * sizeof(UNICODEGLYPH)); + + qsort(aglCopy, PSDRV_AdobeGlyphList.size, + sizeof(UNICODEGLYPH), + (__compar_fn_t)UnicodeGlyphByNameIndex); + } + + for (i = 0; i < afm->NumofMetrics; ++i) + { + UNICODEGLYPH ug, *pug; + + ug.name = afm->Metrics[i].N; + ug.UV = -1; + + pug = bsearch(&ug, aglCopy, PSDRV_AdobeGlyphList.size, + sizeof(UNICODEGLYPH), + (__compar_fn_t)UnicodeGlyphByNameIndex); + if (pug == NULL) + { + WARN("Glyph '%s' in font '%s' does not have a UV\n", + ug.name->sz, afm->FullName); + afm->Metrics[i].UV = -1; + } + else + { + afm->Metrics[i].UV = pug->UV; + } + } + } + else /* FontSpecific encoding or TrueType font */ + { + for (i = 0; i < afm->NumofMetrics; ++i) + afm->Metrics[i].UV = afm->Encoding->glyphs[i].UV; + + /* typecast avoids compiler warning */ + qsort((void *)(afm->Encoding->glyphs), afm->Encoding->size, + sizeof(UNICODEGLYPH), (__compar_fn_t)UnicodeGlyphByUV); + + for (i = 0; i < afm->Encoding->size; ++i) + if (afm->Encoding->glyphs[i].UV >= 0) + break; + + afm->Encoding->size -= i; /* Ignore unencoded glyphs */ + afm->Encoding->glyphs += i; /* from now on */ + } + + qsort(afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS), + (__compar_fn_t)AFMMetricsByUV); + + for (i = 0; i < afm->NumofMetrics; ++i) + if (afm->Metrics[i].UV >= 0) + break; + + afm->NumofMetrics -= i; /* Ignore unencoded glyphs here too */ + afm->Metrics += i; + + afmle = afmle->next; + } + + family = family->next; + } + + if (aglCopy != NULL) + HeapFree(PSDRV_Heap, 0, aglCopy); + + return TRUE; +} /*********************************************************** * @@ -658,8 +838,9 @@ BOOL PSDRV_GetFontMetrics(void) if (PSDRV_ReadAFMDir (value) == FALSE) return FALSE; - PSDRV_DumpGlyphList(); + PSDRV_IndexGlyphList(); + if (SortFontMetrics() == FALSE) + return FALSE; PSDRV_DumpFontList(); return TRUE; } - diff --git a/dlls/wineps/agl.c b/dlls/wineps/agl.c index 0c178105395..fba48384ab8 100644 --- a/dlls/wineps/agl.c +++ b/dlls/wineps/agl.c @@ -3179,4 +3179,4 @@ static const UNICODEGLYPH encoding[1051] = { 0xfb4b, PSDRV_AGLGlyphNames + 515 } /* afii57700 */ }; -const UNICODEVECTOR PSDRV_AdobeGlyphList = { 1051, encoding }; +UNICODEVECTOR PSDRV_AdobeGlyphList = { 1051, encoding }; diff --git a/dlls/wineps/glyphlist.c b/dlls/wineps/glyphlist.c index 4d2d7682468..4a38d90f637 100644 --- a/dlls/wineps/glyphlist.c +++ b/dlls/wineps/glyphlist.c @@ -158,7 +158,7 @@ static INT GlyphListSearch(LPCSTR szName, INT loIndex, INT hiIndex) * necessary, and returns a pointer to it (NULL if unable to add it) * */ -const GLYPHNAME *PSDRV_GlyphName(LPCSTR szName) +GLYPHNAME *PSDRV_GlyphName(LPCSTR szName) { INT index; @@ -172,17 +172,20 @@ const GLYPHNAME *PSDRV_GlyphName(LPCSTR szName) } /******************************************************************************* - * PSDRV_DumpGlyphList + * PSDRV_IndexGlyphList * - * Print contents of glyph list for debugging purposes + * Initializes index member of all GLYPHNAME structures * */ -VOID PSDRV_DumpGlyphList() +VOID PSDRV_IndexGlyphList() { INT i; TRACE("%i glyph names:\n", glyphListSize); for (i = 0; i < glyphListSize; ++i) + { + glyphList[i]->index = i; TRACE(" glyphList[%i] -> '%s'\n", i, glyphList[i]->sz); + } } diff --git a/dlls/wineps/psdrv.h b/dlls/wineps/psdrv.h index 2c45f41ee52..b9a07af5b4d 100644 --- a/dlls/wineps/psdrv.h +++ b/dlls/wineps/psdrv.h @@ -15,23 +15,23 @@ #include "winspool.h" typedef struct { - INT index; - LPCSTR sz; + INT index; + LPCSTR sz; } GLYPHNAME; typedef struct { - LONG UV; - const GLYPHNAME *name; + LONG UV; + GLYPHNAME *name; } UNICODEGLYPH; typedef struct { - INT size; - const UNICODEGLYPH *glyphs; + INT size; + const UNICODEGLYPH *glyphs; } UNICODEVECTOR; -extern const INT PSDRV_AGLGlyphNamesSize; -extern GLYPHNAME PSDRV_AGLGlyphNames[]; -extern const UNICODEVECTOR PSDRV_AdobeGlyphList; +extern const INT PSDRV_AGLGlyphNamesSize; +extern GLYPHNAME PSDRV_AGLGlyphNames[]; +extern UNICODEVECTOR PSDRV_AdobeGlyphList; typedef struct { float llx, lly, urx, ury; @@ -44,13 +44,23 @@ typedef struct _tagAFMLIGS { } AFMLIGS; typedef struct _tagAFMMETRICS { - int C; /* character */ - float WX; - const GLYPHNAME *N; /* name */ - AFMBBOX B; - AFMLIGS *L; /* Ligatures */ + int C; /* character */ + LONG UV; + float WX; + GLYPHNAME *N; /* name */ + AFMBBOX B; + AFMLIGS *L; /* Ligatures */ } AFMMETRICS; +typedef struct { + USHORT usUnitsPerEm; /* 1000 for Type 1 fonts */ + SHORT sTypoAscender; /* AFM Ascender */ + SHORT sTypoDescender; /* AFM Descender */ + SHORT sTypoLineGap; /* guess for Type 1 fonts */ + USHORT usWinAscent; + USHORT usWinDescent; +} WINMETRICS; + typedef struct _tagAFM { char *FontName; char *FullName; @@ -67,9 +77,11 @@ typedef struct _tagAFM { float Ascender; float Descender; float FullAscender; /* Ascent of Aring character */ + WINMETRICS WinMetrics; float CharWidths[256]; int NumofMetrics; AFMMETRICS *Metrics; + UNICODEVECTOR *Encoding; } AFM; /* CharWidths is a shortcut to the WX values of numbered glyphs */ /* Note no 'next' in AFM. Use AFMLISTENTRY as a container. This allow more than @@ -401,8 +413,8 @@ extern DWORD PSDRV_DeviceCapabilities(LPSTR lpszDriver, LPCSTR lpszDevice, LPDEVMODEA lpdm); VOID PSDRV_DrawLine( DC *dc ); INT PSDRV_GlyphListInit(); -const GLYPHNAME *PSDRV_GlyphName(LPCSTR szName); -VOID PSDRV_DumpGlyphList(); +GLYPHNAME *PSDRV_GlyphName(LPCSTR szName); +VOID PSDRV_IndexGlyphList(); #endif