Commit 105caa28 authored by Huw Davies's avatar Huw Davies Committed by Alexandre Julliard

gdi32: Implement CreateScalableFontResource.

Based on patches by Jeremy White and Dmitry Timoshkov.
parent 7ac623f3
......@@ -2873,28 +2873,14 @@ BOOL WINAPI CreateScalableFontResourceA( DWORD fHidden,
/***********************************************************************
* CreateScalableFontResourceW (GDI32.@)
*/
BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
LPCWSTR lpszResourceFile,
LPCWSTR lpszFontFile,
LPCWSTR lpszCurrentPath )
{
HANDLE f;
FIXME("(%d,%s,%s,%s): stub\n",
fHidden, debugstr_w(lpszResourceFile), debugstr_w(lpszFontFile),
debugstr_w(lpszCurrentPath) );
/* fHidden=1 - only visible for the calling app, read-only, not
* enumerated with EnumFonts/EnumFontFamilies
* lpszCurrentPath can be NULL
*/
BOOL WINAPI CreateScalableFontResourceW( DWORD hidden, LPCWSTR resource_file,
LPCWSTR font_file, LPCWSTR font_path )
{
TRACE("(%d, %s, %s, %s)\n", hidden, debugstr_w(resource_file),
debugstr_w(font_file), debugstr_w(font_path) );
/* 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 );
}
/*************************************************************************
......
......@@ -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 <pshpack1.h>
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 <poppack.h>
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 <pshpack2.h>
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 <poppack.h>
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;
......
......@@ -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;
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment