WINEPS: Unicode encodings for PostScript fonts

Ian Pilcher ian.pilcher at home.com
Tue May 8 05:22:26 CDT 2001


No TrueType support yet, but this patch makes the driver build Unicode-
style encodings for the PostScript fonts it uses.  (Actually, most fonts
end up using the pre-defined Adobe Glyph List encoding.)

As an added bonus, knowing the Unicode value for each glyph will allow
the driver to determine if it is part of the "Windows ANSI" character
set.  This will allow the driver to compute the 'WinAscent' and
'WinDescent' metrics for PostScript fonts, which should allow it to
scale them much more accurately.

There is one semi-ugly const->non-const typecasts in afm.c:
SortFontMetrics.  The only way to get rid of it (and not get a
compiler warning) is to make the Adobe Glyph List encoding (not the
glyph name strings) in agl.c non-const, which moves them out of read-
only memory; pick your poison.

Modified files:
    dlls/wineps: afm.c agl.c glyphlist.c psdrv.h

Log message:
    Ian Pilcher
    WINEPS: Unicode encodings for PostScript fonts
-- 
========================================================================
Ian Pilcher                                         ian.pilcher at home.com
========================================================================
-------------- next part --------------
--- ../wine-20010507cvs/dlls/wineps/afm.c	Fri May  4 10:06:55 2001
+++ dlls/wineps/afm.c	Tue May  8 05:04:35 2001
@@ -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 @@
  *  	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 @@
 }
 
 /*******************************************************************************
- *  	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 @@
     HeapFree(PSDRV_Heap, 0, afm);
 }
 
-
 /***********************************************************
  *
  *	PSDRV_AFMGetCharMetrics
@@ -191,6 +193,55 @@
     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 @@
         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_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 @@
 	if (PSDRV_ReadAFMDir (value) == FALSE)
 	    return FALSE;
 
-    PSDRV_DumpGlyphList();
+    PSDRV_IndexGlyphList();
+    if (SortFontMetrics() == FALSE)
+    	return FALSE;
     PSDRV_DumpFontList();
     return TRUE;
 }
-
--- ../wine-20010507cvs/dlls/wineps/agl.c	Fri Apr 20 13:30:38 2001
+++ dlls/wineps/agl.c	Tue May  8 05:00:04 2001
@@ -3179,4 +3179,4 @@
     { 0xfb4b, PSDRV_AGLGlyphNames +  515 }	/* afii57700 */
 };
 
-const UNICODEVECTOR PSDRV_AdobeGlyphList = { 1051, encoding };
+UNICODEVECTOR PSDRV_AdobeGlyphList = { 1051, encoding };
--- ../wine-20010507cvs/dlls/wineps/glyphlist.c	Mon Apr 23 13:12:45 2001
+++ dlls/wineps/glyphlist.c	Tue May  8 04:10:57 2001
@@ -158,7 +158,7 @@
  *  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 @@
 }
 
 /*******************************************************************************
- *	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);
+    }
 }
--- ../wine-20010507cvs/dlls/wineps/psdrv.h	Fri May  4 10:06:55 2001
+++ dlls/wineps/psdrv.h	Tue May  8 04:59:56 2001
@@ -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 @@
 } 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 @@
     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 @@
 				      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
 


More information about the wine-patches mailing list