Merged the NAS driver written by Nicolas
[wine/multimedia.git] / dlls / wineps / builtin.c
blob4b030e52d630425a087a64faea99c5ae6c8cdd2f
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <string.h>
21 #include <stdlib.h>
22 #include <assert.h>
23 #include "winspool.h"
24 #include "gdi.h"
25 #include "psdrv.h"
26 #include "wine/debug.h"
27 #include "winerror.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
32 /***********************************************************************
33 * is_stock_font
35 inline static BOOL is_stock_font( HFONT font )
37 int i;
38 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
40 if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE;
42 return FALSE;
46 /*******************************************************************************
47 * ScaleFont
49 * Scale builtin font to requested lfHeight
52 inline static float round(float f)
54 return (f > 0) ? (f + 0.5) : (f - 0.5);
57 static VOID ScaleFont(const AFM *afm, LONG lfHeight, PSFONT *font,
58 TEXTMETRICW *tm)
60 const WINMETRICS *wm = &(afm->WinMetrics);
61 USHORT usUnitsPerEm, usWinAscent, usWinDescent;
62 SHORT sAscender, sDescender, sLineGap, sAvgCharWidth;
64 TRACE("'%s' %li\n", afm->FontName, lfHeight);
66 if (lfHeight < 0) /* match em height */
68 font->fontinfo.Builtin.scale = - ((float)lfHeight / (float)(wm->usUnitsPerEm));
70 else /* match cell height */
72 font->fontinfo.Builtin.scale = (float)lfHeight /
73 (float)(wm->usWinAscent + wm->usWinDescent);
76 font->size = (INT)round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm);
78 usUnitsPerEm = (USHORT)round((float)(wm->usUnitsPerEm) * font->fontinfo.Builtin.scale);
79 sAscender = (SHORT)round((float)(wm->sAscender) * font->fontinfo.Builtin.scale);
80 sDescender = (SHORT)round((float)(wm->sDescender) * font->fontinfo.Builtin.scale);
81 sLineGap = (SHORT)round((float)(wm->sLineGap) * font->fontinfo.Builtin.scale);
82 usWinAscent = (USHORT)round((float)(wm->usWinAscent) * font->fontinfo.Builtin.scale);
83 usWinDescent = (USHORT)round((float)(wm->usWinDescent) * font->fontinfo.Builtin.scale);
84 sAvgCharWidth = (SHORT)round((float)(wm->sAvgCharWidth) * font->fontinfo.Builtin.scale);
86 tm->tmAscent = (LONG)usWinAscent;
87 tm->tmDescent = (LONG)usWinDescent;
88 tm->tmHeight = tm->tmAscent + tm->tmDescent;
90 tm->tmInternalLeading = tm->tmHeight - (LONG)usUnitsPerEm;
91 if (tm->tmInternalLeading < 0)
92 tm->tmInternalLeading = 0;
94 tm->tmExternalLeading =
95 (LONG)(sAscender - sDescender + sLineGap) - tm->tmHeight;
96 if (tm->tmExternalLeading < 0)
97 tm->tmExternalLeading = 0;
99 tm->tmAveCharWidth = (LONG)sAvgCharWidth;
101 tm->tmWeight = afm->Weight;
102 tm->tmItalic = (afm->ItalicAngle != 0.0);
103 tm->tmUnderlined = 0;
104 tm->tmStruckOut = 0;
105 tm->tmFirstChar = (WCHAR)(afm->Metrics[0].UV);
106 tm->tmLastChar = (WCHAR)(afm->Metrics[afm->NumofMetrics - 1].UV);
107 tm->tmDefaultChar = 0x001f; /* Win2K does this - FIXME? */
108 tm->tmBreakChar = tm->tmFirstChar; /* should be 'space' */
110 tm->tmPitchAndFamily = TMPF_DEVICE | TMPF_VECTOR;
111 if (!afm->IsFixedPitch)
112 tm->tmPitchAndFamily |= TMPF_FIXED_PITCH; /* yes, it's backwards */
113 if (wm->usUnitsPerEm != 1000)
114 tm->tmPitchAndFamily |= TMPF_TRUETYPE;
116 tm->tmCharSet = ANSI_CHARSET; /* FIXME */
117 tm->tmOverhang = 0;
120 * This is kludgy. font->scale is used in several places in the driver
121 * to adjust PostScript-style metrics. Since these metrics have been
122 * "normalized" to an em-square size of 1000, font->scale needs to be
123 * similarly adjusted..
126 font->fontinfo.Builtin.scale *= (float)wm->usUnitsPerEm / 1000.0;
128 tm->tmMaxCharWidth = (LONG)round(
129 (afm->FontBBox.urx - afm->FontBBox.llx) * font->fontinfo.Builtin.scale);
131 font->underlinePosition = afm->UnderlinePosition * font->fontinfo.Builtin.scale;
132 font->underlineThickness = afm->UnderlineThickness * font->fontinfo.Builtin.scale;
133 font->strikeoutPosition = tm->tmAscent / 2;
134 font->strikeoutThickness = font->underlineThickness;
136 TRACE("Selected PS font '%s' size %d weight %ld.\n", afm->FontName,
137 font->size, tm->tmWeight );
138 TRACE("H = %ld As = %ld Des = %ld IL = %ld EL = %ld\n", tm->tmHeight,
139 tm->tmAscent, tm->tmDescent, tm->tmInternalLeading,
140 tm->tmExternalLeading);
144 /****************************************************************************
145 * PSDRV_SelectBuiltinFont
147 * Set up physDev->font for a builtin font
150 BOOL PSDRV_SelectBuiltinFont(PSDRV_PDEVICE *physDev, HFONT hfont,
151 LOGFONTW *plf, LPSTR FaceName)
153 AFMLISTENTRY *afmle;
154 FONTFAMILY *family;
155 BOOL bd = FALSE, it = FALSE;
156 LONG height;
158 TRACE("Trying to find facename '%s'\n", FaceName);
160 /* Look for a matching font family */
161 for(family = physDev->pi->Fonts; family; family = family->next) {
162 if(!strcasecmp(FaceName, family->FamilyName))
163 break;
166 if(!family) {
167 /* Fallback for Window's font families to common PostScript families */
168 if(!strcmp(FaceName, "Arial"))
169 strcpy(FaceName, "Helvetica");
170 else if(!strcmp(FaceName, "System"))
171 strcpy(FaceName, "Helvetica");
172 else if(!strcmp(FaceName, "Times New Roman"))
173 strcpy(FaceName, "Times");
174 else if(!strcmp(FaceName, "Courier New"))
175 strcpy(FaceName, "Courier");
177 for(family = physDev->pi->Fonts; family; family = family->next) {
178 if(!strcmp(FaceName, family->FamilyName))
179 break;
182 /* If all else fails, use the first font defined for the printer */
183 if(!family)
184 family = physDev->pi->Fonts;
186 TRACE("Got family '%s'\n", family->FamilyName);
188 if(plf->lfItalic)
189 it = TRUE;
190 if(plf->lfWeight > 550)
191 bd = TRUE;
193 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
194 if( (bd == (afmle->afm->Weight == FW_BOLD)) &&
195 (it == (afmle->afm->ItalicAngle != 0.0)) )
196 break;
198 if(!afmle)
199 afmle = family->afmlist; /* not ideal */
201 TRACE("Got font '%s'\n", afmle->afm->FontName);
203 physDev->font.fontloc = Builtin;
204 physDev->font.fontinfo.Builtin.afm = afmle->afm;
206 height = plf->lfHeight;
207 /* stock fonts ignore the mapping mode */
208 if (!is_stock_font( hfont )) {
209 POINT pts[2];
210 pts[0].x = pts[0].y = pts[1].x = 0;
211 pts[1].y = height;
212 LPtoDP(physDev->hdc, pts, 2);
213 height = pts[1].y - pts[0].y;
215 ScaleFont(physDev->font.fontinfo.Builtin.afm, height,
216 &(physDev->font), &(physDev->font.fontinfo.Builtin.tm));
219 /* Does anyone know if these are supposed to be reversed like this? */
221 physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectX = physDev->logPixelsY;
222 physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectY = physDev->logPixelsX;
224 return TRUE;
227 BOOL PSDRV_WriteSetBuiltinFont(PSDRV_PDEVICE *physDev)
229 return PSDRV_WriteSetFont(physDev,
230 physDev->font.fontinfo.Builtin.afm->FontName,
231 physDev->font.size, physDev->font.escapement);
234 BOOL PSDRV_WriteBuiltinGlyphShow(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count)
236 int i;
237 LPCSTR name;
239 for (i = 0; i < count; ++i)
241 name = PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->N->sz;
243 PSDRV_WriteGlyphShow(physDev, name);
246 return TRUE;
249 /***********************************************************************
250 * PSDRV_GetTextMetrics
252 BOOL PSDRV_GetTextMetrics(PSDRV_PDEVICE *physDev, TEXTMETRICW *metrics)
254 assert(physDev->dc->gdiFont == 0);
255 assert(physDev->font.fontloc == Builtin);
257 memcpy(metrics, &(physDev->font.fontinfo.Builtin.tm),
258 sizeof(physDev->font.fontinfo.Builtin.tm));
259 return TRUE;
262 /******************************************************************************
263 * PSDRV_UVMetrics
265 * Find the AFMMETRICS for a given UV. Returns first glyph in the font
266 * (space?) if the font does not have a glyph for the given UV.
268 static int MetricsByUV(const void *a, const void *b)
270 return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV);
273 const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm)
275 AFMMETRICS key;
276 const AFMMETRICS *needle;
279 * Ugly work-around for symbol fonts. Wine is sending characters which
280 * belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
281 * characters (U+0020 - U+00FF).
284 if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100)
285 UV |= 0xf000;
287 key.UV = UV;
289 needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS),
290 MetricsByUV);
292 if (needle == NULL)
294 WARN("No glyph for U+%.4lX in %s\n", UV, afm->FontName);
295 needle = afm->Metrics;
298 return needle;
301 /***********************************************************************
302 * PSDRV_GetTextExtentPoint
304 BOOL PSDRV_GetTextExtentPoint(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count, LPSIZE size)
306 int i;
307 float width = 0.0;
309 assert(physDev->dc->gdiFont == 0);
310 assert(physDev->font.fontloc == Builtin);
312 TRACE("%s %i\n", debugstr_wn(str, count), count);
314 for (i = 0; i < count && str[i] != '\0'; ++i)
315 width += PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->WX;
317 width *= physDev->font.fontinfo.Builtin.scale;
319 size->cx = GDI_ROUND((FLOAT)width * physDev->dc->xformVport2World.eM11);
320 size->cy = GDI_ROUND((FLOAT)physDev->font.fontinfo.Builtin.tm.tmHeight *
321 physDev->dc->xformVport2World.eM22);
323 TRACE("cx=%li cy=%li\n", size->cx, size->cy);
325 return TRUE;
328 /***********************************************************************
329 * PSDRV_GetCharWidth
331 BOOL PSDRV_GetCharWidth(PSDRV_PDEVICE *physDev, UINT firstChar, UINT lastChar, LPINT buffer)
333 UINT i;
335 assert(physDev->dc->gdiFont == 0);
336 assert(physDev->font.fontloc == Builtin);
338 TRACE("U+%.4X U+%.4X\n", firstChar, lastChar);
340 if (lastChar > 0xffff || firstChar > lastChar)
342 SetLastError(ERROR_INVALID_PARAMETER);
343 return FALSE;
346 for (i = firstChar; i <= lastChar; ++i)
348 *buffer = GDI_ROUND(PSDRV_UVMetrics(i, physDev->font.fontinfo.Builtin.afm)->WX
349 * physDev->font.fontinfo.Builtin.scale);
350 TRACE("U+%.4X: %i\n", i, *buffer);
351 ++buffer;
354 return TRUE;
358 /***********************************************************************
359 * PSDRV_GetFontMetric
361 static UINT PSDRV_GetFontMetric(HDC hdc, const AFM *afm,
362 NEWTEXTMETRICEXW *ntmx, ENUMLOGFONTEXW *elfx)
364 /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
366 TEXTMETRICW *tm = (TEXTMETRICW *)&(ntmx->ntmTm);
367 LOGFONTW *lf = &(elfx->elfLogFont);
368 PSFONT font;
370 memset(ntmx, 0, sizeof(*ntmx));
371 memset(elfx, 0, sizeof(*elfx));
373 ScaleFont(afm, -(LONG)(afm->WinMetrics.usUnitsPerEm), &font, tm);
375 lf->lfHeight = tm->tmHeight;
376 lf->lfWidth = tm->tmAveCharWidth;
377 lf->lfWeight = tm->tmWeight;
378 lf->lfItalic = tm->tmItalic;
379 lf->lfCharSet = tm->tmCharSet;
381 lf->lfPitchAndFamily = (afm->IsFixedPitch) ? FIXED_PITCH : VARIABLE_PITCH;
383 MultiByteToWideChar(CP_ACP, 0, afm->FamilyName, -1, lf->lfFaceName,
384 LF_FACESIZE);
386 return DEVICE_FONTTYPE;
389 /***********************************************************************
390 * PSDRV_EnumDeviceFonts
392 BOOL PSDRV_EnumDeviceFonts( PSDRV_PDEVICE *physDev, LPLOGFONTW plf,
393 DEVICEFONTENUMPROC proc, LPARAM lp )
395 ENUMLOGFONTEXW lf;
396 NEWTEXTMETRICEXW tm;
397 BOOL b, bRet = 0;
398 AFMLISTENTRY *afmle;
399 FONTFAMILY *family;
400 char FaceName[LF_FACESIZE];
402 if( plf->lfFaceName[0] ) {
403 WideCharToMultiByte(CP_ACP, 0, plf->lfFaceName, -1,
404 FaceName, sizeof(FaceName), NULL, NULL);
405 TRACE("lfFaceName = '%s'\n", FaceName);
406 for(family = physDev->pi->Fonts; family; family = family->next) {
407 if(!strncmp(FaceName, family->FamilyName,
408 strlen(family->FamilyName)))
409 break;
411 if(family) {
412 for(afmle = family->afmlist; afmle; afmle = afmle->next) {
413 TRACE("Got '%s'\n", afmle->afm->FontName);
414 if( (b = (*proc)( &lf, &tm,
415 PSDRV_GetFontMetric( physDev->hdc, afmle->afm, &tm, &lf ),
416 lp )) )
417 bRet = b;
418 else break;
421 } else {
423 TRACE("lfFaceName = NULL\n");
424 for(family = physDev->pi->Fonts; family; family = family->next) {
425 afmle = family->afmlist;
426 TRACE("Got '%s'\n", afmle->afm->FontName);
427 if( (b = (*proc)( &lf, &tm,
428 PSDRV_GetFontMetric( physDev->hdc, afmle->afm, &tm, &lf ),
429 lp )) )
430 bRet = b;
431 else break;
434 return bRet;