[WIN32SS] Improve GetFontResourceInfoW. Patch by Katayama Hirofumi MZ & Doug Lyons.
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
index 14e41d5..5252f15 100644 (file)
@@ -48,49 +48,15 @@ extern const MATRIX gmxWorldToPageDefault;
 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
 
 FT_Library  library;
+static const WORD gusEnglishUS = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
 
 /* special font names */
 static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett");
-static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System");
-static const UNICODE_STRING FixedSysW = RTL_CONSTANT_STRING(L"FixedSys");
 
 /* registry */
 static UNICODE_STRING FontRegPath =
     RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
 
-static PSHARED_FACE
-SharedFace_Create(FT_Face Face)
-{
-    PSHARED_FACE Ptr;
-    Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
-    if (Ptr)
-    {
-        Ptr->Face = Face;
-        Ptr->RefCount = 1;
-    }
-    return Ptr;
-}
-
-static void
-SharedFace_AddRef(PSHARED_FACE Ptr)
-{
-    ++Ptr->RefCount;
-}
-
-static void
-SharedFace_Release(PSHARED_FACE Ptr)
-{
-    if (Ptr->RefCount <= 0)
-        return;
-
-    --Ptr->RefCount;
-    if (Ptr->RefCount == 0)
-    {
-        FT_Done_Face(Ptr->Face);
-        ExFreePoolWithTag(Ptr, TAG_FONT);
-    }
-}
-
 
 /* The FreeType library is not thread safe, so we have
    to serialize access to it */
@@ -106,12 +72,21 @@ static BOOL RenderingEnabled = TRUE;
 #define IntUnLockGlobalFonts \
   ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
 
+#define ASSERT_GLOBALFONTS_LOCK_HELD() \
+  ASSERT(FontListLock->Owner == KeGetCurrentThread())
+
 #define IntLockFreeType \
   ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
 
 #define IntUnLockFreeType \
   ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
 
+#define ASSERT_FREETYPE_LOCK_HELD() \
+  ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
+
+#define ASSERT_FREETYPE_LOCK_NOT_HELD() \
+  ASSERT(FreeTypeLock->Owner != KeGetCurrentThread())
+
 #define MAX_FONT_CACHE 256
 
 static LIST_ENTRY FontCacheListHead;
@@ -189,6 +164,149 @@ static const CHARSETINFO FontTci[MAXTCIINDEX] =
 /* list head */
 static RTL_STATIC_LIST_HEAD(FontSubstListHead);
 
+static void
+SharedMem_AddRef(PSHARED_MEM Ptr)
+{
+    ASSERT_FREETYPE_LOCK_HELD();
+
+    ++Ptr->RefCount;
+}
+
+static void
+SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
+{
+    Cache->OutlineRequiredSize = 0;
+    RtlInitUnicodeString(&Cache->FontFamily, NULL);
+    RtlInitUnicodeString(&Cache->FullName, NULL);
+}
+
+static PSHARED_FACE
+SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
+{
+    PSHARED_FACE Ptr;
+    Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
+    if (Ptr)
+    {
+        Ptr->Face = Face;
+        Ptr->RefCount = 1;
+        Ptr->Memory = Memory;
+        SharedFaceCache_Init(&Ptr->EnglishUS);
+        SharedFaceCache_Init(&Ptr->UserLanguage);
+
+        SharedMem_AddRef(Memory);
+        DPRINT("Creating SharedFace for %s\n", Face->family_name);
+    }
+    return Ptr;
+}
+
+static PSHARED_MEM
+SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
+{
+    PSHARED_MEM Ptr;
+    Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
+    if (Ptr)
+    {
+        Ptr->Buffer = Buffer;
+        Ptr->BufferSize = BufferSize;
+        Ptr->RefCount = 1;
+        Ptr->IsMapping = IsMapping;
+        DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
+    }
+    return Ptr;
+}
+
+static void
+SharedFace_AddRef(PSHARED_FACE Ptr)
+{
+    ASSERT_FREETYPE_LOCK_HELD();
+
+    ++Ptr->RefCount;
+}
+
+static void
+RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
+{
+    ASSERT_FREETYPE_LOCK_HELD();
+
+    FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
+    RemoveEntryList(&Entry->ListEntry);
+    ExFreePoolWithTag(Entry, TAG_FONT);
+    FontCacheNumEntries--;
+    ASSERT(FontCacheNumEntries <= MAX_FONT_CACHE);
+}
+
+static void
+RemoveCacheEntries(FT_Face Face)
+{
+    PLIST_ENTRY CurrentEntry;
+    PFONT_CACHE_ENTRY FontEntry;
+
+    ASSERT_FREETYPE_LOCK_HELD();
+
+    CurrentEntry = FontCacheListHead.Flink;
+    while (CurrentEntry != &FontCacheListHead)
+    {
+        FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
+        CurrentEntry = CurrentEntry->Flink;
+
+        if (FontEntry->Face == Face)
+        {
+            RemoveCachedEntry(FontEntry);
+        }
+    }
+}
+
+static void SharedMem_Release(PSHARED_MEM Ptr)
+{
+    ASSERT_FREETYPE_LOCK_HELD();
+    ASSERT(Ptr->RefCount > 0);
+
+    if (Ptr->RefCount <= 0)
+        return;
+
+    --Ptr->RefCount;
+    if (Ptr->RefCount == 0)
+    {
+        DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
+        if (Ptr->IsMapping)
+            MmUnmapViewInSystemSpace(Ptr->Buffer);
+        else
+            ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
+        ExFreePoolWithTag(Ptr, TAG_FONT);
+    }
+}
+
+static void
+SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
+{
+    RtlFreeUnicodeString(&Cache->FontFamily);
+    RtlFreeUnicodeString(&Cache->FullName);
+}
+
+static void
+SharedFace_Release(PSHARED_FACE Ptr)
+{
+    IntLockFreeType;
+    ASSERT(Ptr->RefCount > 0);
+
+    if (Ptr->RefCount <= 0)
+        return;
+
+    --Ptr->RefCount;
+    if (Ptr->RefCount == 0)
+    {
+        DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name);
+        RemoveCacheEntries(Ptr->Face);
+        FT_Done_Face(Ptr->Face);
+        SharedMem_Release(Ptr->Memory);
+        SharedFaceCache_Release(&Ptr->EnglishUS);
+        SharedFaceCache_Release(&Ptr->UserLanguage);
+        ExFreePoolWithTag(Ptr, TAG_FONT);
+    }
+    IntUnLockFreeType;
+}
+
+
 /*
  * IntLoadFontSubstList --- loads the list of font substitutes
  */
