[WIN32SS] Improve GetFontResourceInfoW. Patch by Katayama Hirofumi MZ & Doug Lyons.
[reactos.git] / reactos / win32ss / gdi / ntgdi / freetype.c
index f76be2e..5252f15 100644 (file)
@@ -52,8 +52,6 @@ static const WORD gusEnglishUS = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
 
 /* special font names */
 static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett");
-static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System");
-static const UNICODE_STRING FixedSysW = RTL_CONSTANT_STRING(L"FixedSys");
 
 /* registry */
 static UNICODE_STRING FontRegPath =
@@ -599,7 +597,7 @@ SubstituteFontRecurse(LOGFONTW* pLogFont)
         if (!Found)
             break;
 
-        RtlStringCbCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
+        RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer);
 
         if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
             CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
@@ -814,7 +812,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
 
         IntUnLockFreeType;
 
-        if (FT_IS_SFNT(Face))
+        if (!Error && FT_IS_SFNT(Face))
             pLoadFont->IsTrueType = TRUE;
 
         if (Error || SharedFace == NULL)
@@ -2452,165 +2450,130 @@ FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
     return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
 }
 
+static BOOL FASTCALL
+FontFamilyFound(PFONTFAMILYINFO InfoEntry,
+                PFONTFAMILYINFO Info, DWORD InfoCount)
+{
+    LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont;
+    LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName;
+    LPWSTR pFullName2;
+    DWORD i;
+
+    for (i = 0; i < InfoCount; ++i)
+    {
+        LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont;
+        if (plf1->lfCharSet != plf2->lfCharSet)
+            continue;
+
+        pFullName2 = Info[i].EnumLogFontEx.elfFullName;
+        if (_wcsicmp(pFullName1, pFullName2) != 0)
+            continue;
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
 static BOOLEAN FASTCALL
 GetFontFamilyInfoForList(LPLOGFONTW LogFont,
                          PFONTFAMILYINFO Info,
-                         DWORD *Count,
-                         DWORD Size,
+                         DWORD *pCount,
+                         DWORD MaxCount,
                          PLIST_ENTRY Head)
 {
     PLIST_ENTRY Entry;
     PFONT_ENTRY CurrentEntry;
-    ANSI_STRING EntryFaceNameA;
-    UNICODE_STRING EntryFaceNameW;
     FONTGDI *FontGDI;
-    NTSTATUS status;
+    FONTFAMILYINFO InfoEntry;
+    DWORD Count = *pCount;
 
-    Entry = Head->Flink;
-    while (Entry != Head)
+    for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
     {
-        CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
-
+        CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
         FontGDI = CurrentEntry->Font;
         ASSERT(FontGDI);
 
-        RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
-        status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
-        if (!NT_SUCCESS(status))
+        if (LogFont->lfCharSet != DEFAULT_CHARSET &&
+            LogFont->lfCharSet != FontGDI->CharSet)
         {
-            return FALSE;
+            continue;
         }
 
-        if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+        if (LogFont->lfFaceName[0] == UNICODE_NULL)
         {
-            EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
-            EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
+            if (Count < MaxCount)
+            {
+                FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
+            }
+            Count++;
+            continue;
+        }
+
+        FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
+
+        if (_wcsicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName) != 0 &&
+            _wcsicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName) != 0)
+        {
+            continue;
         }
 
-        if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
+        if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
         {
-            if (*Count < Size)
+            if (Count < MaxCount)
             {
-                FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer,
-                                   NULL, FontGDI);
+                RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
             }
-            (*Count)++;
+            Count++;
         }
-        RtlFreeUnicodeString(&EntryFaceNameW);
-        Entry = Entry->Flink;
     }
 
+    *pCount = Count;
+
     return TRUE;
 }
 
