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