[WIN32K] -Simplify the parameters passed to GetFontPenalty and FindBestFontFromList...
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
index f529474..bab1ca2 100644 (file)
@@ -75,7 +75,7 @@ static BOOL RenderingEnabled = TRUE;
   ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
 
 #define ASSERT_GLOBALFONTS_LOCK_HELD() \
-  ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
+  ASSERT(FontListLock->Owner == KeGetCurrentThread())
 
 #define IntLockFreeType \
   ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
@@ -86,6 +86,9 @@ static BOOL RenderingEnabled = TRUE;
 #define ASSERT_FREETYPE_LOCK_HELD() \
   ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
 
+#define ASSERT_FREETYPE_LOCK_NOT_HELD() \
+  ASSERT(FreeTypeLock->Owner != KeGetCurrentThread())
+
 #define MAX_FONT_CACHE 256
 
 static LIST_ENTRY FontCacheListHead;
@@ -171,6 +174,14 @@ SharedMem_AddRef(PSHARED_MEM Ptr)
     ++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)
 {
@@ -181,6 +192,9 @@ SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
         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);
     }
@@ -264,6 +278,13 @@ static void SharedMem_Release(PSHARED_MEM Ptr)
     }
 }
 
+static void
+SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
+{
+    RtlFreeUnicodeString(&Cache->FontFamily);
+    RtlFreeUnicodeString(&Cache->FullName);
+}
+
 static void
 SharedFace_Release(PSHARED_FACE Ptr)
 {
@@ -280,6 +301,8 @@ SharedFace_Release(PSHARED_FACE Ptr)
         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;
@@ -499,7 +522,6 @@ SubstituteFontByList(PLIST_ENTRY        pHead,
                      BYTE               RequestedCharSet,
                      BYTE               CharSetMap[FONTSUBST_FROM_AND_TO])
 {
-    NTSTATUS            Status;
     PLIST_ENTRY         pListEntry;
     PFONTSUBST_ENTRY    pSubstEntry;
     BYTE                CharSets[FONTSUBST_FROM_AND_TO];
@@ -541,14 +563,7 @@ SubstituteFontByList(PLIST_ENTRY        pHead,
         }
 
         /* update *pOutputName */
-        RtlFreeUnicodeString(pOutputName);
-        Status = RtlCreateUnicodeString(pOutputName,
-                                        pSubstEntry->FontNames[FONTSUBST_TO].Buffer);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status);
-            continue;   /* cannot create string */
-        }
+        *pOutputName = pSubstEntry->FontNames[FONTSUBST_TO];
 
         if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET)
         {
@@ -563,32 +578,33 @@ SubstituteFontByList(PLIST_ENTRY        pHead,
 }
 
 static BOOL
-SubstituteFontRecurse(PUNICODE_STRING pInOutName, BYTE *pRequestedCharSet)
+SubstituteFontRecurse(LOGFONTW* pLogFont)
 {
     UINT            RecurseCount = 5;
     UNICODE_STRING  OutputNameW = { 0 };
     BYTE            CharSetMap[FONTSUBST_FROM_AND_TO];
     BOOL            Found;
+    UNICODE_STRING  InputNameW;
 
-    if (pInOutName->Buffer[0] == UNICODE_NULL)
+    if (pLogFont->lfFaceName[0] == UNICODE_NULL)
         return FALSE;
 
+    RtlInitUnicodeString(&InputNameW, pLogFont->lfFaceName);
+
     while (RecurseCount-- > 0)
     {
-        RtlInitUnicodeString(&OutputNameW, NULL);
         Found = SubstituteFontByList(&FontSubstListHead,
-                                     &OutputNameW, pInOutName,
-                                     *pRequestedCharSet, CharSetMap);
+                                     &OutputNameW, &InputNameW,
+                                     pLogFont->lfCharSet, CharSetMap);
         if (!Found)
             break;
 
-        /* update *pInOutName and *pRequestedCharSet */
-        RtlFreeUnicodeString(pInOutName);
-        *pInOutName = OutputNameW;
+        RtlStringCbCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
+
         if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
-            CharSetMap[FONTSUBST_FROM] == *pRequestedCharSet)
+            CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
         {
-            *pRequestedCharSet = CharSetMap[FONTSUBST_TO];
+            pLogFont->lfCharSet = CharSetMap[FONTSUBST_TO];
         }
     }
 
