Index: reactos/ntoskrnl/mm/ARM3/pool.c =================================================================== --- reactos/ntoskrnl/mm/ARM3/pool.c (revision 74270) +++ reactos/ntoskrnl/mm/ARM3/pool.c (working copy) @@ -24,7 +24,7 @@ KGUARDED_MUTEX MmPagedPoolMutex; MM_PAGED_POOL_INFO MmPagedPoolInfo; SIZE_T MmAllocatedNonPagedPool; -ULONG MmSpecialPoolTag; +ULONG MmSpecialPoolTag = '*'; ULONG MmConsumedPoolPercentage; BOOLEAN MmProtectFreedNonPagedPool; SLIST_HEADER MiNonPagedPoolSListHead; Index: reactos/win32ss/gdi/eng/engobjects.h =================================================================== --- reactos/win32ss/gdi/eng/engobjects.h (revision 74270) +++ reactos/win32ss/gdi/eng/engobjects.h (working copy) @@ -110,6 +110,8 @@ typedef struct _SHARED_FACE { FT_Face Face; LONG RefCount; + PVOID Buffer; + BOOL IsMemoryFont; } SHARED_FACE, *PSHARED_FACE; typedef struct _FONTGDI { Index: reactos/win32ss/gdi/ntgdi/font.h =================================================================== --- reactos/win32ss/gdi/ntgdi/font.h (revision 74285) +++ reactos/win32ss/gdi/ntgdi/font.h (working copy) @@ -59,6 +59,7 @@ DWORD Characteristics; UNICODE_STRING RegValueName; BOOL IsTrueType; + BOOL IsVertical; PFONT_ENTRY_MEM PrivateEntry; } GDI_LOAD_FONT, *PGDI_LOAD_FONT; Index: reactos/win32ss/gdi/ntgdi/freetype.c =================================================================== --- reactos/win32ss/gdi/ntgdi/freetype.c (revision 74286) +++ reactos/win32ss/gdi/ntgdi/freetype.c (working copy) @@ -35,6 +35,7 @@ #define NDEBUG #include +WINE_DEFAULT_DEBUG_CHANNEL(freetype); /* TPMF_FIXED_PITCH is confusing; brain-dead api */ #ifndef _TMPF_VARIABLE_PITCH @@ -58,40 +59,7 @@ 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 */ static PFAST_MUTEX FreeTypeLock; @@ -189,6 +157,82 @@ /* list head */ static RTL_STATIC_LIST_HEAD(FontSubstListHead); + +static PSHARED_FACE +SharedFace_Create(FT_Face Face, PVOID Buffer, BOOL IsMemoryFont) +{ + PSHARED_FACE Ptr; + Ptr = ExAllocatePoolWithTag(PagedPool, sizeof(SHARED_FACE), TAG_FONT); + if (Ptr) + { + Ptr->Face = Face; + Ptr->RefCount = 1; + Ptr->Buffer = Buffer; + Ptr->IsMemoryFont = IsMemoryFont; + } + return Ptr; +} + +static void +SharedFace_AddRef(PSHARED_FACE Ptr) +{ + ++Ptr->RefCount; +} + +static void RemoveCachedEntry(PFONT_CACHE_ENTRY Entry) +{ + 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; + + IntLockFreeType; + + CurrentEntry = FontCacheListHead.Flink; + while (CurrentEntry != &FontCacheListHead) + { + FontEntry = CONTAINING_RECORD(CurrentEntry, FONT_CACHE_ENTRY, ListEntry); + CurrentEntry = CurrentEntry->Flink; + + if (FontEntry->Face == Face) + { + RemoveCachedEntry(FontEntry); + } + } + + IntUnLockFreeType; +} + + +static void +SharedFace_Release(PSHARED_FACE Ptr) +{ + ASSERT(Ptr->RefCount > 0); + if (Ptr->RefCount <= 0) + return; + + --Ptr->RefCount; + if (Ptr->RefCount == 0) + { + RemoveCacheEntries(Ptr->Face); + FT_Done_Face(Ptr->Face); + if (Ptr->IsMemoryFont) + ExFreePoolWithTag(Ptr->Buffer, TAG_FONT); + else + MmUnmapViewInSystemSpace(Ptr->Buffer); + ExFreePoolWithTag(Ptr, TAG_FONT); + } +} + + /* * IntLoadFontSubstList --- loads the list of font substitutes */ @@ -701,15 +745,16 @@ if (FT_IS_SFNT(Face)) pLoadFont->IsTrueType = TRUE; + pLoadFont->IsVertical = FT_HAS_VERTICAL(Face); if (!Error) - SharedFace = SharedFace_Create(Face); + SharedFace = SharedFace_Create(Face, Buffer, pFileName == NULL); if (Error || SharedFace == NULL) { 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 */ } } @@ -1011,6 +1056,7 @@ LoadFont.Characteristics = Characteristics; RtlInitUnicodeString(&LoadFont.RegValueName, NULL); LoadFont.IsTrueType = FALSE; + LoadFont.IsVertical = FALSE; LoadFont.PrivateEntry = NULL; FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1); @@ -1070,7 +1116,6 @@ 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) { @@ -1084,14 +1129,17 @@ LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM; RtlInitUnicodeString(&LoadFont.RegValueName, NULL); LoadFont.IsTrueType = FALSE; + LoadFont.IsVertical = FALSE; LoadFont.PrivateEntry = NULL; FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1); RtlFreeUnicodeString(&LoadFont.RegValueName); - *pNumAdded = FontCount; if (FontCount > 0) { + /* HACK: For firefox, check if this always applies!! */ + FontCount = LoadFont.IsVertical ? 2 : 1; + EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT); if (EntryCollection) { @@ -1104,6 +1152,7 @@ Ret = (HANDLE)EntryCollection->Handle; } } + *pNumAdded = FontCount; return Ret; } @@ -1110,6 +1159,20 @@ // 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 +1184,31 @@ 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 +1226,7 @@ if (CurrentEntry->Handle == (UINT)hMMFont) { EntryCollection = CurrentEntry; - RemoveEntryList(Entry); + UnlinkFontMemCollection(CurrentEntry); break; } @@ -1164,6 +1244,57 @@ } +VOID FASTCALL +IntGdiCleanupPrivateFontsForProcess() +{ + PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); + PLIST_ENTRY Entry; + PFONT_ENTRY_COLL_MEM EntryCollection; + + DPRINT1("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) + { + DPRINT1("IntGdiCleanupPrivateFontsForProcess ==> Deleting private mem font\n"); + 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) + { + DPRINT1("IntGdiCleanupPrivateFontsForProcess ==> Deleting private font\n"); + CleanupFontEntry(CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry)); + } + } + + } while (Entry); + + + DPRINT1("IntGdiCleanupPrivateFontsForProcess ==> Done\n"); +} + BOOL FASTCALL IntIsFontRenderingEnabled(VOID) { @@ -1737,7 +1868,7 @@ 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 +1905,8 @@ 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); @@ -2336,7 +2468,7 @@ 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) && @@ -2455,13 +2587,10 @@ 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 +4245,7 @@ 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; Index: reactos/win32ss/gdi/ntgdi/init.c =================================================================== --- reactos/win32ss/gdi/ntgdi/init.c (revision 74285) +++ reactos/win32ss/gdi/ntgdi/init.c (working copy) @@ -50,6 +50,8 @@ ASSERT(ppiCurrent); ASSERT(ppiCurrent->peProcess == Process); + IntGdiCleanupPrivateFontsForProcess(); + /* And GDI ones too */ GDI_CleanupForProcess(Process); Index: reactos/win32ss/gdi/ntgdi/text.h =================================================================== --- reactos/win32ss/gdi/ntgdi/text.h (revision 74285) +++ reactos/win32ss/gdi/ntgdi/text.h (working copy) @@ -112,6 +112,7 @@ 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);