[WIN32SS][FONT] Fix GetTextFace function and related (#829)
[reactos.git] / win32ss / gdi / ntgdi / freetype.c
index 5ac3b60..e172c5c 100644 (file)
@@ -1,10 +1,11 @@
 /*
  * PROJECT:         ReactOS win32 kernel mode subsystem
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            subsystems/win32/win32k/objects/freetype.c
+ * FILE:            win32ss/gdi/ntgdi/freetype.c
  * PURPOSE:         FreeType font engine interface
- * PROGRAMMER     Copyright 2001 Huw D M Davies for CodeWeavers.
+ * PROGRAMMERS:     Copyright 2001 Huw D M Davies for CodeWeavers.
  *                  Copyright 2006 Dmitry Timoshkov for CodeWeavers.
+ *                  Copyright 2016-2018 Katayama Hirofumi MZ.
  */
 
 /** Includes ******************************************************************/
 
 #include FT_GLYPH_H
 #include FT_TYPE1_TABLES_H
-#include <tttables.h>
-#include <fttrigon.h>
-#include <ftbitmap.h>
-#include <ftoutln.h>
-#include <ftwinfnt.h>
+#include FT_TRUETYPE_TABLES_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_TRIGONOMETRY_H
+#include FT_BITMAP_H
+#include FT_OUTLINE_H
+#include FT_WINFONTS_H
+#include FT_SFNT_NAMES_H
+#include FT_SYNTHESIS_H
+#include FT_TRUETYPE_IDS_H
+
+#ifndef FT_INTERNAL_INTERNAL_H
+    #define  FT_INTERNAL_INTERNAL_H  <freetype/internal/internal.h>
+    #include FT_INTERNAL_INTERNAL_H
+#endif
+#include FT_INTERNAL_TRUETYPE_TYPES_H
 
 #include <gdi/eng/floatobj.h>
+#include "font.h"
 
 #define NDEBUG
 #include <debug.h>
 
-#ifndef FT_MAKE_TAG
-#define FT_MAKE_TAG( ch0, ch1, ch2, ch3 ) \
-       ( ((DWORD)(BYTE)(ch0) << 24) | ((DWORD)(BYTE)(ch1) << 16) | \
-       ((DWORD)(BYTE)(ch2) << 8) | (DWORD)(BYTE)(ch3) )
+/* TPMF_FIXED_PITCH is confusing; brain-dead api */
+#ifndef _TMPF_VARIABLE_PITCH
+    #define _TMPF_VARIABLE_PITCH    TMPF_FIXED_PITCH
 #endif
 
-FT_Library  library;
+extern const MATRIX gmxWorldToDeviceDefault;
+extern const MATRIX gmxWorldToPageDefault;
+
+/* HACK!! Fix XFORMOBJ then use 1:16 / 16:1 */
+#define gmxWorldToDeviceDefault gmxWorldToPageDefault
+
+FT_Library  g_FreeTypeLibrary;
+
+/* special font names */
+static const UNICODE_STRING g_MarlettW = RTL_CONSTANT_STRING(L"Marlett");
+
+/* registry */
+static UNICODE_STRING g_FontRegPath =
+    RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
 
-typedef struct _FONT_ENTRY
-{
-    LIST_ENTRY ListEntry;
-    FONTGDI *Font;
-    UNICODE_STRING FaceName;
-    BYTE NotEnum;
-} FONT_ENTRY, *PFONT_ENTRY;
 
 /* The FreeType library is not thread safe, so we have
    to serialize access to it */
-static PFAST_MUTEX FreeTypeLock;
+static PFAST_MUTEX      g_FreeTypeLock;
+
+static LIST_ENTRY       g_FontListHead;
+static PFAST_MUTEX      g_FontListLock;
+static BOOL             g_RenderingEnabled = TRUE;
+
+#define IntLockGlobalFonts() \
+    ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FontListLock)
 
-static LIST_ENTRY FontListHead;
-static PFAST_MUTEX FontListLock;
-static BOOL RenderingEnabled = TRUE;
+#define IntUnLockGlobalFonts() \
+    ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FontListLock)
 
-#define IntLockGlobalFonts \
-  ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FontListLock)
+#define ASSERT_GLOBALFONTS_LOCK_HELD() \
+    ASSERT(g_FontListLock->Owner == KeGetCurrentThread())
 
-#define IntUnLockGlobalFonts \
-  ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
+#define IntLockFreeType() \
+    ExEnterCriticalRegionAndAcquireFastMutexUnsafe(g_FreeTypeLock)
 
-#define IntLockFreeType \
-  ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
+#define IntUnLockFreeType() \
+    ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(g_FreeTypeLock)
 
-#define IntUnLockFreeType \
-  ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
+#define ASSERT_FREETYPE_LOCK_HELD() \
+    ASSERT(g_FreeTypeLock->Owner == KeGetCurrentThread())
+
+#define ASSERT_FREETYPE_LOCK_NOT_HELD() \
+    ASSERT(g_FreeTypeLock->Owner != KeGetCurrentThread())
 
 #define MAX_FONT_CACHE 256
 
-typedef struct _FONT_CACHE_ENTRY
-{
-    LIST_ENTRY ListEntry;
-    int GlyphIndex;
-    FT_Face Face;
-    FT_BitmapGlyph BitmapGlyph;
-    int Height;
-    MATRIX mxWorldToDevice;
-} FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
-static LIST_ENTRY FontCacheListHead;
-static UINT FontCacheNumEntries;
+static LIST_ENTRY g_FontCacheListHead;
+static UINT g_FontCacheNumEntries;
 
-static PWCHAR ElfScripts[32] =   /* These are in the order of the fsCsb[0] bits */
+static PWCHAR g_ElfScripts[32] =   /* These are in the order of the fsCsb[0] bits */
 {
     L"Western", /* 00 */
     L"Central_European",
@@ -102,7 +119,7 @@ static PWCHAR ElfScripts[32] =   /* These are in the order of the fsCsb[0] bits
  */
 #define CP_SYMBOL   42
 #define MAXTCIINDEX 32
-static const CHARSETINFO FontTci[MAXTCIINDEX] =
+static const CHARSETINFO g_FontTci[MAXTCIINDEX] =
 {
     /* ANSI */
     { ANSI_CHARSET, 1252, {{0,0,0,0},{FS_LATIN1,0}} },
@@ -143,21 +160,359 @@ static const CHARSETINFO FontTci[MAXTCIINDEX] =
     { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} }
 };
 
+#ifndef CP_OEMCP
+    #define CP_OEMCP  1
+    #define CP_MACCP  2
+#endif
+
+/* Get charset from specified codepage.
+   g_FontTci is used also in TranslateCharsetInfo. */
+BYTE FASTCALL IntCharSetFromCodePage(UINT uCodePage)
+{
+    UINT i;
+
+    if (uCodePage == CP_OEMCP)
+        return OEM_CHARSET;
+
+    if (uCodePage == CP_MACCP)
+        return MAC_CHARSET;
+
+    for (i = 0; i < MAXTCIINDEX; ++i)
+    {
+        if (g_FontTci[i].ciACP == 0)
+            continue;
+
+        if (g_FontTci[i].ciACP == uCodePage)
+            return g_FontTci[i].ciCharset;
+    }
+
+    return DEFAULT_CHARSET;
+}
+
+/* list head */
+static RTL_STATIC_LIST_HEAD(g_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 ? Face->family_name : "<NULL>");
+    }
+    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);
+    g_FontCacheNumEntries--;
+    ASSERT(g_FontCacheNumEntries <= MAX_FONT_CACHE);
+}
+
+static void
+RemoveCacheEntries(FT_Face Face)
+{
+    PLIST_ENTRY CurrentEntry, NextEntry;
+    PFONT_CACHE_ENTRY FontEntry;
+
+    ASSERT_FREETYPE_LOCK_HELD();
+
+    for (CurrentEntry = g_FontCacheListHead.Flink;
+         CurrentEntry != &g_FontCacheListHead;
+         CurrentEntry = NextEntry)
+    {
+        FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
+        NextEntry = 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 ? Ptr->Face->family_name : "<NULL>");
+        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
+ */
+BOOL FASTCALL
+IntLoadFontSubstList(PLIST_ENTRY pHead)
+{
+    NTSTATUS                        Status;
+    HANDLE                          KeyHandle;
+    OBJECT_ATTRIBUTES               ObjectAttributes;
+    KEY_FULL_INFORMATION            KeyFullInfo;
+    ULONG                           i, Length;
+    UNICODE_STRING                  FromW, ToW;
+    BYTE                            InfoBuffer[128];
+    PKEY_VALUE_FULL_INFORMATION     pInfo;
+    BYTE                            CharSets[FONTSUBST_FROM_AND_TO];
+    LPWSTR                          pch;
+    PFONTSUBST_ENTRY                pEntry;
+    BOOLEAN                         Success;
+
+    /* the FontSubstitutes registry key */
+    static UNICODE_STRING FontSubstKey =
+        RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\"
+                            L"Microsoft\\Windows NT\\CurrentVersion\\"
+                            L"FontSubstitutes");
+
+    /* open registry key */
+    InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               NULL, NULL);
+    Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
+        return FALSE;   /* failure */
+    }
+
+    /* query count of values */
+    Status = ZwQueryKey(KeyHandle, KeyFullInformation,
+                        &KeyFullInfo, sizeof(KeyFullInfo), &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
+        ZwClose(KeyHandle);
+        return FALSE;   /* failure */
+    }
+
+    /* for each value */
+    for (i = 0; i < KeyFullInfo.Values; ++i)
+    {
+        /* get value name */
+        Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
+                                     InfoBuffer, sizeof(InfoBuffer), &Length);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
+            break;      /* failure */
+        }
+
+        /* create FromW string */
+        pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
+        Length = pInfo->NameLength / sizeof(WCHAR);
+        pInfo->Name[Length] = UNICODE_NULL;   /* truncate */
+        Success = RtlCreateUnicodeString(&FromW, pInfo->Name);
+        if (!Success)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            DPRINT("RtlCreateUnicodeString failed\n");
+            break;      /* failure */
+        }
+
+        /* query value */
+        Status = ZwQueryValueKey(KeyHandle, &FromW, KeyValueFullInformation, 
+                                 InfoBuffer, sizeof(InfoBuffer), &Length);
+        pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
+        if (!NT_SUCCESS(Status) || !pInfo->DataLength)
+        {
+            DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
+            RtlFreeUnicodeString(&FromW);
+            break;      /* failure */
+        }
+
+        /* create ToW string */
+        pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
+        Length = pInfo->DataLength / sizeof(WCHAR);
+        pch[Length] = UNICODE_NULL; /* truncate */
+        Success = RtlCreateUnicodeString(&ToW, pch);
+        if (!Success)
+        {
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+            DPRINT("RtlCreateUnicodeString failed\n");
+            RtlFreeUnicodeString(&FromW);
+            break;      /* failure */
+        }
+
+        /* does charset exist? (from) */
+        CharSets[FONTSUBST_FROM] = DEFAULT_CHARSET;
+        pch = wcsrchr(FromW.Buffer, L',');
+        if (pch)
+        {
+            /* truncate */
+            *pch = UNICODE_NULL;
+            FromW.Length = (pch - FromW.Buffer) * sizeof(WCHAR);
+            /* parse charset number */
+            CharSets[FONTSUBST_FROM] = (BYTE)_wtoi(pch + 1);
+        }
+
+        /* does charset exist? (to) */
+        CharSets[FONTSUBST_TO] = DEFAULT_CHARSET;
+        pch = wcsrchr(ToW.Buffer, L',');
+        if (pch)
+        {
+            /* truncate */
+            *pch = UNICODE_NULL;
+            ToW.Length = (pch - ToW.Buffer) * sizeof(WCHAR);
+            /* parse charset number */
+            CharSets[FONTSUBST_TO] = (BYTE)_wtoi(pch + 1);
+        }
+
+        /* is it identical? */
+        if (RtlEqualUnicodeString(&FromW, &ToW, TRUE) &&
+            CharSets[FONTSUBST_FROM] == CharSets[FONTSUBST_TO])
+        {
+            RtlFreeUnicodeString(&FromW);
+            RtlFreeUnicodeString(&ToW);
+            continue;
+        }
+
+        /* allocate an entry */
+        pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTSUBST_ENTRY), TAG_FONT);
+        if (pEntry == NULL)
+        {
+            DPRINT("ExAllocatePoolWithTag failed\n");
+            RtlFreeUnicodeString(&FromW);
+            RtlFreeUnicodeString(&ToW);
+            break;      /* failure */
+        }
+
+        /* store to *pEntry */
+        pEntry->FontNames[FONTSUBST_FROM] = FromW;
+        pEntry->FontNames[FONTSUBST_TO] = ToW;
+        pEntry->CharSets[FONTSUBST_FROM] = CharSets[FONTSUBST_FROM];
+        pEntry->CharSets[FONTSUBST_TO] = CharSets[FONTSUBST_TO];
+
+        /* insert pEntry to *pHead */
+        InsertTailList(pHead, &pEntry->ListEntry);
+    }
+
+    /* close now */
+    ZwClose(KeyHandle);
+
+    return NT_SUCCESS(Status);
+}
+
 BOOL FASTCALL
 InitFontSupport(VOID)
 {
     ULONG ulError;
 
-    InitializeListHead(&FontListHead);
-    InitializeListHead(&FontCacheListHead);
-    FontCacheNumEntries = 0;
+    InitializeListHead(&g_FontListHead);
+    InitializeListHead(&g_FontCacheListHead);
+    g_FontCacheNumEntries = 0;
     /* Fast Mutexes must be allocated from non paged pool */
-    FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
-    ExInitializeFastMutex(FontListLock);
-    FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
-    ExInitializeFastMutex(FreeTypeLock);
+    g_FontListLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
+    if (g_FontListLock == NULL)
+    {
+        return FALSE;
+    }
+
+    ExInitializeFastMutex(g_FontListLock);
+    g_FreeTypeLock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), TAG_INTERNAL_SYNC);
+    if (g_FreeTypeLock == NULL)
+    {
+        return FALSE;
+    }
+    ExInitializeFastMutex(g_FreeTypeLock);
 
-    ulError = FT_Init_FreeType(&library);
+    ulError = FT_Init_FreeType(&g_FreeTypeLibrary);
     if (ulError)
     {
         DPRINT1("FT_Init_FreeType failed with error code 0x%x\n", ulError);
@@ -165,6 +520,7 @@ InitFontSupport(VOID)
     }
 
     IntLoadSystemFonts();
+    IntLoadFontSubstList(&g_FontSubstListHead);
 
     return TRUE;
 }
@@ -198,32 +554,135 @@ FtSetCoordinateTransform(
     FT_Set_Transform(face, &ftmatrix, 0);
 }
 
+static BOOL
+SubstituteFontByList(PLIST_ENTRY        pHead,
+                     PUNICODE_STRING    pOutputName,
+                     PUNICODE_STRING    pInputName,
+                     BYTE               RequestedCharSet,
+                     BYTE               CharSetMap[FONTSUBST_FROM_AND_TO])
+{
+    PLIST_ENTRY         pListEntry;
+    PFONTSUBST_ENTRY    pSubstEntry;
+    BYTE                CharSets[FONTSUBST_FROM_AND_TO];
+
+    CharSetMap[FONTSUBST_FROM] = DEFAULT_CHARSET;
+    CharSetMap[FONTSUBST_TO] = RequestedCharSet;
+
+    /* for each list entry */
+    for (pListEntry = pHead->Flink;
+         pListEntry != pHead;
+         pListEntry = pListEntry->Flink)
+    {
+        pSubstEntry =
+            (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_ENTRY, ListEntry);
+
+        CharSets[FONTSUBST_FROM] = pSubstEntry->CharSets[FONTSUBST_FROM];
+
+        if (CharSets[FONTSUBST_FROM] != DEFAULT_CHARSET &&
+            CharSets[FONTSUBST_FROM] != RequestedCharSet)
+        {
+            continue;   /* not matched */
+        }
+
+        /* does charset number exist? (to) */
+        if (pSubstEntry->CharSets[FONTSUBST_TO] != DEFAULT_CHARSET)
+        {
+            CharSets[FONTSUBST_TO] = pSubstEntry->CharSets[FONTSUBST_TO];
+        }
+        else
+        {
+            CharSets[FONTSUBST_TO] = RequestedCharSet;
+        }
+
+        /* does font name match? */
+        if (!RtlEqualUnicodeString(&pSubstEntry->FontNames[FONTSUBST_FROM],
+                                   pInputName, TRUE))
+        {
+            continue;   /* not matched */
+        }
+
+        /* update *pOutputName */
+        *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
+
+        if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
+        {
+            /* update CharSetMap */
+            CharSetMap[FONTSUBST_FROM]  = CharSets[FONTSUBST_FROM];
+            CharSetMap[FONTSUBST_TO]    = CharSets[FONTSUBST_TO];
+        }
+        return TRUE;   /* success */
+    }
+
+    return FALSE;
+}
+
+static BOOL
+SubstituteFontRecurse(LOGFONTW* pLogFont)
+{
+    UINT            RecurseCount = 5;
+    UNICODE_STRING  OutputNameW = { 0 };
+    BYTE            CharSetMap[FONTSUBST_FROM_AND_TO];
+    BOOL            Found;
+    UNICODE_STRING  InputNameW;
+
+    if (pLogFont->lfFaceName[0] == UNICODE_NULL)
+        return FALSE;
+
+    RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
+
+    while (RecurseCount-- > 0)
+    {
+        Found = SubstituteFontByList(&g_FontSubstListHead,
+                                     &OutputNameW, &InputNameW,
+                                     pLogFont->lfCharSet, CharSetMap);
+        if (!Found)
+            break;
+
+        RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
+
+        if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
+            CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
+        {
+            pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
+        }
+    }
+
+    return TRUE;    /* success */
+}
+
 /*
  * IntLoadSystemFonts
  *
  * Search the system font directory and adds each font found.
  */
-
 VOID FASTCALL
 IntLoadSystemFonts(VOID)
 {
     OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING Directory, SearchPattern, FileName, TempString;
+    UNICODE_STRING Directory, FileName, TempString;
     IO_STATUS_BLOCK Iosb;
     HANDLE hDirectory;
     BYTE *DirInfoBuffer;
     PFILE_DIRECTORY_INFORMATION DirInfo;
     BOOLEAN bRestartScan = TRUE;
     NTSTATUS Status;
+    INT i;
+    static UNICODE_STRING SearchPatterns[] =
+    {
+        RTL_CONSTANT_STRING(L"*.ttf"),
+        RTL_CONSTANT_STRING(L"*.ttc"),
+        RTL_CONSTANT_STRING(L"*.otf"),
+        RTL_CONSTANT_STRING(L"*.otc"),
+        RTL_CONSTANT_STRING(L"*.fon"),
+        RTL_CONSTANT_STRING(L"*.fnt")
+    };
 
     RtlInitUnicodeString(&Directory, L"\\SystemRoot\\Fonts\\");
-    /* FIXME: Add support for other font types */
-    RtlInitUnicodeString(&SearchPattern, L"*.ttf");
 
     InitializeObjectAttributes(
         &ObjectAttributes,
         &Directory,
-        OBJ_CASE_INSENSITIVE,
+        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
         NULL,
         NULL);
 
@@ -237,190 +696,358 @@ IntLoadSystemFonts(VOID)
 
     if (NT_SUCCESS(Status))
     {
-        DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
-        if (DirInfoBuffer == NULL)
+        for (i = 0; i < _countof(SearchPatterns); ++i)
         {
-            ZwClose(hDirectory);
-            return;
-        }
+            DirInfoBuffer = ExAllocatePoolWithTag(PagedPool, 0x4000, TAG_FONT);
+            if (DirInfoBuffer == NULL)
+            {
+                ZwClose(hDirectory);
+                return;
+            }
 
-        FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
-        if (FileName.Buffer == NULL)
-        {
-            ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
-            ZwClose(hDirectory);
-            return;
-        }
-        FileName.Length = 0;
-        FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
-
-        while (1)
-        {
-            Status = ZwQueryDirectoryFile(
-                         hDirectory,
-                         NULL,
-                         NULL,
-                         NULL,
-                         &Iosb,
-                         DirInfoBuffer,
-                         0x4000,
-                         FileDirectoryInformation,
-                         FALSE,
-                         &SearchPattern,
-                         bRestartScan);
-
-            if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
+            FileName.Buffer = ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), TAG_FONT);
+            if (FileName.Buffer == NULL)
             {
-                break;
+                ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
+                ZwClose(hDirectory);
+                return;
             }
+            FileName.Length = 0;
+            FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
 
-            DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
             while (1)
             {
-                TempString.Buffer = DirInfo->FileName;
-                TempString.Length =
-                    TempString.MaximumLength = DirInfo->FileNameLength;
-                RtlCopyUnicodeString(&FileName, &Directory);
-                RtlAppendUnicodeStringToString(&FileName, &TempString);
-                IntGdiAddFontResource(&FileName, 0);
-                if (DirInfo->NextEntryOffset == 0)
+                Status = ZwQueryDirectoryFile(
+                             hDirectory,
+                             NULL,
+                             NULL,
+                             NULL,
+                             &Iosb,
+                             DirInfoBuffer,
+                             0x4000,
+                             FileDirectoryInformation,
+                             FALSE,
+                             &SearchPatterns[i],
+                             bRestartScan);
+
+                if (!NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES)
+                {
                     break;
-                DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
+                }
+
+                DirInfo = (PFILE_DIRECTORY_INFORMATION)DirInfoBuffer;
+                while (1)
+                {
+                    TempString.Buffer = DirInfo->FileName;
+                    TempString.Length =
+                        TempString.MaximumLength = DirInfo->FileNameLength;
+                    RtlCopyUnicodeString(&FileName, &Directory);
+                    RtlAppendUnicodeStringToString(&FileName, &TempString);
+                    IntGdiAddFontResource(&FileName, 0);
+                    if (DirInfo->NextEntryOffset == 0)
+                        break;
+                    DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo + DirInfo->NextEntryOffset);
+                }
+
+                bRestartScan = FALSE;
             }
 
-            bRestartScan = FALSE;
+            ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
+            ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
         }
-
-        ExFreePoolWithTag(FileName.Buffer, TAG_FONT);
-        ExFreePoolWithTag(DirInfoBuffer, TAG_FONT);
         ZwClose(hDirectory);
     }
 }
 
+static BYTE
+ItalicFromStyle(const char *style_name)
+{
+    if (style_name == NULL || style_name[0] == 0)
+        return FALSE;
+    if (strstr(style_name, "Italic") != NULL)
+        return TRUE;
+    if (strstr(style_name, "Oblique") != NULL)
+        return TRUE;
+    return FALSE;
+}
 
-/*
- * IntGdiAddFontResource
- *
- * Adds the font resource from the specified file to the system.
- */
-
-INT FASTCALL
-IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
+static LONG
+WeightFromStyle(const char *style_name)
 {
-    FONTGDI *FontGDI;
-    NTSTATUS Status;
-    HANDLE FileHandle, KeyHandle;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    PVOID Buffer = NULL;
-    IO_STATUS_BLOCK Iosb;
-    INT Error;
-    FT_Face Face;
-    ANSI_STRING AnsiFaceName;
-    PFONT_ENTRY Entry;
-    PVOID SectionObject;
-    ULONG ViewSize = 0;
-    LARGE_INTEGER SectionSize;
-    UNICODE_STRING FontRegPath = RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
+    if (style_name == NULL || style_name[0] == 0)
+        return FW_NORMAL;
+    if (strstr(style_name, "Regular") != NULL)
+        return FW_REGULAR;
+    if (strstr(style_name, "Normal") != NULL)
+        return FW_NORMAL;
+    if (strstr(style_name, "SemiBold") != NULL)
+        return FW_SEMIBOLD;
+    if (strstr(style_name, "UltraBold") != NULL)
+        return FW_ULTRABOLD;
+    if (strstr(style_name, "DemiBold") != NULL)
+        return FW_DEMIBOLD;
+    if (strstr(style_name, "ExtraBold") != NULL)
+        return FW_EXTRABOLD;
+    if (strstr(style_name, "Bold") != NULL)
+        return FW_BOLD;
+    if (strstr(style_name, "UltraLight") != NULL)
+        return FW_ULTRALIGHT;
+    if (strstr(style_name, "ExtraLight") != NULL)
+        return FW_EXTRALIGHT;
+    if (strstr(style_name, "Light") != NULL)
+        return FW_LIGHT;
+    if (strstr(style_name, "Hairline") != NULL)
+        return 50;
+    if (strstr(style_name, "Book") != NULL)
+        return 350;
+    if (strstr(style_name, "ExtraBlack") != NULL)
+        return 950;
+    if (strstr(style_name, "UltraBlack") != NULL)
+        return 1000;
+    if (strstr(style_name, "Black") != NULL)
+        return FW_BLACK;
+    if (strstr(style_name, "Medium") != NULL)
+        return FW_MEDIUM;
+    if (strstr(style_name, "Thin") != NULL)
+        return FW_THIN;
+    if (strstr(style_name, "Heavy") != NULL)
+        return FW_HEAVY;
+    return FW_NORMAL;
+}
 
-    /* Open the font file */
+static FT_Error
+IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight);
 
-    InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
-    Status = ZwOpenFile(
-                 &FileHandle,
-                 FILE_GENERIC_READ | SYNCHRONIZE,
-                 &ObjectAttributes,
-                 &Iosb,
-                 FILE_SHARE_READ,
-                 FILE_SYNCHRONOUS_IO_NONALERT);
+static INT FASTCALL
+IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
+                          PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex)
+{
+    FT_Error            Error;
+    PFONT_ENTRY         Entry;
+    FONT_ENTRY_MEM*     PrivateEntry = NULL;
+    FONTGDI *           FontGDI;
+    NTSTATUS            Status;
+    FT_Face             Face;
+    ANSI_STRING         AnsiFaceName;
+    FT_WinFNT_HeaderRec WinFNT;
+    INT                 FaceCount = 0, CharSetCount = 0;
+    PUNICODE_STRING     pFileName       = pLoadFont->pFileName;
+    DWORD               Characteristics = pLoadFont->Characteristics;
+    PUNICODE_STRING     pValueName = &pLoadFont->RegValueName;
+    TT_OS2 *            pOS2;
+    INT                 BitIndex;
+    FT_UShort           os2_version;
+    FT_ULong            os2_ulCodePageRange1;
+    FT_UShort           os2_usWeightClass;
+
+    if (SharedFace == NULL && CharSetIndex == -1)
+    {
+        /* load a face from memory */
+        IntLockFreeType();
+        Error = FT_New_Memory_Face(
+                    g_FreeTypeLibrary,
+                    pLoadFont->Memory->Buffer,
+                    pLoadFont->Memory->BufferSize,
+                    ((FontIndex != -1) ? FontIndex : 0),
+                    &Face);
+
+        if (!Error)
+            SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
+
+        IntUnLockFreeType();
+
+        if (!Error && FT_IS_SFNT(Face))
+            pLoadFont->IsTrueType = TRUE;
+
+        if (Error || SharedFace == NULL)
+        {
+            if (SharedFace)
+                SharedFace_Release(SharedFace);
 
-    if (!NT_SUCCESS(Status))
+            if (Error == FT_Err_Unknown_File_Format)
+                DPRINT1("Unknown font file format\n");
+            else
+                DPRINT1("Error reading font (error code: %d)\n", Error);
+            return 0;   /* failure */
+        }
+    }
+    else
     {
-        DPRINT("Could not load font file: %wZ\n", FileName);
-        return 0;
+        Face = SharedFace->Face;
+        IntLockFreeType();
+        SharedFace_AddRef(SharedFace);
+        IntUnLockFreeType();
     }
 
-    SectionSize.QuadPart = 0LL;
-    Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
-                             NULL, &SectionSize, PAGE_READONLY,
-                             SEC_COMMIT, FileHandle, NULL);
-    if (!NT_SUCCESS(Status))
+    /* allocate a FONT_ENTRY */
+    Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
+    if (!Entry)
     {
-        DPRINT("Could not map file: %wZ\n", FileName);
-        ZwClose(FileHandle);
-        return 0;
+        SharedFace_Release(SharedFace);
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;   /* failure */
     }
 
-    ZwClose(FileHandle);
-
-    Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
-    if (!NT_SUCCESS(Status))
+    /* allocate a FONTGDI */
+    FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
+    if (!FontGDI)
     {
-        DPRINT("Could not map file: %wZ\n", FileName);
-        ObDereferenceObject(SectionObject);
-        return 0;
+        SharedFace_Release(SharedFace);
+        ExFreePoolWithTag(Entry, TAG_FONT);
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return 0;   /* failure */
     }
 
-    IntLockFreeType;
-    Error = FT_New_Memory_Face(
-                library,
-                Buffer,
-                ViewSize,
-                0,
-                &Face);
-    IntUnLockFreeType;
-    ObDereferenceObject(SectionObject);
-
-    if (Error)
+    /* set file name */
+    if (pFileName)
+    {
+        FontGDI->Filename = ExAllocatePoolWithTag(PagedPool,
+                                                  pFileName->Length + sizeof(UNICODE_NULL),
+                                                  GDITAG_PFF);
+        if (FontGDI->Filename == NULL)
+        {
+            EngFreeMem(FontGDI);
+            SharedFace_Release(SharedFace);
+            ExFreePoolWithTag(Entry, TAG_FONT);
+            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return 0;   /* failure */
+        }
+        RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
+        FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
+    }
+    else
     {
-        if (Error == FT_Err_Unknown_File_Format)
-            DPRINT("Unknown font file format\n");
+        FontGDI->Filename = NULL;
+
+        PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT);
+        if (!PrivateEntry)
+        {
+            if (FontGDI->Filename)
+                ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
+            EngFreeMem(FontGDI);
+            SharedFace_Release(SharedFace);
+            ExFreePoolWithTag(Entry, TAG_FONT);
+            return 0;
+        }
+
+        PrivateEntry->Entry = Entry;
+        if (pLoadFont->PrivateEntry)
+        {
+            InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry);
+        }
         else
-            DPRINT("Error reading font file (error code: %d)\n", Error);
-        return 0;
+        {
+            InitializeListHead(&PrivateEntry->ListEntry);
+            pLoadFont->PrivateEntry = PrivateEntry;
+        }
     }
 
-    Entry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY), TAG_FONT);
-    if (!Entry)
+    /* set face */
+    FontGDI->SharedFace = SharedFace;
+    FontGDI->CharSet = ANSI_CHARSET;
+    FontGDI->OriginalItalic = ItalicFromStyle(Face->style_name);
+    FontGDI->RequestItalic = FALSE;
+    FontGDI->OriginalWeight = WeightFromStyle(Face->style_name);
+    FontGDI->RequestWeight = FW_NORMAL;
+
+    RtlInitAnsiString(&AnsiFaceName, Face->family_name);
+    Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
+    if (!NT_SUCCESS(Status))
     {
-        FT_Done_Face(Face);
-        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        if (PrivateEntry)
+        {
+            if (pLoadFont->PrivateEntry == PrivateEntry)
+            {
+                pLoadFont->PrivateEntry = NULL;
+            }
+            else
+            {
+                RemoveEntryList(&PrivateEntry->ListEntry);
+            }
+            ExFreePoolWithTag(PrivateEntry, TAG_FONT);
+        }
+        if (FontGDI->Filename)
+            ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
+        EngFreeMem(FontGDI);
+        SharedFace_Release(SharedFace);
+        ExFreePoolWithTag(Entry, TAG_FONT);
         return 0;
     }
 
-    FontGDI = EngAllocMem(FL_ZERO_MEMORY, sizeof(FONTGDI), GDITAG_RFONT);
-    if (FontGDI == NULL)
+    os2_version = 0;
+    IntLockFreeType();
+    pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(Face, FT_SFNT_OS2);
+    if (pOS2)
     {
-        FT_Done_Face(Face);
-        ExFreePoolWithTag(Entry, TAG_FONT);
-        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return 0;
+        os2_version = pOS2->version;
+        os2_ulCodePageRange1 = pOS2->ulCodePageRange1;
+        os2_usWeightClass = pOS2->usWeightClass;
     }
+    IntUnLockFreeType();
 
-    FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, FileName->Length + sizeof(WCHAR), GDITAG_PFF);
-    if (FontGDI->Filename == NULL)
+    if (pOS2 && os2_version >= 1)
     {
-        EngFreeMem(FontGDI);
-        FT_Done_Face(Face);
-        ExFreePoolWithTag(Entry, TAG_FONT);
-        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-        return 0;
+        /* get charset and weight from OS/2 header */
+
+        /* Make sure we do not use this pointer anymore */
+        pOS2 = NULL;
+
+        for (BitIndex = 0; BitIndex < MAXTCIINDEX; ++BitIndex)
+        {
+            if (os2_ulCodePageRange1 & (1 << BitIndex))
+            {
+                if (g_FontTci[BitIndex].ciCharset == DEFAULT_CHARSET)
+                    continue;
+
+                if ((CharSetIndex == -1 && CharSetCount == 0) ||
+                    CharSetIndex == CharSetCount)
+                {
+                    FontGDI->CharSet = g_FontTci[BitIndex].ciCharset;
+                }
+
+                ++CharSetCount;
+            }
+        }
+
+        /* set actual weight */
+        FontGDI->OriginalWeight = os2_usWeightClass;
+    }
+    else
+    {
+        /* get charset from WinFNT header */
+        IntLockFreeType();
+        Error = FT_Get_WinFNT_Header(Face, &WinFNT);
+        if (!Error)
+        {
+            FontGDI->CharSet = WinFNT.charset;
+        }
+        IntUnLockFreeType();
+    }
+
+    /* FIXME: CharSet is invalid on Marlett */
+    if (RtlEqualUnicodeString(&Entry->FaceName, &g_MarlettW, TRUE))
+    {
+        FontGDI->CharSet = SYMBOL_CHARSET;
     }
-    RtlCopyMemory(FontGDI->Filename, FileName->Buffer, FileName->Length);
-    FontGDI->Filename[FileName->Length / sizeof(WCHAR)] = L'\0';
-    FontGDI->face = Face;
 
-    DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
+    ++FaceCount;
+    DPRINT("Font loaded: %s (%s)\n",
+           Face->family_name ? Face->family_name : "<NULL>",
+           Face->style_name ? Face->style_name : "<NULL>");
     DPRINT("Num glyphs: %d\n", Face->num_glyphs);
+    DPRINT("CharSet: %d\n", FontGDI->CharSet);
 
-    /* Add this font resource to the font table */
+    IntLockFreeType();
+    IntRequestFontSize(NULL, FontGDI, 0, 0);
+    IntUnLockFreeType();
 
+    /* Add this font resource to the font table */
     Entry->Font = FontGDI;
     Entry->NotEnum = (Characteristics & FR_NOT_ENUM);
-    RtlInitAnsiString(&AnsiFaceName, (LPSTR)Face->family_name);
-    RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE);
 
     if (Characteristics & FR_PRIVATE)
     {
+        /* private font */
         PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
         IntLockProcessPrivateFonts(Win32Process);
         InsertTailList(&Win32Process->PrivateFontListHead, &Entry->ListEntry);
@@ -428,34 +1055,376 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
     }
     else
     {
-        IntLockGlobalFonts;
-        InsertTailList(&FontListHead, &Entry->ListEntry);
-        InitializeObjectAttributes(&ObjectAttributes, &FontRegPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
+        /* global font */
+        IntLockGlobalFonts();
+        InsertTailList(&g_FontListHead, &Entry->ListEntry);
+        IntUnLockGlobalFonts();
+    }
+
+    if (FontIndex == -1)
+    {
+        if (FT_IS_SFNT(Face))
+        {
+            TT_Face TrueType = (TT_Face)Face;
+            if (TrueType->ttc_header.count > 1)
+            {
+                FT_Long i;
+                for (i = 1; i < TrueType->ttc_header.count; ++i)
+                {
+                    FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
+                }
+            }
+        }
+        FontIndex = 0;
+    }
+
+    if (CharSetIndex == -1)
+    {
+        INT i;
+
+        if (pLoadFont->RegValueName.Length == 0)
+        {
+            RtlCreateUnicodeString(pValueName, Entry->FaceName.Buffer);
+        }
+        else
+        {
+            UNICODE_STRING NewString;
+            USHORT Length = pValueName->Length + 3 * sizeof(WCHAR) + Entry->FaceName.Length;
+            NewString.Length = 0;
+            NewString.MaximumLength = Length + sizeof(WCHAR);
+            NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                     NewString.MaximumLength,
+                                                     TAG_USTR);
+            NewString.Buffer[0] = UNICODE_NULL;
+
+            RtlAppendUnicodeStringToString(&NewString, pValueName);
+            RtlAppendUnicodeToString(&NewString, L" & ");
+            RtlAppendUnicodeStringToString(&NewString, &Entry->FaceName);
+
+            RtlFreeUnicodeString(pValueName);
+            *pValueName = NewString;
+        }
+
+        for (i = 1; i < CharSetCount; ++i)
+        {
+            /* Do not count charsets towards 'faces' loaded */
+            IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
+        }
+    }
+
+    return FaceCount;   /* number of loaded faces */
+}
+
+/*
+ * IntGdiAddFontResource
+ *
+ * Adds the font resource from the specified file to the system.
+ */
+
+INT FASTCALL
+IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
+{
+    NTSTATUS Status;
+    HANDLE FileHandle;
+    PVOID Buffer = NULL;
+    IO_STATUS_BLOCK Iosb;
+    PVOID SectionObject;
+    SIZE_T ViewSize = 0;
+    LARGE_INTEGER SectionSize;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    GDI_LOAD_FONT   LoadFont;
+    INT FontCount;
+    HANDLE KeyHandle;
+    static const UNICODE_STRING TrueTypePostfix = RTL_CONSTANT_STRING(L" (TrueType)");
+
+    /* Open the font file */
+    InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
+    Status = ZwOpenFile(
+                 &FileHandle,
+                 FILE_GENERIC_READ | SYNCHRONIZE,
+                 &ObjectAttributes,
+                 &Iosb,
+                 FILE_SHARE_READ,
+                 FILE_SYNCHRONOUS_IO_NONALERT);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("Could not load font file: %wZ\n", FileName);
+        return 0;
+    }
+
+    SectionSize.QuadPart = 0LL;
+    Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
+                             NULL, &SectionSize, PAGE_READONLY,
+                             SEC_COMMIT, FileHandle, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("Could not map file: %wZ\n", FileName);
+        ZwClose(FileHandle);
+        return 0;
+    }
+    ZwClose(FileHandle);
+
+    Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("Could not map file: %wZ\n", FileName);
+        ObDereferenceObject(SectionObject);
+        return 0;
+    }
+
+    LoadFont.pFileName          = FileName;
+    LoadFont.Memory             = SharedMem_Create(Buffer, ViewSize, TRUE);
+    LoadFont.Characteristics    = Characteristics;
+    RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
+    LoadFont.IsTrueType         = FALSE;
+    LoadFont.PrivateEntry       = NULL;
+    FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
+
+    ObDereferenceObject(SectionObject);
+
+    /* Release our copy */
+    IntLockFreeType();
+    SharedMem_Release(LoadFont.Memory);
+    IntUnLockFreeType();
+
+    if (FontCount > 0)
+    {
+        if (LoadFont.IsTrueType)
+        {
+            /* append " (TrueType)" */
+            UNICODE_STRING NewString;
+            USHORT Length;
+
+            Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length;
+            NewString.Length = 0;
+            NewString.MaximumLength = Length + sizeof(WCHAR);
+            NewString.Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                     NewString.MaximumLength,
+                                                     TAG_USTR);
+            NewString.Buffer[0] = UNICODE_NULL;
+
+            RtlAppendUnicodeStringToString(&NewString, &LoadFont.RegValueName);
+            RtlAppendUnicodeStringToString(&NewString, &TrueTypePostfix);
+            RtlFreeUnicodeString(&LoadFont.RegValueName);
+            LoadFont.RegValueName = NewString;
+        }
+
+        /* registry */
+        InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
+                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                                   NULL, NULL);
         Status = ZwOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
         if (NT_SUCCESS(Status))
         {
-            LPWSTR pName = wcsrchr(FileName->Buffer, L'\\');
-            if (pName)
+            SIZE_T DataSize;
+            LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
+            if (pFileName)
             {
-                pName++;
-                ZwSetValueKey(KeyHandle, &Entry->FaceName, 0, REG_SZ, pName, (wcslen(pName) + 1) * sizeof(WCHAR));
+                pFileName++;
+                DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
+                ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
+                              pFileName, DataSize);
             }
             ZwClose(KeyHandle);
         }
-        IntUnLockGlobalFonts;
     }
