[WIN32SS] Initial fixes for localized font enumeration. Patch by Katayama Hirofumi...
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
index b2bebd7..f529474 100644 (file)
@@ -48,6 +48,7 @@ extern const MATRIX gmxWorldToPageDefault;
 #define gmxWorldToDeviceDefault gmxWorldToPageDefault
 
 FT_Library  library;
+static const WORD gusEnglishUS = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
 
 /* special font names */
 static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett");
@@ -771,7 +772,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
     FT_Face             Face;
     ANSI_STRING         AnsiFaceName;
     FT_WinFNT_HeaderRec WinFNT;
-    INT                 FontCount = 0, CharSetCount = 0;
+    INT                 FaceCount = 0, CharSetCount = 0;
     PUNICODE_STRING     pFileName       = pLoadFont->pFileName;
     DWORD               Characteristics = pLoadFont->Characteristics;
     PUNICODE_STRING     pValueName = &pLoadFont->RegValueName;
@@ -971,7 +972,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
         FontGDI->CharSet = SYMBOL_CHARSET;
     }
 
-    ++FontCount;
+    ++FaceCount;
     DPRINT("Font loaded: %s (%s)\n", Face->family_name, Face->style_name);
     DPRINT("Num glyphs: %d\n", Face->num_glyphs);
     DPRINT("CharSet: %d\n", FontGDI->CharSet);
@@ -1006,7 +1007,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
                 FT_Long i;
                 for (i = 1; i < TrueType->ttc_header.count; ++i)
                 {
-                    FontCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
+                    FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
                 }
             }
         }
@@ -1042,11 +1043,12 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
 
         for (i = 1; i < CharSetCount; ++i)
         {
-            FontCount += IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
+            /* Do not count charsets towards 'faces' loaded */
+            IntGdiLoadFontsFromMemory(pLoadFont, SharedFace, FontIndex, i);
         }
     }
 
-    return FontCount;   /* number of loaded fonts */
+    return FaceCount;   /* number of loaded faces */
 }
 
 /*
@@ -1172,7 +1174,7 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
 {
     GDI_LOAD_FONT LoadFont;
     FONT_ENTRY_COLL_MEM* EntryCollection;
-    INT FontCount;
+    INT FaceCount;
     HANDLE Ret = 0;
 
     PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
@@ -1190,7 +1192,7 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
     RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
     LoadFont.IsTrueType = FALSE;
     LoadFont.PrivateEntry = NULL;
-    FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
+    FaceCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1);
 
     RtlFreeUnicodeString(&LoadFont.RegValueName);
 
@@ -1199,7 +1201,7 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
     SharedMem_Release(LoadFont.Memory);
     IntUnLockFreeType;
 
-    if (FontCount > 0)
+    if (FaceCount > 0)
     {
         EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
         if (EntryCollection)
@@ -1213,7 +1215,7 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
             Ret = (HANDLE)EntryCollection->Handle;
         }
     }
-    *pNumAdded = FontCount;
+    *pNumAdded = FaceCount;
 
     return Ret;
 }
@@ -2040,30 +2042,40 @@ SwapEndian(LPVOID pvData, DWORD Size)
 }
 
 static NTSTATUS
-IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, FT_Face Face,
+                        FT_UShort NameID, FT_UShort LangID)
 {
     FT_SfntName Name;
     INT i, Count;
-    WCHAR Buf[LF_FACESIZE];
+    WCHAR Buf[LF_FULLFACESIZE];
+    FT_Error Error;
     NTSTATUS Status = STATUS_NOT_FOUND;
+    ANSI_STRING AnsiName;
 
-    RtlInitUnicodeString(pLocalNameW, NULL);
+    RtlInitUnicodeString(pNameW, NULL);
 
     Count = FT_Get_Sfnt_Name_Count(Face);
     for (i = 0; i < Count; ++i)
     {
-        FT_Get_Sfnt_Name(Face, i, &Name);
+        Error = FT_Get_Sfnt_Name(Face, i, &Name);
+        if (Error)
+            continue;
+
         if (Name.platform_id != TT_PLATFORM_MICROSOFT ||
             Name.encoding_id != TT_MS_ID_UNICODE_CS)
         {
             continue;   /* not Microsoft Unicode name */
         }
 
-        if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
-            Name.string == NULL || Name.string_len == 0 ||
+        if (Name.name_id != NameID || Name.language_id != LangID)
+        {
+            continue;   /* mismatched */
+        }
+
+        if (Name.string == NULL || Name.string_len == 0 ||
             (Name.string[0] == 0 && Name.string[1] == 0))
         {
-            continue;   /* not family name */
+            continue;   /* invalid string */
         }
 
         if (sizeof(Buf) < Name.string_len + sizeof(UNICODE_NULL))
@@ -2077,14 +2089,24 @@ IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
 
         /* Convert UTF-16 big endian to little endian */
         SwapEndian(Buf, Name.string_len);
-#if 0
-        DPRINT("IntGetFontLocalizedName: %S (%d)\n", Buf, Name.string_len);
-#endif
 