@@ -1738,6 +1754,10 @@ FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
     FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
 }
 
+static NTSTATUS
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
+                        FT_UShort NameID, FT_UShort LangID);
+
 /*************************************************************
  * IntGetOutlineTextMetrics
  *
@@ -1747,63 +1767,58 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
                          UINT Size,
                          OUTLINETEXTMETRICW *Otm)
 {
-    unsigned Needed;
     TT_OS2 *pOS2;
     TT_HoriHeader *pHori;
     TT_Postscript *pPost;
     FT_Fixed XScale, YScale;
-    ANSI_STRING FamilyNameA, StyleNameA;
-    UNICODE_STRING FamilyNameW, StyleNameW, Regular;
     FT_WinFNT_HeaderRec Win;
     FT_Error Error;
     char *Cp;
-    NTSTATUS status;
-    FT_Face Face = FontGDI->SharedFace->Face;
-
-    Needed = sizeof(OUTLINETEXTMETRICW);
+    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;
 
-    RtlInitAnsiString(&FamilyNameA, Face->family_name);
-    status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
-    if (!NT_SUCCESS(status))
+    if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
     {
-        return 0;
+        return Cache->OutlineRequiredSize;
     }
 
-    RtlInitAnsiString(&StyleNameA, Face->style_name);
-    status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
-    if (!NT_SUCCESS(status))
-    {
-        RtlFreeUnicodeString(&FamilyNameW);
-        return 0;
-    }
+    /* family name */
+    RtlInitUnicodeString(&FamilyNameW, NULL);
+    IntGetFontLocalizedName(&FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
 
-    /* These names should be read from the TT name table */
+    /* face name */
+    RtlInitUnicodeString(&FaceNameW, NULL);
+    IntGetFontLocalizedName(&FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
 
-    /* Length of otmpFamilyName */
-    Needed += FamilyNameW.Length + sizeof(WCHAR);
+    /* style name */
+    RtlInitUnicodeString(&StyleNameW, NULL);
+    IntGetFontLocalizedName(&StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
 
-    RtlInitUnicodeString(&Regular, L"Regular");
-    /* Length of otmpFaceName */
-    if (RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
-    {
-        Needed += FamilyNameW.Length + sizeof(WCHAR); /* Just the family name */
-    }
-    else
-    {
-        Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); /* family + " " + style */
-    }
+    /* unique name (full name) */
+    RtlInitUnicodeString(&FullNameW, NULL);
+    IntGetFontLocalizedName(&FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
 
-    /* Length of otmpStyleName */
-    Needed += StyleNameW.Length + sizeof(WCHAR);
+    if (!Cache->OutlineRequiredSize)
+    {
+        UINT Needed;
+        Needed = sizeof(OUTLINETEXTMETRICW);
+        Needed += FamilyNameW.Length + sizeof(WCHAR);
+        Needed += FaceNameW.Length + sizeof(WCHAR);
+        Needed += StyleNameW.Length + sizeof(WCHAR);
+        Needed += FullNameW.Length + sizeof(WCHAR);
 
-    /* Length of otmpFullName */
-    Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
+        Cache->OutlineRequiredSize = Needed;
+    }
 
-    if (Size < Needed)
+    if (Size < Cache->OutlineRequiredSize)
     {
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
         RtlFreeUnicodeString(&StyleNameW);
-        return Needed;
+        RtlFreeUnicodeString(&FullNameW);
+        return Cache->OutlineRequiredSize;
     }
 
     XScale = Face->size->metrics.x_scale;
@@ -1815,8 +1830,10 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
     {
         IntUnLockFreeType;
         DPRINT1("Can't find OS/2 table - not TT font?\n");
-        RtlFreeUnicodeString(&StyleNameW);
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
+        RtlFreeUnicodeString(&StyleNameW);
+        RtlFreeUnicodeString(&FullNameW);
         return 0;
     }
 
@@ -1825,8 +1842,10 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
     {
         IntUnLockFreeType;
         DPRINT1("Can't find HHEA table - not TT font?\n");
-        RtlFreeUnicodeString(&StyleNameW);
         RtlFreeUnicodeString(&FamilyNameW);
+        RtlFreeUnicodeString(&FaceNameW);
+        RtlFreeUnicodeString(&StyleNameW);
+        RtlFreeUnicodeString(&FullNameW);
         return 0;
     }
 
@@ -1834,7 +1853,7 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
 
     Error = FT_Get_WinFNT_Header(Face , &Win);
 
-    Otm->otmSize = Needed;
+    Otm->otmSize = Cache->OutlineRequiredSize;
 
     FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
 
@@ -1882,35 +1901,36 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
 
     IntUnLockFreeType;
 
-    /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
     Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
+
+    /* family name */
     Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
     wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
     Cp += FamilyNameW.Length + sizeof(WCHAR);
+
+    /* face name */
+    Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
+    wcscpy((WCHAR*) Cp, FaceNameW.Buffer);
+    Cp += FaceNameW.Length + sizeof(WCHAR);
+
+    /* style name */
     Otm->otmpStyleName = (LPSTR)(Cp - (char*) Otm);
     wcscpy((WCHAR*) Cp, StyleNameW.Buffer);
     Cp += StyleNameW.Length + sizeof(WCHAR);
-    Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
-    wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
-    if (!RtlEqualUnicodeString(&StyleNameW, &Regular, TRUE))
-    {
-        wcscat((WCHAR*) Cp, L" ");
-        wcscat((WCHAR*) Cp, StyleNameW.Buffer);
-        Cp += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
-    }
-    else
-    {
-        Cp += FamilyNameW.Length + sizeof(WCHAR);
-    }
+
+    /* unique name (full name) */
     Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
-    wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
-    wcscat((WCHAR*) Cp, L" ");
-    wcscat((WCHAR*) Cp, StyleNameW.Buffer);
+    wcscpy((WCHAR*) Cp, FullNameW.Buffer);
+    Cp += FullNameW.Length + sizeof(WCHAR);
+
+    ASSERT(Cp - (char*)Otm == Cache->OutlineRequiredSize);
 
-    RtlFreeUnicodeString(&StyleNameW);
     RtlFreeUnicodeString(&FamilyNameW);
+    RtlFreeUnicodeString(&FaceNameW);
+    RtlFreeUnicodeString(&StyleNameW);
+    RtlFreeUnicodeString(&FullNameW);
 
-    return Needed;
+    return Cache->OutlineRequiredSize;
 }
 
 static PFONTGDI FASTCALL
@@ -2042,36 +2062,87 @@ SwapEndian(LPVOID pvData, DWORD Size)
 }
 
 static NTSTATUS
-IntGetFontLocalizedName(PUNICODE_STRING pNameW, FT_Face Face,
+DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
+{
+    NTSTATUS Status = STATUS_NO_MEMORY;
+    UNICODE_STRING Tmp;
+
+    Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
+    if (Tmp.Buffer)
+    {
+        Tmp.MaximumLength = Source->MaximumLength;
+        Tmp.Length = 0;
+        RtlCopyUnicodeString(&Tmp, Source);
+
+        Destination->MaximumLength = Tmp.MaximumLength;
+        Destination->Length = Tmp.Length;
+        Destination->Buffer = Tmp.Buffer;
+
+        Status = STATUS_SUCCESS;
+    }
+
+    return Status;
+}
+
+static NTSTATUS
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
                         FT_UShort NameID, FT_UShort LangID)
 {
     FT_SfntName Name;
-    INT i, Count;
+    INT i, Count, BestIndex, Score, BestScore;
     WCHAR Buf[LF_FULLFACESIZE];
     FT_Error Error;
     NTSTATUS Status = STATUS_NOT_FOUND;
     ANSI_STRING AnsiName;
+    PSHARED_FACE_CACHE Cache;
+    FT_Face Face = SharedFace->Face;
 
-    RtlInitUnicodeString(pNameW, NULL);
+    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;
-
-        if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
-            Name.encoding_id != TT_MS_ID_UNICODE_CS)
         {
-            continue;   /* not Microsoft Unicode name */
+            continue;   /* failure */
         }
 
-        if (Name.name_id != NameID || Name.language_id != LangID)
+        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))
         {
@@ -2083,35 +2154,91 @@ IntGetFontLocalizedName(PUNICODE_STRING pNameW, FT_Face Face,
             continue;   /* name too long */
         }
 
-        /* NOTE: Name.string is not null-terminated */
-        RtlCopyMemory(Buf, Name.string, Name.string_len);
-        Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
+        if (Name.language_id == LangID)
+        {
+            Score = 30;
+            BestIndex = i;
+            break;      /* best match */
+        }
+        else if (PRIMARYLANGID(Name.language_id) == PRIMARYLANGID(LangID))
+        {
+            Score = 20;
+        }
+        else if (PRIMARYLANGID(Name.language_id) == LANG_ENGLISH)
+        {
+            Score = 10;
+        }
+        else
+        {
+            Score = 0;
+        }
 
-        /* Convert UTF-16 big endian to little endian */
-        SwapEndian(Buf, Name.string_len);
+        if (Score > BestScore)
+        {
+            BestScore = Score;
+            BestIndex = i;
+        }
+    }
 
