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 static HKEY wine_fonts_key
;
49 struct gdi_physdev dev
;
50 struct gdi_font
*font
;
53 static inline struct font_physdev
*get_font_dev( PHYSDEV dev
)
55 return (struct font_physdev
*)dev
;
58 static const struct font_backend_funcs
*font_funcs
;
60 /* Device -> World size conversion */
62 /* Performs a device to world transformation on the specified width (which
63 * is in integer format).
65 static inline INT
INTERNAL_XDSTOWS(DC
*dc
, INT width
)
69 /* Perform operation with floating point */
70 floatWidth
= (double)width
* dc
->xformVport2World
.eM11
;
71 /* Round to integers */
72 return GDI_ROUND(floatWidth
);
75 /* Performs a device to world transformation on the specified size (which
76 * is in integer format).
78 static inline INT
INTERNAL_YDSTOWS(DC
*dc
, INT height
)
82 /* Perform operation with floating point */
83 floatHeight
= (double)height
* dc
->xformVport2World
.eM22
;
84 /* Round to integers */
85 return GDI_ROUND(floatHeight
);
88 /* scale width and height but don't mirror them */
90 static inline INT
width_to_LP( DC
*dc
, INT width
)
92 return GDI_ROUND( (double)width
* fabs( dc
->xformVport2World
.eM11
));
95 static inline INT
height_to_LP( DC
*dc
, INT height
)
97 return GDI_ROUND( (double)height
* fabs( dc
->xformVport2World
.eM22
));
100 static inline INT
INTERNAL_YWSTODS(DC
*dc
, INT height
)
103 pt
[0].x
= pt
[0].y
= 0;
107 return pt
[1].y
- pt
[0].y
;
110 static inline WCHAR
*strdupW( const WCHAR
*p
)
113 DWORD len
= (strlenW(p
) + 1) * sizeof(WCHAR
);
114 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
119 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
);
120 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
);
121 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
);
122 static BOOL
FONT_DeleteObject( HGDIOBJ handle
);
124 static const struct gdi_obj_funcs fontobj_funcs
=
126 FONT_SelectObject
, /* pSelectObject */
127 FONT_GetObjectA
, /* pGetObjectA */
128 FONT_GetObjectW
, /* pGetObjectW */
129 NULL
, /* pUnrealizeObject */
130 FONT_DeleteObject
/* pDeleteObject */
140 LPLOGFONTW lpLogFontParam
;
141 FONTENUMPROCW lpEnumFunc
;
149 * For TranslateCharsetInfo
151 #define MAXTCIINDEX 32
152 static const CHARSETINFO FONT_tci
[MAXTCIINDEX
] = {
154 { ANSI_CHARSET
, 1252, {{0,0,0,0},{FS_LATIN1
,0}} },
155 { EASTEUROPE_CHARSET
, 1250, {{0,0,0,0},{FS_LATIN2
,0}} },
156 { RUSSIAN_CHARSET
, 1251, {{0,0,0,0},{FS_CYRILLIC
,0}} },
157 { GREEK_CHARSET
, 1253, {{0,0,0,0},{FS_GREEK
,0}} },
158 { TURKISH_CHARSET
, 1254, {{0,0,0,0},{FS_TURKISH
,0}} },
159 { HEBREW_CHARSET
, 1255, {{0,0,0,0},{FS_HEBREW
,0}} },
160 { ARABIC_CHARSET
, 1256, {{0,0,0,0},{FS_ARABIC
,0}} },
161 { BALTIC_CHARSET
, 1257, {{0,0,0,0},{FS_BALTIC
,0}} },
162 { VIETNAMESE_CHARSET
, 1258, {{0,0,0,0},{FS_VIETNAMESE
,0}} },
163 /* reserved by ANSI */
164 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
165 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
166 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
167 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
168 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
169 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
170 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
172 { THAI_CHARSET
, 874, {{0,0,0,0},{FS_THAI
,0}} },
173 { SHIFTJIS_CHARSET
, 932, {{0,0,0,0},{FS_JISJAPAN
,0}} },
174 { GB2312_CHARSET
, 936, {{0,0,0,0},{FS_CHINESESIMP
,0}} },
175 { HANGEUL_CHARSET
, 949, {{0,0,0,0},{FS_WANSUNG
,0}} },
176 { CHINESEBIG5_CHARSET
, 950, {{0,0,0,0},{FS_CHINESETRAD
,0}} },
177 { JOHAB_CHARSET
, 1361, {{0,0,0,0},{FS_JOHAB
,0}} },
178 /* reserved for alternate ANSI and OEM */
179 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
180 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
181 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
182 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
183 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
184 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
185 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
186 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
187 /* reserved for system */
188 { DEFAULT_CHARSET
, 0, {{0,0,0,0},{FS_LATIN1
,0}} },
189 { SYMBOL_CHARSET
, CP_SYMBOL
, {{0,0,0,0},{FS_SYMBOL
,0}} }
192 static const WCHAR win9x_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
193 'W','i','n','d','o','w','s','\\',
194 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
195 'F','o','n','t','s','\0'};
197 static const WCHAR winnt_font_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
198 'W','i','n','d','o','w','s',' ','N','T','\\',
199 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
200 'F','o','n','t','s','\0'};
202 static const WCHAR system_fonts_reg_key
[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
203 static const WCHAR system_link
[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
204 'W','i','n','d','o','w','s',' ','N','T','\\',
205 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','F','o','n','t','L','i','n','k','\\',
206 'S','y','s','t','e','m','L','i','n','k',0};
207 static const WCHAR Lucida_Sans_Unicode
[] = {'L','u','c','i','d','a',' ','S','a','n','s',' ','U','n','i','c','o','d','e',0};
208 static const WCHAR Microsoft_Sans_Serif
[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0 };
209 static const WCHAR Tahoma
[] = {'T','a','h','o','m','a',0};
211 static const struct nls_update_font_list
213 UINT ansi_cp
, oem_cp
;
214 const char *oem
, *fixed
, *system
;
215 const char *courier
, *serif
, *small
, *sserif_96
, *sserif_120
;
216 /* these are for font substitutes */
217 const char *shelldlg
, *tmsrmn
;
218 const char *fixed_0
, *system_0
, *courier_0
, *serif_0
, *small_0
, *sserif_0
, *helv_0
, *tmsrmn_0
;
219 struct subst
{ const char *from
, *to
; } arial_0
, courier_new_0
, times_new_roman_0
;
220 } nls_update_font_list
[] =
222 /* Latin 1 (United States) */
223 { 1252, 437, "vgaoem.fon", "vgafix.fon", "vgasys.fon",
224 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
225 "Tahoma","Times New Roman"
227 /* Latin 1 (Multilingual) */
228 { 1252, 850, "vga850.fon", "vgafix.fon", "vgasys.fon",
229 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
230 "Tahoma","Times New Roman" /* FIXME unverified */
233 { 1250, 852, "vga852.fon", "vgafixe.fon", "vgasyse.fon",
234 "couree.fon", "serifee.fon", "smallee.fon", "sserifee.fon", "sseriffe.fon",
235 "Tahoma","Times New Roman", /* FIXME unverified */
236 "Fixedsys,238", "System,238",
237 "Courier New,238", "MS Serif,238", "Small Fonts,238",
238 "MS Sans Serif,238", "MS Sans Serif,238", "MS Serif,238",
239 { "Arial CE,0", "Arial,238" },
240 { "Courier New CE,0", "Courier New,238" },
241 { "Times New Roman CE,0", "Times New Roman,238" }
244 { 1251, 866, "vga866.fon", "vgafixr.fon", "vgasysr.fon",
245 "courer.fon", "serifer.fon", "smaller.fon", "sserifer.fon", "sseriffr.fon",
246 "Tahoma","Times New Roman", /* FIXME unverified */
247 "Fixedsys,204", "System,204",
248 "Courier New,204", "MS Serif,204", "Small Fonts,204",
249 "MS Sans Serif,204", "MS Sans Serif,204", "MS Serif,204",
250 { "Arial Cyr,0", "Arial,204" },
251 { "Courier New Cyr,0", "Courier New,204" },
252 { "Times New Roman Cyr,0", "Times New Roman,204" }
255 { 1253, 737, "vga869.fon", "vgafixg.fon", "vgasysg.fon",
256 "coureg.fon", "serifeg.fon", "smalleg.fon", "sserifeg.fon", "sseriffg.fon",
257 "Tahoma","Times New Roman", /* FIXME unverified */
258 "Fixedsys,161", "System,161",
259 "Courier New,161", "MS Serif,161", "Small Fonts,161",
260 "MS Sans Serif,161", "MS Sans Serif,161", "MS Serif,161",
261 { "Arial Greek,0", "Arial,161" },
262 { "Courier New Greek,0", "Courier New,161" },
263 { "Times New Roman Greek,0", "Times New Roman,161" }
266 { 1254, 857, "vga857.fon", "vgafixt.fon", "vgasyst.fon",
267 "couret.fon", "serifet.fon", "smallet.fon", "sserifet.fon", "sserifft.fon",
268 "Tahoma","Times New Roman", /* FIXME unverified */
269 "Fixedsys,162", "System,162",
270 "Courier New,162", "MS Serif,162", "Small Fonts,162",
271 "MS Sans Serif,162", "MS Sans Serif,162", "MS Serif,162",
272 { "Arial Tur,0", "Arial,162" },
273 { "Courier New Tur,0", "Courier New,162" },
274 { "Times New Roman Tur,0", "Times New Roman,162" }
277 { 1255, 862, "vgaoem.fon", "vgaf1255.fon", "vgas1255.fon",
278 "coue1255.fon", "sere1255.fon", "smae1255.fon", "ssee1255.fon", "ssef1255.fon",
279 "Tahoma","Times New Roman", /* FIXME unverified */
280 "Fixedsys,177", "System,177",
281 "Courier New,177", "MS Serif,177", "Small Fonts,177",
282 "MS Sans Serif,177", "MS Sans Serif,177", "MS Serif,177"
285 { 1256, 720, "vgaoem.fon", "vgaf1256.fon", "vgas1256.fon",
286 "coue1256.fon", "sere1256.fon", "smae1256.fon", "ssee1256.fon", "ssef1256.fon",
287 "Microsoft Sans Serif","Times New Roman",
288 "Fixedsys,178", "System,178",
289 "Courier New,178", "MS Serif,178", "Small Fonts,178",
290 "MS Sans Serif,178", "MS Sans Serif,178", "MS Serif,178"
293 { 1257, 775, "vga775.fon", "vgaf1257.fon", "vgas1257.fon",
294 "coue1257.fon", "sere1257.fon", "smae1257.fon", "ssee1257.fon", "ssef1257.fon",
295 "Tahoma","Times New Roman", /* FIXME unverified */
296 "Fixedsys,186", "System,186",
297 "Courier New,186", "MS Serif,186", "Small Fonts,186",
298 "MS Sans Serif,186", "MS Sans Serif,186", "MS Serif,186",
299 { "Arial Baltic,0", "Arial,186" },
300 { "Courier New Baltic,0", "Courier New,186" },
301 { "Times New Roman Baltic,0", "Times New Roman,186" }
304 { 1258, 1258, "vga850.fon", "vgafix.fon", "vgasys.fon",
305 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
306 "Tahoma","Times New Roman" /* FIXME unverified */
309 { 874, 874, "vga850.fon", "vgaf874.fon", "vgas874.fon",
310 "coure.fon", "serife.fon", "smalle.fon", "ssee874.fon", "ssef874.fon",
311 "Tahoma","Times New Roman" /* FIXME unverified */
314 { 932, 932, "vga932.fon", "jvgafix.fon", "jvgasys.fon",
315 "coure.fon", "serife.fon", "jsmalle.fon", "sserife.fon", "sseriff.fon",
316 "MS UI Gothic","MS Serif"
318 /* Chinese Simplified */
319 { 936, 936, "vga936.fon", "svgafix.fon", "svgasys.fon",
320 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
324 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
325 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
328 /* Chinese Traditional */
329 { 950, 950, "vga950.fon", "cvgafix.fon", "cvgasys.fon",
330 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
331 "PMingLiU", "MingLiU"
335 static inline BOOL
is_dbcs_ansi_cp(UINT ansi_cp
)
337 return ( ansi_cp
== 932 /* CP932 for Japanese */
338 || ansi_cp
== 936 /* CP936 for Chinese Simplified */
339 || ansi_cp
== 949 /* CP949 for Korean */
340 || ansi_cp
== 950 ); /* CP950 for Chinese Traditional */
343 /* realized font objects */
345 #define FIRST_FONT_HANDLE 1
346 #define MAX_FONT_HANDLES 256
348 struct font_handle_entry
350 struct gdi_font
*font
;
351 WORD generation
; /* generation count for reusing handle values */
354 static struct font_handle_entry font_handles
[MAX_FONT_HANDLES
];
355 static struct font_handle_entry
*next_free
;
356 static struct font_handle_entry
*next_unused
= font_handles
;
358 static struct font_handle_entry
*handle_entry( DWORD handle
)
360 unsigned int idx
= LOWORD(handle
) - FIRST_FONT_HANDLE
;
362 if (idx
< MAX_FONT_HANDLES
)
364 if (!HIWORD( handle
) || HIWORD( handle
) == font_handles
[idx
].generation
)
365 return &font_handles
[idx
];
367 if (handle
) WARN( "invalid handle 0x%08x\n", handle
);
371 static struct gdi_font
*get_font_from_handle( DWORD handle
)
373 struct font_handle_entry
*entry
= handle_entry( handle
);
375 if (entry
) return entry
->font
;
376 SetLastError( ERROR_INVALID_PARAMETER
);
380 static DWORD
alloc_font_handle( struct gdi_font
*font
)
382 struct font_handle_entry
*entry
;
386 next_free
= (struct font_handle_entry
*)entry
->font
;
387 else if (next_unused
< font_handles
+ MAX_FONT_HANDLES
)
388 entry
= next_unused
++;
391 ERR( "out of realized font handles\n" );
395 if (++entry
->generation
== 0xffff) entry
->generation
= 1;
396 return MAKELONG( entry
- font_handles
+ FIRST_FONT_HANDLE
, entry
->generation
);
399 static void free_font_handle( DWORD handle
)
401 struct font_handle_entry
*entry
;
403 if ((entry
= handle_entry( handle
)))
405 entry
->font
= (struct gdi_font
*)next_free
;
410 struct gdi_font
*alloc_gdi_font(void)
412 struct gdi_font
*font
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*font
) );
415 font
->matrix
.eM11
= font
->matrix
.eM22
= 1.0;
418 if (!(font
->handle
= alloc_font_handle( font
)))
420 HeapFree( GetProcessHeap(), 0, font
);
423 if (font_funcs
&& !font_funcs
->alloc_font( font
))
425 free_gdi_font( font
);
431 void free_gdi_font( struct gdi_font
*font
)
433 if (font
->private) font_funcs
->destroy_font( font
);
434 free_font_handle( font
->handle
);
435 HeapFree( GetProcessHeap(), 0, font
->name
);
436 HeapFree( GetProcessHeap(), 0, font
->fileinfo
);
437 HeapFree( GetProcessHeap(), 0, font
);
440 void set_gdi_font_name( struct gdi_font
*font
, const WCHAR
*name
)
442 font
->name
= strdupW( name
);
445 /* Undocumented structure filled in by GetFontFileInfo */
453 void set_gdi_font_file_info( struct gdi_font
*font
, const WCHAR
*file
, SIZE_T data_size
)
455 WIN32_FILE_ATTRIBUTE_DATA info
;
458 if (file
) len
= strlenW( file
);
459 if (!(font
->fileinfo
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
460 offsetof( struct font_fileinfo
, path
[len
+ 1] ))))
463 if (file
&& GetFileAttributesExW( file
, GetFileExInfoStandard
, &info
))
465 font
->fileinfo
->writetime
= info
.ftLastWriteTime
;
466 font
->fileinfo
->size
.QuadPart
= (LONGLONG
)info
.nFileSizeHigh
<< 32 | info
.nFileSizeLow
;
467 strcpyW( font
->fileinfo
->path
, file
);
469 else font
->fileinfo
->size
.QuadPart
= data_size
;
474 static struct list gdi_font_list
= LIST_INIT( gdi_font_list
);
475 static struct list unused_gdi_font_list
= LIST_INIT( unused_gdi_font_list
);
476 static unsigned int unused_font_count
;
477 #define UNUSED_CACHE_SIZE 10
479 static BOOL
fontcmp( const struct gdi_font
*font
, DWORD hash
, const LOGFONTW
*lf
,
480 const FMAT2
*matrix
, BOOL can_use_bitmap
)
482 if (font
->hash
!= hash
) return TRUE
;
483 if (memcmp( &font
->matrix
, matrix
, sizeof(*matrix
))) return TRUE
;
484 if (memcmp( &font
->lf
, lf
, offsetof(LOGFONTW
, lfFaceName
))) return TRUE
;
485 if (!font
->can_use_bitmap
!= !can_use_bitmap
) return TRUE
;
486 return strcmpiW( font
->lf
.lfFaceName
, lf
->lfFaceName
);
489 static DWORD
hash_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
491 DWORD hash
= 0, *ptr
, two_chars
;
495 for (i
= 0, ptr
= (DWORD
*)matrix
; i
< sizeof(*matrix
) / sizeof(DWORD
); i
++, ptr
++)
497 for(i
= 0, ptr
= (DWORD
*)lf
; i
< 7; i
++, ptr
++)
499 for(i
= 0, ptr
= (DWORD
*)lf
->lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++)
502 pwc
= (WCHAR
*)&two_chars
;
504 *pwc
= toupperW(*pwc
);
506 *pwc
= toupperW(*pwc
);
510 hash
^= !can_use_bitmap
;
514 void cache_gdi_font( struct gdi_font
*font
)
516 static DWORD cache_num
= 1;
518 font
->cache_num
= cache_num
++;
519 font
->hash
= hash_font( &font
->lf
, &font
->matrix
, font
->can_use_bitmap
);
520 list_add_head( &gdi_font_list
, &font
->entry
);
521 TRACE( "font %p\n", font
);
524 struct gdi_font
*find_cached_gdi_font( const LOGFONTW
*lf
, const FMAT2
*matrix
, BOOL can_use_bitmap
)
526 struct gdi_font
*font
;
527 DWORD hash
= hash_font( lf
, matrix
, can_use_bitmap
);
529 /* try the in-use list */
530 LIST_FOR_EACH_ENTRY( font
, &gdi_font_list
, struct gdi_font
, entry
)
532 if (fontcmp( font
, hash
, lf
, matrix
, can_use_bitmap
)) continue;
533 list_remove( &font
->entry
);
534 list_add_head( &gdi_font_list
, &font
->entry
);
535 if (!font
->refcount
++)
537 list_remove( &font
->unused_entry
);
545 static void release_gdi_font( struct gdi_font
*font
)
548 if (--font
->refcount
) return;
550 TRACE( "font %p\n", font
);
552 /* add it to the unused list */
553 list_add_head( &unused_gdi_font_list
, &font
->unused_entry
);
554 if (unused_font_count
> UNUSED_CACHE_SIZE
)
556 font
= LIST_ENTRY( list_tail( &unused_gdi_font_list
), struct gdi_font
, unused_entry
);
557 TRACE( "freeing %p\n", font
);
558 list_remove( &font
->entry
);
559 list_remove( &font
->unused_entry
);
560 free_gdi_font( font
);
566 static void add_font_list(HKEY hkey
, const struct nls_update_font_list
*fl
, int dpi
)
568 const char *sserif
= (dpi
<= 108) ? fl
->sserif_96
: fl
->sserif_120
;
570 RegSetValueExA(hkey
, "Courier", 0, REG_SZ
, (const BYTE
*)fl
->courier
, strlen(fl
->courier
)+1);
571 RegSetValueExA(hkey
, "MS Serif", 0, REG_SZ
, (const BYTE
*)fl
->serif
, strlen(fl
->serif
)+1);
572 RegSetValueExA(hkey
, "MS Sans Serif", 0, REG_SZ
, (const BYTE
*)sserif
, strlen(sserif
)+1);
573 RegSetValueExA(hkey
, "Small Fonts", 0, REG_SZ
, (const BYTE
*)fl
->small
, strlen(fl
->small
)+1);
576 static void set_value_key(HKEY hkey
, const char *name
, const char *value
)
579 RegSetValueExA(hkey
, name
, 0, REG_SZ
, (const BYTE
*)value
, strlen(value
) + 1);
581 RegDeleteValueA(hkey
, name
);
584 static void update_font_association_info(UINT current_ansi_codepage
)
586 static const char *font_assoc_reg_key
= "System\\CurrentControlSet\\Control\\FontAssoc";
587 static const char *assoc_charset_subkey
= "Associated Charset";
589 if (is_dbcs_ansi_cp(current_ansi_codepage
))
592 if (RegCreateKeyA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
, &hkey
) == ERROR_SUCCESS
)
595 if (RegCreateKeyA(hkey
, assoc_charset_subkey
, &hsubkey
) == ERROR_SUCCESS
)
597 switch (current_ansi_codepage
)
600 set_value_key(hsubkey
, "ANSI(00)", "NO");
601 set_value_key(hsubkey
, "OEM(FF)", "NO");
602 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
607 set_value_key(hsubkey
, "ANSI(00)", "YES");
608 set_value_key(hsubkey
, "OEM(FF)", "YES");
609 set_value_key(hsubkey
, "SYMBOL(02)", "NO");
612 RegCloseKey(hsubkey
);
615 /* TODO: Associated DefaultFonts */
621 RegDeleteTreeA(HKEY_LOCAL_MACHINE
, font_assoc_reg_key
);
624 static void set_multi_value_key(HKEY hkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD len
)
627 RegSetValueExW(hkey
, name
, 0, REG_MULTI_SZ
, (const BYTE
*)value
, len
);
629 RegDeleteValueW(hkey
, name
);
632 static void update_font_system_link_info(UINT current_ansi_codepage
)
634 static const WCHAR system_link_simplified_chinese
[] =
635 {'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
636 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
637 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
638 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
640 static const WCHAR system_link_traditional_chinese
[] =
641 {'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','u','\0',
642 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
643 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
644 'B','A','T','A','N','G','.','T','T','C',',','B','a','t','a','n','g','\0',
646 static const WCHAR system_link_japanese
[] =
647 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
648 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
649 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
650 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
652 static const WCHAR system_link_korean
[] =
653 {'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
654 'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
655 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
656 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
658 static const WCHAR system_link_non_cjk
[] =
659 {'M','S','G','O','T','H','I','C','.','T','T','C',',','M','S',' ','U','I',' ','G','o','t','h','i','c','\0',
660 'M','I','N','G','L','I','U','.','T','T','C',',','P','M','i','n','g','L','i','U','\0',
661 'S','I','M','S','U','N','.','T','T','C',',','S','i','m','S','u','n','\0',
662 'G','U','L','I','M','.','T','T','C',',','G','u','l','i','m','\0',
666 if (RegCreateKeyW(HKEY_LOCAL_MACHINE
, system_link
, &hkey
) == ERROR_SUCCESS
)
671 switch (current_ansi_codepage
)
674 link
= system_link_japanese
;
675 len
= sizeof(system_link_japanese
);
678 link
= system_link_simplified_chinese
;
679 len
= sizeof(system_link_simplified_chinese
);
682 link
= system_link_korean
;
683 len
= sizeof(system_link_korean
);
686 link
= system_link_traditional_chinese
;
687 len
= sizeof(system_link_traditional_chinese
);
690 link
= system_link_non_cjk
;
691 len
= sizeof(system_link_non_cjk
);
693 set_multi_value_key(hkey
, Lucida_Sans_Unicode
, link
, len
);
694 set_multi_value_key(hkey
, Microsoft_Sans_Serif
, link
, len
);
695 set_multi_value_key(hkey
, Tahoma
, link
, len
);
700 static void update_codepage(void)
702 static const WCHAR logpixels
[] = { 'L','o','g','P','i','x','e','l','s',0 };
703 char buf
[40], cpbuf
[40];
705 DWORD len
, type
, size
;
706 UINT i
, ansi_cp
, oem_cp
;
707 DWORD screen_dpi
, font_dpi
= 0;
710 screen_dpi
= get_dpi();
711 if (!screen_dpi
) screen_dpi
= 96;
713 size
= sizeof(DWORD
);
714 if (RegQueryValueExW(wine_fonts_key
, logpixels
, NULL
, &type
, (BYTE
*)&font_dpi
, &size
) ||
715 type
!= REG_DWORD
|| size
!= sizeof(DWORD
))
720 sprintf( cpbuf
, "%u,%u", ansi_cp
, oem_cp
);
724 if (!RegQueryValueExA(wine_fonts_key
, "Codepages", 0, &type
, (BYTE
*)buf
, &len
) && type
== REG_SZ
)
726 if (!strcmp( buf
, cpbuf
) && screen_dpi
== font_dpi
) return; /* already set correctly */
727 TRACE("updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n",
728 buf
, font_dpi
, ansi_cp
, oem_cp
, screen_dpi
);
730 else TRACE("updating registry, codepages/logpixels changed none -> %u,%u/%u\n",
731 ansi_cp
, oem_cp
, screen_dpi
);
733 RegSetValueExA(wine_fonts_key
, "Codepages", 0, REG_SZ
, (const BYTE
*)cpbuf
, strlen(cpbuf
)+1);
734 RegSetValueExW(wine_fonts_key
, logpixels
, 0, REG_DWORD
, (const BYTE
*)&screen_dpi
, sizeof(screen_dpi
));
736 for (i
= 0; i
< ARRAY_SIZE(nls_update_font_list
); i
++)
738 if (nls_update_font_list
[i
].ansi_cp
== ansi_cp
&& nls_update_font_list
[i
].oem_cp
== oem_cp
)
740 if (!RegCreateKeyW( HKEY_CURRENT_CONFIG
, system_fonts_reg_key
, &hkey
))
742 RegSetValueExA(hkey
, "OEMFONT.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].oem
,
743 strlen(nls_update_font_list
[i
].oem
)+1);
744 RegSetValueExA(hkey
, "FIXEDFON.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].fixed
,
745 strlen(nls_update_font_list
[i
].fixed
)+1);
746 RegSetValueExA(hkey
, "FONTS.FON", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].system
,
747 strlen(nls_update_font_list
[i
].system
)+1);
750 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
, winnt_font_reg_key
, &hkey
))
752 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
755 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE
, win9x_font_reg_key
, &hkey
))
757 add_font_list(hkey
, &nls_update_font_list
[i
], screen_dpi
);
760 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
762 RegSetValueExA(hkey
, "MS Shell Dlg", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].shelldlg
,
763 strlen(nls_update_font_list
[i
].shelldlg
)+1);
764 RegSetValueExA(hkey
, "Tms Rmn", 0, REG_SZ
, (const BYTE
*)nls_update_font_list
[i
].tmsrmn
,
765 strlen(nls_update_font_list
[i
].tmsrmn
)+1);
767 set_value_key(hkey
, "Fixedsys,0", nls_update_font_list
[i
].fixed_0
);
768 set_value_key(hkey
, "System,0", nls_update_font_list
[i
].system_0
);
769 set_value_key(hkey
, "Courier,0", nls_update_font_list
[i
].courier_0
);
770 set_value_key(hkey
, "MS Serif,0", nls_update_font_list
[i
].serif_0
);
771 set_value_key(hkey
, "Small Fonts,0", nls_update_font_list
[i
].small_0
);
772 set_value_key(hkey
, "MS Sans Serif,0", nls_update_font_list
[i
].sserif_0
);
773 set_value_key(hkey
, "Helv,0", nls_update_font_list
[i
].helv_0
);
774 set_value_key(hkey
, "Tms Rmn,0", nls_update_font_list
[i
].tmsrmn_0
);
776 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, nls_update_font_list
[i
].arial_0
.to
);
777 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, nls_update_font_list
[i
].courier_new_0
.to
);
778 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, nls_update_font_list
[i
].times_new_roman_0
.to
);
786 /* Delete the FontSubstitutes from other locales */
787 if (!RegCreateKeyA( HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes", &hkey
))
789 set_value_key(hkey
, nls_update_font_list
[i
].arial_0
.from
, NULL
);
790 set_value_key(hkey
, nls_update_font_list
[i
].courier_new_0
.from
, NULL
);
791 set_value_key(hkey
, nls_update_font_list
[i
].times_new_roman_0
.from
, NULL
);
797 FIXME("there is no font defaults for codepages %u,%u\n", ansi_cp
, oem_cp
);
799 /* update locale dependent font association info and font system link info in registry.
800 update only when codepages changed, not logpixels. */
801 if (strcmp(buf
, cpbuf
) != 0)
803 update_font_association_info(ansi_cp
);
804 update_font_system_link_info(ansi_cp
);
809 /*************************************************************
812 static BOOL CDECL
font_CreateDC( PHYSDEV
*dev
, LPCWSTR driver
, LPCWSTR device
,
813 LPCWSTR output
, const DEVMODEW
*devmode
)
815 struct font_physdev
*physdev
;
817 if (!font_funcs
) return TRUE
;
818 if (!(physdev
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*physdev
) ))) return FALSE
;
819 push_dc_driver( dev
, &physdev
->dev
, &font_driver
);
824 /*************************************************************
827 static BOOL CDECL
font_DeleteDC( PHYSDEV dev
)
829 struct font_physdev
*physdev
= get_font_dev( dev
);
831 release_gdi_font( physdev
->font
);
832 HeapFree( GetProcessHeap(), 0, physdev
);
837 /*************************************************************
840 static BOOL CDECL
font_EnumFonts( PHYSDEV dev
, LOGFONTW
*lf
, FONTENUMPROCW proc
, LPARAM lparam
)
842 return font_funcs
->pEnumFonts( lf
, proc
, lparam
);
846 /*************************************************************
849 static BOOL CDECL
font_FontIsLinked( PHYSDEV dev
)
851 struct font_physdev
*physdev
= get_font_dev( dev
);
855 dev
= GET_NEXT_PHYSDEV( dev
, pFontIsLinked
);
856 return dev
->funcs
->pFontIsLinked( dev
);
858 return font_funcs
->pFontIsLinked( physdev
->font
);
862 /*************************************************************
863 * font_GetCharABCWidths
865 static BOOL CDECL
font_GetCharABCWidths( PHYSDEV dev
, UINT first
, UINT last
, ABC
*buffer
)
867 struct font_physdev
*physdev
= get_font_dev( dev
);
871 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidths
);
872 return dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, buffer
);
874 return font_funcs
->pGetCharABCWidths( physdev
->font
, first
, last
, buffer
);
878 /*************************************************************
879 * font_GetCharABCWidthsI
881 static BOOL CDECL
font_GetCharABCWidthsI( PHYSDEV dev
, UINT first
, UINT count
, WORD
*gi
, ABC
*buffer
)
883 struct font_physdev
*physdev
= get_font_dev( dev
);
887 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharABCWidthsI
);
888 return dev
->funcs
->pGetCharABCWidthsI( dev
, first
, count
, gi
, buffer
);
890 return font_funcs
->pGetCharABCWidthsI( physdev
->font
, first
, count
, gi
, buffer
);
894 /*************************************************************
897 static BOOL CDECL
font_GetCharWidth( PHYSDEV dev
, UINT first
, UINT last
, INT
*buffer
)
899 struct font_physdev
*physdev
= get_font_dev( dev
);
903 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidth
);
904 return dev
->funcs
->pGetCharWidth( dev
, first
, last
, buffer
);
906 return font_funcs
->pGetCharWidth( physdev
->font
, first
, last
, buffer
);
910 /*************************************************************
911 * font_GetCharWidthInfo
913 static BOOL CDECL
font_GetCharWidthInfo( PHYSDEV dev
, void *ptr
)
915 struct font_physdev
*physdev
= get_font_dev( dev
);
919 dev
= GET_NEXT_PHYSDEV( dev
, pGetCharWidthInfo
);
920 return dev
->funcs
->pGetCharWidthInfo( dev
, ptr
);
922 return font_funcs
->pGetCharWidthInfo( physdev
->font
, ptr
);
926 /*************************************************************
929 static DWORD CDECL
font_GetFontData( PHYSDEV dev
, DWORD table
, DWORD offset
, void *buf
, DWORD size
)
931 struct font_physdev
*physdev
= get_font_dev( dev
);
935 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontData
);
936 return dev
->funcs
->pGetFontData( dev
, table
, offset
, buf
, size
);
938 return font_funcs
->pGetFontData( physdev
->font
, table
, offset
, buf
, size
);
942 /*************************************************************
943 * font_GetFontRealizationInfo
945 static BOOL CDECL
font_GetFontRealizationInfo( PHYSDEV dev
, void *ptr
)
947 struct font_physdev
*physdev
= get_font_dev( dev
);
948 struct font_realization_info
*info
= ptr
;
952 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontRealizationInfo
);
953 return dev
->funcs
->pGetFontRealizationInfo( dev
, ptr
);
956 TRACE( "(%p, %p)\n", physdev
->font
, info
);
959 if (physdev
->font
->scalable
) info
->flags
|= 2;
961 info
->cache_num
= physdev
->font
->cache_num
;
962 info
->instance_id
= physdev
->font
->handle
;
963 if (info
->size
== sizeof(*info
))
966 info
->face_index
= physdev
->font
->face_index
;
967 info
->simulations
= 0;
968 if (physdev
->font
->fake_bold
) info
->simulations
|= 0x1;
969 if (physdev
->font
->fake_italic
) info
->simulations
|= 0x2;
975 /*************************************************************
976 * font_GetFontUnicodeRanges
978 static DWORD CDECL
font_GetFontUnicodeRanges( PHYSDEV dev
, GLYPHSET
*glyphset
)
980 struct font_physdev
*physdev
= get_font_dev( dev
);
984 dev
= GET_NEXT_PHYSDEV( dev
, pGetFontUnicodeRanges
);
985 return dev
->funcs
->pGetFontUnicodeRanges( dev
, glyphset
);
987 return font_funcs
->pGetFontUnicodeRanges( physdev
->font
, glyphset
);
991 /*************************************************************
992 * font_GetGlyphIndices
994 static DWORD CDECL
font_GetGlyphIndices( PHYSDEV dev
, const WCHAR
*str
, INT count
, WORD
*gi
, DWORD flags
)
996 struct font_physdev
*physdev
= get_font_dev( dev
);
1000 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphIndices
);
1001 return dev
->funcs
->pGetGlyphIndices( dev
, str
, count
, gi
, flags
);
1003 return font_funcs
->pGetGlyphIndices( physdev
->font
, str
, count
, gi
, flags
);
1007 /*************************************************************
1008 * font_GetGlyphOutline
1010 static DWORD CDECL
font_GetGlyphOutline( PHYSDEV dev
, UINT glyph
, UINT format
,
1011 GLYPHMETRICS
*gm
, DWORD buflen
, void *buf
, const MAT2
*mat
)
1013 struct font_physdev
*physdev
= get_font_dev( dev
);
1017 dev
= GET_NEXT_PHYSDEV( dev
, pGetGlyphOutline
);
1018 return dev
->funcs
->pGetGlyphOutline( dev
, glyph
, format
, gm
, buflen
, buf
, mat
);
1020 return font_funcs
->pGetGlyphOutline( physdev
->font
, glyph
, format
, gm
, buflen
, buf
, mat
);
1024 /*************************************************************
1025 * font_GetKerningPairs
1027 static DWORD CDECL
font_GetKerningPairs( PHYSDEV dev
, DWORD count
, KERNINGPAIR
*pairs
)
1029 struct font_physdev
*physdev
= get_font_dev( dev
);
1033 dev
= GET_NEXT_PHYSDEV( dev
, pGetKerningPairs
);
1034 return dev
->funcs
->pGetKerningPairs( dev
, count
, pairs
);
1036 return font_funcs
->pGetKerningPairs( physdev
->font
, count
, pairs
);
1040 /*************************************************************
1041 * font_GetOutlineTextMetrics
1043 static UINT CDECL
font_GetOutlineTextMetrics( PHYSDEV dev
, UINT size
, OUTLINETEXTMETRICW
*metrics
)
1045 struct font_physdev
*physdev
= get_font_dev( dev
);
1049 dev
= GET_NEXT_PHYSDEV( dev
, pGetOutlineTextMetrics
);
1050 return dev
->funcs
->pGetOutlineTextMetrics( dev
, size
, metrics
);
1052 return font_funcs
->pGetOutlineTextMetrics( physdev
->font
, size
, metrics
);
1056 /*************************************************************
1057 * font_GetTextCharsetInfo
1059 static UINT CDECL
font_GetTextCharsetInfo( PHYSDEV dev
, FONTSIGNATURE
*fs
, DWORD flags
)
1061 struct font_physdev
*physdev
= get_font_dev( dev
);
1065 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextCharsetInfo
);
1066 return dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
1068 if (fs
) *fs
= physdev
->font
->fs
;
1069 return physdev
->font
->charset
;
1073 /*************************************************************
1074 * font_GetTextExtentExPoint
1076 static BOOL CDECL
font_GetTextExtentExPoint( PHYSDEV dev
, const WCHAR
*str
, INT count
, INT
*dxs
)
1078 struct font_physdev
*physdev
= get_font_dev( dev
);
1082 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPoint
);
1083 return dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dxs
);
1085 return font_funcs
->pGetTextExtentExPoint( physdev
->font
, str
, count
, dxs
);
1089 /*************************************************************
1090 * font_GetTextExtentExPointI
1092 static BOOL CDECL
font_GetTextExtentExPointI( PHYSDEV dev
, const WORD
*indices
, INT count
, INT
*dxs
)
1094 struct font_physdev
*physdev
= get_font_dev( dev
);
1098 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextExtentExPointI
);
1099 return dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dxs
);
1101 return font_funcs
->pGetTextExtentExPointI( physdev
->font
, indices
, count
, dxs
);
1105 /*************************************************************
1108 static INT CDECL
font_GetTextFace( PHYSDEV dev
, INT count
, WCHAR
*str
)
1110 struct font_physdev
*physdev
= get_font_dev( dev
);
1115 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextFace
);
1116 return dev
->funcs
->pGetTextFace( dev
, count
, str
);
1118 len
= strlenW( physdev
->font
->name
) + 1;
1121 lstrcpynW( str
, physdev
->font
->name
, count
);
1122 len
= min( count
, len
);
1128 /*************************************************************
1129 * font_GetTextMetrics
1131 static BOOL CDECL
font_GetTextMetrics( PHYSDEV dev
, TEXTMETRICW
*metrics
)
1133 struct font_physdev
*physdev
= get_font_dev( dev
);
1137 dev
= GET_NEXT_PHYSDEV( dev
, pGetTextMetrics
);
1138 return dev
->funcs
->pGetTextMetrics( dev
, metrics
);
1140 return font_funcs
->pGetTextMetrics( physdev
->font
, metrics
);
1144 /*************************************************************
1147 static HFONT CDECL
font_SelectFont( PHYSDEV dev
, HFONT hfont
, UINT
*aa_flags
)
1149 UINT default_aa_flags
= *aa_flags
;
1150 struct font_physdev
*physdev
= get_font_dev( dev
);
1151 struct gdi_font
*prev
= physdev
->font
;
1152 DC
*dc
= get_physdev_dc( dev
);
1154 if (!default_aa_flags
)
1156 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
1157 next
->funcs
->pSelectFont( next
, hfont
, &default_aa_flags
);
1159 if (!hfont
) /* notification that the font has been changed by another driver */
1160 physdev
->font
= NULL
;
1162 physdev
->font
= font_funcs
->pSelectFont( dc
, hfont
, aa_flags
, default_aa_flags
);
1164 if (prev
) release_gdi_font( prev
);
1165 return physdev
->font
? hfont
: 0;
1169 const struct gdi_dc_funcs font_driver
=
1171 NULL
, /* pAbortDoc */
1172 NULL
, /* pAbortPath */
1173 NULL
, /* pAlphaBlend */
1174 NULL
, /* pAngleArc */
1177 NULL
, /* pBeginPath */
1178 NULL
, /* pBlendImage */
1180 NULL
, /* pCloseFigure */
1181 NULL
, /* pCreateCompatibleDC */
1182 font_CreateDC
, /* pCreateDC */
1183 font_DeleteDC
, /* pDeleteDC */
1184 NULL
, /* pDeleteObject */
1185 NULL
, /* pDeviceCapabilities */
1186 NULL
, /* pEllipse */
1188 NULL
, /* pEndPage */
1189 NULL
, /* pEndPath */
1190 font_EnumFonts
, /* pEnumFonts */
1191 NULL
, /* pEnumICMProfiles */
1192 NULL
, /* pExcludeClipRect */
1193 NULL
, /* pExtDeviceMode */
1194 NULL
, /* pExtEscape */
1195 NULL
, /* pExtFloodFill */
1196 NULL
, /* pExtSelectClipRgn */
1197 NULL
, /* pExtTextOut */
1198 NULL
, /* pFillPath */
1199 NULL
, /* pFillRgn */
1200 NULL
, /* pFlattenPath */
1201 font_FontIsLinked
, /* pFontIsLinked */
1202 NULL
, /* pFrameRgn */
1203 NULL
, /* pGdiComment */
1204 NULL
, /* pGetBoundsRect */
1205 font_GetCharABCWidths
, /* pGetCharABCWidths */
1206 font_GetCharABCWidthsI
, /* pGetCharABCWidthsI */
1207 font_GetCharWidth
, /* pGetCharWidth */
1208 font_GetCharWidthInfo
, /* pGetCharWidthInfo */
1209 NULL
, /* pGetDeviceCaps */
1210 NULL
, /* pGetDeviceGammaRamp */
1211 font_GetFontData
, /* pGetFontData */
1212 font_GetFontRealizationInfo
, /* pGetFontRealizationInfo */
1213 font_GetFontUnicodeRanges
, /* pGetFontUnicodeRanges */
1214 font_GetGlyphIndices
, /* pGetGlyphIndices */
1215 font_GetGlyphOutline
, /* pGetGlyphOutline */
1216 NULL
, /* pGetICMProfile */
1217 NULL
, /* pGetImage */
1218 font_GetKerningPairs
, /* pGetKerningPairs */
1219 NULL
, /* pGetNearestColor */
1220 font_GetOutlineTextMetrics
, /* pGetOutlineTextMetrics */
1221 NULL
, /* pGetPixel */
1222 NULL
, /* pGetSystemPaletteEntries */
1223 font_GetTextCharsetInfo
, /* pGetTextCharsetInfo */
1224 font_GetTextExtentExPoint
, /* pGetTextExtentExPoint */
1225 font_GetTextExtentExPointI
, /* pGetTextExtentExPointI */
1226 font_GetTextFace
, /* pGetTextFace */
1227 font_GetTextMetrics
, /* pGetTextMetrics */
1228 NULL
, /* pGradientFill */
1229 NULL
, /* pIntersectClipRect */
1230 NULL
, /* pInvertRgn */
1232 NULL
, /* pModifyWorldTransform */
1234 NULL
, /* pOffsetClipRgn */
1235 NULL
, /* pOffsetViewportOrg */
1236 NULL
, /* pOffsetWindowOrg */
1237 NULL
, /* pPaintRgn */
1240 NULL
, /* pPolyBezier */
1241 NULL
, /* pPolyBezierTo */
1242 NULL
, /* pPolyDraw */
1243 NULL
, /* pPolyPolygon */
1244 NULL
, /* pPolyPolyline */
1245 NULL
, /* pPolygon */
1246 NULL
, /* pPolyline */
1247 NULL
, /* pPolylineTo */
1248 NULL
, /* pPutImage */
1249 NULL
, /* pRealizeDefaultPalette */
1250 NULL
, /* pRealizePalette */
1251 NULL
, /* pRectangle */
1252 NULL
, /* pResetDC */
1253 NULL
, /* pRestoreDC */
1254 NULL
, /* pRoundRect */
1256 NULL
, /* pScaleViewportExt */
1257 NULL
, /* pScaleWindowExt */
1258 NULL
, /* pSelectBitmap */
1259 NULL
, /* pSelectBrush */
1260 NULL
, /* pSelectClipPath */
1261 font_SelectFont
, /* pSelectFont */
1262 NULL
, /* pSelectPalette */
1263 NULL
, /* pSelectPen */
1264 NULL
, /* pSetArcDirection */
1265 NULL
, /* pSetBkColor */
1266 NULL
, /* pSetBkMode */
1267 NULL
, /* pSetBoundsRect */
1268 NULL
, /* pSetDCBrushColor */
1269 NULL
, /* pSetDCPenColor */
1270 NULL
, /* pSetDIBitsToDevice */
1271 NULL
, /* pSetDeviceClipping */
1272 NULL
, /* pSetDeviceGammaRamp */
1273 NULL
, /* pSetLayout */
1274 NULL
, /* pSetMapMode */
1275 NULL
, /* pSetMapperFlags */
1276 NULL
, /* pSetPixel */
1277 NULL
, /* pSetPolyFillMode */
1278 NULL
, /* pSetROP2 */
1279 NULL
, /* pSetRelAbs */
1280 NULL
, /* pSetStretchBltMode */
1281 NULL
, /* pSetTextAlign */
1282 NULL
, /* pSetTextCharacterExtra */
1283 NULL
, /* pSetTextColor */
1284 NULL
, /* pSetTextJustification */
1285 NULL
, /* pSetViewportExt */
1286 NULL
, /* pSetViewportOrg */
1287 NULL
, /* pSetWindowExt */
1288 NULL
, /* pSetWindowOrg */
1289 NULL
, /* pSetWorldTransform */
1290 NULL
, /* pStartDoc */
1291 NULL
, /* pStartPage */
1292 NULL
, /* pStretchBlt */
1293 NULL
, /* pStretchDIBits */
1294 NULL
, /* pStrokeAndFillPath */
1295 NULL
, /* pStrokePath */
1296 NULL
, /* pUnrealizePalette */
1297 NULL
, /* pWidenPath */
1298 NULL
, /* pD3DKMTCheckVidPnExclusiveOwnership */
1299 NULL
, /* pD3DKMTSetVidPnSourceOwner */
1300 NULL
, /* wine_get_wgl_driver */
1301 NULL
, /* wine_get_vulkan_driver */
1302 GDI_PRIORITY_FONT_DRV
/* priority */
1305 /***********************************************************************
1308 void font_init(void)
1310 if (RegCreateKeyExA( HKEY_CURRENT_USER
, "Software\\Wine\\Fonts", 0, NULL
, 0,
1311 KEY_ALL_ACCESS
, NULL
, &wine_fonts_key
, NULL
))
1315 WineEngInit( &font_funcs
);
1319 static void FONT_LogFontAToW( const LOGFONTA
*fontA
, LPLOGFONTW fontW
)
1321 memcpy(fontW
, fontA
, sizeof(LOGFONTA
) - LF_FACESIZE
);
1322 MultiByteToWideChar(CP_ACP
, 0, fontA
->lfFaceName
, -1, fontW
->lfFaceName
,
1324 fontW
->lfFaceName
[LF_FACESIZE
-1] = 0;
1327 static void FONT_LogFontWToA( const LOGFONTW
*fontW
, LPLOGFONTA fontA
)
1329 memcpy(fontA
, fontW
, sizeof(LOGFONTA
) - LF_FACESIZE
);
1330 WideCharToMultiByte(CP_ACP
, 0, fontW
->lfFaceName
, -1, fontA
->lfFaceName
,
1331 LF_FACESIZE
, NULL
, NULL
);
1332 fontA
->lfFaceName
[LF_FACESIZE
-1] = 0;
1335 static void FONT_EnumLogFontExWToA( const ENUMLOGFONTEXW
*fontW
, LPENUMLOGFONTEXA fontA
)
1337 FONT_LogFontWToA( &fontW
->elfLogFont
, &fontA
->elfLogFont
);
1339 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfFullName
, -1,
1340 (LPSTR
) fontA
->elfFullName
, LF_FULLFACESIZE
, NULL
, NULL
);
1341 fontA
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
1342 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfStyle
, -1,
1343 (LPSTR
) fontA
->elfStyle
, LF_FACESIZE
, NULL
, NULL
);
1344 fontA
->elfStyle
[LF_FACESIZE
-1] = '\0';
1345 WideCharToMultiByte( CP_ACP
, 0, fontW
->elfScript
, -1,
1346 (LPSTR
) fontA
->elfScript
, LF_FACESIZE
, NULL
, NULL
);
1347 fontA
->elfScript
[LF_FACESIZE
-1] = '\0';
1350 static void FONT_EnumLogFontExAToW( const ENUMLOGFONTEXA
*fontA
, LPENUMLOGFONTEXW fontW
)
1352 FONT_LogFontAToW( &fontA
->elfLogFont
, &fontW
->elfLogFont
);
1354 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfFullName
, -1,
1355 fontW
->elfFullName
, LF_FULLFACESIZE
);
1356 fontW
->elfFullName
[LF_FULLFACESIZE
-1] = '\0';
1357 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfStyle
, -1,
1358 fontW
->elfStyle
, LF_FACESIZE
);
1359 fontW
->elfStyle
[LF_FACESIZE
-1] = '\0';
1360 MultiByteToWideChar( CP_ACP
, 0, (LPCSTR
)fontA
->elfScript
, -1,
1361 fontW
->elfScript
, LF_FACESIZE
);
1362 fontW
->elfScript
[LF_FACESIZE
-1] = '\0';
1365 /***********************************************************************
1366 * TEXTMETRIC conversion functions.
1368 static void FONT_TextMetricWToA(const TEXTMETRICW
*ptmW
, LPTEXTMETRICA ptmA
)
1370 ptmA
->tmHeight
= ptmW
->tmHeight
;
1371 ptmA
->tmAscent
= ptmW
->tmAscent
;
1372 ptmA
->tmDescent
= ptmW
->tmDescent
;
1373 ptmA
->tmInternalLeading
= ptmW
->tmInternalLeading
;
1374 ptmA
->tmExternalLeading
= ptmW
->tmExternalLeading
;
1375 ptmA
->tmAveCharWidth
= ptmW
->tmAveCharWidth
;
1376 ptmA
->tmMaxCharWidth
= ptmW
->tmMaxCharWidth
;
1377 ptmA
->tmWeight
= ptmW
->tmWeight
;
1378 ptmA
->tmOverhang
= ptmW
->tmOverhang
;
1379 ptmA
->tmDigitizedAspectX
= ptmW
->tmDigitizedAspectX
;
1380 ptmA
->tmDigitizedAspectY
= ptmW
->tmDigitizedAspectY
;
1381 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 255);
1382 if (ptmW
->tmCharSet
== SYMBOL_CHARSET
)
1384 ptmA
->tmFirstChar
= 0x1e;
1385 ptmA
->tmLastChar
= 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
1387 else if (ptmW
->tmPitchAndFamily
& TMPF_TRUETYPE
)
1389 ptmA
->tmFirstChar
= ptmW
->tmDefaultChar
- 1;
1390 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
1394 ptmA
->tmFirstChar
= min(ptmW
->tmFirstChar
, 0xff);
1395 ptmA
->tmLastChar
= min(ptmW
->tmLastChar
, 0xff);
1397 ptmA
->tmDefaultChar
= ptmW
->tmDefaultChar
;
1398 ptmA
->tmBreakChar
= ptmW
->tmBreakChar
;
1399 ptmA
->tmItalic
= ptmW
->tmItalic
;
1400 ptmA
->tmUnderlined
= ptmW
->tmUnderlined
;
1401 ptmA
->tmStruckOut
= ptmW
->tmStruckOut
;
1402 ptmA
->tmPitchAndFamily
= ptmW
->tmPitchAndFamily
;
1403 ptmA
->tmCharSet
= ptmW
->tmCharSet
;
1407 static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW
*ptmW
, NEWTEXTMETRICEXA
*ptmA
)
1409 FONT_TextMetricWToA((const TEXTMETRICW
*)ptmW
, (LPTEXTMETRICA
)ptmA
);
1410 ptmA
->ntmTm
.ntmFlags
= ptmW
->ntmTm
.ntmFlags
;
1411 ptmA
->ntmTm
.ntmSizeEM
= ptmW
->ntmTm
.ntmSizeEM
;
1412 ptmA
->ntmTm
.ntmCellHeight
= ptmW
->ntmTm
.ntmCellHeight
;
1413 ptmA
->ntmTm
.ntmAvgWidth
= ptmW
->ntmTm
.ntmAvgWidth
;
1414 memcpy(&ptmA
->ntmFontSig
, &ptmW
->ntmFontSig
, sizeof(FONTSIGNATURE
));
1417 static DWORD
get_key_value( HKEY key
, const WCHAR
*name
, DWORD
*value
)
1420 DWORD count
= sizeof(buf
), type
, err
;
1422 err
= RegQueryValueExW( key
, name
, NULL
, &type
, (BYTE
*)buf
, &count
);
1425 if (type
== REG_DWORD
) memcpy( value
, buf
, sizeof(*value
) );
1426 else *value
= atoiW( buf
);
1431 static UINT
get_subpixel_orientation( HKEY key
)
1433 static const WCHAR smoothing_orientation
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',
1434 'O','r','i','e','n','t','a','t','i','o','n',0};
1437 /* FIXME: handle vertical orientations even though Windows doesn't */
1438 if (get_key_value( key
, smoothing_orientation
, &orient
)) return GGO_GRAY4_BITMAP
;
1442 case 0: /* FE_FONTSMOOTHINGORIENTATIONBGR */
1443 return WINE_GGO_HBGR_BITMAP
;
1444 case 1: /* FE_FONTSMOOTHINGORIENTATIONRGB */
1445 return WINE_GGO_HRGB_BITMAP
;
1447 return GGO_GRAY4_BITMAP
;
1450 static UINT
get_default_smoothing( HKEY key
)
1452 static const WCHAR smoothing
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g',0};
1453 static const WCHAR smoothing_type
[] = {'F','o','n','t','S','m','o','o','t','h','i','n','g','T','y','p','e',0};
1454 DWORD enabled
, type
;
1456 if (get_key_value( key
, smoothing
, &enabled
)) return 0;
1457 if (!enabled
) return GGO_BITMAP
;
1459 if (!get_key_value( key
, smoothing_type
, &type
) && type
== 2 /* FE_FONTSMOOTHINGCLEARTYPE */)
1460 return get_subpixel_orientation( key
);
1462 return GGO_GRAY4_BITMAP
;
1465 /* compute positions for text rendering, in device coords */
1466 static BOOL
get_char_positions( DC
*dc
, const WCHAR
*str
, INT count
, INT
*dx
, SIZE
*size
)
1471 size
->cx
= size
->cy
= 0;
1472 if (!count
) return TRUE
;
1474 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
1475 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
1477 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPoint
);
1478 if (!dev
->funcs
->pGetTextExtentExPoint( dev
, str
, count
, dx
)) return FALSE
;
1480 if (dc
->breakExtra
|| dc
->breakRem
)
1482 int i
, space
= 0, rem
= dc
->breakRem
;
1484 for (i
= 0; i
< count
; i
++)
1486 if (str
[i
] == tm
.tmBreakChar
)
1488 space
+= dc
->breakExtra
;
1498 size
->cx
= dx
[count
- 1];
1499 size
->cy
= tm
.tmHeight
;
1503 /* compute positions for text rendering, in device coords */
1504 static BOOL
get_char_positions_indices( DC
*dc
, const WORD
*indices
, INT count
, INT
*dx
, SIZE
*size
)
1509 size
->cx
= size
->cy
= 0;
1510 if (!count
) return TRUE
;
1512 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
1513 dev
->funcs
->pGetTextMetrics( dev
, &tm
);
1515 dev
= GET_DC_PHYSDEV( dc
, pGetTextExtentExPointI
);
1516 if (!dev
->funcs
->pGetTextExtentExPointI( dev
, indices
, count
, dx
)) return FALSE
;
1518 if (dc
->breakExtra
|| dc
->breakRem
)
1521 int i
, space
= 0, rem
= dc
->breakRem
;
1523 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
1524 dev
->funcs
->pGetGlyphIndices( dev
, &tm
.tmBreakChar
, 1, &space_index
, 0 );
1526 for (i
= 0; i
< count
; i
++)
1528 if (indices
[i
] == space_index
)
1530 space
+= dc
->breakExtra
;
1540 size
->cx
= dx
[count
- 1];
1541 size
->cy
= tm
.tmHeight
;
1545 /***********************************************************************
1546 * GdiGetCodePage (GDI32.@)
1548 DWORD WINAPI
GdiGetCodePage( HDC hdc
)
1551 DC
*dc
= get_dc_ptr( hdc
);
1555 cp
= dc
->font_code_page
;
1556 release_dc_ptr( dc
);
1561 /***********************************************************************
1562 * get_text_charset_info
1564 * Internal version of GetTextCharsetInfo() that takes a DC pointer.
1566 static UINT
get_text_charset_info(DC
*dc
, FONTSIGNATURE
*fs
, DWORD flags
)
1568 UINT ret
= DEFAULT_CHARSET
;
1571 dev
= GET_DC_PHYSDEV( dc
, pGetTextCharsetInfo
);
1572 ret
= dev
->funcs
->pGetTextCharsetInfo( dev
, fs
, flags
);
1574 if (ret
== DEFAULT_CHARSET
&& fs
)
1575 memset(fs
, 0, sizeof(FONTSIGNATURE
));
1579 /***********************************************************************
1580 * GetTextCharsetInfo (GDI32.@)
1582 UINT WINAPI
GetTextCharsetInfo(HDC hdc
, FONTSIGNATURE
*fs
, DWORD flags
)
1584 UINT ret
= DEFAULT_CHARSET
;
1585 DC
*dc
= get_dc_ptr(hdc
);
1589 ret
= get_text_charset_info( dc
, fs
, flags
);
1590 release_dc_ptr( dc
);
1595 /***********************************************************************
1598 * Returns a Unicode translation of str using the charset of the
1599 * currently selected font in hdc. If count is -1 then str is assumed
1600 * to be '\0' terminated, otherwise it contains the number of bytes to
1601 * convert. If plenW is non-NULL, on return it will point to the
1602 * number of WCHARs that have been written. If pCP is non-NULL, on
1603 * return it will point to the codepage used in the conversion. The
1604 * caller should free the returned LPWSTR from the process heap
1607 static LPWSTR
FONT_mbtowc(HDC hdc
, LPCSTR str
, INT count
, INT
*plenW
, UINT
*pCP
)
1613 cp
= GdiGetCodePage( hdc
);
1615 if(count
== -1) count
= strlen(str
);
1616 lenW
= MultiByteToWideChar(cp
, 0, str
, count
, NULL
, 0);
1617 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
*sizeof(WCHAR
));
1618 MultiByteToWideChar(cp
, 0, str
, count
, strW
, lenW
);
1619 TRACE("mapped %s -> %s\n", debugstr_an(str
, count
), debugstr_wn(strW
, lenW
));
1620 if(plenW
) *plenW
= lenW
;
1625 /***********************************************************************
1626 * CreateFontIndirectExA (GDI32.@)
1628 HFONT WINAPI
CreateFontIndirectExA( const ENUMLOGFONTEXDVA
*penumexA
)
1630 ENUMLOGFONTEXDVW enumexW
;
1632 if (!penumexA
) return 0;
1634 FONT_EnumLogFontExAToW( &penumexA
->elfEnumLogfontEx
, &enumexW
.elfEnumLogfontEx
);
1635 enumexW
.elfDesignVector
= penumexA
->elfDesignVector
;
1636 return CreateFontIndirectExW( &enumexW
);
1639 /***********************************************************************
1640 * CreateFontIndirectExW (GDI32.@)
1642 HFONT WINAPI
CreateFontIndirectExW( const ENUMLOGFONTEXDVW
*penumex
)
1646 const LOGFONTW
*plf
;
1648 if (!penumex
) return 0;
1650 if (penumex
->elfEnumLogfontEx
.elfFullName
[0] ||
1651 penumex
->elfEnumLogfontEx
.elfStyle
[0] ||
1652 penumex
->elfEnumLogfontEx
.elfScript
[0])
1654 FIXME("some fields ignored. fullname=%s, style=%s, script=%s\n",
1655 debugstr_w(penumex
->elfEnumLogfontEx
.elfFullName
),
1656 debugstr_w(penumex
->elfEnumLogfontEx
.elfStyle
),
1657 debugstr_w(penumex
->elfEnumLogfontEx
.elfScript
));
1660 plf
= &penumex
->elfEnumLogfontEx
.elfLogFont
;
1661 if (!(fontPtr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*fontPtr
) ))) return 0;
1663 fontPtr
->logfont
= *plf
;
1665 if (!(hFont
= alloc_gdi_handle( fontPtr
, OBJ_FONT
, &fontobj_funcs
)))
1667 HeapFree( GetProcessHeap(), 0, fontPtr
);
1671 TRACE("(%d %d %d %d %x %d %x %d %d) %s %s %s %s => %p\n",
1672 plf
->lfHeight
, plf
->lfWidth
,
1673 plf
->lfEscapement
, plf
->lfOrientation
,
1674 plf
->lfPitchAndFamily
,
1675 plf
->lfOutPrecision
, plf
->lfClipPrecision
,
1676 plf
->lfQuality
, plf
->lfCharSet
,
1677 debugstr_w(plf
->lfFaceName
),
1678 plf
->lfWeight
> 400 ? "Bold" : "",
1679 plf
->lfItalic
? "Italic" : "",
1680 plf
->lfUnderline
? "Underline" : "", hFont
);
1685 /***********************************************************************
1686 * CreateFontIndirectA (GDI32.@)
1688 HFONT WINAPI
CreateFontIndirectA( const LOGFONTA
*plfA
)
1692 if (!plfA
) return 0;
1694 FONT_LogFontAToW( plfA
, &lfW
);
1695 return CreateFontIndirectW( &lfW
);
1698 /***********************************************************************
1699 * CreateFontIndirectW (GDI32.@)
1701 HFONT WINAPI
CreateFontIndirectW( const LOGFONTW
*plf
)
1703 ENUMLOGFONTEXDVW exdv
;
1707 exdv
.elfEnumLogfontEx
.elfLogFont
= *plf
;
1708 exdv
.elfEnumLogfontEx
.elfFullName
[0] = 0;
1709 exdv
.elfEnumLogfontEx
.elfStyle
[0] = 0;
1710 exdv
.elfEnumLogfontEx
.elfScript
[0] = 0;
1711 return CreateFontIndirectExW( &exdv
);
1714 /*************************************************************************
1715 * CreateFontA (GDI32.@)
1717 HFONT WINAPI
CreateFontA( INT height
, INT width
, INT esc
,
1718 INT orient
, INT weight
, DWORD italic
,
1719 DWORD underline
, DWORD strikeout
, DWORD charset
,
1720 DWORD outpres
, DWORD clippres
, DWORD quality
,
1721 DWORD pitch
, LPCSTR name
)
1725 logfont
.lfHeight
= height
;
1726 logfont
.lfWidth
= width
;
1727 logfont
.lfEscapement
= esc
;
1728 logfont
.lfOrientation
= orient
;
1729 logfont
.lfWeight
= weight
;
1730 logfont
.lfItalic
= italic
;
1731 logfont
.lfUnderline
= underline
;
1732 logfont
.lfStrikeOut
= strikeout
;
1733 logfont
.lfCharSet
= charset
;
1734 logfont
.lfOutPrecision
= outpres
;
1735 logfont
.lfClipPrecision
= clippres
;
1736 logfont
.lfQuality
= quality
;
1737 logfont
.lfPitchAndFamily
= pitch
;
1740 lstrcpynA(logfont
.lfFaceName
,name
,sizeof(logfont
.lfFaceName
));
1742 logfont
.lfFaceName
[0] = '\0';
1744 return CreateFontIndirectA( &logfont
);
1747 /*************************************************************************
1748 * CreateFontW (GDI32.@)
1750 HFONT WINAPI
CreateFontW( INT height
, INT width
, INT esc
,
1751 INT orient
, INT weight
, DWORD italic
,
1752 DWORD underline
, DWORD strikeout
, DWORD charset
,
1753 DWORD outpres
, DWORD clippres
, DWORD quality
,
1754 DWORD pitch
, LPCWSTR name
)
1758 logfont
.lfHeight
= height
;
1759 logfont
.lfWidth
= width
;
1760 logfont
.lfEscapement
= esc
;
1761 logfont
.lfOrientation
= orient
;
1762 logfont
.lfWeight
= weight
;
1763 logfont
.lfItalic
= italic
;
1764 logfont
.lfUnderline
= underline
;
1765 logfont
.lfStrikeOut
= strikeout
;
1766 logfont
.lfCharSet
= charset
;
1767 logfont
.lfOutPrecision
= outpres
;
1768 logfont
.lfClipPrecision
= clippres
;
1769 logfont
.lfQuality
= quality
;
1770 logfont
.lfPitchAndFamily
= pitch
;
1773 lstrcpynW(logfont
.lfFaceName
, name
, ARRAY_SIZE(logfont
.lfFaceName
));
1775 logfont
.lfFaceName
[0] = '\0';
1777 return CreateFontIndirectW( &logfont
);
1780 #define ASSOC_CHARSET_OEM 1
1781 #define ASSOC_CHARSET_ANSI 2
1782 #define ASSOC_CHARSET_SYMBOL 4
1784 static DWORD
get_associated_charset_info(void)
1786 static DWORD associated_charset
= -1;
1788 if (associated_charset
== -1)
1790 static const WCHAR assoc_charset_reg_keyW
[] = {'S','y','s','t','e','m','\\',
1791 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1792 'C','o','n','t','r','o','l','\\','F','o','n','t','A','s','s','o','c','\\',
1793 'A','s','s','o','c','i','a','t','e','d',' ','C','h','a','r','s','e','t','\0'};
1794 static const WCHAR ansiW
[] = {'A','N','S','I','(','0','0',')','\0'};
1795 static const WCHAR oemW
[] = {'O','E','M','(','F','F',')','\0'};
1796 static const WCHAR symbolW
[] = {'S','Y','M','B','O','L','(','0','2',')','\0'};
1797 static const WCHAR yesW
[] = {'Y','E','S','\0'};
1800 DWORD type
, data_len
;
1802 associated_charset
= 0;
1804 if (RegOpenKeyW(HKEY_LOCAL_MACHINE
,
1805 assoc_charset_reg_keyW
, &hkey
) != ERROR_SUCCESS
)
1808 data_len
= sizeof(dataW
);
1809 if (!RegQueryValueExW(hkey
, ansiW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
1810 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
1811 associated_charset
|= ASSOC_CHARSET_ANSI
;
1813 data_len
= sizeof(dataW
);
1814 if (!RegQueryValueExW(hkey
, oemW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
1815 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
1816 associated_charset
|= ASSOC_CHARSET_OEM
;
1818 data_len
= sizeof(dataW
);
1819 if (!RegQueryValueExW(hkey
, symbolW
, NULL
, &type
, (LPBYTE
)dataW
, &data_len
) &&
1820 type
== REG_SZ
&& !strcmpiW(dataW
, yesW
))
1821 associated_charset
|= ASSOC_CHARSET_SYMBOL
;
1825 TRACE("associated_charset = %d\n", associated_charset
);
1828 return associated_charset
;
1831 static void update_font_code_page( DC
*dc
, HANDLE font
)
1834 int charset
= get_text_charset_info( dc
, NULL
, 0 );
1836 if (charset
== ANSI_CHARSET
&& get_associated_charset_info() & ASSOC_CHARSET_ANSI
)
1840 GetObjectW( font
, sizeof(lf
), &lf
);
1841 if (!(lf
.lfClipPrecision
& CLIP_DFA_DISABLE
))
1842 charset
= DEFAULT_CHARSET
;
1845 /* Hmm, nicely designed api this one! */
1846 if (TranslateCharsetInfo( ULongToPtr(charset
), &csi
, TCI_SRCCHARSET
) )
1847 dc
->font_code_page
= csi
.ciACP
;
1851 dc
->font_code_page
= GetOEMCP();
1853 case DEFAULT_CHARSET
:
1854 dc
->font_code_page
= GetACP();
1857 case VISCII_CHARSET
:
1863 case CELTIC_CHARSET
:
1864 /* FIXME: These have no place here, but because x11drv
1865 enumerates fonts with these (made up) charsets some apps
1866 might use them and then the FIXME below would become
1867 annoying. Now we could pick the intended codepage for
1868 each of these, but since it's broken anyway we'll just
1869 use CP_ACP and hope it'll go away...
1871 dc
->font_code_page
= CP_ACP
;
1875 FIXME("Can't find codepage for charset %d\n", charset
);
1876 dc
->font_code_page
= CP_ACP
;
1881 TRACE("charset %d => cp %d\n", charset
, dc
->font_code_page
);
1884 static BOOL WINAPI
fill_font_gamma_ramp( INIT_ONCE
*once
, void *param
, void **context
)
1886 static const WCHAR desktopW
[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
1887 'D','e','s','k','t','o','p',0 };
1888 static const WCHAR smoothing_gamma
[] = { 'F','o','n','t','S','m','o','o','t','h','i','n','g',
1889 'G','a','m','m','a',0 };
1890 struct font_gamma_ramp
*ramp
= param
;
1891 const DWORD gamma_default
= 1400;
1895 gamma
= gamma_default
;
1896 if (RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
) == ERROR_SUCCESS
)
1898 if (get_key_value( key
, smoothing_gamma
, &gamma
) || gamma
== 0)
1899 gamma
= gamma_default
;
1902 gamma
= min( max( gamma
, 1000 ), 2200 );
1905 /* Calibrating the difference between the registry value and the Wine gamma value.
1906 This looks roughly similar to Windows Native with the same registry value.
1907 MS GDI seems to be rasterizing the outline at a different rate than FreeType. */
1908 gamma
= 1000 * gamma
/ 1400;
1910 for (i
= 0; i
< 256; i
++)
1912 ramp
->encode
[i
] = pow( i
/ 255., 1000. / gamma
) * 255. + .5;
1913 ramp
->decode
[i
] = pow( i
/ 255., gamma
/ 1000. ) * 255. + .5;
1916 ramp
->gamma
= gamma
;
1917 TRACE("gamma %d\n", ramp
->gamma
);
1922 static struct font_gamma_ramp
*get_font_gamma_ramp( void )
1924 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
1925 static struct font_gamma_ramp ramp
;
1927 InitOnceExecuteOnce( &init_once
, fill_font_gamma_ramp
, &ramp
, NULL
);
1931 /***********************************************************************
1934 static HGDIOBJ
FONT_SelectObject( HGDIOBJ handle
, HDC hdc
)
1937 DC
*dc
= get_dc_ptr( hdc
);
1943 if (!GDI_inc_ref_count( handle
))
1945 release_dc_ptr( dc
);
1949 physdev
= GET_DC_PHYSDEV( dc
, pSelectFont
);
1950 if (physdev
->funcs
->pSelectFont( physdev
, handle
, &aa_flags
))
1954 dc
->aa_flags
= aa_flags
? aa_flags
: GGO_BITMAP
;
1955 update_font_code_page( dc
, handle
);
1956 if (dc
->font_gamma_ramp
== NULL
)
1957 dc
->font_gamma_ramp
= get_font_gamma_ramp();
1958 GDI_dec_ref_count( ret
);
1960 else GDI_dec_ref_count( handle
);
1962 release_dc_ptr( dc
);
1967 /***********************************************************************
1970 static INT
FONT_GetObjectA( HGDIOBJ handle
, INT count
, LPVOID buffer
)
1972 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
1975 if (!font
) return 0;
1978 FONT_LogFontWToA( &font
->logfont
, &lfA
);
1979 if (count
> sizeof(lfA
)) count
= sizeof(lfA
);
1980 memcpy( buffer
, &lfA
, count
);
1982 else count
= sizeof(lfA
);
1983 GDI_ReleaseObj( handle
);
1987 /***********************************************************************
1990 static INT
FONT_GetObjectW( HGDIOBJ handle
, INT count
, LPVOID buffer
)
1992 FONTOBJ
*font
= GDI_GetObjPtr( handle
, OBJ_FONT
);
1994 if (!font
) return 0;
1997 if (count
> sizeof(LOGFONTW
)) count
= sizeof(LOGFONTW
);
1998 memcpy( buffer
, &font
->logfont
, count
);
2000 else count
= sizeof(LOGFONTW
);
2001 GDI_ReleaseObj( handle
);
2006 /***********************************************************************
2009 static BOOL
FONT_DeleteObject( HGDIOBJ handle
)
2013 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
2014 HeapFree( GetProcessHeap(), 0, obj
);
2019 /***********************************************************************
2020 * nulldrv_SelectFont
2022 HFONT CDECL
nulldrv_SelectFont( PHYSDEV dev
, HFONT font
, UINT
*aa_flags
)
2024 static const WCHAR desktopW
[] = { 'C','o','n','t','r','o','l',' ','P','a','n','e','l','\\',
2025 'D','e','s','k','t','o','p',0 };
2026 static int orientation
= -1, smoothing
= -1;
2030 if (*aa_flags
) return 0;
2032 GetObjectW( font
, sizeof(lf
), &lf
);
2033 switch (lf
.lfQuality
)
2035 case NONANTIALIASED_QUALITY
:
2036 *aa_flags
= GGO_BITMAP
;
2038 case ANTIALIASED_QUALITY
:
2039 *aa_flags
= GGO_GRAY4_BITMAP
;
2041 case CLEARTYPE_QUALITY
:
2042 case CLEARTYPE_NATURAL_QUALITY
:
2043 if (orientation
== -1)
2045 if (RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
)) break;
2046 orientation
= get_subpixel_orientation( key
);
2049 *aa_flags
= orientation
;
2052 if (smoothing
== -1)
2054 if (RegOpenKeyW( HKEY_CURRENT_USER
, desktopW
, &key
)) break;
2055 smoothing
= get_default_smoothing( key
);
2058 *aa_flags
= smoothing
;
2065 /***********************************************************************
2068 * Note: plf is really an ENUMLOGFONTEXW, and ptm is a NEWTEXTMETRICEXW.
2069 * We have to use other types because of the FONTENUMPROCW definition.
2071 static INT CALLBACK
FONT_EnumInstance( const LOGFONTW
*plf
, const TEXTMETRICW
*ptm
,
2072 DWORD fType
, LPARAM lp
)
2074 struct font_enum
*pfe
= (struct font_enum
*)lp
;
2077 /* lfCharSet is at the same offset in both LOGFONTA and LOGFONTW */
2078 if ((!pfe
->lpLogFontParam
||
2079 pfe
->lpLogFontParam
->lfCharSet
== DEFAULT_CHARSET
||
2080 pfe
->lpLogFontParam
->lfCharSet
== plf
->lfCharSet
) &&
2081 (!(fType
& RASTER_FONTTYPE
) || GetDeviceCaps(pfe
->hdc
, TEXTCAPS
) & TC_RA_ABLE
) )
2083 /* convert font metrics */
2084 ENUMLOGFONTEXA logfont
;
2085 NEWTEXTMETRICEXA tmA
;
2089 FONT_EnumLogFontExWToA( (const ENUMLOGFONTEXW
*)plf
, &logfont
);
2090 FONT_NewTextMetricExWToA( (const NEWTEXTMETRICEXW
*)ptm
, &tmA
);
2091 plf
= (LOGFONTW
*)&logfont
.elfLogFont
;
2092 ptm
= (TEXTMETRICW
*)&tmA
;
2094 ret
= pfe
->lpEnumFunc( plf
, ptm
, fType
, pfe
->lpData
);
2100 /***********************************************************************
2101 * FONT_EnumFontFamiliesEx
2103 static INT
FONT_EnumFontFamiliesEx( HDC hDC
, LPLOGFONTW plf
, FONTENUMPROCW efproc
,
2104 LPARAM lParam
, BOOL unicode
)
2107 DC
*dc
= get_dc_ptr( hDC
);
2108 struct font_enum fe
;
2112 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pEnumFonts
);
2114 if (plf
) TRACE("lfFaceName = %s lfCharset = %d\n", debugstr_w(plf
->lfFaceName
), plf
->lfCharSet
);
2115 fe
.lpLogFontParam
= plf
;
2116 fe
.lpEnumFunc
= efproc
;
2118 fe
.unicode
= unicode
;
2121 ret
= physdev
->funcs
->pEnumFonts( physdev
, plf
, FONT_EnumInstance
, (LPARAM
)&fe
);
2122 release_dc_ptr( dc
);
2124 return ret
? fe
.retval
: 0;
2127 /***********************************************************************
2128 * EnumFontFamiliesExW (GDI32.@)
2130 INT WINAPI
EnumFontFamiliesExW( HDC hDC
, LPLOGFONTW plf
,
2131 FONTENUMPROCW efproc
,
2132 LPARAM lParam
, DWORD dwFlags
)
2134 return FONT_EnumFontFamiliesEx( hDC
, plf
, efproc
, lParam
, TRUE
);
2137 /***********************************************************************
2138 * EnumFontFamiliesExA (GDI32.@)
2140 INT WINAPI
EnumFontFamiliesExA( HDC hDC
, LPLOGFONTA plf
,
2141 FONTENUMPROCA efproc
,
2142 LPARAM lParam
, DWORD dwFlags
)
2144 LOGFONTW lfW
, *plfW
;
2148 FONT_LogFontAToW( plf
, &lfW
);
2153 return FONT_EnumFontFamiliesEx( hDC
, plfW
, (FONTENUMPROCW
)efproc
, lParam
, FALSE
);
2156 /***********************************************************************
2157 * EnumFontFamiliesA (GDI32.@)
2159 INT WINAPI
EnumFontFamiliesA( HDC hDC
, LPCSTR lpFamily
,
2160 FONTENUMPROCA efproc
, LPARAM lpData
)
2166 if (!*lpFamily
) return 1;
2167 lstrcpynA( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
2168 lf
.lfCharSet
= DEFAULT_CHARSET
;
2169 lf
.lfPitchAndFamily
= 0;
2174 return EnumFontFamiliesExA( hDC
, plf
, efproc
, lpData
, 0 );
2177 /***********************************************************************
2178 * EnumFontFamiliesW (GDI32.@)
2180 INT WINAPI
EnumFontFamiliesW( HDC hDC
, LPCWSTR lpFamily
,
2181 FONTENUMPROCW efproc
, LPARAM lpData
)
2187 if (!*lpFamily
) return 1;
2188 lstrcpynW( lf
.lfFaceName
, lpFamily
, LF_FACESIZE
);
2189 lf
.lfCharSet
= DEFAULT_CHARSET
;
2190 lf
.lfPitchAndFamily
= 0;
2195 return EnumFontFamiliesExW( hDC
, plf
, efproc
, lpData
, 0 );
2198 /***********************************************************************
2199 * EnumFontsA (GDI32.@)
2201 INT WINAPI
EnumFontsA( HDC hDC
, LPCSTR lpName
, FONTENUMPROCA efproc
,
2204 return EnumFontFamiliesA( hDC
, lpName
, efproc
, lpData
);
2207 /***********************************************************************
2208 * EnumFontsW (GDI32.@)
2210 INT WINAPI
EnumFontsW( HDC hDC
, LPCWSTR lpName
, FONTENUMPROCW efproc
,
2213 return EnumFontFamiliesW( hDC
, lpName
, efproc
, lpData
);
2217 /***********************************************************************
2218 * GetTextCharacterExtra (GDI32.@)
2220 INT WINAPI
GetTextCharacterExtra( HDC hdc
)
2223 DC
*dc
= get_dc_ptr( hdc
);
2224 if (!dc
) return 0x80000000;
2225 ret
= dc
->charExtra
;
2226 release_dc_ptr( dc
);
2231 /***********************************************************************
2232 * SetTextCharacterExtra (GDI32.@)
2234 INT WINAPI
SetTextCharacterExtra( HDC hdc
, INT extra
)
2236 INT ret
= 0x80000000;
2237 DC
* dc
= get_dc_ptr( hdc
);
2241 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetTextCharacterExtra
);
2242 extra
= physdev
->funcs
->pSetTextCharacterExtra( physdev
, extra
);
2243 if (extra
!= 0x80000000)
2245 ret
= dc
->charExtra
;
2246 dc
->charExtra
= extra
;
2248 release_dc_ptr( dc
);
2254 /***********************************************************************
2255 * SetTextJustification (GDI32.@)
2257 BOOL WINAPI
SetTextJustification( HDC hdc
, INT extra
, INT breaks
)
2261 DC
* dc
= get_dc_ptr( hdc
);
2263 if (!dc
) return FALSE
;
2265 physdev
= GET_DC_PHYSDEV( dc
, pSetTextJustification
);
2266 ret
= physdev
->funcs
->pSetTextJustification( physdev
, extra
, breaks
);
2269 extra
= abs((extra
* dc
->vport_ext
.cx
+ dc
->wnd_ext
.cx
/ 2) / dc
->wnd_ext
.cx
);
2270 if (!extra
) breaks
= 0;
2273 dc
->breakExtra
= extra
/ breaks
;
2274 dc
->breakRem
= extra
- (breaks
* dc
->breakExtra
);
2282 release_dc_ptr( dc
);
2287 /***********************************************************************
2288 * GetTextFaceA (GDI32.@)
2290 INT WINAPI
GetTextFaceA( HDC hdc
, INT count
, LPSTR name
)
2292 INT res
= GetTextFaceW(hdc
, 0, NULL
);
2293 LPWSTR nameW
= HeapAlloc( GetProcessHeap(), 0, res
* 2 );
2294 GetTextFaceW( hdc
, res
, nameW
);
2300 res
= WideCharToMultiByte(CP_ACP
, 0, nameW
, -1, name
, count
, NULL
, NULL
);
2304 /* GetTextFaceA does NOT include the nul byte in the return count. */
2311 res
= WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, NULL
, 0, NULL
, NULL
);
2312 HeapFree( GetProcessHeap(), 0, nameW
);
2316 /***********************************************************************
2317 * GetTextFaceW (GDI32.@)
2319 INT WINAPI
GetTextFaceW( HDC hdc
, INT count
, LPWSTR name
)
2324 DC
* dc
= get_dc_ptr( hdc
);
2327 dev
= GET_DC_PHYSDEV( dc
, pGetTextFace
);
2328 ret
= dev
->funcs
->pGetTextFace( dev
, count
, name
);
2329 release_dc_ptr( dc
);
2334 /***********************************************************************
2335 * GetTextExtentPoint32A (GDI32.@)
2337 * See GetTextExtentPoint32W.
2339 BOOL WINAPI
GetTextExtentPoint32A( HDC hdc
, LPCSTR str
, INT count
,
2346 if (count
< 0) return FALSE
;
2348 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
2352 ret
= GetTextExtentPoint32W( hdc
, p
, wlen
, size
);
2353 HeapFree( GetProcessHeap(), 0, p
);
2356 TRACE("(%p %s %d %p): returning %d x %d\n",
2357 hdc
, debugstr_an (str
, count
), count
, size
, size
->cx
, size
->cy
);
2362 /***********************************************************************
2363 * GetTextExtentPoint32W [GDI32.@]
2365 * Computes width/height for a string.
2367 * Computes width and height of the specified string.
2373 BOOL WINAPI
GetTextExtentPoint32W(
2374 HDC hdc
, /* [in] Handle of device context */
2375 LPCWSTR str
, /* [in] Address of text string */
2376 INT count
, /* [in] Number of characters in string */
2377 LPSIZE size
) /* [out] Address of structure for string size */
2379 return GetTextExtentExPointW(hdc
, str
, count
, 0, NULL
, NULL
, size
);
2382 /***********************************************************************
2383 * GetTextExtentExPointI [GDI32.@]
2385 * Computes width and height of the array of glyph indices.
2388 * hdc [I] Handle of device context.
2389 * indices [I] Glyph index array.
2390 * count [I] Number of glyphs in array.
2391 * max_ext [I] Maximum width in glyphs.
2392 * nfit [O] Maximum number of characters.
2393 * dxs [O] Partial string widths.
2394 * size [O] Returned string size.
2400 BOOL WINAPI
GetTextExtentExPointI( HDC hdc
, const WORD
*indices
, INT count
, INT max_ext
,
2401 LPINT nfit
, LPINT dxs
, LPSIZE size
)
2406 INT buffer
[256], *pos
= dxs
;
2408 if (count
< 0) return FALSE
;
2410 dc
= get_dc_ptr( hdc
);
2411 if (!dc
) return FALSE
;
2416 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
2418 release_dc_ptr( dc
);
2423 ret
= get_char_positions_indices( dc
, indices
, count
, pos
, size
);
2428 for (i
= 0; i
< count
; i
++)
2430 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
2431 if (nfit
&& dx
> (unsigned int)max_ext
) break;
2432 if (dxs
) dxs
[i
] = dx
;
2434 if (nfit
) *nfit
= i
;
2437 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
2438 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
2441 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
2442 release_dc_ptr( dc
);
2444 TRACE("(%p %p %d %p): returning %d x %d\n",
2445 hdc
, indices
, count
, size
, size
->cx
, size
->cy
);
2449 /***********************************************************************
2450 * GetTextExtentPointI [GDI32.@]
2452 * Computes width and height of the array of glyph indices.
2455 * hdc [I] Handle of device context.
2456 * indices [I] Glyph index array.
2457 * count [I] Number of glyphs in array.
2458 * size [O] Returned string size.
2464 BOOL WINAPI
GetTextExtentPointI( HDC hdc
, const WORD
*indices
, INT count
, LPSIZE size
)
2466 return GetTextExtentExPointI( hdc
, indices
, count
, 0, NULL
, NULL
, size
);
2470 /***********************************************************************
2471 * GetTextExtentPointA (GDI32.@)
2473 BOOL WINAPI
GetTextExtentPointA( HDC hdc
, LPCSTR str
, INT count
,
2476 TRACE("not bug compatible.\n");
2477 return GetTextExtentPoint32A( hdc
, str
, count
, size
);
2480 /***********************************************************************
2481 * GetTextExtentPointW (GDI32.@)
2483 BOOL WINAPI
GetTextExtentPointW( HDC hdc
, LPCWSTR str
, INT count
,
2486 TRACE("not bug compatible.\n");
2487 return GetTextExtentPoint32W( hdc
, str
, count
, size
);
2491 /***********************************************************************
2492 * GetTextExtentExPointA (GDI32.@)
2494 BOOL WINAPI
GetTextExtentExPointA( HDC hdc
, LPCSTR str
, INT count
,
2495 INT maxExt
, LPINT lpnFit
,
2496 LPINT alpDx
, LPSIZE size
)
2503 if (count
< 0) return FALSE
;
2504 if (maxExt
< -1) return FALSE
;
2508 walpDx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(INT
) );
2509 if (!walpDx
) return FALSE
;
2512 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, NULL
);
2513 ret
= GetTextExtentExPointW( hdc
, p
, wlen
, maxExt
, lpnFit
, walpDx
, size
);
2516 INT n
= lpnFit
? *lpnFit
: wlen
;
2518 for(i
= 0, j
= 0; i
< n
; i
++, j
++)
2520 alpDx
[j
] = walpDx
[i
];
2521 if (IsDBCSLeadByte(str
[j
])) alpDx
[++j
] = walpDx
[i
];
2524 if (lpnFit
) *lpnFit
= WideCharToMultiByte(CP_ACP
,0,p
,*lpnFit
,NULL
,0,NULL
,NULL
);
2525 HeapFree( GetProcessHeap(), 0, p
);
2526 HeapFree( GetProcessHeap(), 0, walpDx
);
2531 /***********************************************************************
2532 * GetTextExtentExPointW (GDI32.@)
2534 * Return the size of the string as it would be if it was output properly by
2537 BOOL WINAPI
GetTextExtentExPointW( HDC hdc
, LPCWSTR str
, INT count
, INT max_ext
,
2538 LPINT nfit
, LPINT dxs
, LPSIZE size
)
2543 INT buffer
[256], *pos
= dxs
;
2545 if (count
< 0) return FALSE
;
2547 dc
= get_dc_ptr(hdc
);
2548 if (!dc
) return FALSE
;
2553 if (count
> 256 && !(pos
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*pos
) )))
2555 release_dc_ptr( dc
);
2560 ret
= get_char_positions( dc
, str
, count
, pos
, size
);
2565 for (i
= 0; i
< count
; i
++)
2567 unsigned int dx
= abs( INTERNAL_XDSTOWS( dc
, pos
[i
] )) + (i
+ 1) * dc
->charExtra
;
2568 if (nfit
&& dx
> (unsigned int)max_ext
) break;
2569 if (dxs
) dxs
[i
] = dx
;
2571 if (nfit
) *nfit
= i
;
2574 size
->cx
= abs( INTERNAL_XDSTOWS( dc
, size
->cx
)) + count
* dc
->charExtra
;
2575 size
->cy
= abs( INTERNAL_YDSTOWS( dc
, size
->cy
));
2578 if (pos
!= buffer
&& pos
!= dxs
) HeapFree( GetProcessHeap(), 0, pos
);
2579 release_dc_ptr( dc
);
2581 TRACE("(%p, %s, %d) returning %dx%d\n", hdc
, debugstr_wn(str
,count
), max_ext
, size
->cx
, size
->cy
);
2585 /***********************************************************************
2586 * GetTextMetricsA (GDI32.@)
2588 BOOL WINAPI
GetTextMetricsA( HDC hdc
, TEXTMETRICA
*metrics
)
2592 if (!GetTextMetricsW( hdc
, &tm32
)) return FALSE
;
2593 FONT_TextMetricWToA( &tm32
, metrics
);
2597 /***********************************************************************
2598 * GetTextMetricsW (GDI32.@)
2600 BOOL WINAPI
GetTextMetricsW( HDC hdc
, TEXTMETRICW
*metrics
)
2604 DC
* dc
= get_dc_ptr( hdc
);
2605 if (!dc
) return FALSE
;
2607 physdev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
2608 ret
= physdev
->funcs
->pGetTextMetrics( physdev
, metrics
);
2612 /* device layer returns values in device units
2613 * therefore we have to convert them to logical */
2615 metrics
->tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2616 metrics
->tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2617 metrics
->tmHeight
= height_to_LP( dc
, metrics
->tmHeight
);
2618 metrics
->tmAscent
= height_to_LP( dc
, metrics
->tmAscent
);
2619 metrics
->tmDescent
= height_to_LP( dc
, metrics
->tmDescent
);
2620 metrics
->tmInternalLeading
= height_to_LP( dc
, metrics
->tmInternalLeading
);
2621 metrics
->tmExternalLeading
= height_to_LP( dc
, metrics
->tmExternalLeading
);
2622 metrics
->tmAveCharWidth
= width_to_LP( dc
, metrics
->tmAveCharWidth
);
2623 metrics
->tmMaxCharWidth
= width_to_LP( dc
, metrics
->tmMaxCharWidth
);
2624 metrics
->tmOverhang
= width_to_LP( dc
, metrics
->tmOverhang
);
2627 TRACE("text metrics:\n"
2628 " Weight = %03i\t FirstChar = %i\t AveCharWidth = %i\n"
2629 " Italic = % 3i\t LastChar = %i\t\t MaxCharWidth = %i\n"
2630 " UnderLined = %01i\t DefaultChar = %i\t Overhang = %i\n"
2631 " StruckOut = %01i\t BreakChar = %i\t CharSet = %i\n"
2632 " PitchAndFamily = %02x\n"
2633 " --------------------\n"
2634 " InternalLeading = %i\n"
2638 metrics
->tmWeight
, metrics
->tmFirstChar
, metrics
->tmAveCharWidth
,
2639 metrics
->tmItalic
, metrics
->tmLastChar
, metrics
->tmMaxCharWidth
,
2640 metrics
->tmUnderlined
, metrics
->tmDefaultChar
, metrics
->tmOverhang
,
2641 metrics
->tmStruckOut
, metrics
->tmBreakChar
, metrics
->tmCharSet
,
2642 metrics
->tmPitchAndFamily
,
2643 metrics
->tmInternalLeading
,
2646 metrics
->tmHeight
);
2648 release_dc_ptr( dc
);
2653 /***********************************************************************
2654 * GetOutlineTextMetricsA (GDI32.@)
2655 * Gets metrics for TrueType fonts.
2658 * If the supplied buffer isn't big enough Windows partially fills it up to
2659 * its given length and returns that length.
2662 * Success: Non-zero or size of required buffer
2665 UINT WINAPI
GetOutlineTextMetricsA(
2666 HDC hdc
, /* [in] Handle of device context */
2667 UINT cbData
, /* [in] Size of metric data array */
2668 LPOUTLINETEXTMETRICA lpOTM
) /* [out] Address of metric data array */
2670 char buf
[512], *ptr
;
2672 OUTLINETEXTMETRICW
*lpOTMW
= (OUTLINETEXTMETRICW
*)buf
;
2673 OUTLINETEXTMETRICA
*output
= lpOTM
;
2676 if((ret
= GetOutlineTextMetricsW(hdc
, 0, NULL
)) == 0)
2678 if(ret
> sizeof(buf
))
2679 lpOTMW
= HeapAlloc(GetProcessHeap(), 0, ret
);
2680 GetOutlineTextMetricsW(hdc
, ret
, lpOTMW
);
2682 needed
= sizeof(OUTLINETEXTMETRICA
);
2683 if(lpOTMW
->otmpFamilyName
)
2684 needed
+= WideCharToMultiByte(CP_ACP
, 0,
2685 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
2686 NULL
, 0, NULL
, NULL
);
2687 if(lpOTMW
->otmpFaceName
)
2688 needed
+= WideCharToMultiByte(CP_ACP
, 0,
2689 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
2690 NULL
, 0, NULL
, NULL
);
2691 if(lpOTMW
->otmpStyleName
)
2692 needed
+= WideCharToMultiByte(CP_ACP
, 0,
2693 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
2694 NULL
, 0, NULL
, NULL
);
2695 if(lpOTMW
->otmpFullName
)
2696 needed
+= WideCharToMultiByte(CP_ACP
, 0,
2697 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
2698 NULL
, 0, NULL
, NULL
);
2705 TRACE("needed = %d\n", needed
);
2707 /* Since the supplied buffer isn't big enough, we'll alloc one
2708 that is and memcpy the first cbData bytes into the lpOTM at
2710 output
= HeapAlloc(GetProcessHeap(), 0, needed
);
2712 ret
= output
->otmSize
= min(needed
, cbData
);
2713 FONT_TextMetricWToA( &lpOTMW
->otmTextMetrics
, &output
->otmTextMetrics
);
2714 output
->otmFiller
= 0;
2715 output
->otmPanoseNumber
= lpOTMW
->otmPanoseNumber
;
2716 output
->otmfsSelection
= lpOTMW
->otmfsSelection
;
2717 output
->otmfsType
= lpOTMW
->otmfsType
;
2718 output
->otmsCharSlopeRise
= lpOTMW
->otmsCharSlopeRise
;
2719 output
->otmsCharSlopeRun
= lpOTMW
->otmsCharSlopeRun
;
2720 output
->otmItalicAngle
= lpOTMW
->otmItalicAngle
;
2721 output
->otmEMSquare
= lpOTMW
->otmEMSquare
;
2722 output
->otmAscent
= lpOTMW
->otmAscent
;
2723 output
->otmDescent
= lpOTMW
->otmDescent
;
2724 output
->otmLineGap
= lpOTMW
->otmLineGap
;
2725 output
->otmsCapEmHeight
= lpOTMW
->otmsCapEmHeight
;
2726 output
->otmsXHeight
= lpOTMW
->otmsXHeight
;
2727 output
->otmrcFontBox
= lpOTMW
->otmrcFontBox
;
2728 output
->otmMacAscent
= lpOTMW
->otmMacAscent
;
2729 output
->otmMacDescent
= lpOTMW
->otmMacDescent
;
2730 output
->otmMacLineGap
= lpOTMW
->otmMacLineGap
;
2731 output
->otmusMinimumPPEM
= lpOTMW
->otmusMinimumPPEM
;
2732 output
->otmptSubscriptSize
= lpOTMW
->otmptSubscriptSize
;
2733 output
->otmptSubscriptOffset
= lpOTMW
->otmptSubscriptOffset
;
2734 output
->otmptSuperscriptSize
= lpOTMW
->otmptSuperscriptSize
;
2735 output
->otmptSuperscriptOffset
= lpOTMW
->otmptSuperscriptOffset
;
2736 output
->otmsStrikeoutSize
= lpOTMW
->otmsStrikeoutSize
;
2737 output
->otmsStrikeoutPosition
= lpOTMW
->otmsStrikeoutPosition
;
2738 output
->otmsUnderscoreSize
= lpOTMW
->otmsUnderscoreSize
;
2739 output
->otmsUnderscorePosition
= lpOTMW
->otmsUnderscorePosition
;
2742 ptr
= (char*)(output
+ 1);
2743 left
= needed
- sizeof(*output
);
2745 if(lpOTMW
->otmpFamilyName
) {
2746 output
->otmpFamilyName
= (LPSTR
)(ptr
- (char*)output
);
2747 len
= WideCharToMultiByte(CP_ACP
, 0,
2748 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFamilyName
), -1,
2749 ptr
, left
, NULL
, NULL
);
2753 output
->otmpFamilyName
= 0;
2755 if(lpOTMW
->otmpFaceName
) {
2756 output
->otmpFaceName
= (LPSTR
)(ptr
- (char*)output
);
2757 len
= WideCharToMultiByte(CP_ACP
, 0,
2758 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFaceName
), -1,
2759 ptr
, left
, NULL
, NULL
);
2763 output
->otmpFaceName
= 0;
2765 if(lpOTMW
->otmpStyleName
) {
2766 output
->otmpStyleName
= (LPSTR
)(ptr
- (char*)output
);
2767 len
= WideCharToMultiByte(CP_ACP
, 0,
2768 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpStyleName
), -1,
2769 ptr
, left
, NULL
, NULL
);
2773 output
->otmpStyleName
= 0;
2775 if(lpOTMW
->otmpFullName
) {
2776 output
->otmpFullName
= (LPSTR
)(ptr
- (char*)output
);
2777 len
= WideCharToMultiByte(CP_ACP
, 0,
2778 (WCHAR
*)((char*)lpOTMW
+ (ptrdiff_t)lpOTMW
->otmpFullName
), -1,
2779 ptr
, left
, NULL
, NULL
);
2782 output
->otmpFullName
= 0;
2786 if(output
!= lpOTM
) {
2787 memcpy(lpOTM
, output
, cbData
);
2788 HeapFree(GetProcessHeap(), 0, output
);
2790 /* check if the string offsets really fit into the provided size */
2791 /* FIXME: should we check string length as well? */
2792 /* make sure that we don't read/write beyond the provided buffer */
2793 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFamilyName
) + sizeof(LPSTR
))
2795 if ((UINT_PTR
)lpOTM
->otmpFamilyName
>= lpOTM
->otmSize
)
2796 lpOTM
->otmpFamilyName
= 0; /* doesn't fit */
2799 /* make sure that we don't read/write beyond the provided buffer */
2800 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFaceName
) + sizeof(LPSTR
))
2802 if ((UINT_PTR
)lpOTM
->otmpFaceName
>= lpOTM
->otmSize
)
2803 lpOTM
->otmpFaceName
= 0; /* doesn't fit */
2806 /* make sure that we don't read/write beyond the provided buffer */
2807 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpStyleName
) + sizeof(LPSTR
))
2809 if ((UINT_PTR
)lpOTM
->otmpStyleName
>= lpOTM
->otmSize
)
2810 lpOTM
->otmpStyleName
= 0; /* doesn't fit */
2813 /* make sure that we don't read/write beyond the provided buffer */
2814 if (lpOTM
->otmSize
>= FIELD_OFFSET(OUTLINETEXTMETRICA
, otmpFullName
) + sizeof(LPSTR
))
2816 if ((UINT_PTR
)lpOTM
->otmpFullName
>= lpOTM
->otmSize
)
2817 lpOTM
->otmpFullName
= 0; /* doesn't fit */
2822 if(lpOTMW
!= (OUTLINETEXTMETRICW
*)buf
)
2823 HeapFree(GetProcessHeap(), 0, lpOTMW
);
2829 /***********************************************************************
2830 * GetOutlineTextMetricsW [GDI32.@]
2832 UINT WINAPI
GetOutlineTextMetricsW(
2833 HDC hdc
, /* [in] Handle of device context */
2834 UINT cbData
, /* [in] Size of metric data array */
2835 LPOUTLINETEXTMETRICW lpOTM
) /* [out] Address of metric data array */
2837 DC
*dc
= get_dc_ptr( hdc
);
2838 OUTLINETEXTMETRICW
*output
= lpOTM
;
2842 TRACE("(%p,%d,%p)\n", hdc
, cbData
, lpOTM
);
2845 dev
= GET_DC_PHYSDEV( dc
, pGetOutlineTextMetrics
);
2846 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, cbData
, output
);
2848 if (lpOTM
&& ret
> cbData
)
2850 output
= HeapAlloc(GetProcessHeap(), 0, ret
);
2851 ret
= dev
->funcs
->pGetOutlineTextMetrics( dev
, ret
, output
);
2856 output
->otmTextMetrics
.tmDigitizedAspectX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
2857 output
->otmTextMetrics
.tmDigitizedAspectY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
2858 output
->otmTextMetrics
.tmHeight
= height_to_LP( dc
, output
->otmTextMetrics
.tmHeight
);
2859 output
->otmTextMetrics
.tmAscent
= height_to_LP( dc
, output
->otmTextMetrics
.tmAscent
);
2860 output
->otmTextMetrics
.tmDescent
= height_to_LP( dc
, output
->otmTextMetrics
.tmDescent
);
2861 output
->otmTextMetrics
.tmInternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmInternalLeading
);
2862 output
->otmTextMetrics
.tmExternalLeading
= height_to_LP( dc
, output
->otmTextMetrics
.tmExternalLeading
);
2863 output
->otmTextMetrics
.tmAveCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmAveCharWidth
);
2864 output
->otmTextMetrics
.tmMaxCharWidth
= width_to_LP( dc
, output
->otmTextMetrics
.tmMaxCharWidth
);
2865 output
->otmTextMetrics
.tmOverhang
= width_to_LP( dc
, output
->otmTextMetrics
.tmOverhang
);
2866 output
->otmAscent
= height_to_LP( dc
, output
->otmAscent
);
2867 output
->otmDescent
= height_to_LP( dc
, output
->otmDescent
);
2868 output
->otmLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmLineGap
);
2869 output
->otmsCapEmHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsCapEmHeight
);
2870 output
->otmsXHeight
= INTERNAL_YDSTOWS(dc
, output
->otmsXHeight
);
2871 output
->otmrcFontBox
.top
= height_to_LP( dc
, output
->otmrcFontBox
.top
);
2872 output
->otmrcFontBox
.bottom
= height_to_LP( dc
, output
->otmrcFontBox
.bottom
);
2873 output
->otmrcFontBox
.left
= width_to_LP( dc
, output
->otmrcFontBox
.left
);
2874 output
->otmrcFontBox
.right
= width_to_LP( dc
, output
->otmrcFontBox
.right
);
2875 output
->otmMacAscent
= height_to_LP( dc
, output
->otmMacAscent
);
2876 output
->otmMacDescent
= height_to_LP( dc
, output
->otmMacDescent
);
2877 output
->otmMacLineGap
= INTERNAL_YDSTOWS(dc
, output
->otmMacLineGap
);
2878 output
->otmptSubscriptSize
.x
= width_to_LP( dc
, output
->otmptSubscriptSize
.x
);
2879 output
->otmptSubscriptSize
.y
= height_to_LP( dc
, output
->otmptSubscriptSize
.y
);
2880 output
->otmptSubscriptOffset
.x
= width_to_LP( dc
, output
->otmptSubscriptOffset
.x
);
2881 output
->otmptSubscriptOffset
.y
= height_to_LP( dc
, output
->otmptSubscriptOffset
.y
);
2882 output
->otmptSuperscriptSize
.x
= width_to_LP( dc
, output
->otmptSuperscriptSize
.x
);
2883 output
->otmptSuperscriptSize
.y
= height_to_LP( dc
, output
->otmptSuperscriptSize
.y
);
2884 output
->otmptSuperscriptOffset
.x
= width_to_LP( dc
, output
->otmptSuperscriptOffset
.x
);
2885 output
->otmptSuperscriptOffset
.y
= height_to_LP( dc
, output
->otmptSuperscriptOffset
.y
);
2886 output
->otmsStrikeoutSize
= INTERNAL_YDSTOWS(dc
, output
->otmsStrikeoutSize
);
2887 output
->otmsStrikeoutPosition
= height_to_LP( dc
, output
->otmsStrikeoutPosition
);
2888 output
->otmsUnderscoreSize
= height_to_LP( dc
, output
->otmsUnderscoreSize
);
2889 output
->otmsUnderscorePosition
= height_to_LP( dc
, output
->otmsUnderscorePosition
);
2893 memcpy(lpOTM
, output
, cbData
);
2894 HeapFree(GetProcessHeap(), 0, output
);
2902 static LPSTR
FONT_GetCharsByRangeA(HDC hdc
, UINT firstChar
, UINT lastChar
, PINT pByteLen
)
2904 INT i
, count
= lastChar
- firstChar
+ 1;
2912 mbcp
= GdiGetCodePage(hdc
);
2920 if (lastChar
> 0xffff)
2922 if ((firstChar
^ lastChar
) > 0xff)
2926 if (lastChar
> 0xff)
2932 str
= HeapAlloc(GetProcessHeap(), 0, count
* 2 + 1);
2936 for(i
= 0, c
= firstChar
; c
<= lastChar
; i
++, c
++)
2940 str
[i
++] = (BYTE
)(c
>> 8);
2941 if (c
<= 0xff && IsDBCSLeadByteEx(mbcp
, c
))
2942 str
[i
] = 0x1f; /* FIXME: use default character */
2956 /***********************************************************************
2957 * GetCharWidthW (GDI32.@)
2958 * GetCharWidth32W (GDI32.@)
2960 BOOL WINAPI
GetCharWidth32W( HDC hdc
, UINT firstChar
, UINT lastChar
,
2966 DC
* dc
= get_dc_ptr( hdc
);
2968 if (!dc
) return FALSE
;
2970 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
2971 ret
= dev
->funcs
->pGetCharWidth( dev
, firstChar
, lastChar
, buffer
);
2975 /* convert device units to logical */
2976 for( i
= firstChar
; i
<= lastChar
; i
++, buffer
++ )
2977 *buffer
= width_to_LP( dc
, *buffer
);
2979 release_dc_ptr( dc
);
2984 /***********************************************************************
2985 * GetCharWidthA (GDI32.@)
2986 * GetCharWidth32A (GDI32.@)
2988 BOOL WINAPI
GetCharWidth32A( HDC hdc
, UINT firstChar
, UINT lastChar
,
2996 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
3000 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
3002 for(i
= 0; i
< wlen
; i
++)
3004 if(!GetCharWidth32W(hdc
, wstr
[i
], wstr
[i
], buffer
))
3012 HeapFree(GetProcessHeap(), 0, str
);
3013 HeapFree(GetProcessHeap(), 0, wstr
);
3019 /* helper for nulldrv_ExtTextOut */
3020 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT flags
, UINT aa_flags
,
3021 GLYPHMETRICS
*metrics
, struct gdi_image_bits
*image
)
3023 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
3024 UINT indices
[3] = {0, 0, 0x20};
3030 if (flags
& ETO_GLYPH_INDEX
) aa_flags
|= GGO_GLYPH_INDEX
;
3032 for (i
= 0; i
< ARRAY_SIZE( indices
); i
++)
3035 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, 0, NULL
, &identity
);
3036 if (ret
!= GDI_ERROR
) break;
3039 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
3040 if (!image
) return ERROR_SUCCESS
;
3044 if (!ret
) /* empty glyph */
3046 metrics
->gmBlackBoxX
= metrics
->gmBlackBoxY
= 0;
3047 return ERROR_SUCCESS
;
3050 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
3051 size
= metrics
->gmBlackBoxY
* stride
;
3053 if (!(image
->ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
3054 image
->is_copy
= TRUE
;
3055 image
->free
= free_heap_bits
;
3057 ret
= GetGlyphOutlineW( hdc
, index
, aa_flags
, metrics
, size
, image
->ptr
, &identity
);
3058 if (ret
== GDI_ERROR
)
3060 HeapFree( GetProcessHeap(), 0, image
->ptr
);
3061 return ERROR_NOT_FOUND
;
3063 return ERROR_SUCCESS
;
3066 /* helper for nulldrv_ExtTextOut */
3067 static RECT
get_total_extents( HDC hdc
, INT x
, INT y
, UINT flags
, UINT aa_flags
,
3068 LPCWSTR str
, UINT count
, const INT
*dx
)
3073 reset_bounds( &bounds
);
3074 for (i
= 0; i
< count
; i
++)
3076 GLYPHMETRICS metrics
;
3078 if (get_glyph_bitmap( hdc
, str
[i
], flags
, aa_flags
, &metrics
, NULL
)) continue;
3080 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
3081 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
3082 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
3083 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
3084 add_bounds_rect( &bounds
, &rect
);
3088 if (flags
& ETO_PDY
)
3091 y
+= dx
[ i
* 2 + 1];
3097 x
+= metrics
.gmCellIncX
;
3098 y
+= metrics
.gmCellIncY
;
3104 /* helper for nulldrv_ExtTextOut */
3105 static void draw_glyph( DC
*dc
, INT origin_x
, INT origin_y
, const GLYPHMETRICS
*metrics
,
3106 const struct gdi_image_bits
*image
, const RECT
*clip
)
3108 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
3109 UINT i
, count
, max_count
;
3111 BYTE
*ptr
= image
->ptr
;
3112 int stride
= get_dib_stride( metrics
->gmBlackBoxX
, 1 );
3114 RECT rect
, clipped_rect
;
3116 rect
.left
= origin_x
+ metrics
->gmptGlyphOrigin
.x
;
3117 rect
.top
= origin_y
- metrics
->gmptGlyphOrigin
.y
;
3118 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
3119 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
3120 if (!clip
) clipped_rect
= rect
;
3121 else if (!intersect_rect( &clipped_rect
, &rect
, clip
)) return;
3123 max_count
= (metrics
->gmBlackBoxX
+ 1) * metrics
->gmBlackBoxY
;
3124 pts
= HeapAlloc( GetProcessHeap(), 0, max_count
* sizeof(*pts
) );
3128 ptr
+= (clipped_rect
.top
- rect
.top
) * stride
;
3129 for (y
= clipped_rect
.top
; y
< clipped_rect
.bottom
; y
++, ptr
+= stride
)
3131 for (x
= clipped_rect
.left
- rect
.left
; x
< clipped_rect
.right
- rect
.left
; x
++)
3133 while (x
< clipped_rect
.right
- rect
.left
&& !(ptr
[x
/ 8] & masks
[x
% 8])) x
++;
3134 pts
[count
].x
= rect
.left
+ x
;
3135 while (x
< clipped_rect
.right
- rect
.left
&& (ptr
[x
/ 8] & masks
[x
% 8])) x
++;
3136 pts
[count
+ 1].x
= rect
.left
+ x
;
3137 if (pts
[count
+ 1].x
> pts
[count
].x
)
3139 pts
[count
].y
= pts
[count
+ 1].y
= y
;
3144 assert( count
<= max_count
);
3145 dp_to_lp( dc
, pts
, count
);
3146 for (i
= 0; i
< count
; i
+= 2) Polyline( dc
->hSelf
, pts
+ i
, 2 );
3147 HeapFree( GetProcessHeap(), 0, pts
);
3150 /***********************************************************************
3151 * nulldrv_ExtTextOut
3153 BOOL CDECL
nulldrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
3154 LPCWSTR str
, UINT count
, const INT
*dx
)
3156 DC
*dc
= get_nulldrv_dc( dev
);
3162 if (flags
& ETO_OPAQUE
)
3165 HBRUSH brush
= CreateSolidBrush( GetNearestColor( dev
->hdc
, dc
->backgroundColor
) );
3169 orig
= SelectObject( dev
->hdc
, brush
);
3170 dp_to_lp( dc
, (POINT
*)&rc
, 2 );
3171 PatBlt( dev
->hdc
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, PATCOPY
);
3172 SelectObject( dev
->hdc
, orig
);
3173 DeleteObject( brush
);
3177 if (!count
) return TRUE
;
3179 if (dc
->aa_flags
!= GGO_BITMAP
)
3181 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
3182 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
3183 struct gdi_image_bits bits
;
3184 struct bitblt_coords src
, dst
;
3186 /* FIXME Subpixel modes */
3187 UINT aa_flags
= GGO_GRAY4_BITMAP
;
3189 dst_dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
3190 src
.visrect
= get_total_extents( dev
->hdc
, x
, y
, flags
, aa_flags
, str
, count
, dx
);
3191 if (flags
& ETO_CLIPPED
) intersect_rect( &src
.visrect
, &src
.visrect
, rect
);
3192 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return TRUE
;
3194 /* FIXME: check for ETO_OPAQUE and avoid GetImage */
3195 src
.x
= src
.visrect
.left
;
3196 src
.y
= src
.visrect
.top
;
3197 src
.width
= src
.visrect
.right
- src
.visrect
.left
;
3198 src
.height
= src
.visrect
.bottom
- src
.visrect
.top
;
3200 if ((flags
& ETO_OPAQUE
) && (src
.visrect
.left
>= rect
->left
) && (src
.visrect
.top
>= rect
->top
) &&
3201 (src
.visrect
.right
<= rect
->right
) && (src
.visrect
.bottom
<= rect
->bottom
))
3203 /* we can avoid the GetImage, just query the needed format */
3204 memset( &info
->bmiHeader
, 0, sizeof(info
->bmiHeader
) );
3205 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
3206 info
->bmiHeader
.biWidth
= src
.width
;
3207 info
->bmiHeader
.biHeight
= -src
.height
;
3208 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
3209 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
3210 if (!err
|| err
== ERROR_BAD_FORMAT
)
3212 /* make the source rectangle relative to the source bits */
3214 src
.visrect
.left
= src
.visrect
.top
= 0;
3215 src
.visrect
.right
= src
.width
;
3216 src
.visrect
.bottom
= src
.height
;
3218 bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
3219 if (!bits
.ptr
) return ERROR_OUTOFMEMORY
;
3220 bits
.is_copy
= TRUE
;
3221 bits
.free
= free_heap_bits
;
3222 err
= ERROR_SUCCESS
;
3227 PHYSDEV src_dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
3228 err
= src_dev
->funcs
->pGetImage( src_dev
, info
, &bits
, &src
);
3229 if (!err
&& !bits
.is_copy
)
3231 void *ptr
= HeapAlloc( GetProcessHeap(), 0, info
->bmiHeader
.biSizeImage
);
3234 if (bits
.free
) bits
.free( &bits
);
3235 return ERROR_OUTOFMEMORY
;
3237 memcpy( ptr
, bits
.ptr
, info
->bmiHeader
.biSizeImage
);
3238 if (bits
.free
) bits
.free( &bits
);
3240 bits
.is_copy
= TRUE
;
3241 bits
.free
= free_heap_bits
;
3246 /* make x,y relative to the image bits */
3247 x
+= src
.visrect
.left
- dst
.visrect
.left
;
3248 y
+= src
.visrect
.top
- dst
.visrect
.top
;
3249 render_aa_text_bitmapinfo( dc
, info
, &bits
, &src
, x
, y
, flags
,
3250 aa_flags
, str
, count
, dx
);
3251 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, info
, &bits
, &src
, &dst
, SRCCOPY
);
3252 if (bits
.free
) bits
.free( &bits
);
3257 pen
= CreatePen( PS_SOLID
, 1, dc
->textColor
);
3258 orig
= SelectObject( dev
->hdc
, pen
);
3260 for (i
= 0; i
< count
; i
++)
3262 GLYPHMETRICS metrics
;
3263 struct gdi_image_bits image
;
3265 err
= get_glyph_bitmap( dev
->hdc
, str
[i
], flags
, GGO_BITMAP
, &metrics
, &image
);
3268 if (image
.ptr
) draw_glyph( dc
, x
, y
, &metrics
, &image
, (flags
& ETO_CLIPPED
) ? rect
: NULL
);
3269 if (image
.free
) image
.free( &image
);
3273 if (flags
& ETO_PDY
)
3276 y
+= dx
[ i
* 2 + 1];
3282 x
+= metrics
.gmCellIncX
;
3283 y
+= metrics
.gmCellIncY
;
3287 SelectObject( dev
->hdc
, orig
);
3288 DeleteObject( pen
);
3293 /***********************************************************************
3294 * ExtTextOutA (GDI32.@)
3298 BOOL WINAPI
ExtTextOutA( HDC hdc
, INT x
, INT y
, UINT flags
,
3299 const RECT
*lprect
, LPCSTR str
, UINT count
, const INT
*lpDx
)
3307 if (flags
& ETO_GLYPH_INDEX
)
3308 return ExtTextOutW( hdc
, x
, y
, flags
, lprect
, (LPCWSTR
)str
, count
, lpDx
);
3310 p
= FONT_mbtowc(hdc
, str
, count
, &wlen
, &codepage
);
3313 unsigned int i
= 0, j
= 0;
3315 /* allocate enough for a ETO_PDY */
3316 lpDxW
= HeapAlloc( GetProcessHeap(), 0, 2*wlen
*sizeof(INT
));
3318 if(IsDBCSLeadByteEx(codepage
, str
[i
]))
3322 lpDxW
[j
++] = lpDx
[i
* 2] + lpDx
[(i
+ 1) * 2];
3323 lpDxW
[j
++] = lpDx
[i
* 2 + 1] + lpDx
[(i
+ 1) * 2 + 1];
3326 lpDxW
[j
++] = lpDx
[i
] + lpDx
[i
+ 1];
3333 lpDxW
[j
++] = lpDx
[i
* 2];
3334 lpDxW
[j
++] = lpDx
[i
* 2 + 1];
3337 lpDxW
[j
++] = lpDx
[i
];
3343 ret
= ExtTextOutW( hdc
, x
, y
, flags
, lprect
, p
, wlen
, lpDxW
);
3345 HeapFree( GetProcessHeap(), 0, p
);
3346 HeapFree( GetProcessHeap(), 0, lpDxW
);
3350 /***********************************************************************
3353 * Scale the underline / strikeout line width.
3355 static inline int get_line_width( DC
*dc
, int metric_size
)
3357 int width
= abs( INTERNAL_YWSTODS( dc
, metric_size
));
3358 if (width
== 0) width
= 1;
3359 if (metric_size
< 0) width
= -width
;
3363 /***********************************************************************
3364 * ExtTextOutW (GDI32.@)
3366 * Draws text using the currently selected font, background color, and text color.
3370 * x,y [I] coordinates of string
3372 * ETO_GRAYED - undocumented on MSDN
3373 * ETO_OPAQUE - use background color for fill the rectangle
3374 * ETO_CLIPPED - clipping text to the rectangle
3375 * ETO_GLYPH_INDEX - Buffer is of glyph locations in fonts rather
3376 * than encoded characters. Implies ETO_IGNORELANGUAGE
3377 * ETO_RTLREADING - Paragraph is basically a right-to-left paragraph.
3378 * Affects BiDi ordering
3379 * ETO_IGNORELANGUAGE - Undocumented in MSDN - instructs ExtTextOut not to do BiDi reordering
3380 * ETO_PDY - unimplemented
3381 * ETO_NUMERICSLATIN - unimplemented always assumed -
3382 * do not translate numbers into locale representations
3383 * ETO_NUMERICSLOCAL - unimplemented - Numerals in Arabic/Farsi context should assume local form
3384 * lprect [I] dimensions for clipping or/and opaquing
3385 * str [I] text string
3386 * count [I] number of symbols in string
3387 * lpDx [I] optional parameter with distance between drawing characters
3393 BOOL WINAPI
ExtTextOutW( HDC hdc
, INT x
, INT y
, UINT flags
,
3394 const RECT
*lprect
, LPCWSTR str
, UINT count
, const INT
*lpDx
)
3397 LPWSTR reordered_str
= (LPWSTR
)str
;
3398 WORD
*glyphs
= NULL
;
3404 double cosEsc
, sinEsc
;
3408 POINT
*deltas
= NULL
, width
= {0, 0};
3410 DC
* dc
= get_dc_ptr( hdc
);
3413 static int quietfixme
= 0;
3415 if (!dc
) return FALSE
;
3417 align
= dc
->textAlign
;
3418 breakRem
= dc
->breakRem
;
3419 layout
= dc
->layout
;
3421 if (quietfixme
== 0 && flags
& (ETO_NUMERICSLOCAL
| ETO_NUMERICSLATIN
))
3423 FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN unimplemented\n");
3428 physdev
= GET_DC_PHYSDEV( dc
, pExtTextOut
);
3429 type
= GetObjectType(hdc
);
3430 if(type
== OBJ_METADC
|| type
== OBJ_ENHMETADC
)
3432 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, flags
, lprect
, str
, count
, lpDx
);
3433 release_dc_ptr( dc
);
3437 if (flags
& ETO_RTLREADING
) align
|= TA_RTLREADING
;
3438 if (layout
& LAYOUT_RTL
)
3440 if ((align
& TA_CENTER
) != TA_CENTER
) align
^= TA_RIGHT
;
3441 align
^= TA_RTLREADING
;
3444 if( !(flags
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)) && count
> 0 )
3447 reordered_str
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
3449 BIDI_Reorder( hdc
, str
, count
, GCP_REORDER
,
3450 (align
& TA_RTLREADING
) ? WINE_GCPW_FORCE_RTL
: WINE_GCPW_FORCE_LTR
,
3451 reordered_str
, count
, NULL
, &glyphs
, &cGlyphs
);
3453 flags
|= ETO_IGNORELANGUAGE
;
3456 flags
|= ETO_GLYPH_INDEX
;
3457 if (cGlyphs
!= count
)
3461 else if(flags
& ETO_GLYPH_INDEX
)
3462 glyphs
= reordered_str
;
3464 TRACE("%p, %d, %d, %08x, %s, %s, %d, %p)\n", hdc
, x
, y
, flags
,
3465 wine_dbgstr_rect(lprect
), debugstr_wn(str
, count
), count
, lpDx
);
3466 TRACE("align = %x bkmode = %x mapmode = %x\n", align
, dc
->backgroundMode
, dc
->MapMode
);
3468 if(align
& TA_UPDATECP
)
3475 GetTextMetricsW(hdc
, &tm
);
3476 GetObjectW(dc
->hFont
, sizeof(lf
), &lf
);
3478 if(!(tm
.tmPitchAndFamily
& TMPF_VECTOR
)) /* Non-scalable fonts shouldn't be rotated */
3479 lf
.lfEscapement
= 0;
3481 if ((dc
->GraphicsMode
== GM_COMPATIBLE
) &&
3482 (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
* dc
->xformWorld2Vport
.eM22
< 0))
3484 lf
.lfEscapement
= -lf
.lfEscapement
;
3487 if(lf
.lfEscapement
!= 0)
3489 cosEsc
= cos(lf
.lfEscapement
* M_PI
/ 1800);
3490 sinEsc
= sin(lf
.lfEscapement
* M_PI
/ 1800);
3498 if (lprect
&& (flags
& (ETO_OPAQUE
| ETO_CLIPPED
)))
3501 lp_to_dp(dc
, (POINT
*)&rc
, 2);
3503 if (flags
& ETO_OPAQUE
)
3504 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &rc
, NULL
, 0, NULL
);
3506 else flags
&= ~ETO_CLIPPED
;
3516 lp_to_dp(dc
, &pt
, 1);
3520 char_extra
= GetTextCharacterExtra(hdc
);
3521 if (char_extra
&& lpDx
&& GetDeviceCaps( hdc
, TECHNOLOGY
) == DT_RASPRINTER
)
3522 char_extra
= 0; /* Printer drivers don't add char_extra if lpDx is supplied */
3524 if(char_extra
|| dc
->breakExtra
|| breakRem
|| lpDx
|| lf
.lfEscapement
!= 0)
3527 POINT total
= {0, 0}, desired
[2];
3529 deltas
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(*deltas
));
3532 if (flags
& ETO_PDY
)
3534 for (i
= 0; i
< count
; i
++)
3536 deltas
[i
].x
= lpDx
[i
* 2] + char_extra
;
3537 deltas
[i
].y
= -lpDx
[i
* 2 + 1];
3542 for (i
= 0; i
< count
; i
++)
3544 deltas
[i
].x
= lpDx
[i
] + char_extra
;
3551 INT
*dx
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*dx
) );
3553 if (flags
& ETO_GLYPH_INDEX
)
3554 GetTextExtentExPointI( hdc
, glyphs
, count
, -1, NULL
, dx
, &sz
);
3556 GetTextExtentExPointW( hdc
, reordered_str
, count
, -1, NULL
, dx
, &sz
);
3558 deltas
[0].x
= dx
[0];
3560 for (i
= 1; i
< count
; i
++)
3562 deltas
[i
].x
= dx
[i
] - dx
[i
- 1];
3565 HeapFree( GetProcessHeap(), 0, dx
);
3568 for(i
= 0; i
< count
; i
++)
3570 total
.x
+= deltas
[i
].x
;
3571 total
.y
+= deltas
[i
].y
;
3573 desired
[0].x
= desired
[0].y
= 0;
3575 desired
[1].x
= cosEsc
* total
.x
+ sinEsc
* total
.y
;
3576 desired
[1].y
= -sinEsc
* total
.x
+ cosEsc
* total
.y
;
3578 lp_to_dp(dc
, desired
, 2);
3579 desired
[1].x
-= desired
[0].x
;
3580 desired
[1].y
-= desired
[0].y
;
3582 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
3584 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
3585 desired
[1].x
= -desired
[1].x
;
3586 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
3587 desired
[1].y
= -desired
[1].y
;
3590 deltas
[i
].x
= desired
[1].x
- width
.x
;
3591 deltas
[i
].y
= desired
[1].y
- width
.y
;
3601 if(flags
& ETO_GLYPH_INDEX
)
3602 GetTextExtentPointI(hdc
, glyphs
, count
, &sz
);
3604 GetTextExtentPointW(hdc
, reordered_str
, count
, &sz
);
3605 desired
[0].x
= desired
[0].y
= 0;
3606 desired
[1].x
= sz
.cx
;
3608 lp_to_dp(dc
, desired
, 2);
3609 desired
[1].x
-= desired
[0].x
;
3610 desired
[1].y
-= desired
[0].y
;
3612 if (dc
->GraphicsMode
== GM_COMPATIBLE
)
3614 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM11
< 0)
3615 desired
[1].x
= -desired
[1].x
;
3616 if (dc
->vport2WorldValid
&& dc
->xformWorld2Vport
.eM22
< 0)
3617 desired
[1].y
= -desired
[1].y
;
3622 tm
.tmAscent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmAscent
));
3623 tm
.tmDescent
= abs(INTERNAL_YWSTODS(dc
, tm
.tmDescent
));
3624 switch( align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
) )
3627 if (align
& TA_UPDATECP
)
3631 dp_to_lp(dc
, &pt
, 1);
3632 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
3644 if (align
& TA_UPDATECP
)
3648 dp_to_lp(dc
, &pt
, 1);
3649 MoveToEx(hdc
, pt
.x
, pt
.y
, NULL
);
3654 switch( align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
) )
3657 y
+= tm
.tmAscent
* cosEsc
;
3658 x
+= tm
.tmAscent
* sinEsc
;
3662 y
-= tm
.tmDescent
* cosEsc
;
3663 x
-= tm
.tmDescent
* sinEsc
;
3670 if (dc
->backgroundMode
!= TRANSPARENT
)
3672 if(!((flags
& ETO_CLIPPED
) && (flags
& ETO_OPAQUE
)))
3674 if(!(flags
& ETO_OPAQUE
) || !lprect
||
3675 x
< rc
.left
|| x
+ width
.x
>= rc
.right
||
3676 y
- tm
.tmAscent
< rc
.top
|| y
+ tm
.tmDescent
>= rc
.bottom
)
3680 text_box
.right
= x
+ width
.x
;
3681 text_box
.top
= y
- tm
.tmAscent
;
3682 text_box
.bottom
= y
+ tm
.tmDescent
;
3684 if (flags
& ETO_CLIPPED
) intersect_rect( &text_box
, &text_box
, &rc
);
3685 if (!is_rect_empty( &text_box
))
3686 physdev
->funcs
->pExtTextOut( physdev
, 0, 0, ETO_OPAQUE
, &text_box
, NULL
, 0, NULL
);
3691 ret
= physdev
->funcs
->pExtTextOut( physdev
, x
, y
, (flags
& ~ETO_OPAQUE
), &rc
,
3692 glyphs
? glyphs
: reordered_str
, count
, (INT
*)deltas
);
3695 HeapFree(GetProcessHeap(), 0, deltas
);
3696 if(glyphs
!= reordered_str
)
3697 HeapFree(GetProcessHeap(), 0, glyphs
);
3698 if(reordered_str
!= str
)
3699 HeapFree(GetProcessHeap(), 0, reordered_str
);
3701 if (ret
&& (lf
.lfUnderline
|| lf
.lfStrikeOut
))
3703 int underlinePos
, strikeoutPos
;
3704 int underlineWidth
, strikeoutWidth
;
3705 UINT size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
3706 OUTLINETEXTMETRICW
* otm
= NULL
;
3708 HPEN hpen
= SelectObject(hdc
, GetStockObject(NULL_PEN
));
3709 HBRUSH hbrush
= CreateSolidBrush(dc
->textColor
);
3711 hbrush
= SelectObject(hdc
, hbrush
);
3716 underlineWidth
= tm
.tmAscent
/ 20 + 1;
3717 strikeoutPos
= tm
.tmAscent
/ 2;
3718 strikeoutWidth
= underlineWidth
;
3722 otm
= HeapAlloc(GetProcessHeap(), 0, size
);
3723 GetOutlineTextMetricsW(hdc
, size
, otm
);
3724 underlinePos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsUnderscorePosition
));
3725 if (otm
->otmsUnderscorePosition
< 0) underlinePos
= -underlinePos
;
3726 underlineWidth
= get_line_width( dc
, otm
->otmsUnderscoreSize
);
3727 strikeoutPos
= abs( INTERNAL_YWSTODS( dc
, otm
->otmsStrikeoutPosition
));
3728 if (otm
->otmsStrikeoutPosition
< 0) strikeoutPos
= -strikeoutPos
;
3729 strikeoutWidth
= get_line_width( dc
, otm
->otmsStrikeoutSize
);
3730 HeapFree(GetProcessHeap(), 0, otm
);
3736 pts
[0].x
= x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
3737 pts
[0].y
= y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
3738 pts
[1].x
= x
+ width
.x
- (underlinePos
+ underlineWidth
/ 2) * sinEsc
;
3739 pts
[1].y
= y
+ width
.y
- (underlinePos
+ underlineWidth
/ 2) * cosEsc
;
3740 pts
[2].x
= pts
[1].x
+ underlineWidth
* sinEsc
;
3741 pts
[2].y
= pts
[1].y
+ underlineWidth
* cosEsc
;
3742 pts
[3].x
= pts
[0].x
+ underlineWidth
* sinEsc
;
3743 pts
[3].y
= pts
[0].y
+ underlineWidth
* cosEsc
;
3744 pts
[4].x
= pts
[0].x
;
3745 pts
[4].y
= pts
[0].y
;
3746 dp_to_lp(dc
, pts
, 5);
3747 Polygon(hdc
, pts
, 5);
3752 pts
[0].x
= x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
3753 pts
[0].y
= y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
3754 pts
[1].x
= x
+ width
.x
- (strikeoutPos
+ strikeoutWidth
/ 2) * sinEsc
;
3755 pts
[1].y
= y
+ width
.y
- (strikeoutPos
+ strikeoutWidth
/ 2) * cosEsc
;
3756 pts
[2].x
= pts
[1].x
+ strikeoutWidth
* sinEsc
;
3757 pts
[2].y
= pts
[1].y
+ strikeoutWidth
* cosEsc
;
3758 pts
[3].x
= pts
[0].x
+ strikeoutWidth
* sinEsc
;
3759 pts
[3].y
= pts
[0].y
+ strikeoutWidth
* cosEsc
;
3760 pts
[4].x
= pts
[0].x
;
3761 pts
[4].y
= pts
[0].y
;
3762 dp_to_lp(dc
, pts
, 5);
3763 Polygon(hdc
, pts
, 5);
3766 SelectObject(hdc
, hpen
);
3767 hbrush
= SelectObject(hdc
, hbrush
);
3768 DeleteObject(hbrush
);
3771 release_dc_ptr( dc
);
3777 /***********************************************************************
3778 * TextOutA (GDI32.@)
3780 BOOL WINAPI
TextOutA( HDC hdc
, INT x
, INT y
, LPCSTR str
, INT count
)
3782 return ExtTextOutA( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
3786 /***********************************************************************
3787 * TextOutW (GDI32.@)
3789 BOOL WINAPI
TextOutW(HDC hdc
, INT x
, INT y
, LPCWSTR str
, INT count
)
3791 return ExtTextOutW( hdc
, x
, y
, 0, NULL
, str
, count
, NULL
);
3795 /***********************************************************************
3796 * PolyTextOutA (GDI32.@)
3800 BOOL WINAPI
PolyTextOutA( HDC hdc
, const POLYTEXTA
*pptxt
, INT cStrings
)
3802 for (; cStrings
>0; cStrings
--, pptxt
++)
3803 if (!ExtTextOutA( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
3810 /***********************************************************************
3811 * PolyTextOutW (GDI32.@)
3813 * Draw several Strings
3819 BOOL WINAPI
PolyTextOutW( HDC hdc
, const POLYTEXTW
*pptxt
, INT cStrings
)
3821 for (; cStrings
>0; cStrings
--, pptxt
++)
3822 if (!ExtTextOutW( hdc
, pptxt
->x
, pptxt
->y
, pptxt
->uiFlags
, &pptxt
->rcl
, pptxt
->lpstr
, pptxt
->n
, pptxt
->pdx
))
3828 /***********************************************************************
3829 * SetMapperFlags (GDI32.@)
3831 DWORD WINAPI
SetMapperFlags( HDC hdc
, DWORD flags
)
3833 DC
*dc
= get_dc_ptr( hdc
);
3834 DWORD ret
= GDI_ERROR
;
3838 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetMapperFlags
);
3839 flags
= physdev
->funcs
->pSetMapperFlags( physdev
, flags
);
3840 if (flags
!= GDI_ERROR
)
3842 ret
= dc
->mapperFlags
;
3843 dc
->mapperFlags
= flags
;
3845 release_dc_ptr( dc
);
3850 /***********************************************************************
3851 * GetAspectRatioFilterEx (GDI32.@)
3853 BOOL WINAPI
GetAspectRatioFilterEx( HDC hdc
, LPSIZE pAspectRatio
)
3855 FIXME("(%p, %p): -- Empty Stub !\n", hdc
, pAspectRatio
);
3860 /***********************************************************************
3861 * GetCharABCWidthsA (GDI32.@)
3863 * See GetCharABCWidthsW.
3865 BOOL WINAPI
GetCharABCWidthsA(HDC hdc
, UINT firstChar
, UINT lastChar
,
3873 str
= FONT_GetCharsByRangeA(hdc
, firstChar
, lastChar
, &i
);
3877 wstr
= FONT_mbtowc(hdc
, str
, i
, &wlen
, NULL
);
3880 HeapFree(GetProcessHeap(), 0, str
);
3884 for(i
= 0; i
< wlen
; i
++)
3886 if(!GetCharABCWidthsW(hdc
, wstr
[i
], wstr
[i
], abc
))
3894 HeapFree(GetProcessHeap(), 0, str
);
3895 HeapFree(GetProcessHeap(), 0, wstr
);
3901 /******************************************************************************
3902 * GetCharABCWidthsW [GDI32.@]
3904 * Retrieves widths of characters in range.
3907 * hdc [I] Handle of device context
3908 * firstChar [I] First character in range to query
3909 * lastChar [I] Last character in range to query
3910 * abc [O] Address of character-width structure
3913 * Only works with TrueType fonts
3919 BOOL WINAPI
GetCharABCWidthsW( HDC hdc
, UINT firstChar
, UINT lastChar
,
3922 DC
*dc
= get_dc_ptr(hdc
);
3928 if (!dc
) return FALSE
;
3932 release_dc_ptr( dc
);
3936 /* unlike GetCharABCWidthsFloatW, this one is supposed to fail on non-scalable fonts */
3937 dev
= GET_DC_PHYSDEV( dc
, pGetTextMetrics
);
3938 if (!dev
->funcs
->pGetTextMetrics( dev
, &tm
) || !(tm
.tmPitchAndFamily
& TMPF_VECTOR
))
3940 release_dc_ptr( dc
);
3944 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
3945 ret
= dev
->funcs
->pGetCharABCWidths( dev
, firstChar
, lastChar
, abc
);
3948 /* convert device units to logical */
3949 for( i
= firstChar
; i
<= lastChar
; i
++, abc
++ ) {
3950 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
3951 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
3952 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
3956 release_dc_ptr( dc
);
3961 /******************************************************************************
3962 * GetCharABCWidthsI [GDI32.@]
3964 * Retrieves widths of characters in range.
3967 * hdc [I] Handle of device context
3968 * firstChar [I] First glyphs in range to query
3969 * count [I] Last glyphs in range to query
3970 * pgi [i] Array of glyphs to query
3971 * abc [O] Address of character-width structure
3974 * Only works with TrueType fonts
3980 BOOL WINAPI
GetCharABCWidthsI( HDC hdc
, UINT firstChar
, UINT count
,
3981 LPWORD pgi
, LPABC abc
)
3983 DC
*dc
= get_dc_ptr(hdc
);
3988 if (!dc
) return FALSE
;
3992 release_dc_ptr( dc
);
3996 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidthsI
);
3997 ret
= dev
->funcs
->pGetCharABCWidthsI( dev
, firstChar
, count
, pgi
, abc
);
4000 /* convert device units to logical */
4001 for( i
= 0; i
< count
; i
++, abc
++ ) {
4002 abc
->abcA
= width_to_LP(dc
, abc
->abcA
);
4003 abc
->abcB
= width_to_LP(dc
, abc
->abcB
);
4004 abc
->abcC
= width_to_LP(dc
, abc
->abcC
);
4008 release_dc_ptr( dc
);
4013 /***********************************************************************
4014 * GetGlyphOutlineA (GDI32.@)
4016 DWORD WINAPI
GetGlyphOutlineA( HDC hdc
, UINT uChar
, UINT fuFormat
,
4017 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
4018 LPVOID lpBuffer
, const MAT2
*lpmat2
)
4020 if (!lpmat2
) return GDI_ERROR
;
4022 if(!(fuFormat
& GGO_GLYPH_INDEX
)) {
4028 cp
= GdiGetCodePage(hdc
);
4029 if (IsDBCSLeadByteEx(cp
, uChar
>> 8)) {
4031 mbchs
[0] = (uChar
& 0xff00) >> 8;
4032 mbchs
[1] = (uChar
& 0xff);
4035 mbchs
[0] = (uChar
& 0xff);
4038 MultiByteToWideChar(cp
, 0, mbchs
, len
, &wChar
, 1);
4042 return GetGlyphOutlineW(hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
,
4046 /***********************************************************************
4047 * GetGlyphOutlineW (GDI32.@)
4049 DWORD WINAPI
GetGlyphOutlineW( HDC hdc
, UINT uChar
, UINT fuFormat
,
4050 LPGLYPHMETRICS lpgm
, DWORD cbBuffer
,
4051 LPVOID lpBuffer
, const MAT2
*lpmat2
)
4057 TRACE("(%p, %04x, %04x, %p, %d, %p, %p)\n",
4058 hdc
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
4060 if (!lpmat2
) return GDI_ERROR
;
4062 dc
= get_dc_ptr(hdc
);
4063 if(!dc
) return GDI_ERROR
;
4067 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphOutline
);
4068 ret
= dev
->funcs
->pGetGlyphOutline( dev
, uChar
, fuFormat
, lpgm
, cbBuffer
, lpBuffer
, lpmat2
);
4069 release_dc_ptr( dc
);
4074 /***********************************************************************
4075 * CreateScalableFontResourceA (GDI32.@)
4077 BOOL WINAPI
CreateScalableFontResourceA( DWORD fHidden
,
4078 LPCSTR lpszResourceFile
,
4079 LPCSTR lpszFontFile
,
4080 LPCSTR lpszCurrentPath
)
4082 LPWSTR lpszResourceFileW
= NULL
;
4083 LPWSTR lpszFontFileW
= NULL
;
4084 LPWSTR lpszCurrentPathW
= NULL
;
4088 if (lpszResourceFile
)
4090 len
= MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, NULL
, 0);
4091 lpszResourceFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4092 MultiByteToWideChar(CP_ACP
, 0, lpszResourceFile
, -1, lpszResourceFileW
, len
);
4097 len
= MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, NULL
, 0);
4098 lpszFontFileW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4099 MultiByteToWideChar(CP_ACP
, 0, lpszFontFile
, -1, lpszFontFileW
, len
);
4102 if (lpszCurrentPath
)
4104 len
= MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, NULL
, 0);
4105 lpszCurrentPathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4106 MultiByteToWideChar(CP_ACP
, 0, lpszCurrentPath
, -1, lpszCurrentPathW
, len
);
4109 ret
= CreateScalableFontResourceW(fHidden
, lpszResourceFileW
,
4110 lpszFontFileW
, lpszCurrentPathW
);
4112 HeapFree(GetProcessHeap(), 0, lpszResourceFileW
);
4113 HeapFree(GetProcessHeap(), 0, lpszFontFileW
);
4114 HeapFree(GetProcessHeap(), 0, lpszCurrentPathW
);
4119 /***********************************************************************
4120 * CreateScalableFontResourceW (GDI32.@)
4122 BOOL WINAPI
CreateScalableFontResourceW( DWORD hidden
, LPCWSTR resource_file
,
4123 LPCWSTR font_file
, LPCWSTR font_path
)
4125 TRACE("(%d, %s, %s, %s)\n", hidden
, debugstr_w(resource_file
),
4126 debugstr_w(font_file
), debugstr_w(font_path
) );
4128 if (!font_funcs
) return FALSE
;
4129 return font_funcs
->pCreateScalableFontResource( hidden
, resource_file
, font_file
, font_path
);
4132 /*************************************************************************
4133 * GetKerningPairsA (GDI32.@)
4135 DWORD WINAPI
GetKerningPairsA( HDC hDC
, DWORD cPairs
,
4136 LPKERNINGPAIR kern_pairA
)
4140 DWORD i
, total_kern_pairs
, kern_pairs_copied
= 0;
4141 KERNINGPAIR
*kern_pairW
;
4143 if (!cPairs
&& kern_pairA
)
4145 SetLastError(ERROR_INVALID_PARAMETER
);
4149 cp
= GdiGetCodePage(hDC
);
4151 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
4152 * to fail on an invalid character for CP_SYMBOL.
4154 cpi
.DefaultChar
[0] = 0;
4155 if (cp
!= CP_SYMBOL
&& !GetCPInfo(cp
, &cpi
))
4157 FIXME("Can't find codepage %u info\n", cp
);
4161 total_kern_pairs
= GetKerningPairsW(hDC
, 0, NULL
);
4162 if (!total_kern_pairs
) return 0;
4164 kern_pairW
= HeapAlloc(GetProcessHeap(), 0, total_kern_pairs
* sizeof(*kern_pairW
));
4165 GetKerningPairsW(hDC
, total_kern_pairs
, kern_pairW
);
4167 for (i
= 0; i
< total_kern_pairs
; i
++)
4171 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wFirst
, 1, &first
, 1, NULL
, NULL
))
4174 if (!WideCharToMultiByte(cp
, 0, &kern_pairW
[i
].wSecond
, 1, &second
, 1, NULL
, NULL
))
4177 if (first
== cpi
.DefaultChar
[0] || second
== cpi
.DefaultChar
[0])
4182 if (kern_pairs_copied
>= cPairs
) break;
4184 kern_pairA
->wFirst
= (BYTE
)first
;
4185 kern_pairA
->wSecond
= (BYTE
)second
;
4186 kern_pairA
->iKernAmount
= kern_pairW
[i
].iKernAmount
;
4189 kern_pairs_copied
++;
4192 HeapFree(GetProcessHeap(), 0, kern_pairW
);
4194 return kern_pairs_copied
;
4197 /*************************************************************************
4198 * GetKerningPairsW (GDI32.@)
4200 DWORD WINAPI
GetKerningPairsW( HDC hDC
, DWORD cPairs
,
4201 LPKERNINGPAIR lpKerningPairs
)
4207 TRACE("(%p,%d,%p)\n", hDC
, cPairs
, lpKerningPairs
);
4209 if (!cPairs
&& lpKerningPairs
)
4211 SetLastError(ERROR_INVALID_PARAMETER
);
4215 dc
= get_dc_ptr(hDC
);
4218 dev
= GET_DC_PHYSDEV( dc
, pGetKerningPairs
);
4219 ret
= dev
->funcs
->pGetKerningPairs( dev
, cPairs
, lpKerningPairs
);
4220 release_dc_ptr( dc
);
4224 /*************************************************************************
4225 * TranslateCharsetInfo [GDI32.@]
4227 * Fills a CHARSETINFO structure for a character set, code page, or
4228 * font. This allows making the correspondence between different labels
4229 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
4230 * of the same encoding.
4232 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
4233 * only one codepage should be set in *lpSrc.
4236 * TRUE on success, FALSE on failure.
4239 BOOL WINAPI
TranslateCharsetInfo(
4240 LPDWORD lpSrc
, /* [in]
4241 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
4242 if flags == TCI_SRCCHARSET: a character set value
4243 if flags == TCI_SRCCODEPAGE: a code page value
4245 LPCHARSETINFO lpCs
, /* [out] structure to receive charset information */
4246 DWORD flags
/* [in] determines interpretation of lpSrc */)
4250 case TCI_SRCFONTSIG
:
4251 while (index
< MAXTCIINDEX
&& !(*lpSrc
>>index
& 0x0001)) index
++;
4253 case TCI_SRCCODEPAGE
:
4254 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciACP
) index
++;
4256 case TCI_SRCCHARSET
:
4257 while (index
< MAXTCIINDEX
&& PtrToUlong(lpSrc
) != FONT_tci
[index
].ciCharset
) index
++;
4262 if (index
>= MAXTCIINDEX
|| FONT_tci
[index
].ciCharset
== DEFAULT_CHARSET
) return FALSE
;
4263 *lpCs
= FONT_tci
[index
];
4267 /*************************************************************************
4268 * GetFontLanguageInfo (GDI32.@)
4270 DWORD WINAPI
GetFontLanguageInfo(HDC hdc
)
4272 FONTSIGNATURE fontsig
;
4273 static const DWORD GCP_DBCS_MASK
=FS_JISJAPAN
|FS_CHINESESIMP
|FS_WANSUNG
|FS_CHINESETRAD
|FS_JOHAB
,
4274 GCP_DIACRITIC_MASK
=0x00000000,
4275 FLI_GLYPHS_MASK
=0x00000000,
4276 GCP_GLYPHSHAPE_MASK
=FS_ARABIC
,
4277 GCP_KASHIDA_MASK
=0x00000000,
4278 GCP_LIGATE_MASK
=0x00000000,
4279 GCP_REORDER_MASK
=FS_HEBREW
|FS_ARABIC
;
4283 GetTextCharsetInfo( hdc
, &fontsig
, 0 );
4284 /* We detect each flag we return using a bitmask on the Codepage Bitfields */
4286 if( (fontsig
.fsCsb
[0]&GCP_DBCS_MASK
)!=0 )
4289 if( (fontsig
.fsCsb
[0]&GCP_DIACRITIC_MASK
)!=0 )
4290 result
|=GCP_DIACRITIC
;
4292 if( (fontsig
.fsCsb
[0]&FLI_GLYPHS_MASK
)!=0 )
4295 if( (fontsig
.fsCsb
[0]&GCP_GLYPHSHAPE_MASK
)!=0 )
4296 result
|=GCP_GLYPHSHAPE
;
4298 if( (fontsig
.fsCsb
[0]&GCP_KASHIDA_MASK
)!=0 )
4299 result
|=GCP_KASHIDA
;
4301 if( (fontsig
.fsCsb
[0]&GCP_LIGATE_MASK
)!=0 )
4304 if( GetKerningPairsW( hdc
, 0, NULL
) )
4305 result
|=GCP_USEKERNING
;
4307 /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
4308 if( GetTextAlign( hdc
) & TA_RTLREADING
)
4309 if( (fontsig
.fsCsb
[0]&GCP_REORDER_MASK
)!=0 )
4310 result
|=GCP_REORDER
;
4316 /*************************************************************************
4317 * GetFontData [GDI32.@]
4319 * Retrieve data for TrueType font.
4323 * success: Number of bytes returned
4324 * failure: GDI_ERROR
4328 * Calls SetLastError()
4331 DWORD WINAPI
GetFontData(HDC hdc
, DWORD table
, DWORD offset
,
4332 LPVOID buffer
, DWORD length
)
4334 DC
*dc
= get_dc_ptr(hdc
);
4338 if(!dc
) return GDI_ERROR
;
4340 dev
= GET_DC_PHYSDEV( dc
, pGetFontData
);
4341 ret
= dev
->funcs
->pGetFontData( dev
, table
, offset
, buffer
, length
);
4342 release_dc_ptr( dc
);
4346 /*************************************************************************
4347 * GetGlyphIndicesA [GDI32.@]
4349 DWORD WINAPI
GetGlyphIndicesA(HDC hdc
, LPCSTR lpstr
, INT count
,
4350 LPWORD pgi
, DWORD flags
)
4356 TRACE("(%p, %s, %d, %p, 0x%x)\n",
4357 hdc
, debugstr_an(lpstr
, count
), count
, pgi
, flags
);
4359 lpstrW
= FONT_mbtowc(hdc
, lpstr
, count
, &countW
, NULL
);
4360 ret
= GetGlyphIndicesW(hdc
, lpstrW
, countW
, pgi
, flags
);
4361 HeapFree(GetProcessHeap(), 0, lpstrW
);
4366 /*************************************************************************
4367 * GetGlyphIndicesW [GDI32.@]
4369 DWORD WINAPI
GetGlyphIndicesW(HDC hdc
, LPCWSTR lpstr
, INT count
,
4370 LPWORD pgi
, DWORD flags
)
4372 DC
*dc
= get_dc_ptr(hdc
);
4376 TRACE("(%p, %s, %d, %p, 0x%x)\n",
4377 hdc
, debugstr_wn(lpstr
, count
), count
, pgi
, flags
);
4379 if(!dc
) return GDI_ERROR
;
4381 dev
= GET_DC_PHYSDEV( dc
, pGetGlyphIndices
);
4382 ret
= dev
->funcs
->pGetGlyphIndices( dev
, lpstr
, count
, pgi
, flags
);
4383 release_dc_ptr( dc
);
4387 /*************************************************************************
4388 * GetCharacterPlacementA [GDI32.@]
4390 * See GetCharacterPlacementW.
4393 * the web browser control of ie4 calls this with dwFlags=0
4396 GetCharacterPlacementA(HDC hdc
, LPCSTR lpString
, INT uCount
,
4397 INT nMaxExtent
, GCP_RESULTSA
*lpResults
,
4402 GCP_RESULTSW resultsW
;
4406 TRACE("%s, %d, %d, 0x%08x\n",
4407 debugstr_an(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
4409 lpStringW
= FONT_mbtowc(hdc
, lpString
, uCount
, &uCountW
, &font_cp
);
4413 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, NULL
, dwFlags
);
4414 HeapFree(GetProcessHeap(), 0, lpStringW
);
4418 /* both structs are equal in size */
4419 memcpy(&resultsW
, lpResults
, sizeof(resultsW
));
4421 if(lpResults
->lpOutString
)
4422 resultsW
.lpOutString
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*uCountW
);
4424 ret
= GetCharacterPlacementW(hdc
, lpStringW
, uCountW
, nMaxExtent
, &resultsW
, dwFlags
);
4426 lpResults
->nGlyphs
= resultsW
.nGlyphs
;
4427 lpResults
->nMaxFit
= resultsW
.nMaxFit
;
4429 if(lpResults
->lpOutString
) {
4430 WideCharToMultiByte(font_cp
, 0, resultsW
.lpOutString
, uCountW
,
4431 lpResults
->lpOutString
, uCount
, NULL
, NULL
);
4434 HeapFree(GetProcessHeap(), 0, lpStringW
);
4435 HeapFree(GetProcessHeap(), 0, resultsW
.lpOutString
);
4440 static int kern_pair(const KERNINGPAIR
*kern
, int count
, WCHAR c1
, WCHAR c2
)
4444 for (i
= 0; i
< count
; i
++)
4446 if (kern
[i
].wFirst
== c1
&& kern
[i
].wSecond
== c2
)
4447 return kern
[i
].iKernAmount
;
4453 static int *kern_string(HDC hdc
, const WCHAR
*str
, int len
, int *kern_total
)
4456 KERNINGPAIR
*kern
= NULL
;
4461 ret
= heap_alloc(len
* sizeof(*ret
));
4462 if (!ret
) return NULL
;
4464 count
= GetKerningPairsW(hdc
, 0, NULL
);
4467 kern
= heap_alloc(count
* sizeof(*kern
));
4474 GetKerningPairsW(hdc
, count
, kern
);
4477 for (i
= 0; i
< len
- 1; i
++)
4479 ret
[i
] = kern_pair(kern
, count
, str
[i
], str
[i
+ 1]);
4480 *kern_total
+= ret
[i
];
4483 ret
[len
- 1] = 0; /* no kerning for last element */
4489 /*************************************************************************
4490 * GetCharacterPlacementW [GDI32.@]
4492 * Retrieve information about a string. This includes the width, reordering,
4493 * Glyphing and so on.
4497 * The width and height of the string if successful, 0 if failed.
4501 * All flags except GCP_REORDER are not yet implemented.
4502 * Reordering is not 100% compliant to the Windows BiDi method.
4503 * Caret positioning is not yet implemented for BiDi.
4504 * Classes are not yet implemented.
4508 GetCharacterPlacementW(
4509 HDC hdc
, /* [in] Device context for which the rendering is to be done */
4510 LPCWSTR lpString
, /* [in] The string for which information is to be returned */
4511 INT uCount
, /* [in] Number of WORDS in string. */
4512 INT nMaxExtent
, /* [in] Maximum extent the string is to take (in HDC logical units) */
4513 GCP_RESULTSW
*lpResults
, /* [in/out] A pointer to a GCP_RESULTSW struct */
4514 DWORD dwFlags
/* [in] Flags specifying how to process the string */
4520 int *kern
= NULL
, kern_total
= 0;
4522 TRACE("%s, %d, %d, 0x%08x\n",
4523 debugstr_wn(lpString
, uCount
), uCount
, nMaxExtent
, dwFlags
);
4529 return GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
) ? MAKELONG(size
.cx
, size
.cy
) : 0;
4531 TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
4532 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
4533 lpResults
->lStructSize
, lpResults
->lpOutString
, lpResults
->lpOrder
,
4534 lpResults
->lpDx
, lpResults
->lpCaretPos
, lpResults
->lpClass
,
4535 lpResults
->lpGlyphs
, lpResults
->nGlyphs
, lpResults
->nMaxFit
);
4537 if (dwFlags
& ~(GCP_REORDER
| GCP_USEKERNING
))
4538 FIXME("flags 0x%08x ignored\n", dwFlags
);
4539 if (lpResults
->lpClass
)
4540 FIXME("classes not implemented\n");
4541 if (lpResults
->lpCaretPos
&& (dwFlags
& GCP_REORDER
))
4542 FIXME("Caret positions for complex scripts not implemented\n");
4544 nSet
= (UINT
)uCount
;
4545 if (nSet
> lpResults
->nGlyphs
)
4546 nSet
= lpResults
->nGlyphs
;
4548 /* return number of initialized fields */
4549 lpResults
->nGlyphs
= nSet
;
4551 if (!(dwFlags
& GCP_REORDER
))
4553 /* Treat the case where no special handling was requested in a fastpath way */
4554 /* copy will do if the GCP_REORDER flag is not set */
4555 if (lpResults
->lpOutString
)
4556 memcpy( lpResults
->lpOutString
, lpString
, nSet
* sizeof(WCHAR
));
4558 if (lpResults
->lpOrder
)
4560 for (i
= 0; i
< nSet
; i
++)
4561 lpResults
->lpOrder
[i
] = i
;
4566 BIDI_Reorder(NULL
, lpString
, uCount
, dwFlags
, WINE_GCPW_FORCE_LTR
, lpResults
->lpOutString
,
4567 nSet
, lpResults
->lpOrder
, NULL
, NULL
);
4570 if (dwFlags
& GCP_USEKERNING
)
4572 kern
= kern_string(hdc
, lpString
, nSet
, &kern_total
);
4575 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
4580 /* FIXME: Will use the placement chars */
4581 if (lpResults
->lpDx
)
4584 for (i
= 0; i
< nSet
; i
++)
4586 if (GetCharWidth32W(hdc
, lpString
[i
], lpString
[i
], &c
))
4588 lpResults
->lpDx
[i
] = c
;
4589 if (dwFlags
& GCP_USEKERNING
)
4590 lpResults
->lpDx
[i
] += kern
[i
];
4595 if (lpResults
->lpCaretPos
&& !(dwFlags
& GCP_REORDER
))
4599 lpResults
->lpCaretPos
[0] = 0;
4600 for (i
= 0; i
< nSet
- 1; i
++)
4602 if (dwFlags
& GCP_USEKERNING
)
4605 if (GetTextExtentPoint32W(hdc
, &lpString
[i
], 1, &size
))
4606 lpResults
->lpCaretPos
[i
+ 1] = (pos
+= size
.cx
);
4610 if (lpResults
->lpGlyphs
)
4611 GetGlyphIndicesW(hdc
, lpString
, nSet
, lpResults
->lpGlyphs
, 0);
4613 if (GetTextExtentPoint32W(hdc
, lpString
, uCount
, &size
))
4614 ret
= MAKELONG(size
.cx
+ kern_total
, size
.cy
);
4621 /*************************************************************************
4622 * GetCharABCWidthsFloatA [GDI32.@]
4624 * See GetCharABCWidthsFloatW.
4626 BOOL WINAPI
GetCharABCWidthsFloatA( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
4633 str
= FONT_GetCharsByRangeA(hdc
, first
, last
, &i
);
4637 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
4639 for (i
= 0; i
< wlen
; i
++)
4641 if (!GetCharABCWidthsFloatW( hdc
, wstr
[i
], wstr
[i
], abcf
))
4649 HeapFree( GetProcessHeap(), 0, str
);
4650 HeapFree( GetProcessHeap(), 0, wstr
);
4655 /*************************************************************************
4656 * GetCharABCWidthsFloatW [GDI32.@]
4658 * Retrieves widths of a range of characters.
4661 * hdc [I] Handle to device context.
4662 * first [I] First character in range to query.
4663 * last [I] Last character in range to query.
4664 * abcf [O] Array of LPABCFLOAT structures.
4670 BOOL WINAPI
GetCharABCWidthsFloatW( HDC hdc
, UINT first
, UINT last
, LPABCFLOAT abcf
)
4676 DC
*dc
= get_dc_ptr( hdc
);
4678 TRACE("%p, %d, %d, %p\n", hdc
, first
, last
, abcf
);
4680 if (!dc
) return FALSE
;
4682 if (!abcf
) goto done
;
4683 if (!(abc
= HeapAlloc( GetProcessHeap(), 0, (last
- first
+ 1) * sizeof(*abc
) ))) goto done
;
4685 dev
= GET_DC_PHYSDEV( dc
, pGetCharABCWidths
);
4686 ret
= dev
->funcs
->pGetCharABCWidths( dev
, first
, last
, abc
);
4689 /* convert device units to logical */
4690 FLOAT scale
= fabs( dc
->xformVport2World
.eM11
);
4691 for (i
= first
; i
<= last
; i
++, abcf
++)
4693 abcf
->abcfA
= abc
[i
- first
].abcA
* scale
;
4694 abcf
->abcfB
= abc
[i
- first
].abcB
* scale
;
4695 abcf
->abcfC
= abc
[i
- first
].abcC
* scale
;
4698 HeapFree( GetProcessHeap(), 0, abc
);
4701 release_dc_ptr( dc
);
4705 /*************************************************************************
4706 * GetCharWidthFloatA [GDI32.@]
4708 BOOL WINAPI
GetCharWidthFloatA( HDC hdc
, UINT first
, UINT last
, float *buffer
)
4714 if (!(str
= FONT_GetCharsByRangeA( hdc
, first
, last
, &i
)))
4716 wstr
= FONT_mbtowc( hdc
, str
, i
, &wlen
, NULL
);
4719 for (i
= 0; i
< wlen
; ++i
)
4721 if (!GetCharWidthFloatW( hdc
, wstr
[i
], wstr
[i
], &buffer
[i
] ))
4731 /*************************************************************************
4732 * GetCharWidthFloatW [GDI32.@]
4734 BOOL WINAPI
GetCharWidthFloatW( HDC hdc
, UINT first
, UINT last
, float *buffer
)
4736 DC
*dc
= get_dc_ptr( hdc
);
4742 TRACE("dc %p, first %#x, last %#x, buffer %p\n", dc
, first
, last
, buffer
);
4744 if (!dc
) return FALSE
;
4746 if (!(ibuffer
= heap_alloc( (last
- first
+ 1) * sizeof(int) )))
4748 release_dc_ptr( dc
);
4752 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidth
);
4753 if ((ret
= dev
->funcs
->pGetCharWidth( dev
, first
, last
, ibuffer
)))
4755 float scale
= fabs( dc
->xformVport2World
.eM11
) / 16.0f
;
4756 for (i
= first
; i
<= last
; ++i
)
4757 buffer
[i
- first
] = ibuffer
[i
- first
] * scale
;
4764 /***********************************************************************
4766 * Font Resource API *
4768 ***********************************************************************/
4770 /***********************************************************************
4771 * AddFontResourceA (GDI32.@)
4773 INT WINAPI
AddFontResourceA( LPCSTR str
)
4775 return AddFontResourceExA( str
, 0, NULL
);
4778 /***********************************************************************
4779 * AddFontResourceW (GDI32.@)
4781 INT WINAPI
AddFontResourceW( LPCWSTR str
)
4783 return AddFontResourceExW(str
, 0, NULL
);
4787 /***********************************************************************
4788 * AddFontResourceExA (GDI32.@)
4790 INT WINAPI
AddFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
4792 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
4793 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4796 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
4797 ret
= AddFontResourceExW(strW
, fl
, pdv
);
4798 HeapFree(GetProcessHeap(), 0, strW
);
4802 static BOOL CALLBACK
load_enumed_resource(HMODULE hModule
, LPCWSTR type
, LPWSTR name
, LONG_PTR lParam
)
4804 HRSRC rsrc
= FindResourceW(hModule
, name
, type
);
4805 HGLOBAL hMem
= LoadResource(hModule
, rsrc
);
4806 LPVOID
*pMem
= LockResource(hMem
);
4807 int *num_total
= (int *)lParam
;
4810 TRACE("Found resource %s - trying to load\n", wine_dbgstr_w(type
));
4811 if (!AddFontMemResourceEx(pMem
, SizeofResource(hModule
, rsrc
), NULL
, &num_in_res
))
4813 ERR("Failed to load PE font resource mod=%p ptr=%p\n", hModule
, hMem
);
4817 *num_total
+= num_in_res
;
4821 static void *map_file( const WCHAR
*filename
, LARGE_INTEGER
*size
)
4823 HANDLE file
, mapping
;
4826 file
= CreateFileW( filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
4827 if (file
== INVALID_HANDLE_VALUE
) return NULL
;
4829 if (!GetFileSizeEx( file
, size
) || size
->u
.HighPart
)
4831 CloseHandle( file
);
4835 mapping
= CreateFileMappingW( file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
4836 CloseHandle( file
);
4837 if (!mapping
) return NULL
;
4839 ptr
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
4840 CloseHandle( mapping
);
4845 static void *find_resource( BYTE
*ptr
, WORD type
, DWORD rsrc_off
, DWORD size
, DWORD
*len
)
4847 WORD align
, type_id
, count
;
4850 if (size
< rsrc_off
+ 10) return NULL
;
4851 align
= *(WORD
*)(ptr
+ rsrc_off
);
4853 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
4854 while (type_id
&& type_id
!= type
)
4856 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
4857 rsrc_off
+= 8 + count
* 12;
4858 if (size
< rsrc_off
+ 8) return NULL
;
4859 type_id
= *(WORD
*)(ptr
+ rsrc_off
);
4861 if (!type_id
) return NULL
;
4862 count
= *(WORD
*)(ptr
+ rsrc_off
+ 2);
4863 if (size
< rsrc_off
+ 8 + count
* 12) return NULL
;
4864 res_off
= *(WORD
*)(ptr
+ rsrc_off
+ 8) << align
;
4865 *len
= *(WORD
*)(ptr
+ rsrc_off
+ 10) << align
;
4866 if (size
< res_off
+ *len
) return NULL
;
4867 return ptr
+ res_off
;
4870 static WCHAR
*get_scalable_filename( const WCHAR
*res
, BOOL
*hidden
)
4873 BYTE
*ptr
= map_file( res
, &size
);
4874 const IMAGE_DOS_HEADER
*dos
;
4875 const IMAGE_OS2_HEADER
*ne
;
4881 if (!ptr
) return NULL
;
4883 if (size
.u
.LowPart
< sizeof( *dos
)) goto fail
;
4884 dos
= (const IMAGE_DOS_HEADER
*)ptr
;
4885 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) goto fail
;
4886 if (size
.u
.LowPart
< dos
->e_lfanew
+ sizeof( *ne
)) goto fail
;
4887 ne
= (const IMAGE_OS2_HEADER
*)(ptr
+ dos
->e_lfanew
);
4889 fontdir
= find_resource( ptr
, 0x8007, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
4890 if (!fontdir
) goto fail
;
4891 *hidden
= (fontdir
[35] & 0x80) != 0; /* fontdir->dfType */
4893 data
= find_resource( ptr
, 0x80cc, dos
->e_lfanew
+ ne
->ne_rsrctab
, size
.u
.LowPart
, &len
);
4894 if (!data
) goto fail
;
4895 if (!memchr( data
, 0, len
)) goto fail
;
4897 len
= MultiByteToWideChar( CP_ACP
, 0, data
, -1, NULL
, 0 );
4898 name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
4899 if (name
) MultiByteToWideChar( CP_ACP
, 0, data
, -1, name
, len
);
4902 UnmapViewOfFile( ptr
);
4906 /***********************************************************************
4907 * AddFontResourceExW (GDI32.@)
4909 INT WINAPI
AddFontResourceExW( LPCWSTR str
, DWORD fl
, PVOID pdv
)
4915 if (!font_funcs
) return 1;
4916 if (!(ret
= font_funcs
->pAddFontResourceEx( str
, fl
, pdv
)))
4918 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
4919 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
4920 if (hModule
!= NULL
)
4922 int num_resources
= 0;
4923 LPWSTR rt_font
= (LPWSTR
)((ULONG_PTR
)8); /* we don't want to include winuser.h */
4925 TRACE("WineEngAddFontResourceEx failed on PE file %s - trying to load resources manually\n",
4926 wine_dbgstr_w(str
));
4927 if (EnumResourceNamesW(hModule
, rt_font
, load_enumed_resource
, (LONG_PTR
)&num_resources
))
4928 ret
= num_resources
;
4929 FreeLibrary(hModule
);
4931 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
4933 if (hidden
) fl
|= FR_PRIVATE
| FR_NOT_ENUM
;
4934 ret
= font_funcs
->pAddFontResourceEx( filename
, fl
, pdv
);
4935 HeapFree( GetProcessHeap(), 0, filename
);
4941 /***********************************************************************
4942 * RemoveFontResourceA (GDI32.@)
4944 BOOL WINAPI
RemoveFontResourceA( LPCSTR str
)
4946 return RemoveFontResourceExA(str
, 0, 0);
4949 /***********************************************************************
4950 * RemoveFontResourceW (GDI32.@)
4952 BOOL WINAPI
RemoveFontResourceW( LPCWSTR str
)
4954 return RemoveFontResourceExW(str
, 0, 0);
4957 /***********************************************************************
4958 * AddFontMemResourceEx (GDI32.@)
4960 HANDLE WINAPI
AddFontMemResourceEx( PVOID pbFont
, DWORD cbFont
, PVOID pdv
, DWORD
*pcFonts
)
4965 if (!pbFont
|| !cbFont
|| !pcFonts
)
4967 SetLastError(ERROR_INVALID_PARAMETER
);
4970 if (!font_funcs
) return NULL
;
4971 ret
= font_funcs
->pAddFontMemResourceEx( pbFont
, cbFont
, pdv
, &num_fonts
);
4976 *pcFonts
= num_fonts
;
4980 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts
);
4981 RemoveFontMemResourceEx(ret
);
4989 /***********************************************************************
4990 * RemoveFontMemResourceEx (GDI32.@)
4992 BOOL WINAPI
RemoveFontMemResourceEx( HANDLE fh
)
4994 FIXME("(%p) stub\n", fh
);
4998 /***********************************************************************
4999 * RemoveFontResourceExA (GDI32.@)
5001 BOOL WINAPI
RemoveFontResourceExA( LPCSTR str
, DWORD fl
, PVOID pdv
)
5003 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
5004 LPWSTR strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
5007 MultiByteToWideChar(CP_ACP
, 0, str
, -1, strW
, len
);
5008 ret
= RemoveFontResourceExW(strW
, fl
, pdv
);
5009 HeapFree(GetProcessHeap(), 0, strW
);
5013 /***********************************************************************
5014 * RemoveFontResourceExW (GDI32.@)
5016 BOOL WINAPI
RemoveFontResourceExW( LPCWSTR str
, DWORD fl
, PVOID pdv
)
5022 if (!font_funcs
) return TRUE
;
5024 if (!(ret
= font_funcs
->pRemoveFontResourceEx( str
, fl
, pdv
)))
5026 /* FreeType <2.3.5 has problems reading resources wrapped in PE files. */
5027 HMODULE hModule
= LoadLibraryExW(str
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
5028 if (hModule
!= NULL
)
5030 WARN("Can't unload resources from PE file %s\n", wine_dbgstr_w(str
));
5031 FreeLibrary(hModule
);
5033 else if ((filename
= get_scalable_filename( str
, &hidden
)) != NULL
)
5035 if (hidden
) fl
|= FR_PRIVATE
| FR_NOT_ENUM
;
5036 ret
= font_funcs
->pRemoveFontResourceEx( filename
, fl
, pdv
);
5037 HeapFree( GetProcessHeap(), 0, filename
);
5043 /***********************************************************************
5044 * GetFontResourceInfoW (GDI32.@)
5046 BOOL WINAPI
GetFontResourceInfoW( LPCWSTR str
, LPDWORD size
, PVOID buffer
, DWORD type
)
5048 FIXME("%s %p(%d) %p %d\n", debugstr_w(str
), size
, size
? *size
: 0, buffer
, type
);
5052 /***********************************************************************
5053 * GetTextCharset (GDI32.@)
5055 UINT WINAPI
GetTextCharset(HDC hdc
)
5057 /* MSDN docs say this is equivalent */
5058 return GetTextCharsetInfo(hdc
, NULL
, 0);
5061 /***********************************************************************
5062 * GdiGetCharDimensions (GDI32.@)
5064 * Gets the average width of the characters in the English alphabet.
5067 * hdc [I] Handle to the device context to measure on.
5068 * lptm [O] Pointer to memory to store the text metrics into.
5069 * height [O] On exit, the maximum height of characters in the English alphabet.
5072 * The average width of characters in the English alphabet.
5075 * This function is used by the dialog manager to get the size of a dialog
5076 * unit. It should also be used by other pieces of code that need to know
5077 * the size of a dialog unit in logical units without having access to the
5078 * window handle of the dialog.
5079 * Windows caches the font metrics from this function, but we don't and
5080 * there doesn't appear to be an immediate advantage to do so.
5083 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
5085 LONG WINAPI
GdiGetCharDimensions(HDC hdc
, LPTEXTMETRICW lptm
, LONG
*height
)
5088 static const WCHAR alphabet
[] = {
5089 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
5090 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
5091 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
5093 if(lptm
&& !GetTextMetricsW(hdc
, lptm
)) return 0;
5095 if(!GetTextExtentPointW(hdc
, alphabet
, 52, &sz
)) return 0;
5097 if (height
) *height
= sz
.cy
;
5098 return (sz
.cx
/ 26 + 1) / 2;
5101 BOOL WINAPI
EnableEUDC(BOOL fEnableEUDC
)
5103 FIXME("(%d): stub\n", fEnableEUDC
);
5107 /***********************************************************************
5108 * GetCharWidthI (GDI32.@)
5110 * Retrieve widths of characters.
5113 * hdc [I] Handle to a device context.
5114 * first [I] First glyph in range to query.
5115 * count [I] Number of glyph indices to query.
5116 * glyphs [I] Array of glyphs to query.
5117 * buffer [O] Buffer to receive character widths.
5120 * Only works with TrueType fonts.
5126 BOOL WINAPI
GetCharWidthI(HDC hdc
, UINT first
, UINT count
, LPWORD glyphs
, LPINT buffer
)
5131 TRACE("(%p, %d, %d, %p, %p)\n", hdc
, first
, count
, glyphs
, buffer
);
5133 if (!(abc
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(ABC
))))
5136 if (!GetCharABCWidthsI(hdc
, first
, count
, glyphs
, abc
))
5138 HeapFree(GetProcessHeap(), 0, abc
);
5142 for (i
= 0; i
< count
; i
++)
5143 buffer
[i
] = abc
[i
].abcA
+ abc
[i
].abcB
+ abc
[i
].abcC
;
5145 HeapFree(GetProcessHeap(), 0, abc
);
5149 /***********************************************************************
5150 * GetFontUnicodeRanges (GDI32.@)
5152 * Retrieve a list of supported Unicode characters in a font.
5155 * hdc [I] Handle to a device context.
5156 * lpgs [O] GLYPHSET structure specifying supported character ranges.
5159 * Success: Number of bytes written to the buffer pointed to by lpgs.
5163 DWORD WINAPI
GetFontUnicodeRanges(HDC hdc
, LPGLYPHSET lpgs
)
5167 DC
*dc
= get_dc_ptr(hdc
);
5169 TRACE("(%p, %p)\n", hdc
, lpgs
);
5173 dev
= GET_DC_PHYSDEV( dc
, pGetFontUnicodeRanges
);
5174 ret
= dev
->funcs
->pGetFontUnicodeRanges( dev
, lpgs
);
5180 /*************************************************************
5181 * FontIsLinked (GDI32.@)
5183 BOOL WINAPI
FontIsLinked(HDC hdc
)
5185 DC
*dc
= get_dc_ptr(hdc
);
5189 if (!dc
) return FALSE
;
5190 dev
= GET_DC_PHYSDEV( dc
, pFontIsLinked
);
5191 ret
= dev
->funcs
->pFontIsLinked( dev
);
5193 TRACE("returning %d\n", ret
);
5197 /*************************************************************
5198 * GetFontRealizationInfo (GDI32.@)
5200 BOOL WINAPI
GetFontRealizationInfo(HDC hdc
, struct font_realization_info
*info
)
5202 BOOL is_v0
= info
->size
== FIELD_OFFSET(struct font_realization_info
, unk
);
5207 if (info
->size
!= sizeof(*info
) && !is_v0
)
5210 dc
= get_dc_ptr(hdc
);
5211 if (!dc
) return FALSE
;
5212 dev
= GET_DC_PHYSDEV( dc
, pGetFontRealizationInfo
);
5213 ret
= dev
->funcs
->pGetFontRealizationInfo( dev
, info
);
5218 /*************************************************************************
5219 * GetRasterizerCaps (GDI32.@)
5221 BOOL WINAPI
GetRasterizerCaps( LPRASTERIZER_STATUS lprs
, UINT cbNumBytes
)
5223 lprs
->nSize
= sizeof(RASTERIZER_STATUS
);
5224 lprs
->wFlags
= font_funcs
? (TT_AVAILABLE
| TT_ENABLED
) : 0;
5225 lprs
->nLanguageID
= 0;
5229 /*************************************************************************
5230 * GetFontFileData (GDI32.@)
5232 BOOL WINAPI
GetFontFileData( DWORD instance_id
, DWORD unknown
, UINT64 offset
, void *buff
, DWORD buff_size
)
5234 struct gdi_font
*font
= get_font_from_handle( instance_id
);
5236 if (!font_funcs
|| !font
) return FALSE
;
5237 return font_funcs
->pGetFontFileData( font
, unknown
, offset
, buff
, buff_size
);
5240 /*************************************************************************
5241 * GetFontFileInfo (GDI32.@)
5243 BOOL WINAPI
GetFontFileInfo( DWORD instance_id
, DWORD unknown
, struct font_fileinfo
*info
,
5244 SIZE_T size
, SIZE_T
*needed
)
5246 SIZE_T required_size
;
5247 struct gdi_font
*font
= get_font_from_handle( instance_id
);
5249 if (!needed
) needed
= &required_size
;
5256 *needed
= sizeof(*info
) + strlenW( font
->fileinfo
->path
) * sizeof(WCHAR
);
5259 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
5262 memcpy( info
, font
->fileinfo
, *needed
);
5266 struct realization_info
5268 DWORD flags
; /* 1 for bitmap fonts, 3 for scalable fonts */
5269 DWORD cache_num
; /* keeps incrementing - num of fonts that have been created allowing for caching?? */
5270 DWORD instance_id
; /* identifies a realized font instance */
5273 /*************************************************************
5274 * GdiRealizationInfo (GDI32.@)
5276 * Returns a structure that contains some font information.
5278 BOOL WINAPI
GdiRealizationInfo(HDC hdc
, struct realization_info
*info
)
5280 struct font_realization_info ri
;
5283 ri
.size
= sizeof(ri
);
5284 ret
= GetFontRealizationInfo( hdc
, &ri
);
5287 info
->flags
= ri
.flags
;
5288 info
->cache_num
= ri
.cache_num
;
5289 info
->instance_id
= ri
.instance_id
;
5295 /*************************************************************
5296 * GetCharWidthInfo (GDI32.@)
5299 BOOL WINAPI
GetCharWidthInfo(HDC hdc
, struct char_width_info
*info
)
5305 dc
= get_dc_ptr(hdc
);
5306 if (!dc
) return FALSE
;
5307 dev
= GET_DC_PHYSDEV( dc
, pGetCharWidthInfo
);
5308 ret
= dev
->funcs
->pGetCharWidthInfo( dev
, info
);
5312 info
->lsb
= width_to_LP( dc
, info
->lsb
);
5313 info
->rsb
= width_to_LP( dc
, info
->rsb
);