-        Status = RtlCreateUnicodeString(pLocalNameW, Buf);
+        Status = RtlCreateUnicodeString(pNameW, Buf);
         break;
     }
 
+    if (Status == STATUS_NOT_FOUND)
+    {
+        if (LangID != gusEnglishUS)
+        {
+            Status = IntGetFontLocalizedName(pNameW, Face, NameID, gusEnglishUS);
+        }
+    }
+    if (Status == STATUS_NOT_FOUND)
+    {
+        RtlInitAnsiString(&AnsiName, Face->family_name);
+        Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
+    }
+
     return Status;
 }
 
@@ -2166,36 +2188,33 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
 
     ExFreePoolWithTag(Otm, GDITAG_TEXT);
 
-    /* try the localized name */
-    status = STATUS_UNSUCCESSFUL;
-    if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
+    /* 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
     {
-        /* get localized name */
-        UNICODE_STRING LocalNameW;
-        status = IntGetFontLocalizedName(&LocalNameW, Face);
+        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),
-                             LocalNameW.Buffer);
+                             NameW.Buffer);
             RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
                              sizeof(Info->EnumLogFontEx.elfFullName),
-                             LocalNameW.Buffer);
+                             NameW.Buffer);
+            RtlFreeUnicodeString(&NameW);
         }
-        RtlFreeUnicodeString(&LocalNameW);
-    }
-
-    /* if localized name was unavailable */
-    if (!NT_SUCCESS(status))
-    {
-        /* store English name */
-        RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName,
-                         sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName),
-                         FaceName);
-        RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
-                         sizeof(Info->EnumLogFontEx.elfFullName),
-                         FaceName);
     }
 
     RtlInitAnsiString(&StyleA, Face->style_name);
@@ -2206,19 +2225,9 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, PCWSTR FaceName, PFONTGDI FontGDI)
     {
         return;
     }
-    if (StyleW.Length)
-    {
-        if (wcslen(Info->EnumLogFontEx.elfFullName) +
-            StyleW.Length / sizeof(WCHAR) + 1 <=
-                sizeof(Info->EnumLogFontEx.elfFullName))
-        {
-            wcscat(Info->EnumLogFontEx.elfFullName, L" ");
-            wcscat(Info->EnumLogFontEx.elfFullName, StyleW.Buffer);
-        }
-    }
-
     Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
-    Info->EnumLogFontEx.elfScript[0] = L'\0';
+    Info->EnumLogFontEx.elfScript[0] = UNICODE_NULL;
+
     IntLockFreeType;
     pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
 
@@ -3916,6 +3925,7 @@ GetFontPenalty(LOGFONTW *               LogFont,
     LONG    Long;
     BOOL    fFixedSys = FALSE, fNeedScaling = FALSE;
     const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
+    NTSTATUS Status;
 
     /* FIXME: Aspect Penalty 30 */
     /* FIXME: IntSizeSynth Penalty 20 */
@@ -4051,32 +4061,58 @@ GetFontPenalty(LOGFONTW *               LogFont,
 
     if (RequestedNameW->Buffer[0])
     {
-        if (RtlEqualUnicodeString(RequestedNameW, FullFaceNameW, TRUE))
+        BOOL Found = FALSE;
+        FT_Face Face = FontGDI->SharedFace->Face;
+
+        /* localized family name */
+        if (!Found)
         {
-            /* matched with full face name */
+            Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FONT_FAMILY,
+                                             gusLanguageID);
+            if (NT_SUCCESS(Status))
+            {
+                Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
+            }
         }
-        else if (RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE))
+        /* localized full name */
+        if (!Found)
         {
-            /* matched with actual name */
+            Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FULL_NAME,
+                                             gusLanguageID);
+            if (NT_SUCCESS(Status))
+            {
+                Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
+            }
         }
-        else
+        if (gusLanguageID != gusEnglishUS)
         {
-            /* try the localized name */
-            UNICODE_STRING LocalNameW;
-            FT_Face Face = FontGDI->SharedFace->Face;
-            IntGetFontLocalizedName(&LocalNameW, Face);
-            if (RtlEqualUnicodeString(RequestedNameW, &LocalNameW, TRUE))
+            /* English family name */
+            if (!Found)
             {
-                /* matched with localizied name */
+                Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FONT_FAMILY,
+                                                 gusEnglishUS);
+                if (NT_SUCCESS(Status))
+                {
+                    Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
+                }
             }
-            else
+            /* English full name */
+            if (!Found)
             {
-                /* FaceName Penalty 10000 */
-                /* Requested a face name, but the candidate's face name
-                   does not match. */
-                Penalty += 10000;
+                Status = IntGetFontLocalizedName(ActualNameW, Face, TT_NAME_ID_FULL_NAME,
+                                                 gusEnglishUS);
+                if (NT_SUCCESS(Status))
+                {
+                    Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
+                }
             }
-            RtlFreeUnicodeString(&LocalNameW);
+        }
+        if (!Found)
+        {
+            /* FaceName Penalty 10000 */
+            /* Requested a face name, but the candidate's face name
+               does not match. */
+            Penalty += 10000;
         }
     }