-    return 1;
+    RtlFreeUnicodeString(&LoadFont.RegValueName);
+
+    return FontCount;
+}
+
+HANDLE FASTCALL
+IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
+{
+    GDI_LOAD_FONT LoadFont;
+    FONT_ENTRY_COLL_MEM* EntryCollection;
+    INT FaceCount;
+    HANDLE Ret = 0;
+
+    PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
+
+    if (!BufferCopy)
+    {
+        *pNumAdded = 0;
+        return NULL;
+    }
+    memcpy(BufferCopy, Buffer, dwSize);
+
+    LoadFont.pFileName = NULL;
+    LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
+    LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
+    RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
+    LoadFont.IsTrueType = FALSE;
+    LoadFont.PrivateEntry = NULL;
+    FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
+
+    RtlFreeUnicodeString(&LoadFont.RegValueName);
+
+    /* Release our copy */
+    IntLockFreeType();
+    SharedMem_Release(LoadFont.Memory);
+    IntUnLockFreeType();
+
+    if (FaceCount > 0)
+    {
+        EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
+        if (EntryCollection)
+        {
+            PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
+            EntryCollection->Entry = LoadFont.PrivateEntry;
+            IntLockProcessPrivateFonts(Win32Process);
+            EntryCollection->Handle = ULongToHandle(++Win32Process->PrivateMemFontHandleCount);
+            InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry);
+            IntUnLockProcessPrivateFonts(Win32Process);
+            Ret = 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)
+{
+    PLIST_ENTRY Entry;
+    PFONT_ENTRY_MEM FontEntry;
+
+    while (!IsListEmpty(&Head->ListEntry))
+    {
+        Entry = RemoveHeadList(&Head->ListEntry);
+        FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
+
+        CleanupFontEntry(FontEntry->Entry);
+        ExFreePoolWithTag(FontEntry, TAG_FONT);
+    }
+
+    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)
+{
+    PLIST_ENTRY Entry;
+    PFONT_ENTRY_COLL_MEM CurrentEntry;
+    PFONT_ENTRY_COLL_MEM EntryCollection = NULL;
+    PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
+
+    IntLockProcessPrivateFonts(Win32Process);
+    for (Entry = Win32Process->PrivateMemFontListHead.Flink;
+         Entry != &Win32Process->PrivateMemFontListHead;
+         Entry = Entry->Flink)
+    {
+        CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
+
+        if (CurrentEntry->Handle == hMMFont)
+        {
+            EntryCollection = CurrentEntry;
+            UnlinkFontMemCollection(CurrentEntry);
+            break;
+        }
+    }
+    IntUnLockProcessPrivateFonts(Win32Process);
+
+    if (EntryCollection)
+    {
+        IntGdiCleanupMemEntry(EntryCollection->Entry);
+        ExFreePoolWithTag(EntryCollection, TAG_FONT);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
+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)
 {
-    BOOL Ret = RenderingEnabled;
+    BOOL Ret = g_RenderingEnabled;
     HDC hDC;
 
     hDC = IntGetScreenDC();
     if (hDC)
-        Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && RenderingEnabled;
+        Ret = (NtGdiGetDeviceCaps(hDC, BITSPIXEL) > 8) && g_RenderingEnabled;
 
     return Ret;
 }
@@ -463,7 +1432,7 @@ IntIsFontRenderingEnabled(VOID)
 VOID FASTCALL
 IntEnableFontRendering(BOOL Enable)
 {
-    RenderingEnabled = Enable;
+    g_RenderingEnabled = Enable;
 }
 
 FT_Render_Mode FASTCALL
@@ -471,6 +1440,8 @@ IntGetFontRenderMode(LOGFONTW *logfont)
 {
     switch (logfont->lfQuality)
     {
+    case ANTIALIASED_QUALITY:
+        break;
     case NONANTIALIASED_QUALITY:
         return FT_RENDER_MODE_MONO;
     case DRAFT_QUALITY:
@@ -486,6 +1457,7 @@ NTSTATUS FASTCALL
 TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
 {
     PLFONT plfont;
+    LOGFONTW *plf;
 
     plfont = LFONT_AllocFontWithHandle();
     if (!plfont)
@@ -495,12 +1467,12 @@ TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
 
     ExInitializePushLock(&plfont->lock);
     *NewFont = plfont->BaseObject.hHmgr;
-    RtlCopyMemory(&plfont->logfont.elfEnumLogfontEx.elfLogFont, lf, sizeof(LOGFONTW));
+    plf = &plfont->logfont.elfEnumLogfontEx.elfLogFont;
+    RtlCopyMemory(plf, lf, sizeof(LOGFONTW));
     if (lf->lfEscapement != lf->lfOrientation)
     {
         /* This should really depend on whether GM_ADVANCED is set */
-        plfont->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation =
-            plfont->logfont.elfEnumLogfontEx.elfLogFont.lfEscapement;
+        plf->lfOrientation = plf->lfEscapement;
     }
     LFONT_UnlockFont(plfont);
 
@@ -541,13 +1513,13 @@ IntTranslateCharsetInfo(PDWORD Src, /* [in]
         }
         break;
     case TCI_SRCCODEPAGE:
-        while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciACP)
+        while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciACP)
         {
             Index++;
         }
         break;
     case TCI_SRCCHARSET:
-        while (Index < MAXTCIINDEX && *Src != FontTci[Index].ciCharset)
+        while (Index < MAXTCIINDEX && *Src != g_FontTci[Index].ciCharset)
         {
             Index++;
         }
@@ -556,12 +1528,12 @@ IntTranslateCharsetInfo(PDWORD Src, /* [in]
         return FALSE;
     }
 
-    if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == FontTci[Index].ciCharset)
+    if (Index >= MAXTCIINDEX || DEFAULT_CHARSET == g_FontTci[Index].ciCharset)
     {
         return FALSE;
     }
 
-    RtlCopyMemory(Cs, &FontTci[Index], sizeof(CHARSETINFO));
+    RtlCopyMemory(Cs, &g_FontTci[Index], sizeof(CHARSETINFO));
 
     return TRUE;
 }
@@ -573,44 +1545,60 @@ static BOOL face_has_symbol_charmap(FT_Face ft_face)
 
     for(i = 0; i < ft_face->num_charmaps; i++)
     {
-        if(ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
+        if (ft_face->charmaps[i]->platform_id == TT_PLATFORM_MICROSOFT &&
+            ft_face->charmaps[i]->encoding == FT_ENCODING_MS_SYMBOL)
+        {
             return TRUE;
+        }
     }
     return FALSE;
 }
 
 static void FASTCALL
-FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT_WinFNT_HeaderRec *pWin)
+FillTMEx(TEXTMETRICW *TM, PFONTGDI FontGDI,
+         TT_OS2 *pOS2, TT_HoriHeader *pHori,
+         FT_WinFNT_HeaderRec *pFNT, BOOL RealFont)
 {
     FT_Fixed XScale, YScale;
     int Ascent, Descent;
-    FT_Face Face = FontGDI->face;
+    FT_Face Face = FontGDI->SharedFace->Face;
 
     XScale = Face->size->metrics.x_scale;
     YScale = Face->size->metrics.y_scale;
 
-    if (pWin)
+    if (pFNT)
     {
-        TM->tmHeight           = pWin->pixel_height;
-        TM->tmAscent           = pWin->ascent;
+        TM->tmHeight           = pFNT->pixel_height;
+        TM->tmAscent           = pFNT->ascent;
         TM->tmDescent          = TM->tmHeight - TM->tmAscent;
-        TM->tmInternalLeading  = pWin->internal_leading;
-        TM->tmExternalLeading  = pWin->external_leading;
-        TM->tmAveCharWidth     = pWin->avg_width;
-        TM->tmMaxCharWidth     = pWin->max_width;
-        TM->tmWeight           = pWin->weight;
+        TM->tmInternalLeading  = pFNT->internal_leading;
+        TM->tmExternalLeading  = pFNT->external_leading;
+        TM->tmAveCharWidth     = pFNT->avg_width;
+        TM->tmMaxCharWidth     = pFNT->max_width;
         TM->tmOverhang         = 0;
-        TM->tmDigitizedAspectX = pWin->horizontal_resolution;
-        TM->tmDigitizedAspectY = pWin->vertical_resolution;
-        TM->tmFirstChar        = pWin->first_char;
-        TM->tmLastChar         = pWin->last_char;
-        TM->tmDefaultChar      = pWin->default_char + pWin->first_char;
-        TM->tmBreakChar        = pWin->break_char + pWin->first_char;
-        TM->tmItalic           = pWin->italic;
-        TM->tmUnderlined       = FontGDI->Underline;
-        TM->tmStruckOut        = FontGDI->StrikeOut;
-        TM->tmPitchAndFamily   = pWin->pitch_and_family;
-        TM->tmCharSet          = pWin->charset;
+        TM->tmDigitizedAspectX = pFNT->horizontal_resolution;
+        TM->tmDigitizedAspectY = pFNT->vertical_resolution;
+        TM->tmFirstChar        = pFNT->first_char;
+        TM->tmLastChar         = pFNT->last_char;
+        TM->tmDefaultChar      = pFNT->default_char + pFNT->first_char;
+        TM->tmBreakChar        = pFNT->break_char + pFNT->first_char;
+        TM->tmPitchAndFamily   = pFNT->pitch_and_family;
+        if (RealFont)
+        {
+            TM->tmWeight       = FontGDI->OriginalWeight;
+            TM->tmItalic       = FontGDI->OriginalItalic;
+            TM->tmUnderlined   = pFNT->underline;
+            TM->tmStruckOut    = pFNT->strike_out;
+            TM->tmCharSet      = pFNT->charset;
+        }
+        else
+        {
+            TM->tmWeight       = FontGDI->RequestWeight;
+            TM->tmItalic       = FontGDI->RequestItalic;
+            TM->tmUnderlined   = FontGDI->RequestUnderline;
+            TM->tmStruckOut    = FontGDI->RequestStrikeOut;
+            TM->tmCharSet      = FontGDI->CharSet;
+        }
         return;
     }
 
@@ -625,16 +1613,14 @@ FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT
         Descent = pOS2->usWinDescent;
     }
 
-#if 0 /* This (Wine) code doesn't seem to work correctly for us, cmd issue */
-    TM->tmAscent = (FT_MulFix(Ascent, YScale) + 32) >> 6;
-    TM->tmDescent = (FT_MulFix(Descent, YScale) + 32) >> 6;
-#else /* This (ros) code was previously affected by a FreeType bug, but it works now */
-    TM->tmAscent = (Face->size->metrics.ascender + 32) >> 6; /* Units above baseline */
-    TM->tmDescent = (32 - Face->size->metrics.descender) >> 6; /* Units below baseline */
-#endif
-    TM->tmInternalLeading = (FT_MulFix(Ascent + Descent - Face->units_per_EM, YScale) + 32) >> 6;
-
+    if (FontGDI->Magic != FONTGDI_MAGIC)
+    {
+        IntRequestFontSize(NULL, FontGDI, 0, 0);
+    }
+    TM->tmAscent = FontGDI->tmAscent;
+    TM->tmDescent = FontGDI->tmDescent;
     TM->tmHeight = TM->tmAscent + TM->tmDescent;
+    TM->tmInternalLeading = FontGDI->tmInternalLeading;
 
     /* MSDN says:
      *  el = MAX(0, LineGap - ((WinAscent + WinDescent) - (Ascender - Descender)))
@@ -653,11 +1639,28 @@ FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT
     /* Correct forumla to get the maxcharwidth from unicode and ansi font */
     TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >> 6;
 
-    TM->tmWeight = pOS2->usWeightClass;
+    if (RealFont)
+    {
+        TM->tmWeight = FontGDI->OriginalWeight;
+    }
+    else
+    {
+        if (FontGDI->OriginalWeight != FW_DONTCARE &&
+            FontGDI->OriginalWeight != FW_NORMAL)
+        {
+            TM->tmWeight = FontGDI->OriginalWeight;
+        }
+        else
+        {
+            TM->tmWeight = FontGDI->RequestWeight;
+        }
+    }
+
     TM->tmOverhang = 0;
     TM->tmDigitizedAspectX = 96;
     TM->tmDigitizedAspectY = 96;
-    if (face_has_symbol_charmap(Face) || (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
+    if (face_has_symbol_charmap(Face) ||
+        (pOS2->usFirstCharIndex >= 0xf000 && pOS2->usFirstCharIndex < 0xf100))
     {
         USHORT cpOEM, cpAnsi;
 
@@ -687,22 +1690,46 @@ FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT
             TM->tmBreakChar = pOS2->usFirstCharIndex;
         TM->tmDefaultChar = TM->tmBreakChar - 1;
     }
-    TM->tmItalic = (Face->style_flags & FT_STYLE_FLAG_ITALIC) ? 255 : 0;
-    TM->tmUnderlined = FontGDI->Underline;
-    TM->tmStruckOut  = FontGDI->StrikeOut;
 
-    /* Yes TPMF_FIXED_PITCH is correct; braindead api */
-    if (! FT_IS_FIXED_WIDTH(Face))
+    if (RealFont)
     {
-        TM->tmPitchAndFamily = TMPF_FIXED_PITCH;
+        TM->tmItalic = FontGDI->OriginalItalic;
+        TM->tmUnderlined = FALSE;
+        TM->tmStruckOut  = FALSE;
     }
     else
     {
-        TM->tmPitchAndFamily = 0;
-    }
-
-    switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
-    {
+        if (FontGDI->OriginalItalic || FontGDI->RequestItalic)
+        {
+            TM->tmItalic = 0xFF;
+        }
+        else
+        {
+            TM->tmItalic = 0;
+        }
+        TM->tmUnderlined = (FontGDI->RequestUnderline ? 0xFF : 0);
+        TM->tmStruckOut  = (FontGDI->RequestStrikeOut ? 0xFF : 0);
+    }
+
+    if (!FT_IS_FIXED_WIDTH(Face))
+    {
+        switch (pOS2->panose[PAN_PROPORTION_INDEX])
+        {
+            case PAN_PROP_MONOSPACED:
+                TM->tmPitchAndFamily = 0;
+                break;
+            default:
+                TM->tmPitchAndFamily = _TMPF_VARIABLE_PITCH;
+                break;
+        }
+    }
+    else
+    {
+        TM->tmPitchAndFamily = 0;
+    }
+
+    switch (pOS2->panose[PAN_FAMILYTYPE_INDEX])
+    {
     case PAN_FAMILY_SCRIPT:
         TM->tmPitchAndFamily |= FF_SCRIPT;
         break;
@@ -764,9 +1791,21 @@ FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI, TT_OS2 *pOS2, TT_HoriHeader *pHori, FT
         TM->tmPitchAndFamily |= TMPF_TRUETYPE;
     }
 
-    TM->tmCharSet = DEFAULT_CHARSET;
+    TM->tmCharSet = FontGDI->CharSet;
+}
+
+static void FASTCALL
+FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
+       TT_OS2 *pOS2, TT_HoriHeader *pHori,
+       FT_WinFNT_HeaderRec *pFNT)
+{
+    FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
 }
 
+static NTSTATUS
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
+                        FT_UShort NameID, FT_UShort LangID);
+
 /*************************************************************
  * IntGetOutlineTextMetrics
  *
@@ -776,83 +1815,93 @@ 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;
+    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);
+    if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
+    {
+        return Cache->OutlineRequiredSize;
+    }
 
-    RtlInitAnsiString(&FamilyNameA, FontGDI->face->family_name);
-    RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
+    /* family name */
+    RtlInitUnicodeString(&FamilyNameW, NULL);
+    IntGetFontLocalizedName(&FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
 
-    RtlInitAnsiString(&StyleNameA, FontGDI->face->style_name);
-    RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
+    /* face name */
+    RtlInitUnicodeString(&FaceNameW, NULL);
+    IntGetFontLocalizedName(&FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
 
-    /* These names should be read from the TT name table */
+    /* style name */
+    RtlInitUnicodeString(&StyleNameW, NULL);
+    IntGetFontLocalizedName(&StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
 
-    /* Length of otmpFamilyName */
-    Needed += FamilyNameW.Length + sizeof(WCHAR);
+    /* unique name (full name) */
+    RtlInitUnicodeString(&FullNameW, NULL);
+    IntGetFontLocalizedName(&FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
 
-    RtlInitUnicodeString(&Regular, L"regular");
-    /* Length of otmpFaceName */
-    if (0 == RtlCompareUnicodeString(&StyleNameW, &Regular, TRUE))
-    {
-        Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
-    }
-    else
+    if (!Cache->OutlineRequiredSize)
     {
-        Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
-    }
-
-    /* Length of otmpStyleName */
-    Needed += StyleNameW.Length + sizeof(WCHAR);
+        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 = FontGDI->face->size->metrics.x_scale;
-    YScale = FontGDI->face->size->metrics.y_scale;
+    XScale = Face->size->metrics.x_scale;
+    YScale = Face->size->metrics.y_scale;
 
-    IntLockFreeType;
-    pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+    IntLockFreeType();
+    pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
     if (NULL == pOS2)
     {
-        IntUnLockFreeType;
+        IntUnLockFreeType();
         DPRINT1("Can't find OS/2 table - not TT font?\n");
-        RtlFreeUnicodeString(&StyleNameW);
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
+        RtlFreeUnicodeString(&StyleNameW);
+        RtlFreeUnicodeString(&FullNameW);
         return 0;
     }
 
-    pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
+    pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
     if (NULL == pHori)
     {
-        IntUnLockFreeType;
+        IntUnLockFreeType();
         DPRINT1("Can't find HHEA table - not TT font?\n");
-        RtlFreeUnicodeString(&StyleNameW);
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
+        RtlFreeUnicodeString(&StyleNameW);
+        RtlFreeUnicodeString(&FullNameW);
         return 0;
     }
 
-    pPost = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_post); /* We can live with this failing */
+    pPost = FT_Get_Sfnt_Table(Face, ft_sfnt_post); /* We can live with this failing */
 
-    Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
+    Error = FT_Get_WinFNT_Header(Face , &Win);
 
-    Otm->otmSize = Needed;
+    Otm->otmSize = Cache->OutlineRequiredSize;
 
     FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
 
@@ -863,16 +1912,16 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
     Otm->otmsCharSlopeRise = pHori->caret_Slope_Rise;
     Otm->otmsCharSlopeRun = pHori->caret_Slope_Run;
     Otm->otmItalicAngle = 0; /* POST table */
-    Otm->otmEMSquare = FontGDI->face->units_per_EM;
+    Otm->otmEMSquare = Face->units_per_EM;
     Otm->otmAscent = (FT_MulFix(pOS2->sTypoAscender, YScale) + 32) >> 6;
     Otm->otmDescent = (FT_MulFix(pOS2->sTypoDescender, YScale) + 32) >> 6;
     Otm->otmLineGap = (FT_MulFix(pOS2->sTypoLineGap, YScale) + 32) >> 6;
     Otm->otmsCapEmHeight = (FT_MulFix(pOS2->sCapHeight, YScale) + 32) >> 6;
     Otm->otmsXHeight = (FT_MulFix(pOS2->sxHeight, YScale) + 32) >> 6;
-    Otm->otmrcFontBox.left = (FT_MulFix(FontGDI->face->bbox.xMin, XScale) + 32) >> 6;
-    Otm->otmrcFontBox.right = (FT_MulFix(FontGDI->face->bbox.xMax, XScale) + 32) >> 6;
-    Otm->otmrcFontBox.top = (FT_MulFix(FontGDI->face->bbox.yMax, YScale) + 32) >> 6;
-    Otm->otmrcFontBox.bottom = (FT_MulFix(FontGDI->face->bbox.yMin, YScale) + 32) >> 6;
+    Otm->otmrcFontBox.left = (FT_MulFix(Face->bbox.xMin, XScale) + 32) >> 6;
+    Otm->otmrcFontBox.right = (FT_MulFix(Face->bbox.xMax, XScale) + 32) >> 6;
+    Otm->otmrcFontBox.top = (FT_MulFix(Face->bbox.yMax, YScale) + 32) >> 6;
+    Otm->otmrcFontBox.bottom = (FT_MulFix(Face->bbox.yMin, YScale) + 32) >> 6;
     Otm->otmMacAscent = Otm->otmTextMetrics.tmAscent;
     Otm->otmMacDescent = -Otm->otmTextMetrics.tmDescent;
     Otm->otmMacLineGap = Otm->otmLineGap;
@@ -898,37 +1947,38 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
         Otm->otmsUnderscorePosition = (FT_MulFix(pPost->underlinePosition, YScale) + 32) >> 6;
     }
 
-    IntUnLockFreeType;
+    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 (0 != RtlCompareUnicodeString(&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
@@ -939,31 +1989,35 @@ FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
     ANSI_STRING EntryFaceNameA;
     UNICODE_STRING EntryFaceNameW;
     FONTGDI *FontGDI;
+    NTSTATUS status;
 
-    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->face->family_name);
-        RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
+        RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
+        status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
+        if (!NT_SUCCESS(status))
+        {
+            break;
+        }
+
         if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
         {
             EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
             EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
         }
 
-        if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
+        if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
         {
             RtlFreeUnicodeString(&EntryFaceNameW);
             return FontGDI;
         }
 
         RtlFreeUnicodeString(&EntryFaceNameW);
-        Entry = Entry->Flink;
     }
 
     return NULL;
@@ -975,7 +2029,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);
@@ -986,15 +2041,258 @@ FindFaceNameInLists(PUNICODE_STRING FaceName)
     }
 
     /* Search the global list */
-    IntLockGlobalFonts;
-    Font = FindFaceNameInList(FaceName, &FontListHead);
-    IntUnLockGlobalFonts;
+    IntLockGlobalFonts();
+    Font = FindFaceNameInList(FaceName, &g_FontListHead);
+    IntUnLockGlobalFonts();
 
     return Font;
 }
 
+/* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
+static BYTE
+CharSetFromLangID(LANGID LangID)
+{
+    /* FIXME: Add more and fix if wrong */
+    switch (PRIMARYLANGID(LangID))
+    {
+        case LANG_CHINESE:
+            switch (SUBLANGID(LangID))
+            {
+                case SUBLANG_CHINESE_TRADITIONAL:
+                    return CHINESEBIG5_CHARSET;
+                case SUBLANG_CHINESE_SIMPLIFIED:
+                default:
+                    break;
+            }
+            return GB2312_CHARSET;
+
+        case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH:
+        case LANG_SLOVAK: case LANG_SLOVENIAN: case LANG_ROMANIAN:
+            return EASTEUROPE_CHARSET;
+
+        case LANG_RUSSIAN: case LANG_BULGARIAN: case LANG_MACEDONIAN:
+        case LANG_SERBIAN: case LANG_UKRAINIAN:
+            return RUSSIAN_CHARSET;
+
+        case LANG_ARABIC:       return ARABIC_CHARSET;
+        case LANG_GREEK:        return GREEK_CHARSET;
+        case LANG_HEBREW:       return HEBREW_CHARSET;
+        case LANG_JAPANESE:     return SHIFTJIS_CHARSET;
+        case LANG_KOREAN:       return JOHAB_CHARSET;
+        case LANG_TURKISH:      return TURKISH_CHARSET;
+        case LANG_THAI:         return THAI_CHARSET;
+        case LANG_LATVIAN:      return BALTIC_CHARSET;
+        case LANG_VIETNAMESE:   return VIETNAMESE_CHARSET;
+
+        case LANG_ENGLISH: case LANG_BASQUE: case LANG_CATALAN:
+        case LANG_DANISH: case LANG_DUTCH: case LANG_FINNISH:
+        case LANG_FRENCH: case LANG_GERMAN: case LANG_ITALIAN:
+        case LANG_NORWEGIAN: case LANG_PORTUGUESE: case LANG_SPANISH:
+        case LANG_SWEDISH: default:
+            return ANSI_CHARSET;
+    }
+}
+
+static void
+SwapEndian(LPVOID pvData, DWORD Size)
+{
+    BYTE b, *pb = pvData;
+    Size /= 2;
+    while (Size-- > 0)
+    {
+        b = pb[0];
+        pb[0] = pb[1];
+        pb[1] = b;
+        ++pb; ++pb;
+    }
+}
+
+static NTSTATUS
+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, BestIndex, Score, BestScore;
+    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);
+    }
+
+    BestIndex = -1;
+    BestScore = 0;
+
+    Count = FT_Get_Sfnt_Name_Count(Face);
+    for (i = 0; i < Count; ++i)
+    {
+        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_SYMBOL_CS))
+        {
+            continue;   /* not Microsoft Unicode name */
+        }
+
+        if (Name.string == NULL || Name.string_len == 0 ||
+            (Name.string[0] == 0 && Name.string[1] == 0))
+        {
+            continue;   /* invalid string */
+        }
+
+        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;
+        }
+
+        if (Score > BestScore)
+        {
+            BestScore = Score;
+            BestIndex = i;
+        }
+    }
+
+    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 */
+            UNICODE_STRING Tmp;
+            Tmp.Buffer = (PWCH)Name.string;
+            Tmp.Length = Tmp.MaximumLength = Name.string_len;
+
+            pNameW->Length = 0;
+            pNameW->MaximumLength = Name.string_len + sizeof(WCHAR);
+            pNameW->Buffer = ExAllocatePoolWithTag(PagedPool, pNameW->MaximumLength, TAG_USTR);
+
+            if (pNameW->Buffer)
+            {
+                Status = RtlAppendUnicodeStringToString(pNameW, &Tmp);
+                if (Status == STATUS_SUCCESS)
+                {
+                    /* Convert UTF-16 big endian to little endian */
+                    SwapEndian(pNameW->Buffer, pNameW->Length);
+                }
+            }
+            else
+            {
+                Status = STATUS_INSUFFICIENT_RESOURCES;
+            }
+        }
+    }
+
+    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;
@@ -1007,7 +2305,12 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     TEXTMETRICW *TM;
     NEWTEXTMETRICW *Ntm;
     DWORD fs0;
+    NTSTATUS status;
+    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);
@@ -1015,7 +2318,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;
@@ -1058,7 +2366,7 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     if (0 == Ntm->ntmFlags) Ntm->ntmFlags = NTM_REGULAR;
 
     Ntm->ntmSizeEM = Otm->otmEMSquare;
-    Ntm->ntmCellHeight = 0;
+    Ntm->ntmCellHeight = Otm->otmEMSquare;
     Ntm->ntmAvgWidth = 0;
 
     Info->FontType = (0 != (TM->tmPitchAndFamily & TMPF_TRUETYPE)
@@ -1067,83 +2375,101 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
         Info->FontType |= RASTER_FONTTYPE;
 
-    ExFreePoolWithTag(Otm, GDITAG_TEXT);
 
-    RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
-                     sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
-                     FaceName);
+    /* face name */
+    if (!FaceName)
+        FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
+
+    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),
-                     FaceName);
-    RtlInitAnsiString(&StyleA, FontGDI->face->style_name);
+                     FullName);
+
+    ExFreePoolWithTag(Otm, GDITAG_TEXT);
+
+    RtlInitAnsiString(&StyleA, Face->style_name);
     StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
     StyleW.MaximumLength = sizeof(Info->EnumLogFontEx.elfStyle);
-    RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
+    status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE);
+    if (!NT_SUCCESS(status))
+    {
+        return;
+    }
+    Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
 
-    Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
-    Info->EnumLogFontEx.elfScript[0] = L'\0';
-    IntLockFreeType;
-    pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
-    IntUnLockFreeType;
-    if (NULL != pOS2)
+    IntLockFreeType();
+    pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
+
+    if (!pOS2)
     {
-        fs.fsCsb[0] = pOS2->ulCodePageRange1;
-        fs.fsCsb[1] = pOS2->ulCodePageRange2;
-        fs.fsUsb[0] = pOS2->ulUnicodeRange1;
-        fs.fsUsb[1] = pOS2->ulUnicodeRange2;
-        fs.fsUsb[2] = pOS2->ulUnicodeRange3;
-        fs.fsUsb[3] = pOS2->ulUnicodeRange4;
+        IntUnLockFreeType();
+        return;
+    }
 
-        if (0 == pOS2->version)
-        {
-            FT_UInt Dummy;
+    fs.fsCsb[0] = pOS2->ulCodePageRange1;
+    fs.fsCsb[1] = pOS2->ulCodePageRange2;
+    fs.fsUsb[0] = pOS2->ulUnicodeRange1;
+    fs.fsUsb[1] = pOS2->ulUnicodeRange2;
+    fs.fsUsb[2] = pOS2->ulUnicodeRange3;
+    fs.fsUsb[3] = pOS2->ulUnicodeRange4;
 
-            if (FT_Get_First_Char(FontGDI->face, &Dummy) < 0x100)
+    if (0 == pOS2->version)
+    {
+        FT_UInt Dummy;
+
+        if (FT_Get_First_Char(Face, &Dummy) < 0x100)
+            fs.fsCsb[0] |= FS_LATIN1;
+        else
+            fs.fsCsb[0] |= FS_SYMBOL;
+    }
+    IntUnLockFreeType();
+
+    if (fs.fsCsb[0] == 0)
+    {
+        /* Let's see if we can find any interesting cmaps */
+        for (i = 0; i < (UINT)Face->num_charmaps; i++)
+        {
+            switch (Face->charmaps[i]->encoding)
+            {
+            case FT_ENCODING_UNICODE:
+            case FT_ENCODING_APPLE_ROMAN:
                 fs.fsCsb[0] |= FS_LATIN1;
-            else
+                break;
+            case FT_ENCODING_MS_SYMBOL:
                 fs.fsCsb[0] |= FS_SYMBOL;
-        }
-        if (fs.fsCsb[0] == 0)
-        { /* Let's see if we can find any interesting cmaps */
-            for (i = 0; i < FontGDI->face->num_charmaps; i++)
-            {
-                switch (FontGDI->face->charmaps[i]->encoding)
-                {
-                case FT_ENCODING_UNICODE:
-                case FT_ENCODING_APPLE_ROMAN:
-                    fs.fsCsb[0] |= FS_LATIN1;
-                    break;
-                case FT_ENCODING_MS_SYMBOL:
-                    fs.fsCsb[0] |= FS_SYMBOL;
-                    break;
-                default:
-                    break;
-                }
+                break;
+            default:
+                break;
             }
         }
-        for (i = 0; i < MAXTCIINDEX; i++)
+    }
+
+    for (i = 0; i < MAXTCIINDEX; i++)
+    {
+        fs0 = 1L << i;
+        if (fs.fsCsb[0] & fs0)
         {
-            fs0 = 1L << i;
-            if (fs.fsCsb[0] & fs0)
+            if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
             {
-                if (!IntTranslateCharsetInfo(&fs0, &CharSetInfo, TCI_SRCFONTSIG))
-                {
-                    CharSetInfo.ciCharset = DEFAULT_CHARSET;
-                }
-                if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
+                CharSetInfo.ciCharset = DEFAULT_CHARSET;
+            }
+            if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
+            {
+                if (g_ElfScripts[i])
+                    wcscpy(Info->EnumLogFontEx.elfScript, g_ElfScripts[i]);
+                else
                 {
-                    Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
-                    if (NULL != ElfScripts[i])
-                        wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
-                    else
-                    {
-                        DPRINT1("Unknown elfscript for bit %u\n", i);
-                    }
+                    DPRINT1("Unknown elfscript for bit %u\n", i);
                 }
             }
         }
-        Info->NewTextMetricEx.ntmFontSig = fs;
     }
+    Info->NewTextMetricEx.ntmFontSig = fs;
 }
 
 static int FASTCALL
@@ -1155,7 +2481,7 @@ FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEnt
     for (i = 0; i < InfoEntries; i++)
     {
         RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
-        if (0 == RtlCompareUnicodeString(&InfoFaceName, FaceName, TRUE))
+        if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
         {
             return i;
         }
@@ -1171,8 +2497,8 @@ FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
     UNICODE_STRING LogFontFaceName;
 
     RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
-    if (0 != LogFontFaceName.Length
-            && 0 != RtlCompareUnicodeString(&LogFontFaceName, FaceName, TRUE))
+    if (0 != LogFontFaceName.Length &&
+        !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
     {
         return FALSE;
     }
@@ -1180,157 +2506,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;
+    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->face->family_name);
-        RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
-        if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+        if (LogFont->lfCharSet != DEFAULT_CHARSET &&
+            LogFont->lfCharSet != FontGDI->CharSet)
         {
-            EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
-            EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+            continue;
         }
 
-        if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
+        if (LogFont->lfFaceName[0] == UNICODE_NULL)
         {
-            if (*Count < Size)
+            if (Count < MaxCount)
             {
-                FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
+                FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
             }
-            (*Count)++;
+            Count++;
+            continue;
         }
-        RtlFreeUnicodeString(&EntryFaceNameW);
-        Entry = Entry->Flink;
-    }
-
-    return TRUE;
-}
-
-typedef struct FontFamilyInfoCallbackContext
-{
-    LPLOGFONTW LogFont;
-    PFONTFAMILYINFO Info;
-    DWORD Count;
-    DWORD Size;
-} FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
-
-static NTSTATUS APIENTRY
-FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
-                                    IN PVOID ValueData, IN ULONG ValueLength,
-                                    IN PVOID Context, IN PVOID EntryContext)
-{
-    PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
-    UNICODE_STRING RegistryName, RegistryValue;
-    int Existing;
-    PFONTGDI FontGDI;
-
-    if (REG_SZ != ValueType)
-    {
-        return STATUS_SUCCESS;
-    }
-    InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
-    RtlInitUnicodeString(&RegistryName, ValueName);
 
-    /* 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)
-        {
-            /* 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;
-        }
+        FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
 
-        /* Try to find information about the "real" font */
-        FontGDI = FindFaceNameInLists(&RegistryValue);
-        if (NULL == FontGDI)
+        if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0 &&
+            _wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0)
         {
-            /* "Real" font not found, discard this registry entry */
-            return STATUS_SUCCESS;
+            continue;
         }
 
-        /* Return info about the "real" font but with the name of the alias */
-        if (InfoContext->Count < InfoContext->Size)
+        if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
         {
-            FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
-                               RegistryName.Buffer, FontGDI);
+            if (Count < MaxCount)
+            {
+                RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
+            }
+            Count++;
         }
-        InfoContext->Count++;
-        return STATUS_SUCCESS;
     }
 
-    return STATUS_SUCCESS;
+    *pCount = Count;
+
+    return TRUE;
 }
 
 static BOOLEAN FASTCALL
 GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
                                 PFONTFAMILYINFO Info,
-                                DWORD *Count,
-                                DWORD Size)
+                                DWORD *pCount,
+                                DWORD MaxCount)
 {
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
-    FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
-    NTSTATUS Status;
+    PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
+    PFONTSUBST_ENTRY pCurrentEntry;
+    PUNICODE_STRING pFromW;
+    FONTGDI *FontGDI;
+    LOGFONTW lf = *LogFont;
+    UNICODE_STRING NameW;
 
-    /* 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))
+    for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
     {
-        *Count = Context.Count;
+        pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
+
+        pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
+        if (LogFont->lfFaceName[0] != UNICODE_NULL)
+        {
+            if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount)))
+                continue;   /* mismatch */
+        }
+
+        RtlStringCchCopyW(lf.lfFaceName, LF_FACESIZE, pFromW->Buffer);
+        SubstituteFontRecurse(&lf);
+
+        RtlInitUnicodeString(&NameW, lf.lfFaceName);
+        FontGDI = FindFaceNameInLists(&NameW);
+        if (FontGDI == NULL)
+        {
+            continue;   /* no real font */
+        }
+
+        if (*pCount < MaxCount)
+        {
+            FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI);
+        }
+        (*pCount)++;
     }
 
-    return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
+    return TRUE;
 }
 
 BOOL
