diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index 74a7e272f6e..1abb6ae379e 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -2873,28 +2873,14 @@ BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden, /*********************************************************************** * CreateScalableFontResourceW (GDI32.@) */ -BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden, - LPCWSTR lpszResourceFile, - LPCWSTR lpszFontFile, - LPCWSTR lpszCurrentPath ) +BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file, + LPCWSTR font_file, LPCWSTR font_path ) { - HANDLE f; - FIXME("(%d,%s,%s,%s): stub\n", - fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile), - debugstr_w(lpszCurrentPath) ); + TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file), + debugstr_w(font_file), debugstr_w(font_path) ); - /* fHidden=1 - only visible for the calling app, read-only, not - * enumerated with EnumFonts/EnumFontFamilies - * lpszCurrentPath can be NULL - */ - - /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */ - if ((f = CreateFileW(lpszResourceFile, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) { - CloseHandle(f); - SetLastError(ERROR_FILE_EXISTS); - return FALSE; - } - return FALSE; /* create failed */ + return WineEngCreateScalableFontResource( hidden, resource_file, + font_file, font_path ); } /************************************************************************* diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index 44222cfa532..d61605eab03 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -278,8 +278,8 @@ typedef struct tagFace { typedef struct tagFamily { struct list entry; - const WCHAR *FamilyName; - const WCHAR *EnglishName; + WCHAR *FamilyName; + WCHAR *EnglishName; struct list faces; struct list *replacement; } Family; @@ -1662,6 +1662,20 @@ static inline void free_face( Face *face ) HeapFree( GetProcessHeap(), 0, face ); } +static inline void free_family( Family *family ) +{ + Face *face, *cursor2; + + LIST_FOR_EACH_ENTRY_SAFE( face, cursor2, &family->faces, Face, entry ) + { + list_remove( &face->entry ); + free_face( face ); + } + HeapFree( GetProcessHeap(), 0, family->FamilyName ); + HeapFree( GetProcessHeap(), 0, family->EnglishName ); + HeapFree( GetProcessHeap(), 0, family ); +} + #define ADDFONT_EXTERNAL_FONT 0x01 #define ADDFONT_FORCE_BITMAP 0x02 #define ADDFONT_ADD_TO_CACHE 0x04 @@ -2729,6 +2743,309 @@ BOOL WineEngRemoveFontResourceEx(LPCWSTR file, DWORD flags, PVOID pdv) return TRUE; } +static char *get_ttf_file_name( LPCWSTR font_file, LPCWSTR font_path ) +{ + WCHAR *fullname; + char *unix_name; + int file_len; + + if (!font_file) return NULL; + + file_len = strlenW( font_file ); + + if (font_path && font_path[0]) + { + int path_len = strlenW( font_path ); + fullname = HeapAlloc( GetProcessHeap(), 0, (file_len + path_len + 2) * sizeof(WCHAR) ); + if (!fullname) return NULL; + memcpy( fullname, font_path, path_len * sizeof(WCHAR) ); + fullname[path_len] = '\\'; + memcpy( fullname + path_len + 1, font_file, (file_len + 1) * sizeof(WCHAR) ); + } + else + { + int len = GetFullPathNameW( font_file, 0, NULL, NULL ); + if (!len) return NULL; + fullname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + if (!fullname) return NULL; + GetFullPathNameW( font_file, len, fullname, NULL ); + } + + unix_name = wine_get_unix_file_name( fullname ); + HeapFree( GetProcessHeap(), 0, fullname ); + return unix_name; +} + +#include +struct fontdir +{ + WORD num_of_resources; + WORD res_id; + WORD dfVersion; + DWORD dfSize; + CHAR dfCopyright[60]; + WORD dfType; + WORD dfPoints; + WORD dfVertRes; + WORD dfHorizRes; + WORD dfAscent; + WORD dfInternalLeading; + WORD dfExternalLeading; + BYTE dfItalic; + BYTE dfUnderline; + BYTE dfStrikeOut; + WORD dfWeight; + BYTE dfCharSet; + WORD dfPixWidth; + WORD dfPixHeight; + BYTE dfPitchAndFamily; + WORD dfAvgWidth; + WORD dfMaxWidth; + BYTE dfFirstChar; + BYTE dfLastChar; + BYTE dfDefaultChar; + BYTE dfBreakChar; + WORD dfWidthBytes; + DWORD dfDevice; + DWORD dfFace; + DWORD dfReserved; + CHAR szFaceName[LF_FACESIZE]; +}; + +#include + +static void GetEnumStructs(Face *face, LPENUMLOGFONTEXW pelf, + NEWTEXTMETRICEXW *pntm, LPDWORD ptype); + +static BOOL get_fontdir( const char *unix_name, struct fontdir *fd ) +{ + FT_Face ft_face = new_ft_face( unix_name, NULL, 0, 0, FALSE ); + Face *face; + Family *family; + WCHAR *name, *english_name; + ENUMLOGFONTEXW elf; + NEWTEXTMETRICEXW ntm; + DWORD type; + + if (!ft_face) return FALSE; + face = create_face( ft_face, 0, unix_name, NULL, 0, 0, FALSE ); + get_family_names( ft_face, &name, &english_name, FALSE ); + family = create_family( name, english_name ); + insert_face_in_family_list( face, family ); + pFT_Done_Face( ft_face ); + + GetEnumStructs( face, &elf, &ntm, &type ); + free_family( family ); + + if ((type & TRUETYPE_FONTTYPE) == 0) return FALSE; + + memset( fd, 0, sizeof(*fd) ); + + fd->num_of_resources = 1; + fd->res_id = 0; + fd->dfVersion = 0x200; + fd->dfSize = sizeof(*fd); + strcpy( fd->dfCopyright, "Wine fontdir" ); + fd->dfType = 0x4003; /* 0x0080 set if private */ + fd->dfPoints = ntm.ntmTm.ntmSizeEM; + fd->dfVertRes = 72; + fd->dfHorizRes = 72; + fd->dfAscent = ntm.ntmTm.tmAscent; + fd->dfInternalLeading = ntm.ntmTm.tmInternalLeading; + fd->dfExternalLeading = ntm.ntmTm.tmExternalLeading; + fd->dfItalic = ntm.ntmTm.tmItalic; + fd->dfUnderline = ntm.ntmTm.tmUnderlined; + fd->dfStrikeOut = ntm.ntmTm.tmStruckOut; + fd->dfWeight = ntm.ntmTm.tmWeight; + fd->dfCharSet = ntm.ntmTm.tmCharSet; + fd->dfPixWidth = 0; + fd->dfPixHeight = ntm.ntmTm.tmHeight; + fd->dfPitchAndFamily = ntm.ntmTm.tmPitchAndFamily; + fd->dfAvgWidth = ntm.ntmTm.tmAveCharWidth; + fd->dfMaxWidth = ntm.ntmTm.tmMaxCharWidth; + fd->dfFirstChar = ntm.ntmTm.tmFirstChar; + fd->dfLastChar = ntm.ntmTm.tmLastChar; + fd->dfDefaultChar = ntm.ntmTm.tmDefaultChar; + fd->dfBreakChar = ntm.ntmTm.tmBreakChar; + fd->dfWidthBytes = 0; + fd->dfDevice = 0; + fd->dfFace = FIELD_OFFSET( struct fontdir, szFaceName ); + fd->dfReserved = 0; + WideCharToMultiByte( CP_ACP, 0, elf.elfLogFont.lfFaceName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL ); + + return TRUE; +} + +#define NE_FFLAGS_LIBMODULE 0x8000 +#define NE_OSFLAGS_WINDOWS 0x02 + +static const char dos_string[0x40] = "This is a TrueType resource file"; +static const char FONTRES[] = {'F','O','N','T','R','E','S',':'}; + +#include + +struct ne_typeinfo +{ + WORD type_id; + WORD count; + DWORD res; +}; + +struct ne_nameinfo +{ + WORD off; + WORD len; + WORD flags; + WORD id; + DWORD res; +}; + +struct rsrc_tab +{ + WORD align; + struct ne_typeinfo fontdir_type; + struct ne_nameinfo fontdir_name; + struct ne_typeinfo scalable_type; + struct ne_nameinfo scalable_name; + WORD end_of_rsrc; + BYTE fontdir_res_name[8]; +}; + +#include + +static BOOL create_fot( const WCHAR *resource, const WCHAR *font_file, const struct fontdir *fontdir ) +{ + BOOL ret = FALSE; + HANDLE file; + DWORD size, written; + BYTE *ptr, *start; + BYTE import_name_len, res_name_len, non_res_name_len, font_file_len; + char *font_fileA, *last_part, *ext; + IMAGE_DOS_HEADER dos; + IMAGE_OS2_HEADER ne = + { + IMAGE_OS2_SIGNATURE, 5, 1, 0, 0, 0, NE_FFLAGS_LIBMODULE, 0, + 0, 0, 0, 0, 0, 0, + 0, sizeof(ne), sizeof(ne), 0, 0, 0, 0, + 0, 4, 2, NE_OSFLAGS_WINDOWS, 0, 0, 0, 0, 0x300 + }; + struct rsrc_tab rsrc_tab = + { + 4, + { 0x8007, 1, 0 }, + { 0, 0, 0x0c50, 0x2c, 0 }, + { 0x80cc, 1, 0 }, + { 0, 0, 0x0c50, 0x8001, 0 }, + 0, + { 7,'F','O','N','T','D','I','R'} + }; + + memset( &dos, 0, sizeof(dos) ); + dos.e_magic = IMAGE_DOS_SIGNATURE; + dos.e_lfanew = sizeof(dos) + sizeof(dos_string); + + /* import name is last part\0, resident name is last part without extension + non-resident name is "FONTRES:" + lfFaceName */ + + font_file_len = WideCharToMultiByte( CP_ACP, 0, font_file, -1, NULL, 0, NULL, NULL ); + font_fileA = HeapAlloc( GetProcessHeap(), 0, font_file_len ); + WideCharToMultiByte( CP_ACP, 0, font_file, -1, font_fileA, font_file_len, NULL, NULL ); + + last_part = strrchr( font_fileA, '\\' ); + if (last_part) last_part++; + else last_part = font_fileA; + import_name_len = strlen( last_part ) + 1; + + ext = strchr( last_part, '.' ); + if (ext) res_name_len = ext - last_part; + else res_name_len = import_name_len - 1; + + non_res_name_len = sizeof( FONTRES ) + strlen( fontdir->szFaceName ); + + ne.ne_cbnrestab = 1 + non_res_name_len + 2 + 1; /* len + string + (WORD) ord_num + 1 byte eod */ + ne.ne_restab = ne.ne_rsrctab + sizeof(rsrc_tab); + ne.ne_modtab = ne.ne_imptab = ne.ne_restab + 1 + res_name_len + 2 + 3; /* len + string + (WORD) ord_num + 3 bytes eod */ + ne.ne_enttab = ne.ne_imptab + 1 + import_name_len; /* len + string */ + ne.ne_cbenttab = 2; + ne.ne_nrestab = ne.ne_enttab + ne.ne_cbenttab + 2 + dos.e_lfanew; /* there are 2 bytes of 0 after entry tab */ + + rsrc_tab.scalable_name.off = (ne.ne_nrestab + ne.ne_cbnrestab + 0xf) >> 4; + rsrc_tab.scalable_name.len = (font_file_len + 0xf) >> 4; + rsrc_tab.fontdir_name.off = rsrc_tab.scalable_name.off + rsrc_tab.scalable_name.len; + rsrc_tab.fontdir_name.len = (fontdir->dfSize + 0xf) >> 4; + + size = (rsrc_tab.fontdir_name.off + rsrc_tab.fontdir_name.len) << 4; + start = ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); + + if (!ptr) + { + HeapFree( GetProcessHeap(), 0, font_fileA ); + return FALSE; + } + + memcpy( ptr, &dos, sizeof(dos) ); + memcpy( ptr + sizeof(dos), dos_string, sizeof(dos_string) ); + memcpy( ptr + dos.e_lfanew, &ne, sizeof(ne) ); + + ptr = start + dos.e_lfanew + ne.ne_rsrctab; + memcpy( ptr, &rsrc_tab, sizeof(rsrc_tab) ); + + ptr = start + dos.e_lfanew + ne.ne_restab; + *ptr++ = res_name_len; + memcpy( ptr, last_part, res_name_len ); + + ptr = start + dos.e_lfanew + ne.ne_imptab; + *ptr++ = import_name_len; + memcpy( ptr, last_part, import_name_len ); + + ptr = start + ne.ne_nrestab; + *ptr++ = non_res_name_len; + memcpy( ptr, FONTRES, sizeof(FONTRES) ); + memcpy( ptr + sizeof(FONTRES), fontdir->szFaceName, strlen( fontdir->szFaceName ) ); + + ptr = start + (rsrc_tab.scalable_name.off << 4); + memcpy( ptr, font_fileA, font_file_len ); + + ptr = start + (rsrc_tab.fontdir_name.off << 4); + memcpy( ptr, fontdir, fontdir->dfSize ); + + file = CreateFileW( resource, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); + if (file != INVALID_HANDLE_VALUE) + { + if (WriteFile( file, start, size, &written, NULL ) && written == size) + ret = TRUE; + CloseHandle( file ); + } + + HeapFree( GetProcessHeap(), 0, start ); + HeapFree( GetProcessHeap(), 0, font_fileA ); + + return ret; +} + +/************************************************************* + * WineEngCreateScalableFontResource + * + */ +BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource, + LPCWSTR font_file, LPCWSTR font_path ) +{ + char *unix_name = get_ttf_file_name( font_file, font_path ); + struct fontdir fontdir; + BOOL ret = FALSE; + + if (!unix_name || !get_fontdir( unix_name, &fontdir )) + SetLastError( ERROR_INVALID_PARAMETER ); + else + { + if (hidden) fontdir.dfType |= 0x80; + ret = create_fot( resource, font_file, &fontdir ); + } + + HeapFree( GetProcessHeap(), 0, unix_name ); + return ret; +} + static const struct nls_update_font_list { UINT ansi_cp, oem_cp; @@ -7478,6 +7795,13 @@ HANDLE WineEngAddFontMemResourceEx(PVOID pbFont, DWORD cbFont, PVOID pdv, DWORD return NULL; } +BOOL WineEngCreateScalableFontResource( DWORD hidden, LPCWSTR resource, + LPCWSTR font_file, LPCWSTR font_path ) +{ + FIXME("stub\n"); + return FALSE; +} + BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph) { return FALSE; diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index b624c8e3523..2053553bc36 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -289,6 +289,7 @@ typedef struct extern INT WineEngAddFontResourceEx(LPCWSTR, DWORD, PVOID) DECLSPEC_HIDDEN; extern HANDLE WineEngAddFontMemResourceEx(PVOID, DWORD, PVOID, LPDWORD) DECLSPEC_HIDDEN; +extern BOOL WineEngCreateScalableFontResource(DWORD, LPCWSTR, LPCWSTR, LPCWSTR) DECLSPEC_HIDDEN; extern BOOL WineEngDestroyFontInstance(HFONT handle) DECLSPEC_HIDDEN; extern BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph) DECLSPEC_HIDDEN; extern BOOL WineEngInit(void) DECLSPEC_HIDDEN; diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index d104452e3ef..38a8544d768 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -3989,13 +3989,11 @@ static void test_CreateScalableFontResource(void) SetLastError(0xdeadbeef); ret = CreateScalableFontResource(0, fot_name, "random file name", tmp_path); ok(!ret, "CreateScalableFontResource() should fail\n"); -todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError()); SetLastError(0xdeadbeef); ret = CreateScalableFontResource(0, fot_name, NULL, ttf_name); ok(!ret, "CreateScalableFontResource() should fail\n"); -todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "not expected error %d\n", GetLastError()); ret = DeleteFile(fot_name);