-typedef struct FontFamilyInfoCallbackContext
-{
-    LPLOGFONTW LogFont;
-    PFONTFAMILYINFO Info;
-    DWORD Count;
-    DWORD Size;
-} FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT;
-
-_Function_class_(RTL_QUERY_REGISTRY_ROUTINE)
-static NTSTATUS APIENTRY
-FontFamilyInfoQueryRegistryCallback(IN PWSTR ValueName, IN ULONG ValueType,
-                                    IN PVOID ValueData, IN ULONG ValueLength,
-                                    IN PVOID Context, IN PVOID EntryContext)
+static BOOLEAN FASTCALL
+GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
+                                PFONTFAMILYINFO Info,
+                                DWORD *pCount,
+                                DWORD MaxCount)
 {
-    PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext;
-    UNICODE_STRING RegistryName, RegistryValue;
-    int Existing;
-    PFONTGDI FontGDI;
+    PLIST_ENTRY pEntry, pHead = &FontSubstListHead;
+    PFONTSUBST_ENTRY pCurrentEntry;
+    PUNICODE_STRING pFromW;
+    FONTGDI *FontGDI;
+    LOGFONTW lf = *LogFont;
+    UNICODE_STRING NameW;
 
-    if (REG_SZ != ValueType)
+    for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
     {
-        return STATUS_SUCCESS;
-    }
-    InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context;
-    RtlInitUnicodeString(&RegistryName, ValueName);
+        pCurrentEntry = CONTAINING_RECORD(pEntry, FONTSUBST_ENTRY, ListEntry);
 
-    /* Do we need to include this font family? */
-    if (FontFamilyInclude(InfoContext->LogFont, &RegistryName, InfoContext->Info,
-                          min(InfoContext->Count, InfoContext->Size)))
-    {
-        RtlInitUnicodeString(&RegistryValue, (PCWSTR) ValueData);
-        Existing = FindFaceNameInInfo(&RegistryValue, InfoContext->Info,
-                                      min(InfoContext->Count, InfoContext->Size));
-        if (0 <= Existing)
+        pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
+        if (LogFont->lfFaceName[0] != UNICODE_NULL)
         {
-            /* We already have the information about the "real" font. Just copy it */
-            if (InfoContext->Count < InfoContext->Size)
-            {
-                InfoContext->Info[InfoContext->Count] = InfoContext->Info[Existing];
-                RtlStringCbCopyNW(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName,
-                                  sizeof(InfoContext->Info[InfoContext->Count].EnumLogFontEx.elfLogFont.lfFaceName),
-                                  RegistryName.Buffer,
-                                  RegistryName.Length);
-            }
-            InfoContext->Count++;
-            return STATUS_SUCCESS;
+            if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount)))
+                continue;   /* mismatch */
         }
 
-        /* Try to find information about the "real" font */
-        FontGDI = FindFaceNameInLists(&RegistryValue);
-        if (NULL == FontGDI)
+        RtlStringCchCopyW(lf.lfFaceName, LF_FACESIZE, pFromW->Buffer);
+        SubstituteFontRecurse(&lf);
+
+        RtlInitUnicodeString(&NameW, lf.lfFaceName);
+        FontGDI = FindFaceNameInLists(&NameW);
+        if (FontGDI == NULL)
         {
-            /* "Real" font not found, discard this registry entry */
-            return STATUS_SUCCESS;
+            continue;   /* no real font */
         }
 
-        /* Return info about the "real" font but with the name of the alias */
-        if (InfoContext->Count < InfoContext->Size)
+        if (*pCount < MaxCount)
         {
-            FontFamilyFillInfo(InfoContext->Info + InfoContext->Count,
-                               RegistryName.Buffer, NULL, FontGDI);
+            FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI);
         }
-        InfoContext->Count++;
-        return STATUS_SUCCESS;
-    }
-
-    return STATUS_SUCCESS;
-}
-
-static BOOLEAN FASTCALL
-GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
-                                PFONTFAMILYINFO Info,
-                                DWORD *Count,
-                                DWORD Size)
-{
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
-    FONT_FAMILY_INFO_CALLBACK_CONTEXT Context;
-    NTSTATUS Status;
-
-    /* Enumerate font families found in HKLM\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes
-       The real work is done in the registry callback function */
-    Context.LogFont = LogFont;
-    Context.Info = Info;
-    Context.Count = *Count;
-    Context.Size = Size;
-
-    QueryTable[0].QueryRoutine = FontFamilyInfoQueryRegistryCallback;
-    QueryTable[0].Flags = 0;
-    QueryTable[0].Name = NULL;
-    QueryTable[0].EntryContext = NULL;
-    QueryTable[0].DefaultType = REG_NONE;
-    QueryTable[0].DefaultData = NULL;
-    QueryTable[0].DefaultLength = 0;
-
-    QueryTable[1].QueryRoutine = NULL;
-    QueryTable[1].Name = NULL;
-
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
-                                    L"FontSubstitutes",
-                                    QueryTable,
-                                    &Context,
-                                    NULL);
-    if (NT_SUCCESS(Status))
-    {
-        *Count = Context.Count;
+        (*pCount)++;
     }
 
