[PATCH 5/6] dwrite: Implement single substitution lookup (GSUB lookup 1).
Nikolay Sivov
nsivov at codeweavers.com
Mon May 4 03:29:34 CDT 2020
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/analyzer.c | 4 +
dlls/dwrite/dwrite_private.h | 6 ++
dlls/dwrite/opentype.c | 165 ++++++++++++++++++++++++++++++++---
3 files changed, 164 insertions(+), 11 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index bc5c54f21e..5ee057028f 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -1252,6 +1252,10 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
context.length = length;
context.is_rtl = is_rtl;
context.is_sideways = is_sideways;
+ context.u.subst.glyphs = glyphs;
+ context.u.subst.glyph_props = glyph_props;
+ context.u.subst.max_glyph_count = max_glyph_count;
+ context.glyph_count = g;
context.language_tag = get_opentype_language(locale);
script = analysis->script > Script_LastId ? Script_Unknown : analysis->script;
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 7a8ce1e499..28ac05a1c1 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -478,6 +478,12 @@ struct scriptshaping_context
const UINT16 *glyphs;
const DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
} pos;
+ struct
+ {
+ UINT16 *glyphs;
+ DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props;
+ unsigned int max_glyph_count;
+ } subst;
} u;
unsigned int glyph_count;
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index b5947a8960..e1bfee097b 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -507,6 +507,18 @@ enum gpos_lookup_type
GPOS_LOOKUP_EXTENSION_POSITION = 9,
};
+enum gsub_lookup_type
+{
+ GSUB_LOOKUP_SINGLE_SUBST = 1,
+ GSUB_LOOKUP_MULTIPLE_SUBST = 2,
+ GSUB_LOOKUP_ALTERNATE_SUBST = 3,
+ GSUB_LOOKUP_LIGATURE_SUBST = 4,
+ GSUB_LOOKUP_CONTEXTUAL_SUBST = 5,
+ GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST = 6,
+ GSUB_LOOKUP_EXTENSION_SUBST = 7,
+ GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST = 8,
+};
+
enum gpos_value_format
{
GPOS_VALUE_X_PLACEMENT = 0x1,
@@ -528,13 +540,28 @@ enum OPENTYPE_PLATFORM_ID
OPENTYPE_PLATFORM_CUSTOM
};
-struct ot_gpos_extensionpos_format1
+struct ot_gsubgpos_extensionpos_format1
{
- WORD format;
- WORD lookup_type;
+ UINT16 format;
+ UINT16 lookup_type;
DWORD extension_offset;
};
+struct ot_gsub_singlesubst_format1
+{
+ UINT16 format;
+ UINT16 coverage;
+ short delta;
+};
+
+struct ot_gsub_singlesubst_format2
+{
+ UINT16 format;
+ UINT16 coverage;
+ UINT16 count;
+ UINT16 substitutes[1];
+};
+
struct ot_feature
{
WORD feature_params;
@@ -740,12 +767,6 @@ typedef struct {
#include "poppack.h"
-enum gsub_lookup_type
-{
- GSUB_LOOKUP_SINGLE_SUBST = 1,
- GSUB_LOOKUP_EXTENSION_SUBST = 7,
-};
-
enum TT_NAME_WINDOWS_ENCODING_ID
{
TT_NAME_WINDOWS_ENCODING_SYMBOL = 0,
@@ -3286,7 +3307,23 @@ 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_gpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gpos.table,
+ const struct ot_gsubgpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gpos.table,
+ lookup_offset + subtable_offset, sizeof(*format1));
+ subtable_offset += GET_BE_DWORD(format1->extension_offset);
+ }
+
+ return lookup_offset + subtable_offset;
+}
+
+static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping_cache *cache,
+ 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 +
+ 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);
}
@@ -3971,7 +4008,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_gpos_extensionpos_format1 *extension = table_read_ensure(&cache->gpos.table,
+ const struct ot_gsubgpos_extensionpos_format1 *extension = table_read_ensure(&cache->gpos.table,
lookup.offset + GET_BE_WORD(lookup_table->subtable[0]), sizeof(*extension));
WORD format;
@@ -4157,9 +4194,115 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
heap_free(lookups.indexes);
}
+static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator *iter, const struct lookup *lookup)
+{
+ struct scriptshaping_cache *cache = iter->context->cache;
+ UINT16 format, coverage;
+ 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 = iter->context->u.subst.glyphs[iter->pos];
+ unsigned int coverage_index;
+
+ format = table_read_be_word(&cache->gsub.table, subtable_offset);
+
+ coverage = table_read_be_word(&cache->gsub.table, subtable_offset +
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage));
+
+ if (format == 1)
+ {
+ const struct ot_gsub_singlesubst_format1 *format1 = table_read_ensure(&cache->gsub.table, subtable_offset,
+ sizeof(*format1));
+
+ coverage_index = opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + coverage, glyph);
+ if (coverage_index == GLYPH_NOT_COVERED)
+ continue;
+
+ iter->context->u.subst.glyphs[iter->pos] = glyph + GET_BE_WORD(format1->delta);
+ break;
+ }
+ else if (format == 2)
+ {
+ UINT16 count = table_read_be_word(&cache->gsub.table, subtable_offset +
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count));
+ const struct ot_gsub_singlesubst_format2 *format2 = table_read_ensure(&cache->gsub.table, subtable_offset,
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count) + count * sizeof(UINT16));
+
+ coverage_index = opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + coverage, glyph);
+ if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count)
+ continue;
+
+ iter->context->u.subst.glyphs[iter->pos] = GET_BE_WORD(format2->substitutes[coverage_index]);
+ break;
+ }
+ else
+ WARN("Unknown single substitution format %u.\n", format);
+ }
+
+ return FALSE;
+}
+
static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph,
unsigned int glyph_count, int lookup_index)
{
+ struct ot_gsubgpos_table *table = &context->cache->gsub;
+ const struct ot_lookup_table *lookup_table;
+ struct glyph_iterator iter;
+ struct lookup lookup;
+ WORD lookup_type;
+
+ lookup.offset = table_read_be_word(&table->table, table->lookup_list + FIELD_OFFSET(struct ot_lookup_list, lookup[lookup_index]));
+ if (!lookup.offset)
+ return;
+
+ lookup.offset += table->lookup_list;
+
+ if (!(lookup_table = table_read_ensure(&table->table, lookup.offset, sizeof(*lookup_table))))
+ return;
+
+ lookup.subtable_count = GET_BE_WORD(lookup_table->subtable_count);
+ if (!lookup.subtable_count)
+ return;
+
+ lookup_type = GET_BE_WORD(lookup_table->lookup_type);
+ lookup.flags = GET_BE_WORD(lookup_table->flags);
+
+ glyph_iterator_init(context, lookup.flags, first_glyph, glyph_count, &iter);
+
+ while (iter.pos < first_glyph + iter.len)
+ {
+ BOOL ret;
+
+ if (!glyph_iterator_match(&iter))
+ {
+ ++iter.pos;
+ continue;
+ }
+
+ switch (lookup_type)
+ {
+ case GSUB_LOOKUP_SINGLE_SUBST:
+ ret = opentype_layout_apply_gsub_single_substitution(&iter, &lookup);
+ break;
+ case GSUB_LOOKUP_MULTIPLE_SUBST:
+ case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST:
+ case GSUB_LOOKUP_ALTERNATE_SUBST:
+ case GSUB_LOOKUP_LIGATURE_SUBST:
+ case GSUB_LOOKUP_CONTEXTUAL_SUBST:
+ case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST:
+ WARN("Unimplemented lookup %d.\n", lookup_type);
+ break;
+ default:
+ WARN("Unknown lookup type %u.\n", lookup_type);
+ return;
+ }
+
+ /* Some lookups update position after making changes. */
+ if (!ret)
+ ++iter.pos;
+ }
}
HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index,
--
2.26.2
More information about the wine-devel
mailing list