From 657c4afaec46061ebf0be073e84a0164a09bca7f Mon Sep 17 00:00:00 2001
From: Ian Pilcher <ian.pilcher@home.com>
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 <string.h>
+#include <stdlib.h> 	/* qsort() & bsearch() */
 #include <stdio.h>
 #include <sys/stat.h>
 #include <dirent.h>
@@ -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
 
-- 
GitLab