-        Status = RtlCreateUnicodeString(pNameW, Buf);
-        break;
+    if (BestIndex >= 0)
+    {
+        /* store the best name */
+        Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
+        if (!Error)
+        {
+            /* NOTE: Name.string is not null-terminated */
+            RtlCopyMemory(Buf, Name.string, Name.string_len);
+            Buf[Name.string_len / sizeof(WCHAR)] = UNICODE_NULL;
+
+            /* Convert UTF-16 big endian to little endian */
+            SwapEndian(Buf, Name.string_len);
+
+            Status = RtlCreateUnicodeString(pNameW, Buf);
+        }
     }
 
-    if (Status == STATUS_NOT_FOUND)
+    if (!NT_SUCCESS(Status))
     {
-        if (LangID != gusEnglishUS)
+        /* defaulted */
+        if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
+        {
+            RtlInitAnsiString(&AnsiName, Face->style_name);
+            Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
+        }
+        else
         {
-            Status = IntGetFontLocalizedName(pNameW, Face, NameID, gusEnglishUS);
+            RtlInitAnsiString(&AnsiName, Face->family_name);
+            Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
         }
     }
-    if (Status == STATUS_NOT_FOUND)
+
+    if (NT_SUCCESS(Status))
     {
-        RtlInitAnsiString(&AnsiName, Face->family_name);
-        Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
+        /* 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;
@@ -2125,8 +2252,11 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     NEWTEXTMETRICW *Ntm;
     DWORD fs0;
     NTSTATUS status;
-    FT_Face Face = FontGDI->SharedFace->Face;
+    PSHARED_FACE SharedFace = FontGDI->SharedFace;
+    FT_Face Face = SharedFace->Face;
+    UNICODE_STRING NameW;
 
+    RtlInitUnicodeString(&NameW, NULL);
     RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
     Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
     Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
@@ -2186,36 +2316,22 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
         Info->FontType |= RASTER_FONTTYPE;
 
-    ExFreePoolWithTag(Otm, GDITAG_TEXT);
 
     /* face name */
-    /* TODO: full name */
-    if (FaceName)
-    {
-        RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
-                         sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
-                         FaceName);
-        RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
-                         sizeof(Info->EnumLogFontEx.elfFullName),
-                         FaceName);
-    }
-    else
-    {
-        UNICODE_STRING NameW;
-        status = IntGetFontLocalizedName(&NameW, Face, TT_NAME_ID_FONT_FAMILY,
-                                         gusLanguageID);
-        if (NT_SUCCESS(status))
-        {
-            /* store it */
-            RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
-                             sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
-                             NameW.Buffer);
-            RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
-                             sizeof(Info->EnumLogFontEx.elfFullName),
-                             NameW.Buffer);
-            RtlFreeUnicodeString(&NameW);
-        }
-    }
+    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),
+                     FullName);
+
+    ExFreePoolWithTag(Otm, GDITAG_TEXT);
 
     RtlInitAnsiString(&StyleA, Face->style_name);
     StyleW.Buffer = Info->EnumLogFontEx.elfStyle;
