[PATCH] dwrite/tests: Add some tests for GetUnicodeRanges().
Nikolay Sivov
nsivov at codeweavers.com
Mon Nov 26 02:43:09 CST 2018
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
Tests are disabled on Wine for now.
dlls/dwrite/tests/font.c | 356 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 355 insertions(+), 1 deletion(-)
diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c
index 86efb8cc05..f752afd08e 100644
--- a/dlls/dwrite/tests/font.c
+++ b/dlls/dwrite/tests/font.c
@@ -396,6 +396,66 @@ struct WOFFHeader2
ULONG privLength;
};
+struct cmap_encoding_record
+{
+ WORD platformID;
+ WORD encodingID;
+ DWORD offset;
+};
+
+struct cmap_header
+{
+ WORD version;
+ WORD numTables;
+ struct cmap_encoding_record tables[1];
+};
+
+struct cmap_segmented_coverage_group
+{
+ DWORD startCharCode;
+ DWORD endCharCode;
+ DWORD startGlyphID;
+};
+
+struct cmap_segmented_coverage
+{
+ WORD format;
+ WORD reserved;
+ DWORD length;
+ DWORD language;
+ DWORD nGroups;
+ struct cmap_segmented_coverage_group groups[1];
+};
+
+struct cmap_segmented_mapping_0
+{
+ WORD format;
+ WORD length;
+ WORD language;
+ WORD segCountX2;
+ WORD searchRange;
+ WORD entrySelector;
+ WORD rangeShift;
+ WORD endCode[1];
+};
+
+enum opentype_cmap_table_platform
+{
+ OPENTYPE_CMAP_TABLE_PLATFORM_WIN = 3,
+};
+
+enum opentype_cmap_table_encoding
+{
+ OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP = 1,
+ OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL = 10,
+};
+
+enum opentype_cmap_table_format
+{
+ OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING = 4,
+ OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE = 12,
+};
+
#include "poppack.h"
static void *create_factory_iid(REFIID riid)
@@ -3318,14 +3378,220 @@ static void test_shared_isolated(void)
ok(ref == 0, "factory not released, %u\n", ref);
}
+struct dwrite_fonttable
+{
+ BYTE *data;
+ void *context;
+ UINT32 size;
+};
+
+static WORD table_read_be_word(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
+{
+ if (!ptr)
+ ptr = table->data;
+
+ if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
+ return 0;
+
+ if (offset > table->size - sizeof(WORD))
+ return 0;
+
+ return GET_BE_WORD(*(WORD *)((BYTE *)ptr + offset));
+}
+
+static DWORD table_read_be_dword(const struct dwrite_fonttable *table, void *ptr, DWORD offset)
+{
+ if (!ptr)
+ ptr = table->data;
+
+ if ((BYTE *)ptr < table->data || (BYTE *)ptr - table->data >= table->size)
+ return 0;
+
+ if (offset > table->size - sizeof(WORD))
+ return 0;
+
+ return GET_BE_DWORD(*(DWORD *)((BYTE *)ptr + offset));
+}
+
+static void array_reserve(void **elements, size_t *capacity, size_t count, size_t size)
+{
+ size_t new_capacity, max_capacity;
+ void *new_elements;
+
+ if (count <= *capacity)
+ return;
+
+ max_capacity = ~(SIZE_T)0 / size;
+ if (count > max_capacity)
+ return;
+
+ new_capacity = max(4, *capacity);
+ while (new_capacity < count && new_capacity <= max_capacity / 2)
+ new_capacity *= 2;
+ if (new_capacity < count)
+ new_capacity = max_capacity;
+
+ if (!(new_elements = heap_realloc(*elements, new_capacity * size)))
+ return;
+
+ *elements = new_elements;
+ *capacity = new_capacity;
+}
+
+static void opentype_cmap_read_table(const struct dwrite_fonttable *table, UINT16 cmap_index, UINT32 *count,
+ size_t *capacity, DWRITE_UNICODE_RANGE **ranges)
+{
+ const BYTE *tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
+ struct cmap_encoding_record *record;
+ DWORD table_offset;
+ WORD format;
+ int j;
+
+ record = (struct cmap_encoding_record *)(tables + cmap_index * sizeof(*record));
+
+ if (!(table_offset = table_read_be_dword(table, record, FIELD_OFFSET(struct cmap_encoding_record, offset))))
+ return;
+
+ format = table_read_be_word(table, NULL, table_offset);
+ switch (format)
+ {
+ case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING:
+ {
+ UINT16 segment_count = table_read_be_word(table, NULL, table_offset +
+ FIELD_OFFSET(struct cmap_segmented_mapping_0, segCountX2)) / 2;
+ DWORD start_code_offset = table_offset + sizeof(struct cmap_segmented_mapping_0) +
+ sizeof(WORD) * segment_count;
+
+ for (j = 0; j < segment_count; ++j) {
+ WORD endcode = table_read_be_word(table, NULL, table_offset +
+ FIELD_OFFSET(struct cmap_segmented_mapping_0, endCode) + j * sizeof(WORD));
+ WORD first;
+
+ if (endcode == 0xffff)
+ break;
+
+ first = table_read_be_word(table, NULL, start_code_offset + j * sizeof(WORD));
+
+ array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
+ (*ranges)[*count].first = first;
+ (*ranges)[*count].last = endcode;
+ (*count)++;
+ }
+ break;
+ }
+ case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE:
+ {
+ DWORD num_groups = table_read_be_dword(table, NULL, table_offset +
+ FIELD_OFFSET(struct cmap_segmented_coverage, nGroups));
+
+ for (j = 0; j < num_groups; ++j) {
+ DWORD group_offset = table_offset + FIELD_OFFSET(struct cmap_segmented_coverage, groups) +
+ j * sizeof(struct cmap_segmented_coverage_group);
+ DWORD first = table_read_be_dword(table, NULL, group_offset +
+ FIELD_OFFSET(struct cmap_segmented_coverage_group, startCharCode));
+ DWORD last = table_read_be_dword(table, NULL, group_offset +
+ FIELD_OFFSET(struct cmap_segmented_coverage_group, endCharCode));
+
+ array_reserve((void **)ranges, capacity, *count + 1, sizeof(**ranges));
+ (*ranges)[*count].first = first;
+ (*ranges)[*count].last = last;
+ (*count)++;
+ }
+ break;
+ }
+ default:
+ ok(0, "%u table format %#x unhandled.\n", cmap_index, format);
+ }
+}
+
+static UINT32 opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *table, DWRITE_UNICODE_RANGE **ranges)
+{
+ int index_full = -1, index_bmp = -1;
+ unsigned int i, count = 0;
+ size_t capacity = 0;
+ const BYTE *tables;
+ WORD num_tables;
+
+ *ranges = NULL;
+
+ num_tables = table_read_be_word(table, 0, FIELD_OFFSET(struct cmap_header, numTables));
+ tables = table->data + FIELD_OFFSET(struct cmap_header, tables);
+
+ for (i = 0; i < num_tables; ++i)
+ {
+ struct cmap_encoding_record *record = (struct cmap_encoding_record *)(tables + i * sizeof(*record));
+ WORD platform, encoding;
+
+ platform = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, platformID));
+ encoding = table_read_be_word(table, record, FIELD_OFFSET(struct cmap_encoding_record, encodingID));
+
+ if (platform == OPENTYPE_CMAP_TABLE_PLATFORM_WIN)
+ {
+ if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_FULL)
+ {
+ index_full = i;
+ break;
+ }
+ else if (encoding == OPENTYPE_CMAP_TABLE_ENCODING_UNICODE_BMP)
+ index_bmp = i;
+ }
+ }
+
+ if (index_full != -1)
+ opentype_cmap_read_table(table, index_full, &count, &capacity, ranges);
+ else if (index_bmp != -1)
+ opentype_cmap_read_table(table, index_bmp, &count, &capacity, ranges);
+
+ return count;
+}
+
+static UINT32 fontface_get_expected_unicode_ranges(IDWriteFontFace1 *fontface, DWRITE_UNICODE_RANGE **out)
+{
+ struct dwrite_fonttable cmap;
+ DWRITE_UNICODE_RANGE *ranges;
+ UINT32 i, j, count;
+ BOOL exists;
+ HRESULT hr;
+
+ *out = NULL;
+
+ hr = IDWriteFontFace1_TryGetFontTable(fontface, MS_CMAP_TAG, (const void **)&cmap.data,
+ &cmap.size, &cmap.context, &exists);
+ if (FAILED(hr) || !exists)
+ return 0;
+
+ count = opentype_cmap_get_unicode_ranges(&cmap, &ranges);
+ IDWriteFontFace1_ReleaseFontTable(fontface, cmap.context);
+
+ *out = heap_alloc(count * sizeof(**out));
+
+ /* Eliminate duplicates and merge ranges together. */
+ for (i = 0, j = 0; i < count; ++i) {
+ if (j) {
+ DWRITE_UNICODE_RANGE *prev = &(*out)[j-1];
+ /* Merge adjacent ranges. */
+ if (ranges[i].first == prev->last + 1) {
+ prev->last = ranges[i].last;
+ continue;
+ }
+ }
+ (*out)[j++] = ranges[i];
+ }
+
+ heap_free(ranges);
+
+ return j;
+}
+
static void test_GetUnicodeRanges(void)
{
+ IDWriteFontCollection *syscollection;
DWRITE_UNICODE_RANGE *ranges, r;
IDWriteFontFile *ffile = NULL;
IDWriteFontFace1 *fontface1;
IDWriteFontFace *fontface;
IDWriteFactory *factory;
- UINT32 count;
+ UINT32 count, i;
HRESULT hr;
HRSRC font;
ULONG ref;
@@ -3383,6 +3649,94 @@ static void test_GetUnicodeRanges(void)
ok(hr == S_OK, "got 0x%08x\n", hr);
IDWriteFontFace1_Release(fontface1);
+
+if (strcmp(winetest_platform, "wine")) {
+
+ hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
+ ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
+
+ count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
+
+ for (i = 0; i < count; i++) {
+ WCHAR familynameW[256], facenameW[128];
+ IDWriteLocalizedStrings *names;
+ IDWriteFontFamily *family;
+ UINT32 j, k, fontcount;
+ IDWriteFont *font;
+
+ hr = IDWriteFontCollection_GetFontFamily(syscollection, 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, familynameW, ARRAY_SIZE(familynameW));
+ IDWriteLocalizedStrings_Release(names);
+
+ fontcount = IDWriteFontFamily_GetFontCount(family);
+ for (j = 0; j < fontcount; j++) {
+ DWRITE_UNICODE_RANGE *expected_ranges = NULL;
+ UINT32 range_count, expected_count;
+
+ hr = IDWriteFontFamily_GetFont(family, j, &font);
+ ok(hr == S_OK, "Failed to get font, 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);
+ IDWriteFont_Release(font);
+
+ get_enus_string(names, facenameW, ARRAY_SIZE(facenameW));
+
+ IDWriteLocalizedStrings_Release(names);
+
+ if (IDWriteFontFace_IsSymbolFont(fontface)) {
+ skip("Skipping for symbol font %s %s.\n", wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW));
+ IDWriteFontFace_Release(fontface);
+ continue;
+ }
+
+ IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1);
+
+ hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &range_count);
+ ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
+
+ ranges = heap_alloc(range_count * sizeof(*ranges));
+
+ hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, range_count, ranges, &range_count);
+ ok(hr == S_OK, "Failed to get ranges, hr %#x.\n", hr);
+
+ expected_count = fontface_get_expected_unicode_ranges(fontface1, &expected_ranges);
+ ok(expected_count == range_count, "%s - %s: unexpected range count %u, expected %u.\n",
+ wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), range_count, expected_count);
+
+ if (expected_count == range_count) {
+ if (memcmp(expected_ranges, ranges, expected_count * sizeof(*ranges))) {
+ for (k = 0; k < expected_count; ++k) {
+ BOOL failed = memcmp(&expected_ranges[k], &ranges[k], sizeof(*ranges));
+ ok(!failed, "%u: %s - %s mismatching range [%#x, %#x] vs [%#x, %#x].\n", k,
+ wine_dbgstr_w(familynameW), wine_dbgstr_w(facenameW), ranges[k].first, ranges[k].last,
+ expected_ranges[k].first, expected_ranges[k].last);
+ if (failed)
+ break;
+ }
+ }
+ }
+
+ heap_free(expected_ranges);
+ heap_free(ranges);
+
+ IDWriteFontFace1_Release(fontface1);
+ IDWriteFontFace_Release(fontface);
+ }
+
+ IDWriteFontFamily_Release(family);
+ }
+
+ IDWriteFontCollection_Release(syscollection);
+}
ref = IDWriteFactory_Release(factory);
ok(ref == 0, "factory not released, %u\n", ref);
}
--
2.19.2
More information about the wine-devel
mailing list