From f48ecfc83e574993bebbbfffd394170a66523e2b Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Wed, 10 Jun 2020 17:21:29 +0300 Subject: [PATCH] dwrite: Return ranges for selected cmap. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/dwrite/dwrite_private.h | 7 +- dlls/dwrite/font.c | 18 +--- dlls/dwrite/opentype.c | 188 ++++++++++++++--------------------- 3 files changed, 81 insertions(+), 132 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 2a8a4d47414..a9fbb260e35 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -198,6 +198,8 @@ enum font_flags struct dwrite_cmap; typedef UINT16 (*p_cmap_get_glyph_func)(const struct dwrite_cmap *cmap, unsigned int ch); +typedef unsigned int (*p_cmap_get_ranges_func)(const struct dwrite_cmap *cmap, unsigned int max_count, + DWRITE_UNICODE_RANGE *ranges); struct dwrite_cmap { @@ -226,6 +228,7 @@ struct dwrite_cmap } format12_13; } u; p_cmap_get_glyph_func get_glyph; + p_cmap_get_ranges_func get_ranges; unsigned short symbol : 1; IDWriteFontFileStream *stream; void *table_context; @@ -235,6 +238,8 @@ extern void dwrite_cmap_init(struct dwrite_cmap *cmap, IDWriteFontFile *file, un DWRITE_FONT_FACE_TYPE face_type) DECLSPEC_HIDDEN; extern void dwrite_cmap_release(struct dwrite_cmap *cmap) DECLSPEC_HIDDEN; extern UINT16 opentype_cmap_get_glyph(const struct dwrite_cmap *cmap, unsigned int ch) DECLSPEC_HIDDEN; +extern HRESULT opentype_cmap_get_unicode_ranges(const struct dwrite_cmap *cmap, unsigned int max_count, + DWRITE_UNICODE_RANGE *ranges, unsigned int *count) DECLSPEC_HIDDEN; struct dwrite_fontface { @@ -387,8 +392,6 @@ struct ot_gsubgpos_table extern HRESULT opentype_analyze_font(IDWriteFontFileStream*,BOOL*,DWRITE_FONT_FILE_TYPE*,DWRITE_FONT_FACE_TYPE*,UINT32*) DECLSPEC_HIDDEN; extern HRESULT opentype_try_get_font_table(const struct file_stream_desc *stream_desc, UINT32 tag, const void **data, void **context, UINT32 *size, BOOL *exists) DECLSPEC_HIDDEN; -extern HRESULT opentype_cmap_get_unicode_ranges(const struct file_stream_desc *stream_desc, unsigned int max_count, - DWRITE_UNICODE_RANGE *ranges, unsigned int *count) DECLSPEC_HIDDEN; extern void opentype_get_font_properties(struct file_stream_desc*,struct dwrite_font_props*) DECLSPEC_HIDDEN; extern void opentype_get_font_metrics(struct file_stream_desc*,DWRITE_FONT_METRICS1*,DWRITE_CARET_METRICS*) DECLSPEC_HIDDEN; extern void opentype_get_font_typo_metrics(struct file_stream_desc *stream_desc, unsigned int *ascent, diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 7f5cce4e4b2..ab60d4368c7 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -1005,7 +1005,6 @@ static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, DWRITE_UNICODE_RANGE *ranges, UINT32 *count) { struct dwrite_fontface *fontface = impl_from_IDWriteFontFace5(iface); - struct file_stream_desc stream_desc; TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count); @@ -1013,10 +1012,8 @@ static HRESULT WINAPI dwritefontface1_GetUnicodeRanges(IDWriteFontFace5 *iface, if (max_count && !ranges) return E_INVALIDARG; - stream_desc.stream = fontface->stream; - stream_desc.face_index = fontface->index; - stream_desc.face_type = fontface->type; - return opentype_cmap_get_unicode_ranges(&stream_desc, max_count, ranges, count); + dwrite_cmap_init(&fontface->cmap, NULL, fontface->index, fontface->type); + return opentype_cmap_get_unicode_ranges(&fontface->cmap, max_count, ranges, count); } static BOOL WINAPI dwritefontface1_IsMonospacedFont(IDWriteFontFace5 *iface) @@ -2000,8 +1997,6 @@ static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 m UINT32 *count) { struct dwrite_font *font = impl_from_IDWriteFont3(iface); - struct file_stream_desc stream_desc; - HRESULT hr; TRACE("%p, %u, %p, %p.\n", iface, max_count, ranges, count); @@ -2009,13 +2004,8 @@ static HRESULT WINAPI dwritefont1_GetUnicodeRanges(IDWriteFont3 *iface, UINT32 m if (max_count && !ranges) return E_INVALIDARG; - if (FAILED(hr = get_filestream_from_file(font->data->file, &stream_desc.stream))) - return hr; - stream_desc.face_index = font->data->face_index; - stream_desc.face_type = font->data->face_type; - hr = opentype_cmap_get_unicode_ranges(&stream_desc, max_count, ranges, count); - IDWriteFontFileStream_Release(stream_desc.stream); - return hr; + dwrite_cmap_init(&font->data->cmap, font->data->file, font->data->face_index, font->data->face_type); + return opentype_cmap_get_unicode_ranges(&font->data->cmap, max_count, ranges, count); } static BOOL WINAPI dwritefont1_IsMonospacedFont(IDWriteFont3 *iface) diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 563154992ab..d8bfa3f7f6d 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -1571,6 +1571,18 @@ static UINT16 opentype_cmap_format0_get_glyph(const struct dwrite_cmap *cmap, un return (ch < 0xff) ? glyphs[ch] : 0; } +static unsigned int opentype_cmap_format0_get_ranges(const struct dwrite_cmap *cmap, unsigned int count, + DWRITE_UNICODE_RANGE *ranges) +{ + if (count > 0) + { + ranges->first = 0; + ranges->last = 255; + } + + return 1; +} + struct cmap_format4_compare_context { const struct dwrite_cmap *cmap; @@ -1627,6 +1639,22 @@ static UINT16 opentype_cmap_format4_get_glyph(const struct dwrite_cmap *cmap, un return glyph & 0xffff; } +static unsigned int opentype_cmap_format4_get_ranges(const struct dwrite_cmap *cmap, unsigned int count, + DWRITE_UNICODE_RANGE *ranges) +{ + unsigned int i; + + count = min(count, cmap->u.format4.seg_count); + + for (i = 0; i < count; ++i) + { + ranges[i].first = GET_BE_WORD(cmap->u.format4.starts[i]); + ranges[i].last = GET_BE_WORD(cmap->u.format4.ends[i]); + } + + return cmap->u.format4.seg_count; +} + static UINT16 opentype_cmap_format6_10_get_glyph(const struct dwrite_cmap *cmap, unsigned int ch) { const UINT16 *glyphs = cmap->data; @@ -1634,6 +1662,18 @@ static UINT16 opentype_cmap_format6_10_get_glyph(const struct dwrite_cmap *cmap, return glyphs[ch - cmap->u.format6_10.first]; } +static unsigned int opentype_cmap_format6_10_get_ranges(const struct dwrite_cmap *cmap, unsigned int count, + DWRITE_UNICODE_RANGE *ranges) +{ + if (count > 0) + { + ranges->first = cmap->u.format6_10.first; + ranges->last = cmap->u.format6_10.last; + } + + return 1; +} + static int cmap_format12_13_compare_group(const void *a, const void *b) { const unsigned int *ch = a; @@ -1661,6 +1701,23 @@ static UINT16 opentype_cmap_format12_get_glyph(const struct dwrite_cmap *cmap, u GET_BE_DWORD(group_found[2]) + (ch - GET_BE_DWORD(group_found[0])) : 0; } +static unsigned int opentype_cmap_format12_13_get_ranges(const struct dwrite_cmap *cmap, unsigned int count, + DWRITE_UNICODE_RANGE *ranges) +{ + unsigned int i, group_count = cmap->u.format12_13.group_count; + const UINT32 *groups = cmap->data; + + count = min(count, group_count); + + for (i = 0; i < count; ++i) + { + ranges[i].first = GET_BE_DWORD(groups[3 * i]); + ranges[i].last = GET_BE_DWORD(groups[3 * i + 1]); + } + + return group_count; +} + static UINT16 opentype_cmap_format13_get_glyph(const struct dwrite_cmap *cmap, unsigned int ch) { const UINT32 *groups = cmap->data; @@ -1678,6 +1735,12 @@ static UINT16 opentype_cmap_dummy_get_glyph(const struct dwrite_cmap *cmap, unsi return 0; } +static unsigned int opentype_cmap_dummy_get_ranges(const struct dwrite_cmap *cmap, unsigned int count, + DWRITE_UNICODE_RANGE *ranges) +{ + return 0; +} + UINT16 opentype_cmap_get_glyph(const struct dwrite_cmap *cmap, unsigned int ch) { UINT16 glyph; @@ -1771,6 +1834,7 @@ void dwrite_cmap_init(struct dwrite_cmap *cmap, IDWriteFontFile *file, unsigned case 0: cmap->data = table_read_ensure(&table, offset + 6, 256); cmap->get_glyph = opentype_cmap_format0_get_glyph; + cmap->get_ranges = opentype_cmap_format0_get_ranges; break; case 4: length = table_read_be_word(&table, offset + 2); @@ -1782,6 +1846,7 @@ void dwrite_cmap_init(struct dwrite_cmap *cmap, IDWriteFontFile *file, unsigned cmap->u.format4.glyph_id_array = cmap->data = cmap->u.format4.id_range_offset + count; cmap->u.format4.glyph_id_array_len = (length - 16 - 8 * count) / 2; cmap->get_glyph = opentype_cmap_format4_get_glyph; + cmap->get_ranges = opentype_cmap_format4_get_ranges; break; case 6: case 10: @@ -1792,12 +1857,14 @@ void dwrite_cmap_init(struct dwrite_cmap *cmap, IDWriteFontFile *file, unsigned cmap->u.format6_10.last = cmap->u.format6_10.first + count; cmap->data = table_read_ensure(&table, offset + f * 10, count * 2); cmap->get_glyph = opentype_cmap_format6_10_get_glyph; + cmap->get_ranges = opentype_cmap_format6_10_get_ranges; break; case 12: case 13: cmap->u.format12_13.group_count = count = table_read_be_dword(&table, offset + 12); cmap->data = table_read_ensure(&table, offset + 16, count * 3 * 4); cmap->get_glyph = format == 12 ? opentype_cmap_format12_get_glyph : opentype_cmap_format13_get_glyph; + cmap->get_ranges = opentype_cmap_format12_13_get_ranges; break; default: WARN("Unhandled subtable format %u.\n", format); @@ -1810,6 +1877,7 @@ failed: /* Dummy implementation, returns 0 unconditionally. */ cmap->data = cmap; cmap->get_glyph = opentype_cmap_dummy_get_glyph; + cmap->get_ranges = opentype_cmap_dummy_get_ranges; } } @@ -1824,125 +1892,13 @@ void dwrite_cmap_release(struct dwrite_cmap *cmap) cmap->stream = NULL; } -static unsigned int opentype_cmap_get_unicode_ranges_count(const struct dwrite_fonttable *cmap) +HRESULT opentype_cmap_get_unicode_ranges(const struct dwrite_cmap *cmap, unsigned int max_count, DWRITE_UNICODE_RANGE *ranges, + unsigned int *count) { - unsigned int i, num_tables, count = 0; - const struct cmap_header *header; - - num_tables = table_read_be_word(cmap, FIELD_OFFSET(struct cmap_header, num_tables)); - header = table_read_ensure(cmap, 0, FIELD_OFFSET(struct cmap_header, tables[num_tables])); - - if (!header) - return 0; - - for (i = 0; i < num_tables; ++i) - { - unsigned int format, offset; - - if (GET_BE_WORD(header->tables[i].platformID) != 3) - continue; - - offset = GET_BE_DWORD(header->tables[i].offset); - format = table_read_be_word(cmap, offset); - - switch (format) - { - case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: - { - count += table_read_be_word(cmap, offset + FIELD_OFFSET(struct cmap_segment_mapping, seg_count_x2)) / 2; - break; - } - case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: - { - count += table_read_be_dword(cmap, offset + FIELD_OFFSET(struct cmap_segmented_coverage, num_groups)); - break; - } - default: - FIXME("table format %u is not supported.\n", format); - } - } - - return count; -} - -HRESULT opentype_cmap_get_unicode_ranges(const struct file_stream_desc *stream_desc, unsigned int max_count, - DWRITE_UNICODE_RANGE *ranges, unsigned int *count) -{ - unsigned int i, num_tables, k = 0; - const struct cmap_header *header; - struct dwrite_fonttable cmap; - - opentype_get_font_table(stream_desc, MS_CMAP_TAG, &cmap); - - if (!cmap.exists) + if (!cmap->data) return E_FAIL; - *count = opentype_cmap_get_unicode_ranges_count(&cmap); - - num_tables = table_read_be_word(&cmap, FIELD_OFFSET(struct cmap_header, num_tables)); - header = table_read_ensure(&cmap, 0, FIELD_OFFSET(struct cmap_header, tables[num_tables])); - - if (!header) - { - IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, cmap.context); - return S_OK; - } - - for (i = 0; i < num_tables && k < max_count; ++i) - { - unsigned int j, offset, format; - - if (GET_BE_WORD(header->tables[i].platformID) != 3) - continue; - - offset = GET_BE_DWORD(header->tables[i].offset); - - format = table_read_be_word(&cmap, offset); - switch (format) - { - case OPENTYPE_CMAP_TABLE_SEGMENT_MAPPING: - { - unsigned int segment_count = table_read_be_word(&cmap, offset + - FIELD_OFFSET(struct cmap_segment_mapping, seg_count_x2)) / 2; - const UINT16 *start_code = table_read_ensure(&cmap, offset, - FIELD_OFFSET(struct cmap_segment_mapping, end_code[segment_count]) + - 2 /* reservedPad */ + - 2 * segment_count /* start code array */); - const UINT16 *end_code = table_read_ensure(&cmap, offset, - FIELD_OFFSET(struct cmap_segment_mapping, end_code[segment_count])); - - if (!start_code || !end_code) - continue; - - for (j = 0; j < segment_count && GET_BE_WORD(end_code[j]) != 0xffff && k < max_count; ++j, ++k) - { - ranges[k].first = GET_BE_WORD(start_code[j]); - ranges[k].last = GET_BE_WORD(end_code[j]); - } - break; - } - case OPENTYPE_CMAP_TABLE_SEGMENTED_COVERAGE: - { - unsigned int num_groups = table_read_be_dword(&cmap, offset + - FIELD_OFFSET(struct cmap_segmented_coverage, num_groups)); - const struct cmap_segmented_coverage *coverage; - - coverage = table_read_ensure(&cmap, offset, - FIELD_OFFSET(struct cmap_segmented_coverage, groups[num_groups])); - - for (j = 0; j < num_groups && k < max_count; j++, k++) - { - ranges[k].first = GET_BE_DWORD(coverage->groups[j].startCharCode); - ranges[k].last = GET_BE_DWORD(coverage->groups[j].endCharCode); - } - break; - } - default: - FIXME("table format %u unhandled.\n", format); - } - } - - IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, cmap.context); + *count = cmap->get_ranges(cmap, max_count, ranges); return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK; }