c96d76cb38783721b0bf28c9c6e27c62b153c8df
[reactos.git] / reactos / dll / win32 / gdi32 / objects / font.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/gdi32/object/font.c
6 * PURPOSE:
7 * PROGRAMMER:
8 *
9 */
10
11 #include "precomp.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /*
17 * For TranslateCharsetInfo
18 */
19 #define MAXTCIINDEX 32
20 static const CHARSETINFO FONT_tci[MAXTCIINDEX] = {
21 /* ANSI */
22 { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
23 { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
24 { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
25 { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
26 { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
27 { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
28 { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
29 { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
30 { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
31 /* reserved by ANSI */
32 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
33 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
34 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
35 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
36 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
37 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
38 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
39 /* ANSI and OEM */
40 { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
41 { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
42 { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
43 { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
44 { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
45 { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
46 /* reserved for alternate ANSI and OEM */
47 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
48 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
49 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
50 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
51 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
52 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
53 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
54 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
55 /* reserved for system */
56 { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
57 { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
58 };
59
60 #define INITIAL_FAMILY_COUNT 64
61
62 /***********************************************************************
63 * TEXTMETRIC conversion functions.
64 */
65 static void FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
66 {
67 ptmA->tmHeight = ptmW->tmHeight;
68 ptmA->tmAscent = ptmW->tmAscent;
69 ptmA->tmDescent = ptmW->tmDescent;
70 ptmA->tmInternalLeading = ptmW->tmInternalLeading;
71 ptmA->tmExternalLeading = ptmW->tmExternalLeading;
72 ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
73 ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
74 ptmA->tmWeight = ptmW->tmWeight;
75 ptmA->tmOverhang = ptmW->tmOverhang;
76 ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
77 ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
78 ptmA->tmFirstChar = ptmW->tmFirstChar > 255 ? 255 : ptmW->tmFirstChar;
79 ptmA->tmLastChar = ptmW->tmLastChar > 255 ? 255 : ptmW->tmLastChar;
80 ptmA->tmDefaultChar = ptmW->tmDefaultChar > 255 ? 255 : ptmW->tmDefaultChar;
81 ptmA->tmBreakChar = ptmW->tmBreakChar > 255 ? 255 : ptmW->tmBreakChar;
82 ptmA->tmItalic = ptmW->tmItalic;
83 ptmA->tmUnderlined = ptmW->tmUnderlined;
84 ptmA->tmStruckOut = ptmW->tmStruckOut;
85 ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
86 ptmA->tmCharSet = ptmW->tmCharSet;
87 }
88
89 /***********************************************************************
90 * FONT_mbtowc
91 *
92 * Returns a Unicode translation of str using the charset of the
93 * currently selected font in hdc. If count is -1 then str is assumed
94 * to be '\0' terminated, otherwise it contains the number of bytes to
95 * convert. If plenW is non-NULL, on return it will point to the
96 * number of WCHARs that have been written. If pCP is non-NULL, on
97 * return it will point to the codepage used in the conversion. The
98 * caller should free the returned LPWSTR from the process heap
99 * itself.
100 */
101 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
102 {
103 UINT cp = GdiGetCodePage( hdc );
104 INT lenW;
105 LPWSTR strW;
106
107 if(count == -1) count = strlen(str);
108 lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
109 strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
110 MultiByteToWideChar(cp, 0, str, count, strW, lenW);
111 DPRINT("mapped %s -> %S\n", str, strW);
112 if(plenW) *plenW = lenW;
113 if(pCP) *pCP = cp;
114 return strW;
115 }
116
117
118 static BOOL FASTCALL
119 MetricsCharConvert(WCHAR w, UCHAR *b)
120 {
121 UNICODE_STRING WString;
122 WCHAR WBuf[2];
123 ANSI_STRING AString;
124 CHAR ABuf[2];
125 NTSTATUS Status;
126
127 if (L'\0' == w)
128 {
129 *b = '\0';
130 }
131 else
132 {
133 WBuf[0] = w;
134 WBuf[1] = L'\0';
135 RtlInitUnicodeString(&WString, WBuf);
136 ABuf[0] = '*';
137 ABuf[1] = L'\0';
138 RtlInitAnsiString(&AString, ABuf);
139
140 Status = RtlUnicodeStringToAnsiString(&AString, &WString, FALSE);
141 if (! NT_SUCCESS(Status))
142 {
143 SetLastError(RtlNtStatusToDosError(Status));
144 return FALSE;
145 }
146 *b = ABuf[0];
147 }
148
149 return TRUE;
150 }
151
152 BOOL FASTCALL
153 TextMetricW2A(TEXTMETRICA *tma, TEXTMETRICW *tmw)
154 {
155 UNICODE_STRING WString;
156 WCHAR WBuf[256];
157 ANSI_STRING AString;
158 CHAR ABuf[256];
159 UINT Letter;
160 NTSTATUS Status;
161
162 tma->tmHeight = tmw->tmHeight;
163 tma->tmAscent = tmw->tmAscent;
164 tma->tmDescent = tmw->tmDescent;
165 tma->tmInternalLeading = tmw->tmInternalLeading;
166 tma->tmExternalLeading = tmw->tmExternalLeading;
167 tma->tmAveCharWidth = tmw->tmAveCharWidth;
168 tma->tmMaxCharWidth = tmw->tmMaxCharWidth;
169 tma->tmWeight = tmw->tmWeight;
170 tma->tmOverhang = tmw->tmOverhang;
171 tma->tmDigitizedAspectX = tmw->tmDigitizedAspectX;
172 tma->tmDigitizedAspectY = tmw->tmDigitizedAspectY;
173
174 /* The Unicode FirstChar/LastChar need not correspond to the ANSI
175 FirstChar/LastChar. For example, if the font contains glyphs for
176 letters A-Z and an accented version of the letter e, the Unicode
177 FirstChar would be A and the Unicode LastChar would be the accented
178 e. If you just translate those to ANSI, the range would become
179 letters A-E instead of A-Z.
180 We translate all possible ANSI chars to Unicode and find the first
181 and last translated character which fall into the Unicode FirstChar/
182 LastChar range and return the corresponding ANSI char. */
183
184 /* Setup an Ansi string containing all possible letters (note: skip '\0' at
185 the beginning since that would be interpreted as end-of-string, handle
186 '\0' special later */
187 for (Letter = 1; Letter < 256; Letter++)
188 {
189 ABuf[Letter - 1] = (CHAR) Letter;
190 WBuf[Letter - 1] = L' ';
191 }
192 ABuf[255] = '\0';
193 WBuf[255] = L'\0';
194 RtlInitAnsiString(&AString, ABuf);
195 RtlInitUnicodeString(&WString, WBuf);
196
197 /* Find the corresponding Unicode characters */
198 Status = RtlAnsiStringToUnicodeString(&WString, &AString, FALSE);
199 if (! NT_SUCCESS(Status))
200 {
201 SetLastError(RtlNtStatusToDosError(Status));
202 return FALSE;
203 }
204
205 /* Scan for the first ANSI character which maps to an Unicode character
206 in the range */
207 tma->tmFirstChar = '\0';
208 if (L'\0' != tmw->tmFirstChar)
209 {
210 for (Letter = 1; Letter < 256; Letter++)
211 {
212 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
213 WBuf[Letter - 1] <= tmw->tmLastChar)
214 {
215 tma->tmFirstChar = (CHAR) Letter;
216 break;
217 }
218 }
219 }
220
221 /* Scan for the last ANSI character which maps to an Unicode character
222 in the range */
223 tma->tmLastChar = '\0';
224 if (L'\0' != tmw->tmLastChar)
225 {
226 for (Letter = 255; 0 < Letter; Letter--)
227 {
228 if (tmw->tmFirstChar <= WBuf[Letter - 1] &&
229 WBuf[Letter - 1] <= tmw->tmLastChar)
230 {
231 tma->tmLastChar = (CHAR) Letter;
232 break;
233 }
234 }
235 }
236
237 if (! MetricsCharConvert(tmw->tmDefaultChar, &tma->tmDefaultChar) ||
238 ! MetricsCharConvert(tmw->tmBreakChar, &tma->tmBreakChar))
239 {
240 return FALSE;
241 }
242
243 tma->tmItalic = tmw->tmItalic;
244 tma->tmUnderlined = tmw->tmUnderlined;
245 tma->tmStruckOut = tmw->tmStruckOut;
246 tma->tmPitchAndFamily = tmw->tmPitchAndFamily;
247 tma->tmCharSet = tmw->tmCharSet;
248
249 return TRUE;
250 }
251
252 BOOL FASTCALL
253 NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw)
254 {
255 if (! TextMetricW2A((TEXTMETRICA *) tma, (TEXTMETRICW *) tmw))
256 {
257 return FALSE;
258 }
259
260 tma->ntmFlags = tmw->ntmFlags;
261 tma->ntmSizeEM = tmw->ntmSizeEM;
262 tma->ntmCellHeight = tmw->ntmCellHeight;
263 tma->ntmAvgWidth = tmw->ntmAvgWidth;
264
265 return TRUE;
266 }
267
268 BOOL FASTCALL
269 NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
270 {
271 if (! NewTextMetricW2A(&tma->ntmTm, &tmw->ntmTm))
272 {
273 return FALSE;
274 }
275
276 tma->ntmFontSig = tmw->ntmFontSig;
277
278 return TRUE;
279 }
280
281 static int FASTCALL
282 IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
283 BOOL Unicode)
284 {
285 int FontFamilyCount;
286 int FontFamilySize;
287 PFONTFAMILYINFO Info;
288 int Ret = 0;
289 int i;
290 ENUMLOGFONTEXA EnumLogFontExA;
291 NEWTEXTMETRICEXA NewTextMetricExA;
292
293 Info = RtlAllocateHeap(GetProcessHeap(), 0,
294 INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO));
295 if (NULL == Info)
296 {
297 return 0;
298 }
299 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT);
300 if (FontFamilyCount < 0)
301 {
302 RtlFreeHeap(GetProcessHeap(), 0, Info);
303 return 0;
304 }
305 if (INITIAL_FAMILY_COUNT < FontFamilyCount)
306 {
307 FontFamilySize = FontFamilyCount;
308 RtlFreeHeap(GetProcessHeap(), 0, Info);
309 Info = RtlAllocateHeap(GetProcessHeap(), 0,
310 FontFamilyCount * sizeof(FONTFAMILYINFO));
311 if (NULL == Info)
312 {
313 return 0;
314 }
315 FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize);
316 if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount)
317 {
318 RtlFreeHeap(GetProcessHeap(), 0, Info);
319 return 0;
320 }
321 }
322
323 for (i = 0; i < FontFamilyCount; i++)
324 {
325 if (Unicode)
326 {
327 Ret = ((FONTENUMPROCW) EnumProc)(
328 (VOID*)&Info[i].EnumLogFontEx,
329 (VOID*)&Info[i].NewTextMetricEx,
330 Info[i].FontType, lParam);
331 }
332 else
333 { // Could use EnumLogFontExW2A here?
334 LogFontW2A(&EnumLogFontExA.elfLogFont, &Info[i].EnumLogFontEx.elfLogFont);
335 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfFullName, -1,
336 (LPSTR)EnumLogFontExA.elfFullName, LF_FULLFACESIZE, NULL, NULL);
337 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfStyle, -1,
338 (LPSTR)EnumLogFontExA.elfStyle, LF_FACESIZE, NULL, NULL);
339 WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfScript, -1,
340 (LPSTR)EnumLogFontExA.elfScript, LF_FACESIZE, NULL, NULL);
341 NewTextMetricExW2A(&NewTextMetricExA,
342 &Info[i].NewTextMetricEx);
343 Ret = ((FONTENUMPROCA) EnumProc)(
344 (VOID*)&EnumLogFontExA,
345 (VOID*)&NewTextMetricExA,
346 Info[i].FontType, lParam);
347 }
348 }
349
350 RtlFreeHeap(GetProcessHeap(), 0, Info);
351
352 return Ret;
353 }
354
355 /*
356 * @implemented
357 */
358 int WINAPI
359 EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
360 LPARAM lParam, DWORD dwFlags)
361 {
362 return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE);
363 }
364
365
366 /*
367 * @implemented
368 */
369 int WINAPI
370 EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
371 LPARAM lParam)
372 {
373 LOGFONTW LogFont;
374
375 ZeroMemory(&LogFont, sizeof(LOGFONTW));
376 LogFont.lfCharSet = DEFAULT_CHARSET;
377 if (NULL != lpszFamily)
378 {
379 if (!*lpszFamily) return 1;
380 lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
381 }
382
383 return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE);
384 }
385
386
387 /*
388 * @implemented
389 */
390 int WINAPI
391 EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamExProc,
392 LPARAM lParam, DWORD dwFlags)
393 {
394 LOGFONTW LogFontW, *pLogFontW;
395
396 if (lpLogfont)
397 {
398 LogFontA2W(&LogFontW,lpLogfont);
399 pLogFontW = &LogFontW;
400 }
401 else pLogFontW = NULL;
402
403 /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
404 return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, FALSE);
405 }
406
407
408 /*
409 * @implemented
410 */
411 int WINAPI
412 EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
413 LPARAM lParam)
414 {
415 LOGFONTW LogFont;
416
417 ZeroMemory(&LogFont, sizeof(LOGFONTW));
418 LogFont.lfCharSet = DEFAULT_CHARSET;
419 if (NULL != lpszFamily)
420 {
421 if (!*lpszFamily) return 1;
422 MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
423 }
424
425 return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, FALSE);
426 }
427
428
429 /*
430 * @implemented
431 */
432 DWORD
433 WINAPI
434 GetCharacterPlacementA(
435 HDC hdc,
436 LPCSTR lpString,
437 INT uCount,
438 INT nMaxExtent,
439 GCP_RESULTSA *lpResults,
440 DWORD dwFlags)
441 {
442 WCHAR *lpStringW;
443 INT uCountW;
444 GCP_RESULTSW resultsW;
445 DWORD ret;
446 UINT font_cp;
447
448 if ( !lpString || uCount <= 0 || (nMaxExtent < 0 && nMaxExtent != -1 ) )
449 {
450 SetLastError(ERROR_INVALID_PARAMETER);
451 return 0;
452 }
453 /* TRACE("%s, %d, %d, 0x%08x\n",
454 debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
455 */
456 /* both structs are equal in size */
457 memcpy(&resultsW, lpResults, sizeof(resultsW));
458
459 lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
460 if(lpResults->lpOutString)
461 resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
462
463 ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
464
465 lpResults->nGlyphs = resultsW.nGlyphs;
466 lpResults->nMaxFit = resultsW.nMaxFit;
467
468 if(lpResults->lpOutString) {
469 WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
470 lpResults->lpOutString, uCount, NULL, NULL );
471 }
472
473 HeapFree(GetProcessHeap(), 0, lpStringW);
474 HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
475
476 return ret;
477 }
478
479
480 /*
481 * @implemented
482 */
483 DWORD
484 WINAPI
485 GetCharacterPlacementW(
486 HDC hdc,
487 LPCWSTR lpString,
488 INT uCount,
489 INT nMaxExtent,
490 GCP_RESULTSW *lpResults,
491 DWORD dwFlags
492 )
493 {
494 DWORD ret=0;
495 SIZE size;
496 UINT i, nSet;
497 DPRINT("GetCharacterPlacementW\n");
498
499 if(dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
500 if(lpResults->lpClass) DPRINT("classes not implemented\n");
501 if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
502 DPRINT("Caret positions for complex scripts not implemented\n");
503
504 nSet = (UINT)uCount;
505 if(nSet > lpResults->nGlyphs)
506 nSet = lpResults->nGlyphs;
507
508 /* return number of initialized fields */
509 lpResults->nGlyphs = nSet;
510
511 /*if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
512 {*/
513 /* Treat the case where no special handling was requested in a fastpath way */
514 /* copy will do if the GCP_REORDER flag is not set */
515 if(lpResults->lpOutString)
516 lstrcpynW( lpResults->lpOutString, lpString, nSet );
517
518 if(lpResults->lpGlyphs)
519 lstrcpynW( lpResults->lpGlyphs, lpString, nSet );
520
521 if(lpResults->lpOrder)
522 {
523 for(i = 0; i < nSet; i++)
524 lpResults->lpOrder[i] = i;
525 }
526 /*} else
527 {
528 BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
529 nSet, lpResults->lpOrder );
530 }*/
531
532 /* FIXME: Will use the placement chars */
533 if (lpResults->lpDx)
534 {
535 int c;
536 for (i = 0; i < nSet; i++)
537 {
538 if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
539 lpResults->lpDx[i]= c;
540 }
541 }
542
543 if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
544 {
545 int pos = 0;
546
547 lpResults->lpCaretPos[0] = 0;
548 for (i = 1; i < nSet; i++)
549 if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
550 lpResults->lpCaretPos[i] = (pos += size.cx);
551 }
552
553 /*if(lpResults->lpGlyphs)
554 NtGdiGetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);*/
555
556 if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
557 ret = MAKELONG(size.cx, size.cy);
558
559 return ret;
560 }
561
562 DWORD
563 WINAPI
564 NewGetCharacterPlacementW(
565 HDC hdc,
566 LPCWSTR lpString,
567 INT uCount,
568 INT nMaxExtent,
569 GCP_RESULTSW *lpResults,
570 DWORD dwFlags
571 )
572 {
573 INT nSet;
574 SIZE Size = {0,0};
575
576 if ( !lpString || uCount <= 0 || (nMaxExtent < 0 && nMaxExtent != -1 ) )
577 {
578 SetLastError(ERROR_INVALID_PARAMETER);
579 return 0;
580 }
581
582 if ( !lpResults )
583 {
584 if ( GetTextExtentPointW(hdc, lpString, uCount, &Size) )
585 {
586 return MAKELONG(Size.cx, Size.cy);
587 }
588 return 0;
589 }
590
591 nSet = uCount;
592 if ( nSet > lpResults->nGlyphs )
593 nSet = lpResults->nGlyphs;
594
595 return NtGdiGetCharacterPlacementW( hdc,
596 (LPWSTR)lpString,
597 nSet,
598 nMaxExtent,
599 lpResults,
600 dwFlags);
601 }
602
603 /*
604 * @implemented
605 *
606 */
607 BOOL
608 WINAPI
609 GetCharABCWidthsFloatW(HDC hdc,
610 UINT FirstChar,
611 UINT LastChar,
612 LPABCFLOAT abcF)
613 {
614 DPRINT("GetCharABCWidthsFloatW\n");
615 if ((!abcF) || (FirstChar > LastChar))
616 {
617 SetLastError(ERROR_INVALID_PARAMETER);
618 return FALSE;
619 }
620 return NtGdiGetCharABCWidthsW( hdc,
621 FirstChar,
622 (ULONG)(LastChar - FirstChar + 1),
623 (PWCHAR) NULL,
624 0,
625 (PVOID)abcF);
626 }
627
628 /*
629 * @implemented
630 *
631 */
632 BOOL
633 WINAPI
634 GetCharWidthFloatW(HDC hdc,
635 UINT iFirstChar,
636 UINT iLastChar,
637 PFLOAT pxBuffer)
638 {
639 DPRINT("GetCharWidthsFloatW\n");
640 if ((!pxBuffer) || (iFirstChar > iLastChar))
641 {
642 SetLastError(ERROR_INVALID_PARAMETER);
643 return FALSE;
644 }
645 return NtGdiGetCharWidthW( hdc,
646 iFirstChar,
647 (ULONG)(iLastChar - iFirstChar + 1),
648 (PWCHAR) NULL,
649 0,
650 (PVOID) pxBuffer);
651 }
652
653 /*
654 * @implemented
655 *
656 */
657 BOOL
658 WINAPI
659 GetCharWidthW(HDC hdc,
660 UINT iFirstChar,
661 UINT iLastChar,
662 LPINT lpBuffer)
663 {
664 DPRINT("GetCharWidthsW\n");
665 if ((!lpBuffer) || (iFirstChar > iLastChar))
666 {
667 SetLastError(ERROR_INVALID_PARAMETER);
668 return FALSE;
669 }
670 return NtGdiGetCharWidthW( hdc,
671 iFirstChar,
672 (ULONG)(iLastChar - iFirstChar + 1),
673 (PWCHAR) NULL,
674 GCW_NOFLOAT,
675 (PVOID) lpBuffer);
676 }
677
678 /*
679 * @implemented
680 *
681 */
682 BOOL
683 WINAPI
684 GetCharWidth32W(HDC hdc,
685 UINT iFirstChar,
686 UINT iLastChar,
687 LPINT lpBuffer)
688 {
689 DPRINT("GetCharWidths32W\n");
690 if ((!lpBuffer) || (iFirstChar > iLastChar))
691 {
692 SetLastError(ERROR_INVALID_PARAMETER);
693 return FALSE;
694 }
695 return NtGdiGetCharWidthW( hdc,
696 iFirstChar,
697 (ULONG)(iLastChar - iFirstChar + 1),
698 (PWCHAR) NULL,
699 GCW_NOFLOAT|GCW_WIN32,
700 (PVOID) lpBuffer);
701 }
702
703
704 /*
705 * @implemented
706 *
707 */
708 BOOL
709 WINAPI
710 GetCharABCWidthsW(HDC hdc,
711 UINT FirstChar,
712 UINT LastChar,
713 LPABC lpabc)
714 {
715 DPRINT("GetCharABCWidthsW\n");
716 if ((!lpabc) || (FirstChar > LastChar))
717 {
718 SetLastError(ERROR_INVALID_PARAMETER);
719 return FALSE;
720 }
721 return NtGdiGetCharABCWidthsW( hdc,
722 FirstChar,
723 (ULONG)(LastChar - FirstChar + 1),
724 (PWCHAR) NULL,
725 GCABCW_NOFLOAT,
726 (PVOID)lpabc);
727 }
728
729 /*
730 * @implemented
731 */
732 BOOL
733 WINAPI
734 GetCharWidthA(
735 HDC hdc,
736 UINT iFirstChar,
737 UINT iLastChar,
738 LPINT lpBuffer
739 )
740 {
741 INT i, wlen, count = (INT)(iLastChar - iFirstChar + 1);
742 LPSTR str;
743 LPWSTR wstr;
744 BOOL ret = TRUE;
745
746 DPRINT("GetCharWidthsA\n");
747 if(count <= 0) return FALSE;
748
749 str = HeapAlloc(GetProcessHeap(), 0, count+1);
750 if (!str)
751 return FALSE;
752
753 for(i = 0; i < count; i++)
754 str[i] = (BYTE)(iFirstChar + i);
755 str[i] = '\0';
756
757 wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
758 if (!wstr)
759 {
760 HeapFree(GetProcessHeap(), 0, str);
761 return FALSE;
762 }
763
764 ret = NtGdiGetCharWidthW( hdc,
765 wstr[0],
766 (ULONG) count,
767 (PWCHAR) wstr,
768 GCW_NOFLOAT,
769 (PVOID) lpBuffer);
770
771 HeapFree(GetProcessHeap(), 0, str);
772 HeapFree(GetProcessHeap(), 0, wstr);
773
774 return ret;
775 }
776
777 /*
778 * @implemented
779 */
780 BOOL
781 WINAPI
782 GetCharWidth32A(
783 HDC hdc,
784 UINT iFirstChar,
785 UINT iLastChar,
786 LPINT lpBuffer
787 )
788 {
789 INT i, wlen, count = (INT)(iLastChar - iFirstChar + 1);
790 LPSTR str;
791 LPWSTR wstr;
792 BOOL ret = TRUE;
793
794 DPRINT("GetCharWidths32A\n");
795 if(count <= 0) return FALSE;
796
797 str = HeapAlloc(GetProcessHeap(), 0, count+1);
798 if (!str)
799 return FALSE;
800 for(i = 0; i < count; i++)
801 str[i] = (BYTE)(iFirstChar + i);
802 str[i] = '\0';
803
804 wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
805 if (!wstr)
806 {
807 HeapFree(GetProcessHeap(), 0, str);
808 return FALSE;
809 }
810
811 ret = NtGdiGetCharWidthW( hdc,
812 wstr[0],
813 (ULONG) count,
814 (PWCHAR) wstr,
815 GCW_NOFLOAT|GCW_WIN32,
816 (PVOID) lpBuffer);
817
818 HeapFree(GetProcessHeap(), 0, str);
819 HeapFree(GetProcessHeap(), 0, wstr);
820
821 return ret;
822 }
823
824 /*
825 * @implemented
826 */
827 BOOL
828 APIENTRY
829 GetCharWidthFloatA(
830 HDC hdc,
831 UINT iFirstChar,
832 UINT iLastChar,
833 PFLOAT pxBuffer
834 )
835 {
836 INT i, wlen, count = (INT)(iLastChar - iFirstChar + 1);
837 LPSTR str;
838 LPWSTR wstr;
839 BOOL ret = TRUE;
840
841 DPRINT("GetCharWidthsFloatA\n");
842 if(count <= 0) return FALSE;
843
844 str = HeapAlloc(GetProcessHeap(), 0, count+1);
845 if (!str)
846 return FALSE;
847 for(i = 0; i < count; i++)
848 str[i] = (BYTE)(iFirstChar + i);
849 str[i] = '\0';
850
851 wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
852 if (!wstr)
853 {
854 HeapFree(GetProcessHeap(), 0, str);
855 return FALSE;
856 }
857 ret = NtGdiGetCharWidthW( hdc, wstr[0], (ULONG) count, (PWCHAR) wstr, 0, (PVOID) pxBuffer);
858
859 HeapFree(GetProcessHeap(), 0, str);
860 HeapFree(GetProcessHeap(), 0, wstr);
861
862 return ret;
863 }
864
865 /*
866 * @implemented
867 */
868 BOOL
869 APIENTRY
870 GetCharABCWidthsA(
871 HDC hdc,
872 UINT uFirstChar,
873 UINT uLastChar,
874 LPABC lpabc
875 )
876 {
877 INT i, wlen, count = (INT)(uLastChar - uFirstChar + 1);
878 LPSTR str;
879 LPWSTR wstr;
880 BOOL ret = TRUE;
881
882 DPRINT("GetCharABCWidthsA\n");
883 if(count <= 0) return FALSE;
884
885 str = HeapAlloc(GetProcessHeap(), 0, count+1);
886 if (!str)
887 return FALSE;
888 for(i = 0; i < count; i++)
889 str[i] = (BYTE)(uFirstChar + i);
890 str[i] = '\0';
891
892 wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
893 if (!wstr)
894 {
895 HeapFree(GetProcessHeap(), 0, str);
896 return FALSE;
897 }
898
899 ret = NtGdiGetCharABCWidthsW( hdc,
900 wstr[0],
901 (ULONG)count,
902 (PWCHAR)wstr,
903 GCABCW_NOFLOAT,
904 (PVOID)lpabc);
905
906 HeapFree(GetProcessHeap(), 0, str);
907 HeapFree(GetProcessHeap(), 0, wstr);
908
909 return ret;
910 }
911
912 /*
913 * @implemented
914 */
915 BOOL
916 APIENTRY
917 GetCharABCWidthsFloatA(
918 HDC hdc,
919 UINT iFirstChar,
920 UINT iLastChar,
921 LPABCFLOAT lpABCF
922 )
923 {
924 INT i, wlen, count = (INT)(iLastChar - iFirstChar + 1);
925 LPSTR str;
926 LPWSTR wstr;
927 BOOL ret = TRUE;
928
929 DPRINT("GetCharABCWidthsFloatA\n");
930 if (count <= 0) return FALSE;
931
932 str = HeapAlloc(GetProcessHeap(), 0, count+1);
933 if (!str)
934 return FALSE;
935
936 for(i = 0; i < count; i++)
937 str[i] = (BYTE)(iFirstChar + i);
938 str[i] = '\0';
939
940 wstr = FONT_mbtowc( hdc, str, count+1, &wlen, NULL );
941 if (!wstr)
942 {
943 HeapFree( GetProcessHeap(), 0, str );
944 return FALSE;
945 }
946 ret = NtGdiGetCharABCWidthsW( hdc,wstr[0],(ULONG)count, (PWCHAR)wstr, 0, (PVOID)lpABCF);
947
948 HeapFree( GetProcessHeap(), 0, str );
949 HeapFree( GetProcessHeap(), 0, wstr );
950
951 return ret;
952 }
953
954 /*
955 * @implemented
956 */
957 BOOL
958 WINAPI
959 GetCharABCWidthsI(HDC hdc,
960 UINT giFirst,
961 UINT cgi,
962 LPWORD pgi,
963 LPABC lpabc)
964 {
965 DPRINT("GetCharABCWidthsI\n");
966 return NtGdiGetCharABCWidthsW( hdc,
967 giFirst,
968 (ULONG) cgi,
969 (PWCHAR) pgi,
970 GCABCW_NOFLOAT|GCABCW_INDICES,
971 (PVOID)lpabc);
972 }
973
974 /*
975 * @implemented
976 */
977 BOOL
978 WINAPI
979 GetCharWidthI(HDC hdc,
980 UINT giFirst,
981 UINT cgi,
982 LPWORD pgi,
983 LPINT lpBuffer
984 )
985 {
986 DPRINT("GetCharWidthsI\n");
987 if (!lpBuffer || (!pgi && (giFirst == MAXUSHORT))) // Cannot be at max.
988 {
989 SetLastError(ERROR_INVALID_PARAMETER);
990 return FALSE;
991 }
992 if (!cgi) return TRUE;
993 return NtGdiGetCharWidthW( hdc,
994 giFirst,
995 cgi,
996 (PWCHAR) pgi,
997 GCW_INDICES|GCW_NOFLOAT|GCW_WIN32,
998 (PVOID) lpBuffer );
999 }
1000
1001 /*
1002 * @implemented
1003 */
1004 DWORD
1005 WINAPI
1006 GetFontLanguageInfo(
1007 HDC hDc
1008 )
1009 {
1010 DWORD Gcp = 0, Ret = 0;
1011 if (gbLpk)
1012 {
1013 Ret = NtGdiGetTextCharsetInfo(hDc, NULL, 0);
1014 if ((Ret == ARABIC_CHARSET) || (Ret == HEBREW_CHARSET))
1015 Ret = (GCP_KASHIDA|GCP_DIACRITIC|GCP_LIGATE|GCP_GLYPHSHAPE|GCP_REORDER);
1016 }
1017 Gcp = GetDCDWord(hDc, GdiGetFontLanguageInfo, GCP_ERROR);
1018 if ( Gcp == GCP_ERROR)
1019 return Gcp;
1020 else
1021 Ret = Gcp | Ret;
1022 return Ret;
1023 }
1024
1025 /*
1026 * @implemented
1027 */
1028 DWORD
1029 WINAPI
1030 GetGlyphIndicesA(
1031 HDC hdc,
1032 LPCSTR lpstr,
1033 INT count,
1034 LPWORD pgi,
1035 DWORD flags
1036 )
1037 {
1038 DWORD Ret;
1039 WCHAR *lpstrW;
1040 INT countW;
1041
1042 lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
1043 Ret = NtGdiGetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
1044 HeapFree(GetProcessHeap(), 0, lpstrW);
1045 return Ret;
1046 }
1047
1048 /*
1049 * @implemented
1050 */
1051 DWORD
1052 WINAPI
1053 GetGlyphOutlineA(
1054 HDC hdc,
1055 UINT uChar,
1056 UINT uFormat,
1057 LPGLYPHMETRICS lpgm,
1058 DWORD cbBuffer,
1059 LPVOID lpvBuffer,
1060 CONST MAT2 *lpmat2
1061 )
1062 {
1063
1064 LPWSTR p = NULL;
1065 DWORD ret;
1066 UINT c;
1067 DPRINT("GetGlyphOutlineA uChar %x\n", uChar);
1068 if(!(uFormat & GGO_GLYPH_INDEX)) {
1069 int len;
1070 char mbchs[2];
1071 if(uChar > 0xff) { /* but, 2 bytes character only */
1072 len = 2;
1073 mbchs[0] = (uChar & 0xff00) >> 8;
1074 mbchs[1] = (uChar & 0xff);
1075 } else {
1076 len = 1;
1077 mbchs[0] = (uChar & 0xff);
1078 }
1079 p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
1080 c = p[0];
1081 } else
1082 c = uChar;
1083 ret = NtGdiGetGlyphOutline(hdc, c, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
1084 HeapFree(GetProcessHeap(), 0, p);
1085 return ret;
1086 }
1087
1088
1089 /*
1090 * @implemented
1091 */
1092 DWORD
1093 WINAPI
1094 GetGlyphOutlineW(
1095 HDC hdc,
1096 UINT uChar,
1097 UINT uFormat,
1098 LPGLYPHMETRICS lpgm,
1099 DWORD cbBuffer,
1100 LPVOID lpvBuffer,
1101 CONST MAT2 *lpmat2
1102 )
1103 {
1104 DPRINT("GetGlyphOutlineW uChar %x\n", uChar);
1105 if (!lpgm & !lpmat2) return GDI_ERROR;
1106 if (!lpvBuffer) cbBuffer = 0;
1107 return NtGdiGetGlyphOutline ( hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
1108 }
1109
1110
1111 /*
1112 * @implemented
1113 */
1114 UINT
1115 APIENTRY
1116 GetOutlineTextMetricsA(
1117 HDC hdc,
1118 UINT cbData,
1119 LPOUTLINETEXTMETRICA lpOTM
1120 )
1121 {
1122 char buf[512], *ptr;
1123 UINT ret, needed;
1124 OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1125 OUTLINETEXTMETRICA *output = lpOTM;
1126 INT left, len;
1127
1128 if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1129 return 0;
1130 if(ret > sizeof(buf))
1131 lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1132 GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1133
1134 needed = sizeof(OUTLINETEXTMETRICA);
1135 if(lpOTMW->otmpFamilyName)
1136 needed += WideCharToMultiByte(CP_ACP, 0,
1137 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
1138 NULL, 0, NULL, NULL);
1139 if(lpOTMW->otmpFaceName)
1140 needed += WideCharToMultiByte(CP_ACP, 0,
1141 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
1142 NULL, 0, NULL, NULL);
1143 if(lpOTMW->otmpStyleName)
1144 needed += WideCharToMultiByte(CP_ACP, 0,
1145 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
1146 NULL, 0, NULL, NULL);
1147 if(lpOTMW->otmpFullName)
1148 needed += WideCharToMultiByte(CP_ACP, 0,
1149 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
1150 NULL, 0, NULL, NULL);
1151
1152 if(!lpOTM) {
1153 ret = needed;
1154 goto end;
1155 }
1156
1157 DPRINT("needed = %d\n", needed);
1158 if(needed > cbData)
1159 /* Since the supplied buffer isn't big enough, we'll alloc one
1160 that is and memcpy the first cbData bytes into the lpOTM at
1161 the end. */
1162 output = HeapAlloc(GetProcessHeap(), 0, needed);
1163
1164 ret = output->otmSize = min(needed, cbData);
1165 FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1166 output->otmFiller = 0;
1167 output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1168 output->otmfsSelection = lpOTMW->otmfsSelection;
1169 output->otmfsType = lpOTMW->otmfsType;
1170 output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1171 output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1172 output->otmItalicAngle = lpOTMW->otmItalicAngle;
1173 output->otmEMSquare = lpOTMW->otmEMSquare;
1174 output->otmAscent = lpOTMW->otmAscent;
1175 output->otmDescent = lpOTMW->otmDescent;
1176 output->otmLineGap = lpOTMW->otmLineGap;
1177 output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1178 output->otmsXHeight = lpOTMW->otmsXHeight;
1179 output->otmrcFontBox = lpOTMW->otmrcFontBox;
1180 output->otmMacAscent = lpOTMW->otmMacAscent;
1181 output->otmMacDescent = lpOTMW->otmMacDescent;
1182 output->otmMacLineGap = lpOTMW->otmMacLineGap;
1183 output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1184 output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1185 output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1186 output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1187 output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1188 output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1189 output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1190 output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1191 output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1192
1193
1194 ptr = (char*)(output + 1);
1195 left = needed - sizeof(*output);
1196
1197 if(lpOTMW->otmpFamilyName) {
1198 output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1199 len = WideCharToMultiByte(CP_ACP, 0,
1200 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
1201 ptr, left, NULL, NULL);
1202 left -= len;
1203 ptr += len;
1204 } else
1205 output->otmpFamilyName = 0;
1206
1207 if(lpOTMW->otmpFaceName) {
1208 output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1209 len = WideCharToMultiByte(CP_ACP, 0,
1210 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
1211 ptr, left, NULL, NULL);
1212 left -= len;
1213 ptr += len;
1214 } else
1215 output->otmpFaceName = 0;
1216
1217 if(lpOTMW->otmpStyleName) {
1218 output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1219 len = WideCharToMultiByte(CP_ACP, 0,
1220 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
1221 ptr, left, NULL, NULL);
1222 left -= len;
1223 ptr += len;
1224 } else
1225 output->otmpStyleName = 0;
1226
1227 if(lpOTMW->otmpFullName) {
1228 output->otmpFullName = (LPSTR)(ptr - (char*)output);
1229 len = WideCharToMultiByte(CP_ACP, 0,
1230 (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
1231 ptr, left, NULL, NULL);
1232 left -= len;
1233 } else
1234 output->otmpFullName = 0;
1235
1236 assert(left == 0);
1237
1238 if(output != lpOTM) {
1239 memcpy(lpOTM, output, cbData);
1240 HeapFree(GetProcessHeap(), 0, output);
1241
1242 /* check if the string offsets really fit into the provided size */
1243 /* FIXME: should we check string length as well? */
1244 if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1245 lpOTM->otmpFamilyName = 0; /* doesn't fit */
1246
1247 if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1248 lpOTM->otmpFaceName = 0; /* doesn't fit */
1249
1250 if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1251 lpOTM->otmpStyleName = 0; /* doesn't fit */
1252
1253 if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1254 lpOTM->otmpFullName = 0; /* doesn't fit */
1255 }
1256
1257 end:
1258 if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1259 HeapFree(GetProcessHeap(), 0, lpOTMW);
1260
1261 return ret;
1262 }
1263
1264
1265 /*
1266 * @implemented
1267 */
1268 UINT
1269 APIENTRY
1270 GetOutlineTextMetricsW(
1271 HDC hdc,
1272 UINT cbData,
1273 LPOUTLINETEXTMETRICW lpOTM
1274 )
1275 {
1276 TMDIFF Tmd; // Should not be zero.
1277
1278 return NtGdiGetOutlineTextMetricsInternalW(hdc, cbData, lpOTM, &Tmd);
1279 }
1280
1281 /*
1282 * @implemented
1283 */
1284 DWORD
1285 WINAPI
1286 GetKerningPairsW(HDC hdc,
1287 ULONG cPairs,
1288 LPKERNINGPAIR pkpDst)
1289 {
1290 if ((cPairs != 0) || (pkpDst == 0))
1291 {
1292 return NtGdiGetKerningPairs(hdc,cPairs,pkpDst);
1293 }
1294 else
1295 {
1296 SetLastError(ERROR_INVALID_PARAMETER);
1297 return 0;
1298 }
1299 }
1300
1301 /*
1302 * @implemented
1303 */
1304 DWORD
1305 WINAPI
1306 GetKerningPairsA( HDC hDC,
1307 DWORD cPairs,
1308 LPKERNINGPAIR kern_pairA )
1309 {
1310 INT charset;
1311 CHARSETINFO csi;
1312 CPINFO cpi;
1313 DWORD i, total_kern_pairs, kern_pairs_copied = 0;
1314 KERNINGPAIR *kern_pairW;
1315
1316 if (!cPairs && kern_pairA)
1317 {
1318 SetLastError(ERROR_INVALID_PARAMETER);
1319 return 0;
1320 }
1321
1322 charset = GetTextCharset(hDC);
1323 if (!TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
1324 {
1325 DPRINT1("Can't find codepage for charset %d\n", charset);
1326 return 0;
1327 }
1328 /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
1329 * to fail on an invalid character for CP_SYMBOL.
1330 */
1331 cpi.DefaultChar[0] = 0;
1332 if (csi.ciACP != CP_SYMBOL && !GetCPInfo(csi.ciACP, &cpi))
1333 {
1334 DPRINT1("Can't find codepage %u info\n", csi.ciACP);
1335 return 0;
1336 }
1337 DPRINT("charset %d => codepage %u\n", charset, csi.ciACP);
1338
1339 total_kern_pairs = NtGdiGetKerningPairs(hDC, 0, NULL);
1340 if (!total_kern_pairs) return 0;
1341
1342 if (!cPairs && !kern_pairA) return total_kern_pairs;
1343
1344 kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
1345 GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
1346
1347 for (i = 0; i < total_kern_pairs; i++)
1348 {
1349 char first, second;
1350
1351 if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
1352 continue;
1353
1354 if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
1355 continue;
1356
1357 if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
1358 continue;
1359
1360 if (kern_pairA)
1361 {
1362 if (kern_pairs_copied >= cPairs) break;
1363
1364 kern_pairA->wFirst = (BYTE)first;
1365 kern_pairA->wSecond = (BYTE)second;
1366 kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
1367 kern_pairA++;
1368 }
1369 kern_pairs_copied++;
1370 }
1371
1372 HeapFree(GetProcessHeap(), 0, kern_pairW);
1373
1374 return kern_pairs_copied;
1375 }
1376
1377
1378
1379 /*
1380 * @implemented
1381 */
1382 HFONT
1383 WINAPI
1384 CreateFontIndirectExA(const ENUMLOGFONTEXDVA *elfexd)
1385 {
1386 if (elfexd)
1387 {
1388 ENUMLOGFONTEXDVW Logfont;
1389
1390 EnumLogFontExW2A( (LPENUMLOGFONTEXA) elfexd,
1391 &Logfont.elfEnumLogfontEx );
1392
1393 RtlCopyMemory( &Logfont.elfDesignVector,
1394 (PVOID) &elfexd->elfDesignVector,
1395 sizeof(DESIGNVECTOR));
1396
1397 return NtGdiHfontCreate( &Logfont, 0, 0, 0, NULL);
1398 }
1399 else return NULL;
1400 }
1401
1402
1403 /*
1404 * @implemented
1405 */
1406 HFONT
1407 WINAPI
1408 CreateFontIndirectExW(const ENUMLOGFONTEXDVW *elfexd)
1409 {
1410 /* Msdn: Note, this function ignores the elfDesignVector member in
1411 ENUMLOGFONTEXDV.
1412 */
1413 if ( elfexd )
1414 {
1415 return NtGdiHfontCreate((PENUMLOGFONTEXDVW) elfexd, 0, 0, 0, NULL );
1416 }
1417 else return NULL;
1418 }
1419
1420
1421 /*
1422 * @implemented
1423 */
1424 HFONT
1425 WINAPI
1426 CreateFontIndirectA(
1427 CONST LOGFONTA *lplf
1428 )
1429 {
1430 if (lplf)
1431 {
1432 LOGFONTW tlf;
1433
1434 LogFontA2W(&tlf, lplf);
1435 return CreateFontIndirectW(&tlf);
1436 }
1437 else return NULL;
1438 }
1439
1440
1441 /*
1442 * @implemented
1443 */
1444 HFONT
1445 WINAPI
1446 CreateFontIndirectW(
1447 CONST LOGFONTW *lplf
1448 )
1449 {
1450 if (lplf)
1451 {
1452 ENUMLOGFONTEXDVW Logfont;
1453
1454 RtlCopyMemory( &Logfont.elfEnumLogfontEx.elfLogFont, lplf, sizeof(LOGFONTW));
1455 // Need something other than just cleaning memory here.
1456 // Guess? Use caller data to determine the rest.
1457 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfFullName,
1458 sizeof(Logfont.elfEnumLogfontEx.elfFullName));
1459 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfStyle,
1460 sizeof(Logfont.elfEnumLogfontEx.elfStyle));
1461 RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfScript,
1462 sizeof(Logfont.elfEnumLogfontEx.elfScript));
1463
1464 Logfont.elfDesignVector.dvNumAxes = 0; // No more than MM_MAX_NUMAXES
1465
1466 RtlZeroMemory( &Logfont.elfDesignVector, sizeof(DESIGNVECTOR));
1467
1468 return CreateFontIndirectExW(&Logfont);
1469 }
1470 else return NULL;
1471 }
1472
1473
1474 /*
1475 * @implemented
1476 */
1477 HFONT
1478 WINAPI
1479 CreateFontA(
1480 int nHeight,
1481 int nWidth,
1482 int nEscapement,
1483 int nOrientation,
1484 int fnWeight,
1485 DWORD fdwItalic,
1486 DWORD fdwUnderline,
1487 DWORD fdwStrikeOut,
1488 DWORD fdwCharSet,
1489 DWORD fdwOutputPrecision,
1490 DWORD fdwClipPrecision,
1491 DWORD fdwQuality,
1492 DWORD fdwPitchAndFamily,
1493 LPCSTR lpszFace
1494 )
1495 {
1496 ANSI_STRING StringA;
1497 UNICODE_STRING StringU;
1498 HFONT ret;
1499
1500 RtlInitAnsiString(&StringA, (LPSTR)lpszFace);
1501 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
1502
1503 ret = CreateFontW(nHeight,
1504 nWidth,
1505 nEscapement,
1506 nOrientation,
1507 fnWeight,
1508 fdwItalic,
1509 fdwUnderline,
1510 fdwStrikeOut,
1511 fdwCharSet,
1512 fdwOutputPrecision,
1513 fdwClipPrecision,
1514 fdwQuality,
1515 fdwPitchAndFamily,
1516 StringU.Buffer);
1517
1518 RtlFreeUnicodeString(&StringU);
1519
1520 return ret;
1521 }
1522
1523
1524 /*
1525 * @implemented
1526 */
1527 HFONT
1528 WINAPI
1529 CreateFontW(
1530 int nHeight,
1531 int nWidth,
1532 int nEscapement,
1533 int nOrientation,
1534 int nWeight,
1535 DWORD fnItalic,
1536 DWORD fdwUnderline,
1537 DWORD fdwStrikeOut,
1538 DWORD fdwCharSet,
1539 DWORD fdwOutputPrecision,
1540 DWORD fdwClipPrecision,
1541 DWORD fdwQuality,
1542 DWORD fdwPitchAndFamily,
1543 LPCWSTR lpszFace
1544 )
1545 {
1546 LOGFONTW logfont;
1547
1548 logfont.lfHeight = nHeight;
1549 logfont.lfWidth = nWidth;
1550 logfont.lfEscapement = nEscapement;
1551 logfont.lfOrientation = nOrientation;
1552 logfont.lfWeight = nWeight;
1553 logfont.lfItalic = fnItalic;
1554 logfont.lfUnderline = fdwUnderline;
1555 logfont.lfStrikeOut = fdwStrikeOut;
1556 logfont.lfCharSet = fdwCharSet;
1557 logfont.lfOutPrecision = fdwOutputPrecision;
1558 logfont.lfClipPrecision = fdwClipPrecision;
1559 logfont.lfQuality = fdwQuality;
1560 logfont.lfPitchAndFamily = fdwPitchAndFamily;
1561
1562 if (NULL != lpszFace)
1563 {
1564 int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
1565 wcsncpy((wchar_t *)logfont.lfFaceName, lpszFace, Size - 1);
1566 /* Be 101% sure to have '\0' at end of string */
1567 logfont.lfFaceName[Size - 1] = '\0';
1568 }
1569 else
1570 {
1571 logfont.lfFaceName[0] = L'\0';
1572 }
1573
1574 return CreateFontIndirectW(&logfont);
1575 }
1576
1577
1578 /*
1579 * @unimplemented
1580 */
1581 BOOL
1582 WINAPI
1583 CreateScalableFontResourceA(
1584 DWORD fdwHidden,
1585 LPCSTR lpszFontRes,
1586 LPCSTR lpszFontFile,
1587 LPCSTR lpszCurrentPath
1588 )
1589 {
1590 return FALSE;
1591 }
1592
1593
1594 /*
1595 * @implemented
1596 */
1597 int
1598 WINAPI
1599 AddFontResourceExW ( LPCWSTR lpszFilename, DWORD fl, PVOID pvReserved )
1600 {
1601 if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
1602 {
1603 SetLastError( ERROR_INVALID_PARAMETER );
1604 return 0;
1605 }
1606
1607 return GdiAddFontResourceW(lpszFilename, fl,0);
1608 }
1609
1610
1611 /*
1612 * @implemented
1613 */
1614 int
1615 WINAPI
1616 AddFontResourceExA ( LPCSTR lpszFilename, DWORD fl, PVOID pvReserved )
1617 {
1618 NTSTATUS Status;
1619 PWSTR FilenameW;
1620 int rc;
1621
1622 if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
1623 {
1624 SetLastError( ERROR_INVALID_PARAMETER );
1625 return 0;
1626 }
1627
1628 Status = HEAP_strdupA2W ( &FilenameW, lpszFilename );
1629 if ( !NT_SUCCESS (Status) )
1630 {
1631 SetLastError (RtlNtStatusToDosError(Status));
1632 return 0;
1633 }
1634
1635 rc = GdiAddFontResourceW ( FilenameW, fl, 0 );
1636 HEAP_free ( FilenameW );
1637 return rc;
1638 }
1639
1640
1641 /*
1642 * @implemented
1643 */
1644 int
1645 WINAPI
1646 AddFontResourceA ( LPCSTR lpszFilename )
1647 {
1648 NTSTATUS Status;
1649 PWSTR FilenameW;
1650 int rc = 0;
1651
1652 Status = HEAP_strdupA2W ( &FilenameW, lpszFilename );
1653 if ( !NT_SUCCESS (Status) )
1654 {
1655 SetLastError (RtlNtStatusToDosError(Status));
1656 }
1657 else
1658 {
1659 rc = GdiAddFontResourceW ( FilenameW, 0, 0);
1660
1661 HEAP_free ( FilenameW );
1662 }
1663 return rc;
1664 }
1665
1666
1667 /*
1668 * @implemented
1669 */
1670 int
1671 WINAPI
1672 AddFontResourceW ( LPCWSTR lpszFilename )
1673 {
1674 return GdiAddFontResourceW ( lpszFilename, 0, 0 );
1675 }
1676
1677
1678 /*
1679 * @implemented
1680 */
1681 BOOL
1682 WINAPI
1683 RemoveFontResourceW(LPCWSTR lpFileName)
1684 {
1685 return RemoveFontResourceExW(lpFileName,0,0);
1686 }
1687
1688
1689 /*
1690 * @implemented
1691 */
1692 BOOL
1693 WINAPI
1694 RemoveFontResourceA(LPCSTR lpFileName)
1695 {
1696 return RemoveFontResourceExA(lpFileName,0,0);
1697 }
1698
1699 /*
1700 * @unimplemented
1701 */
1702 BOOL
1703 WINAPI
1704 RemoveFontResourceExA(LPCSTR lpFileName,
1705 DWORD fl,
1706 PVOID pdv
1707 )
1708 {
1709 NTSTATUS Status;
1710 LPWSTR lpFileNameW;
1711
1712 /* FIXME the flags */
1713 /* FIXME the pdv */
1714 /* FIXME NtGdiRemoveFontResource handle flags and pdv */
1715
1716 Status = HEAP_strdupA2W ( &lpFileNameW, lpFileName );
1717 if (!NT_SUCCESS (Status))
1718 SetLastError (RtlNtStatusToDosError(Status));
1719 else
1720 {
1721
1722 HEAP_free ( lpFileNameW );
1723 }
1724
1725 return 0;
1726 }
1727
1728 /*
1729 * @unimplemented
1730 */
1731 BOOL
1732 WINAPI
1733 RemoveFontResourceExW(LPCWSTR lpFileName,
1734 DWORD fl,
1735 PVOID pdv)
1736 {
1737 /* FIXME the flags */
1738 /* FIXME the pdv */
1739 /* FIXME NtGdiRemoveFontResource handle flags and pdv */
1740 return 0;
1741 }
1742
1743
1744 /***********************************************************************
1745 * GdiGetCharDimensions
1746 *
1747 * Gets the average width of the characters in the English alphabet.
1748 *
1749 * PARAMS
1750 * hdc [I] Handle to the device context to measure on.
1751 * lptm [O] Pointer to memory to store the text metrics into.
1752 * height [O] On exit, the maximum height of characters in the English alphabet.
1753 *
1754 * RETURNS
1755 * The average width of characters in the English alphabet.
1756 *
1757 * NOTES
1758 * This function is used by the dialog manager to get the size of a dialog
1759 * unit. It should also be used by other pieces of code that need to know
1760 * the size of a dialog unit in logical units without having access to the
1761 * window handle of the dialog.
1762 * Windows caches the font metrics from this function, but we don't and
1763 * there doesn't appear to be an immediate advantage to do so.
1764 *
1765 * SEE ALSO
1766 * GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
1767 *
1768 * Despite most of MSDN insisting that the horizontal base unit is
1769 * tmAveCharWidth it isn't. Knowledge base article Q145994
1770 * "HOWTO: Calculate Dialog Units When Not Using the System Font",
1771 * says that we should take the average of the 52 English upper and lower
1772 * case characters.
1773 */
1774 /*
1775 * @implemented
1776 */
1777 DWORD
1778 WINAPI
1779 GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
1780 {
1781 SIZE sz;
1782 TEXTMETRICW tm;
1783 static const WCHAR alphabet[] = {
1784 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
1785 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
1786 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0};
1787
1788 if(!GetTextMetricsW(hdc, &tm)) return 0;
1789
1790 if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
1791
1792 if (lptm) *lptm = tm;
1793 if (height) *height = tm.tmHeight;
1794
1795 return (sz.cx / 26 + 1) / 2;
1796 }
1797
1798 /*************************************************************************
1799 * TranslateCharsetInfo [GDI32.@]
1800 *
1801 * Fills a CHARSETINFO structure for a character set, code page, or
1802 * font. This allows making the correspondance between different labelings
1803 * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1804 * of the same encoding.
1805 *
1806 * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
1807 * only one codepage should be set in *lpSrc.
1808 *
1809 * RETURNS
1810 * TRUE on success, FALSE on failure.
1811 *
1812 */
1813 /*
1814 * @unimplemented
1815 */
1816 BOOL
1817 WINAPI
1818 TranslateCharsetInfo(
1819 LPDWORD lpSrc, /* [in]
1820 if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1821 if flags == TCI_SRCCHARSET: a character set value
1822 if flags == TCI_SRCCODEPAGE: a code page value
1823 */
1824 LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
1825 DWORD flags /* [in] determines interpretation of lpSrc */)
1826 {
1827 int index = 0;
1828 switch (flags) {
1829 case TCI_SRCFONTSIG:
1830 while (!(*lpSrc>>index & 0x0001) && index<MAXTCIINDEX) index++;
1831 break;
1832 case TCI_SRCCODEPAGE:
1833 while (PtrToUlong(lpSrc) != FONT_tci[index].ciACP && index < MAXTCIINDEX) index++;
1834 break;
1835 case TCI_SRCCHARSET:
1836 while (PtrToUlong(lpSrc) != FONT_tci[index].ciCharset && index < MAXTCIINDEX) index++;
1837 break;
1838 default:
1839 return FALSE;
1840 }
1841 if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
1842 memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO));
1843 return TRUE;
1844 }
1845
1846
1847 /*
1848 * @implemented
1849 */
1850 DWORD
1851 WINAPI
1852 SetMapperFlags(
1853 HDC hDC,
1854 DWORD flags
1855 )
1856 {
1857 DWORD Ret = GDI_ERROR;
1858 PDC_ATTR Dc_Attr;
1859 #if 0
1860 if (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)
1861 {
1862 if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_METADC)
1863 return MFDRV_SetMapperFlags( hDC, flags);
1864 else
1865 {
1866 PLDC pLDC = Dc_Attr->pvLDC;
1867 if ( !pLDC )
1868 {
1869 SetLastError(ERROR_INVALID_HANDLE);
1870 return GDI_ERROR;
1871 }
1872 if (pLDC->iType == LDC_EMFLDC)
1873 {
1874 return EMFDRV_SetMapperFlags( hDC, flags);
1875 }
1876 }
1877 }
1878 #endif
1879 if (!GdiGetHandleUserData((HGDIOBJ) hDC, GDI_OBJECT_TYPE_DC, (PVOID) &Dc_Attr)) return GDI_ERROR;
1880
1881 if (NtCurrentTeb()->GdiTebBatch.HDC == hDC)
1882 {
1883 if (Dc_Attr->ulDirty_ & DC_FONTTEXT_DIRTY)
1884 {
1885 NtGdiFlush();
1886 Dc_Attr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
1887 }
1888 }
1889
1890 if ( flags & ~1 )
1891 SetLastError(ERROR_INVALID_PARAMETER);
1892 else
1893 {
1894 Ret = Dc_Attr->flFontMapper;
1895 Dc_Attr->flFontMapper = flags;
1896 }
1897 return Ret;
1898 }
1899
1900
1901 /*
1902 * @unimplemented
1903 */
1904 int
1905 WINAPI
1906 EnumFontsW(
1907 HDC hDC,
1908 LPCWSTR lpFaceName,
1909 FONTENUMPROCW FontFunc,
1910 LPARAM lParam
1911 )
1912 {
1913 #if 0
1914 return NtGdiEnumFonts ( hDC, lpFaceName, FontFunc, lParam );
1915 #else
1916 return EnumFontFamiliesW( hDC, lpFaceName, FontFunc, lParam );
1917 #endif
1918 }
1919
1920 /*
1921 * @unimplemented
1922 */
1923 int
1924 WINAPI
1925 EnumFontsA (
1926 HDC hDC,
1927 LPCSTR lpFaceName,
1928 FONTENUMPROCA FontFunc,
1929 LPARAM lParam
1930 )
1931 {
1932 #if 0
1933 NTSTATUS Status;
1934 LPWSTR lpFaceNameW;
1935 int rc = 0;
1936
1937 Status = HEAP_strdupA2W ( &lpFaceNameW, lpFaceName );
1938 if (!NT_SUCCESS (Status))
1939 SetLastError (RtlNtStatusToDosError(Status));
1940 else
1941 {
1942 rc = NtGdiEnumFonts ( hDC, lpFaceNameW, FontFunc, lParam );
1943
1944 HEAP_free ( lpFaceNameW );
1945 }
1946 return rc;
1947 #else
1948 return EnumFontFamiliesA( hDC, lpFaceName, FontFunc, lParam );
1949 #endif
1950 }
1951
1952 #define EfdFontFamilies 3
1953
1954 INT
1955 WINAPI
1956 NewEnumFontFamiliesExW(
1957 HDC hDC,
1958 LPLOGFONTW lpLogfont,
1959 FONTENUMPROCW lpEnumFontFamExProcW,
1960 LPARAM lParam,
1961 DWORD dwFlags)
1962 {
1963 ULONG_PTR idEnum, cbDataSize, cbRetSize;
1964 PENUMFONTDATAW pEfdw;
1965 PBYTE pBuffer;
1966 PBYTE pMax;
1967 INT ret = 1;
1968
1969 /* Open enumeration handle and find out how much memory we need */
1970 idEnum = NtGdiEnumFontOpen(hDC,
1971 EfdFontFamilies,
1972 0,
1973 LF_FACESIZE,
1974 (lpLogfont && lpLogfont->lfFaceName[0])? lpLogfont->lfFaceName : NULL,
1975 lpLogfont? lpLogfont->lfCharSet : DEFAULT_CHARSET,
1976 &cbDataSize);
1977 if (idEnum == 0)
1978 {
1979 return 0;
1980 }
1981 if (cbDataSize == 0)
1982 {
1983 NtGdiEnumFontClose(idEnum);
1984 return 0;
1985 }
1986
1987 /* Allocate memory */
1988 pBuffer = HeapAlloc(GetProcessHeap(), 0, cbDataSize);
1989 if (pBuffer == NULL)
1990 {
1991 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1992 NtGdiEnumFontClose(idEnum);
1993 return 0;
1994 }
1995
1996 /* Do the enumeration */
1997 if (!NtGdiEnumFontChunk(hDC, idEnum, cbDataSize, &cbRetSize, (PVOID)pBuffer))
1998 {
1999 HeapFree(GetProcessHeap(), 0, pBuffer);
2000 NtGdiEnumFontClose(idEnum);
2001 return 0;
2002 }
2003
2004 /* Get start and end address */
2005 pEfdw = (PENUMFONTDATAW)pBuffer;
2006 pMax = pBuffer + cbDataSize;
2007
2008 /* Iterate through the structures */
2009 while ((PBYTE)pEfdw < pMax && ret)
2010 {
2011 PNTMW_INTERNAL pNtmwi = (PNTMW_INTERNAL)((ULONG_PTR)pEfdw + pEfdw->ulNtmwiOffset);
2012
2013 ret = lpEnumFontFamExProcW((VOID*)&pEfdw->elfexdv.elfEnumLogfontEx,
2014 (VOID*)&pNtmwi->ntmw,
2015 pEfdw->dwFontType,
2016 lParam);
2017
2018 pEfdw = (PENUMFONTDATAW)((ULONG_PTR)pEfdw + pEfdw->cbSize);
2019 }
2020
2021 /* Release the memory and close handle */
2022 HeapFree(GetProcessHeap(), 0, pBuffer);
2023 NtGdiEnumFontClose(idEnum);
2024
2025 return ret;
2026 }