[2/5] gdi32: Implement CreateScalableFontResource, based on a patch by Jeremy White. Take 3.
Dmitry Timoshkov
dmitry at codeweavers.com
Wed Nov 17 09:44:43 CST 2010
---
dlls/gdi32/font.c | 46 ++++---
dlls/gdi32/freetype.c | 330 ++++++++++++++++++++++++++++++++++++++++++++++
dlls/gdi32/gdi_private.h | 1 +
3 files changed, 358 insertions(+), 19 deletions(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index fe68893..afe89f2 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -2546,28 +2546,36 @@ 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 flags, LPCWSTR resource, LPCWSTR font, LPCWSTR path)
+{
+ static const WCHAR slashW[] = { '\\',0 };
+ WCHAR full_font_path[MAX_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);
+ TRACE("%#x,%s,%s,%s\n", flags, debugstr_w(resource), debugstr_w(font), debugstr_w(path));
+
+ if (!font)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- return FALSE; /* create failed */
+
+ if (path && path[0])
+ {
+ DWORD len;
+
+ strcpyW(full_font_path, path);
+ len = strlenW(full_font_path);
+ if (full_font_path[len - 1] != '\\' && full_font_path[len - 1] != '/')
+ strcatW(full_font_path, slashW);
+ strcatW(full_font_path, font);
+ }
+ else
+ {
+ if (!GetFullPathNameW(font, MAX_PATH, full_font_path, NULL))
+ return FALSE;
+ }
+
+ return WineEngCreateScalableFontResource(flags, resource, full_font_path);
}
/*************************************************************************
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 78387be..c952a47 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -357,6 +357,85 @@ typedef struct {
#define GM_BLOCK_SIZE 128
#define FONT_GM(font,idx) (&(font)->gm[(idx) / GM_BLOCK_SIZE][(idx) % GM_BLOCK_SIZE])
+#define NE_FFLAGS_LIBMODULE 0x8000
+
+#define NE_OSFLAGS_WINDOWS 0x02
+
+#define NE_RSCTYPE_FONTDIR 0x8007
+#define NE_RSCTYPE_FONT 0x8008
+#define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
+
+#define NE_SEGFLAGS_MOVEABLE 0x0010
+#define NE_SEGFLAGS_PRELOAD 0x0040
+
+#include "pshpack1.h"
+
+static const struct
+{
+ WORD e_magic; /* 00: MZ Header signature */
+ WORD unused[29];
+ DWORD e_lfanew; /* 3c: Offset to extended header */
+ char info[0x40];
+} dos =
+{
+ IMAGE_DOS_SIGNATURE, { 0 }, sizeof(dos),
+ "This is a TrueType font resource"
+};
+
+typedef struct
+{
+ WORD offset;
+ WORD length;
+ WORD flags;
+ WORD id;
+ WORD handle;
+ WORD usage;
+} NE_NAMEINFO;
+
+typedef struct
+{
+ WORD type_id;
+ WORD count;
+ DWORD resloader;
+} NE_TYPEINFO;
+
+struct fontdir
+{
+ SHORT number_of_resources;
+ SHORT resource_id;
+ SHORT dfVersion;
+ LONG dfSize;
+ char dfCopyright[60];
+ INT16 dfType;
+ INT16 dfPoints;
+ INT16 dfVertRes;
+ INT16 dfHorizRes;
+ INT16 dfAscent;
+ INT16 dfInternalLeading;
+ INT16 dfExternalLeading;
+ BYTE dfItalic;
+ BYTE dfUnderline;
+ BYTE dfStrikeOut;
+ INT16 dfWeight;
+ BYTE dfCharSet;
+ INT16 dfPixWidth;
+ INT16 dfPixHeight;
+ BYTE dfPitchAndFamily;
+ INT16 dfAvgWidth;
+ INT16 dfMaxWidth;
+ BYTE dfFirstChar;
+ BYTE dfLastChar;
+ BYTE dfDefaultChar;
+ BYTE dfBreakChar;
+ INT16 dfWidthBytes;
+ LONG dfDevice;
+ LONG dfFace;
+ LONG dfReserved;
+ char szFaceName[LF_FACESIZE];
+};
+
+#include "poppack.h"
+
static struct list gdi_font_list = LIST_INIT(gdi_font_list);
static struct list unused_gdi_font_list = LIST_INIT(unused_gdi_font_list);
#define UNUSED_CACHE_SIZE 10
@@ -6675,6 +6754,251 @@ DWORD WineEngGetKerningPairs(GdiFont *font, DWORD cPairs, KERNINGPAIR *kern_pair
return font->total_kern_pairs;
}
+static void ntm_to_fontdir(const Face *face, const NEWTEXTMETRICW *ntm, struct fontdir *fd)
+{
+ fd->number_of_resources = 1;
+ fd->resource_id = 0;
+ fd->dfVersion = 0x200,
+ fd->dfSize = 0; /* will be calculated later */
+ memset(fd->dfCopyright, 0, sizeof(fd->dfCopyright));
+ strcpy(fd->dfCopyright, "This is a TrueType font resource");
+ fd->dfType = 0;
+ fd->dfPoints = ntm->ntmSizeEM;
+ fd->dfVertRes = 72;
+ fd->dfHorizRes = 72;
+ fd->dfAscent = ntm->tmAscent;
+ fd->dfInternalLeading = ntm->tmInternalLeading;
+ fd->dfExternalLeading = ntm->tmExternalLeading;
+ fd->dfItalic = ntm->tmItalic;
+ fd->dfUnderline = ntm->tmUnderlined;
+ fd->dfStrikeOut = ntm->tmStruckOut;
+ fd->dfWeight = ntm->tmWeight;
+ fd->dfCharSet = ntm->tmCharSet;
+ fd->dfPixWidth = 0;
+ fd->dfPixHeight = ntm->tmHeight;
+ fd->dfPitchAndFamily = ntm->tmPitchAndFamily;
+ fd->dfAvgWidth = ntm->tmAveCharWidth;
+ fd->dfMaxWidth = ntm->tmMaxCharWidth;
+ fd->dfFirstChar = ntm->tmFirstChar;
+ fd->dfLastChar = ntm->tmLastChar;
+ fd->dfDefaultChar = ntm->tmDefaultChar;
+ fd->dfBreakChar = ntm->tmBreakChar;
+ fd->dfWidthBytes = 0;
+ fd->dfDevice = 0;
+ fd->dfFace = FIELD_OFFSET(struct fontdir, szFaceName);
+ fd->dfReserved = 0;
+ WideCharToMultiByte(CP_ACP, 0, face->family->FamilyName, -1, fd->szFaceName, LF_FACESIZE, NULL, NULL);
+ fd->szFaceName[LF_FACESIZE - 1] = 0;
+
+ fd->dfSize = FIELD_OFFSET(struct fontdir, szFaceName) + strlen(fd->szFaceName) + 1;
+}
+
+static BOOL write_file(HANDLE hfile, const struct fontdir *fd, LPCWSTR ttf_file_name)
+{
+ int resource_table_len, non_resident_name_len, resident_name_len;
+ unsigned short resource_table_off, resident_name_off, module_ref_off, non_resident_name_off, fontdir_off, fontpath_off;
+ char resident_name[9];
+ char non_resident_name[LF_FACESIZE + sizeof("FONTRES:")];
+ IMAGE_OS2_HEADER ne;
+ NE_TYPEINFO rc_type;
+ NE_NAMEINFO rc_name;
+ BYTE str_len;
+ DWORD dummy;
+ DWORD file_len;
+ BOOL ret;
+ char *buf, *p, *file_part;
+ char ttf_file_nameA[MAX_PATH];
+
+ WideCharToMultiByte(CP_ACP, 0, ttf_file_name, -1, ttf_file_nameA, MAX_PATH, NULL, NULL);
+
+ file_part = ttf_file_nameA;
+ if ((p = strrchr(file_part, '\\'))) file_part = p + 1;
+ if ((p = strrchr(file_part, '/'))) file_part = p + 1;
+ lstrcpynA(resident_name, file_part, sizeof(resident_name));
+
+ lstrcpyA(non_resident_name, "FONTRES:");
+ lstrcatA(non_resident_name, fd->szFaceName);
+ non_resident_name_len = strlen(non_resident_name) + 4;
+
+ /* shift count + fontdir entry + num_files of font + nul type + \007FONTDIR */
+ resource_table_len = sizeof(WORD) + sizeof("FONTDIR") +
+ sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) +
+ sizeof(NE_TYPEINFO) + sizeof(NE_NAMEINFO) + sizeof(NE_TYPEINFO);
+ resource_table_off = sizeof(ne);
+ resident_name_off = resource_table_off + resource_table_len;
+ resident_name_len = strlen(resident_name) + 4;
+ module_ref_off = resident_name_off + resident_name_len;
+ non_resident_name_off = sizeof(dos) + module_ref_off + sizeof(WORD);
+ fontdir_off = (non_resident_name_off + non_resident_name_len + 0x0f) & ~0x0f;
+ fontpath_off = (fontdir_off + fd->dfSize + 0x0f) & ~0x0f;
+
+ file_len = fontpath_off + strlen(ttf_file_nameA) + 1;
+ file_len = (file_len + 0x0f) & ~0x0f;
+
+ buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, file_len + 16);
+ if (!buf) return FALSE;
+
+ /* align the starting write address to make padding easier */
+ p = (char *)(((DWORD_PTR)buf + 0x0f) & ~0x0f);
+
+ memset(&ne, 0, sizeof(ne));
+ ne.ne_magic = IMAGE_OS2_SIGNATURE;
+ ne.ne_ver = 5;
+ ne.ne_rev = 1;
+ ne.ne_flags = NE_FFLAGS_LIBMODULE;
+ ne.ne_cbnrestab = non_resident_name_len;
+ ne.ne_segtab = sizeof(ne);
+ ne.ne_rsrctab = sizeof(ne);
+ ne.ne_restab = resident_name_off;
+ ne.ne_modtab = module_ref_off;
+ ne.ne_imptab = module_ref_off;
+ ne.ne_enttab = ne.ne_modtab;
+ ne.ne_nrestab = non_resident_name_off;
+ ne.ne_align = 4;
+ ne.ne_exetyp = NE_OSFLAGS_WINDOWS;
+ ne.ne_expver = 0x300;
+
+ memcpy(p, &dos, sizeof(dos));
+ p += sizeof(dos);
+ memcpy(p, &ne, sizeof(ne));
+ p += sizeof(ne);
+
+ /* resource table */
+ *(WORD *)p = 4; /* align */
+ p += sizeof(WORD);
+
+ rc_type.type_id = NE_RSCTYPE_FONTDIR;
+ rc_type.count = 1;
+ rc_type.resloader = 0;
+ memcpy(p, &rc_type, sizeof(rc_type));
+ p += sizeof(rc_type);
+
+ rc_name.offset = fontdir_off >> 4;
+ rc_name.length = (fd->dfSize + 0x0f) >> 4;
+ rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD;
+ rc_name.id = resident_name_off - sizeof("FONTDIR") - ne.ne_rsrctab;
+ rc_name.handle = 0;
+ rc_name.usage = 0;
+ memcpy(p, &rc_name, sizeof(rc_name));
+ p += sizeof(rc_name);
+
+ rc_type.type_id = NE_RSCTYPE_SCALABLE_FONTPATH;
+ rc_type.count = 1;
+ rc_type.resloader = 0;
+ memcpy(p, &rc_type, sizeof(rc_type));
+ p += sizeof(rc_type);
+
+ rc_name.offset = fontpath_off >> 4;
+ rc_name.length = (strlen(ttf_file_nameA) + 0x0f) >> 4;
+ rc_name.flags = NE_SEGFLAGS_MOVEABLE | NE_SEGFLAGS_PRELOAD;
+ rc_name.id = 0x8001;
+ rc_name.handle = 0;
+ rc_name.usage = 0;
+ memcpy(p, &rc_name, sizeof(rc_name));
+ p += sizeof(rc_name);
+
+ /* empty type info */
+ p += sizeof(rc_type);
+
+ memcpy(p, "\7FONTDIR", 8);
+ p += 8;
+ str_len = strlen(resident_name);
+ *p++ = str_len;
+ memcpy(p, resident_name, str_len);
+ p += str_len + 5;
+
+ str_len = strlen(non_resident_name);
+ *p++ = str_len;
+ memcpy(p, non_resident_name, str_len);
+ p += str_len + 1;
+
+ /* empty ne_modtab and ne_imptab */
+ p += 2;
+
+ /* padding */
+ p = (char *)(((DWORD_PTR)p + 0x0f) & ~0x0f);
+
+ memcpy(p, fd, fd->dfSize);
+ p += fd->dfSize;
+
+ /* padding */
+ p = (char *)(((DWORD_PTR)p + 0x0f) & ~0x0f);
+
+ strcpy(p, ttf_file_nameA);
+
+ p = (char *)(((DWORD_PTR)buf + 0x0f) & ~0x0f);
+ ret = WriteFile(hfile, p, file_len, &dummy, NULL);
+
+ HeapFree(GetProcessHeap(), 0, buf);
+ return ret;
+}
+
+static BOOL write_fot_file(const struct fontdir *fd, LPCWSTR file_name, LPCWSTR ttf_file_name)
+{
+ BOOL done = FALSE;
+ HANDLE hfile;
+
+ hfile = CreateFileW(file_name, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hfile == INVALID_HANDLE_VALUE) return FALSE;
+
+ done = write_file(hfile, fd, ttf_file_name);
+
+ CloseHandle(hfile);
+
+ return done;
+}
+
+static Face *first_face(struct list *flist)
+{
+ Family *family = LIST_ENTRY(list_head(flist), Family, entry);
+ return LIST_ENTRY(list_head(&family->faces), Face, entry);
+}
+
+DWORD WineEngCreateScalableFontResource(DWORD flags, LPCWSTR resource, LPCWSTR font)
+{
+ struct list flist;
+ BOOL ret = FALSE;
+ char *unix_name;
+ struct fontdir fd;
+ Face *face;
+ ENUMLOGFONTEXW elf;
+ NEWTEXTMETRICEXW ntm;
+ DWORD type;
+
+ GDI_CheckNotLock();
+
+ unix_name = wine_get_unix_file_name(font);
+ if (!unix_name)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ list_init(&flist);
+
+ if (!load_font(unix_name, NULL, 0, &flist, 0))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto fail;
+ }
+
+ dump_font_list(&flist);
+
+ face = first_face(&flist);
+ GetEnumStructs(face, &elf, &ntm, &type);
+ if (type == TRUETYPE_FONTTYPE)
+ {
+ ntm_to_fontdir(face, &ntm.ntmTm, &fd);
+ ret = write_fot_file(&fd, resource, font);
+ }
+
+fail:
+ free_font_list(&flist);
+ HeapFree(GetProcessHeap(), 0, unix_name);
+
+ return ret;
+}
+
#else /* HAVE_FREETYPE */
/*************************************************************************/
@@ -6841,4 +7165,10 @@ BOOL WineEngRealizationInfo(GdiFont *font, realization_info_t *info)
return FALSE;
}
+DWORD WineEngCreateScalableFontResource(DWORD flags, LPCWSTR resource, LPCWSTR font)
+{
+ ERR("called but we don't have FreeType\n");
+ return 0;
+}
+
#endif /* HAVE_FREETYPE */
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 3ed9356..1c314a2 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -408,6 +408,7 @@ typedef struct
extern INT WineEngAddFontResourceEx(LPCWSTR, DWORD, PVOID) DECLSPEC_HIDDEN;
extern HANDLE WineEngAddFontMemResourceEx(PVOID, DWORD, PVOID, LPDWORD) DECLSPEC_HIDDEN;
extern GdiFont* WineEngCreateFontInstance(DC*, HFONT) DECLSPEC_HIDDEN;
+extern DWORD WineEngCreateScalableFontResource(DWORD, LPCWSTR, LPCWSTR) DECLSPEC_HIDDEN;
extern BOOL WineEngDestroyFontInstance(HFONT handle) DECLSPEC_HIDDEN;
extern DWORD WineEngEnumFonts(LPLOGFONTW, FONTENUMPROCW, LPARAM) DECLSPEC_HIDDEN;
extern BOOL WineEngGetCharABCWidths(GdiFont *font, UINT firstChar,
--
1.7.0.6
More information about the wine-patches
mailing list