dwrite: Implement GetGlyphIndices from the CMAP table.
This commit is contained in:
parent
a5d8ab57f6
commit
2ec9fbb205
|
@ -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;
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue