Index: reactos/win32ss/gdi/ntgdi/freetype.c =================================================================== --- reactos/win32ss/gdi/ntgdi/freetype.c (revision 74295) +++ reactos/win32ss/gdi/ntgdi/freetype.c (working copy) @@ -49,6 +49,8 @@ FT_Library library; +static const WORD gusEnglishUS = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); + /* special font names */ static const UNICODE_STRING MarlettW = RTL_CONSTANT_STRING(L"Marlett"); static const UNICODE_STRING SystemW = RTL_CONSTANT_STRING(L"System"); @@ -1549,6 +1551,10 @@ FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE); } +static NTSTATUS +IntGetFontName(PUNICODE_STRING pNameW, FT_Face Face, + FT_UShort NameID, FT_UShort LangID); + /************************************************************* * IntGetOutlineTextMetrics * @@ -1558,32 +1564,41 @@ UINT Size, OUTLINETEXTMETRICW *Otm) { - unsigned Needed; + UINT Needed; TT_OS2 *pOS2; TT_HoriHeader *pHori; TT_Postscript *pPost; FT_Fixed XScale, YScale; - ANSI_STRING FamilyNameA, StyleNameA; - UNICODE_STRING FamilyNameW, StyleNameW, Regular; + ANSI_STRING StyleNameA; + UNICODE_STRING FamilyNameW, FullNameW, StyleNameW; FT_WinFNT_HeaderRec Win; FT_Error Error; - char *Cp; + LPBYTE BytePtr; NTSTATUS status; FT_Face Face = FontGDI->SharedFace->Face; - Needed = sizeof(OUTLINETEXTMETRICW); - - RtlInitAnsiString(&FamilyNameA, Face->family_name); - status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE); + /* get family name */ + status = IntGetFontName(&FamilyNameW, Face, TT_NAME_ID_FONT_FAMILY, + gusLanguageID); if (!NT_SUCCESS(status)) { return 0; } + /* get full name */ + status = IntGetFontName(&FullNameW, Face, TT_NAME_ID_FONT_FAMILY, + gusLanguageID); + if (!NT_SUCCESS(status)) + { + RtlFreeUnicodeString(&FamilyNameW); + return 0; + } + /* get style name */ RtlInitAnsiString(&StyleNameA, Face->style_name); status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE); if (!NT_SUCCESS(status)) { + RtlFreeUnicodeString(&FullNameW); RtlFreeUnicodeString(&FamilyNameW); return 0; } @@ -1590,30 +1605,25 @@ /* These names should be read from the TT name table */ + Needed = sizeof(OUTLINETEXTMETRICW); /* Length of otmpFamilyName */ Needed += FamilyNameW.Length + sizeof(WCHAR); - - 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 */ - } - + Needed += FamilyNameW.Length + sizeof(WCHAR); /* Length of otmpStyleName */ Needed += StyleNameW.Length + sizeof(WCHAR); - /* Length of otmpFullName */ - Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1); + Needed += FullNameW.Length + sizeof(WCHAR); if (Size < Needed) { + if (Size != 0) + { + DPRINT("Size < Needed\n"); + } + RtlFreeUnicodeString(&StyleNameW); + RtlFreeUnicodeString(&FullNameW); RtlFreeUnicodeString(&FamilyNameW); - RtlFreeUnicodeString(&StyleNameW); return Needed; } @@ -1627,6 +1637,7 @@ IntUnLockFreeType; DPRINT1("Can't find OS/2 table - not TT font?\n"); RtlFreeUnicodeString(&StyleNameW); + RtlFreeUnicodeString(&FullNameW); RtlFreeUnicodeString(&FamilyNameW); return 0; } @@ -1637,6 +1648,7 @@ IntUnLockFreeType; DPRINT1("Can't find HHEA table - not TT font?\n"); RtlFreeUnicodeString(&StyleNameW); + RtlFreeUnicodeString(&FullNameW); RtlFreeUnicodeString(&FamilyNameW); return 0; } @@ -1694,31 +1706,27 @@ IntUnLockFreeType; /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */ - Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW); - Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm); - wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); - Cp += FamilyNameW.Length + sizeof(WCHAR); - 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); - } - Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm); - wcscpy((WCHAR*) Cp, FamilyNameW.Buffer); - wcscat((WCHAR*) Cp, L" "); - wcscat((WCHAR*) Cp, StyleNameW.Buffer); + BytePtr = (LPBYTE)Otm + sizeof(OUTLINETEXTMETRICW); + Otm->otmpFamilyName = (LPSTR)(BytePtr - (LPBYTE)Otm); + wcscpy((WCHAR*) BytePtr, FamilyNameW.Buffer); + BytePtr += FamilyNameW.Length + sizeof(WCHAR); + Otm->otmpStyleName = (LPSTR)(BytePtr - (LPBYTE)Otm); + wcscpy((WCHAR*) BytePtr, StyleNameW.Buffer); + + BytePtr += StyleNameW.Length + sizeof(WCHAR); + Otm->otmpFaceName = (LPSTR)(BytePtr - (LPBYTE)Otm); + wcscpy((WCHAR*) BytePtr, FamilyNameW.Buffer); + + BytePtr += FamilyNameW.Length + sizeof(WCHAR); + Otm->otmpFullName = (LPSTR)(BytePtr - (LPBYTE)Otm); + wcscpy((WCHAR*) BytePtr, FullNameW.Buffer); + + BytePtr += FullNameW.Length + sizeof(WCHAR); + ASSERT(Needed == BytePtr - (LPBYTE)Otm); + RtlFreeUnicodeString(&StyleNameW); + RtlFreeUnicodeString(&FullNameW); RtlFreeUnicodeString(&FamilyNameW); return Needed; @@ -1729,13 +1737,12 @@ { PLIST_ENTRY Entry; PFONT_ENTRY CurrentEntry; - ANSI_STRING EntryFaceNameA; - UNICODE_STRING EntryFaceNameW; + UNICODE_STRING NameW; FONTGDI *FontGDI; NTSTATUS status; + FT_Face Face; - Entry = Head->Flink; - while (Entry != Head) + for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); @@ -1742,27 +1749,57 @@ FontGDI = CurrentEntry->Font; ASSERT(FontGDI); - RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name); - status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); - if (!NT_SUCCESS(status)) + Face = FontGDI->SharedFace->Face; + ASSERT(Face); + + /* localized family name */ + status = IntGetFontName(&NameW, Face, TT_NAME_ID_FONT_FAMILY, + gusLanguageID); + if (NT_SUCCESS(status)) { - break; + if (NameW.Length && RtlEqualUnicodeString(FaceName, &NameW, TRUE)) + { + RtlFreeUnicodeString(&NameW); + return FontGDI; + } + RtlFreeUnicodeString(&NameW); } - - if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) + /* localized full name */ + status = IntGetFontName(&NameW, Face, TT_NAME_ID_FULL_NAME, + gusLanguageID); + if (NT_SUCCESS(status)) { - EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); - EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; + if (NameW.Length && RtlEqualUnicodeString(FaceName, &NameW, TRUE)) + { + RtlFreeUnicodeString(&NameW); + return FontGDI; + } + RtlFreeUnicodeString(&NameW); } - - if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE)) + /* English family name */ + status = IntGetFontName(&NameW, Face, TT_NAME_ID_FONT_FAMILY, + gusEnglishUS); + if (NT_SUCCESS(status)) { - RtlFreeUnicodeString(&EntryFaceNameW); - return FontGDI; + if (NameW.Length && RtlEqualUnicodeString(FaceName, &NameW, TRUE)) + { + RtlFreeUnicodeString(&NameW); + return FontGDI; + } + RtlFreeUnicodeString(&NameW); } - - RtlFreeUnicodeString(&EntryFaceNameW); - Entry = Entry->Flink; + /* English full name */ + status = IntGetFontName(&NameW, Face, TT_NAME_ID_FULL_NAME, + gusEnglishUS); + if (NT_SUCCESS(status)) + { + if (NameW.Length && RtlEqualUnicodeString(FaceName, &NameW, TRUE)) + { + RtlFreeUnicodeString(&NameW); + return FontGDI; + } + RtlFreeUnicodeString(&NameW); + } } return NULL; @@ -1852,19 +1889,25 @@ } static NTSTATUS -IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face) +IntGetFontName(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) { @@ -1871,11 +1914,15 @@ 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)) @@ -1889,19 +1936,30 @@ /* 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 = IntGetFontName(pNameW, Face, NameID, gusEnglishUS); + } + } + if (Status == STATUS_NOT_FOUND) + { + RtlInitAnsiString(&AnsiName, Face->family_name); + Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE); + } + 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; @@ -1916,6 +1974,7 @@ DWORD fs0; NTSTATUS status; FT_Face Face = FontGDI->SharedFace->Face; + UNICODE_STRING NameW; RtlZeroMemory(Info, sizeof(FONTFAMILYINFO)); Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL); @@ -1978,37 +2037,47 @@ ExFreePoolWithTag(Otm, GDITAG_TEXT); - /* try the localized name */ - status = STATUS_UNSUCCESSFUL; - if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet) + /* face name */ + if (FaceName) { - /* get localized name */ - UNICODE_STRING LocalNameW; - status = IntGetFontLocalizedName(&LocalNameW, Face); + RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName, + sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName), + FaceName); + } + else + { + status = IntGetFontName(&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); - 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)) + /* full name */ + if (FullName) { - /* store English name */ RtlStringCbCopyW(Info->EnumLogFontEx.elfLogFont.lfFaceName, sizeof(Info->EnumLogFontEx.elfLogFont.lfFaceName), - FaceName); - RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName, - sizeof(Info->EnumLogFontEx.elfFullName), - FaceName); + FullName); } + else + { + status = IntGetFontName(&NameW, Face, TT_NAME_ID_FULL_NAME, + gusLanguageID); + if (NT_SUCCESS(status)) + { + /* store it */ + RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName, + sizeof(Info->EnumLogFontEx.elfFullName), + NameW.Buffer); + RtlFreeUnicodeString(&NameW); + } + } RtlInitAnsiString(&StyleA, Face->style_name); StyleW.Buffer = Info->EnumLogFontEx.elfStyle; @@ -2016,21 +2085,10 @@ status = RtlAnsiStringToUnicodeString(&StyleW, &StyleA, FALSE); if (!NT_SUCCESS(status)) { - 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); @@ -2089,9 +2147,10 @@ } if (DEFAULT_CHARSET != CharSetInfo.ciCharset) { - Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset; if (ElfScripts[i]) + { wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]); + } else { DPRINT1("Unknown elfscript for bit %u\n", i); @@ -2103,55 +2162,103 @@ } static int FASTCALL -FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries) +FindFontInInfo(PUNICODE_STRING pNameW, PUNICODE_STRING pFamilyW, + FONTGDI *FontGDI, PFONTFAMILYINFO Info, DWORD InfoEntries) { DWORD i; - UNICODE_STRING InfoFaceName; + LOGFONTW *plfInfo; + UNICODE_STRING InfoFaceNameW; for (i = 0; i < InfoEntries; i++) { - RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName); - if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE)) + /* See also EnumFontFamiliesEx */ + if (FontGDI->CharSet != DEFAULT_CHARSET && + FontGDI->CharSet != plfInfo->lfCharSet) { - return i; + continue; /* not matched */ } + + plfInfo = &Info[i].EnumLogFontEx.elfLogFont; + RtlInitUnicodeString(&InfoFaceNameW, plfInfo->lfFaceName); + if (!RtlEqualUnicodeString(&InfoFaceNameW, pFamilyW, TRUE)) + { + continue; /* not matched */ + } + + return i; /* found matched one */ } - return -1; + return -1; /* not found */ } static BOOLEAN FASTCALL -FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName, - PFONTFAMILYINFO Info, DWORD InfoEntries) +DoesAddFontToInfo(LPLOGFONTW plfPattern, PUNICODE_STRING pNameW, + FONTGDI *FontGDI, PFONTFAMILYINFO Info, DWORD InfoEntries) { - UNICODE_STRING LogFontFaceName; + FT_Face Face = FontGDI->SharedFace->Face; + UNICODE_STRING PatternNameW; + UNICODE_STRING EnglishFamilyNameW, LocalFamilyNameW; + UNICODE_STRING EnglishFullNameW, LocalFullNameW; + INT FoundIndex; - RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName); - if (0 != LogFontFaceName.Length && - !RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE)) + /* get family name */ + IntGetFontName(&EnglishFamilyNameW, Face, TT_NAME_ID_FONT_FAMILY, + gusEnglishUS); + IntGetFontName(&EnglishFullNameW, Face, TT_NAME_ID_FULL_NAME, + gusEnglishUS); + IntGetFontName(&LocalFamilyNameW, Face, TT_NAME_ID_FONT_FAMILY, + gusLanguageID); + IntGetFontName(&LocalFullNameW, Face, TT_NAME_ID_FULL_NAME, + gusLanguageID); + + /* check pattern name */ + RtlInitUnicodeString(&PatternNameW, plfPattern->lfFaceName); + if (PatternNameW.Length != 0) { - return FALSE; + if (!RtlEqualUnicodeString(&PatternNameW, &EnglishFamilyNameW, TRUE) && + !RtlEqualUnicodeString(&PatternNameW, &EnglishFullNameW, TRUE) && + !RtlEqualUnicodeString(&PatternNameW, &LocalFamilyNameW, TRUE) && + !RtlEqualUnicodeString(&PatternNameW, &LocalFullNameW, TRUE)) + { + RtlFreeUnicodeString(&EnglishFamilyNameW); + RtlFreeUnicodeString(&EnglishFullNameW); + RtlFreeUnicodeString(&LocalFamilyNameW); + RtlFreeUnicodeString(&LocalFullNameW); + return FALSE; + } } - return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0; + FoundIndex = FindFontInInfo(pNameW, &LocalFamilyNameW, FontGDI, Info, + InfoEntries); + if (FoundIndex == -1) + { + FoundIndex = FindFontInInfo(pNameW, &EnglishFamilyNameW, FontGDI, + Info, InfoEntries); + } + + RtlFreeUnicodeString(&EnglishFamilyNameW); + RtlFreeUnicodeString(&EnglishFullNameW); + RtlFreeUnicodeString(&LocalFamilyNameW); + RtlFreeUnicodeString(&LocalFullNameW); + return FoundIndex == -1; } static BOOLEAN FASTCALL GetFontFamilyInfoForList(LPLOGFONTW LogFont, PFONTFAMILYINFO Info, - DWORD *Count, + DWORD *pCount, DWORD Size, PLIST_ENTRY Head) { PLIST_ENTRY Entry; PFONT_ENTRY CurrentEntry; - ANSI_STRING EntryFaceNameA; - UNICODE_STRING EntryFaceNameW; FONTGDI *FontGDI; + FT_Face Face; + UNICODE_STRING FamilyNameW; NTSTATUS status; + 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); @@ -2158,142 +2265,124 @@ FontGDI = CurrentEntry->Font; ASSERT(FontGDI); - RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name); - status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE); - if (!NT_SUCCESS(status)) - { - return FALSE; - } + Face = FontGDI->SharedFace->Face; + ASSERT(Face); - if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length) + /* family name */ + RtlInitUnicodeString(&FamilyNameW, NULL); + status = IntGetFontName(&FamilyNameW, Face, TT_NAME_ID_FONT_FAMILY, + gusLanguageID); + if (NT_SUCCESS(status)) { - EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR); - EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0'; - } - - if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size))) - { - if (*Count < Size) + if (DoesAddFontToInfo(LogFont, &FamilyNameW, FontGDI, Info, Count)) { - FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI); + if (Count < Size) + { + FontFamilyFillInfo(&Info[Count++], FamilyNameW.Buffer, NULL, FontGDI); + } + ++(*pCount); } - (*Count)++; + RtlFreeUnicodeString(&FamilyNameW); } - RtlFreeUnicodeString(&EntryFaceNameW); - Entry = Entry->Flink; } return TRUE; } -typedef struct FontFamilyInfoCallbackContext +static BOOLEAN FASTCALL +GetFontFamilyInfoForSubstitutes(LPLOGFONTW plfPattern, + PFONTFAMILYINFO Info, + DWORD *pCount, + DWORD Size) { - LPLOGFONTW LogFont; - PFONTFAMILYINFO Info; - DWORD Count; - DWORD Size; -} FONT_FAMILY_INFO_CALLBACK_CONTEXT, *PFONT_FAMILY_INFO_CALLBACK_CONTEXT; + PFONTSUBST_ENTRY pSubstEntry; + PLIST_ENTRY pListEntry, pHead = &FontSubstListHead; + PUNICODE_STRING SubstFrom; + UNICODE_STRING NameW, PatternNameW; + PFONTGDI FontGDI; + BYTE CharSetFrom; + NTSTATUS Status; + BYTE CharSet; + DWORD Count = *pCount; -_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) -{ - PFONT_FAMILY_INFO_CALLBACK_CONTEXT InfoContext; - UNICODE_STRING RegistryName, RegistryValue; - int Existing; - PFONTGDI FontGDI; + /* FIXME if wrong or slow */ - if (REG_SZ != ValueType) + RtlInitUnicodeString(&PatternNameW, plfPattern->lfFaceName); + + /* for each list entry */ + for (pListEntry = pHead->Flink; + pListEntry != pHead; + pListEntry = pListEntry->Flink) { - return STATUS_SUCCESS; - } - InfoContext = (PFONT_FAMILY_INFO_CALLBACK_CONTEXT) Context; - RtlInitUnicodeString(&RegistryName, ValueName); + pSubstEntry = + (PFONTSUBST_ENTRY)CONTAINING_RECORD(pListEntry, FONT_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) + /* does charset match? */ + CharSetFrom = pSubstEntry->CharSets[FONTSUBST_FROM]; + if (plfPattern->lfCharSet != DEFAULT_CHARSET && + plfPattern->lfCharSet != CharSetFrom) { - /* 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; + continue; /* charset mismatched */ } - /* Try to find information about the "real" font */ - FontGDI = FindFaceNameInLists(&RegistryValue); - if (NULL == FontGDI) + /* does subst key match the pattern face name? */ + SubstFrom = &pSubstEntry->FontNames[FONTSUBST_FROM]; + if (!RtlEqualUnicodeString(SubstFrom, &PatternNameW, TRUE)) { - /* "Real" font not found, discard this registry entry */ - return STATUS_SUCCESS; + continue; /* subst name mismatched */ } - /* Return info about the "real" font but with the name of the alias */ - if (InfoContext->Count < InfoContext->Size) + Status = RtlCreateUnicodeString(&NameW, SubstFrom->Buffer); + if (!NT_SUCCESS(Status)) { - FontFamilyFillInfo(InfoContext->Info + InfoContext->Count, - RegistryName.Buffer, FontGDI); + continue; /* failure */ } - InfoContext->Count++; - return STATUS_SUCCESS; - } - return STATUS_SUCCESS; -} + /* substitutes */ + CharSet = plfPattern->lfCharSet; + SubstituteFontRecurse(&NameW, &CharSet); -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; + /* to be added? */ + FontGDI = FindFaceNameInLists(SubstFrom); + if (FontGDI) + { + if (!DoesAddFontToInfo(plfPattern, SubstFrom, FontGDI, Info, + min(*pCount, Size))) + { + RtlFreeUnicodeString(&NameW); + continue; + } + } + if (FontGDI == NULL) + { + FontGDI = FindFaceNameInLists(&NameW); + if (FontGDI) + { + if (!DoesAddFontToInfo(plfPattern, &NameW, FontGDI, Info, + min(*pCount, Size))) + { + RtlFreeUnicodeString(&NameW); + continue; + } + } + } - /* 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; + RtlFreeUnicodeString(&NameW); + if (FontGDI == NULL) + { + continue; + } - 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; + if (Count < Size) + { + /* OK, let's store info */ + FontFamilyFillInfo(&Info[Count++], SubstFrom->Buffer, + SubstFrom->Buffer, FontGDI); + } + ++(*pCount); } - return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status; + return TRUE; /* success */ } BOOL @@ -3715,7 +3804,6 @@ GetFontPenalty(LOGFONTW * LogFont, PUNICODE_STRING RequestedNameW, PUNICODE_STRING ActualNameW, - PUNICODE_STRING FullFaceNameW, BYTE RequestedCharSet, PFONTGDI FontGDI, OUTLINETEXTMETRICW * Otm, @@ -3727,6 +3815,7 @@ LONG Long; BOOL fFixedSys = FALSE, fNeedScaling = FALSE; const BYTE UserCharSet = CharSetFromLangID(gusLanguageID); + NTSTATUS status; /* FIXME: Aspect Penalty 30 */ /* FIXME: IntSizeSynth Penalty 20 */ @@ -3733,6 +3822,8 @@ /* FIXME: SmallPenalty Penalty 1 */ /* FIXME: FaceNameSubst Penalty 500 */ + RtlInitUnicodeString(ActualNameW, NULL); + if (RtlEqualUnicodeString(RequestedNameW, &SystemW, TRUE)) { /* "System" font */ @@ -3860,35 +3951,60 @@ } } - 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 = IntGetFontName(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 = IntGetFontName(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 = IntGetFontName(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 = IntGetFontName(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; + } } Byte = (LogFont->lfPitchAndFamily & 0xF0); @@ -4094,17 +4210,14 @@ PLIST_ENTRY Head) { ULONG Penalty; - NTSTATUS Status; PLIST_ENTRY Entry; PFONT_ENTRY CurrentEntry; FONTGDI *FontGDI; - ANSI_STRING ActualNameA; - UNICODE_STRING ActualNameW, FullFaceNameW; + UNICODE_STRING ActualNameW; OUTLINETEXTMETRICW *Otm = NULL; UINT OtmSize, OldOtmSize = 0; TEXTMETRICW *TM; FT_Face Face; - LPBYTE pb; ASSERT(FontObj); ASSERT(MatchPenalty); @@ -4113,24 +4226,14 @@ ASSERT(Head); /* get the FontObj of lowest penalty */ - Entry = Head->Flink; - while (Entry != Head) + for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry); FontGDI = CurrentEntry->Font; ASSERT(FontGDI); Face = FontGDI->SharedFace->Face; + ASSERT(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) @@ -4147,24 +4250,12 @@ 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); + RequestedCharSet, FontGDI, Otm, TM, + Face->style_name); if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty) { - DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty); + DPRINT("%ls Penalty: %lu\n", pRequestedNameW->Buffer, Penalty); RtlFreeUnicodeString(pActualNameW); RtlCreateUnicodeString(pActualNameW, ActualNameW.Buffer); @@ -4172,18 +4263,14 @@ *MatchPenalty = Penalty; } - RtlFreeUnicodeString(&FullFaceNameW); + RtlFreeUnicodeString(&ActualNameW); } - - /* free strings */ - RtlFreeUnicodeString(&ActualNameW); - - /* next entry */ - Entry = Entry->Flink; } if (Otm) + { ExFreePoolWithTag(Otm, GDITAG_TEXT); + } } static @@ -4381,8 +4468,16 @@ EqualFamilyInfo(FONTFAMILYINFO *pInfo1, FONTFAMILYINFO *pInfo2) { UNICODE_STRING Str1, Str2; + ENUMLOGFONTEXW *pLog1 = &pInfo1->EnumLogFontEx; ENUMLOGFONTEXW *pLog2 = &pInfo2->EnumLogFontEx; + + LOGFONTW *plf1 = &pLog1->elfLogFont; + LOGFONTW *plf2 = &pLog1->elfLogFont; + + if (plf1->lfCharSet != plf2->lfCharSet) + return FALSE; + RtlInitUnicodeString(&Str1, pLog1->elfLogFont.lfFaceName); RtlInitUnicodeString(&Str2, pLog2->elfLogFont.lfFaceName); if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE)) @@ -4389,17 +4484,9 @@ { return FALSE; } - if ((pLog1->elfStyle != NULL) != (pLog2->elfStyle != NULL)) - return FALSE; - if (pLog1->elfStyle != NULL) - { - RtlInitUnicodeString(&Str1, pLog1->elfStyle); - RtlInitUnicodeString(&Str2, pLog2->elfStyle); - if (!RtlEqualUnicodeString(&Str1, &Str2, TRUE)) - { - return FALSE; - } - } + + /* FIXME: lfPitchAndFamily (MONO_FONT), See also EnumFontFamiliesEx */ + return TRUE; } @@ -4406,13 +4493,7 @@ 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); - } + wcscat(psz, FamInfo->EnumLogFontEx.elfFullName); } BOOL @@ -4471,10 +4552,12 @@ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } + /* Try to find the pathname in the global font list */ Count = 0; IntLockGlobalFonts; - for (ListEntry = FontListHead.Flink; ListEntry != &FontListHead; + for (ListEntry = FontListHead.Flink; + ListEntry != &FontListHead; ListEntry = ListEntry->Flink) { FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry); @@ -4490,7 +4573,7 @@ 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])) @@ -4768,7 +4851,7 @@ NTSTATUS Status; LOGFONTW LogFont; PFONTFAMILYINFO Info; - DWORD Count; + DWORD Count = 0; PPROCESSINFO Win32Process; /* Make a safe copy */ @@ -4789,8 +4872,7 @@ /* Enumerate font families in the global list */ IntLockGlobalFonts; - Count = 0; - if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) ) + if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead)) { IntUnLockGlobalFonts; ExFreePoolWithTag(Info, GDITAG_TEXT);