2 * PostScript driver font functions
4 * Copyright 1998 Huw D M Davies
8 #include <stdlib.h> /* for bsearch() */
11 #include "debugtools.h"
14 DEFAULT_DEBUG_CHANNEL(psdrv);
16 /***********************************************************************
19 inline static BOOL is_stock_font( HFONT font )
22 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
24 if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE;
30 /*******************************************************************************
33 * Scale font to requested lfHeight
36 inline static float round(float f)
38 return (f > 0) ? (f + 0.5) : (f - 0.5);
41 static VOID ScaleFont(const AFM *afm, LONG lfHeight, PSFONT *font,
44 const WINMETRICS *wm = &(afm->WinMetrics);
45 USHORT usUnitsPerEm, usWinAscent, usWinDescent;
46 SHORT sAscender, sDescender, sLineGap, sTypoAscender;
47 SHORT sTypoDescender, sTypoLineGap, sAvgCharWidth;
49 TRACE("'%s' %li\n", afm->FontName, lfHeight);
51 if (lfHeight < 0) /* match em height */
53 font->scale = - ((float)lfHeight / (float)(wm->usUnitsPerEm));
55 else /* match cell height */
57 font->scale = (float)lfHeight /
58 (float)(wm->usWinAscent + wm->usWinDescent);
61 font->size = (INT)round(font->scale * (float)wm->usUnitsPerEm);
64 usUnitsPerEm = (USHORT)round((float)(wm->usUnitsPerEm) * font->scale);
65 sAscender = (SHORT)round((float)(wm->sAscender) * font->scale);
66 sDescender = (SHORT)round((float)(wm->sDescender) * font->scale);
67 sLineGap = (SHORT)round((float)(wm->sLineGap) * font->scale);
68 sTypoAscender = (SHORT)round((float)(wm->sTypoAscender) * font->scale);
69 sTypoDescender = (SHORT)round((float)(wm->sTypoDescender) * font->scale);
70 sTypoLineGap = (SHORT)round((float)(wm->sTypoLineGap) * font->scale);
71 usWinAscent = (USHORT)round((float)(wm->usWinAscent) * font->scale);
72 usWinDescent = (USHORT)round((float)(wm->usWinDescent) * font->scale);
73 sAvgCharWidth = (SHORT)round((float)(wm->sAvgCharWidth) * font->scale);
75 tm->tmAscent = (LONG)usWinAscent;
76 tm->tmDescent = (LONG)usWinDescent;
77 tm->tmHeight = tm->tmAscent + tm->tmDescent;
79 tm->tmInternalLeading = tm->tmHeight - (LONG)usUnitsPerEm;
80 if (tm->tmInternalLeading < 0)
81 tm->tmInternalLeading = 0;
83 tm->tmExternalLeading =
84 (LONG)(sAscender - sDescender + sLineGap) - tm->tmHeight;
85 if (tm->tmExternalLeading < 0)
86 tm->tmExternalLeading = 0;
88 tm->tmAveCharWidth = (LONG)sAvgCharWidth;
90 tm->tmWeight = afm->Weight;
91 tm->tmItalic = (afm->ItalicAngle != 0.0);
94 tm->tmFirstChar = (WCHAR)(afm->Metrics[0].UV);
95 tm->tmLastChar = (WCHAR)(afm->Metrics[afm->NumofMetrics - 1].UV);
96 tm->tmDefaultChar = 0x001f; /* Win2K does this - FIXME? */
97 tm->tmBreakChar = tm->tmFirstChar; /* should be 'space' */
99 tm->tmPitchAndFamily = TMPF_DEVICE | TMPF_VECTOR;
100 if (!afm->IsFixedPitch)
101 tm->tmPitchAndFamily |= TMPF_FIXED_PITCH; /* yes, it's backwards */
102 if (wm->usUnitsPerEm != 1000)
103 tm->tmPitchAndFamily |= TMPF_TRUETYPE;
105 tm->tmCharSet = ANSI_CHARSET; /* FIXME */
109 * This is kludgy. font->scale is used in several places in the driver
110 * to adjust PostScript-style metrics. Since these metrics have been
111 * "normalized" to an em-square size of 1000, font->scale needs to be
112 * similarly adjusted..
115 font->scale *= (float)wm->usUnitsPerEm / 1000.0;
117 tm->tmMaxCharWidth = (LONG)round(
118 (afm->FontBBox.urx - afm->FontBBox.llx) * font->scale);
120 TRACE("Selected PS font '%s' size %d weight %ld.\n", afm->FontName,
121 font->size, tm->tmWeight );
122 TRACE("H = %ld As = %ld Des = %ld IL = %ld EL = %ld\n", tm->tmHeight,
123 tm->tmAscent, tm->tmDescent, tm->tmInternalLeading,
124 tm->tmExternalLeading);
127 /***********************************************************************
128 * PSDRV_FONT_SelectObject
130 HFONT PSDRV_FONT_SelectObject( DC * dc, HFONT hfont )
133 HFONT16 prevfont = dc->hFont;
134 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
135 BOOL bd = FALSE, it = FALSE;
138 char FaceName[LF_FACESIZE];
140 if (!GetObjectW( hfont, sizeof(lf), &lf )) return 0;
142 TRACE("FaceName = %s Height = %ld Italic = %d Weight = %ld\n",
143 debugstr_w(lf.lfFaceName), lf.lfHeight, lf.lfItalic,
150 if(lf.lfWeight > 550)
152 WideCharToMultiByte(CP_ACP, 0, lf.lfFaceName, -1,
153 FaceName, sizeof(FaceName), NULL, NULL);
155 if(FaceName[0] == '\0') {
156 switch(lf.lfPitchAndFamily & 0xf0) {
161 strcpy(FaceName, "Times");
164 strcpy(FaceName, "Helvetica");
167 strcpy(FaceName, "Courier");
170 strcpy(FaceName, "Symbol");
175 if(FaceName[0] == '\0') {
176 switch(lf.lfPitchAndFamily & 0x0f) {
178 strcpy(FaceName, "Times");
181 strcpy(FaceName, "Courier");
186 if (physDev->pi->FontSubTableSize != 0)
190 for (i = 0; i < physDev->pi->FontSubTableSize; ++i)
192 if (!strcasecmp (FaceName,
193 physDev->pi->FontSubTable[i].pValueName))
195 TRACE ("substituting facename '%s' for '%s'\n",
196 (LPSTR) physDev->pi->FontSubTable[i].pData, FaceName);
197 if (strlen ((LPSTR) physDev->pi->FontSubTable[i].pData) <
200 (LPSTR) physDev->pi->FontSubTable[i].pData);
202 WARN ("Facename '%s' is too long; ignoring substitution\n",
203 (LPSTR) physDev->pi->FontSubTable[i].pData);
209 TRACE("Trying to find facename '%s'\n", FaceName);
211 /* Look for a matching font family */
212 for(family = physDev->pi->Fonts; family; family = family->next) {
213 if(!strcasecmp(FaceName, family->FamilyName))
217 /* Fallback for Window's font families to common PostScript families */
218 if(!strcmp(FaceName, "Arial"))
219 strcpy(FaceName, "Helvetica");
220 else if(!strcmp(FaceName, "System"))
221 strcpy(FaceName, "Helvetica");
222 else if(!strcmp(FaceName, "Times New Roman"))
223 strcpy(FaceName, "Times");
224 else if(!strcmp(FaceName, "Courier New"))
225 strcpy(FaceName, "Courier");
227 for(family = physDev->pi->Fonts; family; family = family->next) {
228 if(!strcmp(FaceName, family->FamilyName))
232 /* If all else fails, use the first font defined for the printer */
234 family = physDev->pi->Fonts;
236 TRACE("Got family '%s'\n", family->FamilyName);
238 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
239 if( (bd == (afmle->afm->Weight == FW_BOLD)) &&
240 (it == (afmle->afm->ItalicAngle != 0.0)) )
244 afmle = family->afmlist; /* not ideal */
246 TRACE("Got font '%s'\n", afmle->afm->FontName);
248 physDev->font.afm = afmle->afm;
249 /* stock fonts ignore the mapping mode */
250 if (!is_stock_font( hfont )) lf.lfHeight = INTERNAL_YWSTODS(dc, lf.lfHeight);
251 ScaleFont(physDev->font.afm, lf.lfHeight,
252 &(physDev->font), &(physDev->font.tm));
254 physDev->font.escapement = lf.lfEscapement;
256 /* Does anyone know if these are supposed to be reversed like this? */
258 physDev->font.tm.tmDigitizedAspectX = physDev->logPixelsY;
259 physDev->font.tm.tmDigitizedAspectY = physDev->logPixelsX;
264 /***********************************************************************
265 * PSDRV_GetTextMetrics
267 BOOL PSDRV_GetTextMetrics(DC *dc, TEXTMETRICW *metrics)
269 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
271 memcpy(metrics, &(physDev->font.tm), sizeof(physDev->font.tm));
275 /******************************************************************************
278 * Find the AFMMETRICS for a given UV. Returns first glyph in the font
279 * (space?) if the font does not have a glyph for the given UV.
281 static int MetricsByUV(const void *a, const void *b)
283 return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV);
286 const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm)
289 const AFMMETRICS *needle;
292 * Ugly work-around for symbol fonts. Wine is sending characters which
293 * belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
294 * characters (U+0020 - U+00FF).
297 if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100)
302 needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS),
307 WARN("No glyph for U+%.4lX in %s\n", UV, afm->FontName);
308 needle = afm->Metrics;
314 /***********************************************************************
315 * PSDRV_GetTextExtentPoint
317 BOOL PSDRV_GetTextExtentPoint(DC *dc, LPCWSTR str, INT count, LPSIZE size)
319 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
323 TRACE("%s %i\n", debugstr_wn(str, count), count);
325 for (i = 0; i < count && str[i] != '\0'; ++i)
326 width += PSDRV_UVMetrics(str[i], physDev->font.afm)->WX;
328 width *= physDev->font.scale;
330 size->cx = GDI_ROUND((FLOAT)width * dc->xformVport2World.eM11);
331 size->cy = GDI_ROUND((FLOAT)physDev->font.tm.tmHeight *
332 dc->xformVport2World.eM22);
334 TRACE("cx=%li cy=%li\n", size->cx, size->cy);
339 /***********************************************************************
342 BOOL PSDRV_GetCharWidth(DC *dc, UINT firstChar, UINT lastChar, LPINT buffer)
344 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
347 TRACE("U+%.4X U+%.4X\n", firstChar, lastChar);
349 if (lastChar > 0xffff || firstChar > lastChar)
351 SetLastError(ERROR_INVALID_PARAMETER);
355 for (i = firstChar; i <= lastChar; ++i)
357 *buffer = GDI_ROUND(PSDRV_UVMetrics(i, physDev->font.afm)->WX
358 * physDev->font.scale);
359 TRACE("U+%.4X: %i\n", i, *buffer);
366 /***********************************************************************
369 BOOL PSDRV_SetFont( DC *dc )
371 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
373 PSDRV_WriteSetColor(dc, &physDev->font.color);
374 if(physDev->font.set) return TRUE;
376 PSDRV_WriteSetFont(dc);
377 physDev->font.set = TRUE;
382 /***********************************************************************
383 * PSDRV_GetFontMetric
385 static UINT PSDRV_GetFontMetric(HDC hdc, const AFM *afm,
386 NEWTEXTMETRICEXW *ntmx, ENUMLOGFONTEXW *elfx)
388 /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
390 TEXTMETRICW *tm = (TEXTMETRICW *)&(ntmx->ntmTm);
391 LOGFONTW *lf = &(elfx->elfLogFont);
394 memset(ntmx, 0, sizeof(*ntmx));
395 memset(elfx, 0, sizeof(*elfx));
397 ScaleFont(afm, -(LONG)(afm->WinMetrics.usUnitsPerEm), &font, tm);
399 lf->lfHeight = tm->tmHeight;
400 lf->lfWidth = tm->tmAveCharWidth;
401 lf->lfWeight = tm->tmWeight;
402 lf->lfItalic = tm->tmItalic;
403 lf->lfCharSet = tm->tmCharSet;
405 lf->lfPitchAndFamily = (afm->IsFixedPitch) ? FIXED_PITCH : VARIABLE_PITCH;
407 MultiByteToWideChar(CP_ACP, 0, afm->FamilyName, -1, lf->lfFaceName,
410 return DEVICE_FONTTYPE;
413 /***********************************************************************
414 * PSDRV_EnumDeviceFonts
416 BOOL PSDRV_EnumDeviceFonts( HDC hdc, LPLOGFONTW plf,
417 DEVICEFONTENUMPROC proc, LPARAM lp )
424 PSDRV_PDEVICE *physDev;
425 char FaceName[LF_FACESIZE];
426 DC *dc = DC_GetDCPtr( hdc );
427 if (!dc) return FALSE;
429 physDev = (PSDRV_PDEVICE *)dc->physDev;
430 /* FIXME!! should reevaluate dc->physDev after every callback */
431 GDI_ReleaseObj( hdc );
433 if( plf->lfFaceName[0] ) {
434 WideCharToMultiByte(CP_ACP, 0, plf->lfFaceName, -1,
435 FaceName, sizeof(FaceName), NULL, NULL);
436 TRACE("lfFaceName = '%s'\n", FaceName);
437 for(family = physDev->pi->Fonts; family; family = family->next) {
438 if(!strncmp(FaceName, family->FamilyName,
439 strlen(family->FamilyName)))
443 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
444 TRACE("Got '%s'\n", afmle->afm->FontName);
445 if( (b = (*proc)( &lf, &tm,
446 PSDRV_GetFontMetric( hdc, afmle->afm, &tm, &lf ),
454 TRACE("lfFaceName = NULL\n");
455 for(family = physDev->pi->Fonts; family; family = family->next) {
456 afmle = family->afmlist;
457 TRACE("Got '%s'\n", afmle->afm->FontName);
458 if( (b = (*proc)( &lf, &tm,
459 PSDRV_GetFontMetric( hdc, afmle->afm, &tm, &lf ),