#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");
static UNICODE_STRING FontRegPath =
RTL_CONSTANT_STRING(L"\\REGISTRY\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
-static PSHARED_FACE
-SharedFace_Create(FT_Face Face)
-{
- PSHARED_FACE Ptr;
- Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
- if (Ptr)
- {
- Ptr->Face = Face;
- Ptr->RefCount = 1;
- }
- return Ptr;
-}
-
-static void
-SharedFace_AddRef(PSHARED_FACE Ptr)
-{
- ++Ptr->RefCount;
-}
-
-static void
-SharedFace_Release(PSHARED_FACE Ptr)
-{
- if (Ptr->RefCount <= 0)
- return;
-
- --Ptr->RefCount;
- if (Ptr->RefCount == 0)
- {
- FT_Done_Face(Ptr->Face);
- ExFreePoolWithTag(Ptr, TAG_FONT);
- }
-}
-
/* The FreeType library is not thread safe, so we have
to serialize access to it */
#define IntUnLockGlobalFonts \
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
+#define ASSERT_GLOBALFONTS_LOCK_HELD() \
+ ASSERT(FontListLock->Owner == KeGetCurrentThread())
+
#define IntLockFreeType \
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
#define IntUnLockFreeType \
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
+#define ASSERT_FREETYPE_LOCK_HELD() \
+ ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
+
+#define ASSERT_FREETYPE_LOCK_NOT_HELD() \
+ ASSERT(FreeTypeLock->Owner != KeGetCurrentThread())
+
#define MAX_FONT_CACHE 256
static LIST_ENTRY FontCacheListHead;
/* list head */
static RTL_STATIC_LIST_HEAD(FontSubstListHead);
+static void
+SharedMem_AddRef(PSHARED_MEM Ptr)
+{
+ ASSERT_FREETYPE_LOCK_HELD();
+
+ ++Ptr->RefCount;
+}
+
+static void
+SharedFaceCache_Init(PSHARED_FACE_CACHE Cache)
+{
+ Cache->OutlineRequiredSize = 0;
+ RtlInitUnicodeString(&Cache->FontFamily, NULL);
+ RtlInitUnicodeString(&Cache->FullName, NULL);
+}
+
+static PSHARED_FACE
+SharedFace_Create(FT_Face Face, PSHARED_MEM Memory)
+{
+ PSHARED_FACE Ptr;
+ Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT);
+ if (Ptr)
+ {
+ Ptr->Face = Face;
+ Ptr->RefCount = 1;
+ Ptr->Memory = Memory;
+ SharedFaceCache_Init(&Ptr->EnglishUS);
+ SharedFaceCache_Init(&Ptr->UserLanguage);
+
+ SharedMem_AddRef(Memory);
+ DPRINT("Creating SharedFace for %s\n", Face->family_name);
+ }
+ return Ptr;
+}
+
+static PSHARED_MEM
+SharedMem_Create(PBYTE Buffer, ULONG BufferSize, BOOL IsMapping)
+{
+ PSHARED_MEM Ptr;
+ Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_MEM), TAG_FONT);
+ if (Ptr)
+ {
+ Ptr->Buffer = Buffer;
+ Ptr->BufferSize = BufferSize;
+ Ptr->RefCount = 1;
+ Ptr->IsMapping = IsMapping;
+ DPRINT("Creating SharedMem for %p (%i, %p)\n", Buffer, IsMapping, Ptr);
+ }
+ return Ptr;
+}
+
+static void
+SharedFace_AddRef(PSHARED_FACE Ptr)
+{
+ ASSERT_FREETYPE_LOCK_HELD();
+
+ ++Ptr->RefCount;
+}
+
+static void
+RemoveCachedEntry(PFONT_CACHE_ENTRY Entry)
+{
+ ASSERT_FREETYPE_LOCK_HELD();
+
+ FT_Done_Glyph((FT_Glyph)Entry->BitmapGlyph);
+ RemoveEntryList(&Entry->ListEntry);
+ ExFreePoolWithTag(Entry, TAG_FONT);
+ FontCacheNumEntries--;
+ ASSERT(FontCacheNumEntries <= MAX_FONT_CACHE);
+}
+
+static void
+RemoveCacheEntries(FT_Face Face)
+{
+ PLIST_ENTRY CurrentEntry;
+ PFONT_CACHE_ENTRY FontEntry;
+
+ ASSERT_FREETYPE_LOCK_HELD();
+
+ CurrentEntry = FontCacheListHead.Flink;
+ while (CurrentEntry != &FontCacheListHead)
+ {
+ FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
+ CurrentEntry = CurrentEntry->Flink;
+
+ if (FontEntry->Face == Face)
+ {
+ RemoveCachedEntry(FontEntry);
+ }
+ }
+}
+
+static void SharedMem_Release(PSHARED_MEM Ptr)
+{
+ ASSERT_FREETYPE_LOCK_HELD();
+ ASSERT(Ptr->RefCount > 0);
+
+ if (Ptr->RefCount <= 0)
+ return;
+
+ --Ptr->RefCount;
+ if (Ptr->RefCount == 0)
+ {
+ DPRINT("Releasing SharedMem for %p (%i, %p)\n", Ptr->Buffer, Ptr->IsMapping, Ptr);
+ if (Ptr->IsMapping)
+ MmUnmapViewInSystemSpace(Ptr->Buffer);
+ else
+ ExFreePoolWithTag(Ptr->Buffer, TAG_FONT);
+ ExFreePoolWithTag(Ptr, TAG_FONT);
+ }
+}
+
+static void
+SharedFaceCache_Release(PSHARED_FACE_CACHE Cache)
+{
+ RtlFreeUnicodeString(&Cache->FontFamily);
+ RtlFreeUnicodeString(&Cache->FullName);
+}
+
+static void
+SharedFace_Release(PSHARED_FACE Ptr)
+{
+ IntLockFreeType;
+ ASSERT(Ptr->RefCount > 0);
+
+ if (Ptr->RefCount <= 0)
+ return;
+
+ --Ptr->RefCount;
+ if (Ptr->RefCount == 0)
+ {
+ DPRINT("Releasing SharedFace for %s\n", Ptr->Face->family_name);
+ RemoveCacheEntries(Ptr->Face);
+ FT_Done_Face(Ptr->Face);
+ SharedMem_Release(Ptr->Memory);
+ SharedFaceCache_Release(&Ptr->EnglishUS);
+ SharedFaceCache_Release(&Ptr->UserLanguage);
+ ExFreePoolWithTag(Ptr, TAG_FONT);
+ }
+ IntUnLockFreeType;
+}
+
+
/*
* IntLoadFontSubstList --- loads the list of font substitutes
*/
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];
}
}
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;
- PVOID Buffer = pLoadFont->Buffer;
- ULONG BufferSize = pLoadFont->BufferSize;
DWORD Characteristics = pLoadFont->Characteristics;
PUNICODE_STRING pValueName = &pLoadFont->RegValueName;
TT_OS2 * pOS2;
IntLockFreeType;
Error = FT_New_Memory_Face(
library,
- Buffer,
- BufferSize,
+ pLoadFont->Memory->Buffer,
+ pLoadFont->Memory->BufferSize,
((FontIndex != -1) ? FontIndex : 0),
&Face);
+
+ if (!Error)
+ SharedFace = SharedFace_Create(Face, pLoadFont->Memory);
+
IntUnLockFreeType;
- if (FT_IS_SFNT(Face))
+ if (!Error && FT_IS_SFNT(Face))
pLoadFont->IsTrueType = TRUE;
- if (!Error)
- SharedFace = SharedFace_Create(Face);
if (Error || SharedFace == NULL)
{
+ if (SharedFace)
+ SharedFace_Release(SharedFace);
+
if (Error == FT_Err_Unknown_File_Format)
DPRINT1("Unknown font file format\n");
else
- DPRINT1("Error reading font file (error code: %d)\n", Error);
+ DPRINT1("Error reading font (error code: %d)\n", Error);
return 0; /* failure */
}
}
else
{
Face = SharedFace->Face;
+ IntLockFreeType;
SharedFace_AddRef(SharedFace);
+ IntUnLockFreeType;
}
/* allocate a FONT_ENTRY */
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);
FT_Long i;
for (i = 1; i < TrueType->ttc_header.count; ++i)
{
- FontCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
+ FaceCount += IntGdiLoadFontsFromMemory(pLoadFont, NULL, i, -1);
}
}
}
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 */
}
/*
}
LoadFont.pFileName = FileName;
- LoadFont.Buffer = Buffer;
- LoadFont.BufferSize = ViewSize;
+ LoadFont.Memory = SharedMem_Create(Buffer, ViewSize, TRUE);
LoadFont.Characteristics = Characteristics;
RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
LoadFont.IsTrueType = FALSE;
ObDereferenceObject(SectionObject);
+ /* Release our copy */
+ IntLockFreeType;
+ SharedMem_Release(LoadFont.Memory);
+ IntUnLockFreeType;
+
if (FontCount > 0)
{
if (LoadFont.IsTrueType)
{
GDI_LOAD_FONT LoadFont;
FONT_ENTRY_COLL_MEM* EntryCollection;
- INT FontCount;
+ INT FaceCount;
HANDLE Ret = 0;
+ PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
+
+ if (!BufferCopy)
+ {
+ *pNumAdded = 0;
+ return NULL;
+ }
+ memcpy(BufferCopy, Buffer, dwSize);
+
LoadFont.pFileName = NULL;
- LoadFont.Buffer = Buffer;
- LoadFont.BufferSize = dwSize;
+ LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
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);
- *pNumAdded = FontCount;
- if (FontCount > 0)
+ /* Release our copy */
+ IntLockFreeType;
+ SharedMem_Release(LoadFont.Memory);
+ IntUnLockFreeType;
+
+ if (FaceCount > 0)
{
EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
if (EntryCollection)
Ret = (HANDLE)EntryCollection->Handle;
}
}
+ *pNumAdded = FaceCount;
return Ret;
}
// FIXME: Add RemoveFontResource
+static VOID FASTCALL
+CleanupFontEntry(PFONT_ENTRY FontEntry)
+{
+ PFONTGDI FontGDI = FontEntry->Font;
+ PSHARED_FACE SharedFace = FontGDI->SharedFace;
+
+ if (FontGDI->Filename)
+ ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF);
+
+ EngFreeMem(FontGDI);
+ SharedFace_Release(SharedFace);
+ ExFreePoolWithTag(FontEntry, TAG_FONT);
+}
+
VOID FASTCALL
IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head)
{
Entry = RemoveHeadList(&Head->ListEntry);
FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry);
- // Delete FontEntry->Entry (FONT_ENTRY*)
+ CleanupFontEntry(FontEntry->Entry);
ExFreePoolWithTag(FontEntry, TAG_FONT);
}
- // Delete Head->Entry (FONT_ENTRY*)
+ CleanupFontEntry(Head->Entry);
ExFreePoolWithTag(Head, TAG_FONT);
}
+static VOID FASTCALL
+UnlinkFontMemCollection(PFONT_ENTRY_COLL_MEM Collection)
+{
+ PFONT_ENTRY_MEM FontMemEntry = Collection->Entry;
+ PLIST_ENTRY ListEntry;
+ RemoveEntryList(&Collection->ListEntry);
+
+ do {
+ /* Also unlink the FONT_ENTRY stuff from the PrivateFontListHead */
+ RemoveEntryList(&FontMemEntry->Entry->ListEntry);
+
+ ListEntry = FontMemEntry->ListEntry.Flink;
+ FontMemEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY_MEM, ListEntry);
+
+ } while (FontMemEntry != Collection->Entry);
+}
+
BOOL FASTCALL
IntGdiRemoveFontMemResource(HANDLE hMMFont)
{
if (CurrentEntry->Handle == (UINT)hMMFont)
{
EntryCollection = CurrentEntry;
- RemoveEntryList(Entry);
+ UnlinkFontMemCollection(CurrentEntry);
break;
}
}
+VOID FASTCALL
+IntGdiCleanupPrivateFontsForProcess(VOID)
+{
+ PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
+ PLIST_ENTRY Entry;
+ PFONT_ENTRY_COLL_MEM EntryCollection;
+
+ DPRINT("IntGdiCleanupPrivateFontsForProcess()\n");
+ do {
+ Entry = NULL;
+ EntryCollection = NULL;
+
+ IntLockProcessPrivateFonts(Win32Process);
+ if (!IsListEmpty(&Win32Process->PrivateMemFontListHead))
+ {
+ Entry = Win32Process->PrivateMemFontListHead.Flink;
+ EntryCollection = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry);
+ UnlinkFontMemCollection(EntryCollection);
+ }
+ IntUnLockProcessPrivateFonts(Win32Process);
+
+ if (EntryCollection)
+ {
+ IntGdiCleanupMemEntry(EntryCollection->Entry);
+ ExFreePoolWithTag(EntryCollection, TAG_FONT);
+ }
+ else
+ {
+ /* No Mem fonts anymore, see if we have any other private fonts left */
+ Entry = NULL;
+ IntLockProcessPrivateFonts(Win32Process);
+ if (!IsListEmpty(&Win32Process->PrivateFontListHead))
+ {
+ Entry = RemoveHeadList(&Win32Process->PrivateFontListHead);
+ }
+ IntUnLockProcessPrivateFonts(Win32Process);
+
+ if (Entry)
+ {
+ CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry));
+ }
+ }
+
+ } while (Entry);
+}
+
BOOL FASTCALL
IntIsFontRenderingEnabled(VOID)
{
FillTMEx(TM, FontGDI, pOS2, pHori, pFNT, FALSE);
}
+static NTSTATUS
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
+ FT_UShort NameID, FT_UShort LangID);
+
/*************************************************************
* IntGetOutlineTextMetrics
*
UINT Size,
OUTLINETEXTMETRICW *Otm)
{
- unsigned Needed;
TT_OS2 *pOS2;
TT_HoriHeader *pHori;
TT_Postscript *pPost;
FT_Fixed XScale, YScale;
- ANSI_STRING FamilyNameA, StyleNameA;
- UNICODE_STRING FamilyNameW, StyleNameW, Regular;
FT_WinFNT_HeaderRec Win;
FT_Error Error;
char *Cp;
- NTSTATUS status;
- FT_Face Face = FontGDI->SharedFace->Face;
-
- Needed = sizeof(OUTLINETEXTMETRICW);
+ UNICODE_STRING FamilyNameW, FaceNameW, StyleNameW, FullNameW;
+ PSHARED_FACE SharedFace = FontGDI->SharedFace;
+ PSHARED_FACE_CACHE Cache = (PRIMARYLANGID(gusLanguageID) == LANG_ENGLISH) ? &SharedFace->EnglishUS : &SharedFace->UserLanguage;
+ FT_Face Face = SharedFace->Face;
- RtlInitAnsiString(&FamilyNameA, Face->family_name);
- status = RtlAnsiStringToUnicodeString(&FamilyNameW, &FamilyNameA, TRUE);
- if (!NT_SUCCESS(status))
+ if (Cache->OutlineRequiredSize && Size < Cache->OutlineRequiredSize)
{
- return 0;
+ return Cache->OutlineRequiredSize;
}
- RtlInitAnsiString(&StyleNameA, Face->style_name);
- status = RtlAnsiStringToUnicodeString(&StyleNameW, &StyleNameA, TRUE);
- if (!NT_SUCCESS(status))
- {
- RtlFreeUnicodeString(&FamilyNameW);
- return 0;
- }
+ /* family name */
+ RtlInitUnicodeString(&FamilyNameW, NULL);
+ IntGetFontLocalizedName(&FamilyNameW, SharedFace, TT_NAME_ID_FONT_FAMILY, gusLanguageID);
- /* These names should be read from the TT name table */
+ /* face name */
+ RtlInitUnicodeString(&FaceNameW, NULL);
+ IntGetFontLocalizedName(&FaceNameW, SharedFace, TT_NAME_ID_FULL_NAME, gusLanguageID);
- /* Length of otmpFamilyName */
- Needed += FamilyNameW.Length + sizeof(WCHAR);
+ /* style name */
+ RtlInitUnicodeString(&StyleNameW, NULL);
+ IntGetFontLocalizedName(&StyleNameW, SharedFace, TT_NAME_ID_FONT_SUBFAMILY, gusLanguageID);
- 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 */
- }
+ /* unique name (full name) */
+ RtlInitUnicodeString(&FullNameW, NULL);
+ IntGetFontLocalizedName(&FullNameW, SharedFace, TT_NAME_ID_UNIQUE_ID, gusLanguageID);
- /* Length of otmpStyleName */
- Needed += StyleNameW.Length + sizeof(WCHAR);
+ if (!Cache->OutlineRequiredSize)
+ {
+ UINT Needed;
+ Needed = sizeof(OUTLINETEXTMETRICW);
+ Needed += FamilyNameW.Length + sizeof(WCHAR);
+ Needed += FaceNameW.Length + sizeof(WCHAR);
+ Needed += StyleNameW.Length + sizeof(WCHAR);
+ Needed += FullNameW.Length + sizeof(WCHAR);
- /* Length of otmpFullName */
- Needed += FamilyNameW.Length + StyleNameW.Length + (sizeof(WCHAR) << 1);
+ Cache->OutlineRequiredSize = Needed;
+ }
- if (Size < Needed)
+ if (Size < Cache->OutlineRequiredSize)
{
RtlFreeUnicodeString(&FamilyNameW);
+ RtlFreeUnicodeString(&FaceNameW);
RtlFreeUnicodeString(&StyleNameW);
- return Needed;
+ RtlFreeUnicodeString(&FullNameW);
+ return Cache->OutlineRequiredSize;
}
XScale = Face->size->metrics.x_scale;
{
IntUnLockFreeType;
DPRINT1("Can't find OS/2 table - not TT font?\n");
- RtlFreeUnicodeString(&StyleNameW);
RtlFreeUnicodeString(&FamilyNameW);
+ RtlFreeUnicodeString(&FaceNameW);
+ RtlFreeUnicodeString(&StyleNameW);
+ RtlFreeUnicodeString(&FullNameW);
return 0;
}
{
IntUnLockFreeType;
DPRINT1("Can't find HHEA table - not TT font?\n");
- RtlFreeUnicodeString(&StyleNameW);
RtlFreeUnicodeString(&FamilyNameW);
+ RtlFreeUnicodeString(&FaceNameW);
+ RtlFreeUnicodeString(&StyleNameW);
+ RtlFreeUnicodeString(&FullNameW);
return 0;
}
Error = FT_Get_WinFNT_Header(Face , &Win);
- Otm->otmSize = Needed;
+ Otm->otmSize = Cache->OutlineRequiredSize;
FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
IntUnLockFreeType;
- /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
Cp = (char*) Otm + sizeof(OUTLINETEXTMETRICW);
+
+ /* family name */
Otm->otmpFamilyName = (LPSTR)(Cp - (char*) Otm);
wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
Cp += FamilyNameW.Length + sizeof(WCHAR);
+
+ /* face name */
+ Otm->otmpFaceName = (LPSTR)(Cp - (char*) Otm);
+ wcscpy((WCHAR*) Cp, FaceNameW.Buffer);
+ Cp += FaceNameW.Length + sizeof(WCHAR);
+
+ /* style name */
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);
- }
+
+ /* unique name (full name) */
Otm->otmpFullName = (LPSTR)(Cp - (char*) Otm);
- wcscpy((WCHAR*) Cp, FamilyNameW.Buffer);
- wcscat((WCHAR*) Cp, L" ");
- wcscat((WCHAR*) Cp, StyleNameW.Buffer);
+ wcscpy((WCHAR*) Cp, FullNameW.Buffer);
+ Cp += FullNameW.Length + sizeof(WCHAR);
+
+ ASSERT(Cp - (char*)Otm == Cache->OutlineRequiredSize);
- RtlFreeUnicodeString(&StyleNameW);
RtlFreeUnicodeString(&FamilyNameW);
+ RtlFreeUnicodeString(&FaceNameW);
+ RtlFreeUnicodeString(&StyleNameW);
+ RtlFreeUnicodeString(&FullNameW);
- return Needed;
+ return Cache->OutlineRequiredSize;
}
static PFONTGDI FASTCALL
Entry = Head->Flink;
while (Entry != Head)
{
- CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+ CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
FontGDI = CurrentEntry->Font;
ASSERT(FontGDI);
PPROCESSINFO Win32Process;
PFONTGDI Font;
- /* Search the process local list */
+ /* Search the process local list.
+ We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
Win32Process = PsGetCurrentProcessWin32Process();
IntLockProcessPrivateFonts(Win32Process);
Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
}
static NTSTATUS
-IntGetFontLocalizedName(PUNICODE_STRING pLocalNameW, FT_Face Face)
+DuplicateUnicodeString(PUNICODE_STRING Source, PUNICODE_STRING Destination)
+{
+ NTSTATUS Status = STATUS_NO_MEMORY;
+ UNICODE_STRING Tmp;
+
+ Tmp.Buffer = ExAllocatePoolWithTag(PagedPool, Source->MaximumLength, TAG_USTR);
+ if (Tmp.Buffer)
+ {
+ Tmp.MaximumLength = Source->MaximumLength;
+ Tmp.Length = 0;
+ RtlCopyUnicodeString(&Tmp, Source);
+
+ Destination->MaximumLength = Tmp.MaximumLength;
+ Destination->Length = Tmp.Length;
+ Destination->Buffer = Tmp.Buffer;
+
+ Status = STATUS_SUCCESS;
+ }
+
+ return Status;
+}
+
+static NTSTATUS
+IntGetFontLocalizedName(PUNICODE_STRING pNameW, PSHARED_FACE SharedFace,
+ FT_UShort NameID, FT_UShort LangID)
{
FT_SfntName Name;
- INT i, Count;
- WCHAR Buf[LF_FACESIZE];
+ 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;
+ FT_Face Face = SharedFace->Face;
+
+ RtlFreeUnicodeString(pNameW);
+
+ /* select cache */
+ if (PRIMARYLANGID(LangID) == LANG_ENGLISH)
+ {
+ Cache = &SharedFace->EnglishUS;
+ }
+ else
+ {
+ Cache = &SharedFace->UserLanguage;
+ }
- RtlInitUnicodeString(pLocalNameW, NULL);
+ /* 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)
{
- FT_Get_Sfnt_Name(Face, i, &Name);
+ Error = FT_Get_Sfnt_Name(Face, i, &Name);
+ if (Error)
+ {
+ continue; /* failure */
+ }
+
+ 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_UNICODE_CS &&
+ Name.encoding_id != TT_MS_ID_SYMBOL_CS))
{
continue; /* not Microsoft Unicode name */
}
- if (Name.name_id != TT_NAME_ID_FONT_FAMILY ||
- Name.string == NULL || Name.string_len == 0 ||
+ 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))
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;
+ 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;
+ }
- /* 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
+ if (Score > BestScore)
+ {
+ BestScore = Score;
+ BestIndex = i;
+ }
+ }
- Status = RtlCreateUnicodeString(pLocalNameW, Buf);
- break;
+ if (BestIndex >= 0)
+ {
+ /* store the best name */
+ Error = (Score == 30) ? 0 : FT_Get_Sfnt_Name(Face, BestIndex, &Name);
+ if (!Error)
+ {
+ /* 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);
+ }
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* defaulted */
+ if (NameID == TT_NAME_ID_FONT_SUBFAMILY)
+ {
+ RtlInitAnsiString(&AnsiName, Face->style_name);
+ Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
+ }
+ else
+ {
+ RtlInitAnsiString(&AnsiName, Face->family_name);
+ Status = RtlAnsiStringToUnicodeString(pNameW, &AnsiName, TRUE);
+ }
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ /* 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;
}
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;
NEWTEXTMETRICW *Ntm;
DWORD fs0;
NTSTATUS status;
- FT_Face Face = FontGDI->SharedFace->Face;
+ PSHARED_FACE SharedFace = FontGDI->SharedFace;
+ FT_Face Face = SharedFace->Face;
+ UNICODE_STRING NameW;
+ RtlInitUnicodeString(&NameW, NULL);
RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
Otm = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEXT);
{
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);
- /* try the localized name */
- status = STATUS_UNSUCCESSFUL;
- if (CharSetFromLangID(gusLanguageID) == FontGDI->CharSet)
- {
- /* get localized name */
- UNICODE_STRING LocalNameW;
- status = IntGetFontLocalizedName(&LocalNameW, Face);
- 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);
- }
- RtlFreeUnicodeString(&LocalNameW);
- }
+ /* face name */
+ if (!FaceName)
+ FaceName = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
- /* 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);
- }
+ RtlStringCbCopyW(Lf->lfFaceName, sizeof(Lf->lfFaceName), FaceName);
+
+ /* full name */
+ 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;
}
- 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.elfScript[0] = UNICODE_NULL;
- Info->EnumLogFontEx.elfLogFont.lfCharSet = DEFAULT_CHARSET;
- Info->EnumLogFontEx.elfScript[0] = L'\0';
IntLockFreeType;
pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
}
if (DEFAULT_CHARSET != CharSetInfo.ciCharset)
{
- Info->EnumLogFontEx.elfLogFont.lfCharSet = CharSetInfo.ciCharset;
if (ElfScripts[i])
wcscpy(Info->EnumLogFontEx.elfScript, ElfScripts[i]);
else
{
if (*Count < Size)
{
- FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer, FontGDI);
+ FontFamilyFillInfo(Info + *Count, EntryFaceNameW.Buffer,
+ NULL, FontGDI);
}
(*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, 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
PLIST_ENTRY CurrentEntry;
PFONT_CACHE_ENTRY FontEntry;
+ ASSERT_FREETYPE_LOCK_HELD();
+
CurrentEntry = FontCacheListHead.Flink;
while (CurrentEntry != &FontCacheListHead)
{
- FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
+ FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry);
if ((FontEntry->Face == Face) &&
(FontEntry->GlyphIndex == GlyphIndex) &&
(FontEntry->Height == Height) &&
FT_Bitmap AlignedBitmap;
FT_BitmapGlyph BitmapGlyph;
+ ASSERT_FREETYPE_LOCK_HELD();
+
error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
if (error)
{
{
DPRINT1("Conversion failed\n");
ExFreePoolWithTag(NewEntry, TAG_FONT);
+ FT_Bitmap_Done(GlyphSlot->library, &AlignedBitmap);
FT_Done_Glyph((FT_Glyph)BitmapGlyph);
return NULL;
}
NewEntry->mxWorldToDevice = *pmx;
InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
- if (FontCacheNumEntries++ > MAX_FONT_CACHE)
+ if (++FontCacheNumEntries > MAX_FONT_CACHE)
{
- NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
- FT_Done_Glyph((FT_Glyph)NewEntry->BitmapGlyph);
- RemoveTailList(&FontCacheListHead);
- ExFreePoolWithTag(NewEntry, TAG_FONT);
- FontCacheNumEntries--;
+ NewEntry = CONTAINING_RECORD(FontCacheListHead.Blink, FONT_CACHE_ENTRY, ListEntry);
+ RemoveCachedEntry(NewEntry);
}
return BitmapGlyph;
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;
LONG Long;
BOOL fFixedSys = FALSE, fNeedScaling = FALSE;
const BYTE UserCharSet = CharSetFromLangID(gusLanguageID);
+ 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))
+ if (_wcsicmp(LogFont->lfFaceName, L"System") == 0)
{
/* "System" font */
if (TM->tmCharSet != UserCharSet)
Penalty += 65000;
}
}
- else if (RtlEqualUnicodeString(RequestedNameW, &FixedSysW, TRUE))
+ else if (_wcsicmp(LogFont->lfFaceName, L"FixedSys") == 0)
{
/* "FixedSys" font */
if (TM->tmCharSet != UserCharSet)
}
else /* Request is non-"System" font */
{
- Byte = RequestedCharSet;
+ Byte = LogFont->lfCharSet;
if (Byte == DEFAULT_CHARSET)
{
- if (RtlEqualUnicodeString(RequestedNameW, &MarlettW, TRUE))
+ if (_wcsicmp(LogFont->lfFaceName, L"Marlett") == 0)
{
if (Byte == ANSI_CHARSET)
{
}
}
- if (RequestedNameW->Buffer[0])
+ ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFamilyName);
+
+ if (LogFont->lfFaceName[0])
{
- if (RtlEqualUnicodeString(RequestedNameW, FullFaceNameW, TRUE))
+ BOOL Found = FALSE;
+
+ /* localized family name */
+ if (!Found)
{
- /* matched with full face name */
+ Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
}
- else if (RtlEqualUnicodeString(RequestedNameW, ActualNameW, TRUE))
+ /* localized full name */
+ if (!Found)
{
- /* matched with actual name */
+ ActualNameW = (WCHAR*)((ULONG_PTR)Otm + (ULONG_PTR)Otm->otmpFaceName);
+ Found = (_wcsicmp(LogFont->lfFaceName, ActualNameW) == 0);
}
- else
+ if (!Found)
{
- /* try the localized name */
- UNICODE_STRING LocalNameW;
- FT_Face Face = FontGDI->SharedFace->Face;
- IntGetFontLocalizedName(&LocalNameW, Face);
- if (RtlEqualUnicodeString(RequestedNameW, &LocalNameW, TRUE))
- {
- /* matched with localizied name */
- }
- else
- {
- /* FaceName Penalty 10000 */
- /* Requested a face name, but the candidate's face name
- does not match. */
- Penalty += 10000;
- }
- RtlFreeUnicodeString(&LocalNameW);
+ /* FaceName Penalty 10000 */
+ /* Requested a face name, but the candidate's face name
+ does not match. */
+ Penalty += 10000;
}
}
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)
{
- CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+ CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+ Entry = Entry->Flink;
+
FontGDI = CurrentEntry->Font;
ASSERT(FontGDI);
Face = FontGDI->SharedFace->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)
/* 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);
- /* next entry */
- Entry = Entry->Flink;
+ 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);
-
- /* next entry */
- Entry = Entry->Flink;
}
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);
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]))
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);
}
}