@@ -402,7 +520,6 @@ SubstituteFontByList(PLIST_ENTRY        pHead,
                      BYTE               RequestedCharSet,
                      BYTE               CharSetMap[FONTSUBST_FROM_AND_TO])
 {
-    NTSTATUS            Status;
     PLIST_ENTRY         pListEntry;
     PFONTSUBST_ENTRY    pSubstEntry;
     BYTE                CharSets[FONTSUBST_FROM_AND_TO];
@@ -444,14 +561,7 @@ SubstituteFontByList(PLIST_ENTRY        pHead,
         }
 
         /* update *pOutputName */
-        RtlFreeUnicodeString(pOutputName);
-        Status = RtlCreateUnicodeString(pOutputName,
-                                        pSubstEntry->FontNames[FONTSUBST_TO].Buffer);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
-            continue;   /* cannot create string */
-        }
+        *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
 
         if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
         {
@@ -466,32 +576,33 @@ SubstituteFontByList(PLIST_ENTRY        pHead,
 }
 
 static BOOL
-SubstituteFontRecurse(PUNICODE_STRING pInOutName, BYTE *pRequestedCharSet)
+SubstituteFontRecurse(LOGFONTW* pLogFont)
 {
     UINT            RecurseCount = 5;
     UNICODE_STRING  OutputNameW = { 0 };
     BYTE            CharSetMap[FONTSUBST_FROM_AND_TO];
     BOOL            Found;
+    UNICODE_STRING  InputNameW;
 
-    if (pInOutName->Buffer[0] == UNICODE_NULL)
+    if (pLogFont->lfFaceName[0] == UNICODE_NULL)
         return FALSE;
 
+    RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
+
     while (RecurseCount-- > 0)
     {
-        RtlInitUnicodeString(&OutputNameW, NULL);
         Found = SubstituteFontByList(&FontSubstListHead,
-                                     &OutputNameW, pInOutName,
-                                     *pRequestedCharSet, CharSetMap);
+                                     &OutputNameW, &InputNameW,
+                                     pLogFont->lfCharSet, CharSetMap);
         if (!Found)
             break;
 
-        /* update *pInOutName and *pRequestedCharSet */
-        RtlFreeUnicodeString(pInOutName);
-        *pInOutName = OutputNameW;
+        RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
+
         if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
-            CharSetMap[FONTSUBST_FROM] == *pRequestedCharSet)
+            CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
         {
-            *pRequestedCharSet = CharSetMap[FONTSUBST_TO];
+            pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
         }
     }
 
@@ -675,10 +786,8 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
     FT_Face             Face;
     ANSI_STRING         AnsiFaceName;
     FT_WinFNT_HeaderRec WinFNT;
-    INT                 FontCount = 0, CharSetCount = 0;
+    INT                 FaceCount = 0, CharSetCount = 0;
     PUNICODE_STRING     pFileName       = pLoadFont->pFileName;
-    PVOID               Buffer          = pLoadFont->Buffer;
-    ULONG               BufferSize      = pLoadFont->BufferSize;
     DWORD               Characteristics = pLoadFont->Characteristics;
     PUNICODE_STRING     pValueName = &pLoadFont->RegValueName;
     TT_OS2 *            pOS2;
@@ -693,30 +802,37 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
         IntLockFreeType;
         Error = FT_New_Memory_Face(
                     library,
-                    Buffer,
-                    BufferSize,
+                    pLoadFont->Memory->Buffer,
+                    pLoadFont->Memory->BufferSize,
                     ((FontIndex != -1) ? FontIndex : 0),
                     &Face);
+
+        if (!Error)
+            SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
+
         IntUnLockFreeType;
 
-        if (FT_IS_SFNT(Face))
+        if (!Error && FT_IS_SFNT(Face))
             pLoadFont->IsTrueType = TRUE;
 
-        if (!Error)
-            SharedFace = SharedFace_Create(Face);
         if (Error || SharedFace == NULL)
         {
+            if (SharedFace)
+                SharedFace_Release(SharedFace);
+
             if (Error == FT_Err_Unknown_File_Format)
                 DPRINT1("Unknown font file format\n");
             else
-                DPRINT1("Error reading font file (error code: %d)\n", Error);
+                DPRINT1("Error reading font (error code: %d)\n", Error);
             return 0;   /* failure */
         }
     }
     else
     {
         Face = SharedFace->Face;
+        IntLockFreeType;
         SharedFace_AddRef(SharedFace);
+        IntUnLockFreeType;
     }
 
     /* allocate a FONT_ENTRY */
@@ -870,7 +986,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
         FontGDI->CharSet = SYMBOL_CHARSET;
     }
 
-    ++FontCount;
+    ++FaceCount;
     DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
     DPRINT("Num glyphs: %d\n", Face->num_glyphs);
     DPRINT("CharSet: %d\n", FontGDI->CharSet);
@@ -905,7 +1021,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
                 FT_Long i;
                 for (i = 1; i < TrueType->ttc_header.count; ++i)
                 {
-                    FontCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
+                    FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
                 }
             }
         }
@@ -941,11 +1057,12 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
 
         for (i = 1; i < CharSetCount; ++i)
         {
-            FontCount += IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
+            /* Do not count charsets towards 'faces' loaded */
+            IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
         }
     }
 
-    return FontCount;   /* number of loaded fonts */
+    return FaceCount;   /* number of loaded faces */
 }
 
 /*
@@ -1006,8 +1123,7 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     }
 
     LoadFont.pFileName          = FileName;
-    LoadFont.Buffer             = Buffer;
-    LoadFont.BufferSize         = ViewSize;
+    LoadFont.Memory             = SharedMem_Create(Buffer, ViewSize, TRUE);
     LoadFont.Characteristics    = Characteristics;
     RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
     LoadFont.IsTrueType         = FALSE;
@@ -1016,6 +1132,11 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
 
     ObDereferenceObject(SectionObject);
 
+    /* Release our copy */
+    IntLockFreeType;
+    SharedMem_Release(LoadFont.Memory);
+    IntUnLockFreeType;
+
     if (FontCount > 0)
     {
         if (LoadFont.IsTrueType)
@@ -1067,30 +1188,34 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
 {
     GDI_LOAD_FONT LoadFont;
     FONT_ENTRY_COLL_MEM* EntryCollection;
-    INT FontCount;
+    INT FaceCount;
     HANDLE Ret = 0;
 
-    /* We leak this buffer for now, same as all fonts do with their buffer! */
-    LoadFont.Buffer = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
-    if (!LoadFont.Buffer)
+    PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
+
+    if (!BufferCopy)
     {
         *pNumAdded = 0;
         return NULL;
     }
-    memcpy(LoadFont.Buffer, Buffer, dwSize);
+    memcpy(BufferCopy, Buffer, dwSize);
 
     LoadFont.pFileName = NULL;
-    LoadFont.BufferSize = dwSize;
+    LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
     LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
     RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
     LoadFont.IsTrueType = FALSE;
     LoadFont.PrivateEntry = NULL;
-    FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
+    FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
 
     RtlFreeUnicodeString(&LoadFont.RegValueName);
 
-    *pNumAdded = FontCount;
-    if (FontCount > 0)
+    /* Release our copy */
+    IntLockFreeType;
+    SharedMem_Release(LoadFont.Memory);
+    IntUnLockFreeType;
+
+    if (FaceCount > 0)
     {
         EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
         if (EntryCollection)
@@ -1104,12 +1229,27 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
             Ret = (HANDLE)EntryCollection->Handle;
         }
     }
+    *pNumAdded = FaceCount;
 
     return Ret;
 }
 
 // FIXME: Add RemoveFontResource
 
+static VOID FASTCALL
+CleanupFontEntry(PFONT_ENTRY FontEntry)
+{
+    PFONTGDI FontGDI = FontEntry->Font;
+    PSHARED_FACE SharedFace = FontGDI->SharedFace;
+
+    if (FontGDI->Filename)
+        ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
+
+    EngFreeMem(FontGDI);
+    SharedFace_Release(SharedFace);
+    ExFreePoolWithTag(FontEntry, TAG_FONT);
+}
+
 VOID FASTCALL
 IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
 {
@@ -1121,14 +1261,31 @@ IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
         Entry = RemoveHeadList(&Head->ListEntry);
         FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
 
-        // Delete FontEntry->Entry (FONT_ENTRY*)
+        CleanupFontEntry(FontEntry->Entry);
         ExFreePoolWithTag(FontEntry, TAG_FONT);
     }
 
