[PATCH] dwrite/tests: Add some tests for setting glyph properties from GDEF.
Nikolay Sivov
nsivov at codeweavers.com
Wed Jan 30 08:15:33 CST 2019
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/tests/analyzer.c | 293 ++++++++++++++++++++++++++++++++++-
1 file changed, 292 insertions(+), 1 deletion(-)
diff --git a/dlls/dwrite/tests/analyzer.c b/dlls/dwrite/tests/analyzer.c
index 251887f508..99b415a3fb 100644
--- a/dlls/dwrite/tests/analyzer.c
+++ b/dlls/dwrite/tests/analyzer.c
@@ -27,8 +27,10 @@
#include "initguid.h"
#include "windows.h"
+#include "winternl.h"
#include "dwrite_3.h"
+#include "wine/heap.h"
#include "wine/test.h"
static IDWriteFactory *factory;
@@ -44,6 +46,42 @@ static const WCHAR test_fontfile[] = {'w','i','n','e','_','t','e','s','t','_','f
#define FSI 0x2068
#define PDI 0x2069
+#define MS_GDEF_TAG DWRITE_MAKE_OPENTYPE_TAG('G','D','E','F')
+
+#ifdef WORDS_BIGENDIAN
+#define GET_BE_WORD(x) (x)
+#define GET_BE_DWORD(x) (x)
+#define GET_LE_WORD(x) RtlUshortByteSwap(x)
+#define GET_LE_DWORD(x) RtlUlongByteSwap(x)
+#else
+#define GET_BE_WORD(x) RtlUshortByteSwap(x)
+#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
+#define GET_LE_WORD(x) (x)
+#define GET_LE_DWORD(x) (x)
+#endif
+
+struct ot_gdef_classdef_format1
+{
+ WORD format;
+ WORD start_glyph;
+ WORD glyph_count;
+ WORD classes[1];
+};
+
+struct ot_gdef_class_range
+{
+ WORD start_glyph;
+ WORD end_glyph;
+ WORD glyph_class;
+};
+
+struct ot_gdef_classdef_format2
+{
+ WORD format;
+ WORD range_count;
+ struct ot_gdef_class_range ranges[1];
+};
+
enum analysis_kind {
ScriptAnalysis,
LastKind
@@ -1364,6 +1402,207 @@ static void get_fontface_advances(IDWriteFontFace *fontface, FLOAT emsize, const
}
}
+enum ot_gdef_class
+{
+ GDEF_CLASS_UNCLASSIFIED = 0,
+ GDEF_CLASS_BASE = 1,
+ GDEF_CLASS_LIGATURE = 2,
+ GDEF_CLASS_MARK = 3,
+ GDEF_CLASS_COMPONENT = 4,
+ GDEF_CLASS_MAX = GDEF_CLASS_COMPONENT,
+};
+
+struct dwrite_fonttable
+{
+ BYTE *data;
+ void *context;
+ unsigned int size;
+};
+
+static const void *table_read_ensure(const struct dwrite_fonttable *table, unsigned int offset, unsigned int size)
+{
+ if (size > table->size || offset > table->size - size)
+ return NULL;
+
+ return table->data + offset;
+}
+
+static WORD table_read_be_word(const struct dwrite_fonttable *table, unsigned int offset)
+{
+ const WORD *ptr = table_read_ensure(table, offset, sizeof(*ptr));
+ return ptr ? GET_BE_WORD(*ptr) : 0;
+}
+
+static int gdef_class_compare_format2(const void *g, const void *r)
+{
+ const struct ot_gdef_class_range *range = r;
+ UINT16 glyph = *(UINT16 *)g;
+
+ if (glyph < GET_BE_WORD(range->start_glyph))
+ return -1;
+ else if (glyph > GET_BE_WORD(range->end_glyph))
+ return 1;
+ else
+ return 0;
+}
+
+static unsigned int get_glyph_class(const struct dwrite_fonttable *table, UINT16 glyph)
+{
+ unsigned int glyph_class = GDEF_CLASS_UNCLASSIFIED, offset;
+ WORD format, count;
+
+ offset = table_read_be_word(table, 4);
+
+ format = table_read_be_word(table, offset);
+
+ if (format == 1)
+ {
+ const struct ot_gdef_classdef_format1 *format1;
+
+ count = table_read_be_word(table, offset + FIELD_OFFSET(struct ot_gdef_classdef_format1, glyph_count));
+ format1 = table_read_ensure(table, offset, FIELD_OFFSET(struct ot_gdef_classdef_format1, classes[count]));
+ if (format1)
+ {
+ WORD start_glyph = GET_BE_WORD(format1->start_glyph);
+ if (glyph >= start_glyph && (glyph - start_glyph) < count)
+ {
+ glyph_class = GET_BE_WORD(format1->classes[glyph - start_glyph]);
+ if (glyph_class > GDEF_CLASS_MAX)
+ glyph_class = GDEF_CLASS_UNCLASSIFIED;
+ }
+ }
+ }
+ else if (format == 2)
+ {
+ const struct ot_gdef_classdef_format2 *format2;
+
+ count = table_read_be_word(table, offset + FIELD_OFFSET(struct ot_gdef_classdef_format2, range_count));
+ format2 = table_read_ensure(table, offset, FIELD_OFFSET(struct ot_gdef_classdef_format2, ranges[count]));
+ if (format2)
+ {
+ const struct ot_gdef_class_range *range = bsearch(&glyph, format2->ranges, count,
+ sizeof(struct ot_gdef_class_range), gdef_class_compare_format2);
+ glyph_class = range && glyph <= GET_BE_WORD(range->end_glyph) ?
+ GET_BE_WORD(range->glyph_class) : GDEF_CLASS_UNCLASSIFIED;
+ if (glyph_class > GDEF_CLASS_MAX)
+ glyph_class = GDEF_CLASS_UNCLASSIFIED;
+ }
+ }
+
+ return glyph_class;
+}
+
+static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, unsigned int size)
+{
+ static const WCHAR enusW[] = {'e','n','-','u','s',0};
+ BOOL exists = FALSE;
+ unsigned int index;
+ HRESULT hr;
+
+ hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(exists, "Failed to find locale name %d.\n", exists);
+
+ hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
+ ok(hr == S_OK, "Failed to get name string, hr %#x.\n", hr);
+}
+
+static void test_glyph_props(IDWriteTextAnalyzer *analyzer, const WCHAR *family, const WCHAR *face,
+ IDWriteFontFace *fontface)
+{
+ unsigned int i, ch, count, offset;
+ struct dwrite_fonttable gdef;
+ DWRITE_UNICODE_RANGE *ranges;
+ IDWriteFontFace1 *fontface1;
+ BOOL exists = FALSE;
+ HRESULT hr;
+
+ hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GDEF_TAG, (const void **)&gdef.data, &gdef.size,
+ &gdef.context, &exists);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+
+ if (!exists)
+ return;
+
+ offset = table_read_be_word(&gdef, 4);
+ if (!offset)
+ {
+ IDWriteFontFace_ReleaseFontTable(fontface, gdef.context);
+ return;
+ }
+
+ if (FAILED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1)))
+ {
+ IDWriteFontFace_ReleaseFontTable(fontface, gdef.context);
+ return;
+ }
+
+ hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
+ ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
+
+ ranges = heap_alloc(count * sizeof(*ranges));
+
+ hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
+ ok(hr == S_OK, "Failed to get ranges, hr %#x.\n", hr);
+
+ for (i = 0; i < count; ++i)
+ {
+ if (ranges[i].first > 0xffff)
+ break;
+
+ for (ch = ranges[i].first; ch <= ranges[i].last; ch++)
+ {
+ DWRITE_SHAPING_TEXT_PROPERTIES text_props[10];
+ DWRITE_SHAPING_GLYPH_PROPERTIES glyph_props[10];
+ UINT16 glyphs[10], clustermap[10], glyph;
+ unsigned int actual_count, glyph_class;
+ DWRITE_SCRIPT_ANALYSIS sa;
+ WCHAR text[1];
+
+ hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &ch, 1, &glyph);
+ ok(hr == S_OK, "Failed to get glyph index, hr %#x.\n", hr);
+
+ if (!glyph)
+ continue;
+
+ sa.script = 999;
+ sa.shapes = DWRITE_SCRIPT_SHAPES_DEFAULT;
+ text[0] = (WCHAR)ch;
+ memset(glyph_props, 0, sizeof(glyph_props));
+ hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, text, 1, fontface, FALSE, FALSE, &sa, NULL,
+ NULL, NULL, NULL, 0, ARRAY_SIZE(glyphs), clustermap, text_props, glyphs, glyph_props, &actual_count);
+ ok(hr == S_OK, "Failed to shape, hr %#x.\n", hr);
+ if (actual_count > 1)
+ continue;
+
+ glyph_class = get_glyph_class(&gdef, glyphs[0]);
+
+ switch (glyph_class)
+ {
+ case GDEF_CLASS_MARK:
+ ok(glyph_props[0].isDiacritic && glyph_props[0].isZeroWidthSpace,
+ "%#x -> %u: unexpected glyph properties %u/%u. Class %u. Font %s - %s.\n",
+ text[0], glyphs[0], glyph_props[0].isDiacritic, glyph_props[0].isZeroWidthSpace,
+ glyph_class, wine_dbgstr_w(family), wine_dbgstr_w(face));
+ break;
+ default:
+ break;
+ }
+
+ if (glyph_props[0].isDiacritic)
+ ok(glyph_props[0].isZeroWidthSpace,
+ "%#x -> %u: unexpected glyph properties %u/%u. Class %u. Font %s - %s.\n", text[0], glyphs[0],
+ glyph_props[0].isDiacritic, glyph_props[0].isZeroWidthSpace, glyph_class,
+ wine_dbgstr_w(family), wine_dbgstr_w(face));
+ }
+ }
+
+ heap_free(ranges);
+
+ IDWriteFontFace_ReleaseFontTable(fontface, gdef.context);
+ IDWriteFontFace1_Release(fontface1);
+}
+
static void test_GetGlyphs(void)
{
static const WCHAR test1W[] = {'<','B',' ','C',0};
@@ -1373,6 +1612,7 @@ static void test_GetGlyphs(void)
DWRITE_SHAPING_TEXT_PROPERTIES props[20];
UINT32 maxglyphcount, actual_count;
FLOAT advances[10], advances2[10];
+ IDWriteFontCollection *syscoll;
IDWriteTextAnalyzer *analyzer;
IDWriteFontFace *fontface;
DWRITE_SCRIPT_ANALYSIS sa;
@@ -1380,6 +1620,7 @@ static void test_GetGlyphs(void)
UINT16 clustermap[10];
UINT16 glyphs1[10];
UINT16 glyphs2[10];
+ unsigned int i, j;
HRESULT hr;
hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer);
@@ -1505,8 +1746,58 @@ if (0) {
ok(sa.script == 0, "got %u\n", sa.script);
ok(!shapingprops[0].isZeroWidthSpace, "got %d\n", shapingprops[0].isZeroWidthSpace);
- IDWriteTextAnalyzer_Release(analyzer);
IDWriteFontFace_Release(fontface);
+
+ /* Test setting glyph properties from GDEF. */
+if (strcmp(winetest_platform, "wine"))
+{
+
+ hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
+ ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
+
+ for (i = 0; i < IDWriteFontCollection_GetFontFamilyCount(syscoll); ++i)
+ {
+ IDWriteLocalizedStrings *names;
+ IDWriteFontFamily *family;
+ WCHAR familyW[256];
+
+ hr = IDWriteFontCollection_GetFontFamily(syscoll, i, &family);
+ ok(hr == S_OK, "Failed to get font family, hr %#x.\n", hr);
+
+ hr = IDWriteFontFamily_GetFamilyNames(family, &names);
+ ok(hr == S_OK, "Failed to get family names, hr %#x.\n", hr);
+ get_enus_string(names, familyW, ARRAY_SIZE(familyW));
+ IDWriteLocalizedStrings_Release(names);
+
+ for (j = 0; j < IDWriteFontFamily_GetFontCount(family); ++j)
+ {
+ IDWriteFont *font;
+ WCHAR faceW[256];
+
+ hr = IDWriteFontFamily_GetFont(family, j, &font);
+ ok(hr == S_OK, "Failed to get font instance, hr %#x.\n", hr);
+
+ hr = IDWriteFont_CreateFontFace(font, &fontface);
+ ok(hr == S_OK, "Failed to create fontface, hr %#x.\n", hr);
+
+ hr = IDWriteFont_GetFaceNames(font, &names);
+ ok(hr == S_OK, "Failed to get face names, hr %#x.\n", hr);
+ get_enus_string(names, faceW, ARRAY_SIZE(faceW));
+ IDWriteLocalizedStrings_Release(names);
+
+ test_glyph_props(analyzer, familyW, faceW, fontface);
+
+ IDWriteFontFace_Release(fontface);
+ IDWriteFont_Release(font);
+ }
+
+ IDWriteFontFamily_Release(family);
+ }
+
+ IDWriteFontCollection_Release(syscoll);
+}
+
+ IDWriteTextAnalyzer_Release(analyzer);
}
static BOOL has_feature(const DWRITE_FONT_FEATURE_TAG *tags, UINT32 count, DWRITE_FONT_FEATURE_TAG feature)
--
2.20.1
More information about the wine-devel
mailing list