Nikolay Sivov : dwrite: Implement alternate substitution (GSUB lookup 3).
Alexandre Julliard
julliard at winehq.org
Wed May 27 15:19:30 CDT 2020
Module: wine
Branch: master
Commit: d5058fb304b72d6a0a836780ad865c6100d1a4c8
URL: https://source.winehq.org/git/wine.git/?a=commit;h=d5058fb304b72d6a0a836780ad865c6100d1a4c8
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Wed May 27 10:14:23 2020 +0300
dwrite: Implement alternate substitution (GSUB lookup 3).
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/dwrite/opentype.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 83 insertions(+), 1 deletion(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 81b6aaa229..c815165505 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -569,6 +569,14 @@ struct ot_gsub_singlesubst_format2
UINT16 substitutes[1];
};
+struct ot_gsub_altsubst_format1
+{
+ UINT16 format;
+ UINT16 coverage;
+ UINT16 count;
+ UINT16 sets[1];
+};
+
struct ot_gsub_chaincontext_subst_format1
{
UINT16 format;
@@ -3256,6 +3264,23 @@ static inline unsigned int dwrite_popcount(unsigned int x)
#endif
}
+static inline unsigned int dwrite_ctz(unsigned int x)
+{
+#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))
+ return __builtin_ctz(x);
+#else
+ unsigned int c = 32;
+ x &= - (int) x;
+ if (x) c--;
+ if (x & 0x0000ffff) c -= 16;
+ if (x & 0x00ff00ff) c -= 8;
+ if (x & 0x0f0f0f0f) c -= 4;
+ if (x & 0x33333333) c -= 2;
+ if (x & 0x55555555) c -= 1;
+ return c;
+#endif
+}
+
static inline unsigned int dwrite_log2i(unsigned int x)
{
#if defined(__GNUC__) && ((__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))
@@ -4505,6 +4530,61 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_
return ret;
}
+static BOOL opentype_layout_apply_gsub_alt_substitution(struct scriptshaping_context *context, const struct lookup *lookup,
+ unsigned int subtable_offset)
+{
+ const struct dwrite_fonttable *gsub = &context->table->table;
+ UINT16 format, coverage, orig_glyph, glyph;
+ unsigned int idx, coverage_index, offset;
+ BOOL ret;
+
+ idx = context->cur;
+ orig_glyph = glyph = context->u.subst.glyphs[idx];
+
+ format = table_read_be_word(gsub, subtable_offset);
+
+ if (format == 1)
+ {
+ const struct ot_gsub_altsubst_format1 *format1 = table_read_ensure(gsub, subtable_offset, sizeof(*format1));
+ unsigned int count, shift, alt_index;
+
+ coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_altsubst_format1, coverage));
+
+ coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
+ if (coverage_index == GLYPH_NOT_COVERED)
+ return FALSE;
+
+ if (coverage_index >= GET_BE_WORD(format1->count))
+ return FALSE;
+
+ offset = table_read_be_word(gsub, subtable_offset +
+ FIELD_OFFSET(struct ot_gsub_altsubst_format1, sets[coverage_index]));
+
+ count = table_read_be_word(gsub, subtable_offset + offset);
+ if (!count)
+ return FALSE;
+
+ shift = dwrite_ctz(lookup->mask);
+ alt_index = (lookup->mask & context->glyph_infos[idx].mask) >> shift;
+
+ if (alt_index > count || !alt_index)
+ return FALSE;
+
+ glyph = table_read_be_word(gsub, subtable_offset + offset + sizeof(count) + (alt_index - 1) * sizeof(glyph));
+ }
+ else
+ WARN("Unexpected alternate substitution format %d.\n", format);
+
+ if ((ret = (glyph != orig_glyph)))
+ {
+ context->u.subst.glyphs[idx] = glyph;
+ opentype_set_subst_glyph_props(context, idx, glyph);
+ context->cur++;
+ }
+
+ return ret;
+}
+
#define CHAIN_CONTEXT_MAX_LENGTH 64
static BOOL opentype_layout_context_match_input(struct scriptshaping_context *context, unsigned int subtable_offset,
@@ -4785,11 +4865,13 @@ static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont
case GSUB_LOOKUP_SINGLE_SUBST:
ret = opentype_layout_apply_gsub_single_substitution(context, lookup, subtable_offset);
break;
+ case GSUB_LOOKUP_ALTERNATE_SUBST:
+ ret = opentype_layout_apply_gsub_alt_substitution(context, lookup, subtable_offset);
+ break;
case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST:
ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup, subtable_offset);
break;
case GSUB_LOOKUP_MULTIPLE_SUBST:
- case GSUB_LOOKUP_ALTERNATE_SUBST:
case GSUB_LOOKUP_LIGATURE_SUBST:
case GSUB_LOOKUP_CONTEXTUAL_SUBST:
case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST:
More information about the wine-cvs
mailing list