mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[WIN32SS] Cleanup fonts at process destruction + implement font memory reference counting.
Thanks to everyone involved in reviewing this code! (See CR-112) CORE-13056 svn path=/trunk/; revision=74309
This commit is contained in:
@@ -107,9 +107,17 @@ typedef struct _FLOATGDI {
|
||||
ULONG Dummy;
|
||||
} FLOATGDI;
|
||||
|
||||
typedef struct _SHARED_MEM {
|
||||
PVOID Buffer;
|
||||
ULONG BufferSize;
|
||||
BOOL IsMapping;
|
||||
LONG RefCount;
|
||||
} SHARED_MEM, *PSHARED_MEM;
|
||||
|
||||
typedef struct _SHARED_FACE {
|
||||
FT_Face Face;
|
||||
LONG RefCount;
|
||||
FT_Face Face;
|
||||
LONG RefCount;
|
||||
PSHARED_MEM Memory;
|
||||
} SHARED_FACE, *PSHARED_FACE;
|
||||
|
||||
typedef struct _FONTGDI {
|
||||
|
||||
@@ -54,8 +54,7 @@ typedef struct FONTSUBST_ENTRY
|
||||
typedef struct GDI_LOAD_FONT
|
||||
{
|
||||
PUNICODE_STRING pFileName;
|
||||
PVOID Buffer;
|
||||
ULONG BufferSize;
|
||||
PSHARED_MEM Memory;
|
||||
DWORD Characteristics;
|
||||
UNICODE_STRING RegValueName;
|
||||
BOOL IsTrueType;
|
||||
|
||||
@@ -58,39 +58,6 @@ static const UNICODE_STRING FixedSysW = RTL_CONSTANT_STRING(L"FixedSys");
|
||||
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 */
|
||||
@@ -106,12 +73,18 @@ static BOOL RenderingEnabled = TRUE;
|
||||
#define IntUnLockGlobalFonts \
|
||||
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FontListLock)
|
||||
|
||||
#define ASSERT_GLOBALFONTS_LOCK_HELD() \
|
||||
ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
|
||||
|
||||
#define IntLockFreeType \
|
||||
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(FreeTypeLock)
|
||||
|
||||
#define IntUnLockFreeType \
|
||||
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(FreeTypeLock)
|
||||
|
||||
#define ASSERT_FREETYPE_LOCK_HELD() \
|
||||
ASSERT(FreeTypeLock->Owner == KeGetCurrentThread())
|
||||
|
||||
#define MAX_FONT_CACHE 256
|
||||
|
||||
static LIST_ENTRY FontCacheListHead;
|
||||
@@ -189,6 +162,129 @@ static const CHARSETINFO FontTci[MAXTCIINDEX] =
|
||||
/* list head */
|
||||
static RTL_STATIC_LIST_HEAD(FontSubstListHead);
|
||||
|
||||
static void
|
||||
SharedMem_AddRef(PSHARED_MEM Ptr)
|
||||
{
|
||||
ASSERT_FREETYPE_LOCK_HELD();
|
||||
|
||||
++Ptr->RefCount;
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
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);
|
||||
ExFreePoolWithTag(Ptr, TAG_FONT);
|
||||
}
|
||||
IntUnLockFreeType;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IntLoadFontSubstList --- loads the list of font substitutes
|
||||
*/
|
||||
@@ -677,8 +773,6 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
|
||||
FT_WinFNT_HeaderRec WinFNT;
|
||||
INT FontCount = 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;
|
||||
@@ -693,30 +787,37 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
|
||||
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))
|
||||
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 */
|
||||
@@ -1006,8 +1107,7 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -1016,6 +1116,11 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
|
||||
|
||||
ObDereferenceObject(SectionObject);
|
||||
|
||||
/* Release our copy */
|
||||
IntLockFreeType;
|
||||
SharedMem_Release(LoadFont.Memory);
|
||||
IntUnLockFreeType;
|
||||
|
||||
if (FontCount > 0)
|
||||
{
|
||||
if (LoadFont.IsTrueType)
|
||||
@@ -1070,17 +1175,17 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
|
||||
INT FontCount;
|
||||
HANDLE Ret = 0;
|
||||
|
||||
/* We leak this buffer for now, same as all fonts do with their buffer! */
|
||||
LoadFont.Buffer = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
|
||||
if (!LoadFont.Buffer)
|
||||
PVOID BufferCopy = ExAllocatePoolWithTag(PagedPool, dwSize, TAG_FONT);
|
||||
|
||||
if (!BufferCopy)
|
||||
{
|
||||
*pNumAdded = 0;
|
||||
return NULL;
|
||||
}
|
||||
memcpy(LoadFont.Buffer, Buffer, dwSize);
|
||||
memcpy(BufferCopy, Buffer, dwSize);
|
||||
|
||||
LoadFont.pFileName = NULL;
|
||||
LoadFont.BufferSize = dwSize;
|
||||
LoadFont.Memory = SharedMem_Create(BufferCopy, dwSize, FALSE);
|
||||
LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM;
|
||||
RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
|
||||
LoadFont.IsTrueType = FALSE;
|
||||
@@ -1089,7 +1194,11 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
|
||||
|
||||
RtlFreeUnicodeString(&LoadFont.RegValueName);
|
||||
|
||||
*pNumAdded = FontCount;
|
||||
/* Release our copy */
|
||||
IntLockFreeType;
|
||||
SharedMem_Release(LoadFont.Memory);
|
||||
IntUnLockFreeType;
|
||||
|
||||
if (FontCount > 0)
|
||||
{
|
||||
EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT);
|
||||
@@ -1104,12 +1213,27 @@ IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
|
||||
Ret = (HANDLE)EntryCollection->Handle;
|
||||
}
|
||||
}
|
||||
*pNumAdded = FontCount;
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -1121,14 +1245,31 @@ 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)
|
||||
{
|
||||
@@ -1146,7 +1287,7 @@ IntGdiRemoveFontMemResource(HANDLE hMMFont)
|
||||
if (CurrentEntry->Handle == (UINT)hMMFont)
|
||||
{
|
||||
EntryCollection = CurrentEntry;
|
||||
RemoveEntryList(Entry);
|
||||
UnlinkFontMemCollection(CurrentEntry);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1164,6 +1305,52 @@ IntGdiRemoveFontMemResource(HANDLE hMMFont)
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -1737,7 +1924,7 @@ FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
|
||||
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);
|
||||
@@ -1774,7 +1961,8 @@ FindFaceNameInLists(PUNICODE_STRING FaceName)
|
||||
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);
|
||||
@@ -2333,10 +2521,12 @@ ftGdiGlyphCacheGet(
|
||||
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) &&
|
||||
@@ -2412,6 +2602,8 @@ ftGdiGlyphCacheSet(
|
||||
FT_Bitmap AlignedBitmap;
|
||||
FT_BitmapGlyph BitmapGlyph;
|
||||
|
||||
ASSERT_FREETYPE_LOCK_HELD();
|
||||
|
||||
error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
|
||||
if (error)
|
||||
{
|
||||
@@ -2455,13 +2647,10 @@ ftGdiGlyphCacheSet(
|
||||
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;
|
||||
@@ -4116,7 +4305,7 @@ FindBestFontFromList(FONTOBJ **FontObj, ULONG *MatchPenalty, LOGFONTW *LogFont,
|
||||
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);
|
||||
Face = FontGDI->SharedFace->Face;
|
||||
|
||||
@@ -50,6 +50,8 @@ GdiProcessDestroy(PEPROCESS Process)
|
||||
ASSERT(ppiCurrent);
|
||||
ASSERT(ppiCurrent->peProcess == Process);
|
||||
|
||||
IntGdiCleanupPrivateFontsForProcess();
|
||||
|
||||
/* And GDI ones too */
|
||||
GDI_CleanupForProcess(Process);
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ BOOL FASTCALL IntIsFontRenderingEnabled(VOID);
|
||||
VOID FASTCALL IntEnableFontRendering(BOOL Enable);
|
||||
ULONG FASTCALL FontGetObject(PTEXTOBJ TextObj, ULONG Count, PVOID Buffer);
|
||||
VOID FASTCALL IntLoadSystemFonts(VOID);
|
||||
VOID FASTCALL IntGdiCleanupPrivateFontsForProcess(VOID);
|
||||
INT FASTCALL IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics);
|
||||
HANDLE FASTCALL IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded);
|
||||
BOOL FASTCALL IntGdiRemoveFontMemResource(HANDLE hMMFont);
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
* PURPOSE: Test for AddFontMemResourceEx
|
||||
* PROGRAMMERS: Mark Jansen
|
||||
*
|
||||
* PanosePitchTest by Katayama Hirofumi MZ, licensed under CC BY
|
||||
* PanosePitchTest + TTCTestV by Katayama Hirofumi MZ, licensed under CC BY
|
||||
* Shadows_Into_Light by Kimberly Geswein, licensed under OFL
|
||||
* Captured from firefox, embedded on reactos.org
|
||||
*/
|
||||
|
||||
|
||||
@@ -12,102 +14,260 @@
|
||||
#include <wingdi.h>
|
||||
#include <winuser.h>
|
||||
|
||||
typedef struct _fnt_res
|
||||
{
|
||||
const char* FontName;
|
||||
TEXTMETRICA tm;
|
||||
} fnt_res;
|
||||
|
||||
static void test_font_caps(HDC hdc)
|
||||
typedef struct _fnt_test
|
||||
{
|
||||
const char* ResourceName;
|
||||
int NumFaces;
|
||||
fnt_res res[4];
|
||||
} fnt_test;
|
||||
|
||||
|
||||
|
||||
static fnt_test test_data[] =
|
||||
{
|
||||
{
|
||||
.ResourceName = "PanosePitchTest.ttf",
|
||||
.NumFaces = 2,
|
||||
.res =
|
||||
{
|
||||
{
|
||||
.FontName = "PanosePitchTest",
|
||||
.tm.tmHeight = 11,
|
||||
.tm.tmAscent = 11,
|
||||
.tm.tmDescent = 0,
|
||||
.tm.tmInternalLeading = -5,
|
||||
.tm.tmExternalLeading = 1,
|
||||
.tm.tmAveCharWidth = 8,
|
||||
.tm.tmMaxCharWidth = 11,
|
||||
.tm.tmWeight = FW_NORMAL,
|
||||
.tm.tmOverhang = 0,
|
||||
.tm.tmDigitizedAspectX = 96,
|
||||
.tm.tmDigitizedAspectY = 96,
|
||||
.tm.tmFirstChar = 63,
|
||||
.tm.tmLastChar = 65,
|
||||
.tm.tmDefaultChar = 165,
|
||||
.tm.tmBreakChar = 65,
|
||||
.tm.tmItalic = 0,
|
||||
.tm.tmUnderlined = 0,
|
||||
.tm.tmStruckOut = 0,
|
||||
.tm.tmPitchAndFamily = TMPF_TRUETYPE | TMPF_VECTOR,
|
||||
.tm.tmCharSet = SHIFTJIS_CHARSET,
|
||||
},
|
||||
{
|
||||
.FontName = "@PanosePitchTest",
|
||||
.tm.tmHeight = 11,
|
||||
.tm.tmAscent = 11,
|
||||
.tm.tmDescent = 0,
|
||||
.tm.tmInternalLeading = -5,
|
||||
.tm.tmExternalLeading = 1,
|
||||
.tm.tmAveCharWidth = 8,
|
||||
.tm.tmMaxCharWidth = 11,
|
||||
.tm.tmWeight = FW_NORMAL,
|
||||
.tm.tmOverhang = 0,
|
||||
.tm.tmDigitizedAspectX = 96,
|
||||
.tm.tmDigitizedAspectY = 96,
|
||||
.tm.tmFirstChar = 63,
|
||||
.tm.tmLastChar = 65,
|
||||
.tm.tmDefaultChar = 165,
|
||||
.tm.tmBreakChar = 65,
|
||||
.tm.tmItalic = 0,
|
||||
.tm.tmUnderlined = 0,
|
||||
.tm.tmStruckOut = 0,
|
||||
.tm.tmPitchAndFamily = TMPF_TRUETYPE | TMPF_VECTOR,
|
||||
.tm.tmCharSet = SHIFTJIS_CHARSET,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.ResourceName = "TTCTestV.ttc",
|
||||
.NumFaces = 3,
|
||||
.res =
|
||||
{
|
||||
{
|
||||
.FontName = "No1Of3in1",
|
||||
.tm.tmHeight = 12,
|
||||
.tm.tmAscent = 12,
|
||||
.tm.tmDescent = 0,
|
||||
.tm.tmInternalLeading = -4,
|
||||
.tm.tmExternalLeading = 1,
|
||||
.tm.tmAveCharWidth = -525,
|
||||
.tm.tmMaxCharWidth = 6,
|
||||
.tm.tmWeight = FW_NORMAL,
|
||||
.tm.tmOverhang = 0,
|
||||
.tm.tmDigitizedAspectX = 96,
|
||||
.tm.tmDigitizedAspectY = 96,
|
||||
.tm.tmFirstChar = 63,
|
||||
.tm.tmLastChar = 65,
|
||||
.tm.tmDefaultChar = 64,
|
||||
.tm.tmBreakChar = 65,
|
||||
.tm.tmItalic = 0,
|
||||
.tm.tmUnderlined = 0,
|
||||
.tm.tmStruckOut = 0,
|
||||
.tm.tmPitchAndFamily = TMPF_TRUETYPE | TMPF_VECTOR | TMPF_FIXED_PITCH,
|
||||
.tm.tmCharSet = ANSI_CHARSET,
|
||||
},
|
||||
{
|
||||
.FontName = "No2Of3in1",
|
||||
.tm.tmHeight = 12,
|
||||
.tm.tmAscent = 12,
|
||||
.tm.tmDescent = 0,
|
||||
.tm.tmInternalLeading = -4,
|
||||
.tm.tmExternalLeading = 1,
|
||||
.tm.tmAveCharWidth = 8,
|
||||
.tm.tmMaxCharWidth = 7,
|
||||
.tm.tmWeight = FW_NORMAL,
|
||||
.tm.tmOverhang = 0,
|
||||
.tm.tmDigitizedAspectX = 96,
|
||||
.tm.tmDigitizedAspectY = 96,
|
||||
.tm.tmFirstChar = 63,
|
||||
.tm.tmLastChar = 65,
|
||||
.tm.tmDefaultChar = 64,
|
||||
.tm.tmBreakChar = 65,
|
||||
.tm.tmItalic = 0,
|
||||
.tm.tmUnderlined = 0,
|
||||
.tm.tmStruckOut = 0,
|
||||
.tm.tmPitchAndFamily = TMPF_TRUETYPE | TMPF_VECTOR | TMPF_FIXED_PITCH,
|
||||
.tm.tmCharSet = ANSI_CHARSET,
|
||||
},
|
||||
{
|
||||
.FontName = "No3Of3in1V",
|
||||
.tm.tmHeight = 12,
|
||||
.tm.tmAscent = 12,
|
||||
.tm.tmDescent = 0,
|
||||
.tm.tmInternalLeading = -4,
|
||||
.tm.tmExternalLeading = 1,
|
||||
.tm.tmAveCharWidth = 8,
|
||||
.tm.tmMaxCharWidth = 13,
|
||||
.tm.tmWeight = FW_NORMAL,
|
||||
.tm.tmOverhang = 0,
|
||||
.tm.tmDigitizedAspectX = 96,
|
||||
.tm.tmDigitizedAspectY = 96,
|
||||
.tm.tmFirstChar = 63,
|
||||
.tm.tmLastChar = 65,
|
||||
.tm.tmDefaultChar = 64,
|
||||
.tm.tmBreakChar = 65,
|
||||
.tm.tmItalic = 0,
|
||||
.tm.tmUnderlined = 0,
|
||||
.tm.tmStruckOut = 0,
|
||||
.tm.tmPitchAndFamily = FF_MODERN | TMPF_TRUETYPE | TMPF_VECTOR,
|
||||
.tm.tmCharSet = ANSI_CHARSET,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.ResourceName = "Shadows_Into_Light.ttf",
|
||||
.NumFaces = 1,
|
||||
.res =
|
||||
{
|
||||
{
|
||||
.FontName = "ufaXaAlLOxCUGYJ7KN51UP2Q==",
|
||||
.tm.tmHeight = 26,
|
||||
.tm.tmAscent = 19,
|
||||
.tm.tmDescent = 7,
|
||||
.tm.tmInternalLeading = 10,
|
||||
.tm.tmExternalLeading = 0,
|
||||
.tm.tmAveCharWidth = 7,
|
||||
.tm.tmMaxCharWidth = 23,
|
||||
.tm.tmWeight = FW_NORMAL,
|
||||
.tm.tmOverhang = 0,
|
||||
.tm.tmDigitizedAspectX = 96,
|
||||
.tm.tmDigitizedAspectY = 96,
|
||||
.tm.tmFirstChar = 30,
|
||||
.tm.tmLastChar = 255,
|
||||
.tm.tmDefaultChar = 31,
|
||||
.tm.tmBreakChar = 32,
|
||||
.tm.tmItalic = 0,
|
||||
.tm.tmUnderlined = 0,
|
||||
.tm.tmStruckOut = 0,
|
||||
.tm.tmPitchAndFamily = TMPF_TRUETYPE | TMPF_VECTOR | TMPF_FIXED_PITCH,
|
||||
.tm.tmCharSet = ANSI_CHARSET,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
#define ok_int2(expression) \
|
||||
do { \
|
||||
int _value = (expression); \
|
||||
ok(_value == (res->expression), "Wrong value for '%s', expected: %d, got: %d for %s/%s\n", \
|
||||
#expression, (int)(res->expression), _value, test_name, res->FontName); \
|
||||
} while (0)
|
||||
|
||||
#define ok_hex2(expression) \
|
||||
do { \
|
||||
int _value = (expression); \
|
||||
ok(_value == (res->expression), "Wrong value for '%s', expected: 0x%x, got: 0x%x for %s/%s\n", \
|
||||
#expression, (int)(res->expression), _value, test_name, res->FontName); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static void test_font_caps(HDC hdc, int test_index)
|
||||
{
|
||||
HGDIOBJ old;
|
||||
TEXTMETRICA tm = { 0 };
|
||||
char name[64];
|
||||
BOOL ret;
|
||||
HFONT font = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, TEXT("PanosePitchTest"));
|
||||
HFONT font;
|
||||
int n;
|
||||
const char* test_name = test_data[test_index].ResourceName;
|
||||
|
||||
if (font)
|
||||
for (n = 0; test_data[test_index].res[n].FontName; ++n)
|
||||
{
|
||||
old = SelectObject(hdc, font);
|
||||
fnt_res* res = test_data[test_index].res + n;
|
||||
font = CreateFontA(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, res->FontName);
|
||||
|
||||
memset(&tm, 0xaa, sizeof(tm));
|
||||
ret = GetTextMetricsA(hdc, &tm);
|
||||
ok_int(ret, TRUE);
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = GetTextFaceA(hdc, sizeof(name), name);
|
||||
ok(ret, "GetTextFaceA error %lu\n", GetLastError());
|
||||
if (ret)
|
||||
if (font)
|
||||
{
|
||||
ok_str(name, "PanosePitchTest");
|
||||
old = SelectObject(hdc, font);
|
||||
|
||||
memset(&tm, 0xaa, sizeof(tm));
|
||||
ret = GetTextMetricsA(hdc, &tm);
|
||||
ok(ret, "GetTextMetricsA() for %s/%s\n", test_name, res->FontName);
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = GetTextFaceA(hdc, sizeof(name), name);
|
||||
ok(ret, "GetTextFaceA error %lu for %s/%s\n", GetLastError(), test_name, res->FontName);
|
||||
if (ret)
|
||||
{
|
||||
ok(!strcmp(name, res->FontName), "FontName was %s, expected %s for %s/%s", name, res->FontName, test_name, res->FontName);
|
||||
}
|
||||
|
||||
ok_int2(tm.tmHeight);
|
||||
ok_int2(tm.tmAscent);
|
||||
ok_int2(tm.tmDescent);
|
||||
ok_int2(tm.tmInternalLeading);
|
||||
ok_int2(tm.tmExternalLeading);
|
||||
ok_int2(tm.tmAveCharWidth);
|
||||
ok_int2(tm.tmMaxCharWidth);
|
||||
ok_int2(tm.tmWeight);
|
||||
ok_int2(tm.tmOverhang);
|
||||
ok_int2(tm.tmDigitizedAspectX);
|
||||
ok_int2(tm.tmDigitizedAspectY);
|
||||
ok_int2(tm.tmFirstChar);
|
||||
ok_int2(tm.tmLastChar);
|
||||
ok_int2(tm.tmDefaultChar);
|
||||
ok_int2(tm.tmBreakChar);
|
||||
ok_int2(tm.tmItalic);
|
||||
ok_int2(tm.tmUnderlined);
|
||||
ok_int2(tm.tmStruckOut);
|
||||
ok_hex2(tm.tmPitchAndFamily);
|
||||
ok_int2(tm.tmCharSet);
|
||||
|
||||
SelectObject(hdc, old);
|
||||
DeleteObject(font);
|
||||
}
|
||||
|
||||
ok_int(tm.tmHeight, 11);
|
||||
ok_int(tm.tmAscent, 11);
|
||||
ok_int(tm.tmDescent, 0);
|
||||
ok_int(tm.tmInternalLeading, -5);
|
||||
ok_int(tm.tmExternalLeading, 1);
|
||||
ok_int(tm.tmAveCharWidth, 8);
|
||||
ok_int(tm.tmMaxCharWidth, 11);
|
||||
ok_int(tm.tmWeight, FW_NORMAL);
|
||||
ok_int(tm.tmOverhang, 0);
|
||||
ok_int(tm.tmDigitizedAspectX, 96);
|
||||
ok_int(tm.tmDigitizedAspectY, 96);
|
||||
ok_int(tm.tmFirstChar, 63);
|
||||
ok_int(tm.tmLastChar, 65);
|
||||
ok_int(tm.tmDefaultChar, 165);
|
||||
ok_int(tm.tmBreakChar, 65);
|
||||
ok_int(tm.tmItalic, 0);
|
||||
ok_int(tm.tmUnderlined, 0);
|
||||
ok_int(tm.tmStruckOut, 0);
|
||||
ok_hex(tm.tmPitchAndFamily, TMPF_TRUETYPE | TMPF_VECTOR);
|
||||
ok_int(tm.tmCharSet, SHIFTJIS_CHARSET);
|
||||
|
||||
SelectObject(hdc, old);
|
||||
DeleteObject(font);
|
||||
}
|
||||
|
||||
font = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, TEXT("@PanosePitchTest"));
|
||||
|
||||
if (font)
|
||||
{
|
||||
old = SelectObject(hdc, font);
|
||||
|
||||
memset(&tm, 0xaa, sizeof(tm));
|
||||
ret = GetTextMetricsA(hdc, &tm);
|
||||
ok_int(ret, TRUE);
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = GetTextFaceA(hdc, sizeof(name), name);
|
||||
ok(ret, "GetTextFaceA error %lu\n", GetLastError());
|
||||
if (ret)
|
||||
{
|
||||
ok_str(name, "@PanosePitchTest");
|
||||
}
|
||||
|
||||
ok_int(tm.tmHeight, 11);
|
||||
ok_int(tm.tmAscent, 11);
|
||||
ok_int(tm.tmDescent, 0);
|
||||
ok_int(tm.tmInternalLeading, -5);
|
||||
ok_int(tm.tmExternalLeading, 1);
|
||||
ok_int(tm.tmAveCharWidth, 8);
|
||||
ok_int(tm.tmMaxCharWidth, 11);
|
||||
ok_int(tm.tmWeight, FW_NORMAL);
|
||||
ok_int(tm.tmOverhang, 0);
|
||||
ok_int(tm.tmDigitizedAspectX, 96);
|
||||
ok_int(tm.tmDigitizedAspectY, 96);
|
||||
ok_int(tm.tmFirstChar, 63);
|
||||
ok_int(tm.tmLastChar, 65);
|
||||
ok_int(tm.tmDefaultChar, 165);
|
||||
ok_int(tm.tmBreakChar, 65);
|
||||
ok_int(tm.tmItalic, 0);
|
||||
ok_int(tm.tmUnderlined, 0);
|
||||
ok_int(tm.tmStruckOut, 0);
|
||||
ok_hex(tm.tmPitchAndFamily, TMPF_TRUETYPE | TMPF_VECTOR);
|
||||
ok_int(tm.tmCharSet, SHIFTJIS_CHARSET);
|
||||
|
||||
SelectObject(hdc, old);
|
||||
DeleteObject(font);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Not working as of 2017-04-08 on ReactOS */
|
||||
static BOOL is_font_available(HDC hdc, const char* fontName)
|
||||
{
|
||||
@@ -122,7 +282,7 @@ static BOOL is_font_available(HDC hdc, const char* fontName)
|
||||
SetLastError(0xdeadbeef);
|
||||
|
||||
ret = GetTextFaceA(hdc, sizeof(name), name);
|
||||
ok(ret, "GetTextFaceA error %lu\n", GetLastError());
|
||||
ok(ret, "GetTextFaceA error %lu for %s\n", GetLastError(), fontName);
|
||||
SelectObject(hdc, old);
|
||||
DeleteObject(font);
|
||||
|
||||
@@ -145,16 +305,20 @@ START_TEST(AddFontMemResourceEx)
|
||||
LPVOID pFont;
|
||||
|
||||
HANDLE hFont;
|
||||
fnt_test* data;
|
||||
int n;
|
||||
|
||||
HDC hdc = CreateCompatibleDC(NULL);
|
||||
BOOL is_font_available_broken = is_font_available(hdc, "Nonexisting font name here");
|
||||
|
||||
ok(!is_font_available_broken, "Validating font is broken! (CORE-13053) !\n");
|
||||
ok(!is_font_available_broken, "Validating font is broken! (CORE-13053)!\n");
|
||||
|
||||
if (is_font_available_broken || !is_font_available(hdc, "PanosePitchTest"))
|
||||
for (n = 0; n < _countof(test_data); ++n)
|
||||
{
|
||||
data = test_data + n;
|
||||
|
||||
mod = GetModuleHandle(NULL);
|
||||
hRsrc = FindResource(mod, TEXT("PanosePitchTest.ttf"), MAKEINTRESOURCE(RT_RCDATA));
|
||||
hRsrc = FindResourceA(mod, data->ResourceName, MAKEINTRESOURCE(RT_RCDATA));
|
||||
|
||||
hTemplate = LoadResource(mod, hRsrc);
|
||||
dwSize = SizeofResource(mod, hRsrc);
|
||||
@@ -162,30 +326,27 @@ START_TEST(AddFontMemResourceEx)
|
||||
|
||||
dwNumFonts = 0;
|
||||
hFont = AddFontMemResourceEx(pFont, dwSize, NULL, &dwNumFonts);
|
||||
ok_int(dwNumFonts, 2);
|
||||
ok(hFont != NULL, "Expected valid handle\n");
|
||||
ok(dwNumFonts == data->NumFaces, "dwNumFonts was %lu, expected %d for %s\n", dwNumFonts, data->NumFaces, data->ResourceName);
|
||||
ok(hFont != NULL, "Expected valid handle for %s\n", data->ResourceName);
|
||||
|
||||
if (hFont)
|
||||
{
|
||||
test_font_caps(hdc);
|
||||
test_font_caps(hdc, n);
|
||||
RemoveFontMemResourceEx(hFont);
|
||||
if (!is_font_available_broken)
|
||||
{
|
||||
ok (!is_font_available(hdc, "PanosePitchTest"), "Expected font to be unregistered again\n");
|
||||
ok (!is_font_available(hdc, data->ResourceName), "Expected font to be unregistered again for %s\n", data->ResourceName);
|
||||
}
|
||||
else
|
||||
{
|
||||
skip("Font unregister test\n");
|
||||
skip("Font unregister test for %s\n", data->ResourceName);
|
||||
}
|
||||
}
|
||||
|
||||
UnlockResource(hTemplate);
|
||||
FreeResource(hTemplate);
|
||||
}
|
||||
else
|
||||
{
|
||||
skip("Font PanosePitchTest already available\n");
|
||||
}
|
||||
|
||||
DeleteDC(hdc);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -2,3 +2,5 @@
|
||||
|
||||
ReactOSTestTahoma.ttf RCDATA ReactOSTestTahoma.ttf
|
||||
PanosePitchTest.ttf RCDATA PanosePitchTest.ttf
|
||||
TTCTestV.ttc RCDATA TTCTestV.ttc
|
||||
Shadows_Into_Light.ttf RCDATA Shadows_Into_Light.ttf
|
||||
|
||||
Reference in New Issue
Block a user