4 * Copyright 1993 Alexandre Julliard
6 * Copyright 2002,2003 Shachar Shemesh
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
37 #include "gdi_private.h"
38 #include "wine/exception.h"
39 #include "wine/heap.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(font
);
45 /* Device -> World size conversion */
47 /* Performs a device to world transformation on the specified width (which
48 * is in integer format).
50 static inline INT
INTERNAL_XDSTOWS(DC
*dc
, INT width
)
54 /* Perform operation with floating point */
55 floatWidth
= (double)width
* dc
->xformVport2World
.eM11
;
56 /* Round to integers */
57 return GDI_ROUND(floatWidth
);
60 /* Performs a device to world transformation on the specified size (which
61 * is in integer format).
63 static inline INT
INTERNAL_YDSTOWS(DC
*dc
, INT height
)
67 /* Perform operation with floating point */
68 floatHeight
= (double)height
* dc
->xformVport2World
.eM22
;
69 /* Round to integers */
70 return GDI_ROUND(floatHeight
);
73 /* scale width and height but don't mirror them */
75 static inline INT
width_to_LP( DC
*dc
, INT width
)
77 return GDI_ROUND( (double)width
* fabs( dc
->xformVport2World
.eM11
));
80 static inline INT
height_to_LP( DC
*dc
, INT height
)
82 return GDI_ROUND( (double)height
* fabs( dc
->xformVport2World
.eM22
));
85 static inline INT
INTERNAL_YWSTODS(DC
*dc
, INT height
)
88 pt
[0].x
= pt
[0].y
= 0;
92 return pt
[1].y
- pt
[0].y
;
95 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
);
96 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
);
97 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
);
98 static BOOL
FONT_DeleteObject( HGDIOBJ handle
);
100 static const struct gdi_obj_funcs font_funcs
=
102 FONT_SelectObject
, /* pSelectObject */
103 FONT_GetObjectA
, /* pGetObjectA */
104 FONT_GetObjectW
, /* pGetObjectW */
105 NULL
, /* pUnrealizeObject */
106 FONT_DeleteObject
/* pDeleteObject */
116 LPLOGFONTW lpLogFontParam
;
117 FONTENUMPROCW lpEnumFunc
;
125 * For TranslateCharsetInfo
127 #define MAXTCIINDEX 32
128 static const CHARSETINFO FONT_tci
[MAXTCIINDEX
] = {
130 { ANSI_CHARSET
, 1252, {{0,0,0,0},{FS_LATIN1
,0}} },
131 { EASTEUROPE_CHARSET
, 1250, {{0,0,0,0},{FS_LATIN2
,0}} },
132 { RUSSIAN_CHARSET
, 1251, {{0,0,0,0},{FS_CYRILLIC
,0}} },
133 { GREEK_CHARSET
, 1253, {{0,0,0,0},{FS_GREEK
,0}} },
134 { TURKISH_CHARSET
, 1254, {{0,0,0,0},{FS_TURKISH
,0}} },
135 { HEBREW_CHARSET
, 1255, {{0,0,0,0},{FS_HEBREW
,0}} },
136 { ARABIC_CHARSET
, 1256, {{0,0,0,0},{FS_ARABIC
,0}} },
137 { BALTIC_CHARSET
, 1257, {{0,0,0,0},{FS_BALTIC
,0}} },
138 { VIETNAMESE_CHARSET
, 1258, {{0,0,0,0},{FS_VIETNAMESE
,0}} },
139 /* reserved by ANSI */
140 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
141 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
142 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
143 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
144 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
145 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
146 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
148 { THAI_CHARSET
, 874, {{0,0,0,0},{FS_THAI
,0}} },
149 { SHIFTJIS_CHARSET
, 932, {{0,0,0,0},{FS_JISJAPAN
,0}} },
150 { GB2312_CHARSET
, 936, {{0,0,0,0},{FS_CHINESESIMP
,0}} },
151 { HANGEUL_CHARSET
, 949, {{0,0,0,0},{FS_WANSUNG
,0}} },
152 { CHINESEBIG5_CHARSET
, 950, {{0,0,0,0},{FS_CHINESETRAD
,0}} },
153 { JOHAB_CHARSET
, 1361, {{0,0,0,0},{FS_JOHAB
,0}} },
154 /* reserved for alternate ANSI and OEM */
155 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
156 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
157 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
158 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
159 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
160 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
161 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
162 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
163 /* reserved for system */
164 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
165 { SYMBOL_CHARSET
, CP_SYMBOL
, {{0,0,0,0},{FS_SYMBOL
,0}} }
168 static void FONT_LogFontAToW( const LOGFONTA
*fontA
, LPLOGFONTW fontW
)
170 memcpy(fontW
, fontA
, sizeof(LOGFONTA
) - LF_FACESIZE
);
171 MultiByteToWideChar(CP_ACP
, 0, fontA
->lfFaceName
, -1, fontW
->lfFaceName
,
173 fontW
->lfFaceName
[LF_FACESIZE
-1] = 0;
176 static void FONT_LogFontWToA( const LOGFONTW
*fontW
, LPLOGFONTA fontA
)
178 memcpy(fontA
, fontW
, sizeof(LOGFONTA
) - LF_FACESIZE
);
179 WideCharToMultiByte(CP_ACP
, 0, fontW
->lfFaceName
, -1, fontA
->lfFaceName
,
180 LF_FACESIZE
, NULL
, NULL
);
181 fontA
->lfFaceName
[LF_FACESIZE
-1] = 0;
184 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW
*fontW
, LPENUMLOGFONTEXA fontA
)
186 FONT_LogFontWToA( &fontW
->elfLogFont
, &fontA
->elfLogFont
);
188 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfFullName
, -1,
189 (LPSTR
) fontA
->elfFullName
, LF_FULLFACESIZE
, NULL
, NULL
);
190 fontA
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
191 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfStyle
, -1,
192 (LPSTR
) fontA
->elfStyle
, LF_FACESIZE
, NULL
, NULL
);
193 fontA
->elfStyle
[LF_FACESIZE
-1] = '\0';
194 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfScript
, -1,
195 (LPSTR
) fontA
->elfScript
, LF_FACESIZE
, NULL
, NULL
);
196 fontA
->elfScript
[LF_FACESIZE
-1] = '\0';
199 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA
*fontA
, LPENUMLOGFONTEXW fontW
)
201 FONT_LogFontAToW( &fontA
->elfLogFont
, &fontW
->elfLogFont
);
203 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfFullName
, -1,
204 fontW
->elfFullName
, LF_FULLFACESIZE
);
205 fontW
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
206 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfStyle
, -1,
207 fontW
->elfStyle
, LF_FACESIZE
);
208 fontW
->elfStyle
[LF_FACESIZE
-1] = '\0';
209 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfScript
, -1,
210 fontW
->elfScript
, LF_FACESIZE
);
211 fontW
->elfScript
[LF_FACESIZE
-1] = '\0';
214 /***********************************************************************
215 * TEXTMETRIC conversion functions.
217 static void FONT_TextMetricWToA(const TEXTMETRICW
*ptmW
, LPTEXTMETRICA ptmA
)
219 ptmA
->tmHeight
= ptmW
->tmHeight
;
220 ptmA
->tmAscent
= ptmW
->tmAscent
;
221 ptmA
->tmDescent
= ptmW
->tmDescent
;
222 ptmA
->tmInternalLeading
= ptmW
->tmInternalLeading
;
223 ptmA
->tmExternalLeading
= ptmW
->tmExternalLeading
;
224 ptmA
->tmAveCharWidth
= ptmW
->tmAveCharWidth
;
225 ptmA
->tmMaxCharWidth
= ptmW
->tmMaxCharWidth
;
226 ptmA
->tmWeight
= ptmW
->tmWeight
;
227 ptmA
->tmOverhang
= ptmW
->tmOverhang
;
228 ptmA
->tmDigitizedAspectX
= ptmW
->tmDigitizedAspectX
;
229 ptmA
->tmDigitizedAspectY
= ptmW
->tmDigitizedAspectY
;
230 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 255);
231 if (ptmW
->tmCharSet
== SYMBOL_CHARSET
)
233 ptmA
->tmFirstChar
= 0x1e;
234 ptmA
->tmLastChar
= 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
236 else if (ptmW
->tmPitchAndFamily
& TMPF_TRUETYPE
)
238 ptmA
->tmFirstChar
= ptmW
->tmDefaultChar
- 1;
239 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
243 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 0xff);
244 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
246 ptmA
->tmDefaultChar
= ptmW
->tmDefaultChar
;
247 ptmA
->tmBreakChar
= ptmW
->tmBreakChar
;
248 ptmA
->tmItalic
= ptmW
->tmItalic
;
249 ptmA
->tmUnderlined
= ptmW
->tmUnderlined
;
250 ptmA
->tmStruckOut
= ptmW
->tmStruckOut
;
251 ptmA
->tmPitchAndFamily
= ptmW
->tmPitchAndFamily
;
252 ptmA
->tmCharSet
= ptmW
->tmCharSet
;
256 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW
*ptmW
, NEWTEXTMETRICEXA
*ptmA
)
258 FONT_TextMetricWToA((const TEXTMETRICW
*)ptmW
, (LPTEXTMETRICA
)ptmA
);
259 ptmA
->ntmTm
.ntmFlags
= ptmW
->ntmTm
.ntmFlags
;
260 ptmA
->ntmTm
.ntmSizeEM
= ptmW
->ntmTm
.ntmSizeEM
;
261 ptmA
->ntmTm
.ntmCellHeight
= ptmW
->ntmTm
.ntmCellHeight
;
262 ptmA
->ntmTm
.ntmAvgWidth
= ptmW
->ntmTm
.ntmAvgWidth
;
263 memcpy(&ptmA
->ntmFontSig
, &ptmW
->ntmFontSig
, sizeof(FONTSIGNATURE
));
266 static DWORD
get_key_value( HKEY key
, const WCHAR
*name
, DWORD
*value
)
269 DWORD count
= sizeof(buf
), type
, err
;
271 err
= RegQueryValueExW( key
, name
, NULL
, &type
, (BYTE
*)buf
, &count
);
274 if (type
== REG_DWORD
) memcpy( value
, buf
, sizeof(*value
) );
275 else *value
= atoiW( buf
);
280 static UINT
get_subpixel_orientation( HKEY key
)
282 static const WCHAR smoothing_orientation
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
283 'O','r','i','e','n','t','a','t','i','o','n',0};
286 /* FIXME: handle vertical orientations even though Windows doesn't */
287 if (get_key_value( key
, smoothing_orientation
, &orient
)) return GGO_GRAY4_BITMAP
;
291 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
292 return WINE_GGO_HBGR_BITMAP
;
293 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
294 return WINE_GGO_HRGB_BITMAP
;
296 return GGO_GRAY4_BITMAP
;
299 static UINT
get_default_smoothing( HKEY key
)
301 static const WCHAR smoothing
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
302 static const WCHAR smoothing_type
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
305 if (get_key_value( key
, smoothing
, &enabled
)) return 0;
306 if (!enabled
) return GGO_BITMAP
;
308 if (!get_key_value( key
, smoothing_type
, &type
) && type
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
309 return get_subpixel_orientation( key
);
311 return GGO_GRAY4_BITMAP
;
314 /* compute positions for text rendering, in device coords */
315 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
320 size
->cx
= size
->cy
= 0;
321 if (!count
) return TRUE
;
323 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
324 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
326 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
327 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
329 if (dc
->breakExtra
|| dc
->breakRem
)
331 int i
, space
= 0, rem
= dc
->breakRem
;
333 for (i
= 0; i
< count
; i
++)
335 if (str
[i
] == tm
.tmBreakChar
)
337 space
+= dc
->breakExtra
;
347 size
->cx
= dx
[count
- 1];
348 size
->cy
= tm
.tmHeight
;
352 /* compute positions for text rendering, in device coords */
353 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
358 size
->cx
= size
->cy
= 0;
359 if (!count
) return TRUE
;
361 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
362 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
364 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
365 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
367 if (dc
->breakExtra
|| dc
->breakRem
)
370 int i
, space
= 0, rem
= dc
->breakRem
;
372 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
373 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
375 for (i
= 0; i
< count
; i
++)
377 if (indices
[i
] == space_index
)
379 space
+= dc
->breakExtra
;
389 size
->cx
= dx
[count
- 1];
390 size
->cy
= tm
.tmHeight
;
394 /***********************************************************************
395 * GdiGetCodePage (GDI32.@)
397 DWORD WINAPI
GdiGetCodePage( HDC hdc
)
400 DC
*dc
= get_dc_ptr( hdc
);
404 cp
= dc
->font_code_page
;
405 release_dc_ptr( dc
);
410 /***********************************************************************
411 * get_text_charset_info
413 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
415 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
417 UINT ret
= DEFAULT_CHARSET
;
420 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
421 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
423 if (ret
== DEFAULT_CHARSET
&& fs
)
424 memset(fs
, 0, sizeof(FONTSIGNATURE
));
428 /***********************************************************************
429 * GetTextCharsetInfo (GDI32.@)
431 UINT WINAPI
GetTextCharsetInfo(HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
433 UINT ret
= DEFAULT_CHARSET
;
434 DC
*dc
= get_dc_ptr(hdc
);
438 ret
= get_text_charset_info( dc
, fs
, flags
);
439 release_dc_ptr( dc
);
444 /***********************************************************************
447 * Returns a Unicode translation of str using the charset of the
448 * currently selected font in hdc. If count is -1 then str is assumed
449 * to be '\0' terminated, otherwise it contains the number of bytes to
450 * convert. If plenW is non-NULL, on return it will point to the
451 * number of WCHARs that have been written. If pCP is non-NULL, on
452 * return it will point to the codepage used in the conversion. The
453 * caller should free the returned LPWSTR from the process heap
456 static LPWSTR
FONT_mbtowc(HDC hdc
, LPCSTR str
, INT count
, INT
*plenW
, UINT
*pCP
)
462 cp
= GdiGetCodePage( hdc
);
464 if(count
== -1) count
= strlen(str
);
465 lenW
= MultiByteToWideChar(cp
, 0, str
, count
, NULL
, 0);
466 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
*sizeof(WCHAR
));
467 MultiByteToWideChar(cp
, 0, str
, count
, strW
, lenW
);
468 TRACE("mapped %s -> %s\n", debugstr_an(str
, count
), debugstr_wn(strW
, lenW
));
469 if(plenW
) *plenW
= lenW
;
474 /***********************************************************************
475 * CreateFontIndirectExA (GDI32.@)
477 HFONT WINAPI
CreateFontIndirectExA( const ENUMLOGFONTEXDVA
*penumexA
)
479 ENUMLOGFONTEXDVW enumexW
;
481 if (!penumexA
) return 0;
483 FONT_EnumLogFontExAToW( &penumexA
->elfEnumLogfontEx
, &enumexW
.elfEnumLogfontEx
);
484 enumexW
.elfDesignVector
= penumexA
->elfDesignVector
;
485 return CreateFontIndirectExW( &enumexW
);
488 /***********************************************************************
489 * CreateFontIndirectExW (GDI32.@)
491 HFONT WINAPI
CreateFontIndirectExW( const ENUMLOGFONTEXDVW
*penumex
)
497 if (!penumex
) return 0;
499 if (penumex
->elfEnumLogfontEx
.elfFullName
[0] ||
500 penumex
->elfEnumLogfontEx
.elfStyle
[0] ||
501 penumex
->elfEnumLogfontEx
.elfScript
[0])
503 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
504 debugstr_w(penumex
->elfEnumLogfontEx
.elfFullName
),
505 debugstr_w(penumex
->elfEnumLogfontEx
.elfStyle
),
506 debugstr_w(penumex
->elfEnumLogfontEx
.elfScript
));
509 plf
= &penumex
->elfEnumLogfontEx
.elfLogFont
;
510 if (!(fontPtr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr
) ))) return 0;
512 fontPtr
->logfont
= *plf
;
514 if (!(hFont
= alloc_gdi_handle( fontPtr
, OBJ_FONT
, &font_funcs
)))
516 HeapFree( GetProcessHeap(), 0, fontPtr
);
520 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
521 plf
->lfHeight
, plf
->lfWidth
,
522 plf
->lfEscapement
, plf
->lfOrientation
,
523 plf
->lfPitchAndFamily
,
524 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
525 plf
->lfQuality
, plf
->lfCharSet
,
526 debugstr_w(plf
->lfFaceName
),
527 plf
->lfWeight
> 400 ? "Bold" : "",
528 plf
->lfItalic
? "Italic" : "",
529 plf
->lfUnderline
? "Underline" : "", hFont
);
534 /***********************************************************************
535 * CreateFontIndirectA (GDI32.@)
537 HFONT WINAPI
CreateFontIndirectA( const LOGFONTA
*plfA
)
543 FONT_LogFontAToW( plfA
, &lfW
);
544 return CreateFontIndirectW( &lfW
);
547 /***********************************************************************
548 * CreateFontIndirectW (GDI32.@)
550 HFONT WINAPI
CreateFontIndirectW( const LOGFONTW
*plf
)
552 ENUMLOGFONTEXDVW exdv
;
556 exdv
.elfEnumLogfontEx
.elfLogFont
= *plf
;
557 exdv
.elfEnumLogfontEx
.elfFullName
[0] = 0;
558 exdv
.elfEnumLogfontEx
.elfStyle
[0] = 0;
559 exdv
.elfEnumLogfontEx
.elfScript
[0] = 0;
560 return CreateFontIndirectExW( &exdv
);
563 /*************************************************************************
564 * CreateFontA (GDI32.@)
566 HFONT WINAPI
CreateFontA( INT height
, INT width
, INT esc
,
567 INT orient
, INT weight
, DWORD italic
,
568 DWORD underline
, DWORD strikeout
, DWORD charset
,
569 DWORD outpres
, DWORD clippres
, DWORD quality
,
570 DWORD pitch
, LPCSTR name
)
574 logfont
.lfHeight
= height
;
575 logfont
.lfWidth
= width
;
576 logfont
.lfEscapement
= esc
;
577 logfont
.lfOrientation
= orient
;
578 logfont
.lfWeight
= weight
;
579 logfont
.lfItalic
= italic
;
580 logfont
.lfUnderline
= underline
;
581 logfont
.lfStrikeOut
= strikeout
;
582 logfont
.lfCharSet
= charset
;
583 logfont
.lfOutPrecision
= outpres
;
584 logfont
.lfClipPrecision
= clippres
;
585 logfont
.lfQuality
= quality
;
586 logfont
.lfPitchAndFamily
= pitch
;
589 lstrcpynA(logfont
.lfFaceName
,name
,sizeof(logfont
.lfFaceName
));
591 logfont
.lfFaceName
[0] = '\0';
593 return CreateFontIndirectA( &logfont
);
596 /*************************************************************************
597 * CreateFontW (GDI32.@)
599 HFONT WINAPI
CreateFontW( INT height
, INT width
, INT esc
,
600 INT orient
, INT weight
, DWORD italic
,
601 DWORD underline
, DWORD strikeout
, DWORD charset
,
602 DWORD outpres
, DWORD clippres
, DWORD quality
,
603 DWORD pitch
, LPCWSTR name
)
607 logfont
.lfHeight
= height
;
608 logfont
.lfWidth
= width
;
609 logfont
.lfEscapement
= esc
;
610 logfont
.lfOrientation
= orient
;
611 logfont
.lfWeight
= weight
;
612 logfont
.lfItalic
= italic
;
613 logfont
.lfUnderline
= underline
;
614 logfont
.lfStrikeOut
= strikeout
;
615 logfont
.lfCharSet
= charset
;
616 logfont
.lfOutPrecision
= outpres
;
617 logfont
.lfClipPrecision
= clippres
;
618 logfont
.lfQuality
= quality
;
619 logfont
.lfPitchAndFamily
= pitch
;
622 lstrcpynW(logfont
.lfFaceName
, name
, ARRAY_SIZE(logfont
.lfFaceName
));
624 logfont
.lfFaceName
[0] = '\0';
626 return CreateFontIndirectW( &logfont
);
629 #define ASSOC_CHARSET_OEM 1
630 #define ASSOC_CHARSET_ANSI 2
631 #define ASSOC_CHARSET_SYMBOL 4
633 static DWORD
get_associated_charset_info(void)
635 static DWORD associated_charset
= -1;
637 if (associated_charset
== -1)
639 static const WCHAR assoc_charset_reg_keyW
[] = {'S','y','s','t','e','m','\\',
640 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
641 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
642 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
643 static const WCHAR ansiW
[] = {'A','N','S','I','(','0','0',')','\0'};
644 static const WCHAR oemW
[] = {'O','E','M','(','F','F',')','\0'};
645 static const WCHAR symbolW
[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
646 static const WCHAR yesW
[] = {'Y','E','S','\0'};
649 DWORD type
, data_len
;
651 associated_charset
= 0;
653 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
,
654 assoc_charset_reg_keyW
, &hkey
) != ERROR_SUCCESS
)
657 data_len
= sizeof(dataW
);
658 if (!RegQueryValueExW(hkey
, ansiW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
659 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
660 associated_charset
|= ASSOC_CHARSET_ANSI
;
662 data_len
= sizeof(dataW
);
663 if (!RegQueryValueExW(hkey
, oemW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
664 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
665 associated_charset
|= ASSOC_CHARSET_OEM
;
667 data_len
= sizeof(dataW
);
668 if (!RegQueryValueExW(hkey
, symbolW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
669 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
670 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
674 TRACE("associated_charset = %d\n", associated_charset
);
677 return associated_charset
;
680 static void update_font_code_page( DC
*dc
, HANDLE font
)
683 int charset
= get_text_charset_info( dc
, NULL
, 0 );
685 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
689 GetObjectW( font
, sizeof(lf
), &lf
);
690 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
691 charset
= DEFAULT_CHARSET
;
694 /* Hmm, nicely designed api this one! */
695 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
696 dc
->font_code_page
= csi
.ciACP
;
700 dc
->font_code_page
= GetOEMCP();
702 case DEFAULT_CHARSET
:
703 dc
->font_code_page
= GetACP();
713 /* FIXME: These have no place here, but because x11drv
714 enumerates fonts with these (made up) charsets some apps
715 might use them and then the FIXME below would become
716 annoying. Now we could pick the intended codepage for
717 each of these, but since it's broken anyway we'll just
718 use CP_ACP and hope it'll go away...
720 dc
->font_code_page
= CP_ACP
;
724 FIXME("Can't find codepage for charset %d\n", charset
);
725 dc
->font_code_page
= CP_ACP
;
730 TRACE("charset %d => cp %d\n", charset
, dc
->font_code_page
);
733 static struct font_gamma_ramp
*get_font_gamma_ramp( void )
735 static const WCHAR desktopW
[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
736 'D','e','s','k','t','o','p',0 };
737 static const WCHAR smoothing_gamma
[] = { 'F','o','n','t','S','m','o','o','t','h','i','n','g',
738 'G','a','m','m','a',0 };
739 const DWORD gamma_default
= 1400;
740 struct font_gamma_ramp
*ramp
;
744 ramp
= HeapAlloc( GetProcessHeap(), 0, sizeof(*ramp
) );
745 if ( ramp
== NULL
) return NULL
;
747 gamma
= gamma_default
;
748 if (RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
) == ERROR_SUCCESS
)
750 if (get_key_value( key
, smoothing_gamma
, &gamma
) || gamma
== 0)
751 gamma
= gamma_default
;
754 gamma
= min( max( gamma
, 1000 ), 2200 );
757 /* Calibrating the difference between the registry value and the Wine gamma value.
758 This looks roughly similar to Windows Native with the same registry value.
759 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
760 gamma
= 1000 * gamma
/ 1400;
762 for (i
= 0; i
< 256; i
++)
764 ramp
->encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
765 ramp
->decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
769 TRACE("gamma %d\n", ramp
->gamma
);
774 /***********************************************************************
777 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
)
780 DC
*dc
= get_dc_ptr( hdc
);
786 if (!GDI_inc_ref_count( handle
))
788 release_dc_ptr( dc
);
792 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
793 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
797 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
798 update_font_code_page( dc
, handle
);
799 if (dc
->font_gamma_ramp
== NULL
)
800 dc
->font_gamma_ramp
= get_font_gamma_ramp();
801 GDI_dec_ref_count( ret
);
803 else GDI_dec_ref_count( handle
);
805 release_dc_ptr( dc
);
810 /***********************************************************************
813 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
)
815 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
821 FONT_LogFontWToA( &font
->logfont
, &lfA
);
822 if (count
> sizeof(lfA
)) count
= sizeof(lfA
);
823 memcpy( buffer
, &lfA
, count
);
825 else count
= sizeof(lfA
);
826 GDI_ReleaseObj( handle
);
830 /***********************************************************************
833 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
835 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
840 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
841 memcpy( buffer
, &font
->logfont
, count
);
843 else count
= sizeof(LOGFONTW
);
844 GDI_ReleaseObj( handle
);
849 /***********************************************************************
852 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
856 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
857 HeapFree( GetProcessHeap(), 0, obj
);
862 /***********************************************************************
865 HFONT CDECL
nulldrv_SelectFont( PHYSDEV dev
, HFONT font
, UINT
*aa_flags
)
867 static const WCHAR desktopW
[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
868 'D','e','s','k','t','o','p',0 };
869 static int orientation
= -1, smoothing
= -1;
873 if (*aa_flags
) return 0;
875 GetObjectW( font
, sizeof(lf
), &lf
);
876 switch (lf
.lfQuality
)
878 case NONANTIALIASED_QUALITY
:
879 *aa_flags
= GGO_BITMAP
;
881 case ANTIALIASED_QUALITY
:
882 *aa_flags
= GGO_GRAY4_BITMAP
;
884 case CLEARTYPE_QUALITY
:
885 case CLEARTYPE_NATURAL_QUALITY
:
886 if (orientation
== -1)
888 if (RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
)) break;
889 orientation
= get_subpixel_orientation( key
);
892 *aa_flags
= orientation
;
897 if (RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
)) break;
898 smoothing
= get_default_smoothing( key
);
901 *aa_flags
= smoothing
;
908 /***********************************************************************
911 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
912 * We have to use other types because of the FONTENUMPROCW definition.
914 static INT CALLBACK
FONT_EnumInstance( const LOGFONTW
*plf
, const TEXTMETRICW
*ptm
,
915 DWORD fType
, LPARAM lp
)
917 struct font_enum
*pfe
= (struct font_enum
*)lp
;
920 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
921 if ((!pfe
->lpLogFontParam
||
922 pfe
->lpLogFontParam
->lfCharSet
== DEFAULT_CHARSET
||
923 pfe
->lpLogFontParam
->lfCharSet
== plf
->lfCharSet
) &&
924 (!(fType
& RASTER_FONTTYPE
) || GetDeviceCaps(pfe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
) )
926 /* convert font metrics */
927 ENUMLOGFONTEXA logfont
;
928 NEWTEXTMETRICEXA tmA
;
932 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW
*)plf
, &logfont
);
933 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW
*)ptm
, &tmA
);
934 plf
= (LOGFONTW
*)&logfont
.elfLogFont
;
935 ptm
= (TEXTMETRICW
*)&tmA
;
937 ret
= pfe
->lpEnumFunc( plf
, ptm
, fType
, pfe
->lpData
);
943 /***********************************************************************
944 * FONT_EnumFontFamiliesEx
946 static INT
FONT_EnumFontFamiliesEx( HDC hDC
, LPLOGFONTW plf
, FONTENUMPROCW efproc
,
947 LPARAM lParam
, BOOL unicode
)
950 DC
*dc
= get_dc_ptr( hDC
);
955 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
957 if (plf
) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
958 fe
.lpLogFontParam
= plf
;
959 fe
.lpEnumFunc
= efproc
;
961 fe
.unicode
= unicode
;
964 ret
= physdev
->funcs
->pEnumFonts( physdev
, plf
, FONT_EnumInstance
, (LPARAM
)&fe
);
965 release_dc_ptr( dc
);
967 return ret
? fe
.retval
: 0;
970 /***********************************************************************
971 * EnumFontFamiliesExW (GDI32.@)
973 INT WINAPI
EnumFontFamiliesExW( HDC hDC
, LPLOGFONTW plf
,
974 FONTENUMPROCW efproc
,
975 LPARAM lParam
, DWORD dwFlags
)
977 return FONT_EnumFontFamiliesEx( hDC
, plf
, efproc
, lParam
, TRUE
);
980 /***********************************************************************
981 * EnumFontFamiliesExA (GDI32.@)
983 INT WINAPI
EnumFontFamiliesExA( HDC hDC
, LPLOGFONTA plf
,
984 FONTENUMPROCA efproc
,
985 LPARAM lParam
, DWORD dwFlags
)
991 FONT_LogFontAToW( plf
, &lfW
);
996 return FONT_EnumFontFamiliesEx( hDC
, plfW
, (FONTENUMPROCW
)efproc
, lParam
, FALSE
);
999 /***********************************************************************
1000 * EnumFontFamiliesA (GDI32.@)
1002 INT WINAPI
EnumFontFamiliesA( HDC hDC
, LPCSTR lpFamily
,
1003 FONTENUMPROCA efproc
, LPARAM lpData
)
1009 if (!*lpFamily
) return 1;
1010 lstrcpynA( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
1011 lf
.lfCharSet
= DEFAULT_CHARSET
;
1012 lf
.lfPitchAndFamily
= 0;
1017 return EnumFontFamiliesExA( hDC
, plf
, efproc
, lpData
, 0 );
1020 /***********************************************************************
1021 * EnumFontFamiliesW (GDI32.@)
1023 INT WINAPI
EnumFontFamiliesW( HDC hDC
, LPCWSTR lpFamily
,
1024 FONTENUMPROCW efproc
, LPARAM lpData
)
1030 if (!*lpFamily
) return 1;
1031 lstrcpynW( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
1032 lf
.lfCharSet
= DEFAULT_CHARSET
;
1033 lf
.lfPitchAndFamily
= 0;
1038 return EnumFontFamiliesExW( hDC
, plf
, efproc
, lpData
, 0 );
1041 /***********************************************************************
1042 * EnumFontsA (GDI32.@)
1044 INT WINAPI
EnumFontsA( HDC hDC
, LPCSTR lpName
, FONTENUMPROCA efproc
,
1047 return EnumFontFamiliesA( hDC
, lpName
, efproc
, lpData
);
1050 /***********************************************************************
1051 * EnumFontsW (GDI32.@)
1053 INT WINAPI
EnumFontsW( HDC hDC
, LPCWSTR lpName
, FONTENUMPROCW efproc
,
1056 return EnumFontFamiliesW( hDC
, lpName
, efproc
, lpData
);
1060 /***********************************************************************
1061 * GetTextCharacterExtra (GDI32.@)
1063 INT WINAPI
GetTextCharacterExtra( HDC hdc
)
1066 DC
*dc
= get_dc_ptr( hdc
);
1067 if (!dc
) return 0x80000000;
1068 ret
= dc
->charExtra
;
1069 release_dc_ptr( dc
);
1074 /***********************************************************************
1075 * SetTextCharacterExtra (GDI32.@)
1077 INT WINAPI
SetTextCharacterExtra( HDC hdc
, INT extra
)
1079 INT ret
= 0x80000000;
1080 DC
* dc
= get_dc_ptr( hdc
);
1084 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetTextCharacterExtra
);
1085 extra
= physdev
->funcs
->pSetTextCharacterExtra( physdev
, extra
);
1086 if (extra
!= 0x80000000)
1088 ret
= dc
->charExtra
;
1089 dc
->charExtra
= extra
;
1091 release_dc_ptr( dc
);
1097 /***********************************************************************
1098 * SetTextJustification (GDI32.@)
1100 BOOL WINAPI
SetTextJustification( HDC hdc
, INT extra
, INT breaks
)
1104 DC
* dc
= get_dc_ptr( hdc
);
1106 if (!dc
) return FALSE
;
1108 physdev
= GET_DC_PHYSDEV( dc
, pSetTextJustification
);
1109 ret
= physdev
->funcs
->pSetTextJustification( physdev
, extra
, breaks
);
1112 extra
= abs((extra
* dc
->vport_ext
.cx
+ dc
->wnd_ext
.cx
/ 2) / dc
->wnd_ext
.cx
);
1113 if (!extra
) breaks
= 0;
1116 dc
->breakExtra
= extra
/ breaks
;
1117 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
1125 release_dc_ptr( dc
);
1130 /***********************************************************************
1131 * GetTextFaceA (GDI32.@)
1133 INT WINAPI
GetTextFaceA( HDC hdc
, INT count
, LPSTR name
)
1135 INT res
= GetTextFaceW(hdc
, 0, NULL
);
1136 LPWSTR nameW
= HeapAlloc( GetProcessHeap(), 0, res
* 2 );
1137 GetTextFaceW( hdc
, res
, nameW
);
1143 res
= WideCharToMultiByte(CP_ACP
, 0, nameW
, -1, name
, count
, NULL
, NULL
);
1147 /* GetTextFaceA does NOT include the nul byte in the return count. */
1154 res
= WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, NULL
, 0, NULL
, NULL
);
1155 HeapFree( GetProcessHeap(), 0, nameW
);
1159 /***********************************************************************
1160 * GetTextFaceW (GDI32.@)
1162 INT WINAPI
GetTextFaceW( HDC hdc
, INT count
, LPWSTR name
)
1167 DC
* dc
= get_dc_ptr( hdc
);
1170 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
1171 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
1172 release_dc_ptr( dc
);
1177 /***********************************************************************
1178 * GetTextExtentPoint32A (GDI32.@)
1180 * See GetTextExtentPoint32W.
1182 BOOL WINAPI
GetTextExtentPoint32A( HDC hdc
, LPCSTR str
, INT count
,
1189 if (count
< 0) return FALSE
;
1191 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
1195 ret
= GetTextExtentPoint32W( hdc
, p
, wlen
, size
);
1196 HeapFree( GetProcessHeap(), 0, p
);
1199 TRACE("(%p %s %d %p): returning %d x %d\n",
1200 hdc
, debugstr_an (str
, count
), count
, size
, size
->cx
, size
->cy
);
1205 /***********************************************************************
1206 * GetTextExtentPoint32W [GDI32.@]
1208 * Computes width/height for a string.
1210 * Computes width and height of the specified string.
1216 BOOL WINAPI
GetTextExtentPoint32W(
1217 HDC hdc
, /* [in] Handle of device context */
1218 LPCWSTR str
, /* [in] Address of text string */
1219 INT count
, /* [in] Number of characters in string */
1220 LPSIZE size
) /* [out] Address of structure for string size */
1222 return GetTextExtentExPointW(hdc
, str
, count
, 0, NULL
, NULL
, size
);
1225 /***********************************************************************
1226 * GetTextExtentExPointI [GDI32.@]
1228 * Computes width and height of the array of glyph indices.
1231 * hdc [I] Handle of device context.
1232 * indices [I] Glyph index array.
1233 * count [I] Number of glyphs in array.
1234 * max_ext [I] Maximum width in glyphs.
1235 * nfit [O] Maximum number of characters.
1236 * dxs [O] Partial string widths.
1237 * size [O] Returned string size.
1243 BOOL WINAPI
GetTextExtentExPointI( HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
1244 LPINT nfit
, LPINT dxs
, LPSIZE size
)
1249 INT buffer
[256], *pos
= dxs
;
1251 if (count
< 0) return FALSE
;
1253 dc
= get_dc_ptr( hdc
);
1254 if (!dc
) return FALSE
;
1259 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
1261 release_dc_ptr( dc
);
1266 ret
= get_char_positions_indices( dc
, indices
, count
, pos
, size
);
1271 for (i
= 0; i
< count
; i
++)
1273 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
1274 if (nfit
&& dx
> (unsigned int)max_ext
) break;
1275 if (dxs
) dxs
[i
] = dx
;
1277 if (nfit
) *nfit
= i
;
1280 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
1281 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
1284 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
1285 release_dc_ptr( dc
);
1287 TRACE("(%p %p %d %p): returning %d x %d\n",
1288 hdc
, indices
, count
, size
, size
->cx
, size
->cy
);
1292 /***********************************************************************
1293 * GetTextExtentPointI [GDI32.@]
1295 * Computes width and height of the array of glyph indices.
1298 * hdc [I] Handle of device context.
1299 * indices [I] Glyph index array.
1300 * count [I] Number of glyphs in array.
1301 * size [O] Returned string size.
1307 BOOL WINAPI
GetTextExtentPointI( HDC hdc
, const WORD
*indices
, INT count
, LPSIZE size
)
1309 return GetTextExtentExPointI( hdc
, indices
, count
, 0, NULL
, NULL
, size
);
1313 /***********************************************************************
1314 * GetTextExtentPointA (GDI32.@)
1316 BOOL WINAPI
GetTextExtentPointA( HDC hdc
, LPCSTR str
, INT count
,
1319 TRACE("not bug compatible.\n");
1320 return GetTextExtentPoint32A( hdc
, str
, count
, size
);
1323 /***********************************************************************
1324 * GetTextExtentPointW (GDI32.@)
1326 BOOL WINAPI
GetTextExtentPointW( HDC hdc
, LPCWSTR str
, INT count
,
1329 TRACE("not bug compatible.\n");
1330 return GetTextExtentPoint32W( hdc
, str
, count
, size
);
1334 /***********************************************************************
1335 * GetTextExtentExPointA (GDI32.@)
1337 BOOL WINAPI
GetTextExtentExPointA( HDC hdc
, LPCSTR str
, INT count
,
1338 INT maxExt
, LPINT lpnFit
,
1339 LPINT alpDx
, LPSIZE size
)
1346 if (count
< 0) return FALSE
;
1347 if (maxExt
< -1) return FALSE
;
1351 walpDx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(INT
) );
1352 if (!walpDx
) return FALSE
;
1355 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
1356 ret
= GetTextExtentExPointW( hdc
, p
, wlen
, maxExt
, lpnFit
, walpDx
, size
);
1359 INT n
= lpnFit
? *lpnFit
: wlen
;
1361 for(i
= 0, j
= 0; i
< n
; i
++, j
++)
1363 alpDx
[j
] = walpDx
[i
];
1364 if (IsDBCSLeadByte(str
[j
])) alpDx
[++j
] = walpDx
[i
];
1367 if (lpnFit
) *lpnFit
= WideCharToMultiByte(CP_ACP
,0,p
,*lpnFit
,NULL
,0,NULL
,NULL
);
1368 HeapFree( GetProcessHeap(), 0, p
);
1369 HeapFree( GetProcessHeap(), 0, walpDx
);
1374 /***********************************************************************
1375 * GetTextExtentExPointW (GDI32.@)
1377 * Return the size of the string as it would be if it was output properly by
1380 BOOL WINAPI
GetTextExtentExPointW( HDC hdc
, LPCWSTR str
, INT count
, INT max_ext
,
1381 LPINT nfit
, LPINT dxs
, LPSIZE size
)
1386 INT buffer
[256], *pos
= dxs
;
1388 if (count
< 0) return FALSE
;
1390 dc
= get_dc_ptr(hdc
);
1391 if (!dc
) return FALSE
;
1396 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
1398 release_dc_ptr( dc
);
1403 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
1408 for (i
= 0; i
< count
; i
++)
1410 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
1411 if (nfit
&& dx
> (unsigned int)max_ext
) break;
1412 if (dxs
) dxs
[i
] = dx
;
1414 if (nfit
) *nfit
= i
;
1417 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
1418 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
1421 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
1422 release_dc_ptr( dc
);
1424 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
1428 /***********************************************************************
1429 * GetTextMetricsA (GDI32.@)
1431 BOOL WINAPI
GetTextMetricsA( HDC hdc
, TEXTMETRICA
*metrics
)
1435 if (!GetTextMetricsW( hdc
, &tm32
)) return FALSE
;
1436 FONT_TextMetricWToA( &tm32
, metrics
);
1440 /***********************************************************************
1441 * GetTextMetricsW (GDI32.@)
1443 BOOL WINAPI
GetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
)
1447 DC
* dc
= get_dc_ptr( hdc
);
1448 if (!dc
) return FALSE
;
1450 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
1451 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
1455 /* device layer returns values in device units
1456 * therefore we have to convert them to logical */
1458 metrics
->tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
1459 metrics
->tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
1460 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
1461 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
1462 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
1463 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
1464 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
1465 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
1466 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
1467 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
1470 TRACE("text metrics:\n"
1471 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
1472 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
1473 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
1474 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
1475 " PitchAndFamily = %02x\n"
1476 " --------------------\n"
1477 " InternalLeading = %i\n"
1481 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
1482 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
1483 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
1484 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
1485 metrics
->tmPitchAndFamily
,
1486 metrics
->tmInternalLeading
,
1489 metrics
->tmHeight
);
1491 release_dc_ptr( dc
);
1496 /***********************************************************************
1497 * GetOutlineTextMetricsA (GDI32.@)
1498 * Gets metrics for TrueType fonts.
1501 * If the supplied buffer isn't big enough Windows partially fills it up to
1502 * its given length and returns that length.
1505 * Success: Non-zero or size of required buffer
1508 UINT WINAPI
GetOutlineTextMetricsA(
1509 HDC hdc
, /* [in] Handle of device context */
1510 UINT cbData
, /* [in] Size of metric data array */
1511 LPOUTLINETEXTMETRICA lpOTM
) /* [out] Address of metric data array */
1513 char buf
[512], *ptr
;
1515 OUTLINETEXTMETRICW
*lpOTMW
= (OUTLINETEXTMETRICW
*)buf
;
1516 OUTLINETEXTMETRICA
*output
= lpOTM
;
1519 if((ret
= GetOutlineTextMetricsW(hdc
, 0, NULL
)) == 0)
1521 if(ret
> sizeof(buf
))
1522 lpOTMW
= HeapAlloc(GetProcessHeap(), 0, ret
);
1523 GetOutlineTextMetricsW(hdc
, ret
, lpOTMW
);
1525 needed
= sizeof(OUTLINETEXTMETRICA
);
1526 if(lpOTMW
->otmpFamilyName
)
1527 needed
+= WideCharToMultiByte(CP_ACP
, 0,
1528 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
1529 NULL
, 0, NULL
, NULL
);
1530 if(lpOTMW
->otmpFaceName
)
1531 needed
+= WideCharToMultiByte(CP_ACP
, 0,
1532 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
1533 NULL
, 0, NULL
, NULL
);
1534 if(lpOTMW
->otmpStyleName
)
1535 needed
+= WideCharToMultiByte(CP_ACP
, 0,
1536 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
1537 NULL
, 0, NULL
, NULL
);
1538 if(lpOTMW
->otmpFullName
)
1539 needed
+= WideCharToMultiByte(CP_ACP
, 0,
1540 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
1541 NULL
, 0, NULL
, NULL
);
1548 TRACE("needed = %d\n", needed
);
1550 /* Since the supplied buffer isn't big enough, we'll alloc one
1551 that is and memcpy the first cbData bytes into the lpOTM at
1553 output
= HeapAlloc(GetProcessHeap(), 0, needed
);
1555 ret
= output
->otmSize
= min(needed
, cbData
);
1556 FONT_TextMetricWToA( &lpOTMW
->otmTextMetrics
, &output
->otmTextMetrics
);
1557 output
->otmFiller
= 0;
1558 output
->otmPanoseNumber
= lpOTMW
->otmPanoseNumber
;
1559 output
->otmfsSelection
= lpOTMW
->otmfsSelection
;
1560 output
->otmfsType
= lpOTMW
->otmfsType
;
1561 output
->otmsCharSlopeRise
= lpOTMW
->otmsCharSlopeRise
;
1562 output
->otmsCharSlopeRun
= lpOTMW
->otmsCharSlopeRun
;
1563 output
->otmItalicAngle
= lpOTMW
->otmItalicAngle
;
1564 output
->otmEMSquare
= lpOTMW
->otmEMSquare
;
1565 output
->otmAscent
= lpOTMW
->otmAscent
;
1566 output
->otmDescent
= lpOTMW
->otmDescent
;
1567 output
->otmLineGap
= lpOTMW
->otmLineGap
;
1568 output
->otmsCapEmHeight
= lpOTMW
->otmsCapEmHeight
;
1569 output
->otmsXHeight
= lpOTMW
->otmsXHeight
;
1570 output
->otmrcFontBox
= lpOTMW
->otmrcFontBox
;
1571 output
->otmMacAscent
= lpOTMW
->otmMacAscent
;
1572 output
->otmMacDescent
= lpOTMW
->otmMacDescent
;
1573 output
->otmMacLineGap
= lpOTMW
->otmMacLineGap
;
1574 output
->otmusMinimumPPEM
= lpOTMW
->otmusMinimumPPEM
;
1575 output
->otmptSubscriptSize
= lpOTMW
->otmptSubscriptSize
;
1576 output
->otmptSubscriptOffset
= lpOTMW
->otmptSubscriptOffset
;
1577 output
->otmptSuperscriptSize
= lpOTMW
->otmptSuperscriptSize
;
1578 output
->otmptSuperscriptOffset
= lpOTMW
->otmptSuperscriptOffset
;
1579 output
->otmsStrikeoutSize
= lpOTMW
->otmsStrikeoutSize
;
1580 output
->otmsStrikeoutPosition
= lpOTMW
->otmsStrikeoutPosition
;
1581 output
->otmsUnderscoreSize
= lpOTMW
->otmsUnderscoreSize
;
1582 output
->otmsUnderscorePosition
= lpOTMW
->otmsUnderscorePosition
;
1585 ptr
= (char*)(output
+ 1);
1586 left
= needed
- sizeof(*output
);
1588 if(lpOTMW
->otmpFamilyName
) {
1589 output
->otmpFamilyName
= (LPSTR
)(ptr
- (char*)output
);
1590 len
= WideCharToMultiByte(CP_ACP
, 0,
1591 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
1592 ptr
, left
, NULL
, NULL
);
1596 output
->otmpFamilyName
= 0;
1598 if(lpOTMW
->otmpFaceName
) {
1599 output
->otmpFaceName
= (LPSTR
)(ptr
- (char*)output
);
1600 len
= WideCharToMultiByte(CP_ACP
, 0,
1601 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
1602 ptr
, left
, NULL
, NULL
);
1606 output
->otmpFaceName
= 0;
1608 if(lpOTMW
->otmpStyleName
) {
1609 output
->otmpStyleName
= (LPSTR
)(ptr
- (char*)output
);
1610 len
= WideCharToMultiByte(CP_ACP
, 0,
1611 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
1612 ptr
, left
, NULL
, NULL
);
1616 output
->otmpStyleName
= 0;
1618 if(lpOTMW
->otmpFullName
) {
1619 output
->otmpFullName
= (LPSTR
)(ptr
- (char*)output
);
1620 len
= WideCharToMultiByte(CP_ACP
, 0,
1621 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
1622 ptr
, left
, NULL
, NULL
);
1625 output
->otmpFullName
= 0;
1629 if(output
!= lpOTM
) {
1630 memcpy(lpOTM
, output
, cbData
);
1631 HeapFree(GetProcessHeap(), 0, output
);
1633 /* check if the string offsets really fit into the provided size */
1634 /* FIXME: should we check string length as well? */
1635 /* make sure that we don't read/write beyond the provided buffer */
1636 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFamilyName
) + sizeof(LPSTR
))
1638 if ((UINT_PTR
)lpOTM
->otmpFamilyName
>= lpOTM
->otmSize
)
1639 lpOTM
->otmpFamilyName
= 0; /* doesn't fit */
1642 /* make sure that we don't read/write beyond the provided buffer */
1643 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFaceName
) + sizeof(LPSTR
))
1645 if ((UINT_PTR
)lpOTM
->otmpFaceName
>= lpOTM
->otmSize
)
1646 lpOTM
->otmpFaceName
= 0; /* doesn't fit */
1649 /* make sure that we don't read/write beyond the provided buffer */
1650 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpStyleName
) + sizeof(LPSTR
))
1652 if ((UINT_PTR
)lpOTM
->otmpStyleName
>= lpOTM
->otmSize
)
1653 lpOTM
->otmpStyleName
= 0; /* doesn't fit */
1656 /* make sure that we don't read/write beyond the provided buffer */
1657 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFullName
) + sizeof(LPSTR
))
1659 if ((UINT_PTR
)lpOTM
->otmpFullName
>= lpOTM
->otmSize
)
1660 lpOTM
->otmpFullName
= 0; /* doesn't fit */
1665 if(lpOTMW
!= (OUTLINETEXTMETRICW
*)buf
)
1666 HeapFree(GetProcessHeap(), 0, lpOTMW
);
1672 /***********************************************************************
1673 * GetOutlineTextMetricsW [GDI32.@]
1675 UINT WINAPI
GetOutlineTextMetricsW(
1676 HDC hdc
, /* [in] Handle of device context */
1677 UINT cbData
, /* [in] Size of metric data array */
1678 LPOUTLINETEXTMETRICW lpOTM
) /* [out] Address of metric data array */
1680 DC
*dc
= get_dc_ptr( hdc
);
1681 OUTLINETEXTMETRICW
*output
= lpOTM
;
1685 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
1688 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
1689 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
1691 if (lpOTM
&& ret
> cbData
)
1693 output
= HeapAlloc(GetProcessHeap(), 0, ret
);
1694 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
1699 output
->otmTextMetrics
.tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
1700 output
->otmTextMetrics
.tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
1701 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
1702 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
1703 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
1704 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
1705 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
1706 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
1707 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
1708 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
1709 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
1710 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
1711 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
1712 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
1713 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
1714 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
1715 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
1716 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
1717 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
1718 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
1719 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
1720 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
1721 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
1722 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
1723 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
1724 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
1725 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
1726 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
1727 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
1728 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
1729 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
1730 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
1731 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
1732 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
1736 memcpy(lpOTM
, output
, cbData
);
1737 HeapFree(GetProcessHeap(), 0, output
);
1745 static LPSTR
FONT_GetCharsByRangeA(HDC hdc
, UINT firstChar
, UINT lastChar
, PINT pByteLen
)
1747 INT i
, count
= lastChar
- firstChar
+ 1;
1755 mbcp
= GdiGetCodePage(hdc
);
1763 if (lastChar
> 0xffff)
1765 if ((firstChar
^ lastChar
) > 0xff)
1769 if (lastChar
> 0xff)
1775 str
= HeapAlloc(GetProcessHeap(), 0, count
* 2 + 1);
1779 for(i
= 0, c
= firstChar
; c
<= lastChar
; i
++, c
++)
1783 str
[i
++] = (BYTE
)(c
>> 8);
1784 if (c
<= 0xff && IsDBCSLeadByteEx(mbcp
, c
))
1785 str
[i
] = 0x1f; /* FIXME: use default character */
1799 /***********************************************************************
1800 * GetCharWidthW (GDI32.@)
1801 * GetCharWidth32W (GDI32.@)
1803 BOOL WINAPI
GetCharWidth32W( HDC hdc
, UINT firstChar
, UINT lastChar
,
1809 DC
* dc
= get_dc_ptr( hdc
);
1811 if (!dc
) return FALSE
;
1813 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
1814 ret
= dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
1818 /* convert device units to logical */
1819 for( i
= firstChar
; i
<= lastChar
; i
++, buffer
++ )
1820 *buffer
= width_to_LP( dc
, *buffer
);
1822 release_dc_ptr( dc
);
1827 /***********************************************************************
1828 * GetCharWidthA (GDI32.@)
1829 * GetCharWidth32A (GDI32.@)
1831 BOOL WINAPI
GetCharWidth32A( HDC hdc
, UINT firstChar
, UINT lastChar
,
1839 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
1843 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
1845 for(i
= 0; i
< wlen
; i
++)
1847 if(!GetCharWidth32W(hdc
, wstr
[i
], wstr
[i
], buffer
))
1855 HeapFree(GetProcessHeap(), 0, str
);
1856 HeapFree(GetProcessHeap(), 0, wstr
);
1862 /* helper for nulldrv_ExtTextOut */
1863 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
1864 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
1866 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
1867 UINT indices
[3] = {0, 0, 0x20};
1873 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
1875 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
1878 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
);
1879 if (ret
!= GDI_ERROR
) break;
1882 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
1883 if (!image
) return ERROR_SUCCESS
;
1887 if (!ret
) /* empty glyph */
1889 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
1890 return ERROR_SUCCESS
;
1893 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
1894 size
= metrics
->gmBlackBoxY
* stride
;
1896 if (!(image
->ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
1897 image
->is_copy
= TRUE
;
1898 image
->free
= free_heap_bits
;
1900 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
, &identity
);
1901 if (ret
== GDI_ERROR
)
1903 HeapFree( GetProcessHeap(), 0, image
->ptr
);
1904 return ERROR_NOT_FOUND
;
1906 return ERROR_SUCCESS
;
1909 /* helper for nulldrv_ExtTextOut */
1910 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
1911 LPCWSTR str
, UINT count
, const INT
*dx
)
1916 reset_bounds( &bounds
);
1917 for (i
= 0; i
< count
; i
++)
1919 GLYPHMETRICS metrics
;
1921 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
1923 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
1924 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
1925 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
1926 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
1927 add_bounds_rect( &bounds
, &rect
);
1931 if (flags
& ETO_PDY
)
1934 y
+= dx
[ i
* 2 + 1];
1940 x
+= metrics
.gmCellIncX
;
1941 y
+= metrics
.gmCellIncY
;
1947 /* helper for nulldrv_ExtTextOut */
1948 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
1949 const struct gdi_image_bits
*image
, const RECT
*clip
)
1951 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
1952 UINT i
, count
, max_count
;
1954 BYTE
*ptr
= image
->ptr
;
1955 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
1957 RECT rect
, clipped_rect
;
1959 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
1960 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
1961 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
1962 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
1963 if (!clip
) clipped_rect
= rect
;
1964 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
1966 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
1967 pts
= HeapAlloc( GetProcessHeap(), 0, max_count
* sizeof(*pts
) );
1971 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
1972 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
1974 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
1976 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
1977 pts
[count
].x
= rect
.left
+ x
;
1978 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
1979 pts
[count
+ 1].x
= rect
.left
+ x
;
1980 if (pts
[count
+ 1].x
> pts
[count
].x
)
1982 pts
[count
].y
= pts
[count
+ 1].y
= y
;
1987 assert( count
<= max_count
);
1988 dp_to_lp( dc
, pts
, count
);
1989 for (i
= 0; i
< count
; i
+= 2) Polyline( dc
->hSelf
, pts
+ i
, 2 );
1990 HeapFree( GetProcessHeap(), 0, pts
);
1993 /***********************************************************************
1994 * nulldrv_ExtTextOut
1996 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
1997 LPCWSTR str
, UINT count
, const INT
*dx
)
1999 DC
*dc
= get_nulldrv_dc( dev
);
2005 if (flags
& ETO_OPAQUE
)
2008 HBRUSH brush
= CreateSolidBrush( GetNearestColor( dev
->hdc
, dc
->backgroundColor
) );
2012 orig
= SelectObject( dev
->hdc
, brush
);
2013 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
2014 PatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
2015 SelectObject( dev
->hdc
, orig
);
2016 DeleteObject( brush
);
2020 if (!count
) return TRUE
;
2022 if (dc
->aa_flags
!= GGO_BITMAP
)
2024 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
2025 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
2026 struct gdi_image_bits bits
;
2027 struct bitblt_coords src
, dst
;
2029 /* FIXME Subpixel modes */
2030 UINT aa_flags
= GGO_GRAY4_BITMAP
;
2032 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
2033 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
2034 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
2035 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
2037 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
2038 src
.x
= src
.visrect
.left
;
2039 src
.y
= src
.visrect
.top
;
2040 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
2041 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
2043 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
2044 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
2046 /* we can avoid the GetImage, just query the needed format */
2047 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
2048 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
2049 info
->bmiHeader
.biWidth
= src
.width
;
2050 info
->bmiHeader
.biHeight
= -src
.height
;
2051 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
2052 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
2053 if (!err
|| err
== ERROR_BAD_FORMAT
)
2055 /* make the source rectangle relative to the source bits */
2057 src
.visrect
.left
= src
.visrect
.top
= 0;
2058 src
.visrect
.right
= src
.width
;
2059 src
.visrect
.bottom
= src
.height
;
2061 bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
2062 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
2063 bits
.is_copy
= TRUE
;
2064 bits
.free
= free_heap_bits
;
2065 err
= ERROR_SUCCESS
;
2070 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
2071 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
2072 if (!err
&& !bits
.is_copy
)
2074 void *ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
2077 if (bits
.free
) bits
.free( &bits
);
2078 return ERROR_OUTOFMEMORY
;
2080 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
2081 if (bits
.free
) bits
.free( &bits
);
2083 bits
.is_copy
= TRUE
;
2084 bits
.free
= free_heap_bits
;
2089 /* make x,y relative to the image bits */
2090 x
+= src
.visrect
.left
- dst
.visrect
.left
;
2091 y
+= src
.visrect
.top
- dst
.visrect
.top
;
2092 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
2093 aa_flags
, str
, count
, dx
);
2094 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
2095 if (bits
.free
) bits
.free( &bits
);
2100 pen
= CreatePen( PS_SOLID
, 1, dc
->textColor
);
2101 orig
= SelectObject( dev
->hdc
, pen
);
2103 for (i
= 0; i
< count
; i
++)
2105 GLYPHMETRICS metrics
;
2106 struct gdi_image_bits image
;
2108 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
2111 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
2112 if (image
.free
) image
.free( &image
);
2116 if (flags
& ETO_PDY
)
2119 y
+= dx
[ i
* 2 + 1];
2125 x
+= metrics
.gmCellIncX
;
2126 y
+= metrics
.gmCellIncY
;
2130 SelectObject( dev
->hdc
, orig
);
2131 DeleteObject( pen
);
2136 /***********************************************************************
2137 * ExtTextOutA (GDI32.@)
2141 BOOL WINAPI
ExtTextOutA( HDC hdc
, INT x
, INT y
, UINT flags
,
2142 const RECT
*lprect
, LPCSTR str
, UINT count
, const INT
*lpDx
)
2150 if (flags
& ETO_GLYPH_INDEX
)
2151 return ExtTextOutW( hdc
, x
, y
, flags
, lprect
, (LPCWSTR
)str
, count
, lpDx
);
2153 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, &codepage
);
2156 unsigned int i
= 0, j
= 0;
2158 /* allocate enough for a ETO_PDY */
2159 lpDxW
= HeapAlloc( GetProcessHeap(), 0, 2*wlen
*sizeof(INT
));
2161 if(IsDBCSLeadByteEx(codepage
, str
[i
]))
2165 lpDxW
[j
++] = lpDx
[i
* 2] + lpDx
[(i
+ 1) * 2];
2166 lpDxW
[j
++] = lpDx
[i
* 2 + 1] + lpDx
[(i
+ 1) * 2 + 1];
2169 lpDxW
[j
++] = lpDx
[i
] + lpDx
[i
+ 1];
2176 lpDxW
[j
++] = lpDx
[i
* 2];
2177 lpDxW
[j
++] = lpDx
[i
* 2 + 1];
2180 lpDxW
[j
++] = lpDx
[i
];
2186 ret
= ExtTextOutW( hdc
, x
, y
, flags
, lprect
, p
, wlen
, lpDxW
);
2188 HeapFree( GetProcessHeap(), 0, p
);
2189 HeapFree( GetProcessHeap(), 0, lpDxW
);
2193 /***********************************************************************
2196 * Scale the underline / strikeout line width.
2198 static inline int get_line_width( DC
*dc
, int metric_size
)
2200 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
2201 if (width
== 0) width
= 1;
2202 if (metric_size
< 0) width
= -width
;
2206 /***********************************************************************
2207 * ExtTextOutW (GDI32.@)
2209 * Draws text using the currently selected font, background color, and text color.
2213 * x,y [I] coordinates of string
2215 * ETO_GRAYED - undocumented on MSDN
2216 * ETO_OPAQUE - use background color for fill the rectangle
2217 * ETO_CLIPPED - clipping text to the rectangle
2218 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
2219 * than encoded characters. Implies ETO_IGNORELANGUAGE
2220 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
2221 * Affects BiDi ordering
2222 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
2223 * ETO_PDY - unimplemented
2224 * ETO_NUMERICSLATIN - unimplemented always assumed -
2225 * do not translate numbers into locale representations
2226 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
2227 * lprect [I] dimensions for clipping or/and opaquing
2228 * str [I] text string
2229 * count [I] number of symbols in string
2230 * lpDx [I] optional parameter with distance between drawing characters
2236 BOOL WINAPI
ExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
,
2237 const RECT
*lprect
, LPCWSTR str
, UINT count
, const INT
*lpDx
)
2240 LPWSTR reordered_str
= (LPWSTR
)str
;
2241 WORD
*glyphs
= NULL
;
2247 double cosEsc
, sinEsc
;
2251 POINT
*deltas
= NULL
, width
= {0, 0};
2253 DC
* dc
= get_dc_ptr( hdc
);
2256 static int quietfixme
= 0;
2258 if (!dc
) return FALSE
;
2260 align
= dc
->textAlign
;
2261 breakRem
= dc
->breakRem
;
2262 layout
= dc
->layout
;
2264 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
2266 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
2271 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
2272 type
= GetObjectType(hdc
);
2273 if(type
== OBJ_METADC
|| type
== OBJ_ENHMETADC
)
2275 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, flags
, lprect
, str
, count
, lpDx
);
2276 release_dc_ptr( dc
);
2280 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
2281 if (layout
& LAYOUT_RTL
)
2283 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
2284 align
^= TA_RTLREADING
;
2287 if( !(flags
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)) && count
> 0 )
2290 reordered_str
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
2292 BIDI_Reorder( hdc
, str
, count
, GCP_REORDER
,
2293 (align
& TA_RTLREADING
) ? WINE_GCPW_FORCE_RTL
: WINE_GCPW_FORCE_LTR
,
2294 reordered_str
, count
, NULL
, &glyphs
, &cGlyphs
);
2296 flags
|= ETO_IGNORELANGUAGE
;
2299 flags
|= ETO_GLYPH_INDEX
;
2300 if (cGlyphs
!= count
)
2304 else if(flags
& ETO_GLYPH_INDEX
)
2305 glyphs
= reordered_str
;
2307 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
2308 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
2309 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->backgroundMode
, dc
->MapMode
);
2311 if(align
& TA_UPDATECP
)
2318 GetTextMetricsW(hdc
, &tm
);
2319 GetObjectW(dc
->hFont
, sizeof(lf
), &lf
);
2321 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
2322 lf
.lfEscapement
= 0;
2324 if ((dc
->GraphicsMode
== GM_COMPATIBLE
) &&
2325 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
2327 lf
.lfEscapement
= -lf
.lfEscapement
;
2330 if(lf
.lfEscapement
!= 0)
2332 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
2333 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
2341 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
2344 lp_to_dp(dc
, (POINT
*)&rc
, 2);
2346 if (flags
& ETO_OPAQUE
)
2347 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
2349 else flags
&= ~ETO_CLIPPED
;
2359 lp_to_dp(dc
, &pt
, 1);
2363 char_extra
= GetTextCharacterExtra(hdc
);
2364 if (char_extra
&& lpDx
&& GetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
2365 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
2367 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
2370 POINT total
= {0, 0}, desired
[2];
2372 deltas
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*deltas
));
2375 if (flags
& ETO_PDY
)
2377 for (i
= 0; i
< count
; i
++)
2379 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
2380 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
2385 for (i
= 0; i
< count
; i
++)
2387 deltas
[i
].x
= lpDx
[i
] + char_extra
;
2394 INT
*dx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*dx
) );
2396 if (flags
& ETO_GLYPH_INDEX
)
2397 GetTextExtentExPointI( hdc
, glyphs
, count
, -1, NULL
, dx
, &sz
);
2399 GetTextExtentExPointW( hdc
, reordered_str
, count
, -1, NULL
, dx
, &sz
);
2401 deltas
[0].x
= dx
[0];
2403 for (i
= 1; i
< count
; i
++)
2405 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
2408 HeapFree( GetProcessHeap(), 0, dx
);
2411 for(i
= 0; i
< count
; i
++)
2413 total
.x
+= deltas
[i
].x
;
2414 total
.y
+= deltas
[i
].y
;
2416 desired
[0].x
= desired
[0].y
= 0;
2418 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
2419 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
2421 lp_to_dp(dc
, desired
, 2);
2422 desired
[1].x
-= desired
[0].x
;
2423 desired
[1].y
-= desired
[0].y
;
2425 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
2427 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
2428 desired
[1].x
= -desired
[1].x
;
2429 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
2430 desired
[1].y
= -desired
[1].y
;
2433 deltas
[i
].x
= desired
[1].x
- width
.x
;
2434 deltas
[i
].y
= desired
[1].y
- width
.y
;
2444 if(flags
& ETO_GLYPH_INDEX
)
2445 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
2447 GetTextExtentPointW(hdc
, reordered_str
, count
, &sz
);
2448 desired
[0].x
= desired
[0].y
= 0;
2449 desired
[1].x
= sz
.cx
;
2451 lp_to_dp(dc
, desired
, 2);
2452 desired
[1].x
-= desired
[0].x
;
2453 desired
[1].y
-= desired
[0].y
;
2455 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
2457 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
2458 desired
[1].x
= -desired
[1].x
;
2459 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
2460 desired
[1].y
= -desired
[1].y
;
2465 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
2466 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
2467 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
2470 if (align
& TA_UPDATECP
)
2474 dp_to_lp(dc
, &pt
, 1);
2475 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
2487 if (align
& TA_UPDATECP
)
2491 dp_to_lp(dc
, &pt
, 1);
2492 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
2497 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
2500 y
+= tm
.tmAscent
* cosEsc
;
2501 x
+= tm
.tmAscent
* sinEsc
;
2505 y
-= tm
.tmDescent
* cosEsc
;
2506 x
-= tm
.tmDescent
* sinEsc
;
2513 if (dc
->backgroundMode
!= TRANSPARENT
)
2515 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
2517 if(!(flags
& ETO_OPAQUE
) || !lprect
||
2518 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
2519 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
2523 text_box
.right
= x
+ width
.x
;
2524 text_box
.top
= y
- tm
.tmAscent
;
2525 text_box
.bottom
= y
+ tm
.tmDescent
;
2527 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
2528 if (!is_rect_empty( &text_box
))
2529 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
2534 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
2535 glyphs
? glyphs
: reordered_str
, count
, (INT
*)deltas
);
2538 HeapFree(GetProcessHeap(), 0, deltas
);
2539 if(glyphs
!= reordered_str
)
2540 HeapFree(GetProcessHeap(), 0, glyphs
);
2541 if(reordered_str
!= str
)
2542 HeapFree(GetProcessHeap(), 0, reordered_str
);
2544 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
2546 int underlinePos
, strikeoutPos
;
2547 int underlineWidth
, strikeoutWidth
;
2548 UINT size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
2549 OUTLINETEXTMETRICW
* otm
= NULL
;
2551 HPEN hpen
= SelectObject(hdc
, GetStockObject(NULL_PEN
));
2552 HBRUSH hbrush
= CreateSolidBrush(dc
->textColor
);
2554 hbrush
= SelectObject(hdc
, hbrush
);
2559 underlineWidth
= tm
.tmAscent
/ 20 + 1;
2560 strikeoutPos
= tm
.tmAscent
/ 2;
2561 strikeoutWidth
= underlineWidth
;
2565 otm
= HeapAlloc(GetProcessHeap(), 0, size
);
2566 GetOutlineTextMetricsW(hdc
, size
, otm
);
2567 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
2568 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
2569 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
2570 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
2571 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
2572 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
2573 HeapFree(GetProcessHeap(), 0, otm
);
2579 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
2580 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
2581 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
2582 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
2583 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
2584 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
2585 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
2586 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
2587 pts
[4].x
= pts
[0].x
;
2588 pts
[4].y
= pts
[0].y
;
2589 dp_to_lp(dc
, pts
, 5);
2590 Polygon(hdc
, pts
, 5);
2595 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
2596 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
2597 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
2598 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
2599 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
2600 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
2601 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
2602 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
2603 pts
[4].x
= pts
[0].x
;
2604 pts
[4].y
= pts
[0].y
;
2605 dp_to_lp(dc
, pts
, 5);
2606 Polygon(hdc
, pts
, 5);
2609 SelectObject(hdc
, hpen
);
2610 hbrush
= SelectObject(hdc
, hbrush
);
2611 DeleteObject(hbrush
);
2614 release_dc_ptr( dc
);
2620 /***********************************************************************
2621 * TextOutA (GDI32.@)
2623 BOOL WINAPI
TextOutA( HDC hdc
, INT x
, INT y
, LPCSTR str
, INT count
)
2625 return ExtTextOutA( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
2629 /***********************************************************************
2630 * TextOutW (GDI32.@)
2632 BOOL WINAPI
TextOutW(HDC hdc
, INT x
, INT y
, LPCWSTR str
, INT count
)
2634 return ExtTextOutW( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
2638 /***********************************************************************
2639 * PolyTextOutA (GDI32.@)
2643 BOOL WINAPI
PolyTextOutA( HDC hdc
, const POLYTEXTA
*pptxt
, INT cStrings
)
2645 for (; cStrings
>0; cStrings
--, pptxt
++)
2646 if (!ExtTextOutA( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
2653 /***********************************************************************
2654 * PolyTextOutW (GDI32.@)
2656 * Draw several Strings
2662 BOOL WINAPI
PolyTextOutW( HDC hdc
, const POLYTEXTW
*pptxt
, INT cStrings
)
2664 for (; cStrings
>0; cStrings
--, pptxt
++)
2665 if (!ExtTextOutW( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
2671 /***********************************************************************
2672 * SetMapperFlags (GDI32.@)
2674 DWORD WINAPI
SetMapperFlags( HDC hdc
, DWORD flags
)
2676 DC
*dc
= get_dc_ptr( hdc
);
2677 DWORD ret
= GDI_ERROR
;
2681 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetMapperFlags
);
2682 flags
= physdev
->funcs
->pSetMapperFlags( physdev
, flags
);
2683 if (flags
!= GDI_ERROR
)
2685 ret
= dc
->mapperFlags
;
2686 dc
->mapperFlags
= flags
;
2688 release_dc_ptr( dc
);
2693 /***********************************************************************
2694 * GetAspectRatioFilterEx (GDI32.@)
2696 BOOL WINAPI
GetAspectRatioFilterEx( HDC hdc
, LPSIZE pAspectRatio
)
2698 FIXME("(%p, %p): -- Empty Stub !\n", hdc
, pAspectRatio
);
2703 /***********************************************************************
2704 * GetCharABCWidthsA (GDI32.@)
2706 * See GetCharABCWidthsW.
2708 BOOL WINAPI
GetCharABCWidthsA(HDC hdc
, UINT firstChar
, UINT lastChar
,
2716 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
2720 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
2723 HeapFree(GetProcessHeap(), 0, str
);
2727 for(i
= 0; i
< wlen
; i
++)
2729 if(!GetCharABCWidthsW(hdc
, wstr
[i
], wstr
[i
], abc
))
2737 HeapFree(GetProcessHeap(), 0, str
);
2738 HeapFree(GetProcessHeap(), 0, wstr
);
2744 /******************************************************************************
2745 * GetCharABCWidthsW [GDI32.@]
2747 * Retrieves widths of characters in range.
2750 * hdc [I] Handle of device context
2751 * firstChar [I] First character in range to query
2752 * lastChar [I] Last character in range to query
2753 * abc [O] Address of character-width structure
2756 * Only works with TrueType fonts
2762 BOOL WINAPI
GetCharABCWidthsW( HDC hdc
, UINT firstChar
, UINT lastChar
,
2765 DC
*dc
= get_dc_ptr(hdc
);
2771 if (!dc
) return FALSE
;
2775 release_dc_ptr( dc
);
2779 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
2780 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
2781 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
2783 release_dc_ptr( dc
);
2787 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
2788 ret
= dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, abc
);
2791 /* convert device units to logical */
2792 for( i
= firstChar
; i
<= lastChar
; i
++, abc
++ ) {
2793 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
2794 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
2795 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
2799 release_dc_ptr( dc
);
2804 /******************************************************************************
2805 * GetCharABCWidthsI [GDI32.@]
2807 * Retrieves widths of characters in range.
2810 * hdc [I] Handle of device context
2811 * firstChar [I] First glyphs in range to query
2812 * count [I] Last glyphs in range to query
2813 * pgi [i] Array of glyphs to query
2814 * abc [O] Address of character-width structure
2817 * Only works with TrueType fonts
2823 BOOL WINAPI
GetCharABCWidthsI( HDC hdc
, UINT firstChar
, UINT count
,
2824 LPWORD pgi
, LPABC abc
)
2826 DC
*dc
= get_dc_ptr(hdc
);
2831 if (!dc
) return FALSE
;
2835 release_dc_ptr( dc
);
2839 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
2840 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, abc
);
2843 /* convert device units to logical */
2844 for( i
= 0; i
< count
; i
++, abc
++ ) {
2845 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
2846 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
2847 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
2851 release_dc_ptr( dc
);
2856 /***********************************************************************
2857 * GetGlyphOutlineA (GDI32.@)
2859 DWORD WINAPI
GetGlyphOutlineA( HDC hdc
, UINT uChar
, UINT fuFormat
,
2860 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
2861 LPVOID lpBuffer
, const MAT2
*lpmat2
)
2863 if (!lpmat2
) return GDI_ERROR
;
2865 if(!(fuFormat
& GGO_GLYPH_INDEX
)) {
2871 cp
= GdiGetCodePage(hdc
);
2872 if (IsDBCSLeadByteEx(cp
, uChar
>> 8)) {
2874 mbchs
[0] = (uChar
& 0xff00) >> 8;
2875 mbchs
[1] = (uChar
& 0xff);
2878 mbchs
[0] = (uChar
& 0xff);
2881 MultiByteToWideChar(cp
, 0, mbchs
, len
, &wChar
, 1);
2885 return GetGlyphOutlineW(hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
,
2889 /***********************************************************************
2890 * GetGlyphOutlineW (GDI32.@)
2892 DWORD WINAPI
GetGlyphOutlineW( HDC hdc
, UINT uChar
, UINT fuFormat
,
2893 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
2894 LPVOID lpBuffer
, const MAT2
*lpmat2
)
2900 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
2901 hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
2903 if (!lpmat2
) return GDI_ERROR
;
2905 dc
= get_dc_ptr(hdc
);
2906 if(!dc
) return GDI_ERROR
;
2908 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
2909 ret
= dev
->funcs
->pGetGlyphOutline( dev
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
2910 release_dc_ptr( dc
);
2915 /***********************************************************************
2916 * CreateScalableFontResourceA (GDI32.@)
2918 BOOL WINAPI
CreateScalableFontResourceA( DWORD fHidden
,
2919 LPCSTR lpszResourceFile
,
2920 LPCSTR lpszFontFile
,
2921 LPCSTR lpszCurrentPath
)
2923 LPWSTR lpszResourceFileW
= NULL
;
2924 LPWSTR lpszFontFileW
= NULL
;
2925 LPWSTR lpszCurrentPathW
= NULL
;
2929 if (lpszResourceFile
)
2931 len
= MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, NULL
, 0);
2932 lpszResourceFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2933 MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, lpszResourceFileW
, len
);
2938 len
= MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, NULL
, 0);
2939 lpszFontFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2940 MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, lpszFontFileW
, len
);
2943 if (lpszCurrentPath
)
2945 len
= MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, NULL
, 0);
2946 lpszCurrentPathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
2947 MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, lpszCurrentPathW
, len
);
2950 ret
= CreateScalableFontResourceW(fHidden
, lpszResourceFileW
,
2951 lpszFontFileW
, lpszCurrentPathW
);
2953 HeapFree(GetProcessHeap(), 0, lpszResourceFileW
);
2954 HeapFree(GetProcessHeap(), 0, lpszFontFileW
);
2955 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW
);
2960 /***********************************************************************
2961 * CreateScalableFontResourceW (GDI32.@)
2963 BOOL WINAPI
CreateScalableFontResourceW( DWORD hidden
, LPCWSTR resource_file
,
2964 LPCWSTR font_file
, LPCWSTR font_path
)
2966 TRACE("(%d, %s, %s, %s)\n", hidden
, debugstr_w(resource_file
),
2967 debugstr_w(font_file
), debugstr_w(font_path
) );
2969 return WineEngCreateScalableFontResource( hidden
, resource_file
,
2970 font_file
, font_path
);
2973 /*************************************************************************
2974 * GetKerningPairsA (GDI32.@)
2976 DWORD WINAPI
GetKerningPairsA( HDC hDC
, DWORD cPairs
,
2977 LPKERNINGPAIR kern_pairA
)
2981 DWORD i
, total_kern_pairs
, kern_pairs_copied
= 0;
2982 KERNINGPAIR
*kern_pairW
;
2984 if (!cPairs
&& kern_pairA
)
2986 SetLastError(ERROR_INVALID_PARAMETER
);
2990 cp
= GdiGetCodePage(hDC
);
2992 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
2993 * to fail on an invalid character for CP_SYMBOL.
2995 cpi
.DefaultChar
[0] = 0;
2996 if (cp
!= CP_SYMBOL
&& !GetCPInfo(cp
, &cpi
))
2998 FIXME("Can't find codepage %u info\n", cp
);
3002 total_kern_pairs
= GetKerningPairsW(hDC
, 0, NULL
);
3003 if (!total_kern_pairs
) return 0;
3005 kern_pairW
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pairW
));
3006 GetKerningPairsW(hDC
, total_kern_pairs
, kern_pairW
);
3008 for (i
= 0; i
< total_kern_pairs
; i
++)
3012 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wFirst
, 1, &first
, 1, NULL
, NULL
))
3015 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wSecond
, 1, &second
, 1, NULL
, NULL
))
3018 if (first
== cpi
.DefaultChar
[0] || second
== cpi
.DefaultChar
[0])
3023 if (kern_pairs_copied
>= cPairs
) break;
3025 kern_pairA
->wFirst
= (BYTE
)first
;
3026 kern_pairA
->wSecond
= (BYTE
)second
;
3027 kern_pairA
->iKernAmount
= kern_pairW
[i
].iKernAmount
;
3030 kern_pairs_copied
++;
3033 HeapFree(GetProcessHeap(), 0, kern_pairW
);
3035 return kern_pairs_copied
;
3038 /*************************************************************************
3039 * GetKerningPairsW (GDI32.@)
3041 DWORD WINAPI
GetKerningPairsW( HDC hDC
, DWORD cPairs
,
3042 LPKERNINGPAIR lpKerningPairs
)
3048 TRACE("(%p,%d,%p)\n", hDC
, cPairs
, lpKerningPairs
);
3050 if (!cPairs
&& lpKerningPairs
)
3052 SetLastError(ERROR_INVALID_PARAMETER
);
3056 dc
= get_dc_ptr(hDC
);
3059 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
3060 ret
= dev
->funcs
->pGetKerningPairs( dev
, cPairs
, lpKerningPairs
);
3061 release_dc_ptr( dc
);
3065 /*************************************************************************
3066 * TranslateCharsetInfo [GDI32.@]
3068 * Fills a CHARSETINFO structure for a character set, code page, or
3069 * font. This allows making the correspondence between different labels
3070 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
3071 * of the same encoding.
3073 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
3074 * only one codepage should be set in *lpSrc.
3077 * TRUE on success, FALSE on failure.
3080 BOOL WINAPI
TranslateCharsetInfo(
3081 LPDWORD lpSrc
, /* [in]
3082 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
3083 if flags == TCI_SRCCHARSET: a character set value
3084 if flags == TCI_SRCCODEPAGE: a code page value
3086 LPCHARSETINFO lpCs
, /* [out] structure to receive charset information */
3087 DWORD flags
/* [in] determines interpretation of lpSrc */)
3091 case TCI_SRCFONTSIG
:
3092 while (index
< MAXTCIINDEX
&& !(*lpSrc
>>index
& 0x0001)) index
++;
3094 case TCI_SRCCODEPAGE
:
3095 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciACP
) index
++;
3097 case TCI_SRCCHARSET
:
3098 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciCharset
) index
++;
3103 if (index
>= MAXTCIINDEX
|| FONT_tci
[index
].ciCharset
== DEFAULT_CHARSET
) return FALSE
;
3104 *lpCs
= FONT_tci
[index
];
3108 /*************************************************************************
3109 * GetFontLanguageInfo (GDI32.@)
3111 DWORD WINAPI
GetFontLanguageInfo(HDC hdc
)
3113 FONTSIGNATURE fontsig
;
3114 static const DWORD GCP_DBCS_MASK
=FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
,
3115 GCP_DIACRITIC_MASK
=0x00000000,
3116 FLI_GLYPHS_MASK
=0x00000000,
3117 GCP_GLYPHSHAPE_MASK
=FS_ARABIC
,
3118 GCP_KASHIDA_MASK
=0x00000000,
3119 GCP_LIGATE_MASK
=0x00000000,
3120 GCP_REORDER_MASK
=FS_HEBREW
|FS_ARABIC
;
3124 GetTextCharsetInfo( hdc
, &fontsig
, 0 );
3125 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
3127 if( (fontsig
.fsCsb
[0]&GCP_DBCS_MASK
)!=0 )
3130 if( (fontsig
.fsCsb
[0]&GCP_DIACRITIC_MASK
)!=0 )
3131 result
|=GCP_DIACRITIC
;
3133 if( (fontsig
.fsCsb
[0]&FLI_GLYPHS_MASK
)!=0 )
3136 if( (fontsig
.fsCsb
[0]&GCP_GLYPHSHAPE_MASK
)!=0 )
3137 result
|=GCP_GLYPHSHAPE
;
3139 if( (fontsig
.fsCsb
[0]&GCP_KASHIDA_MASK
)!=0 )
3140 result
|=GCP_KASHIDA
;
3142 if( (fontsig
.fsCsb
[0]&GCP_LIGATE_MASK
)!=0 )
3145 if( GetKerningPairsW( hdc
, 0, NULL
) )
3146 result
|=GCP_USEKERNING
;
3148 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
3149 if( GetTextAlign( hdc
) & TA_RTLREADING
)
3150 if( (fontsig
.fsCsb
[0]&GCP_REORDER_MASK
)!=0 )
3151 result
|=GCP_REORDER
;
3157 /*************************************************************************
3158 * GetFontData [GDI32.@]
3160 * Retrieve data for TrueType font.
3164 * success: Number of bytes returned
3165 * failure: GDI_ERROR
3169 * Calls SetLastError()
3172 DWORD WINAPI
GetFontData(HDC hdc
, DWORD table
, DWORD offset
,
3173 LPVOID buffer
, DWORD length
)
3175 DC
*dc
= get_dc_ptr(hdc
);
3179 if(!dc
) return GDI_ERROR
;
3181 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
3182 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
3183 release_dc_ptr( dc
);
3187 /*************************************************************************
3188 * GetGlyphIndicesA [GDI32.@]
3190 DWORD WINAPI
GetGlyphIndicesA(HDC hdc
, LPCSTR lpstr
, INT count
,
3191 LPWORD pgi
, DWORD flags
)
3197 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3198 hdc
, debugstr_an(lpstr
, count
), count
, pgi
, flags
);
3200 lpstrW
= FONT_mbtowc(hdc
, lpstr
, count
, &countW
, NULL
);
3201 ret
= GetGlyphIndicesW(hdc
, lpstrW
, countW
, pgi
, flags
);
3202 HeapFree(GetProcessHeap(), 0, lpstrW
);
3207 /*************************************************************************
3208 * GetGlyphIndicesW [GDI32.@]
3210 DWORD WINAPI
GetGlyphIndicesW(HDC hdc
, LPCWSTR lpstr
, INT count
,
3211 LPWORD pgi
, DWORD flags
)
3213 DC
*dc
= get_dc_ptr(hdc
);
3217 TRACE("(%p, %s, %d, %p, 0x%x)\n",
3218 hdc
, debugstr_wn(lpstr
, count
), count
, pgi
, flags
);
3220 if(!dc
) return GDI_ERROR
;
3222 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
3223 ret
= dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
3224 release_dc_ptr( dc
);
3228 /*************************************************************************
3229 * GetCharacterPlacementA [GDI32.@]
3231 * See GetCharacterPlacementW.
3234 * the web browser control of ie4 calls this with dwFlags=0
3237 GetCharacterPlacementA(HDC hdc
, LPCSTR lpString
, INT uCount
,
3238 INT nMaxExtent
, GCP_RESULTSA
*lpResults
,
3243 GCP_RESULTSW resultsW
;
3247 TRACE("%s, %d, %d, 0x%08x\n",
3248 debugstr_an(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
3250 lpStringW
= FONT_mbtowc(hdc
, lpString
, uCount
, &uCountW
, &font_cp
);
3254 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, NULL
, dwFlags
);
3255 HeapFree(GetProcessHeap(), 0, lpStringW
);
3259 /* both structs are equal in size */
3260 memcpy(&resultsW
, lpResults
, sizeof(resultsW
));
3262 if(lpResults
->lpOutString
)
3263 resultsW
.lpOutString
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*uCountW
);
3265 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, &resultsW
, dwFlags
);
3267 lpResults
->nGlyphs
= resultsW
.nGlyphs
;
3268 lpResults
->nMaxFit
= resultsW
.nMaxFit
;
3270 if(lpResults
->lpOutString
) {
3271 WideCharToMultiByte(font_cp
, 0, resultsW
.lpOutString
, uCountW
,
3272 lpResults
->lpOutString
, uCount
, NULL
, NULL
);
3275 HeapFree(GetProcessHeap(), 0, lpStringW
);
3276 HeapFree(GetProcessHeap(), 0, resultsW
.lpOutString
);
3281 /*************************************************************************
3282 * GetCharacterPlacementW [GDI32.@]
3284 * Retrieve information about a string. This includes the width, reordering,
3285 * Glyphing and so on.
3289 * The width and height of the string if successful, 0 if failed.
3293 * All flags except GCP_REORDER are not yet implemented.
3294 * Reordering is not 100% compliant to the Windows BiDi method.
3295 * Caret positioning is not yet implemented for BiDi.
3296 * Classes are not yet implemented.
3300 GetCharacterPlacementW(
3301 HDC hdc
, /* [in] Device context for which the rendering is to be done */
3302 LPCWSTR lpString
, /* [in] The string for which information is to be returned */
3303 INT uCount
, /* [in] Number of WORDS in string. */
3304 INT nMaxExtent
, /* [in] Maximum extent the string is to take (in HDC logical units) */
3305 GCP_RESULTSW
*lpResults
, /* [in/out] A pointer to a GCP_RESULTSW struct */
3306 DWORD dwFlags
/* [in] Flags specifying how to process the string */
3313 TRACE("%s, %d, %d, 0x%08x\n",
3314 debugstr_wn(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
3320 return GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
) ? MAKELONG(size
.cx
, size
.cy
) : 0;
3322 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
3323 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
3324 lpResults
->lStructSize
, lpResults
->lpOutString
, lpResults
->lpOrder
,
3325 lpResults
->lpDx
, lpResults
->lpCaretPos
, lpResults
->lpClass
,
3326 lpResults
->lpGlyphs
, lpResults
->nGlyphs
, lpResults
->nMaxFit
);
3328 if(dwFlags
&(~GCP_REORDER
))
3329 FIXME("flags 0x%08x ignored\n", dwFlags
);
3330 if(lpResults
->lpClass
)
3331 FIXME("classes not implemented\n");
3332 if (lpResults
->lpCaretPos
&& (dwFlags
& GCP_REORDER
))
3333 FIXME("Caret positions for complex scripts not implemented\n");
3335 nSet
= (UINT
)uCount
;
3336 if(nSet
> lpResults
->nGlyphs
)
3337 nSet
= lpResults
->nGlyphs
;
3339 /* return number of initialized fields */
3340 lpResults
->nGlyphs
= nSet
;
3342 if((dwFlags
&GCP_REORDER
)==0 )
3344 /* Treat the case where no special handling was requested in a fastpath way */
3345 /* copy will do if the GCP_REORDER flag is not set */
3346 if(lpResults
->lpOutString
)
3347 memcpy( lpResults
->lpOutString
, lpString
, nSet
* sizeof(WCHAR
));
3349 if(lpResults
->lpOrder
)
3351 for(i
= 0; i
< nSet
; i
++)
3352 lpResults
->lpOrder
[i
] = i
;
3357 BIDI_Reorder(NULL
, lpString
, uCount
, dwFlags
, WINE_GCPW_FORCE_LTR
, lpResults
->lpOutString
,
3358 nSet
, lpResults
->lpOrder
, NULL
, NULL
);
3361 /* FIXME: Will use the placement chars */
3362 if (lpResults
->lpDx
)
3365 for (i
= 0; i
< nSet
; i
++)
3367 if (GetCharWidth32W(hdc
, lpString
[i
], lpString
[i
], &c
))
3368 lpResults
->lpDx
[i
]= c
;
3372 if (lpResults
->lpCaretPos
&& !(dwFlags
& GCP_REORDER
))
3376 lpResults
->lpCaretPos
[0] = 0;
3377 for (i
= 1; i
< nSet
; i
++)
3378 if (GetTextExtentPoint32W(hdc
, &(lpString
[i
- 1]), 1, &size
))
3379 lpResults
->lpCaretPos
[i
] = (pos
+= size
.cx
);
3382 if(lpResults
->lpGlyphs
)
3383 GetGlyphIndicesW(hdc
, lpString
, nSet
, lpResults
->lpGlyphs
, 0);
3385 if (GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
))
3386 ret
= MAKELONG(size
.cx
, size
.cy
);
3391 /*************************************************************************
3392 * GetCharABCWidthsFloatA [GDI32.@]
3394 * See GetCharABCWidthsFloatW.
3396 BOOL WINAPI
GetCharABCWidthsFloatA( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
3403 str
= FONT_GetCharsByRangeA(hdc
, first
, last
, &i
);
3407 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
3409 for (i
= 0; i
< wlen
; i
++)
3411 if (!GetCharABCWidthsFloatW( hdc
, wstr
[i
], wstr
[i
], abcf
))
3419 HeapFree( GetProcessHeap(), 0, str
);
3420 HeapFree( GetProcessHeap(), 0, wstr
);
3425 /*************************************************************************
3426 * GetCharABCWidthsFloatW [GDI32.@]
3428 * Retrieves widths of a range of characters.
3431 * hdc [I] Handle to device context.
3432 * first [I] First character in range to query.
3433 * last [I] Last character in range to query.
3434 * abcf [O] Array of LPABCFLOAT structures.
3440 BOOL WINAPI
GetCharABCWidthsFloatW( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
3446 DC
*dc
= get_dc_ptr( hdc
);
3448 TRACE("%p, %d, %d, %p\n", hdc
, first
, last
, abcf
);
3450 if (!dc
) return FALSE
;
3452 if (!abcf
) goto done
;
3453 if (!(abc
= HeapAlloc( GetProcessHeap(), 0, (last
- first
+ 1) * sizeof(*abc
) ))) goto done
;
3455 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
3456 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, abc
);
3459 /* convert device units to logical */
3460 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
3461 for (i
= first
; i
<= last
; i
++, abcf
++)
3463 abcf
->abcfA
= abc
[i
- first
].abcA
* scale
;
3464 abcf
->abcfB
= abc
[i
- first
].abcB
* scale
;
3465 abcf
->abcfC
= abc
[i
- first
].abcC
* scale
;
3468 HeapFree( GetProcessHeap(), 0, abc
);
3471 release_dc_ptr( dc
);
3475 /*************************************************************************
3476 * GetCharWidthFloatA [GDI32.@]
3478 BOOL WINAPI
GetCharWidthFloatA( HDC hdc
, UINT first
, UINT last
, float *buffer
)
3484 if (!(str
= FONT_GetCharsByRangeA( hdc
, first
, last
, &i
)))
3486 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
3489 for (i
= 0; i
< wlen
; ++i
)
3491 if (!GetCharWidthFloatW( hdc
, wstr
[i
], wstr
[i
], &buffer
[i
] ))
3501 /*************************************************************************
3502 * GetCharWidthFloatW [GDI32.@]
3504 BOOL WINAPI
GetCharWidthFloatW( HDC hdc
, UINT first
, UINT last
, float *buffer
)
3506 DC
*dc
= get_dc_ptr( hdc
);
3512 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc
, first
, last
, buffer
);
3514 if (!dc
) return FALSE
;
3516 if (!(ibuffer
= heap_alloc( (last
- first
+ 1) * sizeof(int) )))
3518 release_dc_ptr( dc
);
3522 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
3523 if ((ret
= dev
->funcs
->pGetCharWidth( dev
, first
, last
, ibuffer
)))
3525 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
3526 for (i
= first
; i
<= last
; ++i
)
3527 buffer
[i
- first
] = ibuffer
[i
- first
] * scale
;
3534 /***********************************************************************
3536 * Font Resource API *
3538 ***********************************************************************/
3540 /***********************************************************************
3541 * AddFontResourceA (GDI32.@)
3543 INT WINAPI
AddFontResourceA( LPCSTR str
)
3545 return AddFontResourceExA( str
, 0, NULL
);
3548 /***********************************************************************
3549 * AddFontResourceW (GDI32.@)
3551 INT WINAPI
AddFontResourceW( LPCWSTR str
)
3553 return AddFontResourceExW(str
, 0, NULL
);
3557 /***********************************************************************
3558 * AddFontResourceExA (GDI32.@)
3560 INT WINAPI
AddFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
3562 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
3563 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3566 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
3567 ret
= AddFontResourceExW(strW
, fl
, pdv
);
3568 HeapFree(GetProcessHeap(), 0, strW
);
3572 static BOOL CALLBACK
load_enumed_resource(HMODULE hModule
, LPCWSTR type
, LPWSTR name
, LONG_PTR lParam
)
3574 HRSRC rsrc
= FindResourceW(hModule
, name
, type
);
3575 HGLOBAL hMem
= LoadResource(hModule
, rsrc
);
3576 LPVOID
*pMem
= LockResource(hMem
);
3577 int *num_total
= (int *)lParam
;
3580 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type
));
3581 if (!AddFontMemResourceEx(pMem
, SizeofResource(hModule
, rsrc
), NULL
, &num_in_res
))
3583 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule
, hMem
);
3587 *num_total
+= num_in_res
;
3591 static void *map_file( const WCHAR
*filename
, LARGE_INTEGER
*size
)
3593 HANDLE file
, mapping
;
3596 file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
3597 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
3599 if (!GetFileSizeEx( file
, size
) || size
->u
.HighPart
)
3601 CloseHandle( file
);
3605 mapping
= CreateFileMappingW( file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
3606 CloseHandle( file
);
3607 if (!mapping
) return NULL
;
3609 ptr
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
3610 CloseHandle( mapping
);
3615 static void *find_resource( BYTE
*ptr
, WORD type
, DWORD rsrc_off
, DWORD size
, DWORD
*len
)
3617 WORD align
, type_id
, count
;
3620 if (size
< rsrc_off
+ 10) return NULL
;
3621 align
= *(WORD
*)(ptr
+ rsrc_off
);
3623 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
3624 while (type_id
&& type_id
!= type
)
3626 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
3627 rsrc_off
+= 8 + count
* 12;
3628 if (size
< rsrc_off
+ 8) return NULL
;
3629 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
3631 if (!type_id
) return NULL
;
3632 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
3633 if (size
< rsrc_off
+ 8 + count
* 12) return NULL
;
3634 res_off
= *(WORD
*)(ptr
+ rsrc_off
+ 8) << align
;
3635 *len
= *(WORD
*)(ptr
+ rsrc_off
+ 10) << align
;
3636 if (size
< res_off
+ *len
) return NULL
;
3637 return ptr
+ res_off
;
3640 static WCHAR
*get_scalable_filename( const WCHAR
*res
, BOOL
*hidden
)
3643 BYTE
*ptr
= map_file( res
, &size
);
3644 const IMAGE_DOS_HEADER
*dos
;
3645 const IMAGE_OS2_HEADER
*ne
;
3651 if (!ptr
) return NULL
;
3653 if (size
.u
.LowPart
< sizeof( *dos
)) goto fail
;
3654 dos
= (const IMAGE_DOS_HEADER
*)ptr
;
3655 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto fail
;
3656 if (size
.u
.LowPart
< dos
->e_lfanew
+ sizeof( *ne
)) goto fail
;
3657 ne
= (const IMAGE_OS2_HEADER
*)(ptr
+ dos
->e_lfanew
);
3659 fontdir
= find_resource( ptr
, 0x8007, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
3660 if (!fontdir
) goto fail
;
3661 *hidden
= (fontdir
[35] & 0x80) != 0; /* fontdir->dfType */
3663 data
= find_resource( ptr
, 0x80cc, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
3664 if (!data
) goto fail
;
3665 if (!memchr( data
, 0, len
)) goto fail
;
3667 len
= MultiByteToWideChar( CP_ACP
, 0, data
, -1, NULL
, 0 );
3668 name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
3669 if (name
) MultiByteToWideChar( CP_ACP
, 0, data
, -1, name
, len
);
3672 UnmapViewOfFile( ptr
);
3676 /***********************************************************************
3677 * AddFontResourceExW (GDI32.@)
3679 INT WINAPI
AddFontResourceExW( LPCWSTR str
, DWORD fl
, PVOID pdv
)
3681 int ret
= WineEngAddFontResourceEx(str
, fl
, pdv
);
3687 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3688 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3689 if (hModule
!= NULL
)
3691 int num_resources
= 0;
3692 LPWSTR rt_font
= (LPWSTR
)((ULONG_PTR
)8); /* we don't want to include winuser.h */
3694 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
3695 wine_dbgstr_w(str
));
3696 if (EnumResourceNamesW(hModule
, rt_font
, load_enumed_resource
, (LONG_PTR
)&num_resources
))
3697 ret
= num_resources
;
3698 FreeLibrary(hModule
);
3700 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
3702 if (hidden
) fl
|= FR_PRIVATE
| FR_NOT_ENUM
;
3703 ret
= WineEngAddFontResourceEx( filename
, fl
, pdv
);
3704 HeapFree( GetProcessHeap(), 0, filename
);
3710 /***********************************************************************
3711 * RemoveFontResourceA (GDI32.@)
3713 BOOL WINAPI
RemoveFontResourceA( LPCSTR str
)
3715 return RemoveFontResourceExA(str
, 0, 0);
3718 /***********************************************************************
3719 * RemoveFontResourceW (GDI32.@)
3721 BOOL WINAPI
RemoveFontResourceW( LPCWSTR str
)
3723 return RemoveFontResourceExW(str
, 0, 0);
3726 /***********************************************************************
3727 * AddFontMemResourceEx (GDI32.@)
3729 HANDLE WINAPI
AddFontMemResourceEx( PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
3734 if (!pbFont
|| !cbFont
|| !pcFonts
)
3736 SetLastError(ERROR_INVALID_PARAMETER
);
3740 ret
= WineEngAddFontMemResourceEx(pbFont
, cbFont
, pdv
, &num_fonts
);
3745 *pcFonts
= num_fonts
;
3749 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts
);
3750 RemoveFontMemResourceEx(ret
);
3758 /***********************************************************************
3759 * RemoveFontMemResourceEx (GDI32.@)
3761 BOOL WINAPI
RemoveFontMemResourceEx( HANDLE fh
)
3763 FIXME("(%p) stub\n", fh
);
3767 /***********************************************************************
3768 * RemoveFontResourceExA (GDI32.@)
3770 BOOL WINAPI
RemoveFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
3772 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
3773 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3776 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
3777 ret
= RemoveFontResourceExW(strW
, fl
, pdv
);
3778 HeapFree(GetProcessHeap(), 0, strW
);
3782 /***********************************************************************
3783 * RemoveFontResourceExW (GDI32.@)
3785 BOOL WINAPI
RemoveFontResourceExW( LPCWSTR str
, DWORD fl
, PVOID pdv
)
3787 int ret
= WineEngRemoveFontResourceEx( str
, fl
, pdv
);
3793 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
3794 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
3795 if (hModule
!= NULL
)
3797 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str
));
3798 FreeLibrary(hModule
);
3800 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
3802 if (hidden
) fl
|= FR_PRIVATE
| FR_NOT_ENUM
;
3803 ret
= WineEngRemoveFontResourceEx( filename
, fl
, pdv
);
3804 HeapFree( GetProcessHeap(), 0, filename
);
3810 /***********************************************************************
3811 * GetFontResourceInfoW (GDI32.@)
3813 BOOL WINAPI
GetFontResourceInfoW( LPCWSTR str
, LPDWORD size
, PVOID buffer
, DWORD type
)
3815 FIXME("%s %p(%d) %p %d\n", debugstr_w(str
), size
, size
? *size
: 0, buffer
, type
);
3819 /***********************************************************************
3820 * GetTextCharset (GDI32.@)
3822 UINT WINAPI
GetTextCharset(HDC hdc
)
3824 /* MSDN docs say this is equivalent */
3825 return GetTextCharsetInfo(hdc
, NULL
, 0);
3828 /***********************************************************************
3829 * GdiGetCharDimensions (GDI32.@)
3831 * Gets the average width of the characters in the English alphabet.
3834 * hdc [I] Handle to the device context to measure on.
3835 * lptm [O] Pointer to memory to store the text metrics into.
3836 * height [O] On exit, the maximum height of characters in the English alphabet.
3839 * The average width of characters in the English alphabet.
3842 * This function is used by the dialog manager to get the size of a dialog
3843 * unit. It should also be used by other pieces of code that need to know
3844 * the size of a dialog unit in logical units without having access to the
3845 * window handle of the dialog.
3846 * Windows caches the font metrics from this function, but we don't and
3847 * there doesn't appear to be an immediate advantage to do so.
3850 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
3852 LONG WINAPI
GdiGetCharDimensions(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
)
3855 static const WCHAR alphabet
[] = {
3856 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3857 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3858 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
3860 if(lptm
&& !GetTextMetricsW(hdc
, lptm
)) return 0;
3862 if(!GetTextExtentPointW(hdc
, alphabet
, 52, &sz
)) return 0;
3864 if (height
) *height
= sz
.cy
;
3865 return (sz
.cx
/ 26 + 1) / 2;
3868 BOOL WINAPI
EnableEUDC(BOOL fEnableEUDC
)
3870 FIXME("(%d): stub\n", fEnableEUDC
);
3874 /***********************************************************************
3875 * GetCharWidthI (GDI32.@)
3877 * Retrieve widths of characters.
3880 * hdc [I] Handle to a device context.
3881 * first [I] First glyph in range to query.
3882 * count [I] Number of glyph indices to query.
3883 * glyphs [I] Array of glyphs to query.
3884 * buffer [O] Buffer to receive character widths.
3887 * Only works with TrueType fonts.
3893 BOOL WINAPI
GetCharWidthI(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPINT buffer
)
3898 TRACE("(%p, %d, %d, %p, %p)\n", hdc
, first
, count
, glyphs
, buffer
);
3900 if (!(abc
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(ABC
))))
3903 if (!GetCharABCWidthsI(hdc
, first
, count
, glyphs
, abc
))
3905 HeapFree(GetProcessHeap(), 0, abc
);
3909 for (i
= 0; i
< count
; i
++)
3910 buffer
[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
3912 HeapFree(GetProcessHeap(), 0, abc
);
3916 /***********************************************************************
3917 * GetFontUnicodeRanges (GDI32.@)
3919 * Retrieve a list of supported Unicode characters in a font.
3922 * hdc [I] Handle to a device context.
3923 * lpgs [O] GLYPHSET structure specifying supported character ranges.
3926 * Success: Number of bytes written to the buffer pointed to by lpgs.
3930 DWORD WINAPI
GetFontUnicodeRanges(HDC hdc
, LPGLYPHSET lpgs
)
3934 DC
*dc
= get_dc_ptr(hdc
);
3936 TRACE("(%p, %p)\n", hdc
, lpgs
);
3940 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
3941 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
3947 /*************************************************************
3948 * FontIsLinked (GDI32.@)
3950 BOOL WINAPI
FontIsLinked(HDC hdc
)
3952 DC
*dc
= get_dc_ptr(hdc
);
3956 if (!dc
) return FALSE
;
3957 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
3958 ret
= dev
->funcs
->pFontIsLinked( dev
);
3960 TRACE("returning %d\n", ret
);
3964 /*************************************************************
3965 * GetFontRealizationInfo (GDI32.@)
3967 BOOL WINAPI
GetFontRealizationInfo(HDC hdc
, struct font_realization_info
*info
)
3969 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, unk
);
3974 if (info
->size
!= sizeof(*info
) && !is_v0
)
3977 dc
= get_dc_ptr(hdc
);
3978 if (!dc
) return FALSE
;
3979 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
3980 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
3985 struct realization_info
3987 DWORD flags
; /* 1 for bitmap fonts, 3 for scalable fonts */
3988 DWORD cache_num
; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
3989 DWORD instance_id
; /* identifies a realized font instance */
3992 /*************************************************************
3993 * GdiRealizationInfo (GDI32.@)
3995 * Returns a structure that contains some font information.
3997 BOOL WINAPI
GdiRealizationInfo(HDC hdc
, struct realization_info
*info
)
3999 struct font_realization_info ri
;
4002 ri
.size
= sizeof(ri
);
4003 ret
= GetFontRealizationInfo( hdc
, &ri
);
4006 info
->flags
= ri
.flags
;
4007 info
->cache_num
= ri
.cache_num
;
4008 info
->instance_id
= ri
.instance_id
;
4014 /*************************************************************
4015 * GetCharWidthInfo (GDI32.@)
4018 BOOL WINAPI
GetCharWidthInfo(HDC hdc
, struct char_width_info
*info
)
4024 dc
= get_dc_ptr(hdc
);
4025 if (!dc
) return FALSE
;
4026 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
4027 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
4031 info
->lsb
= width_to_LP( dc
, info
->lsb
);
4032 info
->rsb
= width_to_LP( dc
, info
->rsb
);