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