-    // Delete Head->Entry (FONT_ENTRY*)
+    CleanupFontEntry(Head->Entry);
     ExFreePoolWithTag(Head, TAG_FONT);
 }
 
+static VOID FASTCALL
+UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
+{
+    PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
+    PLIST_ENTRY ListEntry;
+    RemoveEntryList(&Collection->ListEntry);
+
+    do {
+        /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
+        RemoveEntryList(&FontMemEntry->Entry->ListEntry);
+
+        ListEntry = FontMemEntry->ListEntry.Flink;
+        FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
+
+    } while (FontMemEntry != Collection->Entry);
+}
+
 BOOL FASTCALL
 IntGdiRemoveFontMemResource(HANDLE hMMFont)
 {
@@ -1146,7 +1303,7 @@ IntGdiRemoveFontMemResource(HANDLE hMMFont)
         if (CurrentEntry->Handle == (UINT)hMMFont)
         {
             EntryCollection = CurrentEntry;
-            RemoveEntryList(Entry);
+            UnlinkFontMemCollection(CurrentEntry);
             break;
         }
 
@@ -1164,6 +1321,52 @@ IntGdiRemoveFontMemResource(HANDLE hMMFont)
 }
 
 
+VOID FASTCALL
+IntGdiCleanupPrivateFontsForProcess(VOID)
+{
+    PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
+    PLIST_ENTRY Entry;
+    PFONT_ENTRY_COLL_MEM EntryCollection;
+
+    DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
+    do {
+        Entry = NULL;
+        EntryCollection = NULL;
+
+        IntLockProcessPrivateFonts(Win32Process);
+        if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
+        {
+            Entry = Win32Process->PrivateMemFontListHead.Flink;
+            EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
+            UnlinkFontMemCollection(EntryCollection);
+        }
+        IntUnLockProcessPrivateFonts(Win32Process);
+
+        if (EntryCollection)
+        {
+            IntGdiCleanupMemEntry(EntryCollection->Entry);
+            ExFreePoolWithTag(EntryCollection, TAG_FONT);
+        }
+        else
+        {
+            /* No Mem fonts anymore, see if we have any other private fonts left */
+            Entry = NULL;
+            IntLockProcessPrivateFonts(Win32Process);
+            if (!IsListEmpty(&Win32Process->PrivateFontListHead))
+            {
+                Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
+            }
+            IntUnLockProcessPrivateFonts(Win32Process);
+
+            if (Entry)
+            {
+                CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
+            }
+        }
+
+    } while (Entry);
+}
+
 BOOL FASTCALL
 IntIsFontRenderingEnabled(VOID)
 {
@@ -1549,6 +1752,10 @@ FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
     FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
 }
 
