/* 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 =
BYTE RequestedCharSet,
BYTE CharSetMap[FONTSUBST_FROM_AND_TO])
{
- NTSTATUS Status;
PLIST_ENTRY pListEntry;
PFONTSUBST_ENTRY pSubstEntry;
BYTE CharSets[FONTSUBST_FROM_AND_TO];
}
/* 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)
{
}
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;
+ RtlStringCchCopyW(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];
}
}
IntUnLockFreeType;
- if (FT_IS_SFNT(Face))
+ if (!Error && FT_IS_SFNT(Face))
pLoadFont->IsTrueType = TRUE;
if (Error || SharedFace == NULL)
char *Cp;
UNICODE_STRING FamilyNameW, FaceNameW, StyleNameW, FullNameW;
PSHARED_FACE SharedFace = FontGDI->SharedFace;
- PSHARED_FACE_CACHE Cache = (gusLanguageID == gusEnglishUS) ? &SharedFace->EnglishUS : &SharedFace->UserLanguage;
+ PSHARED_FACE_CACHE Cache = (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH) ? &SharedFace->EnglishUS : &SharedFace->UserLanguage;
FT_Face Face = SharedFace->Face;
if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
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 = (LangID == gusEnglishUS) ? &SharedFace->EnglishUS : &SharedFace->UserLanguage;
+ PSHARED_FACE_CACHE Cache;
FT_Face Face = SharedFace->Face;
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))
{
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;
-
- /* Convert UTF-16 big endian to little endian */
- SwapEndian(Buf, Name.string_len);
+ 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;
+ }
- RtlCreateUnicodeString(pNameW, Buf);
- Status = STATUS_SUCCESS;
- break;
+ if (Score > BestScore)
+ {
+ BestScore = Score;
+ BestIndex = i;
+ }
}
- if (Status == STATUS_NOT_FOUND)
+ if (BestIndex >= 0)
{
- if (LangID != gusEnglishUS)
+ /* store the best name */
+ Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
+ if (!Error)
{
- /* Retry with English US */
- Status = IntGetFontLocalizedName(pNameW, SharedFace, NameID, gusEnglishUS);
+ /* 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);
}
- else if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* defaulted */
+ if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
{
RtlInitAnsiString(&AnsiName, Face->style_name);
Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
}
}
- 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)
+ if (NT_SUCCESS(Status))
{
- ASSERT_FREETYPE_LOCK_NOT_HELD();
- IntLockFreeType;
- if (!Cache->FullName.Buffer)
- DuplicateUnicodeString(pNameW, &Cache->FullName);
- IntUnLockFreeType;
+ /* 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;
{
return;
}
- IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+ Size = IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+ if (!Size)
+ {
+ ExFreePoolWithTag(Otm, GDITAG_TEXT);
+ return;
+ }
Lf = &Info->EnumLogFontEx.elfLogFont;
TM = &Otm->otmTextMetrics;
if (0 == (TM->tmPitchAndFamily & TMPF_VECTOR))
Info->FontType |= RASTER_FONTTYPE;
- ExFreePoolWithTag(Otm, GDITAG_TEXT);
/* face name */
- if (FaceName)
- {
- RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
- }
- else
- {
- status = IntGetFontLocalizedName(&NameW, SharedFace, TT_NAME_ID_FONT_FAMILY,
- gusLanguageID);
- if (NT_SUCCESS(status))
- {
- /* store it */
- RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName),
- 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)
- {
- RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
- sizeof(Info->EnumLogFontEx.elfFullName),
- FullName);
- }
- else
- {
- status = IntGetFontLocalizedName(&NameW, SharedFace, TT_NAME_ID_FULL_NAME,
- gusLanguageID);
- if (NT_SUCCESS(status))
- {
- /* store it */
- RtlStringCbCopyW(Info->EnumLogFontEx.elfFullName,
- sizeof(Info->EnumLogFontEx.elfFullName),
- NameW.Buffer);
- RtlFreeUnicodeString(&NameW);
- }
- }
+ 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;
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;
}
- if (FontFamilyInclude(LogFont, &EntryFaceNameW, Info, min(*Count, Size)))
+ FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
+
+ if (_wcsicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName) != 0 &&
+ _wcsicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName) != 0)
{
- if (*Count < Size)
+ continue;
+ }
+
+ if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
+ {
+ 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;
+ (*pCount)++;
}
- 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;
- }
-
- return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
+ return TRUE;
}
BOOL
TEXTOBJ_UnlockText(TextObj);
return GDI_ERROR;
}
- IntGetOutlineTextMetrics(FontGDI, Size, potm);
+ Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
+ if (!Size)
+ {
+ /* FIXME: last error? */
+ ExFreePoolWithTag(potm, GDITAG_TEXT);
+ TEXTOBJ_UnlockText(TextObj);
+ return GDI_ERROR;
+ }
IntLockFreeType;
TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
}
// 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;
BYTE Byte;
LONG Long;
- BOOL fFixedSys = FALSE, fNeedScaling = FALSE;
+ BOOL 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))
+ 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 (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE))
+
+ 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 = RequestedCharSet;
- if (Byte == DEFAULT_CHARSET)
- {
- if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE))
- {
- 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)
+ if (UserCharSet != TM->tmCharSet)
{
- /* CharSet Penalty 65000 */
- /* Requested charset does not match the candidate's. */
- Penalty += 65000;
- }
- else
- {
- if (UserCharSet != TM->tmCharSet)
+ /* UNDOCUMENTED */
+ Penalty += 100;
+ if (ANSI_CHARSET != TM->tmCharSet)
{
/* UNDOCUMENTED */
Penalty += 100;
- if (ANSI_CHARSET != TM->tmCharSet)
- {
- /* UNDOCUMENTED */
- Penalty += 100;
- }
}
}
}
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)
}
}
- if (RequestedNameW->Buffer[0])
+ ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
+
+ if (LogFont->lfFaceName[0])
{
BOOL Found = FALSE;
- PSHARED_FACE SharedFace = FontGDI->SharedFace;
/* localized family name */
if (!Found)
{
- Status = IntGetFontLocalizedName(ActualNameW, SharedFace, 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, SharedFace, 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, SharedFace, TT_NAME_ID_FONT_FAMILY,
- gusEnglishUS);
- if (NT_SUCCESS(Status))
- {
- Found = RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE);
- }
- }
- /* English full name */
- if (!Found)
- {
- Status = IntGetFontLocalizedName(ActualNameW, SharedFace, 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)
{
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);
}
}
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)
ASSERT(FontGDI);
Face = FontGDI->SharedFace->Face;
- /* create actual name */
- RtlInitAnsiString(&ActualNameA, Face->family_name);
- Status = RtlAnsiStringToUnicodeString(&ActualNameW, &ActualNameA, TRUE);
- if (!NT_SUCCESS(Status))
- {
- continue;
- }
-
/* get text metrics */
OtmSize = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
if (OtmSize > OldOtmSize)
/* update FontObj if lowest penalty */
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);
+ OtmSize = IntGetOutlineTextMetrics(FontGDI, OtmSize, Otm);
+ if (!OtmSize)
continue;
- }
- Penalty = GetFontPenalty(LogFont, pRequestedNameW, &ActualNameW,
- &FullFaceNameW, RequestedCharSet,
- FontGDI, Otm, TM, Face->style_name);
+ OldOtmSize = OtmSize;
+
+ 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);
}
if (Otm)
{
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)
{
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;
/* 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;
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);
}
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;
}
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;
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);
BrushOrigin.x = 0;
BrushOrigin.y = 0;
- if (!dc->dclevel.pSurface)
- {
- goto fail;
- }
-
if ((fuOptions & ETO_OPAQUE) && lprc)
{
DestRect.left = lprc->left;
&psurf->SurfObj,
NULL,
NULL,
- &dc->co.ClipObj,
+ (CLIPOBJ *)&dc->co,
NULL,
&DestRect,
&SourcePoint,
&psurf->SurfObj,
NULL,
NULL,
- &dc->co.ClipObj,
+ (CLIPOBJ *)&dc->co,
NULL,
&DestRect,
&SourcePoint,
&psurf->SurfObj,
NULL,
NULL,
- &dc->co.ClipObj,
+ (CLIPOBJ *)&dc->co,
NULL,
&DestRect,
&SourcePoint,
if (!IntEngMaskBlt(
SurfObj,
SourceGlyphSurf,
- &dc->co.ClipObj,
+ (CLIPOBJ *)&dc->co,
&exloRGB2Dst.xlo,
&exloDst2RGB.xlo,
&DestRect,
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,
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,
cwc = GDI_ERROR;
goto ErrorRet;
}
- IntGetOutlineTextMetrics(FontGDI, Size, potm);
- DefChar = potm->otmTextMetrics.tmDefaultChar;
+ Size = IntGetOutlineTextMetrics(FontGDI, Size, potm);
+ if (Size)
+ DefChar = potm->otmTextMetrics.tmDefaultChar;
ExFreePoolWithTag(potm, GDITAG_TEXT);
}
}