@@ -2225,7 +2341,6 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     {
         return;
     }
-    Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
     Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
 
     IntLockFreeType;
@@ -2286,7 +2401,6 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
             }
             if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
             {
-                Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
                 if (ElfScripts[i])
                     wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
                 else
@@ -2372,7 +2486,8 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont,
         {
             if (*Count < Size)
             {
-                FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
+                FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer,
+                                   NULL, FontGDI);
             }
             (*Count)++;
         }
@@ -2443,7 +2558,7 @@ FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
         if (InfoContext->Count < InfoContext->Size)
         {
             FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
-                               RegistryName.Buffer, FontGDI);
+                               RegistryName.Buffer, NULL, FontGDI);
         }
         InfoContext->Count++;
         return STATUS_SUCCESS;
@@ -2642,6 +2757,7 @@ ftGdiGlyphCacheSet(
     {
         DPRINT1("Conversion failed\n");
         ExFreePoolWithTag(NewEntry, TAG_FONT);
+        FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
         FT_Done_Glyph((FT_Glyph)BitmapGlyph);
         return NULL;
     }
@@ -3909,15 +4025,9 @@ ftGdiGetFontData(
 }
 
 // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx
-static UINT FASTCALL
-GetFontPenalty(LOGFONTW *               LogFont,
-               PUNICODE_STRING          RequestedNameW,
-               PUNICODE_STRING          ActualNameW,
-               PUNICODE_STRING          FullFaceNameW,
-               BYTE                     RequestedCharSet,
-               PFONTGDI                 FontGDI,
-               OUTLINETEXTMETRICW *     Otm,
-               TEXTMETRICW *            TM,
+static UINT
+GetFontPenalty(const LOGFONTW *               LogFont,
+               const OUTLINETEXTMETRICW *     Otm,
                const char *             style_name)
 {
     ULONG   Penalty = 0;
@@ -3925,14 +4035,19 @@ GetFontPenalty(LOGFONTW *               LogFont,
     LONG    Long;
     BOOL    fFixedSys = FALSE, fNeedScaling = FALSE;
     const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
-    NTSTATUS Status;
+    const TEXTMETRICW * TM = &Otm->otmTextMetrics;
+    WCHAR* ActualNameW;
+
+    ASSERT(Otm);
+    ASSERT(LogFont);
+    ASSERT(style_name);
 
     /* FIXME: Aspect Penalty 30 */
     /* FIXME: IntSizeSynth Penalty 20 */
     /* FIXME: SmallPenalty Penalty 1 */
     /* FIXME: FaceNameSubst Penalty 500 */
 
-    if (RtlEqualUnicodeString(RequestedNameW, &SystemW, TRUE))
+    if (_wcsicmp(LogFont->lfFaceName, L"System") == 0)
     {
         /* "System" font */
         if (TM->tmCharSet != UserCharSet)
@@ -3942,7 +4057,7 @@ GetFontPenalty(LOGFONTW *               LogFont,
             Penalty += 65000;
         }
     }
-    else if (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE))
+    else if (_wcsicmp(LogFont->lfFaceName, L"FixedSys") == 0)
     {
         /* "FixedSys" font */
         if (TM->tmCharSet != UserCharSet)
@@ -3955,10 +4070,10 @@ GetFontPenalty(LOGFONTW *               LogFont,
     }
     else    /* Request is non-"System" font */
     {
-        Byte = RequestedCharSet;
+        Byte = LogFont->lfCharSet;
         if (Byte == DEFAULT_CHARSET)
         {
-            if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE))
+            if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
             {
                 if (Byte == ANSI_CHARSET)
                 {
@@ -4059,53 +4174,22 @@ GetFontPenalty(LOGFONTW *               LogFont,
         }
     }
 
-    if (RequestedNameW->Buffer[0])
+    ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
+
+    if (LogFont->lfFaceName[0])
     {
         BOOL Found = FALSE;
-        FT_Face Face = FontGDI->SharedFace->Face;
 
         /* localized family name */
         if (!Found)
         {
-            Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FONT_FAMILY,
-                                             gusLanguageID);
-            if (NT_SUCCESS(Status))
-            {
-                Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
-            }
+            Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
         }
         /* localized full name */
         if (!Found)
         {
-            Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FULL_NAME,
-                                             gusLanguageID);
-            if (NT_SUCCESS(Status))
-            {
-                Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
-            }
-        }
-        if (gusLanguageID != gusEnglishUS)
-        {
-            /* English family name */
-            if (!Found)
-            {
-                Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FONT_FAMILY,
-                                                 gusEnglishUS);
-                if (NT_SUCCESS(Status))
-                {
-                    Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
-                }
-            }
-            /* English full name */
-            if (!Found)
-            {
-                Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FULL_NAME,
-                                                 gusEnglishUS);
-                if (NT_SUCCESS(Status))
-                {
-                    Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
-                }
-            }
+            ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
+            Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
         }
         if (!Found)
         {
@@ -4304,7 +4388,7 @@ GetFontPenalty(LOGFONTW *               LogFont,
         DPRINT("WARNING: Penalty:%ld < 200: RequestedNameW:%ls, "
             "ActualNameW:%ls, lfCharSet:%d, lfWeight:%ld, "
             "tmCharSet:%d, tmWeight:%ld\n",
-            Penalty, RequestedNameW->Buffer, ActualNameW->Buffer,
+            Penalty, LogFont->lfFaceName, ActualNameW,
             LogFont->lfCharSet, LogFont->lfWeight,
             TM->tmCharSet, TM->tmWeight);
     }
@@ -4313,49 +4397,38 @@ GetFontPenalty(LOGFONTW *               LogFont,
 }
 
 static __inline VOID
-FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
-                     PUNICODE_STRING pRequestedNameW,
-                     PUNICODE_STRING pActualNameW, BYTE RequestedCharSet,
-                     PLIST_ENTRY Head)
+FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty,
+                     const LOGFONTW *LogFont,
+                     const PLIST_ENTRY Head)
 {
     ULONG Penalty;
-    NTSTATUS Status;
     PLIST_ENTRY Entry;
     PFONT_ENTRY CurrentEntry;
     FONTGDI *FontGDI;
-    ANSI_STRING ActualNameA;
-    UNICODE_STRING ActualNameW, FullFaceNameW;
     OUTLINETEXTMETRICW *Otm = NULL;
     UINT OtmSize, OldOtmSize = 0;
-    TEXTMETRICW *TM;
     FT_Face Face;
-    LPBYTE pb;
 
     ASSERT(FontObj);
     ASSERT(MatchPenalty);
     ASSERT(LogFont);
-    ASSERT(pRequestedNameW);
     ASSERT(Head);
 
+    /* Start with a pretty big buffer */
+    OldOtmSize = 0x200;
+    Otm = ExAllocatePoolWithTag(PagedPool, OldOtmSize, GDITAG_TEXT);
+
     /* get the FontObj of lowest penalty */
     Entry = Head->Flink;
     while (Entry != Head)
     {
         CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+        Entry = Entry->Flink;
+
         FontGDI = CurrentEntry->Font;
         ASSERT(FontGDI);
         Face = FontGDI->SharedFace->Face;
 
-        /* create actual name */
-        RtlInitAnsiString(&ActualNameA, Face->family_name);
-        Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE);
-        if (!NT_SUCCESS(Status))
-        {
-            /* next entry */
-            Entry = Entry->Flink;
-            continue;
-        }
-
         /* get text metrics */
         OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
         if (OtmSize > OldOtmSize)
@@ -4369,42 +4442,15 @@ FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
         if (Otm)
         {
             IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
-            TM = &Otm->otmTextMetrics;
             OldOtmSize = OtmSize;
 
-            /* create full name */
-            pb = (LPBYTE)Otm + (WORD)(DWORD_PTR)Otm->otmpFullName;
-            Status = RtlCreateUnicodeString(&FullFaceNameW, (LPWSTR)pb);
-            if (!NT_SUCCESS(Status))
-            {
-                RtlFreeUnicodeString(&ActualNameW);
-                RtlFreeUnicodeString(&FullFaceNameW);
-                /* next entry */
-                Entry = Entry->Flink;
-                continue;
-            }
-
-            Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW,
-                                     &FullFaceNameW, RequestedCharSet,
-                                     FontGDI, Otm, TM, Face->style_name);
+            Penalty = GetFontPenalty(LogFont, Otm, Face->style_name);
             if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty)
             {
-                DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty);
-                RtlFreeUnicodeString(pActualNameW);
-                RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer);
-
                 *FontObj = GDIToObj(FontGDI, FONT);
                 *MatchPenalty = Penalty;
             }