+static NTSTATUS
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
+                        FT_UShort NameID, FT_UShort LangID);
+
 /*************************************************************
  * IntGetOutlineTextMetrics
  *
@@ -1558,63 +1765,58 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
                          UINT Size,
                          OUTLINETEXTMETRICW *Otm)
 {
-    unsigned Needed;
     TT_OS2 *pOS2;
     TT_HoriHeader *pHori;
     TT_Postscript *pPost;
     FT_Fixed XScale, YScale;
-    ANSI_STRING FamilyNameA, StyleNameA;
-    UNICODE_STRING FamilyNameW, StyleNameW, Regular;
     FT_WinFNT_HeaderRec Win;
     FT_Error Error;
     char *Cp;
-    NTSTATUS status;
-    FT_Face Face = FontGDI->SharedFace->Face;
+    UNICODE_STRING FamilyNameW, FaceNameW, StyleNameW, FullNameW;
+    PSHARED_FACE SharedFace = FontGDI->SharedFace;
+    PSHARED_FACE_CACHE Cache = (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH) ? &SharedFace->EnglishUS : &SharedFace->UserLanguage;
+    FT_Face Face = SharedFace->Face;
 
-    Needed = sizeof(OUTLINETEXTMETRICW);
-
-    RtlInitAnsiString(&FamilyNameA, Face->family_name);
-    status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
-    if (!NT_SUCCESS(status))
+    if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
     {
-        return 0;
+        return Cache->OutlineRequiredSize;
     }
 
-    RtlInitAnsiString(&StyleNameA, Face->style_name);
-    status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
-    if (!NT_SUCCESS(status))
-    {
-        RtlFreeUnicodeString(&FamilyNameW);
-        return 0;
-    }
+    /* family name */
+    RtlInitUnicodeString(&FamilyNameW, NULL);
+    IntGetFontLocalizedName(&FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
 
-    /* These names should be read from the TT name table */
+    /* face name */
+    RtlInitUnicodeString(&FaceNameW, NULL);
+    IntGetFontLocalizedName(&FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
 
-    /* Length of otmpFamilyName */
-    Needed += FamilyNameW.Length + sizeof(WCHAR);
+    /* style name */
+    RtlInitUnicodeString(&StyleNameW, NULL);
+    IntGetFontLocalizedName(&StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
 
-    RtlInitUnicodeString(&Regular, L"Regular");
-    /* Length of otmpFaceName */
-    if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
-    {
-        Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
-    }
-    else
-    {
-        Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
-    }
+    /* unique name (full name) */
+    RtlInitUnicodeString(&FullNameW, NULL);
+    IntGetFontLocalizedName(&FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
 
-    /* Length of otmpStyleName */
-    Needed += StyleNameW.Length + sizeof(WCHAR);
+    if (!Cache->OutlineRequiredSize)
+    {
+        UINT Needed;
+        Needed = sizeof(OUTLINETEXTMETRICW);
+        Needed += FamilyNameW.Length + sizeof(WCHAR);
+        Needed += FaceNameW.Length + sizeof(WCHAR);
+        Needed += StyleNameW.Length + sizeof(WCHAR);
+        Needed += FullNameW.Length + sizeof(WCHAR);
 
-    /* Length of otmpFullName */
-    Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
+        Cache->OutlineRequiredSize = Needed;
+    }
 
-    if (Size < Needed)
+    if (Size < Cache->OutlineRequiredSize)
     {
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
         RtlFreeUnicodeString(&StyleNameW);
-        return Needed;
+        RtlFreeUnicodeString(&FullNameW);
+        return Cache->OutlineRequiredSize;
     }
 
     XScale = Face->size->metrics.x_scale;
@@ -1626,8 +1828,10 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
     {
         IntUnLockFreeType;
         DPRINT1("Can't find OS/2 table - not TT font?\n");
-        RtlFreeUnicodeString(&StyleNameW);
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
+        RtlFreeUnicodeString(&StyleNameW);
+        RtlFreeUnicodeString(&FullNameW);
         return 0;
     }
 
@@ -1636,8 +1840,10 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
     {
         IntUnLockFreeType;
         DPRINT1("Can't find HHEA table - not TT font?\n");
-        RtlFreeUnicodeString(&StyleNameW);
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
+        RtlFreeUnicodeString(&StyleNameW);
+        RtlFreeUnicodeString(&FullNameW);
         return 0;
     }
 
@@ -1645,7 +1851,7 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
 
     Error = FT_Get_WinFNT_Header(Face , &Win);
 
-    Otm->otmSize = Needed;
+    Otm->otmSize = Cache->OutlineRequiredSize;
 
     FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
 
@@ -1693,35 +1899,36 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
 
     IntUnLockFreeType;
 
-    /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
     Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
+
+    /* family name */
     Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
     wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
     Cp += FamilyNameW.Length + sizeof(WCHAR);
+
+    /* face name */
+    Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
+    wcscpy((WCHAR*) Cp, FaceNameW.Buffer);
+    Cp += FaceNameW.Length + sizeof(WCHAR);
+
+    /* style name */
     Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
     wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
     Cp += StyleNameW.Length + sizeof(WCHAR);
-    Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
-    wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
-    if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
-    {
-        wcscat((WCHAR*) Cp, L" ");
-        wcscat((WCHAR*) Cp, StyleNameW.Buffer);
-        Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
-    }
-    else
-    {
-        Cp += FamilyNameW.Length + sizeof(WCHAR);
-    }
+
+    /* unique name (full name) */
     Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
-    wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
-    wcscat((WCHAR*) Cp, L" ");
-    wcscat((WCHAR*) Cp, StyleNameW.Buffer);
+    wcscpy((WCHAR*) Cp, FullNameW.Buffer);
+    Cp += FullNameW.Length + sizeof(WCHAR);
+
+    ASSERT(Cp - (char*)Otm == Cache->OutlineRequiredSize);
 
-    RtlFreeUnicodeString(&StyleNameW);
     RtlFreeUnicodeString(&FamilyNameW);
+    RtlFreeUnicodeString(&FaceNameW);
+    RtlFreeUnicodeString(&StyleNameW);
+    RtlFreeUnicodeString(&FullNameW);
 
-    return Needed;
+    return Cache->OutlineRequiredSize;
 }
 
 static PFONTGDI FASTCALL
@@ -1737,7 +1944,7 @@ FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
     Entry = Head->Flink;
     while (Entry != Head)
     {
-        CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+        CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
 
         FontGDI = CurrentEntry->Font;
         ASSERT(FontGDI);
@@ -1774,7 +1981,8 @@ FindFaceNameInLists(PUNICODE_STRING FaceName)
     PPROCESSINFO Win32Process;
     PFONTGDI Font;
 
-    /* Search the process local list */
+    /* Search the process local list.
+       We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
     Win32Process = PsGetCurrentProcessWin32Process();
     IntLockProcessPrivateFonts(Win32Process);
     Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
@@ -1852,30 +2060,91 @@ SwapEndian(LPVOID pvData, DWORD Size)
 }
 
 static NTSTATUS
-IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
+DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
+{
+    NTSTATUS Status = STATUS_NO_MEMORY;
+    UNICODE_STRING Tmp;
+
+    Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
+    if (Tmp.Buffer)
+    {
+        Tmp.MaximumLength = Source->MaximumLength;
+        Tmp.Length = 0;
+        RtlCopyUnicodeString(&Tmp, Source);
+
+        Destination->MaximumLength = Tmp.MaximumLength;
+        Destination->Length = Tmp.Length;
+        Destination->Buffer = Tmp.Buffer;
+
+        Status = STATUS_SUCCESS;
+    }
+
+    return Status;
+}
+
+static NTSTATUS
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
+                        FT_UShort NameID, FT_UShort LangID)
 {
     FT_SfntName Name;
-    INT i, Count;
-    WCHAR Buf[LF_FACESIZE];
+    INT i, Count, BestIndex, Score, BestScore;
+    WCHAR Buf[LF_FULLFACESIZE];
+    FT_Error Error;
     NTSTATUS Status = STATUS_NOT_FOUND;
+    ANSI_STRING AnsiName;
+    PSHARED_FACE_CACHE Cache;
+    FT_Face Face = SharedFace->Face;
+
+    RtlFreeUnicodeString(pNameW);
+
+    /* select cache */
+    if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
+    {
+        Cache = &SharedFace->EnglishUS;
+    }
+    else
+    {
+        Cache = &SharedFace->UserLanguage;
+    }
+
+    /* use cache if available */
+    if (NameID == TT_NAME_ID_FONT_FAMILY && Cache->FontFamily.Buffer)
+    {
+        return DuplicateUnicodeString(&Cache->FontFamily, pNameW);
+    }
+    if (NameID == TT_NAME_ID_FULL_NAME && Cache->FullName.Buffer)
+    {
+        return DuplicateUnicodeString(&Cache->FullName, pNameW);
+    }
 
-    RtlInitUnicodeString(pLocalNameW, NULL);
+    BestIndex = -1;
+    BestScore = 0;
 
     Count = FT_Get_Sfnt_Name_Count(Face);
     for (i = 0; i < Count; ++i)
     {
-        FT_Get_Sfnt_Name(Face, i, &Name);
+        Error = FT_Get_Sfnt_Name(Face, i, &Name);
+        if (Error)
+        {
+            continue;   /* failure */
+        }
+
+        if (Name.name_id != NameID)
+        {
+            continue;   /* mismatched */
+        }
+
         if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
-            Name.encoding_id != TT_MS_ID_UNICODE_CS)
+            (Name.encoding_id != TT_MS_ID_UNICODE_CS &&
+             Name.encoding_id != TT_MS_ID_SYMBOL_CS))
         {
             continue;   /* not Microsoft Unicode name */
         }
 
-        if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
-            Name.string == NULL || Name.string_len == 0 ||
+        if (Name.string == NULL || Name.string_len == 0 ||
             (Name.string[0] == 0 && Name.string[1] == 0))
         {
-            continue;   /* not family name */
+            continue;   /* invalid string */
         }
 
         if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
@@ -1883,25 +2152,91 @@ IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
             continue;   /* name too long */
         }
 
-        /* NOTE: Name.string is not null-terminated */
-        RtlCopyMemory(Buf, Name.string, Name.string_len);
-        Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
+        if (Name.language_id == LangID)
+        {
+            Score = 30;
+            BestIndex = i;
+            break;      /* best match */
+        }
+        else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
+        {
+            Score = 20;
+        }
+        else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
+        {
+            Score = 10;
+        }
+        else
+        {
+            Score = 0;
+        }
 
-        /* Convert UTF-16 big endian to little endian */
-        SwapEndian(Buf, Name.string_len);
-#if 0
-        DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
-#endif
+        if (Score > BestScore)
+        {
+            BestScore = Score;
+            BestIndex = i;
+        }
+    }
 
-        Status = RtlCreateUnicodeString(pLocalNameW, Buf);
-        break;
+    if (BestIndex >= 0)
+    {
+        /* store the best name */
+        Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
+        if (!Error)
+        {
+            /* NOTE: Name.string is not null-terminated */
+            RtlCopyMemory(Buf, Name.string, Name.string_len);
+            Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
+
+            /* Convert UTF-16 big endian to little endian */
+            SwapEndian(Buf, Name.string_len);
+
+            Status = RtlCreateUnicodeString(pNameW, Buf);
+        }
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        /* defaulted */
+        if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
+        {
+            RtlInitAnsiString(&AnsiName, Face->style_name);
+            Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
+        }
+        else
+        {
+            RtlInitAnsiString(&AnsiName, Face->family_name);
+            Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
+        }
+    }
+
+    if (NT_SUCCESS(Status))
+    {
+        /* make cache */
+        if (NameID == TT_NAME_ID_FONT_FAMILY)
+        {
+            ASSERT_FREETYPE_LOCK_NOT_HELD();
+            IntLockFreeType;
+            if (!Cache->FontFamily.Buffer)
+                DuplicateUnicodeString(pNameW, &Cache->FontFamily);
+            IntUnLockFreeType;
+        }
+        else if (NameID == TT_NAME_ID_FULL_NAME)
+        {
+            ASSERT_FREETYPE_LOCK_NOT_HELD();
+            IntLockFreeType;
+            if (!Cache->FullName.Buffer)
+                DuplicateUnicodeString(pNameW, &Cache->FullName);
+            IntUnLockFreeType;
+        }
     }
 
     return Status;
 }
 
 static void FASTCALL
-FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
+FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
+                   LPCWSTR FullName, PFONTGDI FontGDI)
 {
     ANSI_STRING StyleA;
     UNICODE_STRING StyleW;
@@ -1915,8 +2250,11 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     NEWTEXTMETRICW *Ntm;
     DWORD fs0;
     NTSTATUS status;
-    FT_Face Face = FontGDI->SharedFace->Face;
+    PSHARED_FACE SharedFace = FontGDI->SharedFace;
+    FT_Face Face = SharedFace->Face;
+    UNICODE_STRING NameW;
 
+    RtlInitUnicodeString(&NameW, NULL);
     RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
     Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
     Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
@@ -1924,7 +2262,12 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     {
         return;
     }
-    IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+    Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+    if (!Size)
+    {
+        ExFreePoolWithTag(Otm, GDITAG_TEXT);
+        return;
+    }
 
     Lf = &Info->EnumLogFontEx.elfLogFont;
     TM = &Otm->otmTextMetrics;
@@ -1976,39 +2319,22 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
         Info->FontType |= RASTER_FONTTYPE;
 
-    ExFreePoolWithTag(Otm, GDITAG_TEXT);
 
-    /* try the localized name */
-    status = STATUS_UNSUCCESSFUL;
-    if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
-    {
-        /* get localized name */
-        UNICODE_STRING LocalNameW;
-        status = IntGetFontLocalizedName(&LocalNameW, Face);
-        if (NT_SUCCESS(status))
-        {
-            /* store it */
-            RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
-                             sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
-                             LocalNameW.Buffer);
-            RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
-                             sizeof(Info->EnumLogFontEx.elfFullName),
-                             LocalNameW.Buffer);
-        }
-        RtlFreeUnicodeString(&LocalNameW);
-    }
+    /* face name */
+    if (!FaceName)
+        FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
 
-    /* if localized name was unavailable */
-    if (!NT_SUCCESS(status))
-    {
-        /* store English name */
-        RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
-                         sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
-                         FaceName);
-        RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
-                         sizeof(Info->EnumLogFontEx.elfFullName),
-                         FaceName);
-    }
+    RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
+
+    /* full name */
+    if (!FullName)
+        FullName = (WCHAR*)((ULONG_PTR) Otm + (ULONG_PTR)Otm->otmpFaceName);
+    
+    RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
+                     sizeof(Info->EnumLogFontEx.elfFullName),
+                     FullName);
+
+    ExFreePoolWithTag(Otm, GDITAG_TEXT);
 
     RtlInitAnsiString(&StyleA, Face->style_name);
     StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
@@ -2018,19 +2344,8 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     {
         return;
     }
-    if (StyleW.Length)
-    {
-        if (wcslen(Info->EnumLogFontEx.elfFullName) +
-            StyleW.Length / sizeof(WCHAR) + 1 <=
-                sizeof(Info->EnumLogFontEx.elfFullName))
-        {
-            wcscat(Info->EnumLogFontEx.elfFullName, L" ");
-            wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
-        }
-    }
+    Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
 
-    Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
-    Info->EnumLogFontEx.elfScript[0] = L'\0';
     IntLockFreeType;
     pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
 
@@ -2089,7 +2404,6 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
             }
             if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
             {
-                Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
                 if (ElfScripts[i])
                     wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
                 else
@@ -2136,164 +2450,130 @@ FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
     return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
 }
 
+static BOOL FASTCALL
+FontFamilyFound(PFONTFAMILYINFO InfoEntry,
+                PFONTFAMILYINFO Info, DWORD InfoCount)
+{
+    LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont;
+    LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName;
+    LPWSTR pFullName2;
+    DWORD i;
+
+    for (i = 0; i < InfoCount; ++i)
+    {
+        LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont;
+        if (plf1->lfCharSet != plf2->lfCharSet)
+            continue;
+
+        pFullName2 = Info[i].EnumLogFontEx.elfFullName;
+        if (_wcsicmp(pFullName1, pFullName2) != 0)
+            continue;
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
 static BOOLEAN FASTCALL
 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
                          PFONTFAMILYINFO Info,
-                         DWORD *Count,
-                         DWORD Size,
+                         DWORD *pCount,
+                         DWORD MaxCount,
                          PLIST_ENTRY Head)
 {
     PLIST_ENTRY Entry;
     PFONT_ENTRY CurrentEntry;
-    ANSI_STRING EntryFaceNameA;
-    UNICODE_STRING EntryFaceNameW;
     FONTGDI *FontGDI;
-    NTSTATUS status;
+    FONTFAMILYINFO InfoEntry;
+    DWORD Count = *pCount;
 
-    Entry = Head->Flink;
-    while (Entry != Head)
+    for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
     {
-        CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
-
+        CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
         FontGDI = CurrentEntry->Font;
         ASSERT(FontGDI);
 
-        RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
-        status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
-        if (!NT_SUCCESS(status))
+        if (LogFont->lfCharSet != DEFAULT_CHARSET &&
+            LogFont->lfCharSet != FontGDI->CharSet)
         {
-            return FALSE;
+            continue;
         }
 
-        if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+        if (LogFont->lfFaceName[0] == UNICODE_NULL)
         {
-            EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
-            EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+            if (Count < MaxCount)
+            {
+                FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
+            }
+            Count++;
+            continue;
         }
 
-        if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
+        FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
+
+        if (_wcsicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName) != 0 &&
+            _wcsicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName) != 0)
         {
-            if (*Count < Size)
+            continue;
+        }
+
+        if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
+        {
+            if (Count < MaxCount)
             {
-                FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
+                RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
             }
-            (*Count)++;
+            Count++;
         }
-        RtlFreeUnicodeString(&EntryFaceNameW);
-        Entry = Entry->Flink;
     }
 
+    *pCount = Count;
+
     return TRUE;
 }
 
