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