-
-            RtlFreeUnicodeString(&FullFaceNameW);
         }
-
-        /* free strings */
-        RtlFreeUnicodeString(&ActualNameW);
-
-        /* next entry */
-        Entry = Entry->Flink;
     }
 
     if (Otm)
@@ -4449,12 +4495,11 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 {
     NTSTATUS Status = STATUS_SUCCESS;
     PTEXTOBJ TextObj;
-    UNICODE_STRING ActualNameW, RequestedNameW;
     PPROCESSINFO Win32Process;
     ULONG MatchPenalty;
     LOGFONTW *pLogFont;
+    LOGFONTW SubstitutedLogFont;
     FT_Face Face;
-    BYTE RequestedCharSet;
 
     if (!pTextObj)
     {
@@ -4475,21 +4520,13 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
         TextObj = pTextObj;
     }
 
-    RtlInitUnicodeString(&ActualNameW, NULL);
-
     pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
-    if (!RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName))
-    {
-        if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
-        return STATUS_NO_MEMORY;
-    }
 
     /* substitute */
-    RequestedCharSet = pLogFont->lfCharSet;
-    DPRINT("Font '%ls,%u' is substituted by: ",
-           RequestedNameW.Buffer, RequestedCharSet);
-    SubstituteFontRecurse(&RequestedNameW, &RequestedCharSet);
-    DPRINT("'%ls,%u'.\n", RequestedNameW.Buffer, RequestedCharSet);
+    SubstitutedLogFont = *pLogFont;
+    DPRINT("Font '%S,%u' is substituted by: ", pLogFont->lfFaceName, pLogFont->lfCharSet);
+    SubstituteFontRecurse(&SubstitutedLogFont);
+    DPRINT("'%S,%u'.\n", SubstitutedLogFont.lfFaceName, SubstitutedLogFont.lfCharSet);
 
     MatchPenalty = 0xFFFFFFFF;
     TextObj->Font = NULL;
