Fixed some issues found by winapi_check.
[wine] / dlls / wineps / builtin.c
1 /*
2  *      PostScript driver builtin font functions
3  *
4  *      Copyright 2002  Huw D M Davies for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
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"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
30
31
32 /***********************************************************************
33  *           is_stock_font
34  */
35 inline static BOOL is_stock_font( HFONT font )
36 {
37     int i;
38     for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
39     {
40         if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE;
41     }
42     return FALSE;
43 }
44
45
46 /*******************************************************************************
47  *  ScaleFont
48  *
49  *  Scale builtin font to requested lfHeight
50  *
51  */
52 inline static float Round(float f)
53 {
54     return (f > 0) ? (f + 0.5) : (f - 0.5);
55 }
56
57 static VOID ScaleFont(const AFM *afm, LONG lfHeight, PSFONT *font,
58                       TEXTMETRICW *tm)
59 {
60     const WINMETRICS    *wm = &(afm->WinMetrics);
61     USHORT              usUnitsPerEm, usWinAscent, usWinDescent;
62     SHORT               sAscender, sDescender, sLineGap, sAvgCharWidth;
63
64     TRACE("'%s' %li\n", afm->FontName, lfHeight);
65
66     if (lfHeight < 0)                                   /* match em height */
67     {
68         font->fontinfo.Builtin.scale = - ((float)lfHeight / (float)(wm->usUnitsPerEm));
69     }
70     else                                                /* match cell height */
71     {
72         font->fontinfo.Builtin.scale = (float)lfHeight /
73                 (float)(wm->usWinAscent + wm->usWinDescent);
74     }
75
76     font->size = (INT)Round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm);
77
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);
85
86     tm->tmAscent = (LONG)usWinAscent;
87     tm->tmDescent = (LONG)usWinDescent;
88     tm->tmHeight = tm->tmAscent + tm->tmDescent;
89
90     tm->tmInternalLeading = tm->tmHeight - (LONG)usUnitsPerEm;
91     if (tm->tmInternalLeading < 0)
92         tm->tmInternalLeading = 0;
93
94     tm->tmExternalLeading =
95             (LONG)(sAscender - sDescender + sLineGap) - tm->tmHeight;
96     if (tm->tmExternalLeading < 0)
97         tm->tmExternalLeading = 0;
98
99     tm->tmAveCharWidth = (LONG)sAvgCharWidth;
100
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' */
109
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;
115
116     tm->tmCharSet = ANSI_CHARSET;       /* FIXME */
117     tm->tmOverhang = 0;
118
119     /*
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..
124      */
125
126     font->fontinfo.Builtin.scale *= (float)wm->usUnitsPerEm / 1000.0;
127
128     tm->tmMaxCharWidth = (LONG)Round(
129             (afm->FontBBox.urx - afm->FontBBox.llx) * font->fontinfo.Builtin.scale);
130
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;
135
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);
141 }
142
143
144 /****************************************************************************
145  *  PSDRV_SelectBuiltinFont
146  *
147  *  Set up physDev->font for a builtin font
148  *
149  */
150 BOOL PSDRV_SelectBuiltinFont(PSDRV_PDEVICE *physDev, HFONT hfont,
151                              LOGFONTW *plf, LPSTR FaceName)
152 {
153     AFMLISTENTRY *afmle;
154     FONTFAMILY *family;
155     BOOL bd = FALSE, it = FALSE;
156     LONG height;
157
158     TRACE("Trying to find facename '%s'\n", FaceName);
159
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;
164     }
165
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");
176
177         for(family = physDev->pi->Fonts; family; family = family->next) {
178             if(!strcmp(FaceName, family->FamilyName))
179                 break;
180         }
181     }
182     /* If all else fails, use the first font defined for the printer */
183     if(!family)
184         family = physDev->pi->Fonts;
185
186     TRACE("Got family '%s'\n", family->FamilyName);
187
188     if(plf->lfItalic)
189         it = TRUE;
190     if(plf->lfWeight > 550)
191         bd = TRUE;
192
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;
197     }
198     if(!afmle)
199         afmle = family->afmlist; /* not ideal */
200
201     TRACE("Got font '%s'\n", afmle->afm->FontName);
202
203     physDev->font.fontloc = Builtin;
204     physDev->font.fontinfo.Builtin.afm = afmle->afm;
205
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;
214     }
215     ScaleFont(physDev->font.fontinfo.Builtin.afm, height,
216               &(physDev->font), &(physDev->font.fontinfo.Builtin.tm));
217
218
219     /* Does anyone know if these are supposed to be reversed like this? */
220
221     physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectX = physDev->logPixelsY;
222     physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectY = physDev->logPixelsX;
223
224     return TRUE;
225 }
226
227 BOOL PSDRV_WriteSetBuiltinFont(PSDRV_PDEVICE *physDev)
228 {
229     return PSDRV_WriteSetFont(physDev,
230                               physDev->font.fontinfo.Builtin.afm->FontName,
231                               physDev->font.size, physDev->font.escapement);
232 }
233
234 BOOL PSDRV_WriteBuiltinGlyphShow(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count)
235 {
236     int i;
237     LPCSTR name;
238
239     for (i = 0; i < count; ++i)
240     {
241         name = PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->N->sz;
242
243         PSDRV_WriteGlyphShow(physDev, name);
244     }
245
246     return TRUE;
247 }
248
249 /***********************************************************************
250  *           PSDRV_GetTextMetrics
251  */
252 BOOL PSDRV_GetTextMetrics(PSDRV_PDEVICE *physDev, TEXTMETRICW *metrics)
253 {
254     assert(physDev->dc->gdiFont == 0);
255     assert(physDev->font.fontloc == Builtin);
256
257     memcpy(metrics, &(physDev->font.fontinfo.Builtin.tm),
258            sizeof(physDev->font.fontinfo.Builtin.tm));
259     return TRUE;
260 }
261
262 /******************************************************************************
263  *      PSDRV_UVMetrics
264  *
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.
267  */
268 static int MetricsByUV(const void *a, const void *b)
269 {
270     return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV);
271 }
272
273 const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm)
274 {
275     AFMMETRICS          key;
276     const AFMMETRICS    *needle;
277
278     /*
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).
282      */
283
284     if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100)
285         UV |= 0xf000;
286
287     key.UV = UV;
288
289     needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS),
290             MetricsByUV);
291
292     if (needle == NULL)
293     {
294         WARN("No glyph for U+%.4lX in %s\n", UV, afm->FontName);
295         needle = afm->Metrics;
296     }
297
298     return needle;
299 }
300
301 /***********************************************************************
302  *           PSDRV_GetTextExtentPoint
303  */
304 BOOL PSDRV_GetTextExtentPoint(PSDRV_PDEVICE *physDev, LPCWSTR str, INT count, LPSIZE size)
305 {
306     int             i;
307     float           width = 0.0;
308
309     assert(physDev->dc->gdiFont == 0);
310     assert(physDev->font.fontloc == Builtin);
311
312     TRACE("%s %i\n", debugstr_wn(str, count), count);
313
314     for (i = 0; i < count && str[i] != '\0'; ++i)
315         width += PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->WX;
316
317     width *= physDev->font.fontinfo.Builtin.scale;
318
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);
322
323     TRACE("cx=%li cy=%li\n", size->cx, size->cy);
324
325     return TRUE;
326 }
327
328 /***********************************************************************
329  *           PSDRV_GetCharWidth
330  */
331 BOOL PSDRV_GetCharWidth(PSDRV_PDEVICE *physDev, UINT firstChar, UINT lastChar, LPINT buffer)
332 {
333     UINT            i;
334
335     assert(physDev->dc->gdiFont == 0);
336     assert(physDev->font.fontloc == Builtin);
337
338     TRACE("U+%.4X U+%.4X\n", firstChar, lastChar);
339
340     if (lastChar > 0xffff || firstChar > lastChar)
341     {
342         SetLastError(ERROR_INVALID_PARAMETER);
343         return FALSE;
344     }
345
346     for (i = firstChar; i <= lastChar; ++i)
347     {
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;
352     }
353
354     return TRUE;
355 }
356
357
358 /***********************************************************************
359  *           PSDRV_GetFontMetric
360  */
361 static UINT PSDRV_GetFontMetric(HDC hdc, const AFM *afm,
362         NEWTEXTMETRICEXW *ntmx, ENUMLOGFONTEXW *elfx)
363 {
364     /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
365
366     TEXTMETRICW     *tm = (TEXTMETRICW *)&(ntmx->ntmTm);
367     LOGFONTW        *lf = &(elfx->elfLogFont);
368     PSFONT          font;
369
370     memset(ntmx, 0, sizeof(*ntmx));
371     memset(elfx, 0, sizeof(*elfx));
372
373     ScaleFont(afm, -(LONG)(afm->WinMetrics.usUnitsPerEm), &font, tm);
374
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;
380
381     lf->lfPitchAndFamily = (afm->IsFixedPitch) ? FIXED_PITCH : VARIABLE_PITCH;
382
383     MultiByteToWideChar(CP_ACP, 0, afm->FamilyName, -1, lf->lfFaceName,
384             LF_FACESIZE);
385
386     return DEVICE_FONTTYPE;
387 }
388
389 /***********************************************************************
390  *           PSDRV_EnumDeviceFonts
391  */
392 BOOL PSDRV_EnumDeviceFonts( PSDRV_PDEVICE *physDev, LPLOGFONTW plf,
393                             DEVICEFONTENUMPROC proc, LPARAM lp )
394 {
395     ENUMLOGFONTEXW      lf;
396     NEWTEXTMETRICEXW    tm;
397     BOOL                b, bRet = 0;
398     AFMLISTENTRY        *afmle;
399     FONTFAMILY          *family;
400     char                FaceName[LF_FACESIZE];
401
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;
410         }
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;
419             }
420         }
421     } else {
422
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;
432         }
433     }
434     return bRet;
435 }