quartz: COM cleanup for AsyncReader and FileAsyncReader.
[wine] / dlls / wineps.drv / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 #include <stdarg.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <assert.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winerror.h"
29 #include "wingdi.h"
30 #include "winnls.h"
31
32 #include "psdrv.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
36
37
38 /***********************************************************************
39  *           is_stock_font
40  */
41 static inline BOOL is_stock_font( HFONT font )
42 {
43     int i;
44     for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
45     {
46         if (i != DEFAULT_PALETTE && font == GetStockObject(i)) return TRUE;
47     }
48     return FALSE;
49 }
50
51
52 /*******************************************************************************
53  *  ScaleFont
54  *
55  *  Scale builtin font to requested lfHeight
56  *
57  */
58 static inline float Round(float f)
59 {
60     return (f > 0) ? (f + 0.5) : (f - 0.5);
61 }
62
63 static VOID ScaleFont(const AFM *afm, LONG lfHeight, PSFONT *font,
64                       TEXTMETRICW *tm)
65 {
66     const WINMETRICS    *wm = &(afm->WinMetrics);
67     USHORT              usUnitsPerEm, usWinAscent, usWinDescent;
68     SHORT               sAscender, sDescender, sLineGap, sAvgCharWidth;
69
70     TRACE("'%s' %i\n", afm->FontName, lfHeight);
71
72     if (lfHeight < 0)                                   /* match em height */
73     {
74         font->fontinfo.Builtin.scale = - ((float)lfHeight / (float)(wm->usUnitsPerEm));
75     }
76     else                                                /* match cell height */
77     {
78         font->fontinfo.Builtin.scale = (float)lfHeight /
79                 (float)(wm->usWinAscent + wm->usWinDescent);
80     }
81
82     font->size.xx = (INT)Round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm);
83     font->size.xy = font->size.yx = 0;
84     font->size.yy = -(INT)Round(font->fontinfo.Builtin.scale * (float)wm->usUnitsPerEm);
85
86     usUnitsPerEm = (USHORT)Round((float)(wm->usUnitsPerEm) * font->fontinfo.Builtin.scale);
87     sAscender = (SHORT)Round((float)(wm->sAscender) * font->fontinfo.Builtin.scale);
88     sDescender = (SHORT)Round((float)(wm->sDescender) * font->fontinfo.Builtin.scale);
89     sLineGap = (SHORT)Round((float)(wm->sLineGap) * font->fontinfo.Builtin.scale);
90     usWinAscent = (USHORT)Round((float)(wm->usWinAscent) * font->fontinfo.Builtin.scale);
91     usWinDescent = (USHORT)Round((float)(wm->usWinDescent) * font->fontinfo.Builtin.scale);
92     sAvgCharWidth = (SHORT)Round((float)(wm->sAvgCharWidth) * font->fontinfo.Builtin.scale);
93
94     tm->tmAscent = (LONG)usWinAscent;
95     tm->tmDescent = (LONG)usWinDescent;
96     tm->tmHeight = tm->tmAscent + tm->tmDescent;
97
98     tm->tmInternalLeading = tm->tmHeight - (LONG)usUnitsPerEm;
99     if (tm->tmInternalLeading < 0)
100         tm->tmInternalLeading = 0;
101
102     tm->tmExternalLeading =
103             (LONG)(sAscender - sDescender + sLineGap) - tm->tmHeight;
104     if (tm->tmExternalLeading < 0)
105         tm->tmExternalLeading = 0;
106
107     tm->tmAveCharWidth = (LONG)sAvgCharWidth;
108
109     tm->tmWeight = afm->Weight;
110     tm->tmItalic = (afm->ItalicAngle != 0.0);
111     tm->tmUnderlined = 0;
112     tm->tmStruckOut = 0;
113     tm->tmFirstChar = (WCHAR)(afm->Metrics[0].UV);
114     tm->tmLastChar = (WCHAR)(afm->Metrics[afm->NumofMetrics - 1].UV);
115     tm->tmDefaultChar = 0x001f;         /* Win2K does this - FIXME? */
116     tm->tmBreakChar = tm->tmFirstChar;          /* should be 'space' */
117
118     tm->tmPitchAndFamily = TMPF_DEVICE | TMPF_VECTOR;
119     if (!afm->IsFixedPitch)
120         tm->tmPitchAndFamily |= TMPF_FIXED_PITCH;   /* yes, it's backwards */
121     if (wm->usUnitsPerEm != 1000)
122         tm->tmPitchAndFamily |= TMPF_TRUETYPE;
123
124     tm->tmCharSet = ANSI_CHARSET;       /* FIXME */
125     tm->tmOverhang = 0;
126
127     /*
128      *  This is kludgy.  font->scale is used in several places in the driver
129      *  to adjust PostScript-style metrics.  Since these metrics have been
130      *  "normalized" to an em-square size of 1000, font->scale needs to be
131      *  similarly adjusted..
132      */
133
134     font->fontinfo.Builtin.scale *= (float)wm->usUnitsPerEm / 1000.0;
135
136     tm->tmMaxCharWidth = (LONG)Round(
137             (afm->FontBBox.urx - afm->FontBBox.llx) * font->fontinfo.Builtin.scale);
138
139     font->underlinePosition = afm->UnderlinePosition * font->fontinfo.Builtin.scale;
140     font->underlineThickness = afm->UnderlineThickness * font->fontinfo.Builtin.scale;
141     font->strikeoutPosition = tm->tmAscent / 2;
142     font->strikeoutThickness = font->underlineThickness;
143
144     TRACE("Selected PS font '%s' size %d weight %d.\n", afm->FontName,
145           font->size.xx, tm->tmWeight );
146     TRACE("H = %d As = %d Des = %d IL = %d EL = %d\n", tm->tmHeight,
147             tm->tmAscent, tm->tmDescent, tm->tmInternalLeading,
148             tm->tmExternalLeading);
149 }
150
151
152 /****************************************************************************
153  *  PSDRV_SelectBuiltinFont
154  *
155  *  Set up physDev->font for a builtin font
156  *
157  */
158 BOOL PSDRV_SelectBuiltinFont(PHYSDEV dev, HFONT hfont,
159                              LOGFONTW *plf, LPSTR FaceName)
160 {
161     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
162     AFMLISTENTRY *afmle;
163     FONTFAMILY *family;
164     BOOL bd = FALSE, it = FALSE;
165     LONG height;
166
167     TRACE("Trying to find facename '%s'\n", FaceName);
168
169     /* Look for a matching font family */
170     for(family = physDev->pi->Fonts; family; family = family->next) {
171         if(!strcasecmp(FaceName, family->FamilyName))
172             break;
173     }
174
175     if(!family) {
176         /* Fallback for Window's font families to common PostScript families */
177         if(!strcmp(FaceName, "Arial"))
178             strcpy(FaceName, "Helvetica");
179         else if(!strcmp(FaceName, "System"))
180             strcpy(FaceName, "Helvetica");
181         else if(!strcmp(FaceName, "Times New Roman"))
182             strcpy(FaceName, "Times");
183         else if(!strcmp(FaceName, "Courier New"))
184             strcpy(FaceName, "Courier");
185
186         for(family = physDev->pi->Fonts; family; family = family->next) {
187             if(!strcmp(FaceName, family->FamilyName))
188                 break;
189         }
190     }
191     /* If all else fails, use the first font defined for the printer */
192     if(!family)
193         family = physDev->pi->Fonts;
194
195     TRACE("Got family '%s'\n", family->FamilyName);
196
197     if(plf->lfItalic)
198         it = TRUE;
199     if(plf->lfWeight > 550)
200         bd = TRUE;
201
202     for(afmle = family->afmlist; afmle; afmle = afmle->next) {
203         if( (bd == (afmle->afm->Weight == FW_BOLD)) &&
204             (it == (afmle->afm->ItalicAngle != 0.0)) )
205                 break;
206     }
207     if(!afmle)
208         afmle = family->afmlist; /* not ideal */
209
210     TRACE("Got font '%s'\n", afmle->afm->FontName);
211
212     physDev->font.fontloc = Builtin;
213     physDev->font.fontinfo.Builtin.afm = afmle->afm;
214
215     height = plf->lfHeight;
216     /* stock fonts ignore the mapping mode */
217     if (!is_stock_font( hfont )) {
218         POINT pts[2];
219         pts[0].x = pts[0].y = pts[1].x = 0;
220         pts[1].y = height;
221         LPtoDP(dev->hdc, pts, 2);
222         height = pts[1].y - pts[0].y;
223     }
224     ScaleFont(physDev->font.fontinfo.Builtin.afm, height,
225               &(physDev->font), &(physDev->font.fontinfo.Builtin.tm));
226
227
228     /* Does anyone know if these are supposed to be reversed like this? */
229
230     physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectX = physDev->logPixelsY;
231     physDev->font.fontinfo.Builtin.tm.tmDigitizedAspectY = physDev->logPixelsX;
232
233     return TRUE;
234 }
235
236 BOOL PSDRV_WriteSetBuiltinFont(PHYSDEV dev)
237 {
238     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
239
240     return PSDRV_WriteSetFont(dev, physDev->font.fontinfo.Builtin.afm->FontName,
241                               physDev->font.size, physDev->font.escapement);
242 }
243
244 BOOL PSDRV_WriteBuiltinGlyphShow(PHYSDEV dev, LPCWSTR str, INT count)
245 {
246     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
247     int i;
248     LPCSTR name;
249
250     for (i = 0; i < count; ++i)
251     {
252         name = PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->N->sz;
253
254         PSDRV_WriteGlyphShow(dev, name);
255     }
256
257     return TRUE;
258 }
259
260 /***********************************************************************
261  *           PSDRV_GetTextMetrics
262  */
263 BOOL PSDRV_GetTextMetrics(PHYSDEV dev, TEXTMETRICW *metrics)
264 {
265     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
266
267     if (physDev->font.fontloc == Download)
268     {
269         dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
270         return dev->funcs->pGetTextMetrics( dev, metrics );
271     }
272
273     memcpy(metrics, &(physDev->font.fontinfo.Builtin.tm),
274            sizeof(physDev->font.fontinfo.Builtin.tm));
275     return TRUE;
276 }
277
278 /******************************************************************************
279  *      PSDRV_UVMetrics
280  *
281  *  Find the AFMMETRICS for a given UV.  Returns first glyph in the font
282  *  (space?) if the font does not have a glyph for the given UV.
283  */
284 static int MetricsByUV(const void *a, const void *b)
285 {
286     return (int)(((const AFMMETRICS *)a)->UV - ((const AFMMETRICS *)b)->UV);
287 }
288
289 const AFMMETRICS *PSDRV_UVMetrics(LONG UV, const AFM *afm)
290 {
291     AFMMETRICS          key;
292     const AFMMETRICS    *needle;
293
294     /*
295      *  Ugly work-around for symbol fonts.  Wine is sending characters which
296      *  belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
297      *  characters (U+0020 - U+00FF).
298      */
299
300     if ((afm->Metrics->UV & 0xff00) == 0xf000 && UV < 0x100)
301         UV |= 0xf000;
302
303     key.UV = UV;
304
305     needle = bsearch(&key, afm->Metrics, afm->NumofMetrics, sizeof(AFMMETRICS),
306             MetricsByUV);
307
308     if (needle == NULL)
309     {
310         WARN("No glyph for U+%.4X in %s\n", UV, afm->FontName);
311         needle = afm->Metrics;
312     }
313
314     return needle;
315 }
316
317 /***********************************************************************
318  *           PSDRV_GetTextExtentExPoint
319  */
320 BOOL PSDRV_GetTextExtentExPoint(PHYSDEV dev, LPCWSTR str, INT count,
321                                 INT maxExt, LPINT lpnFit, LPINT alpDx, LPSIZE size)
322 {
323     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
324     int             nfit = 0;
325     int             i;
326     float           width = 0.0;
327     float           scale;
328
329     if (physDev->font.fontloc == Download)
330     {
331         dev = GET_NEXT_PHYSDEV( dev, pGetTextExtentExPoint );
332         return dev->funcs->pGetTextExtentExPoint( dev, str, count, maxExt, lpnFit, alpDx, size );
333     }
334
335     TRACE("%s %i\n", debugstr_wn(str, count), count);
336
337     scale = physDev->font.fontinfo.Builtin.scale;
338     for (i = 0; i < count && str[i] != '\0'; ++i)
339     {
340         float scaled_width;
341         width += PSDRV_UVMetrics(str[i], physDev->font.fontinfo.Builtin.afm)->WX;
342         scaled_width = width * scale;
343         if (alpDx)
344             alpDx[i] = scaled_width;
345         if (scaled_width <= maxExt)
346             ++nfit;
347     }
348
349     size->cx = width * physDev->font.fontinfo.Builtin.scale;
350     size->cy = physDev->font.fontinfo.Builtin.tm.tmHeight;
351
352     if (lpnFit)
353         *lpnFit = nfit;
354
355     TRACE("cx=%i cy=%i\n", size->cx, size->cy);
356
357     return TRUE;
358 }
359
360 /***********************************************************************
361  *           PSDRV_GetCharWidth
362  */
363 BOOL PSDRV_GetCharWidth(PHYSDEV dev, UINT firstChar, UINT lastChar, LPINT buffer)
364 {
365     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
366     UINT            i;
367
368     if (physDev->font.fontloc == Download)
369     {
370         dev = GET_NEXT_PHYSDEV( dev, pGetCharWidth );
371         return dev->funcs->pGetCharWidth( dev, firstChar, lastChar, buffer );
372     }
373
374     TRACE("U+%.4X U+%.4X\n", firstChar, lastChar);
375
376     if (lastChar > 0xffff || firstChar > lastChar)
377     {
378         SetLastError(ERROR_INVALID_PARAMETER);
379         return FALSE;
380     }
381
382     for (i = firstChar; i <= lastChar; ++i)
383     {
384         *buffer = floor( PSDRV_UVMetrics(i, physDev->font.fontinfo.Builtin.afm)->WX
385                          * physDev->font.fontinfo.Builtin.scale + 0.5 );
386         TRACE("U+%.4X: %i\n", i, *buffer);
387         ++buffer;
388     }
389
390     return TRUE;
391 }
392
393
394 /***********************************************************************
395  *           PSDRV_GetFontMetric
396  */
397 static UINT PSDRV_GetFontMetric(HDC hdc, const AFM *afm,
398         NEWTEXTMETRICEXW *ntmx, ENUMLOGFONTEXW *elfx)
399 {
400     /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
401
402     TEXTMETRICW     *tm = (TEXTMETRICW *)&(ntmx->ntmTm);
403     LOGFONTW        *lf = &(elfx->elfLogFont);
404     PSFONT          font;
405
406     memset(ntmx, 0, sizeof(*ntmx));
407     memset(elfx, 0, sizeof(*elfx));
408
409     ScaleFont(afm, -(LONG)(afm->WinMetrics.usUnitsPerEm), &font, tm);
410
411     lf->lfHeight = tm->tmHeight;
412     lf->lfWidth = tm->tmAveCharWidth;
413     lf->lfWeight = tm->tmWeight;
414     lf->lfItalic = tm->tmItalic;
415     lf->lfCharSet = tm->tmCharSet;
416
417     lf->lfPitchAndFamily = (afm->IsFixedPitch) ? FIXED_PITCH : VARIABLE_PITCH;
418
419     MultiByteToWideChar(CP_ACP, 0, afm->FamilyName, -1, lf->lfFaceName,
420             LF_FACESIZE);
421
422     return DEVICE_FONTTYPE;
423 }
424
425 /***********************************************************************
426  *           PSDRV_EnumFonts
427  */
428 BOOL PSDRV_EnumFonts( PHYSDEV dev, LPLOGFONTW plf, FONTENUMPROCW proc, LPARAM lp )
429 {
430     PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
431     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pEnumFonts );
432     ENUMLOGFONTEXW      lf;
433     NEWTEXTMETRICEXW    tm;
434     BOOL                ret;
435     AFMLISTENTRY        *afmle;
436     FONTFAMILY          *family;
437     char                FaceName[LF_FACESIZE];
438
439     ret = next->funcs->pEnumFonts( next, plf, proc, lp );
440     if (!ret) return FALSE;
441
442     if( plf && plf->lfFaceName[0] ) {
443         WideCharToMultiByte(CP_ACP, 0, plf->lfFaceName, -1,
444                           FaceName, sizeof(FaceName), NULL, NULL);
445         TRACE("lfFaceName = '%s'\n", FaceName);
446         for(family = physDev->pi->Fonts; family; family = family->next) {
447             if(!strncmp(FaceName, family->FamilyName,
448                         strlen(family->FamilyName)))
449                 break;
450         }
451         if(family) {
452             for(afmle = family->afmlist; afmle; afmle = afmle->next) {
453                 UINT fm;
454
455                 TRACE("Got '%s'\n", afmle->afm->FontName);
456                 fm = PSDRV_GetFontMetric( dev->hdc, afmle->afm, &tm, &lf );
457                 if (!(ret = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm, fm, lp )))
458                     break;
459             }
460         }
461     } else {
462
463         TRACE("lfFaceName = NULL\n");
464         for(family = physDev->pi->Fonts; family; family = family->next) {
465             UINT fm;
466
467             afmle = family->afmlist;
468             TRACE("Got '%s'\n", afmle->afm->FontName);
469             fm = PSDRV_GetFontMetric( dev->hdc, afmle->afm, &tm, &lf );
470             if (!(ret = (*proc)( &lf.elfLogFont, (TEXTMETRICW *)&tm, fm, lp )))
471                 break;
472         }
473     }
474     return ret;
475 }