[1/4] gdi32: Implement CreateScalableFontResource, based on a patch by Jeremy White.

Dmitry Timoshkov dmitry at codeweavers.com
Sun Nov 14 04:41:02 CST 2010


This set of patches should be applied after
gdi32: Separate font loading from adding a font to global font list.

---
 dlls/gdi32/font.c        |   46 ++++---
 dlls/gdi32/freetype.c    |  325 ++++++++++++++++++++++++++++++++++++++++++++++
 dlls/gdi32/gdi_private.h |    1 +
 3 files changed, 353 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 f13ecb4..97ea04f 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
+
+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"
+};
+
+#include "pshpack1.h"
+
+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,246 @@ 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->tmPitchAndFamily;
+    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_pad(HANDLE hfile)
+{
+    DWORD dummy, pad;
+    char filler[0x10] = { 0 };
+
+    pad = SetFilePointer(hfile, 0, NULL, FILE_CURRENT) & 0x0f;
+    if (pad != 0)
+    {
+        pad = 0x10 - pad;
+        if (!WriteFile(hfile, filler, pad, &dummy, NULL)) return FALSE;
+    }
+    return TRUE;
+}
+
+static BOOL write_file(HANDLE hfile, const struct fontdir *fd, LPCWSTR ttf_file_name)
+{
+    short align;
+    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;
+    char filler[0x10] = { 0 };
+    DWORD dummy;
+    char ttf_file_nameA[MAX_PATH];
+    const char *file_part, *p;
+
+    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(align) + 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(align);
+    fontdir_off = (non_resident_name_off + non_resident_name_len + 0x0f) & ~0x0f;
+    fontpath_off = (fontdir_off + fd->dfSize + 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;
+
+    if (!WriteFile(hfile, &dos, sizeof(dos), &dummy, NULL)) return FALSE;
+    if (!WriteFile(hfile, &ne, sizeof(ne), &dummy, NULL)) return FALSE;
+
+    /* resource table */
+    align = 4;
+    if (!WriteFile(hfile, &align, sizeof(align), &dummy, NULL)) return FALSE;
+
+    rc_type.type_id = NE_RSCTYPE_FONTDIR;
+    rc_type.count = 1;
+    rc_type.resloader = 0;
+    if (!WriteFile(hfile, &rc_type, sizeof(rc_type), &dummy, NULL)) return FALSE;
+
+    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;
+    if (!WriteFile(hfile, &rc_name, sizeof(rc_name), &dummy, NULL)) return FALSE;
+
+    rc_type.type_id = NE_RSCTYPE_SCALABLE_FONTPATH;
+    rc_type.count = 1;
+    rc_type.resloader = 0;
+    if (!WriteFile(hfile, &rc_type, sizeof(rc_type), &dummy, NULL)) return FALSE;
+
+    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;
+    if (!WriteFile(hfile, &rc_name, sizeof(rc_name), &dummy, NULL)) return FALSE;
+
+    /* empty type info */
+    memset(&rc_type, 0, sizeof(rc_type));
+    if (!WriteFile(hfile, &rc_type, sizeof(rc_type), &dummy, NULL)) return FALSE;
+
+    if (!WriteFile(hfile, "\7FONTDIR", 8, &dummy, NULL)) return FALSE;
+    str_len = strlen(resident_name);
+    if (!WriteFile(hfile, &str_len, 1, &dummy, NULL)) return FALSE;
+    if (!WriteFile(hfile, resident_name, str_len, &dummy, NULL)) return FALSE;
+    if (!WriteFile(hfile, filler, 5, &dummy, NULL)) return FALSE;
+
+    str_len = strlen(non_resident_name);
+    if (!WriteFile(hfile, &str_len, 1, &dummy, NULL)) return FALSE;
+    if (!WriteFile(hfile, non_resident_name, str_len, &dummy, NULL)) return FALSE;
+    /* terminator */
+    if (!WriteFile(hfile, filler, 1, &dummy, NULL)) return FALSE;
+
+    /* empty ne_modtab and ne_imptab */
+    if (!WriteFile(hfile, filler, 2, &dummy, NULL)) return FALSE;
+
+    if (!write_pad(hfile)) return FALSE;
+
+    if (!WriteFile(hfile, fd, fd->dfSize, &dummy, NULL)) return FALSE;
+
+    if (!write_pad(hfile)) return FALSE;
+
+    if (!WriteFile(hfile, ttf_file_nameA, strlen(ttf_file_nameA), &dummy, NULL)) return FALSE;
+
+    if (!write_pad(hfile)) return FALSE;
+
+    return TRUE;
+}
+
+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 *font_list)
+{
+    Family *family = LIST_ENTRY(list_head(font_list), Family, entry);
+    return LIST_ENTRY(list_head(&family->faces), Face, entry);
+}
+
+DWORD WineEngCreateScalableFontResource(DWORD flags, LPCWSTR resource, LPCWSTR font)
+{
+    struct list font_list;
+    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(&font_list);
+
+    if (!load_font(unix_name, NULL, 0, &font_list, 0))
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        goto fail;
+    }
+
+    dump_font_list(&font_list);
+
+    face = first_face(&font_list);
+    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(&font_list);
+    HeapFree(GetProcessHeap(), 0, unix_name);
+
+    return ret;
+}
+
 #else /* HAVE_FREETYPE */
 
 /*************************************************************************/
@@ -6841,4 +7160,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