Unicode-enable PostScript driver
Ian Pilcher
ian.pilcher at home.com
Wed Jul 18 16:47:39 CDT 2001
With this patch, the PostScript driver no longer converts text strings
from 16-bit Unicode characters to 8-bit "ANSI" characters. Instead, any
required character metrics are looked up their 16-bit UV (using bsearch)
and the PostScript 'glyphshow' operator is used to individually print
each character -- independent of code pages, encodings, etc. My simple
test application is now able to print a string of Arabic characters
(using Courier New), which came out as garbage before.
Because this is such a significant change to the way the driver works, I
suspect that it may cause some problems. Therefore, I've disabled the
old code (#if 0 ... #endif), rather than removing it. This is will make
it easier for me to see what the driver used to do, if I have to fix
anything. There's some encoding-related stuff that can be removed from
the driver when the new stuff has been pounded on a bit; I'll take the
disabled code out then.
A note of thanks to Gerard Patel for being the only person (as far as I
know) who actually tested the initial version of this patch.
Modified files:
dlls/wineps: afm.c font.c ps.c psdrv.h truetype.c
Log message:
Ian Pilcher
WINEPS: read/calculate average character width for all fonts
WINEPS: work directly with 16-bit WCHARs; don't convert to CP1252
--
========================================================================
Ian Pilcher ian.pilcher at home.com
========================================================================
-------------- next part --------------
diff -urN ../wine-20010718cvs/dlls/wineps/afm.c ./dlls/wineps/afm.c
--- ../wine-20010718cvs/dlls/wineps/afm.c Mon Jul 2 13:00:33 2001
+++ ./dlls/wineps/afm.c Wed Jul 18 15:07:27 2001
@@ -802,6 +802,60 @@
}
/*******************************************************************************
+ * PSDRV_CalcAvgCharWidth
+ *
+ * Calculate WinMetrics.sAvgCharWidth for a Type 1 font. Can also be used on
+ * TrueType fonts, if font designer set OS/2:xAvgCharWidth to zero.
+ *
+ * Tries to use formula in TrueType specification; falls back to simple mean
+ * if any lowercase latin letter (or space) is not present.
+ */
+inline static SHORT MeanCharWidth(const AFM *afm)
+{
+ float w = 0.0;
+ int i;
+
+ for (i = 0; i < afm->NumofMetrics; ++i)
+ w += afm->Metrics[i].WX;
+
+ w /= afm->NumofMetrics;
+
+ return (SHORT)(w + 0.5);
+}
+
+static const struct { LONG UV; int weight; } UVweight[27] =
+{
+ { 0x0061, 64 }, { 0x0062, 14 }, { 0x0063, 27 }, { 0x0064, 35 },
+ { 0x0065, 100 }, { 0x0066, 20 }, { 0x0067, 14 }, { 0x0068, 42 },
+ { 0x0069, 63 }, { 0x006a, 3 }, { 0x006b, 6 }, { 0x006c, 35 },
+ { 0x006d, 20 }, { 0x006e, 56 }, { 0x006f, 56 }, { 0x0070, 17 },
+ { 0x0071, 4 }, { 0x0072, 49 }, { 0x0073, 56 }, { 0x0074, 71 },
+ { 0x0075, 31 }, { 0x0076, 10 }, { 0x0077, 18 }, { 0x0078, 3 },
+ { 0x0079, 18 }, { 0x007a, 2 }, { 0x0020, 166 }
+};
+
+SHORT PSDRV_CalcAvgCharWidth(const AFM *afm)
+{
+ float w = 0.0;
+ int i;
+
+ for (i = 0; i < 27; ++i)
+ {
+ const AFMMETRICS *afmm;
+
+ afmm = PSDRV_UVMetrics(UVweight[i].UV, afm);
+ if (afmm->UV != UVweight[i].UV) /* UVMetrics returns first glyph */
+ return MeanCharWidth(afm); /* in font if UV is missing */
+
+ w += afmm->WX * (float)(UVweight[i].weight);
+ }
+
+ w /= 1000.0;
+
+ return (SHORT)(w + 0.5);
+}
+
+/*******************************************************************************
* CalcWindowsMetrics
*
* Calculates several Windows-specific font metrics for each font. Relies on
@@ -871,6 +925,8 @@
wm.sLineGap = 1150 - (wm.sAscender - wm.sDescender);
if (wm.sLineGap < 0)
wm.sLineGap = 0;
+
+ wm.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
TRACE("Windows metrics for '%s':\n", afm->FullName);
TRACE("\tsAscender = %i\n", wm.sAscender);
@@ -882,6 +938,7 @@
TRACE("\tsTypoLineGap = %i\n", wm.sTypoLineGap);
TRACE("\tusWinAscent = %u\n", wm.usWinAscent);
TRACE("\tusWinDescent = %u\n", wm.usWinDescent);
+ TRACE("\tsAvgCharWidth = %i\n", wm.sAvgCharWidth);
afm->WinMetrics = wm;
diff -urN ../wine-20010718cvs/dlls/wineps/font.c ./dlls/wineps/font.c
--- ../wine-20010718cvs/dlls/wineps/font.c Fri May 11 15:03:41 2001
+++ ./dlls/wineps/font.c Wed Jul 18 14:53:47 2001
@@ -5,6 +5,7 @@
*
*/
#include <string.h>
+#include <stdlib.h> /* for bsearch() */
#include "winspool.h"
#include "psdrv.h"
#include "debugtools.h"
@@ -197,6 +198,7 @@
return TRUE;
}
+#if 0
/***********************************************************************
* PSDRV_UnicodeToANSI
*/
@@ -224,9 +226,51 @@
return 0xff;
}
}
+#endif
+
+/******************************************************************************
+ * PSDRV_UVMetrics
+ *
+ * Find the AFMMETRICS for a given UV. Returns first glyph in the font
+ * (space?) if the font does not have a glyph for the given UV.
+ */
+static int MetricsByUV(const void *a, const void *b)
+{
+ return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV);
+}
+
+const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm)
+{
+ AFMMETRICS key;
+ const AFMMETRICS *needle;
+
+ /*
+ * Ugly work-around for symbol fonts. Wine is sending characters which
+ * belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
+ * characters (U+0020 - U+00FF).
+ */
+
+ if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100)
+ UV |= 0xf000;
+
+ key.UV = UV;
+
+ needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS),
+ MetricsByUV);
+
+ if (needle == NULL)
+ {
+ WARN("No glyph for U+%.4lX in %s\n", UV, afm->FontName);
+ needle = afm->Metrics;
+ }
+
+ return needle;
+}
+
/***********************************************************************
* PSDRV_GetTextExtentPoint
*/
+#if 0
BOOL PSDRV_GetTextExtentPoint( DC *dc, LPCWSTR str, INT count,
LPSIZE size )
{
@@ -249,11 +293,34 @@
return TRUE;
}
+#endif
+BOOL PSDRV_GetTextExtentPoint(DC *dc, LPCWSTR str, INT count, LPSIZE size)
+{
+ PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
+ int i;
+ float width = 0.0;
+
+ TRACE("%s %i\n", debugstr_wn(str, count), count);
+
+ for (i = 0; i < count && str[i] != '\0'; ++i)
+ width += PSDRV_UVMetrics(str[i], physDev->font.afm)->WX;
+
+ width *= physDev->font.scale;
+
+ size->cx = GDI_ROUND((FLOAT)width * dc->xformVport2World.eM11);
+ size->cy = GDI_ROUND((FLOAT)physDev->font.tm.tmHeight *
+ dc->xformVport2World.eM22);
+
+ TRACE("cx=%li cy=%li\n", size->cx, size->cy);
+
+ return TRUE;
+}
/***********************************************************************
* PSDRV_GetCharWidth
*/
+#if 0
BOOL PSDRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
LPINT buffer )
{
@@ -268,7 +335,31 @@
return TRUE;
}
+#endif
+BOOL PSDRV_GetCharWidth(DC *dc, UINT firstChar, UINT lastChar, LPINT buffer)
+{
+ PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
+ UINT i;
+
+ TRACE("U+%.4X U+%.4X\n", firstChar, lastChar);
+
+ if (lastChar > 0xffff || firstChar > lastChar)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ for (i = firstChar; i <= lastChar; ++i)
+ {
+ *buffer = GDI_ROUND(PSDRV_UVMetrics(i, physDev->font.afm)->WX
+ * physDev->font.scale);
+ TRACE("U+%.4X: %i\n", i, *buffer);
+ ++buffer;
+ }
+
+ return TRUE;
+}
/***********************************************************************
* PSDRV_SetFont
diff -urN ../wine-20010718cvs/dlls/wineps/ps.c ./dlls/wineps/ps.c
--- ../wine-20010718cvs/dlls/wineps/ps.c Sun Jan 28 17:13:45 2001
+++ ./dlls/wineps/ps.c Wed Jul 18 14:50:20 2001
@@ -115,6 +115,9 @@
static char psshow[] = /* string */
"(%s) show\n";
+static const char psglyphshow[] = /* glyph name */
+"/%s glyphshow\n";
+
static char pssetfont[] = /* fontname, xscale, yscale, ascent, escapement */
"/%s findfont\n"
"[%d 0 0 %d 0 0]\n"
@@ -634,6 +637,7 @@
return TRUE;
}
+#if 0
BOOL PSDRV_WriteShow(DC *dc, LPCWSTR str, INT count)
{
char *buf, *buf1;
@@ -671,6 +675,33 @@
return TRUE;
}
+#endif
+
+BOOL PSDRV_WriteShow(DC *dc, LPCWSTR str, INT count)
+{
+ char buf[128];
+ int i;
+
+ for (i = 0; i < count; ++i)
+ {
+ LPCSTR name;
+ int l;
+
+ name = PSDRV_UVMetrics(str[i],
+ ((PSDRV_PDEVICE *)dc->physDev)->font.afm)->N->sz;
+ l = snprintf(buf, sizeof(buf), psglyphshow, name);
+
+ if (l < sizeof(psglyphshow) - 2 || l > sizeof(buf) - 1)
+ {
+ WARN("Unusable glyph name '%s' - ignoring\n", name);
+ continue;
+ }
+
+ PSDRV_WriteSpool(dc, buf, l);
+ }
+
+ return TRUE;
+}
BOOL PSDRV_WriteFill(DC *dc)
{
diff -urN ../wine-20010718cvs/dlls/wineps/psdrv.h ./dlls/wineps/psdrv.h
--- ../wine-20010718cvs/dlls/wineps/psdrv.h Tue May 29 17:06:11 2001
+++ ./dlls/wineps/psdrv.h Wed Jul 18 15:05:05 2001
@@ -421,6 +421,8 @@
GLYPHNAME *PSDRV_GlyphName(LPCSTR szName);
VOID PSDRV_IndexGlyphList();
BOOL PSDRV_GetTrueTypeMetrics();
+const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm);
+SHORT PSDRV_CalcAvgCharWidth(const AFM *afm);
#endif
diff -urN ../wine-20010718cvs/dlls/wineps/truetype.c ./dlls/wineps/truetype.c
--- ../wine-20010718cvs/dlls/wineps/truetype.c Mon Jul 2 13:00:33 2001
+++ ./dlls/wineps/truetype.c Wed Jul 18 15:18:00 2001
@@ -329,6 +329,7 @@
afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
afm->WinMetrics.usWinAscent = os2->usWinAscent;
afm->WinMetrics.usWinDescent = os2->usWinDescent;
+ afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
return TRUE;
}
@@ -482,6 +483,11 @@
if (ReadCharMetrics(afm) == FALSE)
return FALSE;
+
+ /* Can't do this check until character metrics are read */
+
+ if (afm->WinMetrics.sAvgCharWidth == 0)
+ afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm);
return TRUE;
}
More information about the wine-patches
mailing list