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