Fixed error handling in DGA_IDirectDraw2Impl_GetCaps().
[wine] / graphics / psdrv / 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 "debug.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(psdrv, "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(psdrv, "Trying to find facename '%s'\n", FaceName);
75
76     for(family = physDev->pi->Fonts; family; family = family->next) {
77         if(!strcmp(FaceName, family->FamilyName))
78             break;
79     }
80     if(!family)
81         family = physDev->pi->Fonts;
82
83     TRACE(psdrv, "Got family '%s'\n", family->FamilyName);
84
85     for(afmle = family->afmlist; afmle; afmle = afmle->next) {
86         if( (bd == (afmle->afm->Weight == FW_BOLD)) && 
87             (it == (afmle->afm->ItalicAngle != 0.0)) )
88                 break;
89     }
90     if(!afmle)
91         afmle = family->afmlist; /* not ideal */
92     
93     afm = afmle->afm;
94
95     physDev->font.afm = afm;
96     physDev->font.tm.tmHeight = YLSTODS(dc, lf->lfHeight);
97     if(physDev->font.tm.tmHeight < 0) {
98         physDev->font.tm.tmHeight *= - (afm->FullAscender - afm->Descender) /
99                                        (afm->Ascender - afm->Descender);
100         TRACE(psdrv, "Fixed -ve height to %ld\n", physDev->font.tm.tmHeight);
101     }
102     physDev->font.size = physDev->font.tm.tmHeight * 1000.0 /
103                                 (afm->FullAscender - afm->Descender);
104     physDev->font.scale = physDev->font.size / 1000.0;
105     physDev->font.escapement = lf->lfEscapement;
106     physDev->font.tm.tmAscent = afm->FullAscender * physDev->font.scale;
107     physDev->font.tm.tmDescent = -afm->Descender * physDev->font.scale;
108     physDev->font.tm.tmInternalLeading = (afm->FullAscender - afm->Ascender)
109                                                 * physDev->font.scale;
110     physDev->font.tm.tmExternalLeading = (1000.0 - afm->FullAscender)
111                                                 * physDev->font.scale; /* ?? */
112     physDev->font.tm.tmAveCharWidth = afm->CharWidths[120] * /* x */
113                                                    physDev->font.scale;
114     physDev->font.tm.tmMaxCharWidth = afm->CharWidths[77] * /* M */
115                                            physDev->font.scale;
116     physDev->font.tm.tmWeight = afm->Weight;
117     physDev->font.tm.tmItalic = afm->ItalicAngle != 0.0;
118     physDev->font.tm.tmUnderlined = lf->lfUnderline;
119     physDev->font.tm.tmStruckOut = lf->lfStrikeOut;
120     physDev->font.tm.tmFirstChar = 32;
121     physDev->font.tm.tmLastChar = 251;
122     physDev->font.tm.tmDefaultChar = 128;
123     physDev->font.tm.tmBreakChar = 32;
124     physDev->font.tm.tmPitchAndFamily = afm->IsFixedPitch ? 0 :
125                                           TMPF_FIXED_PITCH;
126     physDev->font.tm.tmPitchAndFamily |= TMPF_DEVICE;
127     physDev->font.tm.tmCharSet = ANSI_CHARSET;
128     physDev->font.tm.tmOverhang = 0;
129     physDev->font.tm.tmDigitizedAspectX = dc->w.devCaps->logPixelsY;
130     physDev->font.tm.tmDigitizedAspectY = dc->w.devCaps->logPixelsX;
131
132     physDev->font.set = FALSE;
133
134     TRACE(psdrv, "Selected PS font '%s' size %d weight %ld.\n", 
135           physDev->font.afm->FontName, physDev->font.size,
136           physDev->font.tm.tmWeight );
137     TRACE(psdrv, "H = %ld As = %ld Des = %ld IL = %ld EL = %ld\n",
138           physDev->font.tm.tmHeight, physDev->font.tm.tmAscent,
139           physDev->font.tm.tmDescent, physDev->font.tm.tmInternalLeading,
140           physDev->font.tm.tmExternalLeading);
141
142     return prevfont;
143 }
144
145 /***********************************************************************
146  *           PSDRV_GetTextMetrics
147  */
148 BOOL PSDRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
149 {
150     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
151
152     memcpy(metrics, &(physDev->font.tm), sizeof(physDev->font.tm));
153     return TRUE;
154 }
155
156
157 /***********************************************************************
158  *           PSDRV_GetTextExtentPoint
159  */
160 BOOL PSDRV_GetTextExtentPoint( DC *dc, LPCSTR str, INT count,
161                                   LPSIZE size )
162 {
163     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
164     INT i;
165     float width;
166
167     size->cy = YDSTOLS(dc, physDev->font.tm.tmHeight);
168     width = 0.0;
169
170     for(i = 0; i < count && str[i]; i++) {
171         width += physDev->font.afm->CharWidths[ *((unsigned char *)str + i) ];
172 /*      TRACE(psdrv, "Width after %dth char '%c' = %f\n", i, str[i], width);*/
173     }
174     width *= physDev->font.scale;
175     TRACE(psdrv, "Width after scale (%f) is %f\n", physDev->font.scale, width);
176     size->cx = XDSTOLS(dc, width);
177
178     return TRUE;
179 }
180
181
182 /***********************************************************************
183  *           PSDRV_GetCharWidth
184  */
185 BOOL PSDRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
186                            LPINT buffer )
187 {
188     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
189     UINT i;
190
191     TRACE(psdrv, "first = %d last = %d\n", firstChar, lastChar);
192
193     if(lastChar > 0xff) return FALSE;
194     for( i = firstChar; i <= lastChar; i++ )
195         *buffer++ = physDev->font.afm->CharWidths[i] * physDev->font.scale;
196
197     return TRUE;
198 }
199
200     
201 /***********************************************************************
202  *           PSDRV_SetFont
203  */
204 BOOL PSDRV_SetFont( DC *dc )
205 {
206     PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
207     BOOL ReEncode = FALSE;
208
209     PSDRV_WriteSetColor(dc, &physDev->font.color);
210     if(physDev->font.set) return TRUE;
211
212     if(physDev->font.afm->EncodingScheme && 
213        !strcmp(physDev->font.afm->EncodingScheme, "AdobeStandardEncoding"))
214         ReEncode = TRUE;
215     if(ReEncode)
216         PSDRV_WriteReencodeFont(dc);
217     PSDRV_WriteSetFont(dc, ReEncode);
218     physDev->font.set = TRUE;
219     return TRUE;
220 }
221
222
223 /***********************************************************************
224  *           PSDRV_GetFontMetric
225  */
226 static UINT PSDRV_GetFontMetric(DC *dc, AFM *pafm, NEWTEXTMETRIC16 *pTM, 
227               ENUMLOGFONTEX16 *pLF, INT16 size)
228
229 {
230     float scale = size / (pafm->FullAscender - pafm->Descender);
231     memset( pLF, 0, sizeof(*pLF) );
232     memset( pTM, 0, sizeof(*pTM) );
233
234 #define plf ((LPLOGFONT16)pLF)
235     plf->lfHeight    = pTM->tmHeight       = size;
236     plf->lfWidth     = pTM->tmAveCharWidth = pafm->CharWidths[120] * scale;
237     plf->lfWeight    = pTM->tmWeight       = pafm->Weight;
238     plf->lfItalic    = pTM->tmItalic       = pafm->ItalicAngle != 0.0;
239     plf->lfUnderline = pTM->tmUnderlined   = 0;
240     plf->lfStrikeOut = pTM->tmStruckOut    = 0;
241     plf->lfCharSet   = pTM->tmCharSet      = ANSI_CHARSET;
242
243     /* convert pitch values */
244
245     pTM->tmPitchAndFamily = pafm->IsFixedPitch ? 0 : TMPF_FIXED_PITCH;
246     pTM->tmPitchAndFamily |= TMPF_DEVICE;
247     plf->lfPitchAndFamily = 0;
248
249     strncpy( plf->lfFaceName, pafm->FamilyName, LF_FACESIZE );
250 #undef plf
251
252     pTM->tmAscent = pafm->FullAscender * scale;
253     pTM->tmDescent = -pafm->Descender * scale;
254     pTM->tmInternalLeading = (pafm->FullAscender - pafm->Ascender) * scale;
255     pTM->tmMaxCharWidth = pafm->CharWidths[77] * scale;
256     pTM->tmDigitizedAspectX = dc->w.devCaps->logPixelsY;
257     pTM->tmDigitizedAspectY = dc->w.devCaps->logPixelsX;
258
259     *(INT*)&pTM->tmFirstChar = 32;
260
261     /* return font type */
262
263     return DEVICE_FONTTYPE;
264
265 }
266
267 /***********************************************************************
268  *           PSDRV_EnumDeviceFonts
269  */
270 BOOL PSDRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf, 
271                                         DEVICEFONTENUMPROC proc, LPARAM lp )
272 {
273     ENUMLOGFONTEX16     lf;
274     NEWTEXTMETRIC16     tm;
275     BOOL                b, bRet = 0;
276     AFMLISTENTRY        *afmle;
277     FONTFAMILY          *family;
278     PSDRV_PDEVICE       *physDev = (PSDRV_PDEVICE *)dc->physDev;
279
280     if( plf->lfFaceName[0] ) {
281         TRACE(psdrv, "lfFaceName = '%s'\n", plf->lfFaceName);
282         for(family = physDev->pi->Fonts; family; family = family->next) {
283             if(!strncmp(plf->lfFaceName, family->FamilyName, 
284                         strlen(family->FamilyName)))
285                 break;
286         }
287         if(family) {
288             for(afmle = family->afmlist; afmle; afmle = afmle->next) {
289                 TRACE(psdrv, "Got '%s'\n", afmle->afm->FontName);
290                 if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
291                         PSDRV_GetFontMetric( dc, afmle->afm, &tm, &lf, 200 ),
292                                   lp )) )
293                      bRet = b;
294                 else break;
295             }
296         }
297     } else {
298
299         TRACE(psdrv, "lfFaceName = NULL\n");
300         for(family = physDev->pi->Fonts; family; family = family->next) {
301             afmle = family->afmlist;
302             TRACE(psdrv, "Got '%s'\n", afmle->afm->FontName);
303             if( (b = (*proc)( (LPENUMLOGFONT16)&lf, &tm, 
304                    PSDRV_GetFontMetric( dc, afmle->afm, &tm, &lf, 200 ), 
305                               lp )) )
306                 bRet = b;
307             else break;
308         }
309     }
310     return bRet;
311 }