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