dwrite: Handle extension substitution (GSUB lookup 7).
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
3cf308d1b8
commit
3abcf68af9
|
@ -547,7 +547,7 @@ enum OPENTYPE_PLATFORM_ID
|
|||
OPENTYPE_PLATFORM_CUSTOM
|
||||
};
|
||||
|
||||
struct ot_gsubgpos_extensionpos_format1
|
||||
struct ot_gsubgpos_extension_format1
|
||||
{
|
||||
UINT16 format;
|
||||
UINT16 lookup_type;
|
||||
|
@ -3385,7 +3385,7 @@ static unsigned int opentype_layout_get_gpos_subtable(const struct scriptshaping
|
|||
FIELD_OFFSET(struct ot_lookup_table, subtable[subtable]));
|
||||
if (lookup_type == GPOS_LOOKUP_EXTENSION_POSITION)
|
||||
{
|
||||
const struct ot_gsubgpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gpos.table,
|
||||
const struct ot_gsubgpos_extension_format1 *format1 = table_read_ensure(&cache->gpos.table,
|
||||
lookup_offset + subtable_offset, sizeof(*format1));
|
||||
subtable_offset += GET_BE_DWORD(format1->extension_offset);
|
||||
}
|
||||
|
@ -3393,18 +3393,11 @@ static unsigned int opentype_layout_get_gpos_subtable(const struct scriptshaping
|
|||
return lookup_offset + subtable_offset;
|
||||
}
|
||||
|
||||
static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping_cache *cache,
|
||||
static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping_context *context,
|
||||
unsigned int lookup_offset, unsigned int subtable)
|
||||
{
|
||||
UINT16 lookup_type = table_read_be_word(&cache->gsub.table, lookup_offset);
|
||||
unsigned int subtable_offset = table_read_be_word(&cache->gsub.table, lookup_offset +
|
||||
unsigned int subtable_offset = table_read_be_word(&context->table->table, lookup_offset +
|
||||
FIELD_OFFSET(struct ot_lookup_table, subtable[subtable]));
|
||||
if (lookup_type == GSUB_LOOKUP_EXTENSION_SUBST)
|
||||
{
|
||||
const struct ot_gsubgpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gsub.table,
|
||||
lookup_offset + subtable_offset, sizeof(*format1));
|
||||
subtable_offset += GET_BE_DWORD(format1->extension_offset);
|
||||
}
|
||||
|
||||
return lookup_offset + subtable_offset;
|
||||
}
|
||||
|
@ -4086,7 +4079,7 @@ static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont
|
|||
lookup_type = GET_BE_WORD(lookup_table->lookup_type);
|
||||
if (lookup_type == GPOS_LOOKUP_EXTENSION_POSITION)
|
||||
{
|
||||
const struct ot_gsubgpos_extensionpos_format1 *extension = table_read_ensure(&cache->gpos.table,
|
||||
const struct ot_gsubgpos_extension_format1 *extension = table_read_ensure(&cache->gpos.table,
|
||||
lookup.offset + GET_BE_WORD(lookup_table->subtable[0]), sizeof(*extension));
|
||||
WORD format;
|
||||
|
||||
|
@ -4462,22 +4455,17 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
|
|||
heap_free(lookups.lookups);
|
||||
}
|
||||
|
||||
static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup)
|
||||
static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup,
|
||||
unsigned int subtable_offset)
|
||||
{
|
||||
struct scriptshaping_cache *cache = context->cache;
|
||||
const struct dwrite_fonttable *gsub = &context->table->table;
|
||||
UINT16 format, coverage, orig_glyph, glyph;
|
||||
unsigned int i, idx;
|
||||
unsigned int idx, coverage_index;
|
||||
BOOL ret;
|
||||
|
||||
idx = context->cur;
|
||||
orig_glyph = glyph = context->u.subst.glyphs[idx];
|
||||
|
||||
for (i = 0; i < lookup->subtable_count; ++i)
|
||||
{
|
||||
unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i);
|
||||
unsigned int coverage_index;
|
||||
|
||||
format = table_read_be_word(gsub, subtable_offset);
|
||||
|
||||
coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage));
|
||||
|
@ -4488,10 +4476,9 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_
|
|||
|
||||
coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
|
||||
if (coverage_index == GLYPH_NOT_COVERED)
|
||||
continue;
|
||||
return FALSE;
|
||||
|
||||
glyph = orig_glyph + GET_BE_WORD(format1->delta);
|
||||
break;
|
||||
}
|
||||
else if (format == 2)
|
||||
{
|
||||
|
@ -4501,14 +4488,12 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_
|
|||
|
||||
coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
|
||||
if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count)
|
||||
continue;
|
||||
return FALSE;
|
||||
|
||||
glyph = GET_BE_WORD(format2->substitutes[coverage_index]);
|
||||
break;
|
||||
}
|
||||
else
|
||||
WARN("Unknown single substitution format %u.\n", format);
|
||||
}
|
||||
|
||||
if ((ret = (glyph != orig_glyph)))
|
||||
{
|
||||
|
@ -4684,21 +4669,16 @@ static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct scriptshaping
|
|||
}
|
||||
|
||||
static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context,
|
||||
const struct lookup *lookup)
|
||||
const struct lookup *lookup, unsigned int subtable_offset)
|
||||
{
|
||||
struct scriptshaping_cache *cache = context->cache;
|
||||
const struct dwrite_fonttable *table = &context->table->table;
|
||||
UINT16 format, coverage;
|
||||
BOOL ret = FALSE;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < lookup->subtable_count; ++i)
|
||||
{
|
||||
unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i);
|
||||
UINT16 glyph = context->u.subst.glyphs[context->cur];
|
||||
unsigned int coverage_index = GLYPH_NOT_COVERED;
|
||||
UINT16 glyph, format, coverage;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
format = table_read_be_word(&context->table->table, subtable_offset);
|
||||
glyph = context->u.subst.glyphs[context->cur];
|
||||
|
||||
format = table_read_be_word(table, subtable_offset);
|
||||
|
||||
if (format == 1)
|
||||
{
|
||||
|
@ -4707,21 +4687,20 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
|
|||
|
||||
coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
|
||||
if (coverage_index == GLYPH_NOT_COVERED)
|
||||
continue;
|
||||
return FALSE;
|
||||
|
||||
WARN("Chaining contextual substitution (1) is not supported.\n");
|
||||
break;
|
||||
}
|
||||
else if (format == 2)
|
||||
{
|
||||
coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
|
||||
coverage = table_read_be_word(table, subtable_offset +
|
||||
FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
|
||||
|
||||
coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
|
||||
if (coverage_index == GLYPH_NOT_COVERED)
|
||||
continue;
|
||||
return FALSE;
|
||||
|
||||
WARN("Chaining contextual substitution (2) is not supported.\n");
|
||||
break;
|
||||
}
|
||||
else if (format == 3)
|
||||
{
|
||||
|
@ -4753,32 +4732,61 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
|
|||
coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[0]), glyph);
|
||||
|
||||
if (coverage_index == GLYPH_NOT_COVERED)
|
||||
continue;
|
||||
return FALSE;
|
||||
|
||||
if ((ret = opentype_layout_apply_gsub_chain_context_lookup(context, subtable_offset, backtrack_count, backtrack,
|
||||
input_count, input + 1, lookahead_count, lookahead, lookup_count, lookup_records)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
ret = opentype_layout_apply_gsub_chain_context_lookup(context, subtable_offset, backtrack_count, backtrack,
|
||||
input_count, input + 1, lookahead_count, lookahead, lookup_count, lookup_records);
|
||||
}
|
||||
else
|
||||
WARN("Unknown chaining contextual substitution format %u.\n", format);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int opentype_layout_adjust_extension_subtable(struct scriptshaping_context *context,
|
||||
unsigned int *subtable_offset)
|
||||
{
|
||||
const struct ot_gsubgpos_extension_format1 *format1;
|
||||
|
||||
if (!(format1 = table_read_ensure(&context->table->table, *subtable_offset, sizeof(*format1))))
|
||||
return 0;
|
||||
|
||||
if (GET_BE_WORD(format1->format) != 1)
|
||||
{
|
||||
WARN("Unexpected extension table format %#x.\n", format1->format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*subtable_offset = *subtable_offset + GET_BE_DWORD(format1->extension_offset);
|
||||
|
||||
return GET_BE_WORD(format1->lookup_type);
|
||||
}
|
||||
|
||||
static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup)
|
||||
{
|
||||
unsigned int i, lookup_type;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
switch (lookup->type)
|
||||
for (i = 0; i < lookup->subtable_count; ++i)
|
||||
{
|
||||
unsigned int subtable_offset = opentype_layout_get_gsub_subtable(context, lookup->offset, i);
|
||||
|
||||
if (lookup->type == GSUB_LOOKUP_EXTENSION_SUBST)
|
||||
{
|
||||
lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset);
|
||||
if (!lookup_type)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
lookup_type = lookup->type;
|
||||
|
||||
switch (lookup_type)
|
||||
{
|
||||
case GSUB_LOOKUP_SINGLE_SUBST:
|
||||
ret = opentype_layout_apply_gsub_single_substitution(context, lookup);
|
||||
ret = opentype_layout_apply_gsub_single_substitution(context, lookup, subtable_offset);
|
||||
break;
|
||||
case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST:
|
||||
ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup);
|
||||
ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup, subtable_offset);
|
||||
break;
|
||||
case GSUB_LOOKUP_MULTIPLE_SUBST:
|
||||
case GSUB_LOOKUP_ALTERNATE_SUBST:
|
||||
|
@ -4787,8 +4795,15 @@ static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont
|
|||
case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST:
|
||||
WARN("Unimplemented lookup %d.\n", lookup->type);
|
||||
break;
|
||||
case GSUB_LOOKUP_EXTENSION_SUBST:
|
||||
WARN("Invalid lookup type for extension substitution %#x.\n", lookup_type);
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown lookup type %u.\n", lookup->type);
|
||||
WARN("Unknown lookup type %u.\n", lookup_type);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue