Index: reactos/win32ss/gdi/ntgdi/freetype.c =================================================================== --- reactos/win32ss/gdi/ntgdi/freetype.c (revision 74121) +++ reactos/win32ss/gdi/ntgdi/freetype.c (working copy) @@ -3337,65 +3337,182 @@ return Result; } -static __inline BOOLEAN -SubstituteFontNameByKey(PUNICODE_STRING FaceName, - LPCWSTR Key) +static BOOL +SubstituteFontByKey(HANDLE KeyHandle, + PUNICODE_STRING pOutputName, + PUNICODE_STRING pInputName, + BYTE RequestedCharSet, + BYTE CharSetMap[2]) { - RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}}; - NTSTATUS Status; - UNICODE_STRING Value; + NTSTATUS Status; + ULONG i, Length; + KEY_FULL_INFORMATION KeyFullInfo; + BYTE InfoBuffer[128]; + PKEY_VALUE_FULL_INFORMATION pInfo; + UNICODE_STRING NameW, ValueW; + LPWSTR pch; + BYTE CharSets[2]; + BOOL Found; - RtlInitUnicodeString(&Value, NULL); + CharSetMap[0] = DEFAULT_CHARSET; + CharSetMap[1] = RequestedCharSet; - QueryTable[0].QueryRoutine = NULL; - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND | - RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = FaceName->Buffer; - QueryTable[0].EntryContext = &Value; - QueryTable[0].DefaultType = REG_NONE; - QueryTable[0].DefaultData = NULL; - QueryTable[0].DefaultLength = 0; + /* query key info */ + Status = ZwQueryKey(KeyHandle, + KeyFullInformation, + &KeyFullInfo, + sizeof(KeyFullInfo), + &Length); + if (!NT_SUCCESS(Status)) + { + DPRINT("ZwQueryKey failed: 0x%08X\n", Status); + return FALSE; /* failure */ + } - QueryTable[1].QueryRoutine = NULL; - QueryTable[1].Name = NULL; - - Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT, - Key, - QueryTable, - NULL, - NULL); - if (NT_SUCCESS(Status)) + /* enumerate values */ + Found = FALSE; + for (i = 0; i < KeyFullInfo.Values; ++i) { - RtlFreeUnicodeString(FaceName); - *FaceName = Value; + /* get value name */ + Status = ZwEnumerateValueKey(KeyHandle, + i, + KeyValueFullInformation, + InfoBuffer, + sizeof(InfoBuffer), + &Length); + if (!NT_SUCCESS(Status)) + { + DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status); + break; /* failure */ + } - /* truncate */ - if ((LF_FACESIZE - 1) * sizeof(WCHAR) < FaceName->Length) + /* create NameW */ + pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer; + pInfo->Name[pInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; + Status = RtlCreateUnicodeString(&NameW, pInfo->Name); + if (!NT_SUCCESS(Status)) { - FaceName->Length = (LF_FACESIZE - 1) * sizeof(WCHAR); - FaceName->Buffer[LF_FACESIZE - 1] = UNICODE_NULL; + DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status); + break; /* failure */ } + + /* query value */ + Status = ZwQueryValueKey(KeyHandle, &NameW, KeyValueFullInformation, + InfoBuffer, sizeof(InfoBuffer), &Length); + pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer; + if (!NT_SUCCESS(Status) || !pInfo->DataLength) + { + DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status); + RtlFreeUnicodeString(&NameW); + break; /* failure */ + } + + /* create ValueW */ + pch = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset); + Length = pInfo->DataLength; + pch[Length / sizeof(WCHAR)] = UNICODE_NULL; + Status = RtlCreateUnicodeString(&ValueW, pch); + if (!NT_SUCCESS(Status)) + { + DPRINT("RtlCreateUnicodeString failed: 0x%08X\n", Status); + RtlFreeUnicodeString(&NameW); + break; /* failure */ + } + + CharSets[0] = DEFAULT_CHARSET; + CharSets[1] = RequestedCharSet; + + /* does charset exist? */ + pch = wcsrchr(NameW.Buffer, L','); + if (pch) + { + *pch = UNICODE_NULL; + NameW.Length = (pch - NameW.Buffer) * sizeof(WCHAR); + CharSets[0] = (BYTE)_wtoi(pch + 1); + } + pch = wcsrchr(ValueW.Buffer, L','); + if (pch) + { + *pch = UNICODE_NULL; + ValueW.Length = (pch - ValueW.Buffer) * sizeof(WCHAR); + CharSets[1] = (BYTE)_wtoi(pch + 1); + } + + if (RtlEqualUnicodeString(&NameW, pInputName, TRUE)) + { + if (CharSets[0] == DEFAULT_CHARSET || + RequestedCharSet == CharSets[0]) + { + Status = RtlCreateUnicodeString(pOutputName, ValueW.Buffer); + if (NT_SUCCESS(Status)) + { + Found = TRUE; + if (CharSetMap[0] == DEFAULT_CHARSET) + { + CharSetMap[0] = CharSets[0]; + CharSetMap[1] = CharSets[1]; + } + } + } + } + + /* free strings */ + RtlFreeUnicodeString(&NameW); + RtlFreeUnicodeString(&ValueW); } - return NT_SUCCESS(Status); + return Found; } -static __inline BOOL -SubstituteFontName(PUNICODE_STRING FaceName) +static BOOL +SubstituteFont(PUNICODE_STRING pInOutName, BYTE *pRequestedCharSet) { + NTSTATUS Status; + HANDLE KeyHandle; + OBJECT_ATTRIBUTES ObjectAttributes; + BYTE CharSetMap[2]; + BOOL Found; UINT Level; - const UINT MaxLevel = 10; + const UINT MaxLevel = 5; + UNICODE_STRING OutputNameW; + static UNICODE_STRING FontSubstKey = + RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\" + L"Microsoft\\Windows NT\\CurrentVersion\\" + L"FontSubstitutes"); - if (FaceName->Buffer[0] == 0) - return FALSE; + /* open registry key */ + InitializeObjectAttributes(&ObjectAttributes, &FontSubstKey, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, NULL); + Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + DPRINT("ZwOpenKey failed: 0x%08X\n", Status); + return FALSE; /* failure */ + } for (Level = 0; Level < MaxLevel; ++Level) { - /* NOTE: SubstituteFontNameByKey changes FaceName. Be careful... */ - if (!SubstituteFontNameByKey(FaceName, L"FontSubstitutes")) + RtlInitUnicodeString(&OutputNameW, NULL); + Found = SubstituteFontByKey(KeyHandle, &OutputNameW, pInOutName, + *pRequestedCharSet, CharSetMap); + if (!Found) break; + + /* update *pInOutName and *pRequestedCharSet */ + RtlFreeUnicodeString(pInOutName); + *pInOutName = OutputNameW; + if (CharSetMap[0] == DEFAULT_CHARSET || + *pRequestedCharSet == CharSetMap[0]) + { + *pRequestedCharSet = CharSetMap[1]; + } } - return (Level > 0); + + /* close key */ + ZwClose(KeyHandle); + + return TRUE; /* success */ } // NOTE: See Table 1. of https://msdn.microsoft.com/en-us/library/ms969909.aspx @@ -3404,6 +3521,7 @@ PUNICODE_STRING RequestedNameW, PUNICODE_STRING ActualNameW, PUNICODE_STRING FullFaceNameW, + BYTE RequestedCharSet, PFONTGDI FontGDI, OUTLINETEXTMETRICW * Otm, TEXTMETRICW * TM, @@ -3443,7 +3561,7 @@ } else /* Request is non-"System" font */ { - Byte = LogFont->lfCharSet; + Byte = RequestedCharSet; if (Byte == DEFAULT_CHARSET) { if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE)) @@ -3470,13 +3588,13 @@ if (UserCharSet != TM->tmCharSet) { /* UNDOCUMENTED */ - Penalty += 10; + Penalty += 100; + if (ANSI_CHARSET != TM->tmCharSet) + { + /* UNDOCUMENTED */ + Penalty += 100; + } } - if (ANSI_CHARSET != TM->tmCharSet) - { - /* UNDOCUMENTED */ - Penalty += 10; - } } } } @@ -3777,20 +3895,21 @@ static __inline VOID FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont, PUNICODE_STRING pRequestedNameW, - PUNICODE_STRING pActualNameW, PLIST_ENTRY Head) + PUNICODE_STRING pActualNameW, BYTE RequestedCharSet, + PLIST_ENTRY Head) { - ULONG Penalty; - NTSTATUS Status; - PLIST_ENTRY Entry; - PFONT_ENTRY CurrentEntry; - FONTGDI *FontGDI; - ANSI_STRING ActualNameA; - UNICODE_STRING ActualNameW, FullFaceNameW; + 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; + UINT OtmSize, OldOtmSize = 0; + TEXTMETRICW * TM; + FT_Face Face; + LPBYTE pb; ASSERT(FontObj); ASSERT(MatchPenalty); @@ -3846,8 +3965,8 @@ } Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW, - &FullFaceNameW, FontGDI, Otm, TM, - Face->style_name); + &FullFaceNameW, RequestedCharSet, + FontGDI, Otm, TM, Face->style_name); if (*MatchPenalty == 0xFFFFFFFF || Penalty < *MatchPenalty) { DPRINT("%ls Penalty: %lu\n", FullFaceNameW.Buffer, Penalty); @@ -3915,6 +4034,7 @@ ULONG MatchPenalty; LOGFONTW *pLogFont; FT_Face Face; + BYTE RequestedCharSet; if (!pTextObj) { @@ -3938,15 +4058,17 @@ RtlInitUnicodeString(&ActualNameW, NULL); pLogFont = &TextObj->logfont.elfEnumLogfontEx.elfLogFont; - if (! RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName)) + if (!RtlCreateUnicodeString(&RequestedNameW, pLogFont->lfFaceName)) { if (!pTextObj) TEXTOBJ_UnlockText(TextObj); return STATUS_NO_MEMORY; } - DPRINT("Font '%ls' is substituted by: ", RequestedNameW.Buffer); - SubstituteFontName(&RequestedNameW); - DPRINT("'%ls'.\n", RequestedNameW.Buffer); + RequestedCharSet = pLogFont->lfCharSet; + DPRINT("Font '%ls,%u' is substituted by: ", + RequestedNameW.Buffer, RequestedCharSet); + SubstituteFont(&RequestedNameW, &RequestedCharSet); + DPRINT("'%ls,%u'.\n", RequestedNameW.Buffer, RequestedCharSet); MatchPenalty = 0xFFFFFFFF; TextObj->Font = NULL; @@ -3956,7 +4078,7 @@ /* Search private fonts */ IntLockProcessPrivateFonts(Win32Process); FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont, - &RequestedNameW, &ActualNameW, + &RequestedNameW, &ActualNameW, RequestedCharSet, &Win32Process->PrivateFontListHead); IntUnLockProcessPrivateFonts(Win32Process); @@ -3963,7 +4085,7 @@ /* Search system fonts */ IntLockGlobalFonts; FindBestFontFromList(&TextObj->Font, &MatchPenalty, pLogFont, - &RequestedNameW, &ActualNameW, + &RequestedNameW, &ActualNameW, RequestedCharSet, &FontListHead); IntUnLockGlobalFonts;