From 4c0ec6700cb17022f3cbc7fddfff3d514d2d8278 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 16 Oct 2014 07:33:51 +0400 Subject: [PATCH] dwrite: Implement GetUnicodeRanges(). --- dlls/dwrite/bidi.c | 2 +- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/font.c | 66 +++++++++++++++++++++++-------- dlls/dwrite/gdiinterop.c | 2 +- dlls/dwrite/opentype.c | 94 +++++++++++++++++++++++++++++++++++++++++++- dlls/dwrite/shape.c | 2 +- dlls/dwrite/tests/font.c | 77 +++++++++++++++++++++++++++++++++++- 7 files changed, 222 insertions(+), 22 deletions(-) diff --git a/dlls/dwrite/bidi.c b/dlls/dwrite/bidi.c index 8cd56ea7bb9..8e8daf613b2 100644 --- a/dlls/dwrite/bidi.c +++ b/dlls/dwrite/bidi.c @@ -48,7 +48,7 @@ #include "wine/debug.h" #include "wine/list.h" -#include "dwrite.h" +#include "dwrite_1.h" #include "dwrite_private.h" WINE_DEFAULT_DEBUG_CHANNEL(bidi); diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index f4a19c7a891..4c9aeef752e 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -109,6 +109,7 @@ extern HRESULT font_create_fontface(IDWriteFactory *iface, DWRITE_FONT_FACE_TYPE extern HRESULT opentype_analyze_font(IDWriteFontFileStream*,UINT32*,DWRITE_FONT_FILE_TYPE*,DWRITE_FONT_FACE_TYPE*,BOOL*) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_table(IDWriteFontFileStream*,DWRITE_FONT_FACE_TYPE,UINT32,UINT32,const void**,void**,UINT32*,BOOL*) DECLSPEC_HIDDEN; extern void opentype_cmap_get_glyphindex(void*,UINT32,UINT16*) DECLSPEC_HIDDEN; +extern HRESULT opentype_cmap_get_unicode_ranges(void*,UINT32,DWRITE_UNICODE_RANGE*,UINT32*) DECLSPEC_HIDDEN; extern VOID get_font_properties(LPCVOID os2, LPCVOID head, LPCVOID post, DWRITE_FONT_METRICS *metrics, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style) DECLSPEC_HIDDEN; extern HRESULT bidi_computelevels(const WCHAR*,UINT32,UINT8,UINT8*,UINT8*); diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index e3edbaa2d49..0b287ff1b3d 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -163,6 +163,24 @@ static inline struct dwrite_fontcollection *impl_from_IDWriteFontCollection(IDWr return CONTAINING_RECORD(iface, struct dwrite_fontcollection, IDWriteFontCollection_iface); } +static inline void* get_fontface_cmap(struct dwrite_fontface *fontface) +{ + BOOL exists = FALSE; + HRESULT hr; + + if (fontface->cmap.data) + return fontface->cmap.data; + + hr = IDWriteFontFace2_TryGetFontTable(&fontface->IDWriteFontFace2_iface, MS_CMAP_TAG, (const void**)&fontface->cmap.data, + &fontface->cmap.size, &fontface->cmap.context, &exists); + if (FAILED(hr) || !exists) { + ERR("Font does not have a CMAP table\n"); + return NULL; + } + + return fontface->cmap.data; +} + static HRESULT _dwritefontfile_GetFontFileStream(IDWriteFontFile *iface, IDWriteFontFileStream **stream) { HRESULT hr; @@ -377,21 +395,16 @@ static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace2 *iface, UI } else { - HRESULT hr; + void *data; + TRACE("(%p)->(%p %u %p)\n", This, codepoints, count, glyph_indices); - if (!This->cmap.data) - { - BOOL exists = FALSE; - hr = IDWriteFontFace2_TryGetFontTable(iface, MS_CMAP_TAG, (const void**)&This->cmap.data, &This->cmap.size, &This->cmap.context, &exists); - if (FAILED(hr) || !exists) - { - ERR("Font does not have a CMAP table\n"); - return E_FAIL; - } - } + + data = get_fontface_cmap(This); + if (!data) + return E_FAIL; for (i = 0; i < count; i++) - opentype_cmap_get_glyphindex(This->cmap.data, codepoints[i], &glyph_indices[i]); + opentype_cmap_get_glyphindex(data, codepoints[i], &glyph_indices[i]); return S_OK; } @@ -523,8 +536,14 @@ static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace2 *iface, DWRITE_UNICODE_RANGE *ranges, UINT32 *count) { struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface); - FIXME("(%p)->(%u %p %p): stub\n", This, max_count, ranges, count); - return E_NOTIMPL; + + TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count); + + *count = 0; + if (max_count && !ranges) + return E_INVALIDARG; + + return opentype_cmap_get_unicode_ranges(get_fontface_cmap(This), max_count, ranges, count); } static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace2 *iface) @@ -907,8 +926,23 @@ static void WINAPI dwritefont1_GetPanose(IDWriteFont2 *iface, DWRITE_PANOSE *pan static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont2 *iface, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count) { struct dwrite_font *This = impl_from_IDWriteFont2(iface); - FIXME("(%p)->(%u %p %p): stub\n", This, max_count, ranges, count); - return E_NOTIMPL; + IDWriteFontFace2 *fontface2; + IDWriteFontFace *fontface; + HRESULT hr; + + TRACE("(%p)->(%u %p %p)\n", This, max_count, ranges, count); + + hr = IDWriteFont2_CreateFontFace(iface, &fontface); + if (FAILED(hr)) + return hr; + + IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace2, (void**)&fontface2); + IDWriteFontFace_Release(fontface); + + hr = IDWriteFontFace2_GetUnicodeRanges(fontface2, max_count, ranges, count); + IDWriteFontFace2_Release(fontface2); + + return hr; } static HRESULT WINAPI dwritefont1_IsMonospacedFont(IDWriteFont2 *iface) diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c index 329bcdb46b0..7c20110b658 100644 --- a/dlls/dwrite/gdiinterop.c +++ b/dlls/dwrite/gdiinterop.c @@ -25,7 +25,7 @@ #include "windef.h" #include "winbase.h" #include "wingdi.h" -#include "dwrite.h" +#include "dwrite_1.h" #include "dwrite_private.h" #include "wine/debug.h" diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index dba3e3124b4..b17e8ac206e 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -20,7 +20,7 @@ #define COBJMACROS -#include "dwrite.h" +#include "dwrite_1.h" #include "dwrite_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dwrite); @@ -393,6 +393,98 @@ void opentype_cmap_get_glyphindex(void *data, UINT32 utf32c, UINT16 *pgi) } } +static UINT32 opentype_cmap_get_unicode_ranges_count(const CMAP_Header *CMAP_Table) +{ + UINT32 count = 0; + int i; + + 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("table type %i\n", type); + + switch (type) + { + case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: + { + CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table; + count += GET_BE_WORD(format->segCountX2)/2; + break; + } + case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: + { + CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table; + count += GET_BE_DWORD(format->nGroups); + break; + } + default: + FIXME("table type %i unhandled.\n", type); + } + } + + return count; +} + +HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UNICODE_RANGE *ranges, UINT32 *count) +{ + CMAP_Header *CMAP_Table = data; + int i, k = 0; + + if (!CMAP_Table) + return E_FAIL; + + *count = opentype_cmap_get_unicode_ranges_count(CMAP_Table); + + for (i = 0; i < GET_BE_WORD(CMAP_Table->numTables) && k < max_count; i++) + { + WORD type; + WORD *table; + int j; + + 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("table type %i\n", type); + + switch (type) + { + case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: + { + CMAP_SegmentMapping_0 *format = (CMAP_SegmentMapping_0*)table; + UINT16 segment_count = GET_BE_WORD(format->segCountX2)/2; + UINT16 *startCode = (WORD*)((BYTE*)format + sizeof(CMAP_SegmentMapping_0) + (sizeof(WORD) * segment_count)); + + for (j = 0; j < segment_count && GET_BE_WORD(format->endCode[j]) < 0xffff && k < max_count; j++, k++) { + ranges[k].first = GET_BE_WORD(startCode[j]); + ranges[k].last = GET_BE_WORD(format->endCode[j]); + } + break; + } + case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: + { + CMAP_SegmentedCoverage *format = (CMAP_SegmentedCoverage*)table; + for (j = 0; j < GET_BE_DWORD(format->nGroups) && k < max_count; j++, k++) { + ranges[k].first = GET_BE_DWORD(format->groups[j].startCharCode); + ranges[k].last = GET_BE_DWORD(format->groups[j].endCharCode); + } + break; + } + default: + FIXME("table type %i unhandled.\n", type); + } + } + + return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK; +} + VOID get_font_properties(LPCVOID os2, LPCVOID head, LPCVOID post, DWRITE_FONT_METRICS *metrics, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style) { TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2; diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index dbf5c67a0ad..ba306c77f70 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -21,7 +21,7 @@ #define COBJMACROS -#include "dwrite.h" +#include "dwrite_1.h" #include "dwrite_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dwrite); diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 5e269c30df6..411b249e71a 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -21,7 +21,7 @@ #define COBJMACROS #include "windows.h" -#include "dwrite.h" +#include "dwrite_1.h" #include "wine/test.h" @@ -37,6 +37,16 @@ static void _expect_ref(IUnknown* obj, ULONG ref, int line) ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc); } +static inline void *heap_alloc(size_t len) +{ + return HeapAlloc(GetProcessHeap(), 0, len); +} + +static inline BOOL heap_free(void *mem) +{ + return HeapFree(GetProcessHeap(), 0, mem); +} + static IDWriteFactory *factory; static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0}; @@ -189,6 +199,7 @@ static const struct IDWriteFontFileLoaderVtbl resourcefontfileloadervtbl = { resourcefontfileloader_CreateStreamFromKey }; +static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl }; static void test_CreateFontFromLOGFONT(void) { @@ -939,7 +950,6 @@ static void test_FontLoader(void) IDWriteFontFileLoader floader = { &dwritefontfileloadervtbl }; IDWriteFontFileLoader floader2 = { &dwritefontfileloadervtbl }; IDWriteFontFileLoader floader3 = { &dwritefontfileloadervtbl }; - IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl }; IDWriteFontFile *ffile = NULL; BOOL support = 1; DWRITE_FONT_FILE_TYPE type = 1; @@ -1117,6 +1127,68 @@ static void test_shared_isolated(void) IDWriteFactory_Release(isolated2); } +static void test_GetUnicodeRanges(void) +{ + DWRITE_UNICODE_RANGE *ranges, r; + IDWriteFontFile *ffile = NULL; + IDWriteFontFace1 *fontface1; + IDWriteFontFace *fontface; + UINT32 count; + HRESULT hr; + HRSRC font; + + hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader); + ok(hr == S_OK, "got 0x%08x\n", hr); + + font = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA); + ok(font != NULL, "Failed to find font resource\n"); + + hr = IDWriteFactory_CreateCustomFontFileReference(factory, &font, sizeof(HRSRC), &rloader, &ffile); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ffile, 0, DWRITE_FONT_SIMULATIONS_NONE, &fontface); + ok(hr == S_OK, "got 0x%08x\n", hr); + IDWriteFontFile_Release(ffile); + + hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1); + IDWriteFontFace_Release(fontface); + if (hr != S_OK) { + win_skip("GetUnicodeRanges() is not supported.\n"); + return; + } + + count = 0; + hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count); + ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr); + ok(count > 0, "got %u\n", count); + + count = 1; + hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, NULL, &count); + ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); + ok(count == 0, "got %u\n", count); + + count = 0; + hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, &r, &count); + ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr); + ok(count > 1, "got %u\n", count); + + ranges = heap_alloc(count*sizeof(DWRITE_UNICODE_RANGE)); + hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count); + ok(hr == S_OK, "got 0x%08x\n", hr); + + ranges[0].first = ranges[0].last = 0; + hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 1, ranges, &count); + ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr); + ok(ranges[0].first != 0 && ranges[0].last != 0, "got 0x%x-0x%0x\n", ranges[0].first, ranges[0].last); + + heap_free(ranges); + + hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader); + ok(hr == S_OK, "got 0x%08x\n", hr); + + IDWriteFontFace1_Release(fontface1); +} + START_TEST(font) { HRESULT hr; @@ -1141,6 +1213,7 @@ START_TEST(font) test_FontLoader(); test_CreateFontFileReference(); test_shared_isolated(); + test_GetUnicodeRanges(); IDWriteFactory_Release(factory); } -- 2.11.4.GIT