2 * PostScript driver builtin font functions
4 * Copyright 2002 Huw D M Davies for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(psdrv
);
38 /***********************************************************************
41 static inline BOOL
is_stock_font( HFONT font
)
44 for (i
= OEM_FIXED_FONT
; i
<= DEFAULT_GUI_FONT
; i
++)
46 if (i
!= DEFAULT_PALETTE
&& font
== GetStockObject(i
)) return TRUE
;
52 /*******************************************************************************
55 * Scale builtin font to requested lfHeight
58 static inline float Round(float f
)
60 return (f
> 0) ? (f
+ 0.5) : (f
- 0.5);
63 static VOID
ScaleFont(const AFM
*afm
, LONG lfHeight
, PSFONT
*font
,
66 const WINMETRICS
*wm
= &(afm
->WinMetrics
);
67 USHORT usUnitsPerEm
, usWinAscent
, usWinDescent
;
68 SHORT sAscender
, sDescender
, sLineGap
, sAvgCharWidth
;
70 TRACE("'%s' %i\n", afm
->FontName
, lfHeight
);
72 if (lfHeight
< 0) /* match em height */
74 font
->fontinfo
.Builtin
.scale
= - ((float)lfHeight
/ (float)(wm
->usUnitsPerEm
));
76 else /* match cell height */
78 font
->fontinfo
.Builtin
.scale
= (float)lfHeight
/
79 (float)(wm
->usWinAscent
+ wm
->usWinDescent
);
82 font
->size
.xx
= (INT
)Round(font
->fontinfo
.Builtin
.scale
* (float)wm
->usUnitsPerEm
);
83 font
->size
.xy
= font
->size
.yx
= 0;
84 font
->size
.yy
= -(INT
)Round(font
->fontinfo
.Builtin
.scale
* (float)wm
->usUnitsPerEm
);
86 usUnitsPerEm
= (USHORT
)Round((float)(wm
->usUnitsPerEm
) * font
->fontinfo
.Builtin
.scale
);
87 sAscender
= (SHORT
)Round((float)(wm
->sAscender
) * font
->fontinfo
.Builtin
.scale
);
88 sDescender
= (SHORT
)Round((float)(wm
->sDescender
) * font
->fontinfo
.Builtin
.scale
);
89 sLineGap
= (SHORT
)Round((float)(wm
->sLineGap
) * font
->fontinfo
.Builtin
.scale
);
90 usWinAscent
= (USHORT
)Round((float)(wm
->usWinAscent
) * font
->fontinfo
.Builtin
.scale
);
91 usWinDescent
= (USHORT
)Round((float)(wm
->usWinDescent
) * font
->fontinfo
.Builtin
.scale
);
92 sAvgCharWidth
= (SHORT
)Round((float)(wm
->sAvgCharWidth
) * font
->fontinfo
.Builtin
.scale
);
94 tm
->tmAscent
= (LONG
)usWinAscent
;
95 tm
->tmDescent
= (LONG
)usWinDescent
;
96 tm
->tmHeight
= tm
->tmAscent
+ tm
->tmDescent
;
98 tm
->tmInternalLeading
= tm
->tmHeight
- (LONG
)usUnitsPerEm
;
99 if (tm
->tmInternalLeading
< 0)
100 tm
->tmInternalLeading
= 0;
102 tm
->tmExternalLeading
=
103 (LONG
)(sAscender
- sDescender
+ sLineGap
) - tm
->tmHeight
;
104 if (tm
->tmExternalLeading
< 0)
105 tm
->tmExternalLeading
= 0;
107 tm
->tmAveCharWidth
= (LONG
)sAvgCharWidth
;
109 tm
->tmWeight
= afm
->Weight
;
110 tm
->tmItalic
= (afm
->ItalicAngle
!= 0.0);
111 tm
->tmUnderlined
= 0;
113 tm
->tmFirstChar
= (WCHAR
)(afm
->Metrics
[0].UV
);
114 tm
->tmLastChar
= (WCHAR
)(afm
->Metrics
[afm
->NumofMetrics
- 1].UV
);
115 tm
->tmDefaultChar
= 0x001f; /* Win2K does this - FIXME? */
116 tm
->tmBreakChar
= tm
->tmFirstChar
; /* should be 'space' */
118 tm
->tmPitchAndFamily
= TMPF_DEVICE
| TMPF_VECTOR
;
119 if (!afm
->IsFixedPitch
)
120 tm
->tmPitchAndFamily
|= TMPF_FIXED_PITCH
; /* yes, it's backwards */
121 if (wm
->usUnitsPerEm
!= 1000)
122 tm
->tmPitchAndFamily
|= TMPF_TRUETYPE
;
124 tm
->tmCharSet
= ANSI_CHARSET
; /* FIXME */
128 * This is kludgy. font->scale is used in several places in the driver
129 * to adjust PostScript-style metrics. Since these metrics have been
130 * "normalized" to an em-square size of 1000, font->scale needs to be
131 * similarly adjusted..
134 font
->fontinfo
.Builtin
.scale
*= (float)wm
->usUnitsPerEm
/ 1000.0;
136 tm
->tmMaxCharWidth
= (LONG
)Round(
137 (afm
->FontBBox
.urx
- afm
->FontBBox
.llx
) * font
->fontinfo
.Builtin
.scale
);
139 font
->underlinePosition
= afm
->UnderlinePosition
* font
->fontinfo
.Builtin
.scale
;
140 font
->underlineThickness
= afm
->UnderlineThickness
* font
->fontinfo
.Builtin
.scale
;
141 font
->strikeoutPosition
= tm
->tmAscent
/ 2;
142 font
->strikeoutThickness
= font
->underlineThickness
;
144 TRACE("Selected PS font '%s' size %d weight %d.\n", afm
->FontName
,
145 font
->size
.xx
, tm
->tmWeight
);
146 TRACE("H = %d As = %d Des = %d IL = %d EL = %d\n", tm
->tmHeight
,
147 tm
->tmAscent
, tm
->tmDescent
, tm
->tmInternalLeading
,
148 tm
->tmExternalLeading
);
152 /****************************************************************************
153 * PSDRV_SelectBuiltinFont
155 * Set up physDev->font for a builtin font
158 BOOL
PSDRV_SelectBuiltinFont(PHYSDEV dev
, HFONT hfont
,
159 LOGFONTW
*plf
, LPSTR FaceName
)
161 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
164 BOOL bd
= FALSE
, it
= FALSE
;
167 TRACE("Trying to find facename '%s'\n", FaceName
);
169 /* Look for a matching font family */
170 for(family
= physDev
->pi
->Fonts
; family
; family
= family
->next
) {
171 if(!strcasecmp(FaceName
, family
->FamilyName
))
176 /* Fallback for Window's font families to common PostScript families */
177 if(!strcmp(FaceName
, "Arial"))
178 strcpy(FaceName
, "Helvetica");
179 else if(!strcmp(FaceName
, "System"))
180 strcpy(FaceName
, "Helvetica");
181 else if(!strcmp(FaceName
, "Times New Roman"))
182 strcpy(FaceName
, "Times");
183 else if(!strcmp(FaceName
, "Courier New"))
184 strcpy(FaceName
, "Courier");
186 for(family
= physDev
->pi
->Fonts
; family
; family
= family
->next
) {
187 if(!strcmp(FaceName
, family
->FamilyName
))
191 /* If all else fails, use the first font defined for the printer */
193 family
= physDev
->pi
->Fonts
;
195 TRACE("Got family '%s'\n", family
->FamilyName
);
199 if(plf
->lfWeight
> 550)
202 for(afmle
= family
->afmlist
; afmle
; afmle
= afmle
->next
) {
203 if( (bd
== (afmle
->afm
->Weight
== FW_BOLD
)) &&
204 (it
== (afmle
->afm
->ItalicAngle
!= 0.0)) )
208 afmle
= family
->afmlist
; /* not ideal */
210 TRACE("Got font '%s'\n", afmle
->afm
->FontName
);
212 physDev
->font
.fontloc
= Builtin
;
213 physDev
->font
.fontinfo
.Builtin
.afm
= afmle
->afm
;
215 height
= plf
->lfHeight
;
216 /* stock fonts ignore the mapping mode */
217 if (!is_stock_font( hfont
)) {
219 pts
[0].x
= pts
[0].y
= pts
[1].x
= 0;
221 LPtoDP(dev
->hdc
, pts
, 2);
222 height
= pts
[1].y
- pts
[0].y
;
224 ScaleFont(physDev
->font
.fontinfo
.Builtin
.afm
, height
,
225 &(physDev
->font
), &(physDev
->font
.fontinfo
.Builtin
.tm
));
228 /* Does anyone know if these are supposed to be reversed like this? */
230 physDev
->font
.fontinfo
.Builtin
.tm
.tmDigitizedAspectX
= physDev
->logPixelsY
;
231 physDev
->font
.fontinfo
.Builtin
.tm
.tmDigitizedAspectY
= physDev
->logPixelsX
;
236 BOOL
PSDRV_WriteSetBuiltinFont(PHYSDEV dev
)
238 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
240 return PSDRV_WriteSetFont(dev
, physDev
->font
.fontinfo
.Builtin
.afm
->FontName
,
241 physDev
->font
.size
, physDev
->font
.escapement
);
244 BOOL
PSDRV_WriteBuiltinGlyphShow(PHYSDEV dev
, LPCWSTR str
, INT count
)
246 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
250 for (i
= 0; i
< count
; ++i
)
252 name
= PSDRV_UVMetrics(str
[i
], physDev
->font
.fontinfo
.Builtin
.afm
)->N
->sz
;
254 PSDRV_WriteGlyphShow(dev
, name
);
260 /***********************************************************************
261 * PSDRV_GetTextMetrics
263 BOOL
PSDRV_GetTextMetrics(PHYSDEV dev
, TEXTMETRICW
*metrics
)
265 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
267 if (physDev
->font
.fontloc
== Download
)
269 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
270 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
273 memcpy(metrics
, &(physDev
->font
.fontinfo
.Builtin
.tm
),
274 sizeof(physDev
->font
.fontinfo
.Builtin
.tm
));
278 /******************************************************************************
281 * Find the AFMMETRICS for a given UV. Returns first glyph in the font
282 * (space?) if the font does not have a glyph for the given UV.
284 static int MetricsByUV(const void *a
, const void *b
)
286 return (int)(((const AFMMETRICS
*)a
)->UV
- ((const AFMMETRICS
*)b
)->UV
);
289 const AFMMETRICS
*PSDRV_UVMetrics(LONG UV
, const AFM
*afm
)
292 const AFMMETRICS
*needle
;
295 * Ugly work-around for symbol fonts. Wine is sending characters which
296 * belong in the Unicode private use range (U+F020 - U+F0FF) as ASCII
297 * characters (U+0020 - U+00FF).
300 if ((afm
->Metrics
->UV
& 0xff00) == 0xf000 && UV
< 0x100)
305 needle
= bsearch(&key
, afm
->Metrics
, afm
->NumofMetrics
, sizeof(AFMMETRICS
),
310 WARN("No glyph for U+%.4X in %s\n", UV
, afm
->FontName
);
311 needle
= afm
->Metrics
;
317 /***********************************************************************
318 * PSDRV_GetTextExtentExPoint
320 BOOL
PSDRV_GetTextExtentExPoint(PHYSDEV dev
, LPCWSTR str
, INT count
,
321 INT maxExt
, LPINT lpnFit
, LPINT alpDx
, LPSIZE size
)
323 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
329 if (physDev
->font
.fontloc
== Download
)
331 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
332 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, maxExt
, lpnFit
, alpDx
, size
);
335 TRACE("%s %i\n", debugstr_wn(str
, count
), count
);
337 scale
= physDev
->font
.fontinfo
.Builtin
.scale
;
338 for (i
= 0; i
< count
&& str
[i
] != '\0'; ++i
)
341 width
+= PSDRV_UVMetrics(str
[i
], physDev
->font
.fontinfo
.Builtin
.afm
)->WX
;
342 scaled_width
= width
* scale
;
344 alpDx
[i
] = scaled_width
;
345 if (scaled_width
<= maxExt
)
349 size
->cx
= width
* physDev
->font
.fontinfo
.Builtin
.scale
;
350 size
->cy
= physDev
->font
.fontinfo
.Builtin
.tm
.tmHeight
;
355 TRACE("cx=%i cy=%i\n", size
->cx
, size
->cy
);
360 /***********************************************************************
363 BOOL
PSDRV_GetCharWidth(PHYSDEV dev
, UINT firstChar
, UINT lastChar
, LPINT buffer
)
365 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
368 if (physDev
->font
.fontloc
== Download
)
370 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
371 return dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
374 TRACE("U+%.4X U+%.4X\n", firstChar
, lastChar
);
376 if (lastChar
> 0xffff || firstChar
> lastChar
)
378 SetLastError(ERROR_INVALID_PARAMETER
);
382 for (i
= firstChar
; i
<= lastChar
; ++i
)
384 *buffer
= floor( PSDRV_UVMetrics(i
, physDev
->font
.fontinfo
.Builtin
.afm
)->WX
385 * physDev
->font
.fontinfo
.Builtin
.scale
+ 0.5 );
386 TRACE("U+%.4X: %i\n", i
, *buffer
);
394 /***********************************************************************
395 * PSDRV_GetFontMetric
397 static UINT
PSDRV_GetFontMetric(HDC hdc
, const AFM
*afm
,
398 NEWTEXTMETRICEXW
*ntmx
, ENUMLOGFONTEXW
*elfx
)
400 /* ntmx->ntmTm is NEWTEXTMETRICW; compatible w/ TEXTMETRICW per Win32 doc */
402 TEXTMETRICW
*tm
= (TEXTMETRICW
*)&(ntmx
->ntmTm
);
403 LOGFONTW
*lf
= &(elfx
->elfLogFont
);
406 memset(ntmx
, 0, sizeof(*ntmx
));
407 memset(elfx
, 0, sizeof(*elfx
));
409 ScaleFont(afm
, -(LONG
)(afm
->WinMetrics
.usUnitsPerEm
), &font
, tm
);
411 lf
->lfHeight
= tm
->tmHeight
;
412 lf
->lfWidth
= tm
->tmAveCharWidth
;
413 lf
->lfWeight
= tm
->tmWeight
;
414 lf
->lfItalic
= tm
->tmItalic
;
415 lf
->lfCharSet
= tm
->tmCharSet
;
417 lf
->lfPitchAndFamily
= (afm
->IsFixedPitch
) ? FIXED_PITCH
: VARIABLE_PITCH
;
419 MultiByteToWideChar(CP_ACP
, 0, afm
->FamilyName
, -1, lf
->lfFaceName
,
422 return DEVICE_FONTTYPE
;
425 /***********************************************************************
428 BOOL
PSDRV_EnumFonts( PHYSDEV dev
, LPLOGFONTW plf
, FONTENUMPROCW proc
, LPARAM lp
)
430 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
431 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pEnumFonts
);
437 char FaceName
[LF_FACESIZE
];
439 ret
= next
->funcs
->pEnumFonts( next
, plf
, proc
, lp
);
440 if (!ret
) return FALSE
;
442 if( plf
&& plf
->lfFaceName
[0] ) {
443 WideCharToMultiByte(CP_ACP
, 0, plf
->lfFaceName
, -1,
444 FaceName
, sizeof(FaceName
), NULL
, NULL
);
445 TRACE("lfFaceName = '%s'\n", FaceName
);
446 for(family
= physDev
->pi
->Fonts
; family
; family
= family
->next
) {
447 if(!strncmp(FaceName
, family
->FamilyName
,
448 strlen(family
->FamilyName
)))
452 for(afmle
= family
->afmlist
; afmle
; afmle
= afmle
->next
) {
455 TRACE("Got '%s'\n", afmle
->afm
->FontName
);
456 fm
= PSDRV_GetFontMetric( dev
->hdc
, afmle
->afm
, &tm
, &lf
);
457 if (!(ret
= (*proc
)( &lf
.elfLogFont
, (TEXTMETRICW
*)&tm
, fm
, lp
)))
463 TRACE("lfFaceName = NULL\n");
464 for(family
= physDev
->pi
->Fonts
; family
; family
= family
->next
) {
467 afmle
= family
->afmlist
;
468 TRACE("Got '%s'\n", afmle
->afm
->FontName
);
469 fm
= PSDRV_GetFontMetric( dev
->hdc
, afmle
->afm
, &tm
, &lf
);
470 if (!(ret
= (*proc
)( &lf
.elfLogFont
, (TEXTMETRICW
*)&tm
, fm
, lp
)))