-    return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
+    return TRUE;
 }
 
 BOOL
@@ -4045,7 +4008,7 @@ GetFontPenalty(const LOGFONTW *               LogFont,
     ULONG   Penalty = 0;
     BYTE    Byte;
     LONG    Long;
-    BOOL    fFixedSys = FALSE, fNeedScaling = FALSE;
+    BOOL    fNeedScaling = FALSE;
     const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
     const TEXTMETRICW * TM = &Otm->otmTextMetrics;
     WCHAR* ActualNameW;
@@ -4059,62 +4022,38 @@ GetFontPenalty(const LOGFONTW *               LogFont,
     /* FIXME: SmallPenalty Penalty 1 */
     /* FIXME: FaceNameSubst Penalty 500 */
 
-    if (_wcsicmp(LogFont->lfFaceName, L"System") == 0)
+    Byte = LogFont->lfCharSet;
+    if (Byte == DEFAULT_CHARSET)
     {
-        /* "System" font */
-        if (TM->tmCharSet != UserCharSet)
+        if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
         {
-            /* CharSet Penalty 65000 */
-            /* Requested charset does not match the candidate's. */
-            Penalty += 65000;
+            if (Byte == ANSI_CHARSET)
+            {
+                DPRINT("Warning: FIXME: It's Marlett but ANSI_CHARSET.\n");
+            }
+            /* We assume SYMBOL_CHARSET for "Marlett" font */
+            Byte = SYMBOL_CHARSET;
         }
     }
-    else if (_wcsicmp(LogFont->lfFaceName, L"FixedSys") == 0)
+
+    if (Byte != TM->tmCharSet)
     {
-        /* "FixedSys" font */
-        if (TM->tmCharSet != UserCharSet)
+        if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
         {
             /* CharSet Penalty 65000 */
             /* Requested charset does not match the candidate's. */
             Penalty += 65000;
         }
-        fFixedSys = TRUE;
-    }
-    else    /* Request is non-"System" font */
-    {
-        Byte = LogFont->lfCharSet;
-        if (Byte == DEFAULT_CHARSET)
-        {
-            if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 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 (Byte != TM->tmCharSet)
+        else
         {
-            if (Byte != DEFAULT_CHARSET && Byte != ANSI_CHARSET)
-            {
-                /* CharSet Penalty 65000 */
-                /* Requested charset does not match the candidate's. */
-                Penalty += 65000;
-            }
-            else
+            if (UserCharSet != TM->tmCharSet)
             {
-                if (UserCharSet != TM->tmCharSet)
+                /* UNDOCUMENTED */
+                Penalty += 100;
+                if (ANSI_CHARSET != TM->tmCharSet)
                 {
                     /* UNDOCUMENTED */
                     Penalty += 100;
-                    if (ANSI_CHARSET != TM->tmCharSet)
-                    {
-                        /* UNDOCUMENTED */
-                        Penalty += 100;
-                    }
                 }
             }
         }
@@ -4149,11 +4088,6 @@ GetFontPenalty(const LOGFONTW *               LogFont,
     Byte = (LogFont->lfPitchAndFamily & 0x0F);
     if (Byte == DEFAULT_PITCH)
         Byte = VARIABLE_PITCH;
-    if (fFixedSys)
-    {
-        /* "FixedSys" font should be fixed-pitch */
-        Byte = FIXED_PITCH;
-    }
     if (Byte == FIXED_PITCH)
     {
         if (TM->tmPitchAndFamily & _TMPF_VARIABLE_PITCH)
@@ -4647,28 +4581,23 @@ IntGetFullFileName(
 }
 
 static BOOL
-EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2)
+EqualFamilyInfo(const FONTFAMILYINFO *pInfo1, const FONTFAMILYINFO *pInfo2)
 {
-    UNICODE_STRING Str1, Str2;
-    ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
-    ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
-    RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName);
-    RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName);
-    if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
+    const ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx;
+    const ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx;
+    const LOGFONTW *plf1 = &pLog1->elfLogFont;
+    const LOGFONTW *plf2 = &pLog2->elfLogFont;
+
+    if (_wcsicmp(plf1->lfFaceName, plf2->lfFaceName) != 0)
     {
         return FALSE;
     }
-    if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL))
-        return FALSE;
-    if (pLog1->elfStyle != NULL)
+
+    if (_wcsicmp(pLog1->elfStyle, pLog2->elfStyle) != 0)
     {
-        RtlInitUnicodeString(&Str1, pLog1->elfStyle);
-        RtlInitUnicodeString(&Str2, pLog2->elfStyle);
-        if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE))
-        {
-            return FALSE;
-        }
+        return FALSE;
     }
