From 8c1a0961ae7d09e1aed9252e7ed7be2a7d7c3ec4 Mon Sep 17 00:00:00 2001 From: Mikolaj Zalewski Date: Thu, 13 Sep 2007 10:42:55 -0700 Subject: [PATCH] gdi32: implement AddFontMemResourceEx (based on a patch of Byeong-Sik Jeon, helps with bug #5865) --- dlls/gdi32/font.c | 3 - dlls/gdi32/freetype.c | 135 +++++++++++++++++++++++++++++++++++++--------- dlls/gdi32/gdi_private.h | 1 include/wingdi.h | 1 4 files changed, 111 insertions(+), 29 deletions(-) diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index c516736..01182fa 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -3214,8 +3214,7 @@ BOOL WINAPI RemoveFontResourceW( LPCWSTR */ HANDLE WINAPI AddFontMemResourceEx( PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts) { - FIXME("(%p,%08x,%p,%p): stub\n", pbFont, cbFont, pdv, pcFonts); - return NULL; + return WineEngAddFontMemResourceEx(pbFont, cbFont, pdv, pcFonts); } /*********************************************************************** diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 9b83c78..da888c9 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -236,6 +236,8 @@ typedef struct tagFace { struct list entry; WCHAR *StyleName; char *file; + void *font_data_ptr; + DWORD font_data_size; FT_Long face_index; BOOL Italic; BOOL Bold; @@ -708,6 +710,8 @@ static Face *find_face_from_filename(con continue; LIST_FOR_EACH_ENTRY(face, &family->faces, Face, entry) { + if (!face->file) + continue; file = strrchr(face->file, '/'); if(!file) file = face->file; @@ -930,7 +934,7 @@ static WCHAR *get_familyname(FT_Face ft_ #define ADDFONT_EXTERNAL_FONT 0x01 #define ADDFONT_FORCE_BITMAP 0x02 -static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags) +static INT AddFontToList(const char *file, void *font_data_ptr, DWORD font_data_size, char *fake_family, const WCHAR *target_family, DWORD flags) { FT_Face ft_face; TT_OS2 *pOS2; @@ -948,8 +952,11 @@ #endif int i, bitmap_num, internal_leading; FONTSIGNATURE fs; + /* we always load external fonts from files - otherwise we would get a crash in update_reg_entries */ + assert(file || !(flags & ADDFONT_EXTERNAL_FONT)); + #ifdef HAVE_CARBON_CARBON_H - if(!fake_family) + if(file && !fake_family) { char **mac_list = expand_mac_font(file); if(mac_list) @@ -972,21 +979,30 @@ #endif /* HAVE_CARBON_CARBON_H */ do { char *family_name = fake_family; - TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index); - if((err = pFT_New_Face(library, file, face_index, &ft_face)) != 0) { - WARN("Unable to load font file %s err = %x\n", debugstr_a(file), err); + if (file) + { + TRACE("Loading font file %s index %ld\n", debugstr_a(file), face_index); + err = pFT_New_Face(library, file, face_index, &ft_face); + } else + { + TRACE("Loading font from ptr %p size %d, index %ld\n", font_data_ptr, font_data_size, face_index); + err = pFT_New_Memory_Face(library, font_data_ptr, font_data_size, face_index, &ft_face); + } + + if(err != 0) { + WARN("Unable to load font %s/%p err = %x\n", debugstr_a(file), font_data_ptr, err); return 0; } if(!FT_IS_SFNT(ft_face) && (FT_IS_SCALABLE(ft_face) || !(flags & ADDFONT_FORCE_BITMAP))) { /* for now we'll accept TT/OT or bitmap fonts*/ - WARN("Ignoring font %s\n", debugstr_a(file)); + WARN("Ignoring font %s/%p\n", debugstr_a(file), font_data_ptr); pFT_Done_Face(ft_face); return 0; } /* There are too many bugs in FreeType < 2.1.9 for bitmap font support */ if(!FT_IS_SCALABLE(ft_face) && FT_SimpleVersion < ((2 << 16) | (1 << 8) | (9 << 0))) { - WARN("FreeType version < 2.1.9, skipping bitmap font %s\n", debugstr_a(file)); + WARN("FreeType version < 2.1.9, skipping bitmap font %s/%p\n", debugstr_a(file), font_data_ptr); pFT_Done_Face(ft_face); return 0; } @@ -994,14 +1010,14 @@ #endif /* HAVE_CARBON_CARBON_H */ if(FT_IS_SFNT(ft_face) && (!pFT_Get_Sfnt_Table(ft_face, ft_sfnt_os2) || !pFT_Get_Sfnt_Table(ft_face, ft_sfnt_hhea) || !(pHeader = pFT_Get_Sfnt_Table(ft_face, ft_sfnt_head)))) { - TRACE("Font file %s lacks either an OS2, HHEA or HEAD table.\n" - "Skipping this font.\n", debugstr_a(file)); + TRACE("Font %s/%p lacks either an OS2, HHEA or HEAD table.\n" + "Skipping this font.\n", debugstr_a(file), font_data_ptr); pFT_Done_Face(ft_face); return 0; } if(!ft_face->family_name || !ft_face->style_name) { - TRACE("Font file %s lacks either a family or style name\n", debugstr_a(file)); + TRACE("Font %s/%p lacks either a family or style name\n", debugstr_a(file), font_data_ptr); pFT_Done_Face(ft_face); return 0; } @@ -1137,8 +1153,18 @@ #endif face = HeapAlloc(GetProcessHeap(), 0, sizeof(*face)); list_add_tail(&family->faces, &face->entry); face->StyleName = StyleW; - face->file = HeapAlloc(GetProcessHeap(),0,strlen(file)+1); - strcpy(face->file, file); + if (file) + { + face->file = strdupA(file); + face->font_data_ptr = NULL; + face->font_data_size = 0; + } + else + { + face->file = NULL; + face->font_data_ptr = font_data_ptr; + face->font_data_size = font_data_size; + } face->face_index = face_index; face->Italic = (ft_face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0; face->Bold = (ft_face->style_flags & FT_STYLE_FLAG_BOLD) ? 1 : 0; @@ -1198,6 +1224,11 @@ #endif return num_faces; } +static INT AddFontFileToList(const char *file, char *fake_family, const WCHAR *target_family, DWORD flags) +{ + return AddFontToList(file, NULL, 0, fake_family, target_family, flags); +} + static void DumpFontList(void) { Family *family; @@ -1269,7 +1300,7 @@ static void LoadReplaceList(void) TRACE("mapping %s %s to %s\n", debugstr_w(family->FamilyName), debugstr_w(face->StyleName), familyA); /* Now add a new entry with the new family name */ - AddFontFileToList(face->file, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0)); + AddFontToList(face->file, face->font_data_ptr, face->font_data_size, familyA, family->FamilyName, ADDFONT_FORCE_BITMAP | (face->external ? ADDFONT_EXTERNAL_FONT : 0)); } break; } @@ -1713,6 +1744,38 @@ INT WineEngAddFontResourceEx(LPCWSTR fil } /************************************************************* + * WineEngAddFontMemResourceEx + * + */ +HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts) +{ + if (ft_handle) /* do it only if we have freetype up and running */ + { + PVOID pFontCopy = HeapAlloc(GetProcessHeap(), 0, cbFont); + + TRACE("Copying %d bytes of data from %p to %p\n", cbFont, pbFont, pFontCopy); + memcpy(pFontCopy, pbFont, cbFont); + + *pcFonts = AddFontToList(NULL, pFontCopy, cbFont, NULL, NULL, ADDFONT_FORCE_BITMAP); + + if (*pcFonts == 0) + { + TRACE("AddFontToList failed\n"); + HeapFree(GetProcessHeap(), 0, pFontCopy); + return NULL; + } + /* FIXME: is the handle only for use in RemoveFontMemResourceEx or should it be a true handle? + * For now return something unique but quite random + */ + TRACE("Returning handle %lx\n", ((INT_PTR)pFontCopy)^0x87654321); + return (HANDLE)(((INT_PTR)pFontCopy)^0x87654321); + } + + *pcFonts = 0; + return 0; +} + +/************************************************************* * WineEngRemoveFontResourceEx * */ @@ -2179,7 +2242,7 @@ static LONG calc_ppem_for_height(FT_Face return ppem; } -static struct font_mapping *map_font( const char *name ) +static struct font_mapping *map_font_file( const char *name ) { struct font_mapping *mapping; struct stat st; @@ -2220,7 +2283,7 @@ error: return NULL; } -static void unmap_font( struct font_mapping *mapping ) +static void unmap_font_file( struct font_mapping *mapping ) { if (!--mapping->refcount) { @@ -2232,20 +2295,32 @@ static void unmap_font( struct font_mapp static LONG load_VDMX(GdiFont*, LONG); -static FT_Face OpenFontFile(GdiFont *font, char *file, FT_Long face_index, LONG width, LONG height) +static FT_Face OpenFontFace(GdiFont *font, Face *face, LONG width, LONG height) { FT_Error err; FT_Face ft_face; + void *data_ptr; + DWORD data_size; - TRACE("%s, %ld, %d x %d\n", debugstr_a(file), face_index, width, height); + TRACE("%s/%p, %ld, %d x %d\n", debugstr_a(face->file), face->font_data_ptr, face->face_index, width, height); - if (!(font->mapping = map_font( file ))) + if (face->file) { - WARN("failed to map %s\n", debugstr_a(file)); - return 0; + if (!(font->mapping = map_font_file( face->file ))) + { + WARN("failed to map %s\n", debugstr_a(face->file)); + return 0; + } + data_ptr = font->mapping->data; + data_size = font->mapping->size; + } + else + { + data_ptr = face->font_data_ptr; + data_size = face->font_data_size; } - err = pFT_New_Memory_Face(library, font->mapping->data, font->mapping->size, face_index, &ft_face); + err = pFT_New_Memory_Face(library, data_ptr, data_size, face->face_index, &ft_face); if(err) { ERR("FT_New_Face rets %d\n", err); return 0; @@ -2343,7 +2418,7 @@ static void free_font(GdiFont *font) } if (font->ft_face) pFT_Done_Face(font->ft_face); - if (font->mapping) unmap_font( font->mapping ); + if (font->mapping) unmap_font_file( font->mapping ); HeapFree(GetProcessHeap(), 0, font->kern_pairs); HeapFree(GetProcessHeap(), 0, font->potm); HeapFree(GetProcessHeap(), 0, font->name); @@ -2892,14 +2967,14 @@ found: else ret->charset = get_nearest_charset(face, &ret->codepage); - TRACE("Chosen: %s %s (%s:%ld)\n", debugstr_w(family->FamilyName), - debugstr_w(face->StyleName), face->file, face->face_index); + TRACE("Chosen: %s %s (%s/%p:%ld)\n", debugstr_w(family->FamilyName), + debugstr_w(face->StyleName), face->file, face->font_data_ptr, face->face_index); if(!face->scalable) { width = face->size.x_ppem >> 6; height = face->size.y_ppem >> 6; } - ret->ft_face = OpenFontFile(ret, face->file, face->face_index, width, height); + ret->ft_face = OpenFontFace(ret, face, width, height); if (!ret->ft_face) { @@ -3034,7 +3109,7 @@ static void GetEnumStructs(Face *face, L width = face->size.x_ppem >> 6; } - if (!(font->ft_face = OpenFontFile(font, face->file, face->face_index, width, height))) + if (!(font->ft_face = OpenFontFace(font, face, width, height))) { free_font(font); return; @@ -4133,7 +4208,7 @@ static BOOL load_child_font(GdiFont *fon { HFONTLIST *hfontlist; child->font = alloc_font(); - child->font->ft_face = OpenFontFile(child->font, child->face->file, child->face->face_index, 0, -font->ppem); + child->font->ft_face = OpenFontFace(child->font, child->face, 0, -font->ppem); if(!child->font->ft_face) { free_font(child->font); @@ -4950,6 +5025,12 @@ INT WineEngRemoveFontResourceEx(LPCWSTR return TRUE; } +HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD *pcFonts) +{ + FIXME(":stub\n"); + return NULL; +} + UINT WineEngGetTextCharsetInfo(GdiFont *font, LPFONTSIGNATURE fs, DWORD flags) { FIXME(":stub\n"); diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 74cca26..c665373 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -421,6 +421,7 @@ extern HENHMETAFILE EMF_Create_HENHMETAF /* freetype.c */ extern INT WineEngAddFontResourceEx(LPCWSTR, DWORD, PVOID); +extern HANDLE WineEngAddFontMemResourceEx(PVOID, DWORD, PVOID, LPDWORD); extern GdiFont* WineEngCreateFontInstance(DC*, HFONT); extern BOOL WineEngDestroyFontInstance(HFONT handle); extern DWORD WineEngEnumFonts(LPLOGFONTW, FONTENUMPROCW, LPARAM); diff --git a/include/wingdi.h b/include/wingdi.h index 77d8d92..7d8c4a1 100644 --- a/include/wingdi.h +++ b/include/wingdi.h @@ -3274,6 +3274,7 @@ #define AddFontResource WINELIB_NAME INT WINAPI AddFontResourceExA(LPCSTR, DWORD, PVOID); INT WINAPI AddFontResourceExW(LPCWSTR, DWORD, PVOID); #define AddFontResourceEx WINELIB_NAME_AW(AddFontResourceEx) +HANDLE WINAPI AddFontMemResourceEx(PVOID, DWORD, PVOID, DWORD *); BOOL WINAPI AlphaBlend(HDC,int,int,int,int,HDC,int,int,int,int,BLENDFUNCTION); BOOL WINAPI AngleArc(HDC, INT, INT, DWORD, FLOAT, FLOAT); BOOL WINAPI AnimatePalette(HPALETTE,UINT,UINT,const PALETTEENTRY*); -- 1.4.1