@@ -1365,33 +2664,79 @@ ftGdiGlyphCacheGet(
     FT_Face Face,
     INT GlyphIndex,
     INT Height,
+    FT_Render_Mode RenderMode,
     PMATRIX pmx)
 {
     PLIST_ENTRY CurrentEntry;
     PFONT_CACHE_ENTRY FontEntry;
 
-    CurrentEntry = FontCacheListHead.Flink;
-    while (CurrentEntry != &FontCacheListHead)
+    ASSERT_FREETYPE_LOCK_HELD();
+
+    for (CurrentEntry = g_FontCacheListHead.Flink;
+         CurrentEntry != &g_FontCacheListHead;
+         CurrentEntry = CurrentEntry->Flink)
     {
-        FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
+        FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
         if ((FontEntry->Face == Face) &&
             (FontEntry->GlyphIndex == GlyphIndex) &&
             (FontEntry->Height == Height) &&
+            (FontEntry->RenderMode == RenderMode) &&
             (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
             break;
-        CurrentEntry = CurrentEntry->Flink;
     }
 
-    if (CurrentEntry == &FontCacheListHead)
+    if (CurrentEntry == &g_FontCacheListHead)
     {
         return NULL;
     }
 
     RemoveEntryList(CurrentEntry);
-    InsertHeadList(&FontCacheListHead, CurrentEntry);
+    InsertHeadList(&g_FontCacheListHead, CurrentEntry);
     return FontEntry->BitmapGlyph;
 }
 
+/* no cache */
+FT_BitmapGlyph APIENTRY
+ftGdiGlyphSet(
+    FT_Face Face,
+    FT_GlyphSlot GlyphSlot,
+    FT_Render_Mode RenderMode)
+{
+    FT_Glyph Glyph;
+    INT error;
+    FT_Bitmap AlignedBitmap;
+    FT_BitmapGlyph BitmapGlyph;
+
+    error = FT_Get_Glyph(GlyphSlot, &Glyph);
+    if (error)
+    {
+        DPRINT1("Failure getting glyph.\n");
+        return NULL;
+    }
+
+    error = FT_Glyph_To_Bitmap(&Glyph, RenderMode, 0, 1);
+    if (error)
+    {
+        FT_Done_Glyph(Glyph);
+        DPRINT1("Failure rendering glyph.\n");
+        return NULL;
+    }
+
+    BitmapGlyph = (FT_BitmapGlyph)Glyph;
+    FT_Bitmap_New(&AlignedBitmap);
+    if (FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
+    {
+        DPRINT1("Conversion failed\n");
+        FT_Done_Glyph((FT_Glyph)BitmapGlyph);
+        return NULL;
+    }
+
+    FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
+    BitmapGlyph->bitmap = AlignedBitmap;
+
+    return BitmapGlyph;
+}
+
 FT_BitmapGlyph APIENTRY
 ftGdiGlyphCacheSet(
     FT_Face Face,
@@ -1407,6 +2752,8 @@ ftGdiGlyphCacheSet(
     FT_Bitmap AlignedBitmap;
     FT_BitmapGlyph BitmapGlyph;
 
+    ASSERT_FREETYPE_LOCK_HELD();
+
     error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
     if (error)
     {
@@ -1414,87 +2761,501 @@ ftGdiGlyphCacheSet(
         return NULL;
     };
 
-    error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
-    if (error)
+    error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
+    if (error)
+    {
+        FT_Done_Glyph(GlyphCopy);
+        DPRINT1("Failure rendering glyph.\n");
+        return NULL;
+    };
+
+    NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
+    if (!NewEntry)
+    {
+        DPRINT1("Alloc failure caching glyph.\n");
+        FT_Done_Glyph(GlyphCopy);
+        return NULL;
+    }
+
+    BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
+    FT_Bitmap_New(&AlignedBitmap);
+    if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
+    {
+        DPRINT1("Conversion failed\n");
+        ExFreePoolWithTag(NewEntry, TAG_FONT);
+        FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
+        FT_Done_Glyph((FT_Glyph)BitmapGlyph);
+        return NULL;
+    }
+
+    FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
+    BitmapGlyph->bitmap = AlignedBitmap;
+
+    NewEntry->GlyphIndex = GlyphIndex;
+    NewEntry->Face = Face;
+    NewEntry->BitmapGlyph = BitmapGlyph;
+    NewEntry->Height = Height;
+    NewEntry->RenderMode = RenderMode;
+    NewEntry->mxWorldToDevice = *pmx;
+
+    InsertHeadList(&g_FontCacheListHead, &NewEntry->ListEntry);
+    if (++g_FontCacheNumEntries > MAX_FONT_CACHE)
+    {
+        NewEntry = CONTAINING_RECORD(g_FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
+        RemoveCachedEntry(NewEntry);
+    }
+
+    return BitmapGlyph;
+}
+
+
+static void FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
+{
+    pt->x.value = vec->x >> 6;
+    pt->x.fract = (vec->x & 0x3f) << 10;
+    pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
+    pt->y.value = vec->y >> 6;
+    pt->y.fract = (vec->y & 0x3f) << 10;
+    pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
+}
+
+/*
+   This function builds an FT_Fixed from a float. It puts the integer part
+   in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
+   It fails if the integer part of the float number is greater than SHORT_MAX.
+*/
+static __inline FT_Fixed FT_FixedFromFloat(float f)
+{
+    short value = f;
+    unsigned short fract = (f - value) * 0xFFFF;
+    return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
+}
+
+/*
+   This function builds an FT_Fixed from a FIXED. It simply put f.value
+   in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
+*/
+static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
+{
+    return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
+}
+
+static unsigned int get_native_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
+{
+    TTPOLYGONHEADER *pph;
+    TTPOLYCURVE *ppc;
+    int needed = 0, point = 0, contour, first_pt;
+    unsigned int pph_start, cpfx;
+    DWORD type;
+
+    for (contour = 0; contour < outline->n_contours; contour++)
+    {
+        /* Ignore contours containing one point */
+        if (point == outline->contours[contour])
+        {
+            point++;
+            continue;
+        }
+
+        pph_start = needed;
+        pph = (TTPOLYGONHEADER *)(buf + needed);
+        first_pt = point;
+        if (buf)
+        {
+            pph->dwType = TT_POLYGON_TYPE;
+            FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+        }
+        needed += sizeof(*pph);
+        point++;
+        while (point <= outline->contours[contour])
+        {
+            ppc = (TTPOLYCURVE *)(buf + needed);
+            type = outline->tags[point] & FT_Curve_Tag_On ?
+                TT_PRIM_LINE : TT_PRIM_QSPLINE;
+            cpfx = 0;
+            do
+            {
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                cpfx++;
+                point++;
+            } while (point <= outline->contours[contour] &&
+                    (outline->tags[point] & FT_Curve_Tag_On) ==
+                    (outline->tags[point-1] & FT_Curve_Tag_On));
+            /* At the end of a contour Windows adds the start point, but
+               only for Beziers */
+            if (point > outline->contours[contour] &&
+               !(outline->tags[point-1] & FT_Curve_Tag_On))
+            {
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
+                cpfx++;
+            }
+            else if (point <= outline->contours[contour] &&
+                      outline->tags[point] & FT_Curve_Tag_On)
+            {
+                /* add closing pt for bezier */
+                if (buf)
+                    FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                cpfx++;
+                point++;
+            }
+            if (buf)
+            {
+                ppc->wType = type;
+                ppc->cpfx = cpfx;
+            }
+            needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+        }
+        if (buf)
+            pph->cb = needed - pph_start;
+    }
+    return needed;
+}
+
+static unsigned int get_bezier_glyph_outline(FT_Outline *outline, unsigned int buflen, char *buf)
+{
+    /* Convert the quadratic Beziers to cubic Beziers.
+       The parametric eqn for a cubic Bezier is, from PLRM:
+       r(t) = at^3 + bt^2 + ct + r0
+       with the control points:
+       r1 = r0 + c/3
+       r2 = r1 + (c + b)/3
+       r3 = r0 + c + b + a
+
+       A quadratic Bezier has the form:
+       p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
+
+       So equating powers of t leads to:
+       r1 = 2/3 p1 + 1/3 p0
+       r2 = 2/3 p1 + 1/3 p2
+       and of course r0 = p0, r3 = p2
+    */
+    int contour, point = 0, first_pt;
+    TTPOLYGONHEADER *pph;
+    TTPOLYCURVE *ppc;
+    DWORD pph_start, cpfx, type;
+    FT_Vector cubic_control[4];
+    unsigned int needed = 0;
+
+    for (contour = 0; contour < outline->n_contours; contour++)
+    {
+        pph_start = needed;
+        pph = (TTPOLYGONHEADER *)(buf + needed);
+        first_pt = point;
+        if (buf)
+        {
+            pph->dwType = TT_POLYGON_TYPE;
+            FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+        }
+        needed += sizeof(*pph);
+        point++;
+        while (point <= outline->contours[contour])
+        {
+            ppc = (TTPOLYCURVE *)(buf + needed);
+            type = outline->tags[point] & FT_Curve_Tag_On ?
+                TT_PRIM_LINE : TT_PRIM_CSPLINE;
+            cpfx = 0;
+            do
+            {
+                if (type == TT_PRIM_LINE)
+                {
+                    if (buf)
+                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+                    cpfx++;
+                    point++;
+                }
+                else
+                {
+                    /* Unlike QSPLINEs, CSPLINEs always have their endpoint
+                       so cpfx = 3n */
+
+                    /* FIXME: Possible optimization in endpoint calculation
+                       if there are two consecutive curves */
+                    cubic_control[0] = outline->points[point-1];
+                    if (!(outline->tags[point-1] & FT_Curve_Tag_On))
+                    {
+                        cubic_control[0].x += outline->points[point].x + 1;
+                        cubic_control[0].y += outline->points[point].y + 1;
+                        cubic_control[0].x >>= 1;
+                        cubic_control[0].y >>= 1;
+                    }
+                    if (point+1 > outline->contours[contour])
+                        cubic_control[3] = outline->points[first_pt];
+                    else
+                    {
+                        cubic_control[3] = outline->points[point+1];
+                        if (!(outline->tags[point+1] & FT_Curve_Tag_On))
+                        {
+                            cubic_control[3].x += outline->points[point].x + 1;
+                            cubic_control[3].y += outline->points[point].y + 1;
+                            cubic_control[3].x >>= 1;
+                            cubic_control[3].y >>= 1;
+                        }
+                    }
+                    /* r1 = 1/3 p0 + 2/3 p1
+                       r2 = 1/3 p2 + 2/3 p1 */
+                    cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
+                    cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
+                    cubic_control[2] = cubic_control[1];
+                    cubic_control[1].x += (cubic_control[0].x + 1) / 3;
+                    cubic_control[1].y += (cubic_control[0].y + 1) / 3;
+                    cubic_control[2].x += (cubic_control[3].x + 1) / 3;
+                    cubic_control[2].y += (cubic_control[3].y + 1) / 3;
+                    if (buf)
+                    {
+                        FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
+                        FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
+                        FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
+                    }
+                    cpfx += 3;
+                    point++;
+                }
+            } while (point <= outline->contours[contour] &&
+                    (outline->tags[point] & FT_Curve_Tag_On) ==
+                    (outline->tags[point-1] & FT_Curve_Tag_On));
+            /* At the end of a contour Windows adds the start point,
+               but only for Beziers and we've already done that.
+            */
+            if (point <= outline->contours[contour] &&
+               outline->tags[point] & FT_Curve_Tag_On)
+            {
+                /* This is the closing pt of a bezier, but we've already
+                   added it, so just inc point and carry on */
+                point++;
+            }
+            if (buf)
+            {
+                ppc->wType = type;
+                ppc->cpfx = cpfx;
+            }
+            needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+        }
+        if (buf)
+            pph->cb = needed - pph_start;
+    }
+    return needed;
+}
+
+static FT_Error
+IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
+{
+    FT_Error error;
+    FT_Size_RequestRec  req;
+    FT_Face face = FontGDI->SharedFace->Face;
+    TT_OS2 *pOS2;
+    TT_HoriHeader *pHori;
+    FT_WinFNT_HeaderRec WinFNT;
+    LONG Ascent, Descent, Sum, EmHeight64;
+
+    lfWidth = abs(lfWidth);
+    if (lfHeight == 0)
+    {
+        if (lfWidth == 0)
+        {
+            DPRINT("lfHeight and lfWidth are zero.\n");
+            lfHeight = -16;
+        }
+        else
+        {
+            lfHeight = lfWidth;
+        }
+    }
+
+    if (lfHeight == -1)
+        lfHeight = -2;
+
+    ASSERT_FREETYPE_LOCK_HELD();
+    pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
+    pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
+
+    if (!pOS2 || !pHori)
     {
-        FT_Done_Glyph(GlyphCopy);
-        DPRINT1("Failure rendering glyph.\n");
-        return NULL;
-    };
+        error = FT_Get_WinFNT_Header(face, &WinFNT);
+        if (error)
+            return error;
+
+        FontGDI->tmHeight           = WinFNT.pixel_height;
+        FontGDI->tmAscent           = WinFNT.ascent;
+        FontGDI->tmDescent          = FontGDI->tmHeight - FontGDI->tmAscent;
+        FontGDI->tmInternalLeading  = WinFNT.internal_leading;
+        FontGDI->EmHeight           = FontGDI->tmHeight - FontGDI->tmInternalLeading;
+        FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
+        FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
+        FontGDI->Magic = FONTGDI_MAGIC;
+
+        req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
+        req.width          = 0;
+        req.height         = (FT_Long)(FontGDI->EmHeight << 6);
+        req.horiResolution = 0;
+        req.vertResolution = 0;
+        return FT_Request_Size(face, &req);
+    }
+
+    if (lfHeight > 0)
+    {
+        /* case (A): lfHeight is positive */
+        Sum = pOS2->usWinAscent + pOS2->usWinDescent;
+        if (Sum == 0)
+        {
+            Ascent = pHori->Ascender;
+            Descent = -pHori->Descender;
+            Sum = Ascent + Descent;
+        }
+        else
+        {
+            Ascent = pOS2->usWinAscent;
+            Descent = pOS2->usWinDescent;
+        }
 
-    NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
-    if (!NewEntry)
+        FontGDI->tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
+        FontGDI->tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
+        FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
+        FontGDI->tmInternalLeading = FontGDI->tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
+    }
+    else if (lfHeight < 0)
     {
-        DPRINT1("Alloc failure caching glyph.\n");
-        FT_Done_Glyph(GlyphCopy);
-        return NULL;
+        /* case (B): lfHeight is negative */
+        FontGDI->tmAscent = FT_MulDiv(-lfHeight, pOS2->usWinAscent, face->units_per_EM);
+        FontGDI->tmDescent = FT_MulDiv(-lfHeight, pOS2->usWinDescent, face->units_per_EM);
+        FontGDI->tmHeight = FontGDI->tmAscent + FontGDI->tmDescent;
+        FontGDI->tmInternalLeading = FontGDI->tmHeight + lfHeight;
     }
 
-    BitmapGlyph = (FT_BitmapGlyph)GlyphCopy;
-    FT_Bitmap_New(&AlignedBitmap);
-    if(FT_Bitmap_Convert(GlyphSlot->library, &BitmapGlyph->bitmap, &AlignedBitmap, 4))
+    FontGDI->EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
+    FontGDI->EmHeight = max(FontGDI->EmHeight, 1);
+    FontGDI->EmHeight = min(FontGDI->EmHeight, USHORT_MAX);
+    FontGDI->Magic = FONTGDI_MAGIC;
+
+    if (lfHeight > 0)
+        EmHeight64 = (FontGDI->EmHeight << 6) + 31;
+    else
+        EmHeight64 = (FontGDI->EmHeight << 6);
+
+    req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
+    req.width          = 0;
+    req.height         = EmHeight64;
+    req.horiResolution = 0;
+    req.vertResolution = 0;
+    return FT_Request_Size(face, &req);
+}
+
+BOOL
+FASTCALL
+TextIntUpdateSize(PDC dc,
+                  PTEXTOBJ TextObj,
+                  PFONTGDI FontGDI,
+                  BOOL bDoLock)
+{
+    FT_Face face;
+    INT error, n;
+    FT_CharMap charmap, found;
+    LOGFONTW *plf;
+
+    if (bDoLock)
+        IntLockFreeType();
+
+    face = FontGDI->SharedFace->Face;
+    if (face->charmap == NULL)
     {
-        DPRINT1("Conversion failed\n");
-        ExFreePoolWithTag(NewEntry, TAG_FONT);
-        FT_Done_Glyph((FT_Glyph)BitmapGlyph);
-        return NULL;
+        DPRINT("WARNING: No charmap selected!\n");
+        DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+
+        found = NULL;
+        for (n = 0; n < face->num_charmaps; n++)
+        {
+            charmap = face->charmaps[n];
+            if (charmap->encoding == FT_ENCODING_UNICODE)
+            {
+                found = charmap;
+                break;
+            }
+        }
+        if (!found)
+        {
+            for (n = 0; n < face->num_charmaps; n++)
+            {
+                charmap = face->charmaps[n];
+                if (charmap->encoding == FT_ENCODING_MS_SYMBOL)
+                {
+                    found = charmap;
+                    break;
+                }
+            }
+        }
+        if (!found)
+        {
+            DPRINT1("WARNING: Could not find desired charmap!\n");
+        }
+        else
+        {
+            DPRINT("Found charmap encoding: %i\n", found->encoding);
+            error = FT_Set_Charmap(face, found);
+            if (error)
+            {
+                DPRINT1("WARNING: Could not set the charmap!\n");
+            }
+        }
     }
 
-    FT_Bitmap_Done(GlyphSlot->library, &BitmapGlyph->bitmap);
-    BitmapGlyph->bitmap = AlignedBitmap;
+    plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
 
-    NewEntry->GlyphIndex = GlyphIndex;
-    NewEntry->Face = Face;
-    NewEntry->BitmapGlyph = BitmapGlyph;
-    NewEntry->Height = Height;
-    NewEntry->mxWorldToDevice = *pmx;
+    error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
 
-    InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
-    if (FontCacheNumEntries++ > MAX_FONT_CACHE)
+    if (bDoLock)
+        IntUnLockFreeType();
+
+    if (error)
     {
-        NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
-        FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
-        RemoveTailList(&FontCacheListHead);
-        ExFreePoolWithTag(NewEntry, TAG_FONT);
-        FontCacheNumEntries--;
+        DPRINT1("Error in setting pixel sizes: %d\n", error);
+        return FALSE;
     }
 
-    return BitmapGlyph;
+    return TRUE;
 }
 
-
-static
-void
-FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
+static inline FT_UInt FASTCALL
+get_glyph_index_symbol(FT_Face ft_face, UINT glyph)
 {
-    pt->x.value = vec->x >> 6;
-    pt->x.fract = (vec->x & 0x3f) << 10;
-    pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
-    pt->y.value = vec->y >> 6;
-    pt->y.fract = (vec->y & 0x3f) << 10;
-    pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
-    return;
+    FT_UInt ret;
+
+    if (glyph < 0x100) glyph += 0xf000;
+    /* there are a number of old pre-Unicode "broken" TTFs, which
+       do have symbols at U+00XX instead of U+f0XX */
+    if (!(ret = FT_Get_Char_Index(ft_face, glyph)))
+        ret = FT_Get_Char_Index(ft_face, glyph - 0xf000);
+
+    return ret;
 }
 
-/*
-   This function builds an FT_Fixed from a float. It puts the integer part
-   in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
-   It fails if the integer part of the float number is greater than SHORT_MAX.
-*/
-static __inline FT_Fixed FT_FixedFromFloat(float f)
+static inline FT_UInt FASTCALL
+get_glyph_index(FT_Face ft_face, UINT glyph)
 {
-    short value = f;
-    unsigned short fract = (f - value) * 0xFFFF;
-    return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
+    FT_UInt ret;
+
+    if (face_has_symbol_charmap(ft_face))
+    {
+        ret = get_glyph_index_symbol(ft_face, glyph);
+        if (ret != 0)
+            return ret;
+    }
+
+    return FT_Get_Char_Index(ft_face, glyph);
 }
 
-/*
-   This function builds an FT_Fixed from a FIXED. It simply put f.value
-   in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
-*/
-static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
+static inline FT_UInt FASTCALL
+get_glyph_index_flagged(FT_Face face, FT_ULong code, DWORD indexed_flag, DWORD flags)
 {
-    return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
+    FT_UInt glyph_index;
+    if (flags & indexed_flag)
+    {
+        glyph_index = code;
+    }
+    else
+    {
+        glyph_index = get_glyph_index(face, code);
+    }
+    return glyph_index;
 }
 
 /*
@@ -1535,9 +3296,8 @@ ftGdiGetGlyphOutline(
     LONG aveWidth;
     INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
     OUTLINETEXTMETRICW *potm;
-    int n = 0;
-    FT_CharMap found = 0, charmap;
     XFORM xForm;
+    LOGFONTW *plf;
 
     DPRINT("%u, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
            cjBuf, pvBuf, pmat2);
@@ -1556,10 +3316,11 @@ ftGdiGetGlyphOutline(
         return GDI_ERROR;
     }
     FontGDI = ObjToGDI(TextObj->Font, FONT);
-    ft_face = FontGDI->face;
+    ft_face = FontGDI->SharedFace->Face;
 
-    aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
-    orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
+    plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+    aveWidth = FT_IS_SCALABLE(ft_face) ? abs(plf->lfWidth) : 0;
+    orientation = FT_IS_SCALABLE(ft_face) ? plf->lfOrientation : 0;
 
     Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
     potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
@@ -1569,52 +3330,23 @@ ftGdiGetGlyphOutline(
         TEXTOBJ_UnlockText(TextObj);
         return GDI_ERROR;
     }
-    IntGetOutlineTextMetrics(FontGDI, Size, potm);
-
-    IntLockFreeType;
-
-    /* During testing, I never saw this used. It is here just in case. */
-    if (ft_face->charmap == NULL)
+    Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
+    if (!Size)
     {
-        DPRINT("WARNING: No charmap selected!\n");
-        DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
-
-        for (n = 0; n < ft_face->num_charmaps; n++)
-        {
-            charmap = ft_face->charmaps[n];
-            DPRINT("Found charmap encoding: %u\n", charmap->encoding);
-            if (charmap->encoding != 0)
-            {
-                found = charmap;
-                break;
-            }
-        }
-        if (!found)
-        {
-            DPRINT1("WARNING: Could not find desired charmap!\n");
-        }
-        error = FT_Set_Charmap(ft_face, found);
-        if (error)
-        {
-            DPRINT1("WARNING: Could not set the charmap!\n");
-        }
+        /* FIXME: last error? */
+        ExFreePoolWithTag(potm, GDITAG_TEXT);
+        TEXTOBJ_UnlockText(TextObj);
+        return GDI_ERROR;
     }
 
-//  FT_Set_Pixel_Sizes(ft_face,
-//                     TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
-    /* FIXME: Should set character height if neg */
-//                     (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-//                      dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
-//    FtSetCoordinateTransform(face, DC_pmxWorldToDevice(dc));
+    IntLockFreeType();
+    TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
+    FtSetCoordinateTransform(ft_face, DC_pmxWorldToDevice(dc));
 
     TEXTOBJ_UnlockText(TextObj);
 
-    if (iFormat & GGO_GLYPH_INDEX)
-    {
-        glyph_index = wch;
-        iFormat &= ~GGO_GLYPH_INDEX;
-    }
-    else  glyph_index = FT_Get_Char_Index(ft_face, wch);
+    glyph_index = get_glyph_index_flagged(ft_face, wch, GGO_GLYPH_INDEX, iFormat);
+    iFormat &= ~GGO_GLYPH_INDEX;
 
     if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
         load_flags |= FT_LOAD_NO_BITMAP;
@@ -1629,11 +3361,11 @@ ftGdiGetGlyphOutline(
     if (error)
     {
         DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
-        IntUnLockFreeType;
+        IntUnLockFreeType();
         if (potm) ExFreePoolWithTag(potm, GDITAG_TEXT);
         return GDI_ERROR;
     }
-    IntUnLockFreeType;
+    IntUnLockFreeType();
 
     if (aveWidth && potm)
     {
@@ -1651,15 +3383,25 @@ ftGdiGetGlyphOutline(
 
     DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
 
-    IntLockFreeType;
+    IntLockFreeType();
 
-    /* Scaling transform */
-    /*if (aveWidth)*/
+    /* Width scaling transform */
+    if (widthRatio != 1.0)
     {
+        FT_Matrix scaleMat;
+        scaleMat.xx = FT_FixedFromFloat(widthRatio);
+        scaleMat.xy = 0;
+        scaleMat.yx = 0;
+        scaleMat.yy = FT_FixedFromFloat(1.0);
+
+        FT_Matrix_Multiply(&scaleMat, &transMat);
+        needsTransform = TRUE;
+    }
 
+    /* World transform */
+    {
         FT_Matrix ftmatrix;
         FLOATOBJ efTemp;
-
         PMATRIX pmx = DC_pmxWorldToDevice(dc);
 
         /* Create a freetype matrix, by converting to 16.16 fixpoint format */
@@ -1679,21 +3421,11 @@ ftGdiGetGlyphOutline(
         FLOATOBJ_MulLong(&efTemp, 0x00010000);
         ftmatrix.yy = FLOATOBJ_GetLong(&efTemp);
 
-        FT_Matrix_Multiply(&ftmatrix, &transMat);
-        needsTransform = TRUE;
-    }
-
-    /* Slant transform */
-    if (potm->otmTextMetrics.tmItalic)
-    {
-        FT_Matrix slantMat;
-        DPRINT("Slant Trans!\n");
-        slantMat.xx = (1 << 16);
-        slantMat.xy = ((1 << 16) >> 2);
-        slantMat.yx = 0;
-        slantMat.yy = (1 << 16);
-        FT_Matrix_Multiply(&slantMat, &transMat);
-        needsTransform = TRUE;
+        if (memcmp(&ftmatrix, &identityMat, sizeof(identityMat)) != 0)
+        {
+            FT_Matrix_Multiply(&ftmatrix, &transMat);
+            needsTransform = TRUE;
+        }
     }
 
     /* Rotation transform */
@@ -1786,13 +3518,13 @@ ftGdiGetGlyphOutline(
            gm.gmBlackBoxX, gm.gmBlackBoxY,
            gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
 
-    IntUnLockFreeType;
+    IntUnLockFreeType();
 
-    if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
 
     if (iFormat == GGO_METRICS)
     {
         DPRINT("GGO_METRICS Exit!\n");
+        *pgm = gm;
         return 1; /* FIXME */
     }
 
@@ -1811,14 +3543,17 @@ ftGdiGetGlyphOutline(
         needed = pitch * height;
 
         if (!pvBuf || !cjBuf) break;
+        if (!needed) return GDI_ERROR;  /* empty glyph */
+        if (needed > cjBuf)
+            return GDI_ERROR;
 
         switch (ft_face->glyph->format)
         {
         case ft_glyph_format_bitmap:
         {
             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
-            INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
-            INT h = ft_face->glyph->bitmap.rows;
+            INT w = min( pitch, (ft_face->glyph->bitmap.width + 7) >> 3 );
+            INT h = min( height, ft_face->glyph->bitmap.rows );
             while (h--)
             {
                 RtlCopyMemory(dst, src, w);
@@ -1832,10 +3567,10 @@ ftGdiGetGlyphOutline(
             ft_bitmap.width = width;
             ft_bitmap.rows = height;
             ft_bitmap.pitch = pitch;
-            ft_bitmap.pixel_mode = ft_pixel_mode_mono;
+            ft_bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
             ft_bitmap.buffer = pvBuf;
 
-            IntLockFreeType;
+            IntLockFreeType();
             if (needsTransform)
             {
                 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
@@ -1843,8 +3578,8 @@ ftGdiGetGlyphOutline(
             FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
             /* Note: FreeType will only set 'black' bits for us. */
             RtlZeroMemory(pvBuf, needed);
-            FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
-            IntUnLockFreeType;
+            FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
+            IntUnLockFreeType();
             break;
 
         default:
@@ -1866,17 +3601,20 @@ ftGdiGetGlyphOutline(
         needed = pitch * height;
 
         if (!pvBuf || !cjBuf) break;
+        if (!needed) return GDI_ERROR;  /* empty glyph */
+        if (needed > cjBuf)
+            return GDI_ERROR;
 
         switch (ft_face->glyph->format)
         {
         case ft_glyph_format_bitmap:
         {
             BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
-            INT h = ft_face->glyph->bitmap.rows;
+            INT h = min( height, ft_face->glyph->bitmap.rows );
             INT x;
             while (h--)
             {
-                for (x = 0; x < pitch; x++)
+                for (x = 0; (UINT)x < pitch; x++)
                 {
                     if (x < ft_face->glyph->bitmap.width)
                         dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
@@ -1886,25 +3624,25 @@ ftGdiGetGlyphOutline(
                 src += ft_face->glyph->bitmap.pitch;
                 dst += pitch;
             }
-            return needed;
+            break;
         }
         case ft_glyph_format_outline:
         {
             ft_bitmap.width = width;
             ft_bitmap.rows = height;
             ft_bitmap.pitch = pitch;
-            ft_bitmap.pixel_mode = ft_pixel_mode_grays;
+            ft_bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
             ft_bitmap.buffer = pvBuf;
 
-            IntLockFreeType;
+            IntLockFreeType();
             if (needsTransform)
             {
                 FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
             }
             FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
             RtlZeroMemory(ft_bitmap.buffer, cjBuf);
-            FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
-            IntUnLockFreeType;
+            FT_Outline_Get_Bitmap(g_FreeTypeLibrary, &ft_face->glyph->outline, &ft_bitmap);
+            IntUnLockFreeType();
 
             if (iFormat == GGO_GRAY2_BITMAP)
                 mult = 4;
@@ -1916,225 +3654,70 @@ ftGdiGetGlyphOutline(
             {
                 return GDI_ERROR;
             }
+
+            start = pvBuf;
+            for (row = 0; row < height; row++)
+            {
+                ptr = start;
+                for (col = 0; col < width; col++, ptr++)
+                {
+                    *ptr = (((int)*ptr) * mult + 128) / 256;
+                }
+                start += pitch;
+            }
+
+            break;
         }
         default:
             DPRINT1("Loaded glyph format %x\n", ft_face->glyph->format);
             return GDI_ERROR;
         }
-        start = pvBuf;
-        for (row = 0; row < height; row++)
-        {
-            ptr = start;
-            for (col = 0; col < width; col++, ptr++)
-            {
-                *ptr = (((int)*ptr) * mult + 128) / 256;
-            }
-            start += pitch;
-        }
-        break;
     }
 
     case GGO_NATIVE:
     {
-        int contour, point = 0, first_pt;
         FT_Outline *outline = &ft_face->glyph->outline;
-        TTPOLYGONHEADER *pph;
-        TTPOLYCURVE *ppc;
-        DWORD pph_start, cpfx, type;
 
         if (cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
 
-        IntLockFreeType;
+        IntLockFreeType();
         if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
 
-        for (contour = 0; contour < outline->n_contours; contour++)
+        needed = get_native_glyph_outline(outline, cjBuf, NULL);
+
+        if (!pvBuf || !cjBuf)
         {
-            pph_start = needed;
-            pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
-            first_pt = point;
-            if (pvBuf)
-            {
-                pph->dwType = TT_POLYGON_TYPE;
-                FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
-            }
-            needed += sizeof(*pph);
-            point++;
-            while (point <= outline->contours[contour])
-            {
-                ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
-                type = (outline->tags[point] & FT_Curve_Tag_On) ?
-                       TT_PRIM_LINE : TT_PRIM_QSPLINE;
-                cpfx = 0;
-                do
-                {
-                    if (pvBuf)
-                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-                    cpfx++;
-                    point++;
-                }
-                while (point <= outline->contours[contour] &&
-                        (outline->tags[point] & FT_Curve_Tag_On) ==
-                        (outline->tags[point-1] & FT_Curve_Tag_On));
-
-                /* At the end of a contour Windows adds the start point, but
-                   only for Beziers */
-                if (point > outline->contours[contour] &&
-                        !(outline->tags[point-1] & FT_Curve_Tag_On))
-                {
-                    if (pvBuf)
-                        FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
-                    cpfx++;
-                }
-                else if (point <= outline->contours[contour] &&
-                         outline->tags[point] & FT_Curve_Tag_On)
-                {
-                    /* Add closing pt for bezier */
-                    if (pvBuf)
-                        FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-                    cpfx++;
-                    point++;
-                }
-                if (pvBuf)
-                {
-                    ppc->wType = type;
-                    ppc->cpfx = cpfx;
-                }
-                needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
-            }
-            if (pvBuf) pph->cb = needed - pph_start;
+            IntUnLockFreeType();
+            break;
         }
-        IntUnLockFreeType;
+        if (needed > cjBuf)
+        {
+            IntUnLockFreeType();
+            return GDI_ERROR;
+        }
+        get_native_glyph_outline(outline, cjBuf, pvBuf);
+        IntUnLockFreeType();
         break;
     }
     case GGO_BEZIER:
     {
-        /* Convert the quadratic Beziers to cubic Beziers.
-           The parametric eqn for a cubic Bezier is, from PLRM:
-           r(t) = at^3 + bt^2 + ct + r0
-           with the control points:
-           r1 = r0 + c/3
-           r2 = r1 + (c + b)/3
-           r3 = r0 + c + b + a
-
-           A quadratic Beizer has the form:
-           p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
-
-           So equating powers of t leads to:
-           r1 = 2/3 p1 + 1/3 p0
-           r2 = 2/3 p1 + 1/3 p2
-           and of course r0 = p0, r3 = p2
-         */
-
-        int contour, point = 0, first_pt;
         FT_Outline *outline = &ft_face->glyph->outline;
-        TTPOLYGONHEADER *pph;
-        TTPOLYCURVE *ppc;
-        DWORD pph_start, cpfx, type;
-        FT_Vector cubic_control[4];
         if (cjBuf == 0) pvBuf = NULL;
 
         if (needsTransform && pvBuf)
         {
-            IntLockFreeType;
+            IntLockFreeType();
             FT_Outline_Transform(outline, &transMat);
-            IntUnLockFreeType;
+            IntUnLockFreeType();
         }
+        needed = get_bezier_glyph_outline(outline, cjBuf, NULL);
 
-        for (contour = 0; contour < outline->n_contours; contour++)
-        {
-            pph_start = needed;
-            pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
-            first_pt = point;
-            if (pvBuf)
-            {
-                pph->dwType = TT_POLYGON_TYPE;
-                FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
-            }
-            needed += sizeof(*pph);
-            point++;
-            while (point <= outline->contours[contour])
-            {
-                ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
-                type = (outline->tags[point] & FT_Curve_Tag_On) ?
-                       TT_PRIM_LINE : TT_PRIM_CSPLINE;
-                cpfx = 0;
-                do
-                {
-                    if (type == TT_PRIM_LINE)
-                    {
-                        if (pvBuf)
-                            FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
-                        cpfx++;
-                        point++;
-                    }
-                    else
-                    {
-                        /* Unlike QSPLINEs, CSPLINEs always have their endpoint
-                           so cpfx = 3n */
+        if (!pvBuf || !cjBuf)
+            break;
+        if (needed > cjBuf)
+            return GDI_ERROR;
 
-                        /* FIXME: Possible optimization in endpoint calculation
-                           if there are two consecutive curves */
-                        cubic_control[0] = outline->points[point-1];
-                        if (!(outline->tags[point-1] & FT_Curve_Tag_On))
-                        {
-                            cubic_control[0].x += outline->points[point].x + 1;
-                            cubic_control[0].y += outline->points[point].y + 1;
-                            cubic_control[0].x >>= 1;
-                            cubic_control[0].y >>= 1;
-                        }
-                        if (point+1 > outline->contours[contour])
-                            cubic_control[3] = outline->points[first_pt];
-                        else
-                        {
-                            cubic_control[3] = outline->points[point+1];
-                            if (!(outline->tags[point+1] & FT_Curve_Tag_On))
-                            {
-                                cubic_control[3].x += outline->points[point].x + 1;
-                                cubic_control[3].y += outline->points[point].y + 1;
-                                cubic_control[3].x >>= 1;
-                                cubic_control[3].y >>= 1;
-                            }
-                        }
-                        /* r1 = 1/3 p0 + 2/3 p1
-                           r2 = 1/3 p2 + 2/3 p1 */
-                        cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
-                        cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
-                        cubic_control[2] = cubic_control[1];
-                        cubic_control[1].x += (cubic_control[0].x + 1) / 3;
-                        cubic_control[1].y += (cubic_control[0].y + 1) / 3;
-                        cubic_control[2].x += (cubic_control[3].x + 1) / 3;
-                        cubic_control[2].y += (cubic_control[3].y + 1) / 3;
-                        if (pvBuf)
-                        {
-                            FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
-                            FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
-                            FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
-                        }
-                        cpfx += 3;
-                        point++;
-                    }
-                }
-                while (point <= outline->contours[contour] &&
-                        (outline->tags[point] & FT_Curve_Tag_On) ==
-                        (outline->tags[point-1] & FT_Curve_Tag_On));
-                /* At the end of a contour Windows adds the start point,
-                   but only for Beziers and we've already done that. */
-                if (point <= outline->contours[contour] &&
-                        outline->tags[point] & FT_Curve_Tag_On)
-                {
-                    /* This is the closing pt of a bezier, but we've already
-                      added it, so just inc point and carry on */
-                    point++;
-                }
-                if (pvBuf)
-                {
-                    ppc->wType = type;
-                    ppc->cpfx = cpfx;
-                }
-                needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
-            }
-            if (pvBuf) pph->cb = needed - pph_start;
-        }
+        get_bezier_glyph_outline(outline, cjBuf, pvBuf);
         break;
     }
 
@@ -2144,6 +3727,7 @@ ftGdiGetGlyphOutline(
     }
 
     DPRINT("ftGdiGetGlyphOutline END and needed %lu\n", needed);
+    *pgm = gm;
     return needed;
 }
 
@@ -2163,67 +3747,38 @@ TextIntGetTextExtentPoint(PDC dc,
     FT_Face face;
     FT_GlyphSlot glyph;
     FT_BitmapGlyph realglyph;
-    INT error, n, glyph_index, i, previous;
+    INT error, glyph_index, i, previous;
     ULONGLONG TotalWidth = 0;
-    FT_CharMap charmap, found = NULL;
     BOOL use_kerning;
     FT_Render_Mode RenderMode;
     BOOLEAN Render;
     PMATRIX pmxWorldToDevice;
+    LOGFONTW *plf;
+    BOOL EmuBold, EmuItalic;
+    LONG ascender, descender;
 
     FontGDI = ObjToGDI(TextObj->Font, FONT);
 
-    face = FontGDI->face;
+    face = FontGDI->SharedFace->Face;
     if (NULL != Fit)
     {
         *Fit = 0;
     }
 
-    IntLockFreeType;
-    if (face->charmap == NULL)
-    {
-        DPRINT("WARNING: No charmap selected!\n");
-        DPRINT("This font face has %d charmaps\n", face->num_charmaps);
-
-        for (n = 0; n < face->num_charmaps; n++)
-        {
-            charmap = face->charmaps[n];
-            DPRINT("Found charmap encoding: %u\n", charmap->encoding);
-            if (charmap->encoding != 0)
-            {
-                found = charmap;
-                break;
-            }
-        }
+    IntLockFreeType();
 
-        if (! found)
-        {
-            DPRINT1("WARNING: Could not find desired charmap!\n");
-        }
+    TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
 
-        error = FT_Set_Charmap(face, found);
-        if (error)
-        {
-            DPRINT1("WARNING: Could not set the charmap!\n");
-        }
-    }
+    plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+    EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
+    EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
 
     Render = IntIsFontRenderingEnabled();
     if (Render)
-        RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
+        RenderMode = IntGetFontRenderMode(plf);
     else
         RenderMode = FT_RENDER_MODE_MONO;
 
-    error = FT_Set_Pixel_Sizes(face,
-                               TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
-                               /* FIXME: Should set character height if neg */
-                               (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-                                                          dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
-    if (error)
-    {
-        DPRINT1("Error in setting pixel sizes: %d\n", error);
-    }
-
     /* Get the DC's world-to-device transformation matrix */
     pmxWorldToDevice = DC_pmxWorldToDevice(dc);
     FtSetCoordinateTransform(face, pmxWorldToDevice);
@@ -2233,14 +3788,15 @@ TextIntGetTextExtentPoint(PDC dc,
 
     for (i = 0; i < Count; i++)
     {
-        if (fl & GTEF_INDICES)
-            glyph_index = *String;
+        glyph_index = get_glyph_index_flagged(face, *String, GTEF_INDICES, fl);
+
+        if (EmuBold || EmuItalic)
+            realglyph = NULL;
         else
-            glyph_index = FT_Get_Char_Index(face, *String);
+            realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
+                                           RenderMode, pmxWorldToDevice);
 
-        if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
-                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
-                                             pmxWorldToDevice)))
+        if (EmuBold || EmuItalic || !realglyph)
         {
             error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
             if (error)
@@ -2249,13 +3805,25 @@ TextIntGetTextExtentPoint(PDC dc,
                 break;
             }
 
-            glyph = face->glyph;
-            realglyph = ftGdiGlyphCacheSet(face,
-                                           glyph_index,
-                                           TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
-                                           pmxWorldToDevice,
-                                           glyph,
-                                           RenderMode);
+            glyph = face->glyph;
+            if (EmuBold || EmuItalic)
+            {
+                if (EmuBold)
+                    FT_GlyphSlot_Embolden(glyph);
+                if (EmuItalic)
+                    FT_GlyphSlot_Oblique(glyph);
+                realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
+            }
+            else
+            {
+                realglyph = ftGdiGlyphCacheSet(face,
+                                               glyph_index,
+                                               plf->lfHeight,
+                                               pmxWorldToDevice,
+                                               glyph,
+                                               RenderMode);
+            }
+
             if (!realglyph)
             {
                 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
@@ -2282,15 +3850,22 @@ TextIntGetTextExtentPoint(PDC dc,
             Dx[i] = (TotalWidth + 32) >> 6;
         }
 
+        if (EmuBold || EmuItalic)
+        {
+            FT_Done_Glyph((FT_Glyph)realglyph);
+            realglyph = NULL;
+        }
+
         previous = glyph_index;
         String++;
     }
-    IntUnLockFreeType;
+    ASSERT(FontGDI->Magic == FONTGDI_MAGIC);
+    ascender = FontGDI->tmAscent; /* Units above baseline */
+    descender = FontGDI->tmDescent; /* Units below baseline */
+    IntUnLockFreeType();
 
     Size->cx = (TotalWidth + 32) >> 6;
-    Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-                   dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
-    Size->cy = EngMulDiv(Size->cy, dc->ppdev->gdiinfo.ulLogPixelsY, 72);
+    Size->cy = ascender + descender;
 
     return TRUE;
 }
@@ -2304,7 +3879,8 @@ ftGdiGetTextCharsetInfo(
     DWORD dwFlags)
 {
     PDC_ATTR pdcattr;
-    UINT Ret = DEFAULT_CHARSET, i;
+    UINT Ret = DEFAULT_CHARSET;
+    INT i;
     HFONT hFont;
     PTEXTOBJ TextObj;
     PFONTGDI FontGdi;
@@ -2325,12 +3901,12 @@ ftGdiGetTextCharsetInfo(
         return Ret;
     }
     FontGdi = ObjToGDI(TextObj->Font, FONT);
-    Face = FontGdi->face;
+    Face = FontGdi->SharedFace->Face;
     TEXTOBJ_UnlockText(TextObj);
 
-    IntLockFreeType;
+    IntLockFreeType();
     pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
-    IntUnLockFreeType;
+    IntUnLockFreeType();
     memset(&fs, 0, sizeof(FONTSIGNATURE));
     if (NULL != pOS2)
     {
@@ -2413,7 +3989,7 @@ ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
 {
     DWORD size = 0;
     DWORD num_ranges = 0;
-    FT_Face face = Font->face;
+    FT_Face face = Font->SharedFace->Face;
 
     if (face->charmap->encoding == FT_ENCODING_UNICODE)
     {
@@ -2462,13 +4038,14 @@ ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
         }
     }
     else
-        DPRINT1("Encoding %u not supported\n", face->charmap->encoding);
+        DPRINT1("Encoding %i not supported\n", face->charmap->encoding);
 
     size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
     if (glyphset)
     {
         glyphset->cbThis = size;
         glyphset->cRanges = num_ranges;
+        glyphset->flAccel = 0;
     }
     return size;
 }
@@ -2490,6 +4067,7 @@ ftGdiGetTextMetricsW(
     FT_WinFNT_HeaderRec Win;
     ULONG Error;
     NTSTATUS Status = STATUS_SUCCESS;
+    LOGFONTW *plf;
 
     if (!ptmwi)
     {
@@ -2506,17 +4084,16 @@ ftGdiGetTextMetricsW(
     TextObj = RealizeFontInit(pdcattr->hlfntNew);
     if (NULL != TextObj)
     {
+        plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
         FontGDI = ObjToGDI(TextObj->Font, FONT);
 
-        Face = FontGDI->face;
-        IntLockFreeType;
-        Error = FT_Set_Pixel_Sizes(Face,
-                                   TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
-                                   /* FIXME: Should set character height if neg */
-                                   (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-                                   dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+        Face = FontGDI->SharedFace->Face;
+
+        IntLockFreeType();
+        Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
         FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc));
-        IntUnLockFreeType;
+        IntUnLockFreeType();
+
         if (0 != Error)
         {
             DPRINT1("Error in setting pixel sizes: %u\n", Error);
@@ -2524,26 +4101,27 @@ ftGdiGetTextMetricsW(
         }
         else
         {
+            FT_Face Face = FontGDI->SharedFace->Face;
             Status = STATUS_SUCCESS;
 
-            IntLockFreeType;
-            pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+            IntLockFreeType();
+            pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
             if (NULL == pOS2)
             {
                 DPRINT1("Can't find OS/2 table - not TT font?\n");
                 Status = STATUS_INTERNAL_ERROR;
             }
 
-            pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
+            pHori = FT_Get_Sfnt_Table(Face, ft_sfnt_hhea);
             if (NULL == pHori)
             {
                 DPRINT1("Can't find HHEA table - not TT font?\n");
                 Status = STATUS_INTERNAL_ERROR;
             }
 
-            Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
+            Error = FT_Get_WinFNT_Header(Face, &Win);
 
-            IntUnLockFreeType;
+            IntUnLockFreeType();
 
             if (NT_SUCCESS(Status))
             {
@@ -2569,7 +4147,6 @@ ftGdiGetTextMetricsW(
     return TRUE;
 }
 
-
 DWORD
 FASTCALL
 ftGdiGetFontData(
@@ -2580,10 +4157,11 @@ ftGdiGetFontData(
     DWORD Size)
 {
     DWORD Result = GDI_ERROR;
+    FT_Face Face = FontGdi->SharedFace->Face;
 
-    IntLockFreeType;
+    IntLockFreeType();
 
-    if (FT_IS_SFNT(FontGdi->face))
+    if (FT_IS_SFNT(Face))
     {
         if (Table)
             Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
@@ -2596,156 +4174,465 @@ ftGdiGetFontData(
             FT_Error Error;
             FT_ULong Needed = 0;
 
-            Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
+            Error = FT_Load_Sfnt_Table(Face, Table, Offset, NULL, &Needed);
 
             if ( !Error && Needed < Size) Size = Needed;
         }
-        if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
+        if (!FT_Load_Sfnt_Table(Face, Table, Offset, Buffer, &Size))
             Result = Size;
     }
 
-    IntUnLockFreeType;
+    IntUnLockFreeType();
 
     return Result;
 }
 
-static UINT FASTCALL
-GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
+// NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
+static UINT
+GetFontPenalty(const LOGFONTW *               LogFont,
+               const OUTLINETEXTMETRICW *     Otm,
+               const char *             style_name)
 {
-    ANSI_STRING EntryFaceNameA;
-    UNICODE_STRING EntryFaceNameW;
-    unsigned Size;
-    OUTLINETEXTMETRICW *Otm;
-    LONG WeightDiff;
-    NTSTATUS Status;
-    UINT Score = 1;
+    ULONG   Penalty = 0;
+    BYTE    Byte;
+    LONG    Long;
+    BOOL    fNeedScaling = FALSE;
+    const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
+    const TEXTMETRICW * TM = &Otm->otmTextMetrics;
+    WCHAR* ActualNameW;
 
-    RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
-    Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
-    if (NT_SUCCESS(Status))
+    ASSERT(Otm);
+    ASSERT(LogFont);
+
+    /* FIXME: IntSizeSynth Penalty 20 */
+    /* FIXME: SmallPenalty Penalty 1 */
+    /* FIXME: FaceNameSubst Penalty 500 */
+
+    Byte = LogFont->lfCharSet;
+    if (Byte == DEFAULT_CHARSET)
     {
-        if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+        if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
         {
-            EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
-            EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+            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 (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
+    }
+
+    if (Byte != TM->tmCharSet)
+    {
+        if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
         {
-            Score += 49;
+            /* 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;
+                }
+            }
         }
-        RtlFreeUnicodeString(&EntryFaceNameW);
     }
 
-    Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
-    Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
-    if (NULL == Otm)
+    Byte = LogFont->lfOutPrecision;
+    if (Byte == OUT_DEFAULT_PRECIS)
+        Byte = OUT_OUTLINE_PRECIS;  /* Is it OK? */
+    switch (Byte)
     {
-        return Score;
+        case OUT_DEVICE_PRECIS:
+            if (!(TM->tmPitchAndFamily & TMPF_DEVICE) ||
+                !(TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)))
+            {
+                /* OutputPrecision Penalty 19000 */
+                /* Requested OUT_STROKE_PRECIS, but the device can't do it
+                   or the candidate is not a vector font. */
+                Penalty += 19000;
+            }
+            break;
+        default:
+            if (TM->tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
+            {
+                /* OutputPrecision Penalty 19000 */
+                /* Or OUT_STROKE_PRECIS not requested, and the candidate
+                   is a vector font that requires GDI support. */
+                Penalty += 19000;
+            }
+            break;
     }
-    IntGetOutlineTextMetrics(FontGDI, Size, Otm);
 
-    if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
-            (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
+    Byte = (LogFont->lfPitchAndFamily & 0x0F);
+    if (Byte == DEFAULT_PITCH)
+        Byte = VARIABLE_PITCH;
+    if ((Byte & FIXED_PITCH) || (Byte & MONO_FONT))
     {
-        Score += 25;
+        if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
+        {
+            /* FixedPitch Penalty 15000 */
+            /* Requested a fixed pitch font, but the candidate is a
+               variable pitch font. */
+            Penalty += 15000;
+        }
     }
-    if (LogFont->lfWeight != FW_DONTCARE)
+    if (Byte & VARIABLE_PITCH)
     {
-        if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
+        if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
         {
-            WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
+            /* PitchVariable Penalty 350 */
+            /* Requested a variable pitch font, but the candidate is not a
+               variable pitch font. */
+            Penalty += 350;
         }
-        else
+    }
+
+    Byte = (LogFont->lfPitchAndFamily & 0x0F);
+    if (Byte == DEFAULT_PITCH)
+    {
+        if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
         {
-            WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
+            /* DefaultPitchFixed Penalty 1 */
+            /* Requested DEFAULT_PITCH, but the candidate is fixed pitch. */
+            Penalty += 1;
         }
-        Score += (1000 - WeightDiff) / (1000 / 25);
     }
-    else
+
+    ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
+
+    if (LogFont->lfFaceName[0])
     {
-        Score += 25;
+        BOOL Found = FALSE;
+
+        /* localized family name */
+        if (!Found)
+        {
+            Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
+        }
+        /* localized full name */
+        if (!Found)
+        {
+            ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
+            Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
+        }
+        if (!Found)
+        {
+            /* FaceName Penalty 10000 */
+            /* Requested a face name, but the candidate's face name
+               does not match. */
+            Penalty += 10000;
+        }
     }
 
-    ExFreePoolWithTag(Otm, GDITAG_TEXT);
+    Byte = (LogFont->lfPitchAndFamily & 0xF0);
+    if (Byte != FF_DONTCARE)
+    {
+        if (Byte & FF_MODERN)
+        {
+            if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
+            {
+                /* FixedPitch Penalty 15000 */
+                /* Requested a fixed pitch font, but the candidate is a
+                   variable pitch font. */
+                Penalty += 15000;
+            }
+        }
+
+        if ((Byte & FF_ROMAN) || (Byte & FF_SWISS))
+        {
+            if (!(TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH))
+            {
+                /* PitchVariable Penalty 350 */
+                /* Requested a variable pitch font, but the candidate is not a
+                   variable pitch font. */
+                Penalty += 350;
+            }
+        }
+
+#define FF_MASK  (FF_DECORATIVE | FF_SCRIPT | FF_SWISS)
+        if ((Byte & FF_MASK) != (TM->tmPitchAndFamily & FF_MASK))
+        {
+            /* Family Penalty 9000 */
+            /* Requested a family, but the candidate's family is different. */
+            Penalty += 9000;
+        }
+#undef FF_MASK
+
+        if ((TM->tmPitchAndFamily & 0xF0) == FF_DONTCARE)
+        {
+            /* FamilyUnknown Penalty 8000 */
+            /* Requested a family, but the candidate has no family. */
+            Penalty += 8000;
+        }
+    }
+
+    /* Is the candidate a non-vector font? */
+    if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
+    {
+        /* Is lfHeight specified? */
+        if (LogFont->lfHeight != 0)
+        {
+            if (labs(LogFont->lfHeight) < TM->tmHeight)
+            {
+                /* HeightBigger Penalty 600 */
+                /* The candidate is a nonvector font and is bigger than the
+                   requested height. */
+                Penalty += 600;
+                /* HeightBiggerDifference Penalty 150 */
+                /* The candidate is a raster font and is larger than the
+                   requested height. Penalty * height difference */
+                Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
+
+                fNeedScaling = TRUE;
+            }
+            if (TM->tmHeight < labs(LogFont->lfHeight))
+            {
+                /* HeightSmaller Penalty 150 */
+                /* The candidate is a raster font and is smaller than the
+                   requested height. Penalty * height difference */
+                Penalty += 150 * labs(TM->tmHeight - labs(LogFont->lfHeight));
+
+                fNeedScaling = TRUE;
+            }
+        }
+    }
+
+    switch (LogFont->lfPitchAndFamily & 0xF0)
+    {
+        case FF_ROMAN: case FF_MODERN: case FF_SWISS:
+            switch (TM->tmPitchAndFamily & 0xF0)
+            {
+                case FF_DECORATIVE: case FF_SCRIPT:
+                    /* FamilyUnlikely Penalty 50 */
+                    /* Requested a roman/modern/swiss family, but the
+                       candidate is decorative/script. */
+                    Penalty += 50;
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case FF_DECORATIVE: case FF_SCRIPT:
+            switch (TM->tmPitchAndFamily & 0xF0)
+            {
+                case FF_ROMAN: case FF_MODERN: case FF_SWISS:
+                    /* FamilyUnlikely Penalty 50 */
+                    /* Or requested decorative/script, and the candidate is
+                       roman/modern/swiss. */
+                    Penalty += 50;
+                    break;
+                default:
+                    break;
+            }
+        default:
+            break;
+    }
+
+    if (LogFont->lfWidth != 0)
+    {
+        if (LogFont->lfWidth != TM->tmAveCharWidth)
+        {
+            /* Width Penalty 50 */
+            /* Requested a nonzero width, but the candidate's width
+               doesn't match. Penalty * width difference */
+            Penalty += 50 * labs(LogFont->lfWidth - TM->tmAveCharWidth);
+
+            if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
+                fNeedScaling = TRUE;
+        }
+    }
+
+    if (fNeedScaling)
+    {
+        /* SizeSynth Penalty 50 */
+        /* The candidate is a raster font that needs scaling by GDI. */
+        Penalty += 50;
+    }
+
+    if (!!LogFont->lfItalic != !!TM->tmItalic)
+    {
+        if (!LogFont->lfItalic && ItalicFromStyle(style_name))
+        {
+            /* Italic Penalty 4 */
+            /* Requested font and candidate font do not agree on italic status,
+               and the desired result cannot be simulated. */
+            /* Adjusted to 40 to satisfy (Oblique Penalty > Book Penalty). */
+            Penalty += 40;
+        }
+        else if (LogFont->lfItalic && !ItalicFromStyle(style_name))
+        {
+            /* ItalicSim Penalty 1 */
+            /* Requested italic font but the candidate is not italic,
+               although italics can be simulated. */
+            Penalty += 1;
+        }
+    }
+
+    if (LogFont->lfOutPrecision == OUT_TT_PRECIS)
+    {
+        if (!(TM->tmPitchAndFamily & TMPF_TRUETYPE))
+        {
+            /* NotTrueType Penalty 4 */
+            /* Requested OUT_TT_PRECIS, but the candidate is not a
+               TrueType font. */
+            Penalty += 4;
+        }
+    }
+
+    Long = LogFont->lfWeight;
+    if (LogFont->lfWeight == FW_DONTCARE)
+        Long = FW_NORMAL;
+    if (Long != TM->tmWeight)
+    {
+        /* Weight Penalty 3 */
+        /* The candidate's weight does not match the requested weight. 
+           Penalty * (weight difference/10) */
+        Penalty += 3 * (labs(Long - TM->tmWeight) / 10);
+    }
+
+    if (!LogFont->lfUnderline && TM->tmUnderlined)
+    {
+        /* Underline Penalty 3 */
+        /* Requested font has no underline, but the candidate is
+           underlined. */
+        Penalty += 3;
+    }
+
+    if (!LogFont->lfStrikeOut && TM->tmStruckOut)
+    {
+        /* StrikeOut Penalty 3 */
+        /* Requested font has no strike-out, but the candidate is
+           struck out. */
+        Penalty += 3;
+    }
+
+    /* Is the candidate a non-vector font? */
+    if (!(TM->tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)))
+    {
+        if (LogFont->lfHeight != 0 && TM->tmHeight < LogFont->lfHeight)
+        {
+            /* VectorHeightSmaller Penalty 2 */
+            /* Candidate is a vector font that is smaller than the
+               requested height. Penalty * height difference */
+            Penalty += 2 * labs(TM->tmHeight - LogFont->lfHeight);
+        }
+        if (LogFont->lfHeight != 0 && TM->tmHeight > LogFont->lfHeight)
+        {
+            /* VectorHeightBigger Penalty 1 */
+            /* Candidate is a vector font that is bigger than the
+               requested height. Penalty * height difference */
+            Penalty += 1 * labs(TM->tmHeight - LogFont->lfHeight);
+        }
+    }
+
+    if (!(TM->tmPitchAndFamily & TMPF_DEVICE))
+    {
+        /* DeviceFavor Penalty 2 */
+        /* Extra penalty for all nondevice fonts. */
+        Penalty += 2;
+    }
+
+    if (TM->tmAveCharWidth >= 5 && TM->tmHeight >= 5)
+    {
+        if (TM->tmAveCharWidth / TM->tmHeight >= 3)
+        {
+            /* Aspect Penalty 30 */
+            /* The aspect rate is >= 3. It seems like a bad font. */
+            Penalty += ((TM->tmAveCharWidth / TM->tmHeight) - 2) * 30;
+        }
+        else if (TM->tmHeight / TM->tmAveCharWidth >= 3)
+        {
+            /* Aspect Penalty 30 */
+            /* The aspect rate is >= 3. It seems like a bad font. */
+            Penalty += ((TM->tmHeight / TM->tmAveCharWidth) - 2) * 30;
+        }
+    }
 
-    return Score;
+    if (Penalty < 200)
+    {
+        DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
+            "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
+            "tmCharSet:%d, tmWeight:%ld\n",
+            Penalty, LogFont->lfFaceName, ActualNameW,
+            LogFont->lfCharSet, LogFont->lfWeight,
+            TM->tmCharSet, TM->tmWeight);
+    }
+
+    return Penalty;     /* success */
 }
 
 static __inline VOID
-FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
-                     PUNICODE_STRING FaceName, PLIST_ENTRY Head)
+FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
+                     const LOGFONTW *LogFont,
+                     const PLIST_ENTRY Head)
 {
+    ULONG Penalty;
     PLIST_ENTRY Entry;
     PFONT_ENTRY CurrentEntry;
     FONTGDI *FontGDI;
-    UINT Score;
-ASSERT(FontObj && MatchScore && LogFont && FaceName && Head);
-    Entry = Head->Flink;
-    while (Entry != Head)
+    OUTLINETEXTMETRICW *Otm = NULL;
+    UINT OtmSize, OldOtmSize = 0;
+    FT_Face Face;
+
+    ASSERT(FontObj);
+    ASSERT(MatchPenalty);
+    ASSERT(LogFont);
+    ASSERT(Head);
+
+    /* Start with a pretty big buffer */
+    OldOtmSize = 0x200;
+    Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
+
+    /* get the FontObj of lowest penalty */
+    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);
+        Face = FontGDI->SharedFace->Face;
 
-        Score = GetFontScore(LogFont, FaceName, FontGDI);
-        if (*MatchScore == 0 || *MatchScore < Score)
+        /* get text metrics */
+        OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+        if (OtmSize > OldOtmSize)
         {
-            *FontObj = GDIToObj(FontGDI, FONT);
-            *MatchScore = Score;
+            if (Otm)
+                ExFreePoolWithTag(Otm, GDITAG_TEXT);
+            Otm = ExAllocatePoolWithTag(PagedPool, OtmSize, GDITAG_TEXT);
         }
-        Entry = Entry->Flink;
-    }
-}
 
-static __inline BOOLEAN
-SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
-                        LPCWSTR Key)
-{
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
-    NTSTATUS Status;
-    UNICODE_STRING Value;
-
-    RtlInitUnicodeString(&Value, NULL);
-
-    QueryTable[0].QueryRoutine = NULL;
-    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
-                          RTL_QUERY_REGISTRY_REQUIRED;
-    QueryTable[0].Name = FaceName->Buffer;
-    QueryTable[0].EntryContext = &Value;
-    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,
-                                    Key,
-                                    QueryTable,
-                                    NULL,
-                                    NULL);
-    if (NT_SUCCESS(Status))
-    {
-        RtlFreeUnicodeString(FaceName);
-        *FaceName = Value;
-    }
+        /* update FontObj if lowest penalty */
+        if (Otm)
+        {
+            IntLockFreeType();
+            IntRequestFontSize(NULL, FontGDI, LogFont->lfWidth, LogFont->lfHeight);
+            IntUnLockFreeType();
 
-    return NT_SUCCESS(Status);
-}
+            OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
+            if (!OtmSize)
+                continue;
 
-static __inline void
-SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
-{
-    if (10 < Level) /* Enough is enough */
-    {
-        return;
-    }
+            OldOtmSize = OtmSize;
 
-    if (SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
-    {
-        SubstituteFontFamily(FaceName, Level + 1);
+            Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
+            if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
+            {
+                *FontObj = GDIToObj(FontGDI, FONT);
+                *MatchPenalty = Penalty;
+            }
+        }
     }
+
+    if (Otm)
+        ExFreePoolWithTag(Otm, GDITAG_TEXT);
 }
 
 static
@@ -2755,39 +4642,89 @@ IntFontType(PFONTGDI Font)
 {
     PS_FontInfoRec psfInfo;
     FT_ULong tmp_size = 0;
+    FT_Face Face = Font->SharedFace->Face;
 
-    if (FT_HAS_MULTIPLE_MASTERS(Font->face))
+    if (FT_HAS_MULTIPLE_MASTERS(Face))
         Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
-    if (FT_HAS_VERTICAL( Font->face ))
+    if (FT_HAS_VERTICAL(Face))
         Font->FontObj.flFontType |= FO_VERT_FACE;
-    if (FT_IS_SCALABLE( Font->face ))
+    if (!FT_IS_SCALABLE(Face))
         Font->FontObj.flFontType |= FO_TYPE_RASTER;
-    if (FT_IS_SFNT(Font->face))
+    if (FT_IS_SFNT(Face))
     {
         Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
-        if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
+        if (FT_Get_Sfnt_Table(Face, ft_sfnt_post))
             Font->FontObj.flFontType |= FO_POSTSCRIPT;
     }
-    if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
+    if (!FT_Get_PS_Font_Info(Face, &psfInfo ))
     {
         Font->FontObj.flFontType |= FO_POSTSCRIPT;
     }
     /* Check for the presence of the 'CFF ' table to check if the font is Type1 */
-    if (!FT_Load_Sfnt_Table(Font->face, FT_MAKE_TAG('C','F','F',' '), 0, NULL, &tmp_size))
+    if (!FT_Load_Sfnt_Table(Face, TTAG_CFF, 0, NULL, &tmp_size))
     {
         Font->FontObj.flFontType |= (FO_CFF|FO_POSTSCRIPT);
     }
 }
 
+static BOOL
+MatchFontName(PSHARED_FACE SharedFace, LPCWSTR lfFaceName, FT_UShort NameID, FT_UShort LangID)
+{
+    NTSTATUS Status;
+    UNICODE_STRING Name1, Name2;
+
+    if (lfFaceName[0] == UNICODE_NULL)
+        return FALSE;
+
+    RtlInitUnicodeString(&Name1, lfFaceName);
+
+    RtlInitUnicodeString(&Name2, NULL);
+    Status = IntGetFontLocalizedName(&Name2, SharedFace, NameID, LangID);
+
+    if (NT_SUCCESS(Status))
+    {
+        if (RtlCompareUnicodeString(&Name1, &Name2, TRUE) == 0)
+        {
+            RtlFreeUnicodeString(&Name2);
+            return TRUE;
+        }
+
+        RtlFreeUnicodeString(&Name2);
+    }
+
+    return FALSE;
+}
+
+static BOOL
+MatchFontNames(PSHARED_FACE SharedFace, LPCWSTR lfFaceName)
+{
+    if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, LANG_ENGLISH) ||
+        MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, LANG_ENGLISH))
+    {
+        return TRUE;
+    }
+    if (PRIMARYLANGID(gusLanguageID) != LANG_ENGLISH)
+    {
+        if (MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FONT_FAMILY, gusLanguageID) ||
+            MatchFontName(SharedFace, lfFaceName, TT_NAME_ID_FULL_NAME, gusLanguageID))
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
 NTSTATUS
 FASTCALL
 TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 {
     NTSTATUS Status = STATUS_SUCCESS;
     PTEXTOBJ TextObj;
-    UNICODE_STRING FaceName;
     PPROCESSINFO Win32Process;
-    UINT MatchScore;
+    ULONG MatchPenalty;
+    LOGFONTW *pLogFont;
+    LOGFONTW SubstitutedLogFont;
+    FT_Face Face;
 
     if (!pTextObj)
     {
@@ -2804,52 +4741,94 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
         }
     }
     else
-        TextObj = pTextObj;
-
-    if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
     {
-        if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
-        return STATUS_NO_MEMORY;
+        TextObj = pTextObj;
     }
-    SubstituteFontFamily(&FaceName, 0);
-    MatchScore = 0;
+
+    pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+
+    /* substitute */
+    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;
 
-    /* First search private fonts */
     Win32Process = PsGetCurrentProcessWin32Process();
+
+    /* Search private fonts */
     IntLockProcessPrivateFonts(Win32Process);
-    FindBestFontFromList(&TextObj->Font, &MatchScore,
-                         &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
+    FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
                          &Win32Process->PrivateFontListHead);
     IntUnLockProcessPrivateFonts(Win32Process);
 
     /* Search system fonts */
-    IntLockGlobalFonts;
-    FindBestFontFromList(&TextObj->Font, &MatchScore,
-                         &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
-                         &FontListHead);
-    IntUnLockGlobalFonts;
+    IntLockGlobalFonts();
+    FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
+                         &g_FontListHead);
+    IntUnLockGlobalFonts();
+
     if (NULL == TextObj->Font)
     {
-        DPRINT1("Requested font %S not found, no fonts loaded at all\n",
-                TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
+        DPRINT1("Request font %S not found, no fonts loaded at all\n",
+                pLogFont->lfFaceName);
         Status = STATUS_NOT_FOUND;
     }
     else
     {
+        UNICODE_STRING Name;
         PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
+        PSHARED_FACE SharedFace = FontGdi->SharedFace;
+
+        IntLockFreeType();
+        IntRequestFontSize(NULL, FontGdi, pLogFont->lfWidth, pLogFont->lfHeight);
+        IntUnLockFreeType();
+
+        TextObj->TextFace[0] = UNICODE_NULL;
+        if (MatchFontNames(SharedFace, SubstitutedLogFont.lfFaceName))
+        {
+            RtlStringCchCopyW(TextObj->TextFace, _countof(TextObj->TextFace), pLogFont->lfFaceName);
+        }
+        else
+        {
+            RtlInitUnicodeString(&Name, NULL);
+            Status = IntGetFontLocalizedName(&Name, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
+            if (NT_SUCCESS(Status))
+            {
+                /* truncated copy */
+                Name.Length = (USHORT)min(Name.Length, (LF_FACESIZE - 1) * sizeof(WCHAR));
+                RtlStringCbCopyNW(TextObj->TextFace, Name.Length + sizeof(WCHAR), Name.Buffer, Name.Length);
+
+                RtlFreeUnicodeString(&Name);
+            }
+        }
+
         // Need hdev, when freetype is loaded need to create DEVOBJ for
         // Consumer and Producer.
         TextObj->Font->iUniq = 1; // Now it can be cached.
         IntFontType(FontGdi);
         FontGdi->flType = TextObj->Font->flFontType;
-        FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
-        FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
+        FontGdi->RequestUnderline = pLogFont->lfUnderline ? 0xFF : 0;
+        FontGdi->RequestStrikeOut = pLogFont->lfStrikeOut ? 0xFF : 0;
+        FontGdi->RequestItalic = pLogFont->lfItalic ? 0xFF : 0;
+        if (pLogFont->lfWeight != FW_DONTCARE)
+            FontGdi->RequestWeight = pLogFont->lfWeight;
+        else
+            FontGdi->RequestWeight = FW_NORMAL;
+
+        Face = FontGdi->SharedFace->Face;
+
+        //FontGdi->OriginalWeight = WeightFromStyle(Face->style_name);
+
+        if (!FontGdi->OriginalItalic)
+            FontGdi->OriginalItalic = ItalicFromStyle(Face->style_name);
+
         TextObj->fl |= TEXTOBJECT_INIT;
         Status = STATUS_SUCCESS;
     }
 
-    RtlFreeUnicodeString(&FaceName);
     if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
 
     ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
@@ -2874,7 +4853,7 @@ IntGetFullFileName(
 
     InitializeObjectAttributes(&ObjectAttributes,
                                FileName,
-                               OBJ_CASE_INSENSITIVE,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
                                NULL,
                                NULL);
 
@@ -2903,6 +4882,39 @@ IntGetFullFileName(
     return TRUE;
 }
 
+static BOOL
+EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
+{
+    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 (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static VOID
+IntAddNameFromFamInfo(LPWSTR psz, FONTFAMILYINFO *FamInfo)
+{
+    wcscat(psz, FamInfo->EnumLogFontEx.elfLogFont.lfFaceName);
+    if (FamInfo->EnumLogFontEx.elfStyle[0] &&
+        _wcsicmp(FamInfo->EnumLogFontEx.elfStyle, L"Regular") != 0)
+    {
+        wcscat(psz, L" ");
+        wcscat(psz, FamInfo->EnumLogFontEx.elfStyle);
+    }
+}
+
 BOOL
 FASTCALL
 IntGdiGetFontResourceInfo(
@@ -2915,9 +4927,14 @@ IntGdiGetFontResourceInfo(
     POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
     PLIST_ENTRY ListEntry;
     PFONT_ENTRY FontEntry;
-    FONTFAMILYINFO Info;
-    ULONG Size;
-    BOOL bFound = FALSE;
+    ULONG Size, i, Count;
+    LPBYTE pbBuffer;
+    BOOL IsEqual;
+    FONTFAMILYINFO *FamInfo;
+    const ULONG MaxFamInfo = 64;
+    BOOL bSuccess;
+
+    DPRINT("IntGdiGetFontResourceInfo: dwType == %lu\n", dwType);
 
     /* Create buffer for full path name */
     Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
@@ -2944,77 +4961,231 @@ IntGdiGetFontResourceInfo(
         return FALSE;
     }
 
+    FamInfo = ExAllocatePoolWithTag(PagedPool,
+                                    sizeof(FONTFAMILYINFO) * MaxFamInfo,
+                                    TAG_FINF);
+    if (!FamInfo)
+    {
+        ExFreePoolWithTag(NameInfo2, TAG_FINF);
+        ExFreePoolWithTag(NameInfo1, TAG_FINF);
+        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
     /* Try to find the pathname in the global font list */
-    IntLockGlobalFonts;
-    for (ListEntry = FontListHead.Flink;
-            ListEntry != &FontListHead;
-            ListEntry = ListEntry->Flink)
+    Count = 0;
+    IntLockGlobalFonts();
+    for (ListEntry = g_FontListHead.Flink; ListEntry != &g_FontListHead;
+         ListEntry = ListEntry->Flink)
     {
         FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
-        if (FontEntry->Font->Filename != NULL)
+        if (FontEntry->Font->Filename == NULL)
+            continue;
+
+        RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
+        if (!IntGetFullFileName(NameInfo2, Size, &EntryFileName))
+            continue;
+
+        if (!RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
+            continue;
+
+        IsEqual = FALSE;
+        FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
+                           NULL, FontEntry->Font);
+        for (i = 0; i < Count; ++i)
         {
-            RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
-            if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
+            if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))
             {
-                if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
-                {
-                    /* Found */
-                    FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
-                    bFound = TRUE;
-                    break;
-                }
+                IsEqual = TRUE;
+                break;
             }
         }
+        if (!IsEqual)
+        {
+            /* Found */
+            ++Count;
+            if (Count >= MaxFamInfo)
+                break;
+        }
     }
-    IntUnLockGlobalFonts;
+    IntUnLockGlobalFonts();
 
     /* Free the buffers */
     ExFreePoolWithTag(NameInfo1, TAG_FINF);
     ExFreePool(NameInfo2);
 
-    if (!bFound && dwType != 5)
+    if (Count == 0 && dwType != 5)
     {
         /* Font could not be found in system table
            dwType == 5 will still handle this */
+        ExFreePoolWithTag(FamInfo, TAG_FINF);
         return FALSE;
     }
 
+    bSuccess = FALSE;
     switch (dwType)
     {
     case 0: /* FIXME: Returns 1 or 2, don't know what this is atm */
-        *(DWORD*)pBuffer = 1;
-        *pdwBytes = sizeof(DWORD);
+        Size = sizeof(DWORD);
+        if (*pdwBytes == 0)
+        {
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
+        else if (pBuffer)
+        {
+            if (*pdwBytes >= Size)
+            {
+                *(DWORD*)pBuffer = Count;
+            }
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
         break;
 
-    case 1: /* Copy the full font name */
-        Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
-        Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
-        RtlCopyMemory(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
-        // FIXME: Do we have to zeroterminate?
-        *pdwBytes = Size;
+    case 1: /* copy the font title */
+        /* calculate the required size */
+        Size = 0;
+        Size += wcslen(FamInfo[0].EnumLogFontEx.elfLogFont.lfFaceName);
+        if (FamInfo[0].EnumLogFontEx.elfStyle[0] &&
+            _wcsicmp(FamInfo[0].EnumLogFontEx.elfStyle, L"Regular") != 0)
+        {
+            Size += 1 + wcslen(FamInfo[0].EnumLogFontEx.elfStyle);
+        }
+        for (i = 1; i < Count; ++i)
+        {
+            Size += 3;  /* " & " */
+            Size += wcslen(FamInfo[i].EnumLogFontEx.elfLogFont.lfFaceName);
+            if (FamInfo[i].EnumLogFontEx.elfStyle[0] &&
+                _wcsicmp(FamInfo[i].EnumLogFontEx.elfStyle, L"Regular") != 0)
+            {
+                Size += 1 + wcslen(FamInfo[i].EnumLogFontEx.elfStyle);
+            }
+        }
+        Size += 2;  /* "\0\0" */
+        Size *= sizeof(WCHAR);
+
+        if (*pdwBytes == 0)
+        {
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
+        else if (pBuffer)
+        {
+            if (*pdwBytes >= Size)
+            {
+                /* store font title to buffer */
+                WCHAR *psz = pBuffer;
+                *psz = 0;
+                IntAddNameFromFamInfo(psz, &FamInfo[0]);
+                for (i = 1; i < Count; ++i)
+                {
+                    wcscat(psz, L" & ");
+                    IntAddNameFromFamInfo(psz, &FamInfo[i]);
+                }
+                psz[wcslen(psz) + 1] = UNICODE_NULL;
+                *pdwBytes = Size;
+                bSuccess = TRUE;
+            }
+            else
+            {
+                *pdwBytes = 1024;       /* this is confirmed value */
+            }
+        }
         break;
 
-    case 2: /* Copy a LOGFONTW structure */
-        Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
-        RtlCopyMemory(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
-        *pdwBytes = sizeof(LOGFONTW);
+    case 2: /* Copy an array of LOGFONTW */
+        Size = Count * sizeof(LOGFONTW);
+        if (*pdwBytes == 0)
+        {
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
+        else if (pBuffer)
+        {
+            if (*pdwBytes >= Size)
+            {
+                pbBuffer = (LPBYTE)pBuffer;
+                for (i = 0; i < Count; ++i)
+                {
+                    FamInfo[i].EnumLogFontEx.elfLogFont.lfWidth = 0;
+                    RtlCopyMemory(pbBuffer, &FamInfo[i].EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
+                    pbBuffer += sizeof(LOGFONTW);
+                }
+            }
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
+        else
+        {
+            *pdwBytes = 1024;       /* this is confirmed value */
+        }
         break;
 
-    case 3: /* FIXME: What exactly is copied here? */
-        *(DWORD*)pBuffer = 1;
-        *pdwBytes = sizeof(DWORD*);
+    case 3:
+        Size = sizeof(DWORD);
+        if (*pdwBytes == 0)
+        {
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
+        else if (pBuffer)
+        {
+            if (*pdwBytes >= Size)
+            {
+                /* FIXME: What exactly is copied here? */
+                *(DWORD*)pBuffer = 1;
+            }
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
         break;
 
-    case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
-        *(BOOL*)pBuffer = !bFound;
-        *pdwBytes = sizeof(BOOL);
+    case 4:     /* full file path */
+        if (FileName->Length >= 4 * sizeof(WCHAR))
+        {
+            /* The beginning of FileName is \??\ */
+            LPWSTR pch = FileName->Buffer + 4;
+            DWORD Length = FileName->Length - 4 * sizeof(WCHAR);
+
+            Size = Length + sizeof(WCHAR);
+            if (*pdwBytes == 0)
+            {
+                *pdwBytes = Size;
+                bSuccess = TRUE;
+            }
+            else if (pBuffer)
+            {
+                if (*pdwBytes >= Size)
+                {
+                    RtlCopyMemory(pBuffer, pch, Size);
+                }
+                *pdwBytes = Size;
+                bSuccess = TRUE;
+            }
+        }
         break;
 
-    default:
-        return FALSE;
+    case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
+        Size = sizeof(BOOL);
+        if (*pdwBytes == 0)
+        {
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
+        else if (pBuffer)
+        {
+            if (*pdwBytes >= Size)
+            {
+                *(BOOL*)pBuffer = Count == 0;
+            }
+            *pdwBytes = Size;
+            bSuccess = TRUE;
+        }
+        break;
     }
+    ExFreePoolWithTag(FamInfo, TAG_FINF);
 
-    return TRUE;
+    return bSuccess;
 }
 
 
@@ -3022,11 +5193,11 @@ BOOL
 FASTCALL
 ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
 {
-    if (FT_HAS_FIXED_SIZES(Font->face))
+    if (FT_HAS_FIXED_SIZES(Font->SharedFace->Face))
         Info->iTechnology = RI_TECH_BITMAP;
     else
     {
-        if (FT_IS_SCALABLE(Font->face))
+        if (FT_IS_SCALABLE(Font->SharedFace->Face))
             Info->iTechnology = RI_TECH_SCALABLE;
         else
             Info->iTechnology = RI_TECH_FIXED;
@@ -3045,7 +5216,7 @@ ftGdiGetKerningPairs( PFONTGDI Font,
 {
     DWORD Count = 0;
     INT i = 0;
-    FT_Face face = Font->face;
+    FT_Face face = Font->SharedFace->Face;
 
     if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
     {
@@ -3055,7 +5226,7 @@ ftGdiGetKerningPairs( PFONTGDI Font,
 
         char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
 
-        IntLockFreeType;
+        IntLockFreeType();
 
         while (glyph_index)
         {
@@ -3077,7 +5248,7 @@ ftGdiGetKerningPairs( PFONTGDI Font,
             char_previous = char_code;
             char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
         }
-        IntUnLockFreeType;
+        IntUnLockFreeType();
     }
     return Count;
 }
@@ -3117,15 +5288,15 @@ NtGdiGetFontFamilyInfo(HDC Dc,
     }
 
     /* Enumerate font families in the global list */
-    IntLockGlobalFonts;
+    IntLockGlobalFonts();
     Count = 0;
-    if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
+    if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &g_FontListHead) )
     {
-        IntUnLockGlobalFonts;
+        IntUnLockGlobalFonts();
         ExFreePoolWithTag(Info, GDITAG_TEXT);
         return -1;
     }
-    IntUnLockGlobalFonts;
+    IntUnLockGlobalFonts();
 
     /* Enumerate font families in the process local list */
     Win32Process = PsGetCurrentProcessWin32Process();
@@ -3190,7 +5361,7 @@ GreExtTextOutW(
     IN INT YStart,
     IN UINT fuOptions,
     IN OPTIONAL PRECTL lprc,
-    IN LPWSTR String,
+    IN LPCWSTR String,
     IN INT Count,
     IN OPTIONAL LPINT Dx,
     IN DWORD dwCodePage)
@@ -3205,19 +5376,18 @@ GreExtTextOutW(
     PDC_ATTR pdcattr;
     SURFOBJ *SurfObj;
     SURFACE *psurf = NULL;
-    int error, glyph_index, n, i;
+    int error, glyph_index, i;
     FT_Face face;
     FT_GlyphSlot glyph;
     FT_BitmapGlyph realglyph;
     LONGLONG TextLeft, RealXStart;
     ULONG TextTop, previous, BackgroundLeft;
     FT_Bool use_kerning;
-    RECTL DestRect, MaskRect, DummyRect = {0, 0, 0, 0};
+    RECTL DestRect, MaskRect;
     POINTL SourcePoint, BrushOrigin;
     HBITMAP HSourceGlyph;
     SURFOBJ *SourceGlyphSurf;
     SIZEL bitSize;
-    FT_CharMap found = 0, charmap;
     INT yoff;
     FONTOBJ *FontObj;
     PFONTGDI FontGDI;
@@ -3231,6 +5401,21 @@ GreExtTextOutW(
     PMATRIX pmxWorldToDevice;
     LONG fixAscender, fixDescender;
     FLOATOBJ Scale;
+    LOGFONTW *plf;
+    BOOL EmuBold, EmuItalic;
+    int thickness;
+    BOOL bResult;
+
+    /* Check if String is valid */
+    if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
+    {
+        EngSetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    /* NOTE: This function locks the screen DC, so it must never be called
+       with a DC already locked */
+    Render = IntIsFontRenderingEnabled();
 
     // TODO: Write test-cases to exactly match real Windows in different
     // bad parameters (e.g. does Windows check the DC or the RECT first?).
@@ -3240,53 +5425,48 @@ 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;
-
-    if ((fuOptions & ETO_OPAQUE) || pdcattr->jBkMode == OPAQUE)
-    {
-        if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
-            DC_vUpdateBackgroundBrush(dc);
-    }
-
-    /* Check if String is valid */
-    if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
-    {
-        EngSetLastError(ERROR_INVALID_PARAMETER);
-        goto fail;
-    }
-
-    DxShift = fuOptions & ETO_PDY ? 1 : 0;
 
     if (PATH_IsPathOpen(dc->dclevel))
     {
-        if (!PATH_ExtTextOut( dc,
+        bResult = PATH_ExtTextOut(dc,
                               XStart,
                               YStart,
                               fuOptions,
                               (const RECTL *)lprc,
                               String,
                               Count,
-                              (const INT *)Dx)) goto fail;
-        goto good;
+                              (const INT *)Dx);
+        DC_UnlockDc(dc);
+        return bResult;
+    }
+
+    DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
+
+    if (!dc->dclevel.pSurface)
+    {
+        /* Memory DC with no surface selected */
+        bResult = TRUE;
+        goto Cleanup;
     }
 
+    pdcattr = dc->pdcattr;
+
     if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
     {
         IntLPtoDP(dc, (POINT *)lprc, 2);
     }
 
-    Start.x = XStart;
-    Start.y = YStart;
-    IntLPtoDP(dc, &Start, 1);
+    if (pdcattr->lTextAlign & TA_UPDATECP)
+    {
+        Start.x = pdcattr->ptlCurrent.x;
+        Start.y = pdcattr->ptlCurrent.y;
+    } else {
+        Start.x = XStart;
+        Start.y = YStart;
+    }
 
-    RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
+    IntLPtoDP(dc, &Start, 1);
+    RealXStart = ((LONGLONG)Start.x + dc->ptlDCOrig.x) << 6;
     YStart = Start.y + dc->ptlDCOrig.y;
 
     SourcePoint.x = 0;
@@ -3308,16 +5488,22 @@ GreExtTextOutW(
         DestRect.right  += dc->ptlDCOrig.x;
         DestRect.bottom += dc->ptlDCOrig.y;
 
-        DC_vPrepareDCsForBlit(dc, DestRect, NULL, DestRect);
+        if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
+        {
+           IntUpdateBoundsRect(dc, &DestRect);
+        }
 
         if (pdcattr->ulDirty_ & DIRTY_BACKGROUND)
             DC_vUpdateBackgroundBrush(dc);
+        if (dc->dctype == DCTYPE_DIRECT)
+            MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
 
+        psurf = dc->dclevel.pSurface;
         IntEngBitBlt(
-            &dc->dclevel.pSurface->SurfObj,
+            &psurf->SurfObj,
             NULL,
             NULL,
-            dc->rosdc.CombinedClip,
+            (CLIPOBJ *)&dc->co,
             NULL,
             &DestRect,
             &SourcePoint,
@@ -3325,8 +5511,11 @@ GreExtTextOutW(
             &dc->eboBackground.BrushObject,
             &BrushOrigin,
             ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
+
+        if (dc->dctype == DCTYPE_DIRECT)
+            MouseSafetyOnDrawEnd(dc->ppdev);
+
         fuOptions &= ~ETO_OPAQUE;
-        DC_vFinishBlit(dc, NULL);
     }
     else
     {
@@ -3339,7 +5528,8 @@ GreExtTextOutW(
     TextObj = RealizeFontInit(pdcattr->hlfntNew);
     if (TextObj == NULL)
     {
-        goto fail;
+        bResult = FALSE;
+        goto Cleanup;
     }
 
     FontObj = TextObj->Font;
@@ -3347,69 +5537,54 @@ GreExtTextOutW(
     FontGDI = ObjToGDI(FontObj, FONT);
     ASSERT(FontGDI);
 
-    IntLockFreeType;
-    face = FontGDI->face;
-    if (face->charmap == NULL)
-    {
-        DPRINT("WARNING: No charmap selected!\n");
-        DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+    IntLockFreeType();
+    face = FontGDI->SharedFace->Face;
 
-        for (n = 0; n < face->num_charmaps; n++)
-        {
-            charmap = face->charmaps[n];
-            DPRINT("Found charmap encoding: %u\n", charmap->encoding);
-            if (charmap->encoding != 0)
-            {
-                found = charmap;
-                break;
-            }
-        }
-        if (!found)
-        {
-            DPRINT1("WARNING: Could not find desired charmap!\n");
-        }
-        error = FT_Set_Charmap(face, found);
-        if (error)
-        {
-            DPRINT1("WARNING: Could not set the charmap!\n");
-        }
-    }
+    plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+    EmuBold = (plf->lfWeight >= FW_BOLD && FontGDI->OriginalWeight <= FW_NORMAL);
+    EmuItalic = (plf->lfItalic && !FontGDI->OriginalItalic);
 
-    Render = IntIsFontRenderingEnabled();
     if (Render)
-        RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
+        RenderMode = IntGetFontRenderMode(plf);
     else
         RenderMode = FT_RENDER_MODE_MONO;
 
-    error = FT_Set_Pixel_Sizes(
-                face,
-                TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
-                /* FIXME: Should set character height if neg */
-                (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-                dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
-    if (error)
+    if (!TextIntUpdateSize(dc, TextObj, FontGDI, FALSE))
     {
-        DPRINT1("Error in setting pixel sizes: %d\n", error);
-        IntUnLockFreeType;
-        goto fail;
+        IntUnLockFreeType();
+        bResult = FALSE;
+        goto Cleanup;
     }
 
-    pmxWorldToDevice = DC_pmxWorldToDevice(dc);
-    FtSetCoordinateTransform(face, pmxWorldToDevice);
+    /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
+    if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
+    {
+        pmxWorldToDevice = DC_pmxWorldToDevice(dc);
+        FtSetCoordinateTransform(face, pmxWorldToDevice);
+
+        fixAscender = ScaleLong(FontGDI->tmAscent, &pmxWorldToDevice->efM22) << 6;
+        fixDescender = ScaleLong(FontGDI->tmDescent, &pmxWorldToDevice->efM22) << 6;
+    }
+    else
+    {
+        pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
+        FtSetCoordinateTransform(face, pmxWorldToDevice);
+
+        fixAscender = FontGDI->tmAscent << 6;
+        fixDescender = FontGDI->tmDescent << 6;
+    }
 
     /*
      * Process the vertical alignment and determine the yoff.
      */
-
-    fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22);
-    fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22);
-
-    if (pdcattr->lTextAlign & TA_BASELINE)
+#define VALIGN_MASK  (TA_TOP | TA_BASELINE | TA_BOTTOM)
+    if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BASELINE)
         yoff = 0;
-    else if (pdcattr->lTextAlign & TA_BOTTOM)
-        yoff = -fixDescender >> 6;
+    else if ((pdcattr->lTextAlign & VALIGN_MASK) == TA_BOTTOM)
+        yoff = -(fixDescender >> 6);
     else /* TA_TOP */
         yoff = fixAscender >> 6;
+#undef VALIGN_MASK
 
     use_kerning = FT_HAS_KERNING(face);
     previous = 0;
@@ -3417,12 +5592,12 @@ GreExtTextOutW(
     /*
      * Process the horizontal alignment and modify XStart accordingly.
      */
-
+    DxShift = fuOptions & ETO_PDY ? 1 : 0;
     if (pdcattr->lTextAlign & (TA_RIGHT | TA_CENTER))
     {
         ULONGLONG TextWidth = 0;
         LPCWSTR TempText = String;
-        int Start;
+        int iStart;
 
         /*
          * Calculate width of the text.
@@ -3430,25 +5605,25 @@ GreExtTextOutW(
 
         if (NULL != Dx)
         {
-            Start = Count < 2 ? 0 : Count - 2;
+            iStart = Count < 2 ? 0 : Count - 2;
             TextWidth = Count < 2 ? 0 : (Dx[(Count-2)<<DxShift] << 6);
         }
         else
         {
-            Start = 0;
+            iStart = 0;
         }
-        TempText = String + Start;
+        TempText = String + iStart;
 
-        for (i = Start; i < Count; i++)
+        for (i = iStart; i < Count; i++)
         {
-            if (fuOptions & ETO_GLYPH_INDEX)
-                glyph_index = *TempText;
-            else
-                glyph_index = FT_Get_Char_Index(face, *TempText);
+            glyph_index = get_glyph_index_flagged(face, *TempText, ETO_GLYPH_INDEX, fuOptions);
 
-            if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
-                                                 TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
-                                                 pmxWorldToDevice)))
+            if (EmuBold || EmuItalic)
+                realglyph = NULL;
+            else
+                realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
+                                               RenderMode, pmxWorldToDevice);
+            if (!realglyph)
             {
                 error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
                 if (error)
@@ -3457,17 +5632,28 @@ GreExtTextOutW(
                 }
 
                 glyph = face->glyph;
-                realglyph = ftGdiGlyphCacheSet(face,
-                                               glyph_index,
-                                               TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
-                                               pmxWorldToDevice,
-                                               glyph,
-                                               RenderMode);
+                if (EmuBold || EmuItalic)
+                {
+                    if (EmuBold)
+                        FT_GlyphSlot_Embolden(glyph);
+                    if (EmuItalic)
+                        FT_GlyphSlot_Oblique(glyph);
+                    realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
+                }
+                else
+                {
+                    realglyph = ftGdiGlyphCacheSet(face,
+                                                   glyph_index,
+                                                   plf->lfHeight,
+                                                   pmxWorldToDevice,
+                                                   glyph,
+                                                   RenderMode);
+                }
                 if (!realglyph)
                 {
                     DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
-                    IntUnLockFreeType;
-                    goto fail;
+                    IntUnLockFreeType();
+                    goto Cleanup;
                 }
 
             }
@@ -3481,77 +5667,212 @@ GreExtTextOutW(
 
             TextWidth += realglyph->root.advance.x >> 10;
 
+            if (EmuBold || EmuItalic)
+            {
+                FT_Done_Glyph((FT_Glyph)realglyph);
+                realglyph = NULL;
+            }
+
+            previous = glyph_index;
+            TempText++;
+        }
+
+        previous = 0;
+
+        if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
+        {
+            RealXStart -= TextWidth / 2;
+        }
+        else
+        {
+            RealXStart -= TextWidth;
+        }
+    }
+
+    psurf = dc->dclevel.pSurface;
+    SurfObj = &psurf->SurfObj ;
+
+    if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
+        DC_vUpdateBackgroundBrush(dc) ;
+
+    if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
+        DC_vUpdateTextBrush(dc) ;
+
+    if (!face->units_per_EM)
+    {
+        thickness = 1;
+    }
+    else
+    {
+        thickness = face->underline_thickness *
+            face->size->metrics.y_ppem / face->units_per_EM;
+        if (thickness <= 0)
+            thickness = 1;
+    }
+
+    if ((fuOptions & ETO_OPAQUE) && plf->lfItalic)
+    {
+        /* Draw background */
+        TextLeft = RealXStart;
+        TextTop = YStart;
+        BackgroundLeft = (RealXStart + 32) >> 6;
+        for (i = 0; i < Count; ++i)
+        {
+            glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
+
+            error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+            if (error)
+            {
+                DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
+                IntUnLockFreeType();
+                goto Cleanup;
+            }
+
+            glyph = face->glyph;
+            if (EmuBold)
+                FT_GlyphSlot_Embolden(glyph);
+            if (EmuItalic)
+                FT_GlyphSlot_Oblique(glyph);
+            realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
+            if (!realglyph)
+            {
+                DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
+                IntUnLockFreeType();
+                goto Cleanup;
+            }
+
+            /* retrieve kerning distance and move pen position */
+            if (use_kerning && previous && glyph_index && NULL == Dx)
+            {
+                FT_Vector delta;
+                FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+                TextLeft += delta.x;
+            }
+            DPRINT("TextLeft: %I64d\n", TextLeft);
+            DPRINT("TextTop: %lu\n", TextTop);
+            DPRINT("Advance: %d\n", realglyph->root.advance.x);
+
+            DestRect.left = BackgroundLeft;
+            DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
+            DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
+            DestRect.bottom = DestRect.top + ((fixAscender + fixDescender) >> 6);
+            MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
+            if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
+            {
+               IntUpdateBoundsRect(dc, &DestRect);
+            }
+            IntEngBitBlt(
+                &psurf->SurfObj,
+                NULL,
+                NULL,
+                (CLIPOBJ *)&dc->co,
+                NULL,
+                &DestRect,
+                &SourcePoint,
+                &SourcePoint,
+                &dc->eboBackground.BrushObject,
+                &BrushOrigin,
+                ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
+            MouseSafetyOnDrawEnd(dc->ppdev);
+            BackgroundLeft = DestRect.right;
+
+            DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
+            DestRect.right = DestRect.left + realglyph->bitmap.width;
+            DestRect.top = TextTop + yoff - realglyph->top;
+            DestRect.bottom = DestRect.top + realglyph->bitmap.rows;
+
+            bitSize.cx = realglyph->bitmap.width;
+            bitSize.cy = realglyph->bitmap.rows;
+            MaskRect.right = realglyph->bitmap.width;
+            MaskRect.bottom = realglyph->bitmap.rows;
+
+            if (NULL == Dx)
+            {
+                TextLeft += realglyph->root.advance.x >> 10;
+                DPRINT("New TextLeft: %I64d\n", TextLeft);
+            }
+            else
+            {
+                // FIXME this should probably be a matrix transform with TextTop as well.
+                Scale = pdcattr->mxWorldToDevice.efM11;
+                if (FLOATOBJ_Equal0(&Scale))
+                    FLOATOBJ_Set1(&Scale);
+
+                /* do the shift before multiplying to preserve precision */
+                FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); 
+                TextLeft += FLOATOBJ_GetLong(&Scale);
+                DPRINT("New TextLeft2: %I64d\n", TextLeft);
+            }
+
+            if (DxShift)
+            {
+                TextTop -= Dx[2 * i + 1] << 6;
+            }
+
             previous = glyph_index;
-            TempText++;
-        }
-
-        previous = 0;
 
-        if ((pdcattr->lTextAlign & TA_CENTER) == TA_CENTER)
-        {
-            RealXStart -= TextWidth / 2;
-        }
-        else
-        {
-            RealXStart -= TextWidth;
+            if (EmuBold || EmuItalic)
+            {
+                FT_Done_Glyph((FT_Glyph)realglyph);
+                realglyph = NULL;
+            }
         }
     }
 
-    TextLeft = RealXStart;
-    TextTop = YStart;
-    BackgroundLeft = (RealXStart + 32) >> 6;
-
-    /* Lock blit with a dummy rect */
-    DC_vPrepareDCsForBlit(dc, DummyRect, NULL, DummyRect);
-
-    psurf = dc->dclevel.pSurface ;
-    if(!psurf) psurf = psurfDefaultBitmap;
-    SurfObj = &psurf->SurfObj ;
-
     EXLATEOBJ_vInitialize(&exloRGB2Dst, &gpalRGB, psurf->ppal, 0, 0, 0);
     EXLATEOBJ_vInitialize(&exloDst2RGB, psurf->ppal, &gpalRGB, 0, 0, 0);
 
-       if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ & DIRTY_BACKGROUND))
-        DC_vUpdateBackgroundBrush(dc) ;
-
-    if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
-        DC_vUpdateTextBrush(dc) ;
+    /* Assume success */
+    bResult = TRUE;
 
     /*
      * The main rendering loop.
      */
-    for (i = 0; i < Count; i++)
+    TextLeft = RealXStart;
+    TextTop = YStart;
+    BackgroundLeft = (RealXStart + 32) >> 6;
+    for (i = 0; i < Count; ++i)
     {
-        if (fuOptions & ETO_GLYPH_INDEX)
-            glyph_index = *String;
-        else
-            glyph_index = FT_Get_Char_Index(face, *String);
+        glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX, fuOptions);
 
-        if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
-                                             TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
-                                             pmxWorldToDevice)))
+        if (EmuBold || EmuItalic)
+            realglyph = NULL;
+        else
+            realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
+                                           RenderMode, pmxWorldToDevice);
+        if (!realglyph)
         {
             error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
             if (error)
             {
                 DPRINT1("Failed to load and render glyph! [index: %d]\n", glyph_index);
-                IntUnLockFreeType;
-                DC_vFinishBlit(dc, NULL);
-                goto fail2;
+                bResult = FALSE;
+                break;
             }
+
             glyph = face->glyph;
-            realglyph = ftGdiGlyphCacheSet(face,
-                                           glyph_index,
-                                           TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
-                                           pmxWorldToDevice,
-                                           glyph,
-                                           RenderMode);
+            if (EmuBold || EmuItalic)
+            {
+                if (EmuBold)
+                    FT_GlyphSlot_Embolden(glyph);
+                if (EmuItalic)
+                    FT_GlyphSlot_Oblique(glyph);
+                realglyph = ftGdiGlyphSet(face, glyph, RenderMode);
+            }
+            else
+            {
+                realglyph = ftGdiGlyphCacheSet(face,
+                                               glyph_index,
+                                               plf->lfHeight,
+                                               pmxWorldToDevice,
+                                               glyph,
+                                               RenderMode);
+            }
             if (!realglyph)
             {
                 DPRINT1("Failed to render glyph! [index: %d]\n", glyph_index);
-                IntUnLockFreeType;
-                DC_vFinishBlit(dc, NULL);
-                goto fail2;
+                bResult = FALSE;
+                break;
             }
         }
 
@@ -3566,18 +5887,25 @@ GreExtTextOutW(
         DPRINT("TextTop: %lu\n", TextTop);
         DPRINT("Advance: %d\n", realglyph->root.advance.x);
 
-        if (fuOptions & ETO_OPAQUE)
+        if ((fuOptions & ETO_OPAQUE) && !plf->lfItalic)
         {
             DestRect.left = BackgroundLeft;
             DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6;
             DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6);
-            DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6);
-            MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
+            DestRect.bottom = DestRect.top + ((fixAscender + fixDescender) >> 6);
+
+            if (dc->dctype == DCTYPE_DIRECT)
+                MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
+
+            if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
+            {
+               IntUpdateBoundsRect(dc, &DestRect);
+            }
             IntEngBitBlt(
                 &psurf->SurfObj,
                 NULL,
                 NULL,
-                dc->rosdc.CombinedClip,
+                (CLIPOBJ *)&dc->co,
                 NULL,
                 &DestRect,
                 &SourcePoint,
@@ -3585,9 +5913,11 @@ GreExtTextOutW(
                 &dc->eboBackground.BrushObject,
                 &BrushOrigin,
                 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
-            MouseSafetyOnDrawEnd(dc->ppdev);
-            BackgroundLeft = DestRect.right;
 
+            if (dc->dctype == DCTYPE_DIRECT)
+                MouseSafetyOnDrawEnd(dc->ppdev);
+
+            BackgroundLeft = DestRect.right;
         }
 
         DestRect.left = ((TextLeft + 32) >> 6) + realglyph->left;
@@ -3600,85 +5930,137 @@ GreExtTextOutW(
         MaskRect.right = realglyph->bitmap.width;
         MaskRect.bottom = realglyph->bitmap.rows;
 
-        /*
-         * We should create the bitmap out of the loop at the biggest possible
-         * glyph size. Then use memset with 0 to clear it and sourcerect to
-         * limit the work of the transbitblt.
-         */
-
-        HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
-                                       BMF_8BPP, BMF_TOPDOWN,
-                                       realglyph->bitmap.buffer);
-        if ( !HSourceGlyph )
-        {
-            DPRINT1("WARNING: EngLockSurface() failed!\n");
-            // FT_Done_Glyph(realglyph);
-            IntUnLockFreeType;
-            DC_vFinishBlit(dc, NULL);
-            goto fail2;
-        }
-        SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
-        if ( !SourceGlyphSurf )
+        /* Check if the bitmap has any pixels */
+        if ((bitSize.cx != 0) && (bitSize.cy != 0))
         {
+            /*
+             * We should create the bitmap out of the loop at the biggest possible
+             * glyph size. Then use memset with 0 to clear it and sourcerect to
+             * limit the work of the transbitblt.
+             */
+            HSourceGlyph = EngCreateBitmap(bitSize, realglyph->bitmap.pitch,
+                                           BMF_8BPP, BMF_TOPDOWN,
+                                           realglyph->bitmap.buffer);
+            if ( !HSourceGlyph )
+            {
+                DPRINT1("WARNING: EngCreateBitmap() failed!\n");
+                // FT_Done_Glyph(realglyph);
+                bResult = FALSE;
+                break;
+            }
+            SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
+            if ( !SourceGlyphSurf )
+            {
+                EngDeleteSurface((HSURF)HSourceGlyph);
+                DPRINT1("WARNING: EngLockSurface() failed!\n");
+                bResult = FALSE;
+                break;
+            }
+
+            /*
+             * Use the font data as a mask to paint onto the DCs surface using a
+             * brush.
+             */
+            if (lprc && (fuOptions & ETO_CLIPPED) &&
+                    DestRect.right >= lprc->right + dc->ptlDCOrig.x)
+            {
+                // We do the check '>=' instead of '>' to possibly save an iteration
+                // through this loop, since it's breaking after the drawing is done,
+                // and x is always incremented.
+                DestRect.right = lprc->right + dc->ptlDCOrig.x;
+                DoBreak = TRUE;
+            }
+            if (lprc && (fuOptions & ETO_CLIPPED) &&
+                    DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
+            {
+                DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
+            }
+
+            if (dc->dctype == DCTYPE_DIRECT)
+                MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
+
+            if (!IntEngMaskBlt(
+                SurfObj,
+                SourceGlyphSurf,
+                (CLIPOBJ *)&dc->co,
+                &exloRGB2Dst.xlo,
+                &exloDst2RGB.xlo,
+                &DestRect,
+                (PPOINTL)&MaskRect,
+                &dc->eboText.BrushObject,
+                &BrushOrigin))
+            {
+                DPRINT1("Failed to MaskBlt a glyph!\n");
+            }
+
+            if (dc->dctype == DCTYPE_DIRECT)
+                MouseSafetyOnDrawEnd(dc->ppdev) ;
+
+            EngUnlockSurface(SourceGlyphSurf);
             EngDeleteSurface((HSURF)HSourceGlyph);
-            DPRINT1("WARNING: EngLockSurface() failed!\n");
-            IntUnLockFreeType;
-            DC_vFinishBlit(dc, NULL);
-            goto fail2;
         }
 
-        /*
-         * Use the font data as a mask to paint onto the DCs surface using a
-         * brush.
-         */
-
-        if (lprc && (fuOptions & ETO_CLIPPED) &&
-                DestRect.right >= lprc->right + dc->ptlDCOrig.x)
+        if (DoBreak)
         {
-            // We do the check '>=' instead of '>' to possibly save an iteration
-            // through this loop, since it's breaking after the drawing is done,
-            // and x is always incremented.
-            DestRect.right = lprc->right + dc->ptlDCOrig.x;
-            DoBreak = TRUE;
+            break;
         }
-        if (lprc && (fuOptions & ETO_CLIPPED) &&
-                DestRect.bottom >= lprc->bottom + dc->ptlDCOrig.y)
+
+        if (plf->lfUnderline)
         {
-            DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
+            int i, position;
+            if (!face->units_per_EM)
+            {
+                position = 0;
+            }
+            else
+            {
+                position = face->underline_position *
+                    face->size->metrics.y_ppem / face->units_per_EM;
+            }
+            for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
+            {
+                EngLineTo(SurfObj,
+                          (CLIPOBJ *)&dc->co,
+                          &dc->eboText.BrushObject,
+                          (TextLeft >> 6),
+                          TextTop + yoff - position + i,
+                          ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
+                          TextTop + yoff - position + i,
+                          NULL,
+                          ROP2_TO_MIX(R2_COPYPEN));
+            }
         }
-        MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom);
-        IntEngMaskBlt(
-            SurfObj,
-            SourceGlyphSurf,
-            dc->rosdc.CombinedClip,
-            &exloRGB2Dst.xlo,
-            &exloDst2RGB.xlo,
-            &DestRect,
-            (PPOINTL)&MaskRect,
-            &dc->eboText.BrushObject,
-            &BrushOrigin);
-        MouseSafetyOnDrawEnd(dc->ppdev) ;
-
-        EngUnlockSurface(SourceGlyphSurf);
-        EngDeleteSurface((HSURF)HSourceGlyph);
-
-        if (DoBreak)
+        if (plf->lfStrikeOut)
         {
-            break;
+            int i;
+            for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
+            {
+                EngLineTo(SurfObj,
+                          (CLIPOBJ *)&dc->co,
+                          &dc->eboText.BrushObject,
+                          (TextLeft >> 6),
+                          TextTop + yoff - (fixAscender >> 6) / 3 + i,
+                          ((TextLeft + (realglyph->root.advance.x >> 10)) >> 6),
+                          TextTop + yoff - (fixAscender >> 6) / 3 + i,
+                          NULL,
+                          ROP2_TO_MIX(R2_COPYPEN));
+            }
         }
 
         if (NULL == Dx)
         {
             TextLeft += realglyph->root.advance.x >> 10;
-             DPRINT("New TextLeft: %I64d\n", TextLeft);
+            DPRINT("New TextLeft: %I64d\n", TextLeft);
         }
         else
         {
+            // FIXME this should probably be a matrix transform with TextTop as well.
             Scale = pdcattr->mxWorldToDevice.efM11;
-            if (_FLOATOBJ_Equal0(&Scale))
+            if (FLOATOBJ_Equal0(&Scale))
                 FLOATOBJ_Set1(&Scale);
-            FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); // do the shift before multiplying to preserve precision
+
+            /* do the shift before multiplying to preserve precision */
+            FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); 
             TextLeft += FLOATOBJ_GetLong(&Scale);
             DPRINT("New TextLeft2: %I64d\n", TextLeft);
         }
@@ -3690,30 +6072,32 @@ GreExtTextOutW(
 
         previous = glyph_index;
 
-        String++;
+        if (EmuBold || EmuItalic)
+        {
+            FT_Done_Glyph((FT_Glyph)realglyph);
+            realglyph = NULL;
+        }
     }
-    IntUnLockFreeType;
 
-    DC_vFinishBlit(dc, NULL) ;
-    EXLATEOBJ_vCleanup(&exloRGB2Dst);
-    EXLATEOBJ_vCleanup(&exloDst2RGB);
-    if (TextObj != NULL)
-        TEXTOBJ_UnlockText(TextObj);
-good:
-    DC_UnlockDc( dc );
+    if (pdcattr->lTextAlign & TA_UPDATECP) {
+        pdcattr->ptlCurrent.x = DestRect.right - dc->ptlDCOrig.x;
+    }
 
-    return TRUE;
+    IntUnLockFreeType();
 
-fail2:
     EXLATEOBJ_vCleanup(&exloRGB2Dst);
     EXLATEOBJ_vCleanup(&exloDst2RGB);
-fail:
+
+Cleanup:
+
+    DC_vFinishBlit(dc, NULL);
+
     if (TextObj != NULL)
         TEXTOBJ_UnlockText(TextObj);
 
     DC_UnlockDc(dc);
 
-    return FALSE;
+    return bResult;
 }
 
 #define STACK_TEXT_BUFFER_SIZE 100
@@ -3735,7 +6119,7 @@ NtGdiExtTextOutW(
     RECTL SafeRect;
     BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
     PVOID Buffer = LocalBuffer;
-    LPWSTR SafeString = NULL;
+    LPCWSTR SafeString = NULL;
     LPINT SafeDx = NULL;
     ULONG BufSize, StringSize, DxSize = 0;
 
@@ -3772,7 +6156,7 @@ NtGdiExtTextOutW(
         _SEH2_TRY
         {
             /* Put the Dx before the String to assure alignment of 4 */
-            SafeString = (LPWSTR)(((ULONG_PTR)Buffer) + DxSize);
+            SafeString = (LPCWSTR)(((ULONG_PTR)Buffer) + DxSize);
 
             /* Probe and copy the string */
             ProbeForRead(UnsafeString, StringSize, 1);
@@ -3848,7 +6232,7 @@ NtGdiGetCharABCWidthsW(
     IN HDC hDC,
     IN UINT FirstChar,
     IN ULONG Count,
-    IN OPTIONAL PWCHAR pwch,
+    IN OPTIONAL PWCHAR UnSafepwch,
     IN FLONG fl,
     OUT PVOID Buffer)
 {
@@ -3864,14 +6248,30 @@ NtGdiGetCharABCWidthsW(
     HFONT hFont = 0;
     NTSTATUS Status = STATUS_SUCCESS;
     PMATRIX pmxWorldToDevice;
+    PWCHAR Safepwch = NULL;
+    LOGFONTW *plf;
+
+    if (!Buffer)
+    {
+        EngSetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
 
-    if (pwch)
+    if (UnSafepwch)
     {
+        UINT pwchSize = Count * sizeof(WCHAR);
+        Safepwch = ExAllocatePoolWithTag(PagedPool, pwchSize, GDITAG_TEXT);
+
+        if(!Safepwch)
+        {
+            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+
         _SEH2_TRY
         {
-            ProbeForRead(pwch,
-            sizeof(PWSTR),
-            1);
+            ProbeForRead(UnSafepwch, pwchSize, 1);
+            RtlCopyMemory(Safepwch, UnSafepwch, pwchSize);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -3879,15 +6279,13 @@ NtGdiGetCharABCWidthsW(
         }
         _SEH2_END;
     }
+
     if (!NT_SUCCESS(Status))
     {
-        EngSetLastError(Status);
-        return FALSE;
-    }
+        if(Safepwch)
+            ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
 
-    if (!Buffer)
-    {
-        EngSetLastError(ERROR_INVALID_PARAMETER);
+        EngSetLastError(Status);
         return FALSE;
     }
 
@@ -3896,6 +6294,10 @@ NtGdiGetCharABCWidthsW(
     if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
     if (SafeBuff == NULL)
     {
+
+        if(Safepwch)
+            ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
+
         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
@@ -3904,6 +6306,10 @@ NtGdiGetCharABCWidthsW(
     if (dc == NULL)
     {
         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
+
+        if(Safepwch)
+            ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
+
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
@@ -3918,16 +6324,20 @@ NtGdiGetCharABCWidthsW(
     if (TextObj == NULL)
     {
         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
+
+        if(Safepwch)
+            ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
+
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
 
     FontGDI = ObjToGDI(TextObj->Font, FONT);
 
-    face = FontGDI->face;
+    face = FontGDI->SharedFace->Face;
     if (face->charmap == NULL)
     {
-        for (i = 0; i < face->num_charmaps; i++)
+        for (i = 0; i < (UINT)face->num_charmaps; i++)
         {
             charmap = face->charmaps[i];
             if (charmap->encoding != 0)
@@ -3941,40 +6351,35 @@ NtGdiGetCharABCWidthsW(
         {
             DPRINT1("WARNING: Could not find desired charmap!\n");
             ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
+
+            if(Safepwch)
+                ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
+
             EngSetLastError(ERROR_INVALID_HANDLE);
             return FALSE;
         }
 
-        IntLockFreeType;
+        IntLockFreeType();
         FT_Set_Charmap(face, found);
-        IntUnLockFreeType;
+        IntUnLockFreeType();
     }
 
-    IntLockFreeType;
-    FT_Set_Pixel_Sizes(face,
-                       TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
-                       /* FIXME: Should set character height if neg */
-                       (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-                       dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+    plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+    IntLockFreeType();
+    IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
     FtSetCoordinateTransform(face, pmxWorldToDevice);
 
     for (i = FirstChar; i < FirstChar+Count; i++)
     {
         int adv, lsb, bbx, left, right;
 
-        if (pwch)
+        if (Safepwch)
         {
-            if (fl & GCABCW_INDICES)
-                glyph_index = pwch[i - FirstChar];
-            else
-                glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
+            glyph_index = get_glyph_index_flagged(face, Safepwch[i - FirstChar], GCABCW_INDICES, fl);
         }
         else
         {
-            if (fl & GCABCW_INDICES)
-                glyph_index = i;
-            else
-                glyph_index = FT_Get_Char_Index(face, i);
+            glyph_index = get_glyph_index_flagged(face, i, GCABCW_INDICES, fl);
         }
         FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
 
@@ -4003,16 +6408,21 @@ NtGdiGetCharABCWidthsW(
             SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
         }
     }
-    IntUnLockFreeType;
+    IntUnLockFreeType();
     TEXTOBJ_UnlockText(TextObj);
     Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
+
+    ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
+
+    if(Safepwch)
+        ExFreePoolWithTag(Safepwch , GDITAG_TEXT);
+
     if (! NT_SUCCESS(Status))
     {
         SetLastNtError(Status);
-        ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         return FALSE;
     }
-    ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
+
     DPRINT("NtGdiGetCharABCWidths Worked!\n");
     return TRUE;
 }
@@ -4026,7 +6436,7 @@ NtGdiGetCharWidthW(
     IN HDC hDC,
     IN UINT FirstChar,
     IN UINT Count,
-    IN OPTIONAL PWCHAR pwc,
+    IN OPTIONAL PWCHAR UnSafepwc,
     IN FLONG fl,
     OUT PVOID Buffer)
 {
@@ -4042,14 +6452,23 @@ NtGdiGetCharWidthW(
     UINT i, glyph_index, BufferSize;
     HFONT hFont = 0;
     PMATRIX pmxWorldToDevice;
+    PWCHAR Safepwc = NULL;
+    LOGFONTW *plf;
 
-    if (pwc)
+    if (UnSafepwc)
     {
+        UINT pwcSize = Count * sizeof(WCHAR);
+        Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
+
+        if(!Safepwc)
+        {
+            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
         _SEH2_TRY
         {
-            ProbeForRead(pwc,
-            sizeof(PWSTR),
-            1);
+            ProbeForRead(UnSafepwc, pwcSize, 1);
+            RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -4057,6 +6476,7 @@ NtGdiGetCharWidthW(
         }
         _SEH2_END;
     }
+
     if (!NT_SUCCESS(Status))
     {
         EngSetLastError(Status);
@@ -4068,6 +6488,9 @@ NtGdiGetCharWidthW(
     if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
     if (SafeBuff == NULL)
     {
+        if(Safepwc)
+            ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
+
         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
@@ -4075,6 +6498,9 @@ NtGdiGetCharWidthW(
     dc = DC_LockDc(hDC);
     if (dc == NULL)
     {
+        if(Safepwc)
+            ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
+
         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -4088,6 +6514,9 @@ NtGdiGetCharWidthW(
 
     if (TextObj == NULL)
     {
+        if(Safepwc)
+            ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
+
         ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
@@ -4095,10 +6524,10 @@ NtGdiGetCharWidthW(
 
     FontGDI = ObjToGDI(TextObj->Font, FONT);
 
-    face = FontGDI->face;
+    face = FontGDI->SharedFace->Face;
     if (face->charmap == NULL)
     {
-        for (i = 0; i < face->num_charmaps; i++)
+        for (i = 0; i < (UINT)face->num_charmaps; i++)
         {
             charmap = face->charmaps[i];
             if (charmap->encoding != 0)
@@ -4111,39 +6540,34 @@ NtGdiGetCharWidthW(
         if (!found)
         {
             DPRINT1("WARNING: Could not find desired charmap!\n");
-            ExFreePool(SafeBuff);
+
+            if(Safepwc)
+                ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
+
+            ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
             EngSetLastError(ERROR_INVALID_HANDLE);
             return FALSE;
         }
 
-        IntLockFreeType;
+        IntLockFreeType();
         FT_Set_Charmap(face, found);
-        IntUnLockFreeType;
+        IntUnLockFreeType();
     }
 
-    IntLockFreeType;
-    FT_Set_Pixel_Sizes(face,
-                       TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
-                       /* FIXME: Should set character height if neg */
-                       (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ?
-                       dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)));
+    plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+    IntLockFreeType();
+    IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
     FtSetCoordinateTransform(face, pmxWorldToDevice);
 
     for (i = FirstChar; i < FirstChar+Count; i++)
     {
-        if (pwc)
+        if (Safepwc)
         {
-            if (fl & GCW_INDICES)
-                glyph_index = pwc[i - FirstChar];
-            else
-                glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]);
+            glyph_index = get_glyph_index_flagged(face, Safepwc[i - FirstChar], GCW_INDICES, fl);
         }
         else
         {
-            if (fl & GCW_INDICES)
-                glyph_index = i;
-            else
-                glyph_index = FT_Get_Char_Index(face, i);
+            glyph_index = get_glyph_index_flagged(face, i, GCW_INDICES, fl);
         }
         FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
         if (!fl)
@@ -4151,137 +6575,80 @@ NtGdiGetCharWidthW(
         else
             SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
     }
-    IntUnLockFreeType;
+    IntUnLockFreeType();
     TEXTOBJ_UnlockText(TextObj);
     MmCopyToCaller(Buffer, SafeBuff, BufferSize);
+
+    if(Safepwc)
+        ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
+
     ExFreePoolWithTag(SafeBuff, GDITAG_TEXT);
     return TRUE;
 }
 
+
+/*
+* @implemented
+*/
+// TODO: Move this code into NtGdiGetGlyphIndicesWInternal and wrap
+// NtGdiGetGlyphIndicesW around NtGdiGetGlyphIndicesWInternal instead.
+// NOTE: See also GreGetGlyphIndicesW.
+__kernel_entry
+W32KAPI
 DWORD
-FASTCALL
-GreGetGlyphIndicesW(
-    HDC hdc,
-    LPWSTR pwc,
-    INT cwc,
-    LPWORD pgi,
-    DWORD iMode,
-    DWORD Unknown)
+APIENTRY
+NtGdiGetGlyphIndicesW(
+    _In_ HDC hdc,
+    _In_reads_opt_(cwc) LPCWSTR pwc,
+    _In_ INT cwc,
+    _Out_writes_opt_(cwc) LPWORD pgi,
+    _In_ DWORD iMode)
 {
     PDC dc;
     PDC_ATTR pdcattr;
     PTEXTOBJ TextObj;
     PFONTGDI FontGDI;
-    HFONT hFont = 0;
+    HFONT hFont = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
     OUTLINETEXTMETRICW *potm;
     INT i;
-    FT_Face face;
     WCHAR DefChar = 0xffff;
     PWSTR Buffer = NULL;
-    ULONG Size;
+    ULONG Size, pwcSize;
+    PWSTR Safepwc = NULL;
+    LPCWSTR UnSafepwc = pwc;
+    LPWORD UnSafepgi = pgi;
 
-    if ((!pwc) && (!pgi)) return cwc;
-
-    dc = DC_LockDc(hdc);
-    if (!dc)
-    {
-        EngSetLastError(ERROR_INVALID_HANDLE);
-        return GDI_ERROR;
-    }
-    pdcattr = dc->pdcattr;
-    hFont = pdcattr->hlfntNew;
-    TextObj = RealizeFontInit(hFont);
-    DC_UnlockDc(dc);
-    if (!TextObj)
-    {
-        EngSetLastError(ERROR_INVALID_HANDLE);
+    /* Check for integer overflow */
+    if (cwc & 0x80000000) // (INT_MAX + 1) == INT_MIN 
         return GDI_ERROR;
-    }
 
-    FontGDI = ObjToGDI(TextObj->Font, FONT);
-    TEXTOBJ_UnlockText(TextObj);
+    if (!UnSafepwc && !UnSafepgi)
+        return cwc;
 
-    Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
-    if (!Buffer)
+    if (!UnSafepwc || !UnSafepgi)
     {
-        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        DPRINT1("UnSafepwc == %p, UnSafepgi = %p\n", UnSafepwc, UnSafepgi);
         return GDI_ERROR;
     }
 
-    if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f;  /* Indicate non existence */
-    else
+    // TODO: Special undocumented case!
+    if (!pwc && !pgi && (cwc == 0))
     {
-        Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
-        potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
-        if (!potm)
-        {
-            EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
-            cwc = GDI_ERROR;
-            goto ErrorRet;
-        }
-        IntGetOutlineTextMetrics(FontGDI, Size, potm);
-        DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
-        ExFreePoolWithTag(potm, GDITAG_TEXT);
+        DPRINT1("ERR: NtGdiGetGlyphIndicesW with (!pwc && !pgi && (cwc == 0)) is UNIMPLEMENTED!\n");
+        return 0;
     }
 
-    IntLockFreeType;
-    face = FontGDI->face;
-
-    for (i = 0; i < cwc; i++)
+    // FIXME: This is a hack!! (triggered by e.g. Word 2010). See CORE-12825
+    if (cwc == 0)
     {
-        Buffer[i] = FT_Get_Char_Index(face, pwc[i]);
-        if (Buffer[i] == 0)
-        {
-            if (DefChar == 0xffff && FT_IS_SFNT(face))
-            {
-                TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-                DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
-            }
-            Buffer[i] = DefChar;
-        }
+        DPRINT1("ERR: NtGdiGetGlyphIndicesW with (cwc == 0) is UNIMPLEMENTED!\n");
+        return GDI_ERROR;
     }
 
-    IntUnLockFreeType;
-
-    RtlCopyMemory( pgi, Buffer, cwc*sizeof(WORD));
-
-ErrorRet:
-    if (Buffer) ExFreePoolWithTag(Buffer, GDITAG_TEXT);
-    return cwc;
-}
-
-
-/*
-* @implemented
-*/
-DWORD
-APIENTRY
-NtGdiGetGlyphIndicesW(
-    IN HDC hdc,
-    IN OPTIONAL LPWSTR UnSafepwc,
-    IN INT cwc,
-    OUT OPTIONAL LPWORD UnSafepgi,
-    IN DWORD iMode)
-{
-    PDC dc;
-    PDC_ATTR pdcattr;
-    PTEXTOBJ TextObj;
-    PFONTGDI FontGDI;
-    HFONT hFont = 0;
-    NTSTATUS Status = STATUS_SUCCESS;
-    OUTLINETEXTMETRICW *potm;
-    INT i;
-    FT_Face face;
-    WCHAR DefChar = 0xffff;
-    PWSTR Buffer = NULL;
-    ULONG Size;
-
-    if ((!UnSafepwc) && (!UnSafepgi)) return cwc;
-
     dc = DC_LockDc(hdc);
     if (!dc)
     {
-        EngSetLastError(ERROR_INVALID_HANDLE);
         return GDI_ERROR;
     }
     pdcattr = dc->pdcattr;
@@ -4290,7 +6657,6 @@ NtGdiGetGlyphIndicesW(
     DC_UnlockDc(dc);
     if (!TextObj)
     {
-        EngSetLastError(ERROR_INVALID_HANDLE);
         return GDI_ERROR;
     }
 
@@ -4300,30 +6666,50 @@ NtGdiGetGlyphIndicesW(
     Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), GDITAG_TEXT);
     if (!Buffer)
     {
-        EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return GDI_ERROR;
     }
 
-    if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f;  /* Indicate non existence */
+    if (iMode & GGI_MARK_NONEXISTING_GLYPHS)
+    {
+        DefChar = 0xffff;
+    }
     else
     {
-        Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
-        potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
-        if (!potm)
+        FT_Face Face = FontGDI->SharedFace->Face;
+        if (FT_IS_SFNT(Face))
         {
-            Status = ERROR_NOT_ENOUGH_MEMORY;
-            goto ErrorRet;
+            TT_OS2 *pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
+            DefChar = (pOS2->usDefaultChar ? get_glyph_index(Face, pOS2->usDefaultChar) : 0);
         }
-        IntGetOutlineTextMetrics(FontGDI, Size, potm);
-        DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
-        ExFreePoolWithTag(potm, GDITAG_TEXT);
+        else
+        {
+            Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+            potm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
+            if (!potm)
+            {
+                cwc = GDI_ERROR;
+                goto ErrorRet;
+            }
+            Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
+            if (Size)
+                DefChar = potm->otmTextMetrics.tmDefaultChar;
+            ExFreePoolWithTag(potm, GDITAG_TEXT);
+        }
+    }
+
+    pwcSize = cwc * sizeof(WCHAR);
+    Safepwc = ExAllocatePoolWithTag(PagedPool, pwcSize, GDITAG_TEXT);
+
+    if (!Safepwc)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto ErrorRet;
     }
 
     _SEH2_TRY
     {
-        ProbeForRead(UnSafepwc,
-        sizeof(PWSTR),
-        1);
+        ProbeForRead(UnSafepwc, pwcSize, 1);
+        RtlCopyMemory(Safepwc, UnSafepwc, pwcSize);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -4333,34 +6719,23 @@ NtGdiGetGlyphIndicesW(
 
     if (!NT_SUCCESS(Status)) goto ErrorRet;
 
-    IntLockFreeType;
-    face = FontGDI->face;
-
-    if (DefChar == 0xffff && FT_IS_SFNT(face))
-    {
-        TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
-        DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
-    }
+    IntLockFreeType();
 
     for (i = 0; i < cwc; i++)
     {
-        Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]); // FIXME: Unsafe!
+        Buffer[i] = get_glyph_index(FontGDI->SharedFace->Face, Safepwc[i]);
         if (Buffer[i] == 0)
         {
             Buffer[i] = DefChar;
         }
     }
 
-    IntUnLockFreeType;
+    IntUnLockFreeType();
 
     _SEH2_TRY
     {
-        ProbeForWrite(UnSafepgi,
-        sizeof(WORD),
-        1);
-        RtlCopyMemory(UnSafepgi,
-                      Buffer,
-                      cwc*sizeof(WORD));
+        ProbeForWrite(UnSafepgi, cwc * sizeof(WORD), 1);
+        RtlCopyMemory(UnSafepgi, Buffer, cwc * sizeof(WORD));
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -4370,8 +6745,11 @@ NtGdiGetGlyphIndicesW(
 
 ErrorRet:
     ExFreePoolWithTag(Buffer, GDITAG_TEXT);
+    if (Safepwc != NULL)
+    {
+        ExFreePoolWithTag(Safepwc, GDITAG_TEXT);
+    }
     if (NT_SUCCESS(Status)) return cwc;
-    EngSetLastError(Status);
     return GDI_ERROR;
 }