Read/calculate average character width for all fonts.

Work directly with 16-bit WCHARs; don't convert to CP1252.
This commit is contained in:
Ian Pilcher 2001-07-19 00:30:43 +00:00 committed by Alexandre Julliard
parent 4194fe48e3
commit 020146619c
5 changed files with 187 additions and 0 deletions

View File

@ -801,6 +801,60 @@ static BOOL SortFontMetrics()
return TRUE;
}
/*******************************************************************************
* 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
*
@ -871,6 +925,8 @@ static VOID CalcWindowsMetrics()
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 @@ static VOID CalcWindowsMetrics()
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;

View File

@ -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 @@ BOOL PSDRV_GetTextMetrics(DC *dc, TEXTMETRICW *metrics)
return TRUE;
}
#if 0
/***********************************************************************
* PSDRV_UnicodeToANSI
*/
@ -224,9 +226,51 @@ char PSDRV_UnicodeToANSI(int u)
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 @@ BOOL PSDRV_GetTextExtentPoint( DC *dc, LPCWSTR str, INT count,
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 @@ BOOL PSDRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
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

View File

@ -115,6 +115,9 @@ static char psrrectangle[] = /* x, y, width, height, -width */
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 @@ BOOL PSDRV_WriteReencodeFont(DC *dc)
return TRUE;
}
#if 0
BOOL PSDRV_WriteShow(DC *dc, LPCWSTR str, INT count)
{
char *buf, *buf1;
@ -671,6 +675,33 @@ BOOL PSDRV_WriteShow(DC *dc, LPCWSTR str, INT count)
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)
{

View File

@ -421,6 +421,8 @@ INT PSDRV_GlyphListInit();
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

View File

@ -329,6 +329,7 @@ static BOOL ReadMetricsTables(AFM *afm)
afm->WinMetrics.sTypoLineGap = os2->sTypoLineGap;
afm->WinMetrics.usWinAscent = os2->usWinAscent;
afm->WinMetrics.usWinDescent = os2->usWinDescent;
afm->WinMetrics.sAvgCharWidth = os2->xAvgCharWidth;
return TRUE;
}
@ -483,6 +484,11 @@ static BOOL ReadTrueTypeAFM(AFM *afm)
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;
}