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