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