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