Maarten Lankhorst : gdiplus: Implement in-memory font storage.

Alexandre Julliard julliard at winehq.org
Tue Feb 22 10:36:10 CST 2011


Module: wine
Branch: master
Commit: 8794f8f7086b46d6726d69dfe7a03974e5df48f5
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=8794f8f7086b46d6726d69dfe7a03974e5df48f5

Author: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date:   Wed Feb 16 19:09:15 2011 +0100

gdiplus: Implement in-memory font storage.

---

 dlls/gdiplus/font.c |  145 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c
index 843cfb5..242a857 100644
--- a/dlls/gdiplus/font.c
+++ b/dlls/gdiplus/font.c
@@ -930,17 +930,158 @@ GpStatus WINGDIPAPI GdipPrivateAddFontFile(GpFontCollection* fontCollection,
     return NotImplemented;
 }
 
+/* Copied from msi/font.c */
+
+typedef struct _tagTT_OFFSET_TABLE {
+    USHORT uMajorVersion;
+    USHORT uMinorVersion;
+    USHORT uNumOfTables;
+    USHORT uSearchRange;
+    USHORT uEntrySelector;
+    USHORT uRangeShift;
+} TT_OFFSET_TABLE;
+
+typedef struct _tagTT_TABLE_DIRECTORY {
+    char szTag[4]; /* table name */
+    ULONG uCheckSum; /* Check sum */
+    ULONG uOffset; /* Offset from beginning of file */
+    ULONG uLength; /* length of the table in bytes */
+} TT_TABLE_DIRECTORY;
+
+typedef struct _tagTT_NAME_TABLE_HEADER {
+    USHORT uFSelector; /* format selector. Always 0 */
+    USHORT uNRCount; /* Name Records count */
+    USHORT uStorageOffset; /* Offset for strings storage,
+                            * from start of the table */
+} TT_NAME_TABLE_HEADER;
+
+#define NAME_ID_FULL_FONT_NAME  4
+#define NAME_ID_VERSION         5
+
+typedef struct _tagTT_NAME_RECORD {
+    USHORT uPlatformID;
+    USHORT uEncodingID;
+    USHORT uLanguageID;
+    USHORT uNameID;
+    USHORT uStringLength;
+    USHORT uStringOffset; /* from start of storage area */
+} TT_NAME_RECORD;
+
+#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
+#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
+
+/*
+ * Code based off of code located here
+ * http://www.codeproject.com/gdi/fontnamefromfile.asp
+ */
+WCHAR *load_ttf_name_id( const char *mem, DWORD_PTR size, DWORD id, WCHAR *ret, DWORD len )
+{
+    const TT_TABLE_DIRECTORY *tblDir;
+    TT_OFFSET_TABLE ttOffsetTable;
+    TT_NAME_TABLE_HEADER ttNTHeader;
+    TT_NAME_RECORD ttRecord;
+    DWORD ofs, pos;
+    int i;
+
+    if (sizeof(TT_OFFSET_TABLE) > size)
+        return NULL;
+    ttOffsetTable = *(TT_OFFSET_TABLE*)mem;
+    ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
+    ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
+    ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
+
+    if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
+        return NULL;
+
+    pos = sizeof(ttOffsetTable);
+    for (i = 0; i < ttOffsetTable.uNumOfTables; i++)
+    {
+        tblDir = (const TT_TABLE_DIRECTORY*)&mem[pos];
+        pos += sizeof(*tblDir);
+        if (memcmp(tblDir->szTag,"name",4)==0)
+        {
+            ofs = SWAPLONG(tblDir->uOffset);
+            break;
+        }
+    }
+    if (i >= ttOffsetTable.uNumOfTables)
+        return NULL;
+
+    pos = ofs + sizeof(ttNTHeader);
+    if (pos > size)
+        return NULL;
+    ttNTHeader = *(TT_NAME_TABLE_HEADER*)&mem[ofs];
+    ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
+    ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
+    for(i=0; i<ttNTHeader.uNRCount; i++)
+    {
+        ttRecord = *(TT_NAME_RECORD*)&mem[pos];
+        pos += sizeof(ttRecord);
+        if (pos > size)
+            return NULL;
+
+        ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
+        if (ttRecord.uNameID == id)
+        {
+            const char *buf;
+
+            ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
+            ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
+            if (ofs + ttRecord.uStringOffset + ttNTHeader.uStorageOffset + ttRecord.uStringLength > size)
+                return NULL;
+            buf = mem + ofs + ttRecord.uStringOffset + ttNTHeader.uStorageOffset;
+            len = MultiByteToWideChar(CP_ACP, 0, buf, ttRecord.uStringLength, ret, len-1);
+            ret[len] = 0;
+            return ret;
+        }
+    }
+    return NULL;
+}
+
+static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam);
+
 /*****************************************************************************
  * GdipPrivateAddMemoryFont [GDIPLUS.@]
  */
 GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection,
         GDIPCONST void* memory, INT length)
 {
-    FIXME("%p, %p, %d\n", fontCollection, memory, length);
+    WCHAR buf[32], *name;
+    DWORD count = 0;
+    HANDLE font;
+    TRACE("%p, %p, %d\n", fontCollection, memory, length);
 
-    if (!(fontCollection && memory && length))
+    if (!fontCollection || !memory || !length)
         return InvalidParameter;
 
+    name = load_ttf_name_id(memory, length, NAME_ID_FULL_FONT_NAME, buf, sizeof(buf)/sizeof(*buf));
+    if (!name)
+        return OutOfMemory;
+
+    font = AddFontMemResourceEx((void*)memory, length, NULL, &count);
+    TRACE("%s: %p/%u\n", debugstr_w(name), font, count);
+    if (!font || !count)
+        return InvalidParameter;
+
+    if (count)
+    {
+        HDC hdc;
+        LOGFONTW lfw;
+
+        hdc = GetDC(0);
+
+        lfw.lfCharSet = DEFAULT_CHARSET;
+        lstrcpyW(lfw.lfFaceName, name);
+        lfw.lfPitchAndFamily = 0;
+
+        if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)fontCollection, 0))
+        {
+            ReleaseDC(0, hdc);
+            return OutOfMemory;
+        }
+
+        ReleaseDC(0, hdc);
+    }
     return Ok;
 }
 




More information about the wine-cvs mailing list