gdi32: Move more font metrics information to the generic font structure.
[wine.git] / dlls / gdi32 / font.c
blob31c9d1561a517e9a6b262bfd093c175f75bdb0b8
1 /*
2 * GDI font objects
4 * Copyright 1993 Alexandre Julliard
5 * 1997 Alex Korobka
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <limits.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <assert.h>
31 #include "winerror.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "winreg.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;
47 struct font_physdev
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)
67 double floatWidth;
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)
80 double floatHeight;
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)
102 POINT pt[2];
103 pt[0].x = pt[0].y = 0;
104 pt[1].x = 0;
105 pt[1].y = height;
106 lp_to_dp(dc, pt, 2);
107 return pt[1].y - pt[0].y;
110 static inline WCHAR *strdupW( const WCHAR *p )
112 WCHAR *ret;
113 DWORD len = (strlenW(p) + 1) * sizeof(WCHAR);
114 ret = HeapAlloc(GetProcessHeap(), 0, len);
115 memcpy(ret, p, len);
116 return ret;
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 */
133 typedef struct
135 LOGFONTW logfont;
136 } FONTOBJ;
138 struct font_enum
140 LPLOGFONTW lpLogFontParam;
141 FONTENUMPROCW lpEnumFunc;
142 LPARAM lpData;
143 BOOL unicode;
144 HDC hdc;
145 INT retval;
149 * For TranslateCharsetInfo
151 #define MAXTCIINDEX 32
152 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
153 /* ANSI */
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}} },
171 /* ANSI and OEM */
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 */
232 /* Eastern Europe */
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" }
243 /* Cyrillic */
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" }
254 /* Greek */
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" }
265 /* Turkish */
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" }
276 /* Hebrew */
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"
284 /* Arabic */
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"
292 /* Baltic */
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" }
303 /* Vietnamese */
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 */
308 /* Thai */
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 */
313 /* Japanese */
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",
321 "SimSun", "NSimSun"
323 /* Korean */
324 { 949, 949, "vga949.fon", "hvgafix.fon", "hvgasys.fon",
325 "coure.fon", "serife.fon", "smalle.fon", "sserife.fon", "sseriff.fon",
326 "Gulim", "Batang"
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 );
368 return NULL;
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 );
377 return NULL;
380 static DWORD alloc_font_handle( struct gdi_font *font )
382 struct font_handle_entry *entry;
384 entry = next_free;
385 if (entry)
386 next_free = (struct font_handle_entry *)entry->font;
387 else if (next_unused < font_handles + MAX_FONT_HANDLES)
388 entry = next_unused++;
389 else
391 ERR( "out of realized font handles\n" );
392 return 0;
394 entry->font = font;
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;
406 next_free = entry;
410 struct gdi_font *alloc_gdi_font(void)
412 struct gdi_font *font = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*font) );
414 font->refcount = 1;
415 font->matrix.eM11 = font->matrix.eM22 = 1.0;
416 font->scale_y = 1.0;
418 if (!(font->handle = alloc_font_handle( font )))
420 HeapFree( GetProcessHeap(), 0, font );
421 return NULL;
423 if (font_funcs && !font_funcs->alloc_font( font ))
425 free_gdi_font( font );
426 return NULL;
428 return 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 */
446 struct font_fileinfo
448 FILETIME writetime;
449 LARGE_INTEGER size;
450 WCHAR path[1];
453 void set_gdi_font_file_info( struct gdi_font *font, const WCHAR *file, SIZE_T data_size )
455 WIN32_FILE_ATTRIBUTE_DATA info;
456 int len = 0;
458 if (file) len = strlenW( file );
459 if (!(font->fileinfo = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
460 offsetof( struct font_fileinfo, path[len + 1] ))))
461 return;
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;
472 /* font cache */
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;
492 WORD *pwc;
493 unsigned int i;
495 for (i = 0, ptr = (DWORD *)matrix; i < sizeof(*matrix) / sizeof(DWORD); i++, ptr++)
496 hash ^= *ptr;
497 for(i = 0, ptr = (DWORD *)lf; i < 7; i++, ptr++)
498 hash ^= *ptr;
499 for(i = 0, ptr = (DWORD *)lf->lfFaceName; i < LF_FACESIZE/2; i++, ptr++)
501 two_chars = *ptr;
502 pwc = (WCHAR *)&two_chars;
503 if(!*pwc) break;
504 *pwc = toupperW(*pwc);
505 pwc++;
506 *pwc = toupperW(*pwc);
507 hash ^= two_chars;
508 if(!*pwc) break;
510 hash ^= !can_use_bitmap;
511 return hash;
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 );
538 unused_font_count--;
540 return font;
542 return NULL;
545 static void release_gdi_font( struct gdi_font *font )
547 if (!font) return;
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 );
561 return;
563 unused_font_count++;
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)
578 if (value)
579 RegSetValueExA(hkey, name, 0, REG_SZ, (const BYTE *)value, strlen(value) + 1);
580 else if (name)
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))
591 HKEY hkey;
592 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, font_assoc_reg_key, &hkey) == ERROR_SUCCESS)
594 HKEY hsubkey;
595 if (RegCreateKeyA(hkey, assoc_charset_subkey, &hsubkey) == ERROR_SUCCESS)
597 switch (current_ansi_codepage)
599 case 932:
600 set_value_key(hsubkey, "ANSI(00)", "NO");
601 set_value_key(hsubkey, "OEM(FF)", "NO");
602 set_value_key(hsubkey, "SYMBOL(02)", "NO");
603 break;
604 case 936:
605 case 949:
606 case 950:
607 set_value_key(hsubkey, "ANSI(00)", "YES");
608 set_value_key(hsubkey, "OEM(FF)", "YES");
609 set_value_key(hsubkey, "SYMBOL(02)", "NO");
610 break;
612 RegCloseKey(hsubkey);
615 /* TODO: Associated DefaultFonts */
617 RegCloseKey(hkey);
620 else
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)
626 if (value)
627 RegSetValueExW(hkey, name, 0, REG_MULTI_SZ, (const BYTE *)value, len);
628 else if (name)
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',
639 '\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',
645 '\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',
651 '\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',
657 '\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',
663 '\0'};
664 HKEY hkey;
666 if (RegCreateKeyW(HKEY_LOCAL_MACHINE, system_link, &hkey) == ERROR_SUCCESS)
668 const WCHAR *link;
669 DWORD len;
671 switch (current_ansi_codepage)
673 case 932:
674 link = system_link_japanese;
675 len = sizeof(system_link_japanese);
676 break;
677 case 936:
678 link = system_link_simplified_chinese;
679 len = sizeof(system_link_simplified_chinese);
680 break;
681 case 949:
682 link = system_link_korean;
683 len = sizeof(system_link_korean);
684 break;
685 case 950:
686 link = system_link_traditional_chinese;
687 len = sizeof(system_link_traditional_chinese);
688 break;
689 default:
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);
696 RegCloseKey(hkey);
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];
704 HKEY hkey;
705 DWORD len, type, size;
706 UINT i, ansi_cp, oem_cp;
707 DWORD screen_dpi, font_dpi = 0;
708 BOOL done = FALSE;
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))
716 font_dpi = 0;
718 ansi_cp = GetACP();
719 oem_cp = GetOEMCP();
720 sprintf( cpbuf, "%u,%u", ansi_cp, oem_cp );
722 buf[0] = 0;
723 len = sizeof(buf);
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);
748 RegCloseKey(hkey);
750 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, winnt_font_reg_key, &hkey ))
752 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
753 RegCloseKey(hkey);
755 if (!RegCreateKeyW( HKEY_LOCAL_MACHINE, win9x_font_reg_key, &hkey ))
757 add_font_list(hkey, &nls_update_font_list[i], screen_dpi);
758 RegCloseKey(hkey);
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);
780 RegCloseKey(hkey);
782 done = TRUE;
784 else
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);
792 RegCloseKey(hkey);
796 if (!done)
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 /*************************************************************
810 * font_CreateDC
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 );
820 return TRUE;
824 /*************************************************************
825 * font_DeleteDC
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 );
833 return TRUE;
837 /*************************************************************
838 * font_EnumFonts
840 static BOOL CDECL font_EnumFonts( PHYSDEV dev, LOGFONTW *lf, FONTENUMPROCW proc, LPARAM lparam )
842 return font_funcs->pEnumFonts( lf, proc, lparam );
846 /*************************************************************
847 * font_FontIsLinked
849 static BOOL CDECL font_FontIsLinked( PHYSDEV dev )
851 struct font_physdev *physdev = get_font_dev( dev );
853 if (!physdev->font)
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 );
869 if (!physdev->font)
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 );
885 if (!physdev->font)
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 /*************************************************************
895 * font_GetCharWidth
897 static BOOL CDECL font_GetCharWidth( PHYSDEV dev, UINT first, UINT last, INT *buffer )
899 struct font_physdev *physdev = get_font_dev( dev );
901 if (!physdev->font)
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 );
917 if (!physdev->font)
919 dev = GET_NEXT_PHYSDEV( dev, pGetCharWidthInfo );
920 return dev->funcs->pGetCharWidthInfo( dev, ptr );
922 return font_funcs->pGetCharWidthInfo( physdev->font, ptr );
926 /*************************************************************
927 * font_GetFontData
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 );
933 if (!physdev->font)
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;
950 if (!physdev->font)
952 dev = GET_NEXT_PHYSDEV( dev, pGetFontRealizationInfo );
953 return dev->funcs->pGetFontRealizationInfo( dev, ptr );
956 TRACE( "(%p, %p)\n", physdev->font, info);
958 info->flags = 1;
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))
965 info->unk = 0;
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;
971 return TRUE;
975 /*************************************************************
976 * font_GetFontUnicodeRanges
978 static DWORD CDECL font_GetFontUnicodeRanges( PHYSDEV dev, GLYPHSET *glyphset )
980 struct font_physdev *physdev = get_font_dev( dev );
982 if (!physdev->font)
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 );
998 if (!physdev->font)
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 );
1015 if (!physdev->font)
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 );
1031 if (!physdev->font)
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 );
1047 if (!physdev->font)
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 );
1063 if (!physdev->font)
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 );
1080 if (!physdev->font)
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 );
1096 if (!physdev->font)
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 /*************************************************************
1106 * font_GetTextFace
1108 static INT CDECL font_GetTextFace( PHYSDEV dev, INT count, WCHAR *str )
1110 struct font_physdev *physdev = get_font_dev( dev );
1111 INT len;
1113 if (!physdev->font)
1115 dev = GET_NEXT_PHYSDEV( dev, pGetTextFace );
1116 return dev->funcs->pGetTextFace( dev, count, str );
1118 len = strlenW( physdev->font->name ) + 1;
1119 if (str)
1121 lstrcpynW( str, physdev->font->name, count );
1122 len = min( count, len );
1124 return len;
1128 /*************************************************************
1129 * font_GetTextMetrics
1131 static BOOL CDECL font_GetTextMetrics( PHYSDEV dev, TEXTMETRICW *metrics )
1133 struct font_physdev *physdev = get_font_dev( dev );
1135 if (!physdev->font)
1137 dev = GET_NEXT_PHYSDEV( dev, pGetTextMetrics );
1138 return dev->funcs->pGetTextMetrics( dev, metrics );
1140 return font_funcs->pGetTextMetrics( physdev->font, metrics );
1144 /*************************************************************
1145 * font_SelectFont
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;
1161 else
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 */
1175 NULL, /* pArc */
1176 NULL, /* pArcTo */
1177 NULL, /* pBeginPath */
1178 NULL, /* pBlendImage */
1179 NULL, /* pChord */
1180 NULL, /* pCloseFigure */
1181 NULL, /* pCreateCompatibleDC */
1182 font_CreateDC, /* pCreateDC */
1183 font_DeleteDC, /* pDeleteDC */
1184 NULL, /* pDeleteObject */
1185 NULL, /* pDeviceCapabilities */
1186 NULL, /* pEllipse */
1187 NULL, /* pEndDoc */
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 */
1231 NULL, /* pLineTo */
1232 NULL, /* pModifyWorldTransform */
1233 NULL, /* pMoveTo */
1234 NULL, /* pOffsetClipRgn */
1235 NULL, /* pOffsetViewportOrg */
1236 NULL, /* pOffsetWindowOrg */
1237 NULL, /* pPaintRgn */
1238 NULL, /* pPatBlt */
1239 NULL, /* pPie */
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 */
1255 NULL, /* pSaveDC */
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 /***********************************************************************
1306 * font_init
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 ))
1312 return;
1314 update_codepage();
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,
1323 LF_FACESIZE);
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);
1392 else
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 )
1419 WCHAR buf[12];
1420 DWORD count = sizeof(buf), type, err;
1422 err = RegQueryValueExW( key, name, NULL, &type, (BYTE *)buf, &count );
1423 if (!err)
1425 if (type == REG_DWORD) memcpy( value, buf, sizeof(*value) );
1426 else *value = atoiW( buf );
1428 return err;
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};
1435 DWORD orient;
1437 /* FIXME: handle vertical orientations even though Windows doesn't */
1438 if (get_key_value( key, smoothing_orientation, &orient )) return GGO_GRAY4_BITMAP;
1440 switch (orient)
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 )
1468 TEXTMETRICW tm;
1469 PHYSDEV dev;
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;
1489 if (rem > 0)
1491 space++;
1492 rem--;
1495 dx[i] += space;
1498 size->cx = dx[count - 1];
1499 size->cy = tm.tmHeight;
1500 return TRUE;
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 )
1506 TEXTMETRICW tm;
1507 PHYSDEV dev;
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)
1520 WORD space_index;
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;
1531 if (rem > 0)
1533 space++;
1534 rem--;
1537 dx[i] += space;
1540 size->cx = dx[count - 1];
1541 size->cy = tm.tmHeight;
1542 return TRUE;
1545 /***********************************************************************
1546 * GdiGetCodePage (GDI32.@)
1548 DWORD WINAPI GdiGetCodePage( HDC hdc )
1550 UINT cp = CP_ACP;
1551 DC *dc = get_dc_ptr( hdc );
1553 if (dc)
1555 cp = dc->font_code_page;
1556 release_dc_ptr( dc );
1558 return cp;
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;
1569 PHYSDEV dev;
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));
1576 return ret;
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);
1587 if (dc)
1589 ret = get_text_charset_info( dc, fs, flags );
1590 release_dc_ptr( dc );
1592 return ret;
1595 /***********************************************************************
1596 * FONT_mbtowc
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
1605 * itself.
1607 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
1609 UINT cp;
1610 INT lenW;
1611 LPWSTR strW;
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;
1621 if(pCP) *pCP = cp;
1622 return strW;
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 )
1644 HFONT hFont;
1645 FONTOBJ *fontPtr;
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 );
1668 return 0;
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);
1682 return hFont;
1685 /***********************************************************************
1686 * CreateFontIndirectA (GDI32.@)
1688 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *plfA )
1690 LOGFONTW lfW;
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;
1705 if (!plf) return 0;
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 )
1723 LOGFONTA logfont;
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;
1739 if (name)
1740 lstrcpynA(logfont.lfFaceName,name,sizeof(logfont.lfFaceName));
1741 else
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 )
1756 LOGFONTW logfont;
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;
1772 if (name)
1773 lstrcpynW(logfont.lfFaceName, name, ARRAY_SIZE(logfont.lfFaceName));
1774 else
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'};
1798 HKEY hkey;
1799 WCHAR dataW[32];
1800 DWORD type, data_len;
1802 associated_charset = 0;
1804 if (RegOpenKeyW(HKEY_LOCAL_MACHINE,
1805 assoc_charset_reg_keyW, &hkey) != ERROR_SUCCESS)
1806 return 0;
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;
1823 RegCloseKey(hkey);
1825 TRACE("associated_charset = %d\n", associated_charset);
1828 return associated_charset;
1831 static void update_font_code_page( DC *dc, HANDLE font )
1833 CHARSETINFO csi;
1834 int charset = get_text_charset_info( dc, NULL, 0 );
1836 if (charset == ANSI_CHARSET && get_associated_charset_info() & ASSOC_CHARSET_ANSI)
1838 LOGFONTW lf;
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;
1848 else {
1849 switch(charset) {
1850 case OEM_CHARSET:
1851 dc->font_code_page = GetOEMCP();
1852 break;
1853 case DEFAULT_CHARSET:
1854 dc->font_code_page = GetACP();
1855 break;
1857 case VISCII_CHARSET:
1858 case TCVN_CHARSET:
1859 case KOI8_CHARSET:
1860 case ISO3_CHARSET:
1861 case ISO4_CHARSET:
1862 case ISO10_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;
1872 break;
1874 default:
1875 FIXME("Can't find codepage for charset %d\n", charset);
1876 dc->font_code_page = CP_ACP;
1877 break;
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;
1892 DWORD i, gamma;
1893 HKEY key;
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;
1900 RegCloseKey( key );
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);
1919 return TRUE;
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 );
1928 return &ramp;
1931 /***********************************************************************
1932 * FONT_SelectObject
1934 static HGDIOBJ FONT_SelectObject( HGDIOBJ handle, HDC hdc )
1936 HGDIOBJ ret = 0;
1937 DC *dc = get_dc_ptr( hdc );
1938 PHYSDEV physdev;
1939 UINT aa_flags = 0;
1941 if (!dc) return 0;
1943 if (!GDI_inc_ref_count( handle ))
1945 release_dc_ptr( dc );
1946 return 0;
1949 physdev = GET_DC_PHYSDEV( dc, pSelectFont );
1950 if (physdev->funcs->pSelectFont( physdev, handle, &aa_flags ))
1952 ret = dc->hFont;
1953 dc->hFont = handle;
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 );
1963 return ret;
1967 /***********************************************************************
1968 * FONT_GetObjectA
1970 static INT FONT_GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
1972 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
1973 LOGFONTA lfA;
1975 if (!font) return 0;
1976 if (buffer)
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 );
1984 return count;
1987 /***********************************************************************
1988 * FONT_GetObjectW
1990 static INT FONT_GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
1992 FONTOBJ *font = GDI_GetObjPtr( handle, OBJ_FONT );
1994 if (!font) return 0;
1995 if (buffer)
1997 if (count > sizeof(LOGFONTW)) count = sizeof(LOGFONTW);
1998 memcpy( buffer, &font->logfont, count );
2000 else count = sizeof(LOGFONTW);
2001 GDI_ReleaseObj( handle );
2002 return count;
2006 /***********************************************************************
2007 * FONT_DeleteObject
2009 static BOOL FONT_DeleteObject( HGDIOBJ handle )
2011 FONTOBJ *obj;
2013 if (!(obj = free_gdi_handle( handle ))) return FALSE;
2014 HeapFree( GetProcessHeap(), 0, obj );
2015 return TRUE;
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;
2027 LOGFONTW lf;
2028 HKEY key;
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;
2037 break;
2038 case ANTIALIASED_QUALITY:
2039 *aa_flags = GGO_GRAY4_BITMAP;
2040 break;
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 );
2047 RegCloseKey( key );
2049 *aa_flags = orientation;
2050 break;
2051 default:
2052 if (smoothing == -1)
2054 if (RegOpenKeyW( HKEY_CURRENT_USER, desktopW, &key )) break;
2055 smoothing = get_default_smoothing( key );
2056 RegCloseKey( key );
2058 *aa_flags = smoothing;
2059 break;
2061 return 0;
2065 /***********************************************************************
2066 * FONT_EnumInstance
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;
2075 INT ret = 1;
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;
2087 if (!pfe->unicode)
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 );
2095 pfe->retval = ret;
2097 return ret;
2100 /***********************************************************************
2101 * FONT_EnumFontFamiliesEx
2103 static INT FONT_EnumFontFamiliesEx( HDC hDC, LPLOGFONTW plf, FONTENUMPROCW efproc,
2104 LPARAM lParam, BOOL unicode )
2106 INT ret = 0;
2107 DC *dc = get_dc_ptr( hDC );
2108 struct font_enum fe;
2110 if (dc)
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;
2117 fe.lpData = lParam;
2118 fe.unicode = unicode;
2119 fe.hdc = hDC;
2120 fe.retval = 1;
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;
2146 if (plf)
2148 FONT_LogFontAToW( plf, &lfW );
2149 plfW = &lfW;
2151 else plfW = NULL;
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 )
2162 LOGFONTA lf, *plf;
2164 if (lpFamily)
2166 if (!*lpFamily) return 1;
2167 lstrcpynA( lf.lfFaceName, lpFamily, LF_FACESIZE );
2168 lf.lfCharSet = DEFAULT_CHARSET;
2169 lf.lfPitchAndFamily = 0;
2170 plf = &lf;
2172 else plf = NULL;
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 )
2183 LOGFONTW lf, *plf;
2185 if (lpFamily)
2187 if (!*lpFamily) return 1;
2188 lstrcpynW( lf.lfFaceName, lpFamily, LF_FACESIZE );
2189 lf.lfCharSet = DEFAULT_CHARSET;
2190 lf.lfPitchAndFamily = 0;
2191 plf = &lf;
2193 else plf = NULL;
2195 return EnumFontFamiliesExW( hDC, plf, efproc, lpData, 0 );
2198 /***********************************************************************
2199 * EnumFontsA (GDI32.@)
2201 INT WINAPI EnumFontsA( HDC hDC, LPCSTR lpName, FONTENUMPROCA efproc,
2202 LPARAM lpData )
2204 return EnumFontFamiliesA( hDC, lpName, efproc, lpData );
2207 /***********************************************************************
2208 * EnumFontsW (GDI32.@)
2210 INT WINAPI EnumFontsW( HDC hDC, LPCWSTR lpName, FONTENUMPROCW efproc,
2211 LPARAM lpData )
2213 return EnumFontFamiliesW( hDC, lpName, efproc, lpData );
2217 /***********************************************************************
2218 * GetTextCharacterExtra (GDI32.@)
2220 INT WINAPI GetTextCharacterExtra( HDC hdc )
2222 INT ret;
2223 DC *dc = get_dc_ptr( hdc );
2224 if (!dc) return 0x80000000;
2225 ret = dc->charExtra;
2226 release_dc_ptr( dc );
2227 return ret;
2231 /***********************************************************************
2232 * SetTextCharacterExtra (GDI32.@)
2234 INT WINAPI SetTextCharacterExtra( HDC hdc, INT extra )
2236 INT ret = 0x80000000;
2237 DC * dc = get_dc_ptr( hdc );
2239 if (dc)
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 );
2250 return ret;
2254 /***********************************************************************
2255 * SetTextJustification (GDI32.@)
2257 BOOL WINAPI SetTextJustification( HDC hdc, INT extra, INT breaks )
2259 BOOL ret;
2260 PHYSDEV physdev;
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 );
2267 if (ret)
2269 extra = abs((extra * dc->vport_ext.cx + dc->wnd_ext.cx / 2) / dc->wnd_ext.cx);
2270 if (!extra) breaks = 0;
2271 if (breaks)
2273 dc->breakExtra = extra / breaks;
2274 dc->breakRem = extra - (breaks * dc->breakExtra);
2276 else
2278 dc->breakExtra = 0;
2279 dc->breakRem = 0;
2282 release_dc_ptr( dc );
2283 return ret;
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 );
2296 if (name)
2298 if (count)
2300 res = WideCharToMultiByte(CP_ACP, 0, nameW, -1, name, count, NULL, NULL);
2301 if (res == 0)
2302 res = count;
2303 name[count-1] = 0;
2304 /* GetTextFaceA does NOT include the nul byte in the return count. */
2305 res--;
2307 else
2308 res = 0;
2310 else
2311 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
2312 HeapFree( GetProcessHeap(), 0, nameW );
2313 return res;
2316 /***********************************************************************
2317 * GetTextFaceW (GDI32.@)
2319 INT WINAPI GetTextFaceW( HDC hdc, INT count, LPWSTR name )
2321 PHYSDEV dev;
2322 INT ret;
2324 DC * dc = get_dc_ptr( hdc );
2325 if (!dc) return 0;
2327 dev = GET_DC_PHYSDEV( dc, pGetTextFace );
2328 ret = dev->funcs->pGetTextFace( dev, count, name );
2329 release_dc_ptr( dc );
2330 return ret;
2334 /***********************************************************************
2335 * GetTextExtentPoint32A (GDI32.@)
2337 * See GetTextExtentPoint32W.
2339 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, LPCSTR str, INT count,
2340 LPSIZE size )
2342 BOOL ret = FALSE;
2343 INT wlen;
2344 LPWSTR p;
2346 if (count < 0) return FALSE;
2348 p = FONT_mbtowc(hdc, str, count, &wlen, NULL);
2350 if (p)
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 );
2358 return ret;
2362 /***********************************************************************
2363 * GetTextExtentPoint32W [GDI32.@]
2365 * Computes width/height for a string.
2367 * Computes width and height of the specified string.
2369 * RETURNS
2370 * Success: TRUE
2371 * Failure: FALSE
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.
2387 * PARAMS
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.
2396 * RETURNS
2397 * Success: TRUE
2398 * Failure: FALSE
2400 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
2401 LPINT nfit, LPINT dxs, LPSIZE size )
2403 DC *dc;
2404 int i;
2405 BOOL ret;
2406 INT buffer[256], *pos = dxs;
2408 if (count < 0) return FALSE;
2410 dc = get_dc_ptr( hdc );
2411 if (!dc) return FALSE;
2413 if (!dxs)
2415 pos = buffer;
2416 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
2418 release_dc_ptr( dc );
2419 return FALSE;
2423 ret = get_char_positions_indices( dc, indices, count, pos, size );
2424 if (ret)
2426 if (dxs || nfit)
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 );
2446 return ret;
2449 /***********************************************************************
2450 * GetTextExtentPointI [GDI32.@]
2452 * Computes width and height of the array of glyph indices.
2454 * PARAMS
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.
2460 * RETURNS
2461 * Success: TRUE
2462 * Failure: FALSE
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,
2474 LPSIZE size )
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,
2484 LPSIZE size )
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 )
2498 BOOL ret;
2499 INT wlen;
2500 INT *walpDx = NULL;
2501 LPWSTR p = NULL;
2503 if (count < 0) return FALSE;
2504 if (maxExt < -1) return FALSE;
2506 if (alpDx)
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);
2514 if (walpDx)
2516 INT n = lpnFit ? *lpnFit : wlen;
2517 INT i, j;
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 );
2527 return ret;
2531 /***********************************************************************
2532 * GetTextExtentExPointW (GDI32.@)
2534 * Return the size of the string as it would be if it was output properly by
2535 * e.g. TextOut.
2537 BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext,
2538 LPINT nfit, LPINT dxs, LPSIZE size )
2540 DC *dc;
2541 int i;
2542 BOOL ret;
2543 INT buffer[256], *pos = dxs;
2545 if (count < 0) return FALSE;
2547 dc = get_dc_ptr(hdc);
2548 if (!dc) return FALSE;
2550 if (!dxs)
2552 pos = buffer;
2553 if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) )))
2555 release_dc_ptr( dc );
2556 return FALSE;
2560 ret = get_char_positions( dc, str, count, pos, size );
2561 if (ret)
2563 if (dxs || nfit)
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 );
2582 return ret;
2585 /***********************************************************************
2586 * GetTextMetricsA (GDI32.@)
2588 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
2590 TEXTMETRICW tm32;
2592 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
2593 FONT_TextMetricWToA( &tm32, metrics );
2594 return TRUE;
2597 /***********************************************************************
2598 * GetTextMetricsW (GDI32.@)
2600 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
2602 PHYSDEV physdev;
2603 BOOL ret = FALSE;
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 );
2610 if (ret)
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 );
2625 ret = TRUE;
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"
2635 " Ascent = %i\n"
2636 " Descent = %i\n"
2637 " Height = %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,
2644 metrics->tmAscent,
2645 metrics->tmDescent,
2646 metrics->tmHeight );
2648 release_dc_ptr( dc );
2649 return ret;
2653 /***********************************************************************
2654 * GetOutlineTextMetricsA (GDI32.@)
2655 * Gets metrics for TrueType fonts.
2657 * NOTES
2658 * If the supplied buffer isn't big enough Windows partially fills it up to
2659 * its given length and returns that length.
2661 * RETURNS
2662 * Success: Non-zero or size of required buffer
2663 * Failure: 0
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;
2671 UINT ret, needed;
2672 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
2673 OUTLINETEXTMETRICA *output = lpOTM;
2674 INT left, len;
2676 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
2677 return 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);
2700 if(!lpOTM) {
2701 ret = needed;
2702 goto end;
2705 TRACE("needed = %d\n", needed);
2706 if(needed > cbData)
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
2709 the end. */
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);
2750 left -= len;
2751 ptr += len;
2752 } else
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);
2760 left -= len;
2761 ptr += len;
2762 } else
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);
2770 left -= len;
2771 ptr += len;
2772 } else
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);
2780 left -= len;
2781 } else
2782 output->otmpFullName = 0;
2784 assert(left == 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 */
2821 end:
2822 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
2823 HeapFree(GetProcessHeap(), 0, lpOTMW);
2825 return ret;
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;
2839 PHYSDEV dev;
2840 UINT ret;
2842 TRACE("(%p,%d,%p)\n", hdc, cbData, lpOTM);
2843 if(!dc) return 0;
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 );
2854 if (lpOTM && ret)
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);
2891 if(output != lpOTM)
2893 memcpy(lpOTM, output, cbData);
2894 HeapFree(GetProcessHeap(), 0, output);
2895 ret = cbData;
2898 release_dc_ptr(dc);
2899 return ret;
2902 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
2904 INT i, count = lastChar - firstChar + 1;
2905 UINT mbcp;
2906 UINT c;
2907 LPSTR str;
2909 if (count <= 0)
2910 return NULL;
2912 mbcp = GdiGetCodePage(hdc);
2913 switch (mbcp)
2915 case 932:
2916 case 936:
2917 case 949:
2918 case 950:
2919 case 1361:
2920 if (lastChar > 0xffff)
2921 return NULL;
2922 if ((firstChar ^ lastChar) > 0xff)
2923 return NULL;
2924 break;
2925 default:
2926 if (lastChar > 0xff)
2927 return NULL;
2928 mbcp = 0;
2929 break;
2932 str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
2933 if (str == NULL)
2934 return NULL;
2936 for(i = 0, c = firstChar; c <= lastChar; i++, c++)
2938 if (mbcp) {
2939 if (c > 0xff)
2940 str[i++] = (BYTE)(c >> 8);
2941 if (c <= 0xff && IsDBCSLeadByteEx(mbcp, c))
2942 str[i] = 0x1f; /* FIXME: use default character */
2943 else
2944 str[i] = (BYTE)c;
2946 else
2947 str[i] = (BYTE)c;
2949 str[i] = '\0';
2951 *pByteLen = i;
2953 return str;
2956 /***********************************************************************
2957 * GetCharWidthW (GDI32.@)
2958 * GetCharWidth32W (GDI32.@)
2960 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT firstChar, UINT lastChar,
2961 LPINT buffer )
2963 UINT i;
2964 BOOL ret;
2965 PHYSDEV dev;
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 );
2973 if (ret)
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 );
2980 return ret;
2984 /***********************************************************************
2985 * GetCharWidthA (GDI32.@)
2986 * GetCharWidth32A (GDI32.@)
2988 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT firstChar, UINT lastChar,
2989 LPINT buffer )
2991 INT i, wlen;
2992 LPSTR str;
2993 LPWSTR wstr;
2994 BOOL ret = TRUE;
2996 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
2997 if(str == NULL)
2998 return FALSE;
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))
3006 ret = FALSE;
3007 break;
3009 buffer++;
3012 HeapFree(GetProcessHeap(), 0, str);
3013 HeapFree(GetProcessHeap(), 0, wstr);
3015 return ret;
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};
3025 unsigned int i;
3026 DWORD ret, size;
3027 int stride;
3029 indices[0] = index;
3030 if (flags & ETO_GLYPH_INDEX) aa_flags |= GGO_GLYPH_INDEX;
3032 for (i = 0; i < ARRAY_SIZE( indices ); i++)
3034 index = 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;
3042 image->ptr = NULL;
3043 image->free = NULL;
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 )
3070 UINT i;
3071 RECT rect, bounds;
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 );
3086 if (dx)
3088 if (flags & ETO_PDY)
3090 x += dx[ i * 2 ];
3091 y += dx[ i * 2 + 1];
3093 else x += dx[ i ];
3095 else
3097 x += metrics.gmCellIncX;
3098 y += metrics.gmCellIncY;
3101 return bounds;
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;
3110 LONG x, y;
3111 BYTE *ptr = image->ptr;
3112 int stride = get_dib_stride( metrics->gmBlackBoxX, 1 );
3113 POINT *pts;
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) );
3125 if (!pts) return;
3127 count = 0;
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;
3140 count += 2;
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 );
3157 UINT i;
3158 DWORD err;
3159 HGDIOBJ orig;
3160 HPEN pen;
3162 if (flags & ETO_OPAQUE)
3164 RECT rc = *rect;
3165 HBRUSH brush = CreateSolidBrush( GetNearestColor( dev->hdc, dc->backgroundColor ) );
3167 if (brush)
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;
3185 PHYSDEV dst_dev;
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;
3199 dst = src;
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 */
3213 src.x = src.y = 0;
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;
3225 else
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 );
3232 if (!ptr)
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 );
3239 bits.ptr = ptr;
3240 bits.is_copy = TRUE;
3241 bits.free = free_heap_bits;
3244 if (!err)
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 );
3253 return !err;
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 );
3266 if (err) continue;
3268 if (image.ptr) draw_glyph( dc, x, y, &metrics, &image, (flags & ETO_CLIPPED) ? rect : NULL );
3269 if (image.free) image.free( &image );
3271 if (dx)
3273 if (flags & ETO_PDY)
3275 x += dx[ i * 2 ];
3276 y += dx[ i * 2 + 1];
3278 else x += dx[ i ];
3280 else
3282 x += metrics.gmCellIncX;
3283 y += metrics.gmCellIncY;
3287 SelectObject( dev->hdc, orig );
3288 DeleteObject( pen );
3289 return TRUE;
3293 /***********************************************************************
3294 * ExtTextOutA (GDI32.@)
3296 * See ExtTextOutW.
3298 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags,
3299 const RECT *lprect, LPCSTR str, UINT count, const INT *lpDx )
3301 INT wlen;
3302 UINT codepage;
3303 LPWSTR p;
3304 BOOL ret;
3305 LPINT lpDxW = NULL;
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);
3312 if (lpDx) {
3313 unsigned int i = 0, j = 0;
3315 /* allocate enough for a ETO_PDY */
3316 lpDxW = HeapAlloc( GetProcessHeap(), 0, 2*wlen*sizeof(INT));
3317 while(i < count) {
3318 if(IsDBCSLeadByteEx(codepage, str[i]))
3320 if(flags & ETO_PDY)
3322 lpDxW[j++] = lpDx[i * 2] + lpDx[(i + 1) * 2];
3323 lpDxW[j++] = lpDx[i * 2 + 1] + lpDx[(i + 1) * 2 + 1];
3325 else
3326 lpDxW[j++] = lpDx[i] + lpDx[i + 1];
3327 i = i + 2;
3329 else
3331 if(flags & ETO_PDY)
3333 lpDxW[j++] = lpDx[i * 2];
3334 lpDxW[j++] = lpDx[i * 2 + 1];
3336 else
3337 lpDxW[j++] = lpDx[i];
3338 i = i + 1;
3343 ret = ExtTextOutW( hdc, x, y, flags, lprect, p, wlen, lpDxW );
3345 HeapFree( GetProcessHeap(), 0, p );
3346 HeapFree( GetProcessHeap(), 0, lpDxW );
3347 return ret;
3350 /***********************************************************************
3351 * get_line_width
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;
3360 return width;
3363 /***********************************************************************
3364 * ExtTextOutW (GDI32.@)
3366 * Draws text using the currently selected font, background color, and text color.
3369 * PARAMS
3370 * x,y [I] coordinates of string
3371 * flags [I]
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
3389 * RETURNS
3390 * Success: TRUE
3391 * Failure: FALSE
3393 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
3394 const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx )
3396 BOOL ret = FALSE;
3397 LPWSTR reordered_str = (LPWSTR)str;
3398 WORD *glyphs = NULL;
3399 UINT align;
3400 DWORD layout;
3401 POINT pt;
3402 TEXTMETRICW tm;
3403 LOGFONTW lf;
3404 double cosEsc, sinEsc;
3405 INT char_extra;
3406 SIZE sz;
3407 RECT rc;
3408 POINT *deltas = NULL, width = {0, 0};
3409 DWORD type;
3410 DC * dc = get_dc_ptr( hdc );
3411 PHYSDEV physdev;
3412 INT breakRem;
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");
3424 quietfixme = 1;
3427 update_dc( dc );
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 );
3434 return ret;
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 )
3446 INT cGlyphs;
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;
3454 if (glyphs)
3456 flags |= ETO_GLYPH_INDEX;
3457 if (cGlyphs != count)
3458 count = cGlyphs;
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)
3470 pt = dc->cur_pos;
3471 x = pt.x;
3472 y = pt.y;
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);
3492 else
3494 cosEsc = 1;
3495 sinEsc = 0;
3498 if (lprect && (flags & (ETO_OPAQUE | ETO_CLIPPED)))
3500 rc = *lprect;
3501 lp_to_dp(dc, (POINT*)&rc, 2);
3502 order_rect( &rc );
3503 if (flags & ETO_OPAQUE)
3504 physdev->funcs->pExtTextOut( physdev, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL );
3506 else flags &= ~ETO_CLIPPED;
3508 if(count == 0)
3510 ret = TRUE;
3511 goto done;
3514 pt.x = x;
3515 pt.y = y;
3516 lp_to_dp(dc, &pt, 1);
3517 x = pt.x;
3518 y = pt.y;
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)
3526 UINT i;
3527 POINT total = {0, 0}, desired[2];
3529 deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*deltas));
3530 if (lpDx)
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];
3540 else
3542 for (i = 0; i < count; i++)
3544 deltas[i].x = lpDx[i] + char_extra;
3545 deltas[i].y = 0;
3549 else
3551 INT *dx = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*dx) );
3553 if (flags & ETO_GLYPH_INDEX)
3554 GetTextExtentExPointI( hdc, glyphs, count, -1, NULL, dx, &sz );
3555 else
3556 GetTextExtentExPointW( hdc, reordered_str, count, -1, NULL, dx, &sz );
3558 deltas[0].x = dx[0];
3559 deltas[0].y = 0;
3560 for (i = 1; i < count; i++)
3562 deltas[i].x = dx[i] - dx[i - 1];
3563 deltas[i].y = 0;
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;
3593 width = desired[1];
3595 flags |= ETO_PDY;
3597 else
3599 POINT desired[2];
3601 if(flags & ETO_GLYPH_INDEX)
3602 GetTextExtentPointI(hdc, glyphs, count, &sz);
3603 else
3604 GetTextExtentPointW(hdc, reordered_str, count, &sz);
3605 desired[0].x = desired[0].y = 0;
3606 desired[1].x = sz.cx;
3607 desired[1].y = 0;
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;
3619 width = desired[1];
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) )
3626 case TA_LEFT:
3627 if (align & TA_UPDATECP)
3629 pt.x = x + width.x;
3630 pt.y = y + width.y;
3631 dp_to_lp(dc, &pt, 1);
3632 MoveToEx(hdc, pt.x, pt.y, NULL);
3634 break;
3636 case TA_CENTER:
3637 x -= width.x / 2;
3638 y -= width.y / 2;
3639 break;
3641 case TA_RIGHT:
3642 x -= width.x;
3643 y -= width.y;
3644 if (align & TA_UPDATECP)
3646 pt.x = x;
3647 pt.y = y;
3648 dp_to_lp(dc, &pt, 1);
3649 MoveToEx(hdc, pt.x, pt.y, NULL);
3651 break;
3654 switch( align & (TA_TOP | TA_BOTTOM | TA_BASELINE) )
3656 case TA_TOP:
3657 y += tm.tmAscent * cosEsc;
3658 x += tm.tmAscent * sinEsc;
3659 break;
3661 case TA_BOTTOM:
3662 y -= tm.tmDescent * cosEsc;
3663 x -= tm.tmDescent * sinEsc;
3664 break;
3666 case TA_BASELINE:
3667 break;
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)
3678 RECT text_box;
3679 text_box.left = x;
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 );
3694 done:
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;
3707 POINT pts[5];
3708 HPEN hpen = SelectObject(hdc, GetStockObject(NULL_PEN));
3709 HBRUSH hbrush = CreateSolidBrush(dc->textColor);
3711 hbrush = SelectObject(hdc, hbrush);
3713 if(!size)
3715 underlinePos = 0;
3716 underlineWidth = tm.tmAscent / 20 + 1;
3717 strikeoutPos = tm.tmAscent / 2;
3718 strikeoutWidth = underlineWidth;
3720 else
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);
3734 if (lf.lfUnderline)
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);
3750 if (lf.lfStrikeOut)
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 );
3773 return ret;
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.@)
3798 * See PolyTextOutW.
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 ))
3804 return FALSE;
3805 return TRUE;
3810 /***********************************************************************
3811 * PolyTextOutW (GDI32.@)
3813 * Draw several Strings
3815 * RETURNS
3816 * TRUE: Success.
3817 * FALSE: Failure.
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 ))
3823 return FALSE;
3824 return TRUE;
3828 /***********************************************************************
3829 * SetMapperFlags (GDI32.@)
3831 DWORD WINAPI SetMapperFlags( HDC hdc, DWORD flags )
3833 DC *dc = get_dc_ptr( hdc );
3834 DWORD ret = GDI_ERROR;
3836 if (dc)
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 );
3847 return ret;
3850 /***********************************************************************
3851 * GetAspectRatioFilterEx (GDI32.@)
3853 BOOL WINAPI GetAspectRatioFilterEx( HDC hdc, LPSIZE pAspectRatio )
3855 FIXME("(%p, %p): -- Empty Stub !\n", hdc, pAspectRatio);
3856 return FALSE;
3860 /***********************************************************************
3861 * GetCharABCWidthsA (GDI32.@)
3863 * See GetCharABCWidthsW.
3865 BOOL WINAPI GetCharABCWidthsA(HDC hdc, UINT firstChar, UINT lastChar,
3866 LPABC abc )
3868 INT i, wlen;
3869 LPSTR str;
3870 LPWSTR wstr;
3871 BOOL ret = TRUE;
3873 str = FONT_GetCharsByRangeA(hdc, firstChar, lastChar, &i);
3874 if (str == NULL)
3875 return FALSE;
3877 wstr = FONT_mbtowc(hdc, str, i, &wlen, NULL);
3878 if (wstr == NULL)
3880 HeapFree(GetProcessHeap(), 0, str);
3881 return FALSE;
3884 for(i = 0; i < wlen; i++)
3886 if(!GetCharABCWidthsW(hdc, wstr[i], wstr[i], abc))
3888 ret = FALSE;
3889 break;
3891 abc++;
3894 HeapFree(GetProcessHeap(), 0, str);
3895 HeapFree(GetProcessHeap(), 0, wstr);
3897 return ret;
3901 /******************************************************************************
3902 * GetCharABCWidthsW [GDI32.@]
3904 * Retrieves widths of characters in range.
3906 * PARAMS
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
3912 * NOTES
3913 * Only works with TrueType fonts
3915 * RETURNS
3916 * Success: TRUE
3917 * Failure: FALSE
3919 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT firstChar, UINT lastChar,
3920 LPABC abc )
3922 DC *dc = get_dc_ptr(hdc);
3923 PHYSDEV dev;
3924 unsigned int i;
3925 BOOL ret;
3926 TEXTMETRICW tm;
3928 if (!dc) return FALSE;
3930 if (!abc)
3932 release_dc_ptr( dc );
3933 return FALSE;
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 );
3941 return FALSE;
3944 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidths );
3945 ret = dev->funcs->pGetCharABCWidths( dev, firstChar, lastChar, abc );
3946 if (ret)
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 );
3957 return ret;
3961 /******************************************************************************
3962 * GetCharABCWidthsI [GDI32.@]
3964 * Retrieves widths of characters in range.
3966 * PARAMS
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
3973 * NOTES
3974 * Only works with TrueType fonts
3976 * RETURNS
3977 * Success: TRUE
3978 * Failure: FALSE
3980 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT firstChar, UINT count,
3981 LPWORD pgi, LPABC abc)
3983 DC *dc = get_dc_ptr(hdc);
3984 PHYSDEV dev;
3985 unsigned int i;
3986 BOOL ret;
3988 if (!dc) return FALSE;
3990 if (!abc)
3992 release_dc_ptr( dc );
3993 return FALSE;
3996 dev = GET_DC_PHYSDEV( dc, pGetCharABCWidthsI );
3997 ret = dev->funcs->pGetCharABCWidthsI( dev, firstChar, count, pgi, abc );
3998 if (ret)
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 );
4009 return ret;
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)) {
4023 UINT cp;
4024 int len;
4025 char mbchs[2];
4026 WCHAR wChar;
4028 cp = GdiGetCodePage(hdc);
4029 if (IsDBCSLeadByteEx(cp, uChar >> 8)) {
4030 len = 2;
4031 mbchs[0] = (uChar & 0xff00) >> 8;
4032 mbchs[1] = (uChar & 0xff);
4033 } else {
4034 len = 1;
4035 mbchs[0] = (uChar & 0xff);
4037 wChar = 0;
4038 MultiByteToWideChar(cp, 0, mbchs, len, &wChar, 1);
4039 uChar = wChar;
4042 return GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cbBuffer, lpBuffer,
4043 lpmat2);
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 )
4053 DC *dc;
4054 DWORD ret;
4055 PHYSDEV dev;
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;
4065 uChar &= 0xffff;
4067 dev = GET_DC_PHYSDEV( dc, pGetGlyphOutline );
4068 ret = dev->funcs->pGetGlyphOutline( dev, uChar, fuFormat, lpgm, cbBuffer, lpBuffer, lpmat2 );
4069 release_dc_ptr( dc );
4070 return ret;
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;
4085 int len;
4086 BOOL ret;
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);
4095 if (lpszFontFile)
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);
4116 return ret;
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 )
4138 UINT cp;
4139 CPINFO cpi;
4140 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
4141 KERNINGPAIR *kern_pairW;
4143 if (!cPairs && kern_pairA)
4145 SetLastError(ERROR_INVALID_PARAMETER);
4146 return 0;
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);
4158 return 0;
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++)
4169 char first, second;
4171 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
4172 continue;
4174 if (!WideCharToMultiByte(cp, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
4175 continue;
4177 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
4178 continue;
4180 if (kern_pairA)
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;
4187 kern_pairA++;
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 )
4203 DC *dc;
4204 DWORD ret;
4205 PHYSDEV dev;
4207 TRACE("(%p,%d,%p)\n", hDC, cPairs, lpKerningPairs);
4209 if (!cPairs && lpKerningPairs)
4211 SetLastError(ERROR_INVALID_PARAMETER);
4212 return 0;
4215 dc = get_dc_ptr(hDC);
4216 if (!dc) return 0;
4218 dev = GET_DC_PHYSDEV( dc, pGetKerningPairs );
4219 ret = dev->funcs->pGetKerningPairs( dev, cPairs, lpKerningPairs );
4220 release_dc_ptr( dc );
4221 return ret;
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.
4235 * RETURNS
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 */)
4248 int index = 0;
4249 switch (flags) {
4250 case TCI_SRCFONTSIG:
4251 while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
4252 break;
4253 case TCI_SRCCODEPAGE:
4254 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
4255 break;
4256 case TCI_SRCCHARSET:
4257 while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
4258 break;
4259 default:
4260 return FALSE;
4262 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
4263 *lpCs = FONT_tci[index];
4264 return TRUE;
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;
4281 DWORD result=0;
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 )
4287 result|=GCP_DBCS;
4289 if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
4290 result|=GCP_DIACRITIC;
4292 if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
4293 result|=FLI_GLYPHS;
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 )
4302 result|=GCP_LIGATE;
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;
4312 return result;
4316 /*************************************************************************
4317 * GetFontData [GDI32.@]
4319 * Retrieve data for TrueType font.
4321 * RETURNS
4323 * success: Number of bytes returned
4324 * failure: GDI_ERROR
4326 * NOTES
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);
4335 PHYSDEV dev;
4336 DWORD ret;
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 );
4343 return ret;
4346 /*************************************************************************
4347 * GetGlyphIndicesA [GDI32.@]
4349 DWORD WINAPI GetGlyphIndicesA(HDC hdc, LPCSTR lpstr, INT count,
4350 LPWORD pgi, DWORD flags)
4352 DWORD ret;
4353 WCHAR *lpstrW;
4354 INT countW;
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);
4363 return ret;
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);
4373 PHYSDEV dev;
4374 DWORD ret;
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 );
4384 return ret;
4387 /*************************************************************************
4388 * GetCharacterPlacementA [GDI32.@]
4390 * See GetCharacterPlacementW.
4392 * NOTES:
4393 * the web browser control of ie4 calls this with dwFlags=0
4395 DWORD WINAPI
4396 GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount,
4397 INT nMaxExtent, GCP_RESULTSA *lpResults,
4398 DWORD dwFlags)
4400 WCHAR *lpStringW;
4401 INT uCountW;
4402 GCP_RESULTSW resultsW;
4403 DWORD ret;
4404 UINT font_cp;
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);
4411 if (!lpResults)
4413 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, NULL, dwFlags);
4414 HeapFree(GetProcessHeap(), 0, lpStringW);
4415 return ret;
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);
4437 return ret;
4440 static int kern_pair(const KERNINGPAIR *kern, int count, WCHAR c1, WCHAR c2)
4442 int i;
4444 for (i = 0; i < count; i++)
4446 if (kern[i].wFirst == c1 && kern[i].wSecond == c2)
4447 return kern[i].iKernAmount;
4450 return 0;
4453 static int *kern_string(HDC hdc, const WCHAR *str, int len, int *kern_total)
4455 int i, count;
4456 KERNINGPAIR *kern = NULL;
4457 int *ret;
4459 *kern_total = 0;
4461 ret = heap_alloc(len * sizeof(*ret));
4462 if (!ret) return NULL;
4464 count = GetKerningPairsW(hdc, 0, NULL);
4465 if (count)
4467 kern = heap_alloc(count * sizeof(*kern));
4468 if (!kern)
4470 heap_free(ret);
4471 return NULL;
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 */
4485 heap_free(kern);
4486 return ret;
4489 /*************************************************************************
4490 * GetCharacterPlacementW [GDI32.@]
4492 * Retrieve information about a string. This includes the width, reordering,
4493 * Glyphing and so on.
4495 * RETURNS
4497 * The width and height of the string if successful, 0 if failed.
4499 * BUGS
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.
4507 DWORD WINAPI
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 */
4517 DWORD ret=0;
4518 SIZE size;
4519 UINT i, nSet;
4520 int *kern = NULL, kern_total = 0;
4522 TRACE("%s, %d, %d, 0x%08x\n",
4523 debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags);
4525 if (!uCount)
4526 return 0;
4528 if (!lpResults)
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;
4564 else
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);
4573 if (!kern)
4575 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4576 return 0;
4580 /* FIXME: Will use the placement chars */
4581 if (lpResults->lpDx)
4583 int c;
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))
4597 int pos = 0;
4599 lpResults->lpCaretPos[0] = 0;
4600 for (i = 0; i < nSet - 1; i++)
4602 if (dwFlags & GCP_USEKERNING)
4603 pos += kern[i];
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);
4616 heap_free(kern);
4618 return ret;
4621 /*************************************************************************
4622 * GetCharABCWidthsFloatA [GDI32.@]
4624 * See GetCharABCWidthsFloatW.
4626 BOOL WINAPI GetCharABCWidthsFloatA( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
4628 INT i, wlen;
4629 LPSTR str;
4630 LPWSTR wstr;
4631 BOOL ret = TRUE;
4633 str = FONT_GetCharsByRangeA(hdc, first, last, &i);
4634 if (str == NULL)
4635 return FALSE;
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 ))
4643 ret = FALSE;
4644 break;
4646 abcf++;
4649 HeapFree( GetProcessHeap(), 0, str );
4650 HeapFree( GetProcessHeap(), 0, wstr );
4652 return ret;
4655 /*************************************************************************
4656 * GetCharABCWidthsFloatW [GDI32.@]
4658 * Retrieves widths of a range of characters.
4660 * PARAMS
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.
4666 * RETURNS
4667 * Success: TRUE
4668 * Failure: FALSE
4670 BOOL WINAPI GetCharABCWidthsFloatW( HDC hdc, UINT first, UINT last, LPABCFLOAT abcf )
4672 UINT i;
4673 ABC *abc;
4674 PHYSDEV dev;
4675 BOOL ret = FALSE;
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 );
4687 if (ret)
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 );
4700 done:
4701 release_dc_ptr( dc );
4702 return ret;
4705 /*************************************************************************
4706 * GetCharWidthFloatA [GDI32.@]
4708 BOOL WINAPI GetCharWidthFloatA( HDC hdc, UINT first, UINT last, float *buffer )
4710 WCHAR *wstr;
4711 int i, wlen;
4712 char *str;
4714 if (!(str = FONT_GetCharsByRangeA( hdc, first, last, &i )))
4715 return FALSE;
4716 wstr = FONT_mbtowc( hdc, str, i, &wlen, NULL );
4717 heap_free(str);
4719 for (i = 0; i < wlen; ++i)
4721 if (!GetCharWidthFloatW( hdc, wstr[i], wstr[i], &buffer[i] ))
4723 heap_free(wstr);
4724 return FALSE;
4727 heap_free(wstr);
4728 return TRUE;
4731 /*************************************************************************
4732 * GetCharWidthFloatW [GDI32.@]
4734 BOOL WINAPI GetCharWidthFloatW( HDC hdc, UINT first, UINT last, float *buffer )
4736 DC *dc = get_dc_ptr( hdc );
4737 int *ibuffer;
4738 PHYSDEV dev;
4739 BOOL ret;
4740 UINT i;
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 );
4749 return FALSE;
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;
4760 heap_free(ibuffer);
4761 return ret;
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));
4794 INT ret;
4796 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
4797 ret = AddFontResourceExW(strW, fl, pdv);
4798 HeapFree(GetProcessHeap(), 0, strW);
4799 return ret;
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;
4808 DWORD num_in_res;
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);
4814 return FALSE;
4817 *num_total += num_in_res;
4818 return TRUE;
4821 static void *map_file( const WCHAR *filename, LARGE_INTEGER *size )
4823 HANDLE file, mapping;
4824 void *ptr;
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 );
4832 return NULL;
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 );
4842 return ptr;
4845 static void *find_resource( BYTE *ptr, WORD type, DWORD rsrc_off, DWORD size, DWORD *len )
4847 WORD align, type_id, count;
4848 DWORD res_off;
4850 if (size < rsrc_off + 10) return NULL;
4851 align = *(WORD *)(ptr + rsrc_off);
4852 rsrc_off += 2;
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 )
4872 LARGE_INTEGER size;
4873 BYTE *ptr = map_file( res, &size );
4874 const IMAGE_DOS_HEADER *dos;
4875 const IMAGE_OS2_HEADER *ne;
4876 WORD *fontdir;
4877 char *data;
4878 WCHAR *name = NULL;
4879 DWORD len;
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 );
4901 fail:
4902 UnmapViewOfFile( ptr );
4903 return name;
4906 /***********************************************************************
4907 * AddFontResourceExW (GDI32.@)
4909 INT WINAPI AddFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
4911 int ret;
4912 WCHAR *filename;
4913 BOOL hidden;
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 );
4938 return ret;
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)
4962 HANDLE ret;
4963 DWORD num_fonts;
4965 if (!pbFont || !cbFont || !pcFonts)
4967 SetLastError(ERROR_INVALID_PARAMETER);
4968 return NULL;
4970 if (!font_funcs) return NULL;
4971 ret = font_funcs->pAddFontMemResourceEx( pbFont, cbFont, pdv, &num_fonts );
4972 if (ret)
4974 __TRY
4976 *pcFonts = num_fonts;
4978 __EXCEPT_PAGE_FAULT
4980 WARN("page fault while writing to *pcFonts (%p)\n", pcFonts);
4981 RemoveFontMemResourceEx(ret);
4982 ret = 0;
4984 __ENDTRY
4986 return ret;
4989 /***********************************************************************
4990 * RemoveFontMemResourceEx (GDI32.@)
4992 BOOL WINAPI RemoveFontMemResourceEx( HANDLE fh )
4994 FIXME("(%p) stub\n", fh);
4995 return TRUE;
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));
5005 INT ret;
5007 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
5008 ret = RemoveFontResourceExW(strW, fl, pdv);
5009 HeapFree(GetProcessHeap(), 0, strW);
5010 return ret;
5013 /***********************************************************************
5014 * RemoveFontResourceExW (GDI32.@)
5016 BOOL WINAPI RemoveFontResourceExW( LPCWSTR str, DWORD fl, PVOID pdv )
5018 int ret;
5019 WCHAR *filename;
5020 BOOL hidden;
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 );
5040 return ret;
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);
5049 return FALSE;
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.
5066 * PARAMS
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.
5071 * RETURNS
5072 * The average width of characters in the English alphabet.
5074 * NOTES
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.
5082 * SEE ALSO
5083 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
5085 LONG WINAPI GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
5087 SIZE sz;
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);
5104 return FALSE;
5107 /***********************************************************************
5108 * GetCharWidthI (GDI32.@)
5110 * Retrieve widths of characters.
5112 * PARAMS
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.
5119 * NOTES
5120 * Only works with TrueType fonts.
5122 * RETURNS
5123 * Success: TRUE
5124 * Failure: FALSE
5126 BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT buffer)
5128 ABC *abc;
5129 unsigned int i;
5131 TRACE("(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer);
5133 if (!(abc = HeapAlloc(GetProcessHeap(), 0, count * sizeof(ABC))))
5134 return FALSE;
5136 if (!GetCharABCWidthsI(hdc, first, count, glyphs, abc))
5138 HeapFree(GetProcessHeap(), 0, abc);
5139 return FALSE;
5142 for (i = 0; i < count; i++)
5143 buffer[i] = abc[i].abcA + abc[i].abcB + abc[i].abcC;
5145 HeapFree(GetProcessHeap(), 0, abc);
5146 return TRUE;
5149 /***********************************************************************
5150 * GetFontUnicodeRanges (GDI32.@)
5152 * Retrieve a list of supported Unicode characters in a font.
5154 * PARAMS
5155 * hdc [I] Handle to a device context.
5156 * lpgs [O] GLYPHSET structure specifying supported character ranges.
5158 * RETURNS
5159 * Success: Number of bytes written to the buffer pointed to by lpgs.
5160 * Failure: 0
5163 DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs)
5165 DWORD ret;
5166 PHYSDEV dev;
5167 DC *dc = get_dc_ptr(hdc);
5169 TRACE("(%p, %p)\n", hdc, lpgs);
5171 if (!dc) return 0;
5173 dev = GET_DC_PHYSDEV( dc, pGetFontUnicodeRanges );
5174 ret = dev->funcs->pGetFontUnicodeRanges( dev, lpgs );
5175 release_dc_ptr(dc);
5176 return ret;
5180 /*************************************************************
5181 * FontIsLinked (GDI32.@)
5183 BOOL WINAPI FontIsLinked(HDC hdc)
5185 DC *dc = get_dc_ptr(hdc);
5186 PHYSDEV dev;
5187 BOOL ret;
5189 if (!dc) return FALSE;
5190 dev = GET_DC_PHYSDEV( dc, pFontIsLinked );
5191 ret = dev->funcs->pFontIsLinked( dev );
5192 release_dc_ptr(dc);
5193 TRACE("returning %d\n", ret);
5194 return 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);
5203 PHYSDEV dev;
5204 BOOL ret;
5205 DC *dc;
5207 if (info->size != sizeof(*info) && !is_v0)
5208 return FALSE;
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 );
5214 release_dc_ptr(dc);
5215 return ret;
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;
5226 return TRUE;
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;
5251 if (!font)
5253 *needed = 0;
5254 return FALSE;
5256 *needed = sizeof(*info) + strlenW( font->fileinfo->path ) * sizeof(WCHAR);
5257 if (*needed > size)
5259 SetLastError( ERROR_INSUFFICIENT_BUFFER );
5260 return FALSE;
5262 memcpy( info, font->fileinfo, *needed );
5263 return TRUE;
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;
5281 BOOL ret;
5283 ri.size = sizeof(ri);
5284 ret = GetFontRealizationInfo( hdc, &ri );
5285 if (ret)
5287 info->flags = ri.flags;
5288 info->cache_num = ri.cache_num;
5289 info->instance_id = ri.instance_id;
5292 return ret;
5295 /*************************************************************
5296 * GetCharWidthInfo (GDI32.@)
5299 BOOL WINAPI GetCharWidthInfo(HDC hdc, struct char_width_info *info)
5301 PHYSDEV dev;
5302 BOOL ret;
5303 DC *dc;
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 );
5310 if (ret)
5312 info->lsb = width_to_LP( dc, info->lsb );
5313 info->rsb = width_to_LP( dc, info->rsb );
5315 release_dc_ptr(dc);
5316 return ret;