[GDI32] Reduce verbosity on debug builds
[reactos.git] / win32ss / gdi / gdi32 / objects / font.c
index 1d0122c..8789223 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
- * FILE:            lib/gdi32/object/font.c
+ * FILE:            win32ss/gdi/gdi32/objects/font.c
  * PURPOSE:
  * PROGRAMMER:
  *
@@ -10,6 +10,7 @@
 #include <precomp.h>
 
 #include <math.h>
+#include <strsafe.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -131,7 +132,11 @@ static LPWSTR FONT_mbtowc(HDC hdc, LPCSTR str, INT count, INT *plenW, UINT *pCP)
     strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
     if (!strW)
         return NULL;
-    MultiByteToWideChar(cp, 0, str, count, strW, lenW);
+    if(!MultiByteToWideChar(cp, 0, str, count, strW, lenW))
+    {
+        HeapFree(GetProcessHeap(), 0, strW);
+        return NULL;
+    }
     DPRINT("mapped %s -> %S\n", str, strW);
     if(plenW) *plenW = lenW;
     if(pCP) *pCP = cp;
@@ -199,61 +204,162 @@ NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
     tma->ntmFontSig = tmw->ntmFontSig;
 }
 
+// IntFontFamilyCompareEx's flags
+#define IFFCX_CHARSET 1
+#define IFFCX_STYLE 2
+
+FORCEINLINE int FASTCALL
+IntFontFamilyCompareEx(const FONTFAMILYINFO *ffi1,
+                       const FONTFAMILYINFO *ffi2, DWORD dwCompareFlags)
+{
+    const LOGFONTW *plf1 = &ffi1->EnumLogFontEx.elfLogFont;
+    const LOGFONTW *plf2 = &ffi2->EnumLogFontEx.elfLogFont;
+    ULONG WeightDiff1, WeightDiff2;
+    int cmp = _wcsicmp(plf1->lfFaceName, plf2->lfFaceName);
+    if (cmp)
+        return cmp;
+    if (dwCompareFlags & IFFCX_CHARSET)
+    {
+        if (plf1->lfCharSet < plf2->lfCharSet)
+            return -1;
+        if (plf1->lfCharSet > plf2->lfCharSet)
+            return 1;
+    }
+    if (dwCompareFlags & IFFCX_STYLE)
+    {
+        WeightDiff1 = labs(plf1->lfWeight - FW_NORMAL);
+        WeightDiff2 = labs(plf2->lfWeight - FW_NORMAL);
+        if (WeightDiff1 < WeightDiff2)
+            return -1;
+        if (WeightDiff1 > WeightDiff2)
+            return 1;
+        if (plf1->lfItalic < plf2->lfItalic)
+            return -1;
+        if (plf1->lfItalic > plf2->lfItalic)
+            return 1;
+    }
+    return 0;
+}
+
+static int __cdecl
+IntFontFamilyCompare(const void *ffi1, const void *ffi2)
+{
+    return IntFontFamilyCompareEx(ffi1, ffi2, IFFCX_STYLE | IFFCX_CHARSET);
+}
+
+// IntEnumFontFamilies' flags:
+#define IEFF_UNICODE 1
+#define IEFF_EXTENDED 2
+
+int FASTCALL
+IntFontFamilyListUnique(FONTFAMILYINFO *InfoList, INT nCount,
+                        const LOGFONTW *plf, DWORD dwFlags)
+{
+    FONTFAMILYINFO *first, *last, *result;
+    DWORD dwCompareFlags = 0;
+
+    if (plf->lfFaceName[0])
+        dwCompareFlags |= IFFCX_STYLE;
+
+    if ((dwFlags & IEFF_EXTENDED) && plf->lfCharSet == DEFAULT_CHARSET)
+        dwCompareFlags |= IFFCX_CHARSET;
+
+    first = InfoList;
+    last = &InfoList[nCount];
+
+    /* std::unique(first, last, IntFontFamilyCompareEx); */
+    if (first == last)
+        return 0;
+
+    result = first;
+    while (++first != last)
+    {
+        if (IntFontFamilyCompareEx(result, first, dwCompareFlags) != 0)
+        {
+            *(++result) = *first;
+        }
+    }
+    nCount = (int)(++result - InfoList);
+
+    return nCount;
+}
+
 static int FASTCALL
-IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
-                    BOOL Unicode)
+IntEnumFontFamilies(HDC Dc, const LOGFONTW *LogFont, PVOID EnumProc, LPARAM lParam,
+                    DWORD dwFlags)
 {
     int FontFamilyCount;
-    int FontFamilySize;
     PFONTFAMILYINFO Info;
-    int Ret = 0;
+    int Ret = 1;
     int i;
     ENUMLOGFONTEXA EnumLogFontExA;
     NEWTEXTMETRICEXA NewTextMetricExA;
     LOGFONTW lfW;
+    LONG InfoCount;
+    ULONG DataSize;
+    NTSTATUS Status;
 
-    Info = RtlAllocateHeap(GetProcessHeap(), 0,
-                           INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO));
-    if (NULL == Info)
+    DataSize = INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO);
+    Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
+    if (Info == NULL)
     {
-        return 0;
+        return 1;
     }
 
+    /* Initialize the LOGFONT structure */
+    ZeroMemory(&lfW, sizeof(lfW));
     if (!LogFont)
     {
         lfW.lfCharSet = DEFAULT_CHARSET;
-        lfW.lfPitchAndFamily = 0;
-        lfW.lfFaceName[0] = 0;
-        LogFont = &lfW;
+    }
+    else
+    {
+        lfW.lfCharSet = LogFont->lfCharSet;
+        lfW.lfPitchAndFamily = LogFont->lfPitchAndFamily;
+        StringCbCopyW(lfW.lfFaceName, sizeof(lfW.lfFaceName), LogFont->lfFaceName);
     }
 
-    FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT);
+    /* Retrieve the font information */
+    InfoCount = INITIAL_FAMILY_COUNT;
+    FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount);
     if (FontFamilyCount < 0)
     {
         RtlFreeHeap(GetProcessHeap(), 0, Info);
-        return 0;
+        return 1;
     }
-    if (INITIAL_FAMILY_COUNT < FontFamilyCount)
+
+    /* Resize the buffer if the buffer is too small */
+    if (INITIAL_FAMILY_COUNT < InfoCount)
     {
-        FontFamilySize = FontFamilyCount;
         RtlFreeHeap(GetProcessHeap(), 0, Info);
-        Info = RtlAllocateHeap(GetProcessHeap(), 0,
-                               FontFamilyCount * sizeof(FONTFAMILYINFO));
-        if (NULL == Info)
+
+        Status = RtlULongMult(InfoCount, sizeof(FONTFAMILYINFO), &DataSize);
+        if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
         {
-            return 0;
+            DPRINT1("Overflowed.\n");
+            return 1;
         }
-        FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize);
-        if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount)
+        Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
+        if (Info == NULL)
+        {
+            return 1;
+        }
+        FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount);
+        if (FontFamilyCount < 0 || FontFamilyCount < InfoCount)
         {
             RtlFreeHeap(GetProcessHeap(), 0, Info);
-            return 0;
+            return 1;
         }
     }
 
+    /* Sort and remove redundant information */
+    qsort(Info, FontFamilyCount, sizeof(*Info), IntFontFamilyCompare);
+    FontFamilyCount = IntFontFamilyListUnique(Info, FontFamilyCount, &lfW, dwFlags);
+
+    /* call the callback */
     for (i = 0; i < FontFamilyCount; i++)
     {
-        if (Unicode)
+        if (dwFlags & IEFF_UNICODE)
         {
             Ret = ((FONTENUMPROCW) EnumProc)(
                       (VOID*)&Info[i].EnumLogFontEx,
@@ -277,6 +383,9 @@ IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
                       (VOID*)&NewTextMetricExA,
                       Info[i].FontType, lParam);
         }
+
+        if(Ret == 0)
+            break;
     }
 
     RtlFreeHeap(GetProcessHeap(), 0, Info);
