dwrite: Implement GetGlyphIndices from the CMAP table.

This commit is contained in:
Aric Stewart 2014-09-03 07:26:43 -05:00 committed by Alexandre Julliard
parent a5d8ab57f6
commit 2ec9fbb205
4 changed files with 184 additions and 3 deletions

View file

@ -100,3 +100,4 @@ extern HRESULT font_create_fontface(IDWriteFactory *iface, DWRITE_FONT_FACE_TYPE
/* Opentype font table functions */
extern HRESULT analyze_opentype_font(const void* font_data, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported) DECLSPEC_HIDDEN;
extern HRESULT find_font_table(IDWriteFontFileStream *stream, UINT32 font_index, UINT32 tag, const void** table_data, void** table_context, UINT32 *table_size, BOOL* found) DECLSPEC_HIDDEN;
extern VOID OpenType_CMAP_GetGlyphIndex(LPVOID data, DWORD utf32c, LPWORD pgi, DWORD flags) DECLSPEC_HIDDEN;

View file

@ -124,6 +124,7 @@ typedef struct
#define MS_HEAD_TAG MS_MAKE_TAG('h','e','a','d')
#define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2')
#define MS_POST_TAG MS_MAKE_TAG('p','o','s','t')
#define MS_CMAP_TAG MS_MAKE_TAG('c','m','a','p')
struct dwrite_fontface_data {
LONG ref;
@ -188,6 +189,10 @@ struct dwrite_fontface {
struct dwrite_fontface_data *data;
LPVOID CMAP_table;
LPVOID CMAP_context;
DWORD CMAP_size;
BOOL is_system;
LOGFONTW logfont;
};
@ -296,6 +301,8 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace *iface)
if (!ref)
{
if (This->CMAP_context)
IDWriteFontFace_ReleaseFontTable(iface, This->CMAP_context);
_free_fontface_data(This->data);
heap_free(This);
}
@ -379,12 +386,13 @@ static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace *iface, UIN
UINT32 count, UINT16 *glyph_indices)
{
struct dwrite_fontface *This = impl_from_IDWriteFontFace(iface);
unsigned int i;
if (This->is_system)
{
HFONT hfont;
WCHAR *str;
HDC hdc;
unsigned int i;
TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
@ -408,8 +416,24 @@ static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace *iface, UIN
}
else
{
FIXME("(%p)->(%p %u %p): Stub\n", This, codepoints, count, glyph_indices);
return E_NOTIMPL;
HRESULT hr;
TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices);
if (!This->CMAP_table)
{
BOOL exists = FALSE;
hr = IDWriteFontFace_TryGetFontTable(iface, MS_CMAP_TAG, (const void**)&This->CMAP_table, &This->CMAP_size, &This->CMAP_context, &exists);
if (FAILED(hr) || !exists)
{
ERR("Font does not have a CMAP table\n");
return E_FAIL;
}
}
for (i = 0; i < count; i++)
{
OpenType_CMAP_GetGlyphIndex(This->CMAP_table, codepoints[i], &glyph_indices[i], 0);
}
return S_OK;
}
}
@ -557,6 +581,9 @@ static HRESULT create_system_fontface(struct dwrite_font *font, IDWriteFontFace
This->data->files = NULL;
This->data->index = 0;
This->data->simulations = DWRITE_FONT_SIMULATIONS_NONE;
This->CMAP_table = NULL;
This->CMAP_context = NULL;
This->CMAP_size = 0;
This->is_system = TRUE;
memset(&This->logfont, 0, sizeof(This->logfont));
@ -1318,6 +1345,9 @@ HRESULT font_create_fontface(IDWriteFactory *iface, DWRITE_FONT_FACE_TYPE facety
This->data->type = facetype;
This->data->file_count = files_number;
This->data->files = heap_alloc(sizeof(*This->data->files) * files_number);
This->CMAP_table = NULL;
This->CMAP_context = NULL;
This->CMAP_size = 0;
/* Verify font file streams */
for (i = 0; i < This->data->file_count && SUCCEEDED(hr); i++)
{

View file

@ -62,6 +62,44 @@ typedef struct {
DWORD length;
} TT_TableRecord;
typedef struct {
WORD platformID;
WORD encodingID;
DWORD offset;
} CMAP_EncodingRecord;
typedef struct {
WORD version;
WORD numTables;
CMAP_EncodingRecord tables[1];
} CMAP_Header;
typedef struct {
DWORD startCharCode;
DWORD endCharCode;
DWORD startGlyphID;
} CMAP_SegmentedCoverage_group;
typedef struct {
WORD format;
WORD reserved;
DWORD length;
DWORD language;
DWORD nGroups;
CMAP_SegmentedCoverage_group groups[1];
} CMAP_SegmentedCoverage;
typedef struct {
WORD format;
WORD length;
WORD language;
WORD segCountX2;
WORD searchRange;
WORD entrySelector;
WORD rangeShift;
WORD endCode[1];
} CMAP_SegmentMapping_0;
HRESULT analyze_opentype_font(const void* font_data, UINT32* font_count, DWRITE_FONT_FILE_TYPE *file_type, DWRITE_FONT_FACE_TYPE *face_type, BOOL *supported)
{
/* TODO: Do font validation */
@ -169,3 +207,110 @@ HRESULT find_font_table(IDWriteFontFileStream *stream, UINT32 font_index, UINT32
return hr;
}
/**********
* CMAP
**********/
static int compare_group(const void *a, const void* b)
{
const DWORD *chr = a;
const CMAP_SegmentedCoverage_group *group = b;
if (*chr < GET_BE_DWORD(group->startCharCode))
return -1;
if (*chr > GET_BE_DWORD(group->endCharCode))
return 1;
return 0;
}
static void CMAP4_GetGlyphIndex(CMAP_SegmentMapping_0* format, DWORD utf32c, LPWORD pgi)
{
WORD *startCode;
SHORT *idDelta;
WORD *idRangeOffset;
int segment;
int segment_count = GET_BE_WORD(format->segCountX2)/2;
/* This is correct because of the padding before startCode */
startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count));
idDelta = (SHORT*)(((BYTE*)startCode) + (sizeof(WORD) * segment_count));
idRangeOffset = (WORD*)(((BYTE*)idDelta) + (sizeof(WORD) * segment_count));
segment = 0;
while(GET_BE_WORD(format->endCode[segment]) < 0xffff)
{
if (utf32c <= GET_BE_WORD(format->endCode[segment]))
break;
segment++;
}
if (segment >= segment_count)
return;
TRACE("Segment %i of %i\n",segment, segment_count);
if (GET_BE_WORD(startCode[segment]) > utf32c)
return;
TRACE("In range %i -> %i\n", GET_BE_WORD(startCode[segment]), GET_BE_WORD(format->endCode[segment]));
if (GET_BE_WORD(idRangeOffset[segment]) == 0)
{
*pgi = (SHORT)(GET_BE_WORD(idDelta[segment])) + utf32c;
}
else
{
WORD ro = GET_BE_WORD(idRangeOffset[segment])/2;
WORD co = (utf32c - GET_BE_WORD(startCode[segment]));
WORD *index = (WORD*)((BYTE*)&idRangeOffset[segment] + (ro + co));
*pgi = GET_BE_WORD(*index);
}
}
static void CMAP12_GetGlyphIndex(CMAP_SegmentedCoverage* format, DWORD utf32c, LPWORD pgi)
{
CMAP_SegmentedCoverage_group *group = NULL;
group = bsearch(&utf32c, format->groups, GET_BE_DWORD(format->nGroups),
sizeof(CMAP_SegmentedCoverage_group), compare_group);
if (group)
{
DWORD offset = utf32c - GET_BE_DWORD(group->startCharCode);
*pgi = GET_BE_DWORD(group->startGlyphID) + offset;
}
}
VOID OpenType_CMAP_GetGlyphIndex(LPVOID data, DWORD utf32c, LPWORD pgi, DWORD flags)
{
int i;
CMAP_Header *CMAP_Table = NULL;
if (flags & GGI_MARK_NONEXISTING_GLYPHS)
*pgi = 0xffff;
else
*pgi = 0;
CMAP_Table = data;
for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables); i++)
{
WORD type;
WORD *table;
if (GET_BE_WORD(CMAP_Table->tables[i].platformID) != 3)
continue;
table = (WORD*)(((BYTE*)CMAP_Table) + GET_BE_DWORD(CMAP_Table->tables[i].offset));
type = GET_BE_WORD(*table);
TRACE("Type %i\n", type);
/* Break when we find a handled type */
switch(type)
{
case 4:
CMAP4_GetGlyphIndex((CMAP_SegmentMapping_0*) table, utf32c, pgi);
break;
case 12:
CMAP12_GetGlyphIndex((CMAP_SegmentedCoverage*) table, utf32c, pgi);
break;
default:
TRACE("Type %i unhandled.\n", type);
}
}
}

View file

@ -919,6 +919,8 @@ static void test_FontLoader(void)
IDWriteFontFace *fface = NULL;
HRESULT hr;
HRSRC font;
UINT32 codePoints[1] = {0xa8};
UINT16 indices[1];
hr = IDWriteFactory_RegisterFontFileLoader(factory, NULL);
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
@ -975,6 +977,9 @@ static void test_FontLoader(void)
hr = IDWriteFactory_CreateFontFace(factory, face, 1, &ffile, 0, 0, &fface);
ok(hr == S_OK, "got 0x%08x\n",hr);
hr = IDWriteFontFace_GetGlyphIndices(fface, codePoints, 1, indices);
ok(hr == S_OK, "got0x%08x\n",hr);
ok(indices[0] == 6, "got index %i\n",indices[0]);
IDWriteFontFace_Release(fface);
IDWriteFontFile_Release(ffile);
}