-typedef struct FontFamilyInfoCallbackContext
-{
-    LPLOGFONTW LogFont;
-    PFONTFAMILYINFO Info;
-    DWORD Count;
-    DWORD Size;
-} FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
-
-_Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
-static NTSTATUS APIENTRY
-FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
-                                    IN PVOID ValueData, IN ULONG ValueLength,
-                                    IN PVOID Context, IN PVOID EntryContext)
+static BOOLEAN FASTCALL
+GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
+                                PFONTFAMILYINFO Info,
+                                DWORD *pCount,
+                                DWORD MaxCount)
 {
-    PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
-    UNICODE_STRING RegistryName, RegistryValue;
-    int Existing;
-    PFONTGDI FontGDI;
+    PLIST_ENTRY pEntry, pHead = &FontSubstListHead;
+    PFONTSUBST_ENTRY pCurrentEntry;
+    PUNICODE_STRING pFromW;
+    FONTGDI *FontGDI;
+    LOGFONTW lf = *LogFont;
+    UNICODE_STRING NameW;
 
-    if (REG_SZ != ValueType)
+    for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
     {
-        return STATUS_SUCCESS;
-    }
-    InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
-    RtlInitUnicodeString(&RegistryName, ValueName);
+        pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
 
-    /* Do we need to include this font family? */
-    if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
-                          min(InfoContext->Count, InfoContext->Size)))
-    {
-        RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
-        Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
-                                      min(InfoContext->Count, InfoContext->Size));
-        if (0 <= Existing)
+        pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
+        if (LogFont->lfFaceName[0] != UNICODE_NULL)
         {
-            /* We already have the information about the "real" font. Just copy it */
-            if (InfoContext->Count < InfoContext->Size)
-            {
-                InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
-                RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
-                                  sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
-                                  RegistryName.Buffer,
-                                  RegistryName.Length);
-            }
-            InfoContext->Count++;
-            return STATUS_SUCCESS;
+            if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount)))
+                continue;   /* mismatch */
         }
 
-        /* Try to find information about the "real" font */
-        FontGDI = FindFaceNameInLists(&RegistryValue);
-        if (NULL == FontGDI)
+        RtlStringCchCopyW(lf.lfFaceName, LF_FACESIZE, pFromW->Buffer);
+        SubstituteFontRecurse(&lf);
+
+        RtlInitUnicodeString(&NameW, lf.lfFaceName);
+        FontGDI = FindFaceNameInLists(&NameW);
+        if (FontGDI == NULL)
         {
-            /* "Real" font not found, discard this registry entry */
-            return STATUS_SUCCESS;
+            continue;   /* no real font */
         }
 
-        /* Return info about the "real" font but with the name of the alias */
-        if (InfoContext->Count < InfoContext->Size)
+        if (*pCount < MaxCount)
         {
-            FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
-                               RegistryName.Buffer, FontGDI);
+            FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI);
         }
-        InfoContext->Count++;
-        return STATUS_SUCCESS;
+        (*pCount)++;
     }
 
-    return STATUS_SUCCESS;
-}
-
-static BOOLEAN FASTCALL
-GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
-                                PFONTFAMILYINFO Info,
-                                DWORD *Count,
-                                DWORD Size)
-{
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
-    FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
-    NTSTATUS Status;
-
-    /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
-       The real work is done in the registry callback function */
-    Context.LogFont = LogFont;
-    Context.Info = Info;
-    Context.Count = *Count;
-    Context.Size = Size;
-
-    QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
-    QueryTable[0].Flags = 0;
-    QueryTable[0].Name = NULL;
-    QueryTable[0].EntryContext = NULL;
-    QueryTable[0].DefaultType = REG_NONE;
-    QueryTable[0].DefaultData = NULL;
-    QueryTable[0].DefaultLength = 0;
-
-    QueryTable[1].QueryRoutine = NULL;
-    QueryTable[1].Name = NULL;
-
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
-                                    L"FontSubstitutes",
-                                    QueryTable,
-                                    &Context,
-                                    NULL);
-    if (NT_SUCCESS(Status))
-    {
-        *Count = Context.Count;
-    }
-
-    return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
+    return TRUE;
 }
 
 BOOL
