push 27a9569132e9fc3a545aded7efca0a004a7b7ea9
[wine/hacks.git] / dlls / wineps.drv / builtin.c
blob01547db17a09222ef3052b6505a356c76fe8da3f
1 /*
2 * PostScript driver builtin font functions
4 * Copyright 2002 Huw D M Davies for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <assert.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winerror.h"
29 #include "wingdi.h"
31 #include "psdrv.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
37 /***********************************************************************
38 * is_stock_font
40 static inline BOOL is_stock_font( HFONT font )
42 int i;
43 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
45 if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE;
47 return FALSE;
51 /*******************************************************************************
52 * ScaleFont
54 * Scale builtin font to requested lfHeight
57 static inline float Round(float f)
59 return (f > 0) ? (f + 0.5) : (f - 0.5);
62 static VOID ScaleFont(const AFM *afm, LONG lfHeight, PSFONT *font,
63 TEXTMETRICW *tm)
65 const WINMETRICS *wm = &(afm->WinMetrics);
66 USHORT usUnitsPerEm, usWinAscent, usWinDescent;
67 SHORT sAscender, sDescender, sLineGap, sAvgCharWidth;
69 TRACE("'%s' %i\n", afm->FontName, lfHeight);
71 if (lfHeight < 0) /* match em height */
73 font->fontinfo.Builtin.scale = - ((float)lfHeight / (float)(wm->usUnitsPerEm));
75 else /* match cell height */
77 font->fontinfo.Builtin.scale = (float)lfHeight /
78 (float)(wm->usWinAscent + wm->usWinDescent);
81 font->size = (INT)Round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm);
83 usUnitsPerEm = (USHORT)Round((float)(wm->usUnitsPerEm) * font->fontinfo.Builtin.scale);
84 sAscender = (SHORT)Round((float)(wm->sAscender) * font->fontinfo.Builtin.scale);
85 sDescender = (SHORT)Round((float)(wm->sDescender) * font->fontinfo.Builtin.scale);
86 sLineGap = (SHORT)Round((float)(wm->sLineGap) * font->fontinfo.Builtin.scale);
87 usWinAscent = (USHORT)Round((float)(wm->usWinAscent) * font->fontinfo.Builtin.scale);
88 usWinDescent = (USHORT)Round((float)(wm->usWinDescent) * font->fontinfo.Builtin.scale);
89 sAvgCharWidth = (SHORT)Round((float)(wm->sAvgCharWidth) * font->fontinfo.Builtin.scale);
91 tm->tmAscent = (LONG)usWinAscent;
92 tm->tmDescent = (LONG)usWinDescent;
93 tm->tmHeight = tm->tmAscent + tm->tmDescent;
95 tm->tmInternalLeading = tm->tmHeight - (LONG)usUnitsPerEm;
96 if (tm->tmInternalLeading < 0)
97 tm->tmInternalLeading = 0;
99 tm->tmExternalLeading =
100 (LONG)(sAscender - sDescender + sLineGap) - tm->tmHeight;
101 if (tm->tmExternalLeading < 0)
102 tm->tmExternalLeading = 0;
104 tm->tmAveCharWidth = (LONG)sAvgCharWidth;
106 tm->tmWeight = afm->Weight;
107 tm->tmItalic = (afm->ItalicAngle != 0.0);
108 tm->tmUnderlined = 0;
109 tm->tmStruckOut = 0;
110 tm->tmFirstChar = (WCHAR)(afm->Metrics[0].UV);
111 tm->tmLastChar = (WCHAR)(afm->Metrics[afm->NumofMetrics - 1].UV);
112 tm->tmDefaultChar = 0x001f; /* Win2K does this - FIXME? */
113 tm->tmBreakChar = tm->tmFirstChar; /* should be 'space' */
115 tm->tmPitchAndFamily = TMPF_DEVICE | TMPF_VECTOR;
116 if (!afm->IsFixedPitch)
117 tm->tmPitchAndFamily |= TMPF_FIXED_PITCH; /* yes, it's backwards */
118 if (wm->usUnitsPerEm != 1000)
119 tm->tmPitchAndFamily |= TMPF_TRUETYPE;
121 tm->tmCharSet = ANSI_CHARSET; /* FIXME */
122 tm->tmOverhang = 0;
125 * This is kludgy. font->scale is used in several places in the driver
126 * to adjust PostScript-style metrics. Since these metrics have been
127 * "normalized" to an em-square size of 1000, font->scale needs to be
128 * similarly adjusted..
131 font->fontinfo.Builtin.scale *= (float)wm->usUnitsPerEm / 1000.0;
133 tm->tmMaxCharWidth = (LONG)Round(
134 (afm->FontBBox.urx - afm->FontBBox.llx) * font->fontinfo.Builtin.scale);
136 font->underlinePosition = afm->UnderlinePosition * font->fontinfo.Builtin.scale;
137 font->underlineThickness = afm->UnderlineThickness * font->fontinfo.Builtin.scale;
138 font->strikeoutPosition = tm->tmAscent / 2;
139 font->strikeoutThickness = font->underlineThickness;
141 TRACE("Selected PS font '%s' size %d weight %d.\n", afm->FontName,
142 font->size, tm->tmWeight );
143 TRACE("H = %d As = %d Des = %d IL = %d EL = %d\n", tm->tmHeight,
144 tm->tmAscent, tm->tmDescent, tm->tmInternalLeading,
145 tm->tmExternalLeading);
149 /****************************************************************************
150 * PSDRV_SelectBuiltinFont
152 * Set up physDev->font for a builtin font
155 BOOL PSDRV_SelectBuiltinFont(PSDRV_PDEVICE *physDev, HFONT hfont,
156 LOGFONTW *plf, LPSTR FaceName)
158 AFMLISTENTRY *afmle;
159 FONTFAMILY *family;
160 BOOL bd = FALSE, it = FALSE;
161 LONG height;
163 TRACE("Trying to find facename '%s'\n", FaceName);
165 /* Look for a matching font family */
166 for(family = physDev->pi->Fonts; family; family = family->next) {
167 if(!strcasecmp(FaceName, family->FamilyName))
168 break;
171 if(!family) {
172 /* Fallback for Window's font families to common PostScript families */
173 if(!strcmp(FaceName, "Arial"))
174 strcpy(FaceName, "Helvetica");
175 else if(!strcmp(FaceName, "System"))
176 strcpy(FaceName, "Helvetica");
177 else if(!strcmp(FaceName, "Times New Roman"))
178 strcpy(FaceName, "Times");
179 else if(!strcmp(FaceName, "Courier New"))
180 strcpy(FaceName, "Courier");
182 for(family = physDev->pi->Fonts; family; family = family->next) {
183 if(!strcmp(FaceName, family->FamilyName))
184 break;
187 /* If all else fails, use the first font defined for the printer */
188 if(!family)
189 family = physDev->pi->Fonts;
191 TRACE("Got family '%s'\n", family->FamilyName);
193 if(plf->lfItalic)
194 it = TRUE;
195 if(plf->lfWeight > 550)
196 bd = TRUE;
198 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
199 if( (bd == (afmle->afm->Weight == FW_BOLD)) &&
200 (it == (afmle->afm->ItalicAngle != 0.0)) )
201 break;
203 if(!afmle)
204 afmle = family->afmlist; /* not ideal */
206 TRACE("Got font '%s'\n", afmle->afm->FontName);
208 physDev->font.fontloc = Builtin;
209 physDev->font.fontinfo.Builtin.afm = afmle->afm;
211 height = plf->lfHeight;
212 /* stock fonts ignore the mapping mode */
213 if (!is_stock_font( hfont )) {
214 POINT pts[2];
215 pts[0].x = pts[0].y = pts[1].x = 0;
216 pts[1].y = height;
217 LPtoDP(physDev->hdc, pts, 2);
218 height = pts[1].y - pts[0].y;
220 ScaleFont(physDev->font.fontinfo.Builtin.afm, height,
221 &(physDev->font), &(physDev->font.fontinfo.Builtin.tm));
224 /* Does anyone know if these are supposed to be reversed like this? */
226 physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectX = physDev->logPixelsY;
227 physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectY = physDev->logPixelsX;
229 return TRUE;
232 BOOL PSDRV_WriteSetBuiltinFont(PSDRV_PDEVICE *physDev)
234 return PSDRV_WriteSetFont(physDev,
235 physDev->font.fontinfo.Builtin.afm->FontName,
236 physDev->font.size, physDev->font.escapement);
239 BOOL PSDRV_WriteBuiltinGlyphShow(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count)
241 int i;
242 LPCSTR name;
244 for (i = 0; i < count; ++i)
246 name = PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->N->sz;
248 PSDRV_WriteGlyphShow(physDev, name);
251 return TRUE;
254 /***********************************************************************
255 * PSDRV_GetTextMetrics
257 BOOL PSDRV_GetTextMetrics(PSDRV_PDEVICE *physDev, TEXTMETRICW *metrics)
259 assert(physDev->font.fontloc == Builtin);
261 memcpy(metrics, &(physDev->font.fontinfo.Builtin.tm),
262 sizeof(physDev->font.fontinfo.Builtin.tm));
263 return TRUE;
266 /******************************************************************************
267 * PSDRV_UVMetrics
269 * Find the AFMMETRICS for a given UV. Returns first glyph in the font
270 * (space?) if the font does not have a glyph for the given UV.
272 static int MetricsByUV(const void *a, const void *b)
274 return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV);
277 const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm)
279 AFMMETRICS key;
280 const AFMMETRICS *needle;
283 * Ugly work-around for symbol fonts. Wine is sending characters which
284 * belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
285 * characters (U+0020 - U+00FF).
288 if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100)
289 UV |= 0xf000;
291 key.UV = UV;
293 needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS),
294 MetricsByUV);
296 if (needle == NULL)
298 WARN("No glyph for U+%.4X in %s\n", UV, afm->FontName);
299 needle = afm->Metrics;
302 return needle;
305 /***********************************************************************
306 * PSDRV_GetTextExtentExPoint
308 BOOL PSDRV_GetTextExtentExPoint(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count,
309 INT maxExt, LPINT lpnFit, LPINT alpDx, LPSIZE size)
311 int nfit = 0;
312 int i;
313 float width = 0.0;
314 float scale;
316 assert(physDev->font.fontloc == Builtin);
318 TRACE("%s %i\n", debugstr_wn(str, count), count);
320 scale = physDev->font.fontinfo.Builtin.scale;
321 for (i = 0; i < count && str[i] != '\0'; ++i)
323 float scaled_width;
324 width += PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->WX;
325 scaled_width = width * scale;
326 if (alpDx)
327 alpDx[i] = scaled_width;
328 if (scaled_width <= maxExt)
329 ++nfit;
332 size->cx = width * physDev->font.fontinfo.Builtin.scale;
333 size->cy = physDev->font.fontinfo.Builtin.tm.tmHeight;
335 if (lpnFit)
336 *lpnFit = nfit;
338 TRACE("cx=%i cy=%i\n", size->cx, size->cy);
340 return TRUE;
343 /***********************************************************************
344 * PSDRV_GetCharWidth
346 BOOL PSDRV_GetCharWidth(PSDRV_PDEVICE *physDev, UINT firstChar, UINT lastChar, LPINT buffer)
348 UINT i;
350 assert(physDev->font.fontloc == Builtin);
352 TRACE("U+%.4X U+%.4X\n", firstChar, lastChar);
354 if (lastChar > 0xffff || firstChar > lastChar)
356 SetLastError(ERROR_INVALID_PARAMETER);
357 return FALSE;
360 for (i = firstChar; i <= lastChar; ++i)
362 *buffer = floor( PSDRV_UVMetrics(i, physDev->font.fontinfo.Builtin.afm)->WX
363 * physDev->font.fontinfo.Builtin.scale + 0.5 );
364 TRACE("U+%.4X: %i\n", i, *buffer);
365 ++buffer;
368 return TRUE;
372 /***********************************************************************
373 * PSDRV_GetFontMetric
375 static UINT PSDRV_GetFontMetric(HDC hdc, const AFM *afm,
376 NEWTEXTMETRICEXW *ntmx, ENUMLOGFONTEXW *elfx)
378 /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
380 TEXTMETRICW *tm = (TEXTMETRICW *)&(ntmx->ntmTm);
381 LOGFONTW *lf = &(elfx->elfLogFont);
382 PSFONT font;
384 memset(ntmx, 0, sizeof(*ntmx));
385 memset(elfx, 0, sizeof(*elfx));
387 ScaleFont(afm, -(LONG)(afm->WinMetrics.usUnitsPerEm), &font, tm);
389 lf->lfHeight = tm->tmHeight;
390 lf->lfWidth = tm->tmAveCharWidth;
391 lf->lfWeight = tm->tmWeight;
392 lf->lfItalic = tm->tmItalic;
393 lf->lfCharSet = tm->tmCharSet;
395 lf->lfPitchAndFamily = (afm->IsFixedPitch) ? FIXED_PITCH : VARIABLE_PITCH;
397 MultiByteToWideChar(CP_ACP, 0, afm->FamilyName, -1, lf->lfFaceName,
398 LF_FACESIZE);
400 return DEVICE_FONTTYPE;
403 /***********************************************************************
404 * PSDRV_EnumDeviceFonts
406 BOOL PSDRV_EnumDeviceFonts( PSDRV_PDEVICE *physDev, LPLOGFONTW plf,
407 FONTENUMPROCW proc, LPARAM lp )
409 ENUMLOGFONTEXW lf;
410 NEWTEXTMETRICEXW tm;
411 BOOL b, bRet = 0;
412 AFMLISTENTRY *afmle;
413 FONTFAMILY *family;
414 char FaceName[LF_FACESIZE];
416 if( plf->lfFaceName[0] ) {
417 WideCharToMultiByte(CP_ACP, 0, plf->lfFaceName, -1,
418 FaceName, sizeof(FaceName), NULL, NULL);
419 TRACE("lfFaceName = '%s'\n", FaceName);
420 for(family = physDev->pi->Fonts; family; family = family->next) {
421 if(!strncmp(FaceName, family->FamilyName,
422 strlen(family->FamilyName)))
423 break;
425 if(family) {
426 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
427 TRACE("Got '%s'\n", afmle->afm->FontName);
428 if( (b = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm,
429 PSDRV_GetFontMetric( physDev->hdc, afmle->afm, &tm, &lf ),
430 lp )) )
431 bRet = b;
432 else break;
435 } else {
437 TRACE("lfFaceName = NULL\n");
438 for(family = physDev->pi->Fonts; family; family = family->next) {
439 afmle = family->afmlist;
440 TRACE("Got '%s'\n", afmle->afm->FontName);
441 if( (b = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm,
442 PSDRV_GetFontMetric( physDev->hdc, afmle->afm, &tm, &lf ),
443 lp )) )
444 bRet = b;
445 else break;
448 return bRet;