+
     return TRUE;
 }
 
@@ -5182,12 +5111,6 @@ GreExtTextOutW(
         EngSetLastError(ERROR_INVALID_HANDLE);
         return FALSE;
     }
-    if (dc->dctype == DC_TYPE_INFO)
-    {
-        DC_UnlockDc(dc);
-        /* Yes, Windows really returns TRUE in this case */
-        return TRUE;
-    }
 
     pdcattr = dc->pdcattr;
 
@@ -5219,6 +5142,13 @@ GreExtTextOutW(
         goto good;
     }
 
+    if (!dc->dclevel.pSurface)
+    {
+        /* Memory DC with no surface selected */
+        DC_UnlockDc(dc);
+        return TRUE;
+    }
+
     if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
     {
         IntLPtoDP(dc, (POINT *)lprc, 2);
@@ -5244,11 +5174,6 @@ GreExtTextOutW(
     BrushOrigin.x = 0;
     BrushOrigin.y = 0;
 
-    if (!dc->dclevel.pSurface)
-    {
-        goto fail;
-    }
-
     if ((fuOptions & ETO_OPAQUE) && lprc)
     {
         DestRect.left   = lprc->left;
@@ -5276,7 +5201,7 @@ GreExtTextOutW(
             &psurf->SurfObj,
             NULL,
             NULL,
-            &dc->co.ClipObj,
+            (CLIPOBJ *)&dc->co,
             NULL,
             &DestRect,
             &SourcePoint,
@@ -5546,7 +5471,7 @@ GreExtTextOutW(
                 &psurf->SurfObj,
                 NULL,
                 NULL,
-                &dc->co.ClipObj,
+                (CLIPOBJ *)&dc->co,
                 NULL,
                 &DestRect,
                 &SourcePoint,
@@ -5682,7 +5607,7 @@ GreExtTextOutW(
                 &psurf->SurfObj,
                 NULL,
                 NULL,
-                &dc->co.ClipObj,
+                (CLIPOBJ *)&dc->co,
                 NULL,
                 &DestRect,
                 &SourcePoint,
@@ -5755,7 +5680,7 @@ GreExtTextOutW(
             if (!IntEngMaskBlt(
                 SurfObj,
                 SourceGlyphSurf,
-                &dc->co.ClipObj,
+                (CLIPOBJ *)&dc->co,
                 &exloRGB2Dst.xlo,
                 &exloDst2RGB.xlo,
                 &DestRect,
@@ -5792,7 +5717,7 @@ GreExtTextOutW(
             for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
             {
                 EngLineTo(SurfObj,
-                          &dc->co.ClipObj,
+                          (CLIPOBJ *)&dc->co,
                           &dc->eboText.BrushObject,
                           (TextLeft >> 6),
                           TextTop + yoff - position + i,
@@ -5808,7 +5733,7 @@ GreExtTextOutW(
             for (i = -thickness / 2; i < -thickness / 2 + thickness; ++i)
             {
                 EngLineTo(SurfObj,
-                          &dc->co.ClipObj,
+                          (CLIPOBJ *)&dc->co,
                           &dc->eboText.BrushObject,
                           (TextLeft >> 6),
                           TextTop + yoff - (fixAscender >> 6) / 3 + i,