@@ -291,7 +400,19 @@ int WINAPI
 EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
                     LPARAM lParam, DWORD dwFlags)
 {
-    return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE);
+    if (lpLogfont)
+    {
+        DPRINT("EnumFontFamiliesExW(%p, %p(%S, %u, %u), %p, %p, 0x%08lX)\n",
+               hdc, lpLogfont, lpLogfont->lfFaceName, lpLogfont->lfCharSet,
+               lpLogfont->lfPitchAndFamily, lpEnumFontFamExProc, lParam, dwFlags);
+    }
+    else
+    {
+        DPRINT("EnumFontFamiliesExW(%p, NULL, %p, %p, 0x%08lX)\n",
+               hdc, lpEnumFontFamExProc, lParam, dwFlags);
+    }
+    return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam,
+                               IEFF_UNICODE | IEFF_EXTENDED);
 }
 
 
@@ -304,6 +425,9 @@ EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
 {
     LOGFONTW LogFont;
 
+    DPRINT("EnumFontFamiliesW(%p, %S, %p, %p)\n",
+           hdc, lpszFamily, lpEnumFontFamProc, lParam);
+
     ZeroMemory(&LogFont, sizeof(LOGFONTW));
     LogFont.lfCharSet = DEFAULT_CHARSET;
     if (NULL != lpszFamily)
@@ -312,7 +436,7 @@ EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
         lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
     }
 
-    return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE);
+    return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, IEFF_UNICODE);
 }
 
 
@@ -325,6 +449,18 @@ EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamE
 {
     LOGFONTW LogFontW, *pLogFontW;
 
+    if (lpLogfont)
+    {
+        DPRINT("EnumFontFamiliesExA(%p, %p(%s, %u, %u), %p, %p, 0x%08lX)\n",
+               hdc, lpLogfont, lpLogfont->lfFaceName, lpLogfont->lfCharSet,
+               lpLogfont->lfPitchAndFamily, lpEnumFontFamExProc, lParam, dwFlags);
+    }
+    else
+    {
+        DPRINT("EnumFontFamiliesExA(%p, NULL, %p, %p, 0x%08lX)\n",
+               hdc, lpEnumFontFamExProc, lParam, dwFlags);
+    }
+
     if (lpLogfont)
     {
         LogFontA2W(&LogFontW,lpLogfont);
@@ -333,7 +469,7 @@ EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamE
     else pLogFontW = NULL;
 
     /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
-    return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, FALSE);
+    return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, IEFF_EXTENDED);
 }
 
 
@@ -346,6 +482,9 @@ EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
 {
     LOGFONTW LogFont;
 
+    DPRINT("EnumFontFamiliesA(%p, %s, %p, %p)\n",
+           hdc, lpszFamily, lpEnumFontFamProc, lParam);
+
     ZeroMemory(&LogFont, sizeof(LOGFONTW));
     LogFont.lfCharSet = DEFAULT_CHARSET;
     if (NULL != lpszFamily)
@@ -354,7 +493,7 @@ EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
         MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
     }
 
-    return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, FALSE);
+    return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, 0);
 }
 
 
