Index: reactos/win32ss/gdi/eng/stubs.c =================================================================== --- reactos/win32ss/gdi/eng/stubs.c (revision 74270) +++ reactos/win32ss/gdi/eng/stubs.c (working copy) @@ -838,22 +838,6 @@ /* * @unimplemented */ -HANDLE -APIENTRY -NtGdiAddFontMemResourceEx( - IN PVOID pvBuffer, - IN DWORD cjBuffer, - IN DESIGNVECTOR *pdv, - IN ULONG cjDV, - OUT DWORD *pNumFonts) -{ - UNIMPLEMENTED; - return NULL; -} - -/* - * @unimplemented - */ BOOL APIENTRY NtGdiRemoveMergeFont( @@ -1331,18 +1315,6 @@ */ BOOL APIENTRY -NtGdiRemoveFontMemResourceEx( - IN HANDLE hMMFont) -{ - UNIMPLEMENTED; - return FALSE; -} - -/* - * @unimplemented - */ -BOOL -APIENTRY NtGdiRemoveFontResourceW( IN WCHAR *pwszFiles, IN ULONG cwc, Index: reactos/win32ss/gdi/ntgdi/font.c =================================================================== --- reactos/win32ss/gdi/ntgdi/font.c (revision 74270) +++ reactos/win32ss/gdi/ntgdi/font.c (working copy) @@ -478,6 +478,71 @@ return Ret; } +HANDLE +APIENTRY +NtGdiAddFontMemResourceEx( + IN PVOID pvBuffer, + IN DWORD cjBuffer, + IN DESIGNVECTOR *pdv, + IN ULONG cjDV, + OUT DWORD *pNumFonts) +{ + _SEH2_VOLATILE PVOID Buffer = NULL; + HANDLE Ret; + DWORD NumFonts = 0; + + DPRINT("NtGdiAddFontMemResourceEx\n"); + DBG_UNREFERENCED_PARAMETER(pdv); + DBG_UNREFERENCED_PARAMETER(cjDV); + + if (!pvBuffer || !cjBuffer) + return NULL; + + _SEH2_TRY + { + ProbeForRead(pvBuffer, cjBuffer, sizeof(BYTE)); + Buffer = ExAllocatePoolWithQuotaTag(PagedPool, cjBuffer, TAG_FONT); + RtlCopyMemory(Buffer, pvBuffer, cjBuffer); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + if (Buffer != NULL) + { + ExFreePoolWithTag(Buffer, TAG_FONT); + } + _SEH2_YIELD(return NULL); + } + _SEH2_END; + + Ret = IntGdiAddFontMemResource(Buffer, cjBuffer, &NumFonts); + ExFreePoolWithTag(Buffer, TAG_FONT); + + _SEH2_TRY + { + ProbeForWrite(pNumFonts, sizeof(NumFonts), 1); + *pNumFonts = NumFonts; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Leak it? */ + _SEH2_YIELD(return NULL); + } + _SEH2_END; + + + return Ret; +} + + +BOOL +APIENTRY +NtGdiRemoveFontMemResourceEx( + IN HANDLE hMMFont) +{ + return IntGdiRemoveFontMemResource(hMMFont); +} + + /* * @unimplemented */ Index: reactos/win32ss/gdi/ntgdi/font.h =================================================================== --- reactos/win32ss/gdi/ntgdi/font.h (nonexistent) +++ reactos/win32ss/gdi/ntgdi/font.h (working copy) @@ -0,0 +1,64 @@ +#pragma once + + +typedef struct _FONT_ENTRY +{ + LIST_ENTRY ListEntry; + FONTGDI *Font; + UNICODE_STRING FaceName; + BYTE NotEnum; +} FONT_ENTRY, *PFONT_ENTRY; + +typedef struct _FONT_ENTRY_MEM +{ + LIST_ENTRY ListEntry; + FONT_ENTRY *Entry; +} FONT_ENTRY_MEM, *PFONT_ENTRY_MEM; + +typedef struct _FONT_ENTRY_COLL_MEM +{ + LIST_ENTRY ListEntry; + UINT Handle; + FONT_ENTRY_MEM *Entry; +} FONT_ENTRY_COLL_MEM, *PFONT_ENTRY_COLL_MEM; + +typedef struct _FONT_CACHE_ENTRY +{ + LIST_ENTRY ListEntry; + int GlyphIndex; + FT_Face Face; + FT_BitmapGlyph BitmapGlyph; + int Height; + MATRIX mxWorldToDevice; +} FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY; + + +/* + * FONTSUBST_... --- constants for font substitutes + */ +#define FONTSUBST_FROM 0 +#define FONTSUBST_TO 1 +#define FONTSUBST_FROM_AND_TO 2 + +/* + * FONTSUBST_ENTRY --- font substitute entry + */ +typedef struct FONTSUBST_ENTRY +{ + LIST_ENTRY ListEntry; + UNICODE_STRING FontNames[FONTSUBST_FROM_AND_TO]; + BYTE CharSets[FONTSUBST_FROM_AND_TO]; +} FONTSUBST_ENTRY, *PFONTSUBST_ENTRY; + + +typedef struct GDI_LOAD_FONT +{ + PUNICODE_STRING pFileName; + PVOID Buffer; + ULONG BufferSize; + DWORD Characteristics; + UNICODE_STRING RegValueName; + BOOL IsTrueType; + PFONT_ENTRY_MEM PrivateEntry; +} GDI_LOAD_FONT, *PGDI_LOAD_FONT; + Index: reactos/win32ss/gdi/ntgdi/freetype.c =================================================================== --- reactos/win32ss/gdi/ntgdi/freetype.c (revision 74282) +++ reactos/win32ss/gdi/ntgdi/freetype.c (working copy) @@ -31,6 +31,7 @@ #include FT_INTERNAL_TRUETYPE_TYPES_H #include +#include "font.h" #define NDEBUG #include @@ -90,13 +91,6 @@ } } -typedef struct _FONT_ENTRY -{ - LIST_ENTRY ListEntry; - FONTGDI *Font; - UNICODE_STRING FaceName; - BYTE NotEnum; -} FONT_ENTRY, *PFONT_ENTRY; /* The FreeType library is not thread safe, so we have to serialize access to it */ @@ -120,15 +114,6 @@ #define MAX_FONT_CACHE 256 -typedef struct _FONT_CACHE_ENTRY -{ - LIST_ENTRY ListEntry; - int GlyphIndex; - FT_Face Face; - FT_BitmapGlyph BitmapGlyph; - int Height; - MATRIX mxWorldToDevice; -} FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY; static LIST_ENTRY FontCacheListHead; static UINT FontCacheNumEntries; @@ -201,23 +186,6 @@ { SYMBOL_CHARSET, CP_SYMBOL, {{0,0,0,0},{FS_SYMBOL,0}} } }; -/* - * FONTSUBST_... --- constants for font substitutes - */ -#define FONTSUBST_FROM 0 -#define FONTSUBST_TO 1 -#define FONTSUBST_FROM_AND_TO 2 - -/* - * FONTSUBST_ENTRY --- font substitute entry - */ -typedef struct FONTSUBST_ENTRY -{ - LIST_ENTRY ListEntry; - UNICODE_STRING FontNames[FONTSUBST_FROM_AND_TO]; - BYTE CharSets[FONTSUBST_FROM_AND_TO]; -} FONTSUBST_ENTRY, *PFONTSUBST_ENTRY; - /* list head */ static RTL_STATIC_LIST_HEAD(FontSubstListHead); @@ -695,16 +663,6 @@ return FW_NORMAL; } -typedef struct GDI_LOAD_FONT -{ - PUNICODE_STRING pFileName; - PVOID Buffer; - ULONG BufferSize; - DWORD Characteristics; - UNICODE_STRING RegValueName; - BOOL IsTrueType; -} GDI_LOAD_FONT, *PGDI_LOAD_FONT; - static INT FASTCALL IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont, PSHARED_FACE SharedFace, FT_Long FontIndex, INT CharSetIndex) @@ -711,6 +669,7 @@ { FT_Error Error; PFONT_ENTRY Entry; + FONT_ENTRY_MEM* PrivateEntry = NULL; FONTGDI * FontGDI; NTSTATUS Status; FT_Face Face; @@ -780,20 +739,49 @@ } /* set file name */ - FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, - pFileName->Length + sizeof(UNICODE_NULL), - GDITAG_PFF); - if (FontGDI->Filename == NULL) + if (pFileName) { - EngFreeMem(FontGDI); - SharedFace_Release(SharedFace); - ExFreePoolWithTag(Entry, TAG_FONT); - EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; /* failure */ + FontGDI->Filename = ExAllocatePoolWithTag(PagedPool, + pFileName->Length + sizeof(UNICODE_NULL), + GDITAG_PFF); + if (FontGDI->Filename == NULL) + { + EngFreeMem(FontGDI); + SharedFace_Release(SharedFace); + ExFreePoolWithTag(Entry, TAG_FONT); + EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; /* failure */ + } + RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length); + FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL; } - RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length); - FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL; + else + { + FontGDI->Filename = NULL; /* FIXME: Is this safe? */ + PrivateEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_MEM), TAG_FONT); + if (!PrivateEntry) + { + if (FontGDI->Filename) + ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); + EngFreeMem(FontGDI); + SharedFace_Release(SharedFace); + ExFreePoolWithTag(Entry, TAG_FONT); + return 0; + } + + PrivateEntry->Entry = Entry; + if (pLoadFont->PrivateEntry) + { + InsertTailList(&pLoadFont->PrivateEntry->ListEntry, &PrivateEntry->ListEntry); + } + else + { + InitializeListHead(&PrivateEntry->ListEntry); + pLoadFont->PrivateEntry = PrivateEntry; + } + } + /* set face */ FontGDI->SharedFace = SharedFace; FontGDI->CharSet = ANSI_CHARSET; @@ -806,7 +794,20 @@ Status = RtlAnsiStringToUnicodeString(&Entry->FaceName, &AnsiFaceName, TRUE); if (!NT_SUCCESS(Status)) { - ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); + if (PrivateEntry) + { + if (pLoadFont->PrivateEntry == PrivateEntry) + { + pLoadFont->PrivateEntry = NULL; + } + else + { + RemoveEntryList(&PrivateEntry->ListEntry); + } + ExFreePoolWithTag(PrivateEntry, TAG_FONT); + } + if (FontGDI->Filename) + ExFreePoolWithTag(FontGDI->Filename, GDITAG_PFF); EngFreeMem(FontGDI); SharedFace_Release(SharedFace); ExFreePoolWithTag(Entry, TAG_FONT); @@ -1010,6 +1011,7 @@ LoadFont.Characteristics = Characteristics; RtlInitUnicodeString(&LoadFont.RegValueName, NULL); LoadFont.IsTrueType = FALSE; + LoadFont.PrivateEntry = NULL; FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1); ObDereferenceObject(SectionObject); @@ -1060,9 +1062,101 @@ return FontCount; } +HANDLE FASTCALL +IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded) +{ + GDI_LOAD_FONT LoadFont; + FONT_ENTRY_COLL_MEM* EntryCollection; + INT FontCount; + HANDLE Ret = 0; + + LoadFont.pFileName = NULL; + LoadFont.Buffer = Buffer; + LoadFont.BufferSize = dwSize; + LoadFont.Characteristics = FR_PRIVATE | FR_NOT_ENUM; + RtlInitUnicodeString(&LoadFont.RegValueName, NULL); + LoadFont.IsTrueType = FALSE; + LoadFont.PrivateEntry = NULL; + FontCount = IntGdiLoadFontsFromMemory(&LoadFont, NULL, -1, -1); + + RtlFreeUnicodeString(&LoadFont.RegValueName); + + *pNumAdded = FontCount; + if (FontCount > 0) + { + EntryCollection = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_ENTRY_COLL_MEM), TAG_FONT); + if (EntryCollection) + { + PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); + EntryCollection->Entry = LoadFont.PrivateEntry; + IntLockProcessPrivateFonts(Win32Process); + EntryCollection->Handle = ++Win32Process->PrivateMemFontHandleCount; + InsertTailList(&Win32Process->PrivateMemFontListHead, &EntryCollection->ListEntry); + IntUnLockProcessPrivateFonts(Win32Process); + Ret = (HANDLE)EntryCollection->Handle; + } + } + + return Ret; +} + // FIXME: Add RemoveFontResource +VOID FASTCALL +IntGdiCleanupMemEntry(PFONT_ENTRY_MEM Head) +{ + PLIST_ENTRY Entry; + PFONT_ENTRY_MEM FontEntry; + + while (!IsListEmpty(&Head->ListEntry)) + { + Entry = RemoveHeadList(&Head->ListEntry); + FontEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_MEM, ListEntry); + + // Delete FontEntry->Entry (FONT_ENTRY*) + ExFreePoolWithTag(FontEntry, TAG_FONT); + } + + // Delete Head->Entry (FONT_ENTRY*) + ExFreePoolWithTag(Head, TAG_FONT); +} + BOOL FASTCALL +IntGdiRemoveFontMemResource(HANDLE hMMFont) +{ + PLIST_ENTRY Entry; + PFONT_ENTRY_COLL_MEM CurrentEntry; + PFONT_ENTRY_COLL_MEM EntryCollection = NULL; + PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process(); + + IntLockProcessPrivateFonts(Win32Process); + Entry = Win32Process->PrivateMemFontListHead.Flink; + while (Entry != &Win32Process->PrivateMemFontListHead) + { + CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY_COLL_MEM, ListEntry); + + if (CurrentEntry->Handle == (UINT)hMMFont) + { + EntryCollection = CurrentEntry; + RemoveEntryList(Entry); + break; + } + + Entry = Entry->Flink; + } + IntUnLockProcessPrivateFonts(Win32Process); + + if (EntryCollection) + { + IntGdiCleanupMemEntry(EntryCollection->Entry); + ExFreePoolWithTag(EntryCollection, TAG_FONT); + return TRUE; + } + return FALSE; +} + + +BOOL FASTCALL IntIsFontRenderingEnabled(VOID) { BOOL Ret = RenderingEnabled; Index: reactos/win32ss/gdi/ntgdi/init.c =================================================================== --- reactos/win32ss/gdi/ntgdi/init.c (revision 74270) +++ reactos/win32ss/gdi/ntgdi/init.c (working copy) @@ -21,6 +21,8 @@ ASSERT(ppiCurrent); InitializeListHead(&ppiCurrent->PrivateFontListHead); + InitializeListHead(&ppiCurrent->PrivateMemFontListHead); + ppiCurrent->PrivateMemFontHandleCount = 0; ExInitializeFastMutex(&ppiCurrent->PrivateFontListLock); InitializeListHead(&ppiCurrent->GDIBrushAttrFreeList); Index: reactos/win32ss/gdi/ntgdi/text.h =================================================================== --- reactos/win32ss/gdi/ntgdi/text.h (revision 74270) +++ reactos/win32ss/gdi/ntgdi/text.h (working copy) @@ -113,6 +113,8 @@ ULONG FASTCALL FontGetObject(PTEXTOBJ TextObj, ULONG Count, PVOID Buffer); VOID FASTCALL IntLoadSystemFonts(VOID); INT FASTCALL IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics); +HANDLE FASTCALL IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded); +BOOL FASTCALL IntGdiRemoveFontMemResource(HANDLE hMMFont); ULONG FASTCALL ftGdiGetGlyphOutline(PDC,WCHAR,UINT,LPGLYPHMETRICS,ULONG,PVOID,LPMAT2,BOOL); INT FASTCALL IntGetOutlineTextMetrics(PFONTGDI,UINT,OUTLINETEXTMETRICW *); BOOL FASTCALL TextIntUpdateSize(PDC,PTEXTOBJ,PFONTGDI,BOOL); Index: reactos/win32ss/user/ntuser/win32.h =================================================================== --- reactos/win32ss/user/ntuser/win32.h (revision 74270) +++ reactos/win32ss/user/ntuser/win32.h (working copy) @@ -273,6 +273,9 @@ /* ReactOS */ FAST_MUTEX PrivateFontListLock; LIST_ENTRY PrivateFontListHead; + LIST_ENTRY PrivateMemFontListHead; + UINT PrivateMemFontHandleCount; + FAST_MUTEX DriverObjListLock; LIST_ENTRY DriverObjListHead; W32HEAP_USER_MAPPING HeapMappings;