@@ -2333,10 +2613,12 @@ ftGdiGlyphCacheGet(
     PLIST_ENTRY CurrentEntry;
     PFONT_CACHE_ENTRY FontEntry;
 
+    ASSERT_FREETYPE_LOCK_HELD();
+
     CurrentEntry = FontCacheListHead.Flink;
     while (CurrentEntry != &FontCacheListHead)
     {
-        FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
+        FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
         if ((FontEntry->Face == Face) &&
             (FontEntry->GlyphIndex == GlyphIndex) &&
             (FontEntry->Height == Height) &&
@@ -2412,6 +2694,8 @@ ftGdiGlyphCacheSet(
     FT_Bitmap AlignedBitmap;
     FT_BitmapGlyph BitmapGlyph;
 
+    ASSERT_FREETYPE_LOCK_HELD();
+
     error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
     if (error)
     {
@@ -2441,6 +2725,7 @@ ftGdiGlyphCacheSet(
     {
         DPRINT1("Conversion failed\n");
         ExFreePoolWithTag(NewEntry, TAG_FONT);
+        FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
         FT_Done_Glyph((FT_Glyph)BitmapGlyph);
         return NULL;
     }
@@ -2455,13 +2740,10 @@ ftGdiGlyphCacheSet(
     NewEntry->mxWorldToDevice = *pmx;
 
     InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
-    if (FontCacheNumEntries++ > MAX_FONT_CACHE)
+    if (++FontCacheNumEntries > MAX_FONT_CACHE)
     {
-        NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
-        FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
-        RemoveTailList(&FontCacheListHead);
-        ExFreePoolWithTag(NewEntry, TAG_FONT);
-        FontCacheNumEntries--;
+        NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
+        RemoveCachedEntry(NewEntry);
     }
 
     return BitmapGlyph;
@@ -2868,7 +3150,14 @@ ftGdiGetGlyphOutline(
         TEXTOBJ_UnlockText(TextObj);
         return GDI_ERROR;
     }
-    IntGetOutlineTextMetrics(FontGDI, Size, potm);
+    Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
+    if (!Size)
+    {
+        /* FIXME: last error? */
+        ExFreePoolWithTag(potm, GDITAG_TEXT);
+        TEXTOBJ_UnlockText(TextObj);
+        return GDI_ERROR;
+    }
 
     IntLockFreeType;
     TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
@@ -3711,84 +4000,60 @@ ftGdiGetFontData(
 }
 
 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
-static UINT FASTCALL
-GetFontPenalty(LOGFONTW *               LogFont,
-               PUNICODE_STRING          RequestedNameW,
-               PUNICODE_STRING          ActualNameW,
-               PUNICODE_STRING          FullFaceNameW,
-               BYTE                     RequestedCharSet,
-               PFONTGDI                 FontGDI,
-               OUTLINETEXTMETRICW *     Otm,
-               TEXTMETRICW *            TM,
+static UINT
+GetFontPenalty(const LOGFONTW *               LogFont,
+               const OUTLINETEXTMETRICW *     Otm,
                const char *             style_name)
 {
     ULONG   Penalty = 0;
     BYTE    Byte;
     LONG    Long;
-    BOOL    fFixedSys = FALSE, fNeedScaling = FALSE;
+    BOOL    fNeedScaling = FALSE;
     const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
+    const TEXTMETRICW * TM = &Otm->otmTextMetrics;
+    WCHAR* ActualNameW;
+
+    ASSERT(Otm);
+    ASSERT(LogFont);
+    ASSERT(style_name);
 
     /* FIXME: Aspect Penalty 30 */
     /* FIXME: IntSizeSynth Penalty 20 */
     /* FIXME: SmallPenalty Penalty 1 */
     /* FIXME: FaceNameSubst Penalty 500 */
 
-    if (RtlEqualUnicodeString(RequestedNameW, &SystemW, TRUE))
+    Byte = LogFont->lfCharSet;
+    if (Byte == DEFAULT_CHARSET)
     {
-        /* "System" font */
-        if (TM->tmCharSet != UserCharSet)
+        if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
         {
-            /* CharSet Penalty 65000 */
-            /* Requested charset does not match the candidate's. */
-            Penalty += 65000;
+            if (Byte == ANSI_CHARSET)
+            {
+                DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
+            }
+            /* We assume SYMBOL_CHARSET for "Marlett" font */
+            Byte = SYMBOL_CHARSET;
         }
     }
-    else if (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE))
+
+    if (Byte != TM->tmCharSet)
     {
-        /* "FixedSys" font */
-        if (TM->tmCharSet != UserCharSet)
+        if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
         {
             /* CharSet Penalty 65000 */
             /* Requested charset does not match the candidate's. */
             Penalty += 65000;
         }
-        fFixedSys = TRUE;
-    }
-    else    /* Request is non-"System" font */
-    {
-        Byte = RequestedCharSet;
-        if (Byte == DEFAULT_CHARSET)
-        {
-            if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE))
-            {
-                if (Byte == ANSI_CHARSET)
-                {
-                    DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
-                }
-                /* We assume SYMBOL_CHARSET for "Marlett" font */
-                Byte = SYMBOL_CHARSET;
-            }
-        }
-
-        if (Byte != TM->tmCharSet)
+        else
         {
-            if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
+            if (UserCharSet != TM->tmCharSet)
             {
-                /* CharSet Penalty 65000 */
-                /* Requested charset does not match the candidate's. */
-                Penalty += 65000;
-            }
-            else
-            {
-                if (UserCharSet != TM->tmCharSet)
+                /* UNDOCUMENTED */
+                Penalty += 100;
+                if (ANSI_CHARSET != TM->tmCharSet)
                 {
                     /* UNDOCUMENTED */
                     Penalty += 100;
-                    if (ANSI_CHARSET != TM->tmCharSet)
-                    {
-                        /* UNDOCUMENTED */
-                        Penalty += 100;
-                    }
                 }
             }
         }
@@ -3823,11 +4088,6 @@ GetFontPenalty(LOGFONTW *               LogFont,
     Byte = (LogFont->lfPitchAndFamily & 0x0F);
     if (Byte == DEFAULT_PITCH)
         Byte = VARIABLE_PITCH;
-    if (fFixedSys)
-    {
-        /* "FixedSys" font should be fixed-pitch */
-        Byte = FIXED_PITCH;
-    }
     if (Byte == FIXED_PITCH)
     {
         if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
@@ -3860,34 +4120,29 @@ GetFontPenalty(LOGFONTW *               LogFont,
         }
     }
 
-    if (RequestedNameW->Buffer[0])
+    ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
+
+    if (LogFont->lfFaceName[0])
     {
-        if (RtlEqualUnicodeString(RequestedNameW, FullFaceNameW, TRUE))
+        BOOL Found = FALSE;
+
+        /* localized family name */
+        if (!Found)
         {
-            /* matched with full face name */
+            Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
         }
-        else if (RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE))
+        /* localized full name */
+        if (!Found)
         {
-            /* matched with actual name */
+            ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
+            Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
         }
-        else
+        if (!Found)
         {
-            /* try the localized name */
-            UNICODE_STRING LocalNameW;
-            FT_Face Face = FontGDI->SharedFace->Face;
-            IntGetFontLocalizedName(&LocalNameW, Face);
-            if (RtlEqualUnicodeString(RequestedNameW, &LocalNameW, TRUE))
-            {
-                /* matched with localizied name */
-            }
-            else
-            {
-                /* FaceName Penalty 10000 */
-                /* Requested a face name, but the candidate's face name
-                   does not match. */
-                Penalty += 10000;
-            }
-            RtlFreeUnicodeString(&LocalNameW);
+            /* FaceName Penalty 10000 */
+            /* Requested a face name, but the candidate's face name
+               does not match. */
+            Penalty += 10000;
         }
     }
 
@@ -4079,7 +4334,7 @@ GetFontPenalty(LOGFONTW *               LogFont,
         DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
             "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
             "tmCharSet:%d, tmWeight:%ld\n",
-            Penalty, RequestedNameW->Buffer, ActualNameW->Buffer,
+            Penalty, LogFont->lfFaceName, ActualNameW,
             LogFont->lfCharSet, LogFont->lfWeight,
             TM->tmCharSet, TM->tmWeight);
     }
@@ -4088,49 +4343,38 @@ GetFontPenalty(LOGFONTW *               LogFont,
 }
 
 static __inline VOID
-FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
-                     PUNICODE_STRING pRequestedNameW,
-                     PUNICODE_STRING pActualNameW, BYTE RequestedCharSet,
-                     PLIST_ENTRY Head)
+FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
+                     const LOGFONTW *LogFont,
+                     const PLIST_ENTRY Head)
 {
     ULONG Penalty;
-    NTSTATUS Status;
     PLIST_ENTRY Entry;
     PFONT_ENTRY CurrentEntry;
     FONTGDI *FontGDI;
-    ANSI_STRING ActualNameA;
-    UNICODE_STRING ActualNameW, FullFaceNameW;
     OUTLINETEXTMETRICW *Otm = NULL;
     UINT OtmSize, OldOtmSize = 0;
-    TEXTMETRICW *TM;
     FT_Face Face;
-    LPBYTE pb;
 
     ASSERT(FontObj);
     ASSERT(MatchPenalty);
     ASSERT(LogFont);
-    ASSERT(pRequestedNameW);
     ASSERT(Head);
 
+    /* Start with a pretty big buffer */
+    OldOtmSize = 0x200;
+    Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
+
     /* get the FontObj of lowest penalty */
     Entry = Head->Flink;
     while (Entry != Head)
     {
-        CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+        CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+        Entry = Entry->Flink;
+
         FontGDI = CurrentEntry->Font;
         ASSERT(FontGDI);
         Face = FontGDI->SharedFace->Face;
 
-        /* create actual name */
-        RtlInitAnsiString(&ActualNameA, Face->family_name);
-        Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE);
-        if (!NT_SUCCESS(Status))
-        {
-            /* next entry */
-            Entry = Entry->Flink;
-            continue;
-        }
-
         /* get text metrics */
         OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
         if (OtmSize > OldOtmSize)
@@ -4143,43 +4387,19 @@ FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
         /* update FontObj if lowest penalty */
         if (Otm)
         {
-            IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
-            TM = &Otm->otmTextMetrics;
-            OldOtmSize = OtmSize;
-
-            /* create full name */
-            pb = (LPBYTE)Otm + (WORD)(DWORD_PTR)Otm->otmpFullName;
-            Status = RtlCreateUnicodeString(&FullFaceNameW, (LPWSTR)pb);
-            if (!NT_SUCCESS(Status))
-            {
-                RtlFreeUnicodeString(&ActualNameW);
-                RtlFreeUnicodeString(&FullFaceNameW);
-                /* next entry */
-                Entry = Entry->Flink;
+            OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
+            if (!OtmSize)
                 continue;
-            }
 
-            Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW,
-                                     &FullFaceNameW, RequestedCharSet,
-                                     FontGDI, Otm, TM, Face->style_name);
+            OldOtmSize = OtmSize;
+
+            Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
             if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
             {
-                DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty);
-                RtlFreeUnicodeString(pActualNameW);
-                RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer);
-
                 *FontObj = GDIToObj(FontGDI, FONT);
                 *MatchPenalty = Penalty;
             }
-
-            RtlFreeUnicodeString(&FullFaceNameW);
         }
-
-        /* free strings */
-        RtlFreeUnicodeString(&ActualNameW);
-
-        /* next entry */
-        Entry = Entry->Flink;
     }
 
     if (Otm)
@@ -4224,12 +4444,11 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 {
     NTSTATUS Status = STATUS_SUCCESS;
     PTEXTOBJ TextObj;
-    UNICODE_STRING ActualNameW, RequestedNameW;
     PPROCESSINFO Win32Process;
     ULONG MatchPenalty;
     LOGFONTW *pLogFont;
+    LOGFONTW SubstitutedLogFont;
     FT_Face Face;
-    BYTE RequestedCharSet;
 
     if (!pTextObj)
     {
@@ -4250,21 +4469,13 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
         TextObj = pTextObj;
     }
 
-    RtlInitUnicodeString(&ActualNameW, NULL);
-
     pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
-    if (!RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName))
-    {
-        if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
-        return STATUS_NO_MEMORY;
-    }
 
     /* substitute */
-    RequestedCharSet = pLogFont->lfCharSet;
-    DPRINT("Font '%ls,%u' is substituted by: ",
-           RequestedNameW.Buffer, RequestedCharSet);
-    SubstituteFontRecurse(&RequestedNameW, &RequestedCharSet);
-    DPRINT("'%ls,%u'.\n", RequestedNameW.Buffer, RequestedCharSet);
+    SubstitutedLogFont = *pLogFont;
+    DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
+    SubstituteFontRecurse(&SubstitutedLogFont);
+    DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
 
     MatchPenalty = 0xFFFFFFFF;
     TextObj->Font = NULL;
@@ -4273,15 +4484,13 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 
     /* Search private fonts */
     IntLockProcessPrivateFonts(Win32Process);
-    FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
-                         &RequestedNameW, &ActualNameW, RequestedCharSet,
+    FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
                          &Win32Process->PrivateFontListHead);
     IntUnLockProcessPrivateFonts(Win32Process);
 
     /* Search system fonts */
     IntLockGlobalFonts;
