Handle WM_CHARs and pass them to TREEVIEW_ProcessLetterKeys. See also
[wine] / dlls / wineps / font.c
1 /*
2  *      PostScript driver font functions
3  *
4  *      Copyright 1998  Huw D M Davies
5  *
6  */
7 #include <string.h>
8 #include "winspool.h"
9 #include "psdrv.h"
10 #include "debugtools.h"
11 #include "gdi.h"
12 #include "winerror.h"
13
14 DEFAULT_DEBUG_CHANNEL(psdrv);
15
16
17 /***********************************************************************
18  *           PSDRV_FONT_SelectObject
19  */
20 HFONT16 PSDRV_FONT_SelectObject( DC * dc, HFONT16 hfont,
21                                         FONTOBJ *font )
22 {
23     HFONT16 prevfont = dc->hFont;
24     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
25     LOGFONT16 *lf = &(font->logfont);
26     BOOL bd = FALSE, it = FALSE;
27     AFMLISTENTRY *afmle;
28     AFM *afm;
29     FONTFAMILY *family;
30     char FaceName[LF_FACESIZE];
31
32
33     TRACE("FaceName = '%s' Height = %d Italic = %d Weight = %d\n",
34           lf->lfFaceName, lf->lfHeight, lf->lfItalic, lf->lfWeight);
35
36     dc->hFont = hfont;
37
38     if(lf->lfItalic)
39         it = TRUE;
40     if(lf->lfWeight > 550)
41         bd = TRUE;
42     strcpy(FaceName, lf->lfFaceName);
43     
44     if(FaceName[0] == '\0') {
45         switch(lf->lfPitchAndFamily & 0xf0) {
46         case FF_DONTCARE:
47             break;
48         case FF_ROMAN:
49         case FF_SCRIPT:
50             strcpy(FaceName, "Times");
51             break;
52         case FF_SWISS:
53             strcpy(FaceName, "Helvetica");
54             break;
55         case FF_MODERN:
56             strcpy(FaceName, "Courier");
57             break;
58         case FF_DECORATIVE:
59             strcpy(FaceName, "Symbol");
60             break;
61         }
62     }
63
64     if(FaceName[0] == '\0') {
65         switch(lf->lfPitchAndFamily & 0x0f) {
66         case VARIABLE_PITCH:
67             strcpy(FaceName, "Times");
68             break;
69         default:
70             strcpy(FaceName, "Courier");
71             break;
72         }
73     }
74
75     TRACE("Trying to find facename '%s'\n", FaceName);
76
77     /* Look for a matching font family */
78     for(family = physDev->pi->Fonts; family; family = family->next) {
79         if(!strcasecmp(FaceName, family->FamilyName))
80             break;
81     }
82     if(!family) {
83         /* Fallback for Window's font families to common PostScript families */
84         if(!strcmp(FaceName, "Arial"))
85             strcpy(FaceName, "Helvetica");
86         else if(!strcmp(FaceName, "System"))
87             strcpy(FaceName, "Helvetica");
88         else if(!strcmp(FaceName, "Times New Roman"))
89             strcpy(FaceName, "Times");
90         else if(!strcmp(FaceName, "Courier New"))
91             strcpy(FaceName, "Courier");
92
93         for(family = physDev->pi->Fonts; family; family = family->next) {
94             if(!strcmp(FaceName, family->FamilyName))
95                 break;
96         }
97     }
98     /* If all else fails, use the first font defined for the printer */
99     if(!family)
100         family = physDev->pi->Fonts;
101
102     TRACE("Got family '%s'\n", family->FamilyName);
103
104     for(afmle = family->afmlist; afmle; afmle = afmle->next) {
105         if( (bd == (afmle->afm->Weight == FW_BOLD)) && 
106             (it == (afmle->afm->ItalicAngle != 0.0)) )
107                 break;
108     }
109     if(!afmle)
110         afmle = family->afmlist; /* not ideal */
111     
112     afm = afmle->afm;
113
114     physDev->font.afm = afm;
115     physDev->font.tm.tmHeight = INTERNAL_YWSTODS(dc, lf->lfHeight);
116     if(physDev->font.tm.tmHeight < 0) {
117         physDev->font.tm.tmHeight *= - (afm->FullAscender - afm->Descender) /
118                                        (afm->Ascender - afm->Descender);
119         TRACE("Fixed -ve height to %ld\n", physDev->font.tm.tmHeight);
120     }
121     physDev->font.size = physDev->font.tm.tmHeight * 1000.0 /
122                                 (afm->FullAscender - afm->Descender);
123     physDev->font.scale = physDev->font.size / 1000.0;
124     physDev->font.escapement = lf->lfEscapement;
125     physDev->font.tm.tmAscent = afm->FullAscender * physDev->font.scale;
126     physDev->font.tm.tmDescent = -afm->Descender * physDev->font.scale;
127     physDev->font.tm.tmInternalLeading = (afm->FullAscender - afm->Ascender)
128                                                 * physDev->font.scale;
129     physDev->font.tm.tmExternalLeading = (1000.0 - afm->FullAscender)
130                                                 * physDev->font.scale; /* ?? */
131     physDev->font.tm.tmAveCharWidth = afm->CharWidths[120] * /* x */
132                                                    physDev->font.scale;
133     physDev->font.tm.tmMaxCharWidth = afm->CharWidths[77] * /* M */
134                                            physDev->font.scale;
135     physDev->font.tm.tmWeight = afm->Weight;
136     physDev->font.tm.tmItalic = afm->ItalicAngle != 0.0;
137     physDev->font.tm.tmUnderlined = lf->lfUnderline;
138     physDev->font.tm.tmStruckOut = lf->lfStrikeOut;
139     physDev->font.tm.tmFirstChar = 32;
140     physDev->font.tm.tmLastChar = 251;
141     physDev->font.tm.tmDefaultChar = 128;
142     physDev->font.tm.tmBreakChar = 32;
143     physDev->font.tm.tmPitchAndFamily = afm->IsFixedPitch ? 0 :
144                                           TMPF_FIXED_PITCH;
145     physDev->font.tm.tmPitchAndFamily |= TMPF_DEVICE;
146     physDev->font.tm.tmCharSet = ANSI_CHARSET;
147     physDev->font.tm.tmOverhang = 0;
148     physDev->font.tm.tmDigitizedAspectX = dc->devCaps->logPixelsY;
149     physDev->font.tm.tmDigitizedAspectY = dc->devCaps->logPixelsX;
150
151     physDev->font.set = FALSE;
152
153     TRACE("Selected PS font '%s' size %d weight %ld.\n", 
154           physDev->font.afm->FontName, physDev->font.size,
155           physDev->font.tm.tmWeight );
156     TRACE("H = %ld As = %ld Des = %ld IL = %ld EL = %ld\n",
157           physDev->font.tm.tmHeight, physDev->font.tm.tmAscent,
158           physDev->font.tm.tmDescent, physDev->font.tm.tmInternalLeading,
159           physDev->font.tm.tmExternalLeading);
160
161     return prevfont;
162 }
163
164 /***********************************************************************
165  *           PSDRV_GetTextMetrics
166  */
167 BOOL PSDRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
168 {
169     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
170
171     memcpy(metrics, &(physDev->font.tm), sizeof(physDev->font.tm));
172     return TRUE;
173 }
174
175 /***********************************************************************
176  *           PSDRV_UnicodeToANSI
177  */
178 char PSDRV_UnicodeToANSI(int u)
179 {
180     if((u & 0xff) == u)
181         return u;
182     switch(u) {
183     case 0x2013: /* endash */
184         return 0x96;
185     case 0x2014: /* emdash */
186         return 0x97;
187     case 0x2018: /* quoteleft */
188         return 0x91;
189     case 0x2019: /* quoteright */
190         return 0x92;
191     case 0x201c: /* quotedblleft */
192        return 0x93;
193     case 0x201d: /* quotedblright */
194         return 0x94;
195     case 0x2022: /* bullet */
196         return 0x95;
197     default:
198         WARN("Umapped unicode char U%04x\n", u);
199         return 0xff;
200     }
201 }
202 /***********************************************************************
203  *           PSDRV_GetTextExtentPoint
204  */
205 BOOL PSDRV_GetTextExtentPoint( DC *dc, LPCWSTR str, INT count,
206                                   LPSIZE size )
207 {
208     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
209     INT i;
210     float width;
211
212     width = 0.0;
213
214     for(i = 0; i < count && str[i]; i++) {
215         char c = PSDRV_UnicodeToANSI(str[i]);
216         width += physDev->font.afm->CharWidths[(int)(unsigned char)c];
217 /*      TRACE(psdrv, "Width after %dth char '%c' = %f\n", i, str[i], width);*/
218     }
219     width *= physDev->font.scale;
220     TRACE("Width after scale (%f) is %f\n", physDev->font.scale, width);
221
222     size->cx = GDI_ROUND((FLOAT)width * dc->xformVport2World.eM11);
223     size->cy = GDI_ROUND((FLOAT)physDev->font.tm.tmHeight  * dc->xformVport2World.eM22);
224
225     return TRUE;
226 }
227
228
229 /***********************************************************************
230  *           PSDRV_GetCharWidth
231  */
232 BOOL PSDRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
233                            LPINT buffer )
234 {
235     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
236     UINT i;
237
238     TRACE("first = %d last = %d\n", firstChar, lastChar);
239
240     if(lastChar > 0xff) return FALSE;
241     for( i = firstChar; i <= lastChar; i++ )
242         *buffer++ = physDev->font.afm->CharWidths[i] * physDev->font.scale;
243
244     return TRUE;
245 }
246
247     
248 /***********************************************************************
249  *           PSDRV_SetFont
250  */
251 BOOL PSDRV_SetFont( DC *dc )
252 {
253     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
254     BOOL ReEncode = FALSE;
255
256     PSDRV_WriteSetColor(dc, &physDev->font.color);
257     if(physDev->font.set) return TRUE;
258
259     if(physDev->font.afm->EncodingScheme && 
260        !strcmp(physDev->font.afm->EncodingScheme, "AdobeStandardEncoding"))
261         ReEncode = TRUE;
262     if(ReEncode)
263         PSDRV_WriteReencodeFont(dc);
264     PSDRV_WriteSetFont(dc, ReEncode);
265     physDev->font.set = TRUE;
266     return TRUE;
267 }
268
269
270 /***********************************************************************
271  *           PSDRV_GetFontMetric
272  */
273 static UINT PSDRV_GetFontMetric(HDC hdc, AFM *pafm, NEWTEXTMETRIC16 *pTM, 
274               ENUMLOGFONTEX16 *pLF, INT16 size)
275
276 {
277     DC *dc = DC_GetDCPtr( hdc );
278     float scale = size / (pafm->FullAscender - pafm->Descender);
279
280     if (!dc) return FALSE;
281
282     memset( pLF, 0, sizeof(*pLF) );
283     memset( pTM, 0, sizeof(*pTM) );
284
285 #define plf ((LPLOGFONT16)pLF)
286     plf->lfHeight    = pTM->tmHeight       = size;
287     plf->lfWidth     = pTM->tmAveCharWidth = pafm->CharWidths[120] * scale;
288     plf->lfWeight    = pTM->tmWeight       = pafm->Weight;
289     plf->lfItalic    = pTM->tmItalic       = pafm->ItalicAngle != 0.0;
290     plf->lfUnderline = pTM->tmUnderlined   = 0;
291     plf->lfStrikeOut = pTM->tmStruckOut    = 0;
292     plf->lfCharSet   = pTM->tmCharSet      = ANSI_CHARSET;
293
294     /* convert pitch values */
295
296     pTM->tmPitchAndFamily = pafm->IsFixedPitch ? 0 : TMPF_FIXED_PITCH;
297     pTM->tmPitchAndFamily |= TMPF_DEVICE;
298     plf->lfPitchAndFamily = 0;
299
300     lstrcpynA( plf->lfFaceName, pafm->FamilyName, LF_FACESIZE );
301 #undef plf
302
303     pTM->tmAscent = pafm->FullAscender * scale;
304     pTM->tmDescent = -pafm->Descender * scale;
305     pTM->tmInternalLeading = (pafm->FullAscender - pafm->Ascender) * scale;
306     pTM->tmMaxCharWidth = pafm->CharWidths[77] * scale;
307     pTM->tmDigitizedAspectX = dc->devCaps->logPixelsY;
308     pTM->tmDigitizedAspectY = dc->devCaps->logPixelsX;
309
310     *(INT*)&pTM->tmFirstChar = 32;
311
312     GDI_ReleaseObj( hdc );
313     /* return font type */
314     return DEVICE_FONTTYPE;
315
316 }
317
318 /***********************************************************************
319  *           PSDRV_EnumDeviceFonts
320  */
321 BOOL PSDRV_EnumDeviceFonts( HDC hdc, LPLOGFONT16 plf, 
322                                         DEVICEFONTENUMPROC proc, LPARAM lp )
323 {
324     ENUMLOGFONTEX16     lf;
325     NEWTEXTMETRIC16     tm;
326     BOOL                b, bRet = 0;
327     AFMLISTENTRY        *afmle;
328     FONTFAMILY          *family;
329     PSDRV_PDEVICE       *physDev;
330
331     DC *dc = DC_GetDCPtr( hdc );
332     if (!dc) return FALSE;
333
334     physDev = (PSDRV_PDEVICE *)dc->physDev;
335     /* FIXME!! should reevaluate dc->physDev after every callback */
336     GDI_ReleaseObj( hdc );
337
338     if( plf->lfFaceName[0] ) {
339         TRACE("lfFaceName = '%s'\n", plf->lfFaceName);
340         for(family = physDev->pi->Fonts; family; family = family->next) {
341             if(!strncmp(plf->lfFaceName, family->FamilyName, 
342                         strlen(family->FamilyName)))
343                 break;
344         }
345         if(family) {
346             for(afmle = family->afmlist; afmle; afmle = afmle->next) {
347                 TRACE("Got '%s'\n", afmle->afm->FontName);
348                 if( (b = (*proc)( &lf, &tm, 
349                         PSDRV_GetFontMetric( hdc, afmle->afm, &tm, &lf, 200 ),
350                                   lp )) )
351                      bRet = b;
352                 else break;
353             }
354         }
355     } else {
356
357         TRACE("lfFaceName = NULL\n");
358         for(family = physDev->pi->Fonts; family; family = family->next) {
359             afmle = family->afmlist;
360             TRACE("Got '%s'\n", afmle->afm->FontName);
361             if( (b = (*proc)( &lf, &tm, 
362                    PSDRV_GetFontMetric( hdc, afmle->afm, &tm, &lf, 200 ), 
363                               lp )) )
364                 bRet = b;
365             else break;
366         }
367     }
368     return bRet;
369 }