@@ -377,7 +516,7 @@ GetCharacterPlacementA(
     DWORD ret;
     UINT font_cp;
 
-    if ( !lpString || uCount <= 0 || (nMaxExtent < 0 && nMaxExtent != -1 ) )
+    if ( !lpString || uCount <= 0 || !lpResults || (nMaxExtent < 0 && nMaxExtent != -1 ) )
     {
         SetLastError(ERROR_INVALID_PARAMETER);
         return 0;
@@ -440,38 +579,32 @@ GetCharacterPlacementW(
     UINT i, nSet;
     DPRINT("GetCharacterPlacementW\n");
 
-    if(dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
-    if(lpResults->lpClass) DPRINT("classes not implemented\n");
-    if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
-        DPRINT("Caret positions for complex scripts not implemented\n");
+    if (dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
+    if (lpResults->lpClass) DPRINT("classes not implemented\n");
 
     nSet = (UINT)uCount;
-    if(nSet > lpResults->nGlyphs)
+    if (nSet > lpResults->nGlyphs)
         nSet = lpResults->nGlyphs;
 
     /* return number of initialized fields */
     lpResults->nGlyphs = nSet;
 
-    /*if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
-      {*/
+    if (dwFlags & GCP_REORDER)
+    {
+        if (LoadLPK(LPK_GCP))
+            return LpkGetCharacterPlacement(hdc, lpString, uCount, nMaxExtent, lpResults, dwFlags, 0);
+    }
+
     /* Treat the case where no special handling was requested in a fastpath way */
-    /* copy will do if the GCP_REORDER flag is not set */
-    if(lpResults->lpOutString)
+    /* copy will do if the GCP_REORDER flag is not set */ 
+    if (lpResults->lpOutString)
         lstrcpynW( lpResults->lpOutString, lpString, nSet );
 
-    if(lpResults->lpGlyphs)
-        lstrcpynW( lpResults->lpGlyphs, lpString, nSet );
-
-    if(lpResults->lpOrder)
+    if (lpResults->lpOrder)
     {
-        for(i = 0; i < nSet; i++)
+        for (i = 0; i < nSet; i++)
             lpResults->lpOrder[i] = i;
     }
-    /*} else
-      {
-          BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
-                        nSet, lpResults->lpOrder );
-      }*/
 
     /* FIXME: Will use the placement chars */
     if (lpResults->lpDx)
@@ -494,8 +627,8 @@ GetCharacterPlacementW(
                 lpResults->lpCaretPos[i] = (pos += size.cx);
     }
 
-    /*if(lpResults->lpGlyphs)
-      NtGdiGetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);*/
+    if (lpResults->lpGlyphs)
+        NtGdiGetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
 
     if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
         ret = MAKELONG(size.cx, size.cy);
@@ -825,7 +958,7 @@ GetCharABCWidthsA(
 
     ret = NtGdiGetCharABCWidthsW( hdc,
                                   wstr[0],
-                                  (ULONG)count,
+                                  wlen - 1,
                                   (PWCHAR)wstr,
                                   GCABCW_NOFLOAT,
                                   (PVOID)lpabc);
@@ -1008,6 +1141,8 @@ GetGlyphOutlineA(
             mbchs[0] = (uChar & 0xff);
         }
         p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
+        if(!p)
+            return GDI_ERROR;
         c = p[0];
     }
     else
@@ -1039,6 +1174,25 @@ GetGlyphOutlineW(
     return NtGdiGetGlyphOutline ( hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
 }
 
+/*
+ * @unimplemented
+ */
+DWORD
+WINAPI
+GetGlyphOutlineWow(
+    DWORD      a0,
+    DWORD      a1,
+    DWORD      a2,
+    DWORD      a3,
+    DWORD      a4,
+    DWORD      a5,
+    DWORD      a6
+)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
 
 /*
  * @implemented
@@ -1072,19 +1226,19 @@ GetOutlineTextMetricsA(
     needed = sizeof(OUTLINETEXTMETRICA);
     if(lpOTMW->otmpFamilyName)
         needed += WideCharToMultiByte(CP_ACP, 0,
-                                      (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
+                                      (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
                                       NULL, 0, NULL, NULL);
     if(lpOTMW->otmpFaceName)
         needed += WideCharToMultiByte(CP_ACP, 0,
-                                      (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
+                                      (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
                                       NULL, 0, NULL, NULL);
     if(lpOTMW->otmpStyleName)
         needed += WideCharToMultiByte(CP_ACP, 0,
-                                      (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
+                                      (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
                                       NULL, 0, NULL, NULL);
     if(lpOTMW->otmpFullName)
         needed += WideCharToMultiByte(CP_ACP, 0,
-                                      (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
+                                      (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
                                       NULL, 0, NULL, NULL);
 
     if(!lpOTM)
@@ -1143,7 +1297,7 @@ GetOutlineTextMetricsA(
     {
         output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
         len = WideCharToMultiByte(CP_ACP, 0,
-                                  (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
+                                  (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
                                   ptr, left, NULL, NULL);
         left -= len;
         ptr += len;
@@ -1155,7 +1309,7 @@ GetOutlineTextMetricsA(
     {
         output->otmpFaceName = (LPSTR)(ptr - (char*)output);
         len = WideCharToMultiByte(CP_ACP, 0,
-                                  (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
+                                  (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
                                   ptr, left, NULL, NULL);
         left -= len;
         ptr += len;
@@ -1167,7 +1321,7 @@ GetOutlineTextMetricsA(
     {
         output->otmpStyleName = (LPSTR)(ptr - (char*)output);
         len = WideCharToMultiByte(CP_ACP, 0,
-                                  (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
+                                  (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
                                   ptr, left, NULL, NULL);
         left -= len;
         ptr += len;
@@ -1179,14 +1333,14 @@ GetOutlineTextMetricsA(
     {
         output->otmpFullName = (LPSTR)(ptr - (char*)output);
         len = WideCharToMultiByte(CP_ACP, 0,
-                                  (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
+                                  (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
                                   ptr, left, NULL, NULL);
         left -= len;
     }
     else
         output->otmpFullName = 0;
 
-    assert(left == 0);
+    ASSERT(left == 0);
 
     if(output != lpOTM)
     {
@@ -1557,6 +1711,90 @@ CreateFontIndirectA(
 }
 
 
+#if DBG
+VOID DumpFamilyInfo(const FONTFAMILYINFO *Info, LONG Count)
+{
+    LONG i;
+    const LOGFONTW *plf;
+
+    DPRINT1("---\n");
+    DPRINT1("Count: %d\n", Count);
+    for (i = 0; i < Count; ++i)
+    {
+        plf = &Info[i].EnumLogFontEx.elfLogFont;
+        DPRINT1("%d: '%S',%u,'%S', %ld:%ld, %ld, %d, %d\n", i,
+            plf->lfFaceName, plf->lfCharSet, Info[i].EnumLogFontEx.elfFullName,
+            plf->lfHeight, plf->lfWidth, plf->lfWeight, plf->lfItalic, plf->lfPitchAndFamily);
+    }
+}
+
+VOID DoFontSystemUnittest(VOID)
+{
+#ifndef RTL_SOFT_ASSERT
+#define RTL_SOFT_ASSERT(exp) \
+  (void)((!(exp)) ? \
+    DbgPrint("%s(%d): Soft assertion failed\n Expression: %s\n", __FILE__, __LINE__, #exp), FALSE : TRUE)
+#define RTL_SOFT_ASSERT_defined
+#endif
+
+    LOGFONTW LogFont;
+    FONTFAMILYINFO Info[4];
+    UNICODE_STRING Str1, Str2;
+    LONG ret, InfoCount;
+
+    //DumpFontInfo(TRUE);
+
+    /* L"" DEFAULT_CHARSET */
+    RtlZeroMemory(&LogFont, sizeof(LogFont));
+    LogFont.lfCharSet = DEFAULT_CHARSET;
+    InfoCount = RTL_NUMBER_OF(Info);
+    ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
+    DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
+    DumpFamilyInfo(Info, ret);
+    RTL_SOFT_ASSERT(ret == RTL_NUMBER_OF(Info));
+    RTL_SOFT_ASSERT(InfoCount > 32);
+
+    /* L"Microsoft Sans Serif" ANSI_CHARSET */
+    RtlZeroMemory(&LogFont, sizeof(LogFont));
+    LogFont.lfCharSet = ANSI_CHARSET;
+    StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Microsoft Sans Serif");
+    InfoCount = RTL_NUMBER_OF(Info);
+    ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
+    DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
+    DumpFamilyInfo(Info, ret);
+    RTL_SOFT_ASSERT(ret != -1);
+    RTL_SOFT_ASSERT(InfoCount > 0);
+    RTL_SOFT_ASSERT(InfoCount < 16);
+
+    RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfLogFont.lfFaceName);
+    RtlInitUnicodeString(&Str2, L"Microsoft Sans Serif");
+    ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE);
+    RTL_SOFT_ASSERT(ret == 0);
+
+    RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfFullName);
+    RtlInitUnicodeString(&Str2, L"Tahoma");
+    ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE);
+    RTL_SOFT_ASSERT(ret == 0);
+
+    /* L"Non-Existent" DEFAULT_CHARSET */
+    RtlZeroMemory(&LogFont, sizeof(LogFont));
+    LogFont.lfCharSet = ANSI_CHARSET;
+    StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Non-Existent");
+    InfoCount = RTL_NUMBER_OF(Info);
+    ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
+    DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
+    DumpFamilyInfo(Info, ret);
+    RTL_SOFT_ASSERT(ret == 0);
+    RTL_SOFT_ASSERT(InfoCount == 0);
+
+#ifdef RTL_SOFT_ASSERT_defined
+#undef RTL_SOFT_ASSERT_defined
+#undef RTL_SOFT_ASSERT
+#endif
+}
+#endif
+
+/* EOF */
 /*
  * @implemented
  */
@@ -1566,6 +1804,14 @@ CreateFontIndirectW(
     CONST LOGFONTW             *lplf
 )
 {
+#if 0
+    static BOOL bDidTest = FALSE;
+    if (!bDidTest)
+    {
+        bDidTest = TRUE;
+        DoFontSystemUnittest();
+    }
+#endif
     if (lplf)
     {
         ENUMLOGFONTEXDVW Logfont;
@@ -1856,6 +2102,7 @@ RemoveFontResourceExW(LPCWSTR lpFileName,
     /* FIXME the flags */
     /* FIXME the pdv */
     /* FIXME NtGdiRemoveFontResource handle flags and pdv */
+    DPRINT("RemoveFontResourceExW\n");
     return 0;
 }
 
@@ -2096,7 +2343,8 @@ NewEnumFontFamiliesExW(
     LPARAM lParam,
     DWORD dwFlags)
 {
-    ULONG_PTR idEnum, cbDataSize, cbRetSize;
+    ULONG_PTR idEnum;
+    ULONG cbDataSize, cbRetSize;
     PENUMFONTDATAW pEfdw;
     PBYTE pBuffer;
     PBYTE pMax;
@@ -2160,3 +2408,281 @@ NewEnumFontFamiliesExW(
 
     return ret;
 }
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+GdiAddFontResourceW(
+    LPCWSTR lpszFilename,
+    FLONG fl,
+    DESIGNVECTOR *pdv)
+{
+    INT Ret;
+    WCHAR lpszBuffer[MAX_PATH];
+    WCHAR lpszAbsPath[MAX_PATH];
+    UNICODE_STRING NtAbsPath;
+
+    /* FIXME: We don't support multiple files passed in lpszFilename
+     *        as L"abcxxxxx.pfm|abcxxxxx.pfb"
+     */
+
+    /* Does the file exist in CurrentDirectory or in the Absolute Path passed? */
+    GetCurrentDirectoryW(MAX_PATH, lpszBuffer);
+
+    if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
+    {
+        /* Nope. Then let's check Fonts folder */
+        GetWindowsDirectoryW(lpszBuffer, MAX_PATH);
+        StringCbCatW(lpszBuffer, sizeof(lpszBuffer), L"\\Fonts");
+
+        if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
+        {
+            DPRINT1("Font not found. The Buffer is: %ls, the FileName is: %S\n", lpszBuffer, lpszFilename);
+            return 0;
+        }
+    }
+
+    /* We found the font file so: */
+    if (!RtlDosPathNameToNtPathName_U(lpszAbsPath, &NtAbsPath, NULL, NULL))
+    {
+        DPRINT1("Can't convert Path! Path: %ls\n", lpszAbsPath);
+        return 0;
+    }
+
+    /* The Nt call expects a null-terminator included in cwc param. */
+    ASSERT(NtAbsPath.Buffer[NtAbsPath.Length / sizeof(WCHAR)] == UNICODE_NULL);
+    Ret = NtGdiAddFontResourceW(NtAbsPath.Buffer, NtAbsPath.Length / sizeof(WCHAR) + 1, 1, fl, 0, pdv);
+
+    RtlFreeUnicodeString(&NtAbsPath);
+
+    return Ret;
+}
+
+/*
+ * @implemented
+ */
+HANDLE
+WINAPI
+AddFontMemResourceEx(
+    PVOID pbFont,
+    DWORD cbFont,
+    PVOID pdv,
+    DWORD *pcFonts
+)
+{
+    if ( pbFont && cbFont && pcFonts)
+    {
+        return NtGdiAddFontMemResourceEx(pbFont, cbFont, NULL, 0, pcFonts);
+    }
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return NULL;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+RemoveFontMemResourceEx(HANDLE fh)
+{
+    if (fh)
+    {
+        return NtGdiRemoveFontMemResourceEx(fh);
+    }
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+}
+
+
+/*
+ * @unimplemented
+ */
+int
+WINAPI
+AddFontResourceTracking(
+    LPCSTR lpString,
+    int unknown
+)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+/*
+ * @unimplemented
+ */
+int
+WINAPI
+RemoveFontResourceTracking(LPCSTR lpString,int unknown)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+BOOL
+WINAPI
+CreateScalableFontResourceW(
+    DWORD fdwHidden,
+    LPCWSTR lpszFontRes,
+    LPCWSTR lpszFontFile,
+    LPCWSTR lpszCurrentPath
+)
+{
+    HANDLE f;
+
+    UNIMPLEMENTED;
+
+    /* fHidden=1 - only visible for the calling app, read-only, not
+     * enumerated with EnumFonts/EnumFontFamilies
+     * lpszCurrentPath can be NULL
+     */
+
+    /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
+    if ((f = CreateFileW(lpszFontRes, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(f);
+        SetLastError(ERROR_FILE_EXISTS);
+        return FALSE;
+    }
+    return FALSE; /* create failed */
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+bInitSystemAndFontsDirectoriesW(LPWSTR *SystemDir,LPWSTR *FontsDir)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+EudcLoadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath,INT iPriority,INT iFontLinkType)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+EudcUnloadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+WINAPI
+GetEUDCTimeStamp(VOID)
+{
+    return NtGdiGetEudcTimeStampEx(NULL,0,TRUE);
+}
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+GetEUDCTimeStampExW(LPWSTR lpBaseFaceName)
+{
+    DWORD retValue = 0;
+
+    if (!lpBaseFaceName)
+    {
+        retValue = NtGdiGetEudcTimeStampEx(NULL,0,FALSE);
+    }
+    else
+    {
+        retValue = NtGdiGetEudcTimeStampEx(lpBaseFaceName, wcslen(lpBaseFaceName), FALSE);
+    }
+
+    return retValue;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+WINAPI
+GetFontAssocStatus(HDC hdc)
+{
+    ULONG retValue = 0;
+
+    if (hdc)
+    {
+        retValue = NtGdiQueryFontAssocInfo(hdc);
+    }
+
+    return retValue;
+}
+
+/*
+ * @unimplemented
+ */
+DWORD
+WINAPI
+QueryFontAssocStatus(VOID)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+WINAPI
+UnloadNetworkFonts(DWORD unknown)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+}
+
+/*
+ * @implemented
+ *
+ */
+DWORD
+WINAPI
+GetFontData(HDC hdc,
+            DWORD dwTable,
+            DWORD dwOffset,
+            LPVOID lpvBuffer,
+            DWORD cbData)
+{
+    if (!lpvBuffer)
+    {
+        cbData = 0;
+    }
+    return NtGdiGetFontData(hdc, dwTable, dwOffset, lpvBuffer, cbData);
+}
+
+DWORD
+WINAPI
+cGetTTFFromFOT(DWORD x1 ,DWORD x2 ,DWORD x3, DWORD x4, DWORD x5, DWORD x6, DWORD x7)
+{
+    UNIMPLEMENTED;
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return 0;
+}
+