dwrite: Return ranges for selected cmap.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
87ca6a068a
commit
f48ecfc83e
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue