gdiplus: Implement in-memory font storage.

This commit is contained in:
Maarten Lankhorst 2011-02-16 19:09:15 +01:00 committed by Alexandre Julliard
parent 130e38e047
commit 8794f8f708
1 changed files with 143 additions and 2 deletions

View File

@ -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;
}