@@ -4498,15 +4535,13 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 
     /* Search private fonts */
     IntLockProcessPrivateFonts(Win32Process);
-    FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
-                         &RequestedNameW, &ActualNameW, RequestedCharSet,
+    FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
                          &Win32Process->PrivateFontListHead);
     IntUnLockProcessPrivateFonts(Win32Process);
 
     /* Search system fonts */
     IntLockGlobalFonts;
-    FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont,
-                         &RequestedNameW, &ActualNameW, RequestedCharSet,
+    FindBestFontFromList(&TextObj->Font, &MatchPenalty, &SubstitutedLogFont,
                          &FontListHead);
     IntUnLockGlobalFonts;
 
@@ -4541,14 +4576,8 @@ TextIntRealizeFont(HFONT FontHandle, PTEXTOBJ pTextObj)
 
         TextObj->fl |= TEXTOBJECT_INIT;
         Status = STATUS_SUCCESS;
-
-        DPRINT("RequestedNameW: %ls (CharSet: %d) -> ActualNameW: %ls (CharSet: %d)\n",
-            RequestedNameW.Buffer, pLogFont->lfCharSet,
-            ActualNameW.Buffer, FontGdi->CharSet);
     }
 
-    RtlFreeUnicodeString(&RequestedNameW);
-    RtlFreeUnicodeString(&ActualNameW);
     if (!pTextObj) TEXTOBJ_UnlockText(TextObj);
 
     ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
@@ -4715,7 +4744,7 @@ IntGdiGetFontResourceInfo(
 
         IsEqual = FALSE;
         FontFamilyFillInfo(&FamInfo[Count], FontEntry->FaceName.Buffer,
-                           FontEntry->Font);
+                           NULL, FontEntry->Font);
         for (i = 0; i < Count; ++i)
         {
             if (EqualFamilyInfo(&FamInfo[i], &FamInfo[Count]))