[PATCH 4/4] dwrite: Implement mark-to-base attachment, GPOS lookup 4.

Nikolay Sivov nsivov at codeweavers.com
Fri Feb 1 04:48:12 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/opentype.c | 105 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index e9c755e51b..92a5d40dfc 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -653,6 +653,34 @@ struct ot_gpos_cursive_format1
     WORD anchors[1];
 };
 
+struct ot_gpos_mark_record
+{
+    WORD mark_class;
+    WORD mark_anchor;
+};
+
+struct ot_gpos_mark_array
+{
+    WORD count;
+    struct ot_gpos_mark_record records[1];
+};
+
+struct ot_gpos_base_array
+{
+    WORD count;
+    WORD offsets[1];
+};
+
+struct ot_gpos_mark_to_base_format1
+{
+    WORD format;
+    WORD mark_coverage;
+    WORD base_coverage;
+    WORD mark_class_count;
+    WORD mark_array;
+    WORD base_array;
+};
+
 typedef struct {
     WORD SubstFormat;
     WORD Coverage;
@@ -3386,6 +3414,83 @@ static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_c
 static BOOL opentype_layout_apply_gpos_mark_to_base_attachment(const struct scriptshaping_context *context,
         struct glyph_iterator *iter, const struct lookup *lookup)
 {
+    struct scriptshaping_cache *cache = context->cache;
+    unsigned int i;
+    WORD format;
+
+    for (i = 0; i < lookup->subtable_count; ++i)
+    {
+        unsigned int subtable_offset = opentype_layout_get_gpos_subtable(cache, lookup->offset, i);
+
+        format = table_read_be_word(&cache->gpos.table, subtable_offset);
+
+        if (format == 1)
+        {
+            const struct ot_gpos_mark_to_base_format1 *format1 = table_read_ensure(&cache->gpos.table, subtable_offset,
+                    sizeof(*format1));
+            unsigned int mark_class_count, count, mark_array_offset, base_array_offset;
+            const struct ot_gpos_mark_array *mark_array;
+            const struct ot_gpos_base_array *base_array;
+            float mark_x, mark_y, base_x, base_y;
+            unsigned int base_index, mark_index;
+            struct glyph_iterator base_iter;
+            unsigned int base_anchor;
+
+            if (!format1)
+                continue;
+
+            mark_array_offset = subtable_offset + GET_BE_WORD(format1->mark_array);
+            if (!(count = table_read_be_word(&cache->gpos.table, mark_array_offset)))
+                continue;
+
+            mark_array = table_read_ensure(&cache->gpos.table, mark_array_offset,
+                    FIELD_OFFSET(struct ot_gpos_mark_array, records[count]));
+            if (!mark_array)
+                continue;
+
+            base_array_offset = subtable_offset + GET_BE_WORD(format1->base_array);
+            if (!(count = table_read_be_word(&cache->gpos.table, base_array_offset)))
+                continue;
+
+            base_array = table_read_ensure(&cache->gpos.table, base_array_offset,
+                    FIELD_OFFSET(struct ot_gpos_base_array, offsets[count * GET_BE_WORD(format1->mark_class_count)]));
+            if (!base_array)
+                continue;
+
+            mark_class_count = GET_BE_WORD(format1->mark_class_count);
+
+            mark_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset +
+                    GET_BE_WORD(format1->mark_coverage), context->u.pos.glyphs[iter->pos]);
+
+            if (mark_index == GLYPH_NOT_COVERED || mark_index >= GET_BE_WORD(mark_array->count))
+                continue;
+
+            /* Look back for first base glyph. */
+            glyph_iterator_init(context, LOOKUP_FLAG_IGNORE_MARKS, iter->pos, 1, &base_iter);
+            if (!glyph_iterator_prev(&base_iter))
+                continue;
+
+            base_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset +
+                    GET_BE_WORD(format1->base_coverage), context->u.pos.glyphs[base_iter.pos]);
+            if (base_index == GLYPH_NOT_COVERED || base_index >= GET_BE_WORD(base_array->count))
+                continue;
+
+            base_anchor = GET_BE_WORD(base_array->offsets[base_index * mark_class_count +
+                    GET_BE_WORD(mark_array->records[mark_index].mark_class)]);
+
+            opentype_layout_gpos_get_anchor(context, mark_array_offset +
+                    GET_BE_WORD(mark_array->records[mark_index].mark_anchor), iter->pos, &mark_x, &mark_y);
+            opentype_layout_gpos_get_anchor(context, base_array_offset + base_anchor, base_iter.pos, &base_x, &base_y);
+
+            context->offsets[iter->pos].advanceOffset = (context->is_rtl ? -1.0f : 1.0f) * (base_x - mark_x);
+            context->offsets[iter->pos].ascenderOffset = base_y - mark_y;
+
+            break;
+        }
+        else
+            WARN("Unknown mark-to-base format %u.\n", format);
+    }
+
     return FALSE;
 }
 
-- 
2.20.1




More information about the wine-devel mailing list