Aric Stewart : dwrite: Implement GetGlyphIndices from the CMAP table.
Alexandre Julliard
julliard at wine.codeweavers.com
Wed Sep 3 15:09:21 CDT 2014
Module: wine
Branch: master
Commit: 2ec9fbb2058d2e59e0be5c05ba7efd9ff051146a
URL: http://source.winehq.org/git/wine.git/?a=commit;h=2ec9fbb2058d2e59e0be5c05ba7efd9ff051146a
Author: Aric Stewart <aric at codeweavers.com>
Date: Wed Sep 3 07:26:43 2014 -0500
dwrite: Implement GetGlyphIndices from the CMAP table.
---
dlls/dwrite/dwrite_private.h | 1 +
dlls/dwrite/font.c | 36 ++++++++++-
dlls/dwrite/opentype.c | 145 +++++++++++++++++++++++++++++++++++++++++++
dlls/dwrite/tests/font.c | 5 ++
4 files changed, 184 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index e78f9bf..08bd40f 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -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;
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 07a8b86..e782104 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -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++)
{
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 6c90a96..9e7a716 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -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);
+ }
+ }
+}
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 7a90c58..3a17064 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -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);
}
More information about the wine-cvs
mailing list