xref: /reactos/win32ss/gdi/gdi32/objects/font.c (revision f2df3bf0)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            win32ss/gdi/gdi32/objects/font.c
5  * PURPOSE:
6  * PROGRAMMER:
7  *
8  */
9 
10 #include <precomp.h>
11 
12 #include <math.h>
13 #include <strsafe.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* Rounds a floating point number to integer. The world-to-viewport
19  * transformation process is done in floating point internally. This function
20  * is then used to round these coordinates to integer values.
21  */
22 static __inline INT GDI_ROUND(FLOAT val)
23 {
24    return (int)floor(val + 0.5);
25 }
26 
27 /*
28  *  For TranslateCharsetInfo
29  */
30 #define MAXTCIINDEX 32
31 static const CHARSETINFO FONT_tci[MAXTCIINDEX] =
32 {
33     /* ANSI */
34     { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
35     { EASTEUROPE_CHARSET, 1250, {{0,0,0,0},{FS_LATIN2,0}} },
36     { RUSSIAN_CHARSET, 1251, {{0,0,0,0},{FS_CYRILLIC,0}} },
37     { GREEK_CHARSET, 1253, {{0,0,0,0},{FS_GREEK,0}} },
38     { TURKISH_CHARSET, 1254, {{0,0,0,0},{FS_TURKISH,0}} },
39     { HEBREW_CHARSET, 1255, {{0,0,0,0},{FS_HEBREW,0}} },
40     { ARABIC_CHARSET, 1256, {{0,0,0,0},{FS_ARABIC,0}} },
41     { BALTIC_CHARSET, 1257, {{0,0,0,0},{FS_BALTIC,0}} },
42     { VIETNAMESE_CHARSET, 1258, {{0,0,0,0},{FS_VIETNAMESE,0}} },
43     /* reserved by ANSI */
44     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
45     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
46     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
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     /* ANSI and OEM */
52     { THAI_CHARSET, 874, {{0,0,0,0},{FS_THAI,0}} },
53     { SHIFTJIS_CHARSET, 932, {{0,0,0,0},{FS_JISJAPAN,0}} },
54     { GB2312_CHARSET, 936, {{0,0,0,0},{FS_CHINESESIMP,0}} },
55     { HANGEUL_CHARSET, 949, {{0,0,0,0},{FS_WANSUNG,0}} },
56     { CHINESEBIG5_CHARSET, 950, {{0,0,0,0},{FS_CHINESETRAD,0}} },
57     { JOHAB_CHARSET, 1361, {{0,0,0,0},{FS_JOHAB,0}} },
58     /* reserved for alternate ANSI and OEM */
59     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
60     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
61     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
62     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
63     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
64     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
65     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
66     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
67     /* reserved for system */
68     { DEFAULT_CHARSET, 0, {{0,0,0,0},{FS_LATIN1,0}} },
69     { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
70 };
71 
72 #define INITIAL_FAMILY_COUNT 64
73 
74 /***********************************************************************
75  *              TEXTMETRIC conversion functions.
76  */
77 VOID
78 FASTCALL
79 FONT_TextMetricWToA(const TEXTMETRICW *ptmW, LPTEXTMETRICA ptmA )
80 {
81     ptmA->tmHeight = ptmW->tmHeight;
82     ptmA->tmAscent = ptmW->tmAscent;
83     ptmA->tmDescent = ptmW->tmDescent;
84     ptmA->tmInternalLeading = ptmW->tmInternalLeading;
85     ptmA->tmExternalLeading = ptmW->tmExternalLeading;
86     ptmA->tmAveCharWidth = ptmW->tmAveCharWidth;
87     ptmA->tmMaxCharWidth = ptmW->tmMaxCharWidth;
88     ptmA->tmWeight = ptmW->tmWeight;
89     ptmA->tmOverhang = ptmW->tmOverhang;
90     ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
91     ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
92     ptmA->tmFirstChar = min(ptmW->tmFirstChar, 255);
93     if (ptmW->tmCharSet == SYMBOL_CHARSET)
94     {
95         ptmA->tmFirstChar = 0x1e;
96         ptmA->tmLastChar = 0xff;  /* win9x behaviour - we need the OS2 table data to calculate correctly */
97     }
98     else
99     {
100         ptmA->tmFirstChar = ptmW->tmDefaultChar - 1;
101         ptmA->tmLastChar = min(ptmW->tmLastChar, 0xff);
102     }
103     ptmA->tmDefaultChar = (CHAR)ptmW->tmDefaultChar;
104     ptmA->tmBreakChar = (CHAR)ptmW->tmBreakChar;
105     ptmA->tmItalic = ptmW->tmItalic;
106     ptmA->tmUnderlined = ptmW->tmUnderlined;
107     ptmA->tmStruckOut = ptmW->tmStruckOut;
108     ptmA->tmPitchAndFamily = ptmW->tmPitchAndFamily;
109     ptmA->tmCharSet = ptmW->tmCharSet;
110 }
111 
112 /***********************************************************************
113  *           FONT_mbtowc
114  *
115  * Returns a Unicode translation of str using the charset of the
116  * currently selected font in hdc.  If count is -1 then str is assumed
117  * to be '\0' terminated, otherwise it contains the number of bytes to
118  * convert.  If plenW is non-NULL, on return it will point to the
119  * number of WCHARs that have been written.  If pCP is non-NULL, on
120  * return it will point to the codepage used in the conversion.  The
121  * caller should free the returned LPWSTR from the process heap
122  * itself.
123  */
124 static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
125 {
126     UINT cp = GdiGetCodePage( hdc );
127     INT lenW;
128     LPWSTR strW;
129 
130     if(count == -1) count = strlen(str);
131     lenW = MultiByteToWideChar(cp, 0, str, count, NULL, 0);
132     strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
133     if (!strW)
134         return NULL;
135     if(!MultiByteToWideChar(cp, 0, str, count, strW, lenW))
136     {
137         HeapFree(GetProcessHeap(), 0, strW);
138         return NULL;
139     }
140     DPRINT("mapped %s -> %S\n", str, strW);
141     if(plenW) *plenW = lenW;
142     if(pCP) *pCP = cp;
143     return strW;
144 }
145 
146 static LPSTR FONT_GetCharsByRangeA(HDC hdc, UINT firstChar, UINT lastChar, PINT pByteLen)
147 {
148     INT i, count = lastChar - firstChar + 1;
149     UINT c;
150     LPSTR str;
151 
152     if (count <= 0)
153         return NULL;
154 
155     switch (GdiGetCodePage(hdc))
156     {
157     case 932:
158     case 936:
159     case 949:
160     case 950:
161     case 1361:
162         if (lastChar > 0xffff)
163             return NULL;
164         if ((firstChar ^ lastChar) > 0xff)
165             return NULL;
166         break;
167     default:
168         if (lastChar > 0xff)
169             return NULL;
170         break;
171     }
172 
173     str = HeapAlloc(GetProcessHeap(), 0, count * 2 + 1);
174     if (str == NULL)
175         return NULL;
176 
177     for(i = 0, c = firstChar; c <= lastChar; i++, c++)
178     {
179         if (c > 0xff)
180             str[i++] = (BYTE)(c >> 8);
181         str[i] = (BYTE)c;
182     }
183     str[i] = '\0';
184 
185     *pByteLen = i;
186 
187     return str;
188 }
189 
190 VOID FASTCALL
191 NewTextMetricW2A(NEWTEXTMETRICA *tma, NEWTEXTMETRICW *tmw)
192 {
193     FONT_TextMetricWToA((TEXTMETRICW *) tmw, (TEXTMETRICA *) tma);
194     tma->ntmFlags = tmw->ntmFlags;
195     tma->ntmSizeEM = tmw->ntmSizeEM;
196     tma->ntmCellHeight = tmw->ntmCellHeight;
197     tma->ntmAvgWidth = tmw->ntmAvgWidth;
198 }
199 
200 VOID FASTCALL
201 NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
202 {
203     NewTextMetricW2A(&tma->ntmTm, &tmw->ntmTm);
204     tma->ntmFontSig = tmw->ntmFontSig;
205 }
206 
207 static int FASTCALL
208 IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
209                     BOOL Unicode)
210 {
211     int FontFamilyCount;
212     int FontFamilySize;
213     PFONTFAMILYINFO Info;
214     int Ret = 1;
215     int i;
216     ENUMLOGFONTEXA EnumLogFontExA;
217     NEWTEXTMETRICEXA NewTextMetricExA;
218     LOGFONTW lfW;
219 
220     Info = RtlAllocateHeap(GetProcessHeap(), 0,
221                            INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO));
222     if (NULL == Info)
223     {
224         return 1;
225     }
226 
227     if (!LogFont)
228     {
229         lfW.lfCharSet = DEFAULT_CHARSET;
230         lfW.lfPitchAndFamily = 0;
231         lfW.lfFaceName[0] = 0;
232         LogFont = &lfW;
233     }
234 
235     FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT);
236     if (FontFamilyCount < 0)
237     {
238         RtlFreeHeap(GetProcessHeap(), 0, Info);
239         return 1;
240     }
241     if (INITIAL_FAMILY_COUNT < FontFamilyCount)
242     {
243         FontFamilySize = FontFamilyCount;
244         RtlFreeHeap(GetProcessHeap(), 0, Info);
245         Info = RtlAllocateHeap(GetProcessHeap(), 0,
246                                FontFamilyCount * sizeof(FONTFAMILYINFO));
247         if (NULL == Info)
248         {
249             return 1;
250         }
251         FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize);
252         if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount)
253         {
254             RtlFreeHeap(GetProcessHeap(), 0, Info);
255             return 1;
256         }
257     }
258 
259     for (i = 0; i < FontFamilyCount; i++)
260     {
261         if (Unicode)
262         {
263             Ret = ((FONTENUMPROCW) EnumProc)(
264                       (VOID*)&Info[i].EnumLogFontEx,
265                       (VOID*)&Info[i].NewTextMetricEx,
266                       Info[i].FontType, lParam);
267         }
268         else
269         {
270             // Could use EnumLogFontExW2A here?
271             LogFontW2A(&EnumLogFontExA.elfLogFont, &Info[i].EnumLogFontEx.elfLogFont);
272             WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfFullName, -1,
273                                 (LPSTR)EnumLogFontExA.elfFullName, LF_FULLFACESIZE, NULL, NULL);
274             WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfStyle, -1,
275                                 (LPSTR)EnumLogFontExA.elfStyle, LF_FACESIZE, NULL, NULL);
276             WideCharToMultiByte(CP_THREAD_ACP, 0, Info[i].EnumLogFontEx.elfScript, -1,
277                                 (LPSTR)EnumLogFontExA.elfScript, LF_FACESIZE, NULL, NULL);
278             NewTextMetricExW2A(&NewTextMetricExA,
279                                &Info[i].NewTextMetricEx);
280             Ret = ((FONTENUMPROCA) EnumProc)(
281                       (VOID*)&EnumLogFontExA,
282                       (VOID*)&NewTextMetricExA,
283                       Info[i].FontType, lParam);
284         }
285 
286         if(Ret == 0)
287             break;
288     }
289 
290     RtlFreeHeap(GetProcessHeap(), 0, Info);
291 
292     return Ret;
293 }
294 
295 /*
296  * @implemented
297  */
298 int WINAPI
299 EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
300                     LPARAM lParam, DWORD dwFlags)
301 {
302     return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE);
303 }
304 
305 
306 /*
307  * @implemented
308  */
309 int WINAPI
310 EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
311                   LPARAM lParam)
312 {
313     LOGFONTW LogFont;
314 
315     ZeroMemory(&LogFont, sizeof(LOGFONTW));
316     LogFont.lfCharSet = DEFAULT_CHARSET;
317     if (NULL != lpszFamily)
318     {
319         if (!*lpszFamily) return 1;
320         lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
321     }
322 
323     return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE);
324 }
325 
326 
327 /*
328  * @implemented
329  */
330 int WINAPI
331 EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamExProc,
332                      LPARAM lParam, DWORD dwFlags)
333 {
334     LOGFONTW LogFontW, *pLogFontW;
335 
336     if (lpLogfont)
337     {
338         LogFontA2W(&LogFontW,lpLogfont);
339         pLogFontW = &LogFontW;
340     }
341     else pLogFontW = NULL;
342 
343     /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
344     return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, FALSE);
345 }
346 
347 
348 /*
349  * @implemented
350  */
351 int WINAPI
352 EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
353                   LPARAM lParam)
354 {
355     LOGFONTW LogFont;
356 
357     ZeroMemory(&LogFont, sizeof(LOGFONTW));
358     LogFont.lfCharSet = DEFAULT_CHARSET;
359     if (NULL != lpszFamily)
360     {
361         if (!*lpszFamily) return 1;
362         MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
363     }
364 
365     return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, FALSE);
366 }
367 
368 
369 /*
370  * @implemented
371  */
372 DWORD
373 WINAPI
374 GetCharacterPlacementA(
375     HDC hdc,
376     LPCSTR lpString,
377     INT uCount,
378     INT nMaxExtent,
379     GCP_RESULTSA *lpResults,
380     DWORD dwFlags)
381 {
382     WCHAR *lpStringW;
383     INT uCountW;
384     GCP_RESULTSW resultsW;
385     DWORD ret;
386     UINT font_cp;
387 
388     if ( !lpString || uCount <= 0 || !lpResults || (nMaxExtent < 0 && nMaxExtent != -1 ) )
389     {
390         SetLastError(ERROR_INVALID_PARAMETER);
391         return 0;
392     }
393     /*    TRACE("%s, %d, %d, 0x%08x\n",
394               debugstr_an(lpString, uCount), uCount, nMaxExtent, dwFlags);
395     */
396     /* both structs are equal in size */
397     memcpy(&resultsW, lpResults, sizeof(resultsW));
398 
399     lpStringW = FONT_mbtowc(hdc, lpString, uCount, &uCountW, &font_cp);
400     if (lpStringW == NULL)
401     {
402         return 0;
403     }
404     if(lpResults->lpOutString)
405     {
406         resultsW.lpOutString = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*uCountW);
407         if (resultsW.lpOutString == NULL)
408         {
409             HeapFree(GetProcessHeap(), 0, lpStringW);
410             return 0;
411         }
412     }
413 
414     ret = GetCharacterPlacementW(hdc, lpStringW, uCountW, nMaxExtent, &resultsW, dwFlags);
415 
416     lpResults->nGlyphs = resultsW.nGlyphs;
417     lpResults->nMaxFit = resultsW.nMaxFit;
418 
419     if(lpResults->lpOutString)
420     {
421         WideCharToMultiByte(font_cp, 0, resultsW.lpOutString, uCountW,
422                             lpResults->lpOutString, uCount, NULL, NULL );
423     }
424 
425     HeapFree(GetProcessHeap(), 0, lpStringW);
426     HeapFree(GetProcessHeap(), 0, resultsW.lpOutString);
427 
428     return ret;
429 }
430 
431 
432 /*
433  * @implemented
434  */
435 DWORD
436 WINAPI
437 GetCharacterPlacementW(
438     HDC hdc,
439     LPCWSTR lpString,
440     INT uCount,
441     INT nMaxExtent,
442     GCP_RESULTSW *lpResults,
443     DWORD dwFlags
444 )
445 {
446     DWORD ret=0;
447     SIZE size;
448     UINT i, nSet;
449     DPRINT("GetCharacterPlacementW\n");
450 
451     if (dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
452     if (lpResults->lpClass) DPRINT("classes not implemented\n");
453 
454     nSet = (UINT)uCount;
455     if (nSet > lpResults->nGlyphs)
456         nSet = lpResults->nGlyphs;
457 
458     /* return number of initialized fields */
459     lpResults->nGlyphs = nSet;
460 
461     if (dwFlags & GCP_REORDER)
462     {
463         if (LoadLPK(LPK_GCP))
464             return LpkGetCharacterPlacement(hdc, lpString, uCount, nMaxExtent, lpResults, dwFlags, 0);
465     }
466 
467     /* Treat the case where no special handling was requested in a fastpath way */
468     /* copy will do if the GCP_REORDER flag is not set */
469     if (lpResults->lpOutString)
470         lstrcpynW( lpResults->lpOutString, lpString, nSet );
471 
472     if (lpResults->lpOrder)
473     {
474         for (i = 0; i < nSet; i++)
475             lpResults->lpOrder[i] = i;
476     }
477 
478     /* FIXME: Will use the placement chars */
479     if (lpResults->lpDx)
480     {
481         int c;
482         for (i = 0; i < nSet; i++)
483         {
484             if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
485                 lpResults->lpDx[i]= c;
486         }
487     }
488 
489     if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
490     {
491         int pos = 0;
492 
493         lpResults->lpCaretPos[0] = 0;
494         for (i = 1; i < nSet; i++)
495             if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
496                 lpResults->lpCaretPos[i] = (pos += size.cx);
497     }
498 
499     if (lpResults->lpGlyphs)
500         NtGdiGetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
501 
502     if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
503         ret = MAKELONG(size.cx, size.cy);
504 
505     return ret;
506 }
507 
508 DWORD
509 WINAPI
510 NewGetCharacterPlacementW(
511     HDC hdc,
512     LPCWSTR lpString,
513     INT uCount,
514     INT nMaxExtent,
515     GCP_RESULTSW *lpResults,
516     DWORD dwFlags
517 )
518 {
519     ULONG nSet;
520     SIZE Size = {0,0};
521 
522     if ( !lpString || uCount <= 0 || (nMaxExtent < 0 && nMaxExtent != -1 ) )
523     {
524         SetLastError(ERROR_INVALID_PARAMETER);
525         return 0;
526     }
527 
528     if ( !lpResults )
529     {
530         if ( GetTextExtentPointW(hdc, lpString, uCount, &Size) )
531         {
532             return MAKELONG(Size.cx, Size.cy);
533         }
534         return 0;
535     }
536 
537     nSet = uCount;
538     if ( nSet > lpResults->nGlyphs )
539         nSet = lpResults->nGlyphs;
540 
541     return NtGdiGetCharacterPlacementW( hdc,
542                                         (LPWSTR)lpString,
543                                         nSet,
544                                         nMaxExtent,
545                                         lpResults,
546                                         dwFlags);
547 }
548 
549 /*
550  * @implemented
551  *
552  */
553 BOOL
554 WINAPI
555 GetCharABCWidthsFloatW(HDC hdc,
556                        UINT FirstChar,
557                        UINT LastChar,
558                        LPABCFLOAT abcF)
559 {
560     DPRINT("GetCharABCWidthsFloatW\n");
561     if ((!abcF) || (FirstChar > LastChar))
562     {
563         SetLastError(ERROR_INVALID_PARAMETER);
564         return FALSE;
565     }
566     return NtGdiGetCharABCWidthsW( hdc,
567                                    FirstChar,
568                                    (ULONG)(LastChar - FirstChar + 1),
569                                    (PWCHAR) NULL,
570                                    0,
571                                    (PVOID)abcF);
572 }
573 
574 /*
575  * @implemented
576  *
577  */
578 BOOL
579 WINAPI
580 GetCharWidthFloatW(HDC hdc,
581                    UINT iFirstChar,
582                    UINT iLastChar,
583                    PFLOAT pxBuffer)
584 {
585     DPRINT("GetCharWidthsFloatW\n");
586     if ((!pxBuffer) || (iFirstChar > iLastChar))
587     {
588         SetLastError(ERROR_INVALID_PARAMETER);
589         return FALSE;
590     }
591     return NtGdiGetCharWidthW( hdc,
592                                iFirstChar,
593                                (ULONG)(iLastChar - iFirstChar + 1),
594                                (PWCHAR) NULL,
595                                0,
596                                (PVOID) pxBuffer);
597 }
598 
599 /*
600  * @implemented
601  *
602  */
603 BOOL
604 WINAPI
605 GetCharWidthW(HDC hdc,
606               UINT iFirstChar,
607               UINT iLastChar,
608               LPINT lpBuffer)
609 {
610     DPRINT("GetCharWidthsW\n");
611     if ((!lpBuffer) || (iFirstChar > iLastChar))
612     {
613         SetLastError(ERROR_INVALID_PARAMETER);
614         return FALSE;
615     }
616     return NtGdiGetCharWidthW( hdc,
617                                iFirstChar,
618                                (ULONG)(iLastChar - iFirstChar + 1),
619                                (PWCHAR) NULL,
620                                GCW_NOFLOAT,
621                                (PVOID) lpBuffer);
622 }
623 
624 /*
625  * @implemented
626  *
627  */
628 BOOL
629 WINAPI
630 GetCharWidth32W(HDC hdc,
631                 UINT iFirstChar,
632                 UINT iLastChar,
633                 LPINT lpBuffer)
634 {
635     DPRINT("GetCharWidths32W\n");
636     if ((!lpBuffer) || (iFirstChar > iLastChar))
637     {
638         SetLastError(ERROR_INVALID_PARAMETER);
639         return FALSE;
640     }
641     return NtGdiGetCharWidthW( hdc,
642                                iFirstChar,
643                                (ULONG)(iLastChar - iFirstChar + 1),
644                                (PWCHAR) NULL,
645                                GCW_NOFLOAT|GCW_WIN32,
646                                (PVOID) lpBuffer);
647 }
648 
649 
650 /*
651  * @implemented
652  *
653  */
654 BOOL
655 WINAPI
656 GetCharABCWidthsW(HDC hdc,
657                   UINT FirstChar,
658                   UINT LastChar,
659                   LPABC lpabc)
660 {
661     DPRINT("GetCharABCWidthsW\n");
662     if ((!lpabc) || (FirstChar > LastChar))
663     {
664         SetLastError(ERROR_INVALID_PARAMETER);
665         return FALSE;
666     }
667     return NtGdiGetCharABCWidthsW( hdc,
668                                    FirstChar,
669                                    (ULONG)(LastChar - FirstChar + 1),
670                                    (PWCHAR) NULL,
671                                    GCABCW_NOFLOAT,
672                                    (PVOID)lpabc);
673 }
674 
675 /*
676  * @implemented
677  */
678 BOOL
679 WINAPI
680 GetCharWidthA(
681     HDC	hdc,
682     UINT	iFirstChar,
683     UINT	iLastChar,
684     LPINT	lpBuffer
685 )
686 {
687     INT wlen, count = 0;
688     LPSTR str;
689     LPWSTR wstr;
690     BOOL ret = TRUE;
691 
692     DPRINT("GetCharWidthsA\n");
693 
694     str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
695     if (!str)
696         return FALSE;
697 
698     wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
699     if (!wstr)
700     {
701         HeapFree(GetProcessHeap(), 0, str);
702         return FALSE;
703     }
704 
705     ret = NtGdiGetCharWidthW( hdc,
706                               wstr[0],
707                               (ULONG) count,
708                               (PWCHAR) wstr,
709                               GCW_NOFLOAT,
710                               (PVOID) lpBuffer);
711 
712     HeapFree(GetProcessHeap(), 0, str);
713     HeapFree(GetProcessHeap(), 0, wstr);
714 
715     return ret;
716 }
717 
718 /*
719  * @implemented
720  */
721 BOOL
722 WINAPI
723 GetCharWidth32A(
724     HDC	hdc,
725     UINT	iFirstChar,
726     UINT	iLastChar,
727     LPINT	lpBuffer
728 )
729 {
730     INT wlen, count = 0;
731     LPSTR str;
732     LPWSTR wstr;
733     BOOL ret = TRUE;
734 
735     DPRINT("GetCharWidths32A\n");
736 
737     str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
738     if (!str)
739         return FALSE;
740 
741     wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
742     if (!wstr)
743     {
744         HeapFree(GetProcessHeap(), 0, str);
745         return FALSE;
746     }
747 
748     ret = NtGdiGetCharWidthW( hdc,
749                               wstr[0],
750                               (ULONG) count,
751                               (PWCHAR) wstr,
752                               GCW_NOFLOAT|GCW_WIN32,
753                               (PVOID) lpBuffer);
754 
755     HeapFree(GetProcessHeap(), 0, str);
756     HeapFree(GetProcessHeap(), 0, wstr);
757 
758     return ret;
759 }
760 
761 /*
762  * @implemented
763  */
764 BOOL
765 APIENTRY
766 GetCharWidthFloatA(
767     HDC	hdc,
768     UINT	iFirstChar,
769     UINT	iLastChar,
770     PFLOAT	pxBuffer
771 )
772 {
773     INT wlen, count = 0;
774     LPSTR str;
775     LPWSTR wstr;
776     BOOL ret = TRUE;
777 
778     DPRINT("GetCharWidthsFloatA\n");
779 
780     str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
781     if (!str)
782         return FALSE;
783 
784     wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
785     if (!wstr)
786     {
787         HeapFree(GetProcessHeap(), 0, str);
788         return FALSE;
789     }
790     ret = NtGdiGetCharWidthW( hdc, wstr[0], (ULONG) count, (PWCHAR) wstr, 0, (PVOID) pxBuffer);
791 
792     HeapFree(GetProcessHeap(), 0, str);
793     HeapFree(GetProcessHeap(), 0, wstr);
794 
795     return ret;
796 }
797 
798 /*
799  * @implemented
800  */
801 BOOL
802 APIENTRY
803 GetCharABCWidthsA(
804     HDC	hdc,
805     UINT	iFirstChar,
806     UINT	iLastChar,
807     LPABC	lpabc
808 )
809 {
810     INT wlen, count = 0;
811     LPSTR str;
812     LPWSTR wstr;
813     BOOL ret = TRUE;
814 
815     DPRINT("GetCharABCWidthsA\n");
816 
817     str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
818     if (!str)
819         return FALSE;
820 
821     wstr = FONT_mbtowc(hdc, str, count+1, &wlen, NULL);
822     if (!wstr)
823     {
824         HeapFree(GetProcessHeap(), 0, str);
825         return FALSE;
826     }
827 
828     ret = NtGdiGetCharABCWidthsW( hdc,
829                                   wstr[0],
830                                   wlen - 1,
831                                   (PWCHAR)wstr,
832                                   GCABCW_NOFLOAT,
833                                   (PVOID)lpabc);
834 
835     HeapFree(GetProcessHeap(), 0, str);
836     HeapFree(GetProcessHeap(), 0, wstr);
837 
838     return ret;
839 }
840 
841 /*
842  * @implemented
843  */
844 BOOL
845 APIENTRY
846 GetCharABCWidthsFloatA(
847     HDC		hdc,
848     UINT		iFirstChar,
849     UINT		iLastChar,
850     LPABCFLOAT	lpABCF
851 )
852 {
853     INT wlen, count = 0;
854     LPSTR str;
855     LPWSTR wstr;
856     BOOL ret = TRUE;
857 
858     DPRINT("GetCharABCWidthsFloatA\n");
859 
860     str = FONT_GetCharsByRangeA(hdc, iFirstChar, iLastChar, &count);
861     if (!str)
862         return FALSE;
863 
864     wstr = FONT_mbtowc( hdc, str, count+1, &wlen, NULL );
865     if (!wstr)
866     {
867         HeapFree( GetProcessHeap(), 0, str );
868         return FALSE;
869     }
870     ret = NtGdiGetCharABCWidthsW( hdc,wstr[0],(ULONG)count, (PWCHAR)wstr, 0, (PVOID)lpABCF);
871 
872     HeapFree( GetProcessHeap(), 0, str );
873     HeapFree( GetProcessHeap(), 0, wstr );
874 
875     return ret;
876 }
877 
878 /*
879  * @implemented
880  */
881 BOOL
882 WINAPI
883 GetCharABCWidthsI(HDC hdc,
884                   UINT giFirst,
885                   UINT cgi,
886                   LPWORD pgi,
887                   LPABC lpabc)
888 {
889     DPRINT("GetCharABCWidthsI\n");
890     return NtGdiGetCharABCWidthsW( hdc,
891                                    giFirst,
892                                    (ULONG) cgi,
893                                    (PWCHAR) pgi,
894                                    GCABCW_NOFLOAT|GCABCW_INDICES,
895                                    (PVOID)lpabc);
896 }
897 
898 /*
899  * @implemented
900  */
901 BOOL
902 WINAPI
903 GetCharWidthI(HDC hdc,
904               UINT giFirst,
905               UINT cgi,
906               LPWORD pgi,
907               LPINT lpBuffer
908              )
909 {
910     DPRINT("GetCharWidthsI\n");
911     if (!lpBuffer || (!pgi && (giFirst == MAXUSHORT))) // Cannot be at max.
912     {
913         SetLastError(ERROR_INVALID_PARAMETER);
914         return FALSE;
915     }
916     if (!cgi) return TRUE;
917     return NtGdiGetCharWidthW( hdc,
918                                giFirst,
919                                cgi,
920                                (PWCHAR) pgi,
921                                GCW_INDICES|GCW_NOFLOAT|GCW_WIN32,
922                                (PVOID) lpBuffer );
923 }
924 
925 /*
926  * @implemented
927  */
928 DWORD
929 WINAPI
930 GetFontLanguageInfo(
931     HDC 	hDc
932 )
933 {
934     DWORD Gcp = 0, Ret = 0;
935     if (gbLpk)
936     {
937         Ret = NtGdiGetTextCharsetInfo(hDc, NULL, 0);
938         if ((Ret == ARABIC_CHARSET) || (Ret == HEBREW_CHARSET))
939             Ret = (GCP_KASHIDA|GCP_DIACRITIC|GCP_LIGATE|GCP_GLYPHSHAPE|GCP_REORDER);
940     }
941     Gcp = GetDCDWord(hDc, GdiGetFontLanguageInfo, GCP_ERROR);
942     if ( Gcp == GCP_ERROR)
943         return Gcp;
944     else
945         Ret = Gcp | Ret;
946     return Ret;
947 }
948 
949 /*
950  * @implemented
951  */
952 DWORD
953 WINAPI
954 GetGlyphIndicesA(
955     HDC hdc,
956     LPCSTR lpstr,
957     INT count,
958     LPWORD pgi,
959     DWORD flags
960 )
961 {
962     DWORD Ret;
963     WCHAR *lpstrW;
964     INT countW;
965 
966     lpstrW = FONT_mbtowc(hdc, lpstr, count, &countW, NULL);
967 
968     if (lpstrW == NULL)
969         return GDI_ERROR;
970 
971     Ret = NtGdiGetGlyphIndicesW(hdc, lpstrW, countW, pgi, flags);
972     HeapFree(GetProcessHeap(), 0, lpstrW);
973     return Ret;
974 }
975 
976 /*
977  * @implemented
978  */
979 DWORD
980 WINAPI
981 GetGlyphOutlineA(
982     HDC		hdc,
983     UINT		uChar,
984     UINT		uFormat,
985     LPGLYPHMETRICS	lpgm,
986     DWORD		cbBuffer,
987     LPVOID		lpvBuffer,
988     CONST MAT2	*lpmat2
989 )
990 {
991 
992     LPWSTR p = NULL;
993     DWORD ret;
994     UINT c;
995     DPRINT("GetGlyphOutlineA uChar %x\n", uChar);
996     if (!lpgm || !lpmat2) return GDI_ERROR;
997     if(!(uFormat & GGO_GLYPH_INDEX))
998     {
999         int len;
1000         char mbchs[2];
1001         if(uChar > 0xff)   /* but, 2 bytes character only */
1002         {
1003             len = 2;
1004             mbchs[0] = (uChar & 0xff00) >> 8;
1005             mbchs[1] = (uChar & 0xff);
1006         }
1007         else
1008         {
1009             len = 1;
1010             mbchs[0] = (uChar & 0xff);
1011         }
1012         p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
1013         if(!p)
1014             return GDI_ERROR;
1015         c = p[0];
1016     }
1017     else
1018         c = uChar;
1019     ret = NtGdiGetGlyphOutline(hdc, c, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
1020     HeapFree(GetProcessHeap(), 0, p);
1021     return ret;
1022 }
1023 
1024 
1025 /*
1026  * @implemented
1027  */
1028 DWORD
1029 WINAPI
1030 GetGlyphOutlineW(
1031     HDC		hdc,
1032     UINT		uChar,
1033     UINT		uFormat,
1034     LPGLYPHMETRICS	lpgm,
1035     DWORD		cbBuffer,
1036     LPVOID		lpvBuffer,
1037     CONST MAT2	*lpmat2
1038 )
1039 {
1040     DPRINT("GetGlyphOutlineW uChar %x\n", uChar);
1041     if (!lpgm || !lpmat2) return GDI_ERROR;
1042     if (!lpvBuffer) cbBuffer = 0;
1043     return NtGdiGetGlyphOutline ( hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
1044 }
1045 
1046 /*
1047  * @unimplemented
1048  */
1049 DWORD
1050 WINAPI
1051 GetGlyphOutlineWow(
1052     DWORD	a0,
1053     DWORD	a1,
1054     DWORD	a2,
1055     DWORD	a3,
1056     DWORD	a4,
1057     DWORD	a5,
1058     DWORD	a6
1059 )
1060 {
1061     UNIMPLEMENTED;
1062     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1063     return 0;
1064 }
1065 
1066 /*
1067  * @implemented
1068  */
1069 UINT
1070 APIENTRY
1071 GetOutlineTextMetricsA(
1072     HDC			hdc,
1073     UINT			cbData,
1074     LPOUTLINETEXTMETRICA	lpOTM
1075 )
1076 {
1077     char buf[512], *ptr;
1078     UINT ret, needed;
1079     OUTLINETEXTMETRICW *lpOTMW = (OUTLINETEXTMETRICW *)buf;
1080     OUTLINETEXTMETRICA *output = lpOTM;
1081     INT left, len;
1082 
1083     if((ret = GetOutlineTextMetricsW(hdc, 0, NULL)) == 0)
1084         return 0;
1085     if(ret > sizeof(buf))
1086     {
1087         lpOTMW = HeapAlloc(GetProcessHeap(), 0, ret);
1088         if (lpOTMW == NULL)
1089         {
1090             return 0;
1091         }
1092     }
1093     GetOutlineTextMetricsW(hdc, ret, lpOTMW);
1094 
1095     needed = sizeof(OUTLINETEXTMETRICA);
1096     if(lpOTMW->otmpFamilyName)
1097         needed += WideCharToMultiByte(CP_ACP, 0,
1098                                       (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
1099                                       NULL, 0, NULL, NULL);
1100     if(lpOTMW->otmpFaceName)
1101         needed += WideCharToMultiByte(CP_ACP, 0,
1102                                       (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
1103                                       NULL, 0, NULL, NULL);
1104     if(lpOTMW->otmpStyleName)
1105         needed += WideCharToMultiByte(CP_ACP, 0,
1106                                       (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
1107                                       NULL, 0, NULL, NULL);
1108     if(lpOTMW->otmpFullName)
1109         needed += WideCharToMultiByte(CP_ACP, 0,
1110                                       (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
1111                                       NULL, 0, NULL, NULL);
1112 
1113     if(!lpOTM)
1114     {
1115         ret = needed;
1116         goto end;
1117     }
1118 
1119     DPRINT("needed = %u\n", needed);
1120     if(needed > cbData)
1121     {
1122         /* Since the supplied buffer isn't big enough, we'll alloc one
1123            that is and memcpy the first cbData bytes into the lpOTM at
1124            the end. */
1125         output = HeapAlloc(GetProcessHeap(), 0, needed);
1126         if (output == NULL)
1127         {
1128             goto end;
1129         }
1130     }
1131 
1132     ret = output->otmSize = min(needed, cbData);
1133     FONT_TextMetricWToA( &lpOTMW->otmTextMetrics, &output->otmTextMetrics );
1134     output->otmFiller = 0;
1135     output->otmPanoseNumber = lpOTMW->otmPanoseNumber;
1136     output->otmfsSelection = lpOTMW->otmfsSelection;
1137     output->otmfsType = lpOTMW->otmfsType;
1138     output->otmsCharSlopeRise = lpOTMW->otmsCharSlopeRise;
1139     output->otmsCharSlopeRun = lpOTMW->otmsCharSlopeRun;
1140     output->otmItalicAngle = lpOTMW->otmItalicAngle;
1141     output->otmEMSquare = lpOTMW->otmEMSquare;
1142     output->otmAscent = lpOTMW->otmAscent;
1143     output->otmDescent = lpOTMW->otmDescent;
1144     output->otmLineGap = lpOTMW->otmLineGap;
1145     output->otmsCapEmHeight = lpOTMW->otmsCapEmHeight;
1146     output->otmsXHeight = lpOTMW->otmsXHeight;
1147     output->otmrcFontBox = lpOTMW->otmrcFontBox;
1148     output->otmMacAscent = lpOTMW->otmMacAscent;
1149     output->otmMacDescent = lpOTMW->otmMacDescent;
1150     output->otmMacLineGap = lpOTMW->otmMacLineGap;
1151     output->otmusMinimumPPEM = lpOTMW->otmusMinimumPPEM;
1152     output->otmptSubscriptSize = lpOTMW->otmptSubscriptSize;
1153     output->otmptSubscriptOffset = lpOTMW->otmptSubscriptOffset;
1154     output->otmptSuperscriptSize = lpOTMW->otmptSuperscriptSize;
1155     output->otmptSuperscriptOffset = lpOTMW->otmptSuperscriptOffset;
1156     output->otmsStrikeoutSize = lpOTMW->otmsStrikeoutSize;
1157     output->otmsStrikeoutPosition = lpOTMW->otmsStrikeoutPosition;
1158     output->otmsUnderscoreSize = lpOTMW->otmsUnderscoreSize;
1159     output->otmsUnderscorePosition = lpOTMW->otmsUnderscorePosition;
1160 
1161 
1162     ptr = (char*)(output + 1);
1163     left = needed - sizeof(*output);
1164 
1165     if(lpOTMW->otmpFamilyName)
1166     {
1167         output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
1168         len = WideCharToMultiByte(CP_ACP, 0,
1169                                   (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
1170                                   ptr, left, NULL, NULL);
1171         left -= len;
1172         ptr += len;
1173     }
1174     else
1175         output->otmpFamilyName = 0;
1176 
1177     if(lpOTMW->otmpFaceName)
1178     {
1179         output->otmpFaceName = (LPSTR)(ptr - (char*)output);
1180         len = WideCharToMultiByte(CP_ACP, 0,
1181                                   (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
1182                                   ptr, left, NULL, NULL);
1183         left -= len;
1184         ptr += len;
1185     }
1186     else
1187         output->otmpFaceName = 0;
1188 
1189     if(lpOTMW->otmpStyleName)
1190     {
1191         output->otmpStyleName = (LPSTR)(ptr - (char*)output);
1192         len = WideCharToMultiByte(CP_ACP, 0,
1193                                   (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
1194                                   ptr, left, NULL, NULL);
1195         left -= len;
1196         ptr += len;
1197     }
1198     else
1199         output->otmpStyleName = 0;
1200 
1201     if(lpOTMW->otmpFullName)
1202     {
1203         output->otmpFullName = (LPSTR)(ptr - (char*)output);
1204         len = WideCharToMultiByte(CP_ACP, 0,
1205                                   (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
1206                                   ptr, left, NULL, NULL);
1207         left -= len;
1208     }
1209     else
1210         output->otmpFullName = 0;
1211 
1212     assert(left == 0);
1213 
1214     if(output != lpOTM)
1215     {
1216         memcpy(lpOTM, output, cbData);
1217         HeapFree(GetProcessHeap(), 0, output);
1218 
1219         /* check if the string offsets really fit into the provided size */
1220         /* FIXME: should we check string length as well? */
1221         if ((UINT_PTR)lpOTM->otmpFamilyName >= lpOTM->otmSize)
1222             lpOTM->otmpFamilyName = 0; /* doesn't fit */
1223 
1224         if ((UINT_PTR)lpOTM->otmpFaceName >= lpOTM->otmSize)
1225             lpOTM->otmpFaceName = 0; /* doesn't fit */
1226 
1227         if ((UINT_PTR)lpOTM->otmpStyleName >= lpOTM->otmSize)
1228             lpOTM->otmpStyleName = 0; /* doesn't fit */
1229 
1230         if ((UINT_PTR)lpOTM->otmpFullName >= lpOTM->otmSize)
1231             lpOTM->otmpFullName = 0; /* doesn't fit */
1232     }
1233 
1234 end:
1235     if(lpOTMW != (OUTLINETEXTMETRICW *)buf)
1236         HeapFree(GetProcessHeap(), 0, lpOTMW);
1237 
1238     return ret;
1239 }
1240 
1241 /* Performs a device to world transformation on the specified size (which
1242  * is in integer format).
1243  */
1244 static inline INT INTERNAL_YDSTOWS(XFORM *xForm, INT height)
1245 {
1246     double floatHeight;
1247 
1248     /* Perform operation with floating point */
1249     floatHeight = (double)height * xForm->eM22;
1250     /* Round to integers */
1251     return GDI_ROUND(floatHeight);
1252 }
1253 
1254 /* scale width and height but don't mirror them */
1255 static inline INT width_to_LP( XFORM *xForm, INT width )
1256 {
1257     return GDI_ROUND( (double)width * fabs( xForm->eM11));
1258 }
1259 
1260 static inline INT height_to_LP( XFORM *xForm, INT height )
1261 {
1262     return GDI_ROUND( (double)height * fabs( xForm->eM22 ));
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     UINT Size, AvailableSize = 0, StringSize;
1278     XFORM DevToWorld;
1279     OUTLINETEXTMETRICW* LocalOTM;
1280     WCHAR* Str;
1281     BYTE* Ptr;
1282 
1283     /* Get the structure */
1284     Size = NtGdiGetOutlineTextMetricsInternalW(hdc, 0, NULL, &Tmd);
1285     if (!Size)
1286         return 0;
1287     if (!lpOTM || (cbData < sizeof(*lpOTM)))
1288         return Size;
1289 
1290     LocalOTM = HeapAlloc(GetProcessHeap(), 0, Size);
1291     LocalOTM->otmSize = Size;
1292     Size = NtGdiGetOutlineTextMetricsInternalW(hdc, Size, LocalOTM, &Tmd);
1293     if (!Size)
1294     {
1295         HeapFree(GetProcessHeap(), 0, LocalOTM);
1296         return 0;
1297     }
1298 
1299     if (!NtGdiGetTransform(hdc, GdiDeviceSpaceToWorldSpace, &DevToWorld))
1300     {
1301         DPRINT1("NtGdiGetTransform failed!\n");
1302         HeapFree(GetProcessHeap(), 0, LocalOTM);
1303         SetLastError(ERROR_INVALID_HANDLE);
1304         return 0;
1305     }
1306 
1307     /* Fill in DC specific data */
1308     LocalOTM->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
1309     LocalOTM->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
1310     LocalOTM->otmTextMetrics.tmHeight = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmHeight );
1311     LocalOTM->otmTextMetrics.tmAscent = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmAscent );
1312     LocalOTM->otmTextMetrics.tmDescent = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmDescent );
1313     LocalOTM->otmTextMetrics.tmInternalLeading = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmInternalLeading );
1314     LocalOTM->otmTextMetrics.tmExternalLeading = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmExternalLeading );
1315     LocalOTM->otmTextMetrics.tmAveCharWidth = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmAveCharWidth );
1316     LocalOTM->otmTextMetrics.tmMaxCharWidth = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmMaxCharWidth );
1317     LocalOTM->otmTextMetrics.tmOverhang = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmOverhang );
1318     LocalOTM->otmAscent                = height_to_LP( &DevToWorld, LocalOTM->otmAscent);
1319     LocalOTM->otmDescent               = height_to_LP( &DevToWorld, LocalOTM->otmDescent);
1320     LocalOTM->otmLineGap               = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmLineGap));
1321     LocalOTM->otmsCapEmHeight          = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsCapEmHeight));
1322     LocalOTM->otmsXHeight              = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsXHeight));
1323     LocalOTM->otmrcFontBox.top         = height_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.top);
1324     LocalOTM->otmrcFontBox.bottom      = height_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.bottom);
1325     LocalOTM->otmrcFontBox.left        = width_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.left);
1326     LocalOTM->otmrcFontBox.right       = width_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.right);
1327     LocalOTM->otmMacAscent             = height_to_LP( &DevToWorld, LocalOTM->otmMacAscent);
1328     LocalOTM->otmMacDescent            = height_to_LP( &DevToWorld, LocalOTM->otmMacDescent);
1329     LocalOTM->otmMacLineGap            = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmMacLineGap));
1330     LocalOTM->otmptSubscriptSize.x     = width_to_LP( &DevToWorld, LocalOTM->otmptSubscriptSize.x);
1331     LocalOTM->otmptSubscriptSize.y     = height_to_LP( &DevToWorld, LocalOTM->otmptSubscriptSize.y);
1332     LocalOTM->otmptSubscriptOffset.x   = width_to_LP( &DevToWorld, LocalOTM->otmptSubscriptOffset.x);
1333     LocalOTM->otmptSubscriptOffset.y   = height_to_LP( &DevToWorld, LocalOTM->otmptSubscriptOffset.y);
1334     LocalOTM->otmptSuperscriptSize.x   = width_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptSize.x);
1335     LocalOTM->otmptSuperscriptSize.y   = height_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptSize.y);
1336     LocalOTM->otmptSuperscriptOffset.x = width_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptOffset.x);
1337     LocalOTM->otmptSuperscriptOffset.y = height_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptOffset.y);
1338     LocalOTM->otmsStrikeoutSize        = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsStrikeoutSize));
1339     LocalOTM->otmsStrikeoutPosition    = height_to_LP( &DevToWorld, LocalOTM->otmsStrikeoutPosition);
1340     LocalOTM->otmsUnderscoreSize       = height_to_LP( &DevToWorld, LocalOTM->otmsUnderscoreSize);
1341     LocalOTM->otmsUnderscorePosition   = height_to_LP( &DevToWorld, LocalOTM->otmsUnderscorePosition);
1342 
1343     /* Copy what we can */
1344     CopyMemory(lpOTM, LocalOTM, min(Size, cbData));
1345 
1346     lpOTM->otmpFamilyName = NULL;
1347     lpOTM->otmpFaceName = NULL;
1348     lpOTM->otmpStyleName = NULL;
1349     lpOTM->otmpFullName = NULL;
1350 
1351     Size = sizeof(*lpOTM);
1352     AvailableSize = cbData - Size;
1353     Ptr = (BYTE*)lpOTM + sizeof(*lpOTM);
1354 
1355     /* Fix string values up */
1356     if (LocalOTM->otmpFamilyName)
1357     {
1358         Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFamilyName);
1359         StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
1360         if (AvailableSize >= StringSize)
1361         {
1362             CopyMemory(Ptr, Str, StringSize);
1363             lpOTM->otmpFamilyName = (PSTR)(Ptr - (BYTE*)lpOTM);
1364             Ptr += StringSize;
1365             AvailableSize -= StringSize;
1366             Size += StringSize;
1367         }
1368     }
1369 
1370     if (LocalOTM->otmpFaceName)
1371     {
1372         Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFaceName);
1373         StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
1374         if (AvailableSize >= StringSize)
1375         {
1376             CopyMemory(Ptr, Str, StringSize);
1377             lpOTM->otmpFaceName = (PSTR)(Ptr - (BYTE*)lpOTM);
1378             Ptr += StringSize;
1379             AvailableSize -= StringSize;
1380             Size += StringSize;
1381         }
1382     }
1383 
1384     if (LocalOTM->otmpStyleName)
1385     {
1386         Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpStyleName);
1387         StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
1388         if (AvailableSize >= StringSize)
1389         {
1390             CopyMemory(Ptr, Str, StringSize);
1391             lpOTM->otmpStyleName = (PSTR)(Ptr - (BYTE*)lpOTM);
1392             Ptr += StringSize;
1393             AvailableSize -= StringSize;
1394             Size += StringSize;
1395         }
1396     }
1397 
1398     if (LocalOTM->otmpFullName)
1399     {
1400         Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFullName);
1401         StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
1402         if (AvailableSize >= StringSize)
1403         {
1404             CopyMemory(Ptr, Str, StringSize);
1405             lpOTM->otmpFullName = (PSTR)(Ptr - (BYTE*)lpOTM);
1406             Ptr += StringSize;
1407             AvailableSize -= StringSize;
1408             Size += StringSize;
1409         }
1410     }
1411 
1412     lpOTM->otmSize = Size;
1413 
1414     HeapFree(GetProcessHeap(), 0, LocalOTM);
1415 
1416     return Size;
1417 }
1418 
1419 /*
1420  * @implemented
1421  */
1422 DWORD
1423 WINAPI
1424 GetKerningPairsW(HDC hdc,
1425                  ULONG cPairs,
1426                  LPKERNINGPAIR pkpDst)
1427 {
1428     if ((cPairs != 0) || (pkpDst == 0))
1429     {
1430         return NtGdiGetKerningPairs(hdc,cPairs,pkpDst);
1431     }
1432     else
1433     {
1434         SetLastError(ERROR_INVALID_PARAMETER);
1435         return 0;
1436     }
1437 }
1438 
1439 /*
1440  * @implemented
1441  */
1442 DWORD
1443 WINAPI
1444 GetKerningPairsA( HDC hDC,
1445                   DWORD cPairs,
1446                   LPKERNINGPAIR kern_pairA )
1447 {
1448     INT charset;
1449     CHARSETINFO csi;
1450     CPINFO cpi;
1451     DWORD i, total_kern_pairs, kern_pairs_copied = 0;
1452     KERNINGPAIR *kern_pairW;
1453 
1454     if (!cPairs && kern_pairA)
1455     {
1456         SetLastError(ERROR_INVALID_PARAMETER);
1457         return 0;
1458     }
1459 
1460     charset = GetTextCharset(hDC);
1461     if (!TranslateCharsetInfo(ULongToPtr(charset), &csi, TCI_SRCCHARSET))
1462     {
1463         DPRINT1("Can't find codepage for charset %d\n", charset);
1464         return 0;
1465     }
1466     /* GetCPInfo() will fail on CP_SYMBOL, and WideCharToMultiByte is supposed
1467      * to fail on an invalid character for CP_SYMBOL.
1468      */
1469     cpi.DefaultChar[0] = 0;
1470     if (csi.ciACP != CP_SYMBOL && !GetCPInfo(csi.ciACP, &cpi))
1471     {
1472         DPRINT1("Can't find codepage %u info\n", csi.ciACP);
1473         return 0;
1474     }
1475     DPRINT("charset %d => codepage %u\n", charset, csi.ciACP);
1476 
1477     total_kern_pairs = NtGdiGetKerningPairs(hDC, 0, NULL);
1478     if (!total_kern_pairs) return 0;
1479 
1480     if (!cPairs && !kern_pairA) return total_kern_pairs;
1481 
1482     kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
1483     if (kern_pairW == NULL)
1484     {
1485         return 0;
1486     }
1487     GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
1488 
1489     for (i = 0; i < total_kern_pairs; i++)
1490     {
1491         char first, second;
1492 
1493         if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
1494             continue;
1495 
1496         if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
1497             continue;
1498 
1499         if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
1500             continue;
1501 
1502         if (kern_pairA)
1503         {
1504             if (kern_pairs_copied >= cPairs) break;
1505 
1506             kern_pairA->wFirst = (BYTE)first;
1507             kern_pairA->wSecond = (BYTE)second;
1508             kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
1509             kern_pairA++;
1510         }
1511         kern_pairs_copied++;
1512     }
1513 
1514     HeapFree(GetProcessHeap(), 0, kern_pairW);
1515 
1516     return kern_pairs_copied;
1517 }
1518 
1519 
1520 
1521 /*
1522  * @implemented
1523  */
1524 HFONT
1525 WINAPI
1526 CreateFontIndirectExA(const ENUMLOGFONTEXDVA *elfexd)
1527 {
1528     if (elfexd)
1529     {
1530         ENUMLOGFONTEXDVW Logfont;
1531 
1532         EnumLogFontExW2A( (LPENUMLOGFONTEXA) elfexd,
1533                           &Logfont.elfEnumLogfontEx );
1534 
1535         RtlCopyMemory( &Logfont.elfDesignVector,
1536                        (PVOID) &elfexd->elfDesignVector,
1537                        sizeof(DESIGNVECTOR));
1538 
1539         return NtGdiHfontCreate( &Logfont, 0, 0, 0, NULL);
1540     }
1541     else return NULL;
1542 }
1543 
1544 
1545 /*
1546  * @implemented
1547  */
1548 HFONT
1549 WINAPI
1550 CreateFontIndirectExW(const ENUMLOGFONTEXDVW *elfexd)
1551 {
1552     /* Msdn: Note, this function ignores the elfDesignVector member in
1553              ENUMLOGFONTEXDV.
1554      */
1555     if ( elfexd )
1556     {
1557         return NtGdiHfontCreate((PENUMLOGFONTEXDVW) elfexd, 0, 0, 0, NULL );
1558     }
1559     else return NULL;
1560 }
1561 
1562 
1563 /*
1564  * @implemented
1565  */
1566 HFONT
1567 WINAPI
1568 CreateFontIndirectA(
1569     CONST LOGFONTA		*lplf
1570 )
1571 {
1572     if (lplf)
1573     {
1574         LOGFONTW tlf;
1575 
1576         LogFontA2W(&tlf, lplf);
1577         return CreateFontIndirectW(&tlf);
1578     }
1579     else return NULL;
1580 }
1581 
1582 
1583 /*
1584  * @implemented
1585  */
1586 HFONT
1587 WINAPI
1588 CreateFontIndirectW(
1589     CONST LOGFONTW		*lplf
1590 )
1591 {
1592     if (lplf)
1593     {
1594         ENUMLOGFONTEXDVW Logfont;
1595 
1596         RtlCopyMemory( &Logfont.elfEnumLogfontEx.elfLogFont, lplf, sizeof(LOGFONTW));
1597         // Need something other than just cleaning memory here.
1598         // Guess? Use caller data to determine the rest.
1599         RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfFullName,
1600                        sizeof(Logfont.elfEnumLogfontEx.elfFullName));
1601         RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfStyle,
1602                        sizeof(Logfont.elfEnumLogfontEx.elfStyle));
1603         RtlZeroMemory( &Logfont.elfEnumLogfontEx.elfScript,
1604                        sizeof(Logfont.elfEnumLogfontEx.elfScript));
1605 
1606         Logfont.elfDesignVector.dvNumAxes = 0; // No more than MM_MAX_NUMAXES
1607 
1608         RtlZeroMemory( &Logfont.elfDesignVector, sizeof(DESIGNVECTOR));
1609 
1610         return CreateFontIndirectExW(&Logfont);
1611     }
1612     else return NULL;
1613 }
1614 
1615 
1616 /*
1617  * @implemented
1618  */
1619 HFONT
1620 WINAPI
1621 CreateFontA(
1622     int	nHeight,
1623     int	nWidth,
1624     int	nEscapement,
1625     int	nOrientation,
1626     int	fnWeight,
1627     DWORD	fdwItalic,
1628     DWORD	fdwUnderline,
1629     DWORD	fdwStrikeOut,
1630     DWORD	fdwCharSet,
1631     DWORD	fdwOutputPrecision,
1632     DWORD	fdwClipPrecision,
1633     DWORD	fdwQuality,
1634     DWORD	fdwPitchAndFamily,
1635     LPCSTR	lpszFace
1636 )
1637 {
1638     ANSI_STRING StringA;
1639     UNICODE_STRING StringU;
1640     HFONT ret;
1641 
1642     RtlInitAnsiString(&StringA, (LPSTR)lpszFace);
1643     RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
1644 
1645     ret = CreateFontW(nHeight,
1646                       nWidth,
1647                       nEscapement,
1648                       nOrientation,
1649                       fnWeight,
1650                       fdwItalic,
1651                       fdwUnderline,
1652                       fdwStrikeOut,
1653                       fdwCharSet,
1654                       fdwOutputPrecision,
1655                       fdwClipPrecision,
1656                       fdwQuality,
1657                       fdwPitchAndFamily,
1658                       StringU.Buffer);
1659 
1660     RtlFreeUnicodeString(&StringU);
1661 
1662     return ret;
1663 }
1664 
1665 
1666 /*
1667  * @implemented
1668  */
1669 HFONT
1670 WINAPI
1671 CreateFontW(
1672     int	nHeight,
1673     int	nWidth,
1674     int	nEscapement,
1675     int	nOrientation,
1676     int	nWeight,
1677     DWORD	fnItalic,
1678     DWORD	fdwUnderline,
1679     DWORD	fdwStrikeOut,
1680     DWORD	fdwCharSet,
1681     DWORD	fdwOutputPrecision,
1682     DWORD	fdwClipPrecision,
1683     DWORD	fdwQuality,
1684     DWORD	fdwPitchAndFamily,
1685     LPCWSTR	lpszFace
1686 )
1687 {
1688     LOGFONTW logfont;
1689 
1690     logfont.lfHeight = nHeight;
1691     logfont.lfWidth = nWidth;
1692     logfont.lfEscapement = nEscapement;
1693     logfont.lfOrientation = nOrientation;
1694     logfont.lfWeight = nWeight;
1695     logfont.lfItalic = (BYTE)fnItalic;
1696     logfont.lfUnderline = (BYTE)fdwUnderline;
1697     logfont.lfStrikeOut = (BYTE)fdwStrikeOut;
1698     logfont.lfCharSet = (BYTE)fdwCharSet;
1699     logfont.lfOutPrecision = (BYTE)fdwOutputPrecision;
1700     logfont.lfClipPrecision = (BYTE)fdwClipPrecision;
1701     logfont.lfQuality = (BYTE)fdwQuality;
1702     logfont.lfPitchAndFamily = (BYTE)fdwPitchAndFamily;
1703 
1704     if (NULL != lpszFace)
1705     {
1706         int Size = sizeof(logfont.lfFaceName) / sizeof(WCHAR);
1707         wcsncpy((wchar_t *)logfont.lfFaceName, lpszFace, Size - 1);
1708         /* Be 101% sure to have '\0' at end of string */
1709         logfont.lfFaceName[Size - 1] = '\0';
1710     }
1711     else
1712     {
1713         logfont.lfFaceName[0] = L'\0';
1714     }
1715 
1716     return CreateFontIndirectW(&logfont);
1717 }
1718 
1719 
1720 /*
1721  * @unimplemented
1722  */
1723 BOOL
1724 WINAPI
1725 CreateScalableFontResourceA(
1726     DWORD		fdwHidden,
1727     LPCSTR		lpszFontRes,
1728     LPCSTR		lpszFontFile,
1729     LPCSTR		lpszCurrentPath
1730 )
1731 {
1732     return FALSE;
1733 }
1734 
1735 
1736 /*
1737  * @implemented
1738  */
1739 int
1740 WINAPI
1741 AddFontResourceExW ( LPCWSTR lpszFilename, DWORD fl, PVOID pvReserved )
1742 {
1743     if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
1744     {
1745         SetLastError( ERROR_INVALID_PARAMETER );
1746         return 0;
1747     }
1748 
1749     return GdiAddFontResourceW(lpszFilename, fl,0);
1750 }
1751 
1752 
1753 /*
1754  * @implemented
1755  */
1756 int
1757 WINAPI
1758 AddFontResourceExA ( LPCSTR lpszFilename, DWORD fl, PVOID pvReserved )
1759 {
1760     NTSTATUS Status;
1761     PWSTR FilenameW;
1762     int rc;
1763 
1764     if (fl & ~(FR_PRIVATE | FR_NOT_ENUM))
1765     {
1766         SetLastError( ERROR_INVALID_PARAMETER );
1767         return 0;
1768     }
1769 
1770     Status = HEAP_strdupA2W ( &FilenameW, lpszFilename );
1771     if ( !NT_SUCCESS (Status) )
1772     {
1773         SetLastError (RtlNtStatusToDosError(Status));
1774         return 0;
1775     }
1776 
1777     rc = GdiAddFontResourceW ( FilenameW, fl, 0 );
1778     HEAP_free ( FilenameW );
1779     return rc;
1780 }
1781 
1782 
1783 /*
1784  * @implemented
1785  */
1786 int
1787 WINAPI
1788 AddFontResourceA ( LPCSTR lpszFilename )
1789 {
1790     NTSTATUS Status;
1791     PWSTR FilenameW;
1792     int rc = 0;
1793 
1794     Status = HEAP_strdupA2W ( &FilenameW, lpszFilename );
1795     if ( !NT_SUCCESS (Status) )
1796     {
1797         SetLastError (RtlNtStatusToDosError(Status));
1798     }
1799     else
1800     {
1801         rc = GdiAddFontResourceW ( FilenameW, 0, 0);
1802 
1803         HEAP_free ( FilenameW );
1804     }
1805     return rc;
1806 }
1807 
1808 
1809 /*
1810  * @implemented
1811  */
1812 int
1813 WINAPI
1814 AddFontResourceW ( LPCWSTR lpszFilename )
1815 {
1816     return GdiAddFontResourceW ( lpszFilename, 0, 0 );
1817 }
1818 
1819 
1820 /*
1821  * @implemented
1822  */
1823 BOOL
1824 WINAPI
1825 RemoveFontResourceW(LPCWSTR lpFileName)
1826 {
1827     return RemoveFontResourceExW(lpFileName,0,0);
1828 }
1829 
1830 
1831 /*
1832  * @implemented
1833  */
1834 BOOL
1835 WINAPI
1836 RemoveFontResourceA(LPCSTR lpFileName)
1837 {
1838     return RemoveFontResourceExA(lpFileName,0,0);
1839 }
1840 
1841 /*
1842  * @unimplemented
1843  */
1844 BOOL
1845 WINAPI
1846 RemoveFontResourceExA(LPCSTR lpFileName,
1847                       DWORD fl,
1848                       PVOID pdv
1849                      )
1850 {
1851     NTSTATUS Status;
1852     LPWSTR lpFileNameW;
1853 
1854     /* FIXME the flags */
1855     /* FIXME the pdv */
1856     /* FIXME NtGdiRemoveFontResource handle flags and pdv */
1857 
1858     Status = HEAP_strdupA2W ( &lpFileNameW, lpFileName );
1859     if (!NT_SUCCESS (Status))
1860         SetLastError (RtlNtStatusToDosError(Status));
1861     else
1862     {
1863 
1864         HEAP_free ( lpFileNameW );
1865     }
1866 
1867     return 0;
1868 }
1869 
1870 /*
1871  * @unimplemented
1872  */
1873 BOOL
1874 WINAPI
1875 RemoveFontResourceExW(LPCWSTR lpFileName,
1876                       DWORD fl,
1877                       PVOID pdv)
1878 {
1879     /* FIXME the flags */
1880     /* FIXME the pdv */
1881     /* FIXME NtGdiRemoveFontResource handle flags and pdv */
1882     DPRINT("RemoveFontResourceExW\n");
1883     return 0;
1884 }
1885 
1886 
1887 /***********************************************************************
1888  *           GdiGetCharDimensions
1889  *
1890  * Gets the average width of the characters in the English alphabet.
1891  *
1892  * PARAMS
1893  *  hdc    [I] Handle to the device context to measure on.
1894  *  lptm   [O] Pointer to memory to store the text metrics into.
1895  *  height [O] On exit, the maximum height of characters in the English alphabet.
1896  *
1897  * RETURNS
1898  *  The average width of characters in the English alphabet.
1899  *
1900  * NOTES
1901  *  This function is used by the dialog manager to get the size of a dialog
1902  *  unit. It should also be used by other pieces of code that need to know
1903  *  the size of a dialog unit in logical units without having access to the
1904  *  window handle of the dialog.
1905  *  Windows caches the font metrics from this function, but we don't and
1906  *  there doesn't appear to be an immediate advantage to do so.
1907  *
1908  * SEE ALSO
1909  *  GetTextExtentPointW, GetTextMetricsW, MapDialogRect.
1910  *
1911  * Despite most of MSDN insisting that the horizontal base unit is
1912  * tmAveCharWidth it isn't.  Knowledge base article Q145994
1913  * "HOWTO: Calculate Dialog Units When Not Using the System Font",
1914  * says that we should take the average of the 52 English upper and lower
1915  * case characters.
1916  */
1917 /*
1918  * @implemented
1919  */
1920 LONG
1921 WINAPI
1922 GdiGetCharDimensions(HDC hdc, LPTEXTMETRICW lptm, LONG *height)
1923 {
1924     SIZE sz;
1925     TEXTMETRICW tm;
1926     static const WCHAR alphabet[] =
1927     {
1928         'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
1929         'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
1930         'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0
1931     };
1932 
1933     if(!GetTextMetricsW(hdc, &tm)) return 0;
1934 
1935     if(!GetTextExtentPointW(hdc, alphabet, 52, &sz)) return 0;
1936 
1937     if (lptm) *lptm = tm;
1938     if (height) *height = tm.tmHeight;
1939 
1940     return (sz.cx / 26 + 1) / 2;
1941 }
1942 
1943 /*************************************************************************
1944  * TranslateCharsetInfo [GDI32.@]
1945  *
1946  * Fills a CHARSETINFO structure for a character set, code page, or
1947  * font. This allows making the correspondance between different labelings
1948  * (character set, Windows, ANSI, and OEM codepages, and Unicode ranges)
1949  * of the same encoding.
1950  *
1951  * Only one codepage will be set in lpCs->fs. If TCI_SRCFONTSIG is used,
1952  * only one codepage should be set in *lpSrc.
1953  *
1954  * RETURNS
1955  *   TRUE on success, FALSE on failure.
1956  *
1957  */
1958 /*
1959  * @implemented
1960  */
1961 BOOL
1962 WINAPI
1963 TranslateCharsetInfo(
1964     LPDWORD lpSrc, /* [in]
1965        if flags == TCI_SRCFONTSIG: pointer to fsCsb of a FONTSIGNATURE
1966        if flags == TCI_SRCCHARSET: a character set value
1967        if flags == TCI_SRCCODEPAGE: a code page value
1968 		 */
1969     LPCHARSETINFO lpCs, /* [out] structure to receive charset information */
1970     DWORD flags /* [in] determines interpretation of lpSrc */)
1971 {
1972     int index = 0;
1973     switch (flags)
1974     {
1975     case TCI_SRCFONTSIG:
1976         while (index < MAXTCIINDEX && !(*lpSrc>>index & 0x0001)) index++;
1977         break;
1978     case TCI_SRCCODEPAGE:
1979         while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciACP) index++;
1980         break;
1981     case TCI_SRCCHARSET:
1982         while (index < MAXTCIINDEX && PtrToUlong(lpSrc) != FONT_tci[index].ciCharset) index++;
1983         break;
1984     case TCI_SRCLOCALE:
1985     {
1986         LCID lCid = (LCID)PtrToUlong(lpSrc);
1987         LOCALESIGNATURE LocSig;
1988         INT Ret = GetLocaleInfoW(lCid, LOCALE_FONTSIGNATURE, (LPWSTR)&LocSig, 0);
1989         if ( GetLocaleInfoW(lCid, LOCALE_FONTSIGNATURE, (LPWSTR)&LocSig, Ret))
1990         {
1991            while (index < MAXTCIINDEX && !(LocSig.lsCsbDefault[0]>>index & 0x0001)) index++;
1992            break;
1993         }
1994     }
1995     default:
1996         GdiSetLastError(ERROR_INVALID_PARAMETER);
1997         return FALSE;
1998     }
1999     if (index >= MAXTCIINDEX || FONT_tci[index].ciCharset == DEFAULT_CHARSET) return FALSE;
2000     DPRINT("Index %d Charset %u CodePage %u FontSig %lu\n",
2001              index,FONT_tci[index].ciCharset,FONT_tci[index].ciACP,FONT_tci[index].fs.fsCsb[0]);
2002     memcpy(lpCs, &FONT_tci[index], sizeof(CHARSETINFO));
2003     return TRUE;
2004 }
2005 
2006 
2007 /*
2008  * @implemented
2009  */
2010 DWORD
2011 WINAPI
2012 SetMapperFlags(
2013     HDC	hDC,
2014     DWORD	flags
2015 )
2016 {
2017     DWORD Ret = GDI_ERROR;
2018     PDC_ATTR Dc_Attr;
2019 #if 0
2020     if (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_DC)
2021     {
2022         if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_METADC)
2023             return MFDRV_SetMapperFlags( hDC, flags);
2024         else
2025         {
2026             PLDC pLDC = Dc_Attr->pvLDC;
2027             if ( !pLDC )
2028             {
2029                 SetLastError(ERROR_INVALID_HANDLE);
2030                 return GDI_ERROR;
2031             }
2032             if (pLDC->iType == LDC_EMFLDC)
2033             {
2034                 return EMFDRV_SetMapperFlags( hDC, flags);
2035             }
2036         }
2037     }
2038 #endif
2039     if (!GdiGetHandleUserData((HGDIOBJ) hDC, GDI_OBJECT_TYPE_DC, (PVOID) &Dc_Attr)) return GDI_ERROR;
2040 
2041     if (NtCurrentTeb()->GdiTebBatch.HDC == hDC)
2042     {
2043         if (Dc_Attr->ulDirty_ & DC_FONTTEXT_DIRTY)
2044         {
2045             NtGdiFlush();
2046             Dc_Attr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
2047         }
2048     }
2049 
2050     if ( flags & ~1 )
2051         SetLastError(ERROR_INVALID_PARAMETER);
2052     else
2053     {
2054         Ret = Dc_Attr->flFontMapper;
2055         Dc_Attr->flFontMapper = flags;
2056     }
2057     return Ret;
2058 }
2059 
2060 
2061 /*
2062  * @unimplemented
2063  */
2064 int
2065 WINAPI
2066 EnumFontsW(
2067     HDC  hDC,
2068     LPCWSTR lpFaceName,
2069     FONTENUMPROCW  FontFunc,
2070     LPARAM  lParam
2071 )
2072 {
2073 #if 0
2074     return NtGdiEnumFonts ( hDC, lpFaceName, FontFunc, lParam );
2075 #else
2076     return EnumFontFamiliesW( hDC, lpFaceName, FontFunc, lParam );
2077 #endif
2078 }
2079 
2080 /*
2081  * @unimplemented
2082  */
2083 int
2084 WINAPI
2085 EnumFontsA (
2086     HDC  hDC,
2087     LPCSTR lpFaceName,
2088     FONTENUMPROCA  FontFunc,
2089     LPARAM  lParam
2090 )
2091 {
2092 #if 0
2093     NTSTATUS Status;
2094     LPWSTR lpFaceNameW;
2095     int rc = 0;
2096 
2097     Status = HEAP_strdupA2W ( &lpFaceNameW, lpFaceName );
2098     if (!NT_SUCCESS (Status))
2099         SetLastError (RtlNtStatusToDosError(Status));
2100     else
2101     {
2102         rc = NtGdiEnumFonts ( hDC, lpFaceNameW, FontFunc, lParam );
2103 
2104         HEAP_free ( lpFaceNameW );
2105     }
2106     return rc;
2107 #else
2108     return EnumFontFamiliesA( hDC, lpFaceName, FontFunc, lParam );
2109 #endif
2110 }
2111 
2112 #define EfdFontFamilies 3
2113 
2114 INT
2115 WINAPI
2116 NewEnumFontFamiliesExW(
2117     HDC hDC,
2118     LPLOGFONTW lpLogfont,
2119     FONTENUMPROCW lpEnumFontFamExProcW,
2120     LPARAM lParam,
2121     DWORD dwFlags)
2122 {
2123     ULONG_PTR idEnum;
2124     ULONG cbDataSize, cbRetSize;
2125     PENUMFONTDATAW pEfdw;
2126     PBYTE pBuffer;
2127     PBYTE pMax;
2128     INT ret = 1;
2129 
2130     /* Open enumeration handle and find out how much memory we need */
2131     idEnum = NtGdiEnumFontOpen(hDC,
2132                                EfdFontFamilies,
2133                                0,
2134                                LF_FACESIZE,
2135                                (lpLogfont && lpLogfont->lfFaceName[0])? lpLogfont->lfFaceName : NULL,
2136                                lpLogfont? lpLogfont->lfCharSet : DEFAULT_CHARSET,
2137                                &cbDataSize);
2138     if (idEnum == 0)
2139     {
2140         return 0;
2141     }
2142     if (cbDataSize == 0)
2143     {
2144         NtGdiEnumFontClose(idEnum);
2145         return 0;
2146     }
2147 
2148     /* Allocate memory */
2149     pBuffer = HeapAlloc(GetProcessHeap(), 0, cbDataSize);
2150     if (pBuffer == NULL)
2151     {
2152         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2153         NtGdiEnumFontClose(idEnum);
2154         return 0;
2155     }
2156 
2157     /* Do the enumeration */
2158     if (!NtGdiEnumFontChunk(hDC, idEnum, cbDataSize, &cbRetSize, (PVOID)pBuffer))
2159     {
2160         HeapFree(GetProcessHeap(), 0, pBuffer);
2161         NtGdiEnumFontClose(idEnum);
2162         return 0;
2163     }
2164 
2165     /* Get start and end address */
2166     pEfdw = (PENUMFONTDATAW)pBuffer;
2167     pMax = pBuffer + cbDataSize;
2168 
2169     /* Iterate through the structures */
2170     while ((PBYTE)pEfdw < pMax && ret)
2171     {
2172         PNTMW_INTERNAL pNtmwi = (PNTMW_INTERNAL)((ULONG_PTR)pEfdw + pEfdw->ulNtmwiOffset);
2173 
2174         ret = lpEnumFontFamExProcW((VOID*)&pEfdw->elfexdv.elfEnumLogfontEx,
2175                                    (VOID*)&pNtmwi->ntmw,
2176                                    pEfdw->dwFontType,
2177                                    lParam);
2178 
2179         pEfdw = (PENUMFONTDATAW)((ULONG_PTR)pEfdw + pEfdw->cbSize);
2180     }
2181 
2182     /* Release the memory and close handle */
2183     HeapFree(GetProcessHeap(), 0, pBuffer);
2184     NtGdiEnumFontClose(idEnum);
2185 
2186     return ret;
2187 }
2188 
2189 /*
2190  * @implemented
2191  */
2192 int
2193 WINAPI
2194 GdiAddFontResourceW(
2195     LPCWSTR lpszFilename,
2196     FLONG fl,
2197     DESIGNVECTOR *pdv)
2198 {
2199     INT Ret;
2200     WCHAR lpszBuffer[MAX_PATH];
2201     WCHAR lpszAbsPath[MAX_PATH];
2202     UNICODE_STRING NtAbsPath;
2203 
2204     /* FIXME: We don't support multiple files passed in lpszFilename
2205      *        as L"abcxxxxx.pfm|abcxxxxx.pfb"
2206      */
2207 
2208     /* Does the file exist in CurrentDirectory or in the Absolute Path passed? */
2209     GetCurrentDirectoryW(MAX_PATH, lpszBuffer);
2210 
2211     if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
2212     {
2213         /* Nope. Then let's check Fonts folder */
2214         GetWindowsDirectoryW(lpszBuffer, MAX_PATH);
2215         StringCbCatW(lpszBuffer, sizeof(lpszBuffer), L"\\Fonts");
2216 
2217         if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
2218         {
2219             DPRINT1("Font not found. The Buffer is: %ls, the FileName is: %S\n", lpszBuffer, lpszFilename);
2220             return 0;
2221         }
2222     }
2223 
2224     /* We found the font file so: */
2225     if (!RtlDosPathNameToNtPathName_U(lpszAbsPath, &NtAbsPath, NULL, NULL))
2226     {
2227         DPRINT1("Can't convert Path! Path: %ls\n", lpszAbsPath);
2228         return 0;
2229     }
2230 
2231     /* The Nt call expects a null-terminator included in cwc param. */
2232     ASSERT(NtAbsPath.Buffer[NtAbsPath.Length / sizeof(WCHAR)] == UNICODE_NULL);
2233     Ret = NtGdiAddFontResourceW(NtAbsPath.Buffer, NtAbsPath.Length / sizeof(WCHAR) + 1, 1, fl, 0, pdv);
2234 
2235     RtlFreeUnicodeString(&NtAbsPath);
2236 
2237     return Ret;
2238 }
2239 
2240 /*
2241  * @implemented
2242  */
2243 HANDLE
2244 WINAPI
2245 AddFontMemResourceEx(
2246     PVOID pbFont,
2247     DWORD cbFont,
2248     PVOID pdv,
2249     DWORD *pcFonts
2250 )
2251 {
2252     if ( pbFont && cbFont && pcFonts)
2253     {
2254         return NtGdiAddFontMemResourceEx(pbFont, cbFont, NULL, 0, pcFonts);
2255     }
2256     SetLastError(ERROR_INVALID_PARAMETER);
2257     return NULL;
2258 }
2259 
2260 /*
2261  * @implemented
2262  */
2263 BOOL
2264 WINAPI
2265 RemoveFontMemResourceEx(HANDLE fh)
2266 {
2267     if (fh)
2268     {
2269         return NtGdiRemoveFontMemResourceEx(fh);
2270     }
2271     SetLastError(ERROR_INVALID_PARAMETER);
2272     return FALSE;
2273 }
2274 
2275 
2276 /*
2277  * @unimplemented
2278  */
2279 int
2280 WINAPI
2281 AddFontResourceTracking(
2282     LPCSTR lpString,
2283     int unknown
2284 )
2285 {
2286     UNIMPLEMENTED;
2287     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2288     return 0;
2289 }
2290 
2291 /*
2292  * @unimplemented
2293  */
2294 int
2295 WINAPI
2296 RemoveFontResourceTracking(LPCSTR lpString,int unknown)
2297 {
2298     UNIMPLEMENTED;
2299     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2300     return 0;
2301 }
2302 
2303 BOOL
2304 WINAPI
2305 CreateScalableFontResourceW(
2306     DWORD fdwHidden,
2307     LPCWSTR lpszFontRes,
2308     LPCWSTR lpszFontFile,
2309     LPCWSTR lpszCurrentPath
2310 )
2311 {
2312     HANDLE f;
2313 
2314     UNIMPLEMENTED;
2315 
2316     /* fHidden=1 - only visible for the calling app, read-only, not
2317      * enumerated with EnumFonts/EnumFontFamilies
2318      * lpszCurrentPath can be NULL
2319      */
2320 
2321     /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
2322     if ((f = CreateFileW(lpszFontRes, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
2323     {
2324         CloseHandle(f);
2325         SetLastError(ERROR_FILE_EXISTS);
2326         return FALSE;
2327     }
2328     return FALSE; /* create failed */
2329 }
2330 
2331 /*
2332  * @unimplemented
2333  */
2334 BOOL
2335 WINAPI
2336 bInitSystemAndFontsDirectoriesW(LPWSTR *SystemDir,LPWSTR *FontsDir)
2337 {
2338     UNIMPLEMENTED;
2339     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2340     return 0;
2341 }
2342 
2343 /*
2344  * @unimplemented
2345  */
2346 BOOL
2347 WINAPI
2348 EudcLoadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath,INT iPriority,INT iFontLinkType)
2349 {
2350     UNIMPLEMENTED;
2351     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2352     return 0;
2353 }
2354 
2355 /*
2356  * @unimplemented
2357  */
2358 BOOL
2359 WINAPI
2360 EudcUnloadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath)
2361 {
2362     UNIMPLEMENTED;
2363     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2364     return 0;
2365 }
2366 
2367 /*
2368  * @implemented
2369  */
2370 ULONG
2371 WINAPI
2372 GetEUDCTimeStamp(VOID)
2373 {
2374     return NtGdiGetEudcTimeStampEx(NULL,0,TRUE);
2375 }
2376 
2377 /*
2378  * @implemented
2379  */
2380 DWORD
2381 WINAPI
2382 GetEUDCTimeStampExW(LPWSTR lpBaseFaceName)
2383 {
2384     DWORD retValue = 0;
2385 
2386     if (!lpBaseFaceName)
2387     {
2388         retValue = NtGdiGetEudcTimeStampEx(NULL,0,FALSE);
2389     }
2390     else
2391     {
2392         retValue = NtGdiGetEudcTimeStampEx(lpBaseFaceName, wcslen(lpBaseFaceName), FALSE);
2393     }
2394 
2395     return retValue;
2396 }
2397 
2398 /*
2399  * @implemented
2400  */
2401 ULONG
2402 WINAPI
2403 GetFontAssocStatus(HDC hdc)
2404 {
2405     ULONG retValue = 0;
2406 
2407     if (hdc)
2408     {
2409         retValue = NtGdiQueryFontAssocInfo(hdc);
2410     }
2411 
2412     return retValue;
2413 }
2414 
2415 /*
2416  * @unimplemented
2417  */
2418 DWORD
2419 WINAPI
2420 QueryFontAssocStatus(VOID)
2421 {
2422     UNIMPLEMENTED;
2423     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2424     return 0;
2425 }
2426 
2427 /*
2428  * @unimplemented
2429  */
2430 VOID
2431 WINAPI
2432 UnloadNetworkFonts(DWORD unknown)
2433 {
2434     UNIMPLEMENTED;
2435     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2436 }
2437 
2438 /*
2439  * @implemented
2440  *
2441  */
2442 DWORD
2443 WINAPI
2444 GetFontData(HDC hdc,
2445             DWORD dwTable,
2446             DWORD dwOffset,
2447             LPVOID lpvBuffer,
2448             DWORD cbData)
2449 {
2450     if (!lpvBuffer)
2451     {
2452         cbData = 0;
2453     }
2454     return NtGdiGetFontData(hdc, dwTable, dwOffset, lpvBuffer, cbData);
2455 }
2456 
2457 DWORD
2458 WINAPI
2459 cGetTTFFromFOT(DWORD x1 ,DWORD x2 ,DWORD x3, DWORD x4, DWORD x5, DWORD x6, DWORD x7)
2460 {
2461     UNIMPLEMENTED;
2462     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2463     return 0;
2464 }
2465 
2466