-    FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
-                         &RequestedNameW, &ActualNameW, RequestedCharSet,
+    FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
                          &FontListHead);
     IntUnLockGlobalFonts;
 
@@ -4316,14 +4525,8 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 
         TextObj->fl |= TEXTOBJECT_INIT;
         Status = STATUS_SUCCESS;
-
-        DPRINT("RequestedNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n",
-            RequestedNameW.Buffer, pLogFont->lfCharSet,
-            ActualNameW.Buffer, FontGdi->CharSet);
     }
 
-    RtlFreeUnicodeString(&RequestedNameW);
-    RtlFreeUnicodeString(&ActualNameW);
     if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
 
     ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
@@ -4378,28 +4581,23 @@ IntGetFullFileName(
 }
 
 static BOOL
-EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2)
+EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
 {
-    UNICODE_STRING Str1, Str2;
-    ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
-    ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
-    RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName);
-    RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName);
-    if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
+    const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
+    const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
+    const LOGFONTW *plf1 = &pLog1->elfLogFont;
+    const LOGFONTW *plf2 = &pLog2->elfLogFont;
+
+    if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
     {
         return FALSE;
     }
-    if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL))
-        return FALSE;
-    if (pLog1->elfStyle != NULL)
+
+    if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
     {
-        RtlInitUnicodeString(&Str1, pLog1->elfStyle);
-        RtlInitUnicodeString(&Str2, pLog2->elfStyle);
-        if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
-        {
-            return FALSE;
-        }
+        return FALSE;
     }
+
     return TRUE;
 }
 
@@ -4490,7 +4688,7 @@ IntGdiGetFontResourceInfo(
 
         IsEqual = FALSE;
         FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
-                           FontEntry->Font);
+                           NULL, FontEntry->Font);
         for (i = 0; i < Count; ++i)
         {
             if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
@@ -4913,12 +5111,6 @@ GreExtTextOutW(
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
-    if (dc->dctype == DC_TYPE_INFO)
-    {
-        DC_UnlockDc(dc);
-        /* Yes, Windows really returns TRUE in this case */
-        return TRUE;
-    }
 
     pdcattr = dc->pdcattr;
 
@@ -4950,6 +5142,13 @@ GreExtTextOutW(
         goto good;
     }
 
+    if (!dc->dclevel.pSurface)
+    {
+        /* Memory DC with no surface selected */
+        DC_UnlockDc(dc);
+        return TRUE;
+    }
+
     if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
     {
         IntLPtoDP(dc, (POINT *)lprc, 2);
@@ -4975,11 +5174,6 @@ GreExtTextOutW(
     BrushOrigin.x = 0;
     BrushOrigin.y = 0;
 
-    if (!dc->dclevel.pSurface)
-    {
-        goto fail;
-    }
-
     if ((fuOptions & ETO_OPAQUE) && lprc)
     {
         DestRect.left   = lprc->left;
@@ -5007,7 +5201,7 @@ GreExtTextOutW(
             &psurf->SurfObj,
             NULL,
             NULL,
-            &dc->co.ClipObj,
+            (CLIPOBJ *)&dc->co,
             NULL,
             &DestRect,
             &SourcePoint,
@@ -5277,7 +5471,7 @@ GreExtTextOutW(
                 &psurf->SurfObj,
                 NULL,
                 NULL,
-                &dc->co.ClipObj,
+                (CLIPOBJ *)&dc->co,
                 NULL,
                 &DestRect,
                 &SourcePoint,
@@ -5413,7 +5607,7 @@ GreExtTextOutW(
                 &psurf->SurfObj,
                 NULL,
                 NULL,
-                &dc->co.ClipObj,
+                (CLIPOBJ *)&dc->co,
                 NULL,
                 &DestRect,
                 &SourcePoint,
@@ -5486,7 +5680,7 @@ GreExtTextOutW(
             if (!IntEngMaskBlt(
                 SurfObj,
                 SourceGlyphSurf,
-                &dc->co.ClipObj,
+                (CLIPOBJ *)&dc->co,
                 &exloRGB2Dst.xlo,
                 &exloDst2RGB.xlo,
                 &DestRect,
@@ -5523,7 +5717,7 @@ GreExtTextOutW(
             for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
             {
                 EngLineTo(SurfObj,
-                          &dc->co.ClipObj,
+                          (CLIPOBJ *)&dc->co,
                           &dc->eboText.BrushObject,
                           (TextLeft >> 6),
                           TextTop + yoff - position + i,
@@ -5539,7 +5733,7 @@ GreExtTextOutW(
             for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
             {
                 EngLineTo(SurfObj,
-                          &dc->co.ClipObj,
+                          (CLIPOBJ *)&dc->co,
                           &dc->eboText.BrushObject,
                           (TextLeft >> 6),
                           TextTop + yoff - (fixAscender >> 6) / 3 + i,
@@ -6213,8 +6407,9 @@ NtGdiGetGlyphIndicesW(
                 cwc = GDI_ERROR;
                 goto ErrorRet;
             }
-            IntGetOutlineTextMetrics(FontGDI, Size, potm);
-            DefChar = potm->otmTextMetrics.tmDefaultChar;
+            Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
+            if (Size)
+                DefChar = potm->otmTextMetrics.tmDefaultChar;
             ExFreePoolWithTag(potm, GDITAG_TEXT);
         }
     }