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