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