ntdll: Make sure we don't try to attach the main exe a second time.
[wine/zf.git] / dlls / wineps.drv / builtin.c
blob22397567aa48d213611803f305994b471b05474b
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"
30 #include "winnls.h"
31 #include "winternl.h"
33 #include "psdrv.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
39 /***********************************************************************
40 * is_stock_font
42 static inline BOOL is_stock_font( HFONT font )
44 int i;
45 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
47 if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE;
49 return FALSE;
53 /*******************************************************************************
54 * ScaleFont
56 * Scale builtin font to requested lfHeight
59 static inline float Round(float f)
61 return (f > 0) ? (f + 0.5) : (f - 0.5);
64 static VOID ScaleFont(const AFM *afm, LONG lfHeight, PSFONT *font,
65 TEXTMETRICW *tm)
67 const WINMETRICS *wm = &(afm->WinMetrics);
68 USHORT usUnitsPerEm, usWinAscent, usWinDescent;
69 SHORT sAscender, sDescender, sLineGap, sAvgCharWidth;
71 TRACE("'%s' %i\n", afm->FontName, lfHeight);
73 if (lfHeight < 0) /* match em height */
75 font->fontinfo.Builtin.scale = - ((float)lfHeight / (float)(wm->usUnitsPerEm));
77 else /* match cell height */
79 font->fontinfo.Builtin.scale = (float)lfHeight /
80 (float)(wm->usWinAscent + wm->usWinDescent);
83 font->size.xx = (INT)Round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm);
84 font->size.xy = font->size.yx = 0;
85 font->size.yy = -(INT)Round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm);
87 usUnitsPerEm = (USHORT)Round((float)(wm->usUnitsPerEm) * font->fontinfo.Builtin.scale);
88 sAscender = (SHORT)Round((float)(wm->sAscender) * font->fontinfo.Builtin.scale);
89 sDescender = (SHORT)Round((float)(wm->sDescender) * font->fontinfo.Builtin.scale);
90 sLineGap = (SHORT)Round((float)(wm->sLineGap) * font->fontinfo.Builtin.scale);
91 usWinAscent = (USHORT)Round((float)(wm->usWinAscent) * font->fontinfo.Builtin.scale);
92 usWinDescent = (USHORT)Round((float)(wm->usWinDescent) * font->fontinfo.Builtin.scale);
93 sAvgCharWidth = (SHORT)Round((float)(wm->sAvgCharWidth) * font->fontinfo.Builtin.scale);
95 tm->tmAscent = (LONG)usWinAscent;
96 tm->tmDescent = (LONG)usWinDescent;
97 tm->tmHeight = tm->tmAscent + tm->tmDescent;
99 tm->tmInternalLeading = tm->tmHeight - (LONG)usUnitsPerEm;
100 if (tm->tmInternalLeading < 0)
101 tm->tmInternalLeading = 0;
103 tm->tmExternalLeading =
104 (LONG)(sAscender - sDescender + sLineGap) - tm->tmHeight;
105 if (tm->tmExternalLeading < 0)
106 tm->tmExternalLeading = 0;
108 tm->tmAveCharWidth = (LONG)sAvgCharWidth;
110 tm->tmWeight = afm->Weight;
111 tm->tmItalic = (afm->ItalicAngle != 0.0);
112 tm->tmUnderlined = 0;
113 tm->tmStruckOut = 0;
114 tm->tmFirstChar = (WCHAR)(afm->Metrics[0].UV);
115 tm->tmLastChar = (WCHAR)(afm->Metrics[afm->NumofMetrics - 1].UV);
116 tm->tmDefaultChar = 0x001f; /* Win2K does this - FIXME? */
117 tm->tmBreakChar = tm->tmFirstChar; /* should be 'space' */
119 tm->tmPitchAndFamily = TMPF_DEVICE | TMPF_VECTOR;
120 if (!afm->IsFixedPitch)
121 tm->tmPitchAndFamily |= TMPF_FIXED_PITCH; /* yes, it's backwards */
122 if (wm->usUnitsPerEm != 1000)
123 tm->tmPitchAndFamily |= TMPF_TRUETYPE;
125 tm->tmCharSet = ANSI_CHARSET; /* FIXME */
126 tm->tmOverhang = 0;
129 * This is kludgy. font->scale is used in several places in the driver
130 * to adjust PostScript-style metrics. Since these metrics have been
131 * "normalized" to an em-square size of 1000, font->scale needs to be
132 * similarly adjusted..
135 font->fontinfo.Builtin.scale *= (float)wm->usUnitsPerEm / 1000.0;
137 tm->tmMaxCharWidth = (LONG)Round(
138 (afm->FontBBox.urx - afm->FontBBox.llx) * font->fontinfo.Builtin.scale);
140 font->underlinePosition = afm->UnderlinePosition * font->fontinfo.Builtin.scale;
141 font->underlineThickness = afm->UnderlineThickness * font->fontinfo.Builtin.scale;
142 font->strikeoutPosition = tm->tmAscent / 2;
143 font->strikeoutThickness = font->underlineThickness;
145 TRACE("Selected PS font '%s' size %d weight %d.\n", afm->FontName,
146 font->size.xx, tm->tmWeight );
147 TRACE("H = %d As = %d Des = %d IL = %d EL = %d\n", tm->tmHeight,
148 tm->tmAscent, tm->tmDescent, tm->tmInternalLeading,
149 tm->tmExternalLeading);
153 /****************************************************************************
154 * PSDRV_SelectBuiltinFont
156 * Set up physDev->font for a builtin font
159 BOOL PSDRV_SelectBuiltinFont(PHYSDEV dev, HFONT hfont,
160 LOGFONTW *plf, LPSTR FaceName)
162 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
163 AFMLISTENTRY *afmle;
164 FONTFAMILY *family;
165 BOOL bd = FALSE, it = FALSE;
166 LONG height;
168 TRACE("Trying to find facename '%s'\n", FaceName);
170 /* Look for a matching font family */
171 for(family = physDev->pi->Fonts; family; family = family->next) {
172 if(!stricmp(FaceName, family->FamilyName))
173 break;
176 if(!family) {
177 /* Fallback for Window's font families to common PostScript families */
178 if(!strcmp(FaceName, "Arial"))
179 strcpy(FaceName, "Helvetica");
180 else if(!strcmp(FaceName, "System"))
181 strcpy(FaceName, "Helvetica");
182 else if(!strcmp(FaceName, "Times New Roman"))
183 strcpy(FaceName, "Times");
184 else if(!strcmp(FaceName, "Courier New"))
185 strcpy(FaceName, "Courier");
187 for(family = physDev->pi->Fonts; family; family = family->next) {
188 if(!strcmp(FaceName, family->FamilyName))
189 break;
192 /* If all else fails, use the first font defined for the printer */
193 if(!family)
194 family = physDev->pi->Fonts;
196 TRACE("Got family '%s'\n", family->FamilyName);
198 if(plf->lfItalic)
199 it = TRUE;
200 if(plf->lfWeight > 550)
201 bd = TRUE;
203 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
204 if( (bd == (afmle->afm->Weight == FW_BOLD)) &&
205 (it == (afmle->afm->ItalicAngle != 0.0)) )
206 break;
208 if(!afmle)
209 afmle = family->afmlist; /* not ideal */
211 TRACE("Got font '%s'\n", afmle->afm->FontName);
213 physDev->font.fontloc = Builtin;
214 physDev->font.fontinfo.Builtin.afm = afmle->afm;
216 height = plf->lfHeight;
217 /* stock fonts ignore the mapping mode */
218 if (!is_stock_font( hfont )) {
219 POINT pts[2];
220 pts[0].x = pts[0].y = pts[1].x = 0;
221 pts[1].y = height;
222 LPtoDP(dev->hdc, pts, 2);
223 height = pts[1].y - pts[0].y;
225 ScaleFont(physDev->font.fontinfo.Builtin.afm, height,
226 &(physDev->font), &(physDev->font.fontinfo.Builtin.tm));
229 /* Does anyone know if these are supposed to be reversed like this? */
231 physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectX = physDev->logPixelsY;
232 physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectY = physDev->logPixelsX;
234 return TRUE;
237 BOOL PSDRV_WriteSetBuiltinFont(PHYSDEV dev)
239 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
241 return PSDRV_WriteSetFont(dev, physDev->font.fontinfo.Builtin.afm->FontName,
242 physDev->font.size, physDev->font.escapement, FALSE);
245 BOOL PSDRV_WriteBuiltinGlyphShow(PHYSDEV dev, LPCWSTR str, INT count)
247 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
248 int i;
249 LPCSTR name;
251 for (i = 0; i < count; ++i)
253 name = PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->N->sz;
255 PSDRV_WriteGlyphShow(dev, name);
258 return TRUE;
261 /***********************************************************************
262 * PSDRV_GetTextMetrics
264 BOOL CDECL PSDRV_GetTextMetrics(PHYSDEV dev, TEXTMETRICW *metrics)
266 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
268 if (physDev->font.fontloc == Download)
270 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
271 return dev->funcs->pGetTextMetrics( dev, metrics );
274 memcpy(metrics, &(physDev->font.fontinfo.Builtin.tm),
275 sizeof(physDev->font.fontinfo.Builtin.tm));
276 return TRUE;
279 /******************************************************************************
280 * PSDRV_UVMetrics
282 * Find the AFMMETRICS for a given UV. Returns first glyph in the font
283 * (space?) if the font does not have a glyph for the given UV.
285 static int __cdecl MetricsByUV(const void *a, const void *b)
287 return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV);
290 const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm)
292 AFMMETRICS key;
293 const AFMMETRICS *needle;
296 * Ugly work-around for symbol fonts. Wine is sending characters which
297 * belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
298 * characters (U+0020 - U+00FF).
301 if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100)
302 UV |= 0xf000;
304 key.UV = UV;
306 needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS),
307 MetricsByUV);
309 if (needle == NULL)
311 WARN("No glyph for U+%.4X in %s\n", UV, afm->FontName);
312 needle = afm->Metrics;
315 return needle;
318 /***********************************************************************
319 * PSDRV_GetTextExtentExPoint
321 BOOL CDECL PSDRV_GetTextExtentExPoint(PHYSDEV dev, LPCWSTR str, INT count, LPINT alpDx)
323 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
324 int i;
325 float width = 0.0;
327 if (physDev->font.fontloc == Download)
329 dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
330 return dev->funcs->pGetTextExtentExPoint( dev, str, count, alpDx );
333 TRACE("%s %i\n", debugstr_wn(str, count), count);
335 for (i = 0; i < count; ++i)
337 width += PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->WX;
338 alpDx[i] = width * physDev->font.fontinfo.Builtin.scale;
340 return TRUE;
343 /***********************************************************************
344 * PSDRV_GetCharWidth
346 BOOL CDECL PSDRV_GetCharWidth(PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer)
348 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
349 UINT i;
351 if (physDev->font.fontloc == Download)
353 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
354 return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
357 TRACE("U+%.4X U+%.4X\n", firstChar, lastChar);
359 if (lastChar > 0xffff || firstChar > lastChar)
361 SetLastError(ERROR_INVALID_PARAMETER);
362 return FALSE;
365 for (i = firstChar; i <= lastChar; ++i)
367 *buffer = floor( PSDRV_UVMetrics(i, physDev->font.fontinfo.Builtin.afm)->WX
368 * physDev->font.fontinfo.Builtin.scale + 0.5 );
369 TRACE("U+%.4X: %i\n", i, *buffer);
370 ++buffer;
373 return TRUE;
377 /***********************************************************************
378 * PSDRV_GetFontMetric
380 static UINT PSDRV_GetFontMetric(HDC hdc, const AFM *afm,
381 NEWTEXTMETRICEXW *ntmx, ENUMLOGFONTEXW *elfx)
383 /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
385 TEXTMETRICW *tm = (TEXTMETRICW *)&(ntmx->ntmTm);
386 LOGFONTW *lf = &(elfx->elfLogFont);
387 PSFONT font;
389 memset(ntmx, 0, sizeof(*ntmx));
390 memset(elfx, 0, sizeof(*elfx));
392 ScaleFont(afm, -(LONG)(afm->WinMetrics.usUnitsPerEm), &font, tm);
394 lf->lfHeight = tm->tmHeight;
395 lf->lfWidth = tm->tmAveCharWidth;
396 lf->lfWeight = tm->tmWeight;
397 lf->lfItalic = tm->tmItalic;
398 lf->lfCharSet = tm->tmCharSet;
400 lf->lfPitchAndFamily = (afm->IsFixedPitch) ? FIXED_PITCH : VARIABLE_PITCH;
402 MultiByteToWideChar(CP_ACP, 0, afm->FamilyName, -1, lf->lfFaceName,
403 LF_FACESIZE);
405 return DEVICE_FONTTYPE;
408 /***********************************************************************
409 * PSDRV_EnumFonts
411 BOOL CDECL PSDRV_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lp )
413 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
414 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pEnumFonts );
415 ENUMLOGFONTEXW lf;
416 NEWTEXTMETRICEXW tm;
417 BOOL ret;
418 AFMLISTENTRY *afmle;
419 FONTFAMILY *family;
420 char FaceName[LF_FACESIZE];
422 ret = next->funcs->pEnumFonts( next, plf, proc, lp );
423 if (!ret) return FALSE;
425 if( plf && plf->lfFaceName[0] ) {
426 WideCharToMultiByte(CP_ACP, 0, plf->lfFaceName, -1,
427 FaceName, sizeof(FaceName), NULL, NULL);
428 TRACE("lfFaceName = '%s'\n", FaceName);
429 for(family = physDev->pi->Fonts; family; family = family->next) {
430 if(!strncmp(FaceName, family->FamilyName,
431 strlen(family->FamilyName)))
432 break;
434 if(family) {
435 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
436 UINT fm;
438 TRACE("Got '%s'\n", afmle->afm->FontName);
439 fm = PSDRV_GetFontMetric( dev->hdc, afmle->afm, &tm, &lf );
440 if (!(ret = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm, fm, lp )))
441 break;
444 } else {
446 TRACE("lfFaceName = NULL\n");
447 for(family = physDev->pi->Fonts; family; family = family->next) {
448 UINT fm;
450 afmle = family->afmlist;
451 TRACE("Got '%s'\n", afmle->afm->FontName);
452 fm = PSDRV_GetFontMetric( dev->hdc, afmle->afm, &tm, &lf );
453 if (!(ret = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm, fm, lp )))
454 break;
457 return ret;