Rounds to the lowest integer, not the nearest.
[wine.git] / graphics / psdrv / font.c
blob4e407f24726369b012ade08961fb1591459e0e98
1 /*
2 * PostScript driver font functions
4 * Copyright 1998 Huw D M Davies
6 */
7 #include <string.h>
8 #include "winspool.h"
9 #include "psdrv.h"
10 #include "debugtools.h"
12 DEFAULT_DEBUG_CHANNEL(psdrv)
16 /***********************************************************************
17 * PSDRV_FONT_SelectObject
19 HFONT16 PSDRV_FONT_SelectObject( DC * dc, HFONT16 hfont,
20 FONTOBJ *font )
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];
32 TRACE("FaceName = '%s' Height = %d Italic = %d Weight = %d\n",
33 lf->lfFaceName, lf->lfHeight, lf->lfItalic, lf->lfWeight);
35 dc->w.hFont = hfont;
37 if(lf->lfItalic)
38 it = TRUE;
39 if(lf->lfWeight > 550)
40 bd = TRUE;
41 strcpy(FaceName, lf->lfFaceName);
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;
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;
74 TRACE("Trying to find facename '%s'\n", FaceName);
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;
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;
94 /* If all else fails, use the first font defined for the printer */
95 if(!family)
96 family = physDev->pi->Fonts;
98 TRACE("Got family '%s'\n", family->FamilyName);
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;
105 if(!afmle)
106 afmle = family->afmlist; /* not ideal */
108 afm = afmle->afm;
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);
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;
147 physDev->font.set = FALSE;
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);
157 return prevfont;
160 /***********************************************************************
161 * PSDRV_GetTextMetrics
163 BOOL PSDRV_GetTextMetrics(DC *dc, TEXTMETRICA *metrics)
165 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
167 memcpy(metrics, &(physDev->font.tm), sizeof(physDev->font.tm));
168 return TRUE;
171 /***********************************************************************
172 * PSDRV_UnicodeToANSI
174 char PSDRV_UnicodeToANSI(int u)
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;
198 /***********************************************************************
199 * PSDRV_GetTextExtentPoint
201 BOOL PSDRV_GetTextExtentPoint( DC *dc, LPCWSTR str, INT count,
202 LPSIZE size )
204 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
205 INT i;
206 float width;
208 size->cy = YDSTOLS(dc, physDev->font.tm.tmHeight);
209 width = 0.0;
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);*/
216 width *= physDev->font.scale;
217 TRACE("Width after scale (%f) is %f\n", physDev->font.scale, width);
218 size->cx = XDSTOLS(dc, width);
220 return TRUE;
224 /***********************************************************************
225 * PSDRV_GetCharWidth
227 BOOL PSDRV_GetCharWidth( DC *dc, UINT firstChar, UINT lastChar,
228 LPINT buffer )
230 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
231 UINT i;
233 TRACE("first = %d last = %d\n", firstChar, lastChar);
235 if(lastChar > 0xff) return FALSE;
236 for( i = firstChar; i <= lastChar; i++ )
237 *buffer++ = physDev->font.afm->CharWidths[i] * physDev->font.scale;
239 return TRUE;
243 /***********************************************************************
244 * PSDRV_SetFont
246 BOOL PSDRV_SetFont( DC *dc )
248 PSDRV_PDEVICE *physDev = (PSDRV_PDEVICE *)dc->physDev;
249 BOOL ReEncode = FALSE;
251 PSDRV_WriteSetColor(dc, &physDev->font.color);
252 if(physDev->font.set) return TRUE;
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;
265 /***********************************************************************
266 * PSDRV_GetFontMetric
268 static UINT PSDRV_GetFontMetric(DC *dc, AFM *pafm, NEWTEXTMETRIC16 *pTM,
269 ENUMLOGFONTEX16 *pLF, INT16 size)
272 float scale = size / (pafm->FullAscender - pafm->Descender);
273 memset( pLF, 0, sizeof(*pLF) );
274 memset( pTM, 0, sizeof(*pTM) );
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;
285 /* convert pitch values */
287 pTM->tmPitchAndFamily = pafm->IsFixedPitch ? 0 : TMPF_FIXED_PITCH;
288 pTM->tmPitchAndFamily |= TMPF_DEVICE;
289 plf->lfPitchAndFamily = 0;
291 lstrcpynA( plf->lfFaceName, pafm->FamilyName, LF_FACESIZE );
292 #undef plf
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;
301 *(INT*)&pTM->tmFirstChar = 32;
303 /* return font type */
305 return DEVICE_FONTTYPE;
309 /***********************************************************************
310 * PSDRV_EnumDeviceFonts
312 BOOL PSDRV_EnumDeviceFonts( DC* dc, LPLOGFONT16 plf,
313 DEVICEFONTENUMPROC proc, LPARAM lp )
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;
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;
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;
339 } else {
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;
352 return bRet;