Nikolay Sivov : dwrite: Implement cursive attachment, GPOS lookup 3.

Alexandre Julliard julliard at winehq.org
Mon Feb 4 13:29:53 CST 2019


Module: wine
Branch: master
Commit: d1642df049cb17ade2b5458974fd040090a0ba51
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=d1642df049cb17ade2b5458974fd040090a0ba51

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Fri Feb  1 13:48:11 2019 +0300

dwrite: Implement cursive attachment, GPOS lookup 3.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dwrite/analyzer.c       |   2 +
 dlls/dwrite/dwrite_private.h |   1 +
 dlls/dwrite/opentype.c       | 185 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 188 insertions(+)

diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 1fc8f98..0d8305d 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -1317,6 +1317,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2
         context.u.pos.glyph_props = glyph_props;
         context.glyph_count = glyph_count;
         context.emsize = emSize;
+        context.measuring_mode = DWRITE_MEASURING_MODE_NATURAL;
         context.advances = advances;
         context.offsets = offsets;
         context.language_tag = get_opentype_language(locale);
@@ -1381,6 +1382,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWrite
         context.u.pos.glyph_props = glyph_props;
         context.glyph_count = glyph_count;
         context.emsize = emSize * ppdip;
+        context.measuring_mode = measuring_mode;
         context.advances = advances;
         context.offsets = offsets;
         context.language_tag = get_opentype_language(locale);
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 355a826..0451a7e 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -394,6 +394,7 @@ struct scriptshaping_context
 
     unsigned int glyph_count;
     float emsize;
+    DWRITE_MEASURING_MODE measuring_mode;
     float *advances;
     DWRITE_GLYPH_OFFSET *offsets;
 };
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index f3c2043..e9c755e 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -621,6 +621,38 @@ struct ot_gpos_pairpos_format2
     WORD values[1];
 };
 
+struct ot_gpos_anchor_format1
+{
+    WORD format;
+    short x_coord;
+    short y_coord;
+};
+
+struct ot_gpos_anchor_format2
+{
+    WORD format;
+    short x_coord;
+    short y_coord;
+    WORD anchor_point;
+};
+
+struct ot_gpos_anchor_format3
+{
+    WORD format;
+    short x_coord;
+    short y_coord;
+    WORD x_dev_offset;
+    WORD y_dev_offset;
+};
+
+struct ot_gpos_cursive_format1
+{
+    WORD format;
+    WORD coverage;
+    WORD count;
+    WORD anchors[1];
+};
+
 typedef struct {
     WORD SubstFormat;
     WORD Coverage;
@@ -2979,6 +3011,24 @@ static BOOL glyph_iterator_next(struct glyph_iterator *iter)
     return FALSE;
 }
 
+static BOOL glyph_iterator_prev(struct glyph_iterator *iter)
+{
+    if (!iter->pos)
+        return FALSE;
+
+    while (iter->pos > iter->len - 1)
+    {
+        --iter->pos;
+        if (glyph_iterator_match(iter))
+        {
+            --iter->len;
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
 static BOOL opentype_layout_apply_gpos_single_adjustment(struct scriptshaping_context *context,
         struct glyph_iterator *iter, const struct lookup *lookup)
 {
@@ -3192,9 +3242,144 @@ static BOOL opentype_layout_apply_gpos_pair_adjustment(struct scriptshaping_cont
     return FALSE;
 }
 
+static void opentype_layout_gpos_get_anchor(const struct scriptshaping_context *context, unsigned int anchor_offset,
+        unsigned int glyph_index, float *x, float *y)
+{
+    const struct scriptshaping_cache *cache = context->cache;
+
+    WORD format = table_read_be_word(&cache->gpos.table, anchor_offset);
+
+    *x = *y = 0.0f;
+
+    if (format == 1)
+    {
+        const struct ot_gpos_anchor_format1 *format1 = table_read_ensure(&cache->gpos.table, anchor_offset,
+                sizeof(*format1));
+
+        if (format1)
+        {
+            *x = opentype_scale_gpos_be_value(format1->x_coord, context->emsize, cache->upem);
+            *y = opentype_scale_gpos_be_value(format1->y_coord, context->emsize, cache->upem);
+        }
+    }
+    else if (format == 2)
+    {
+        const struct ot_gpos_anchor_format2 *format2 = table_read_ensure(&cache->gpos.table, anchor_offset,
+                sizeof(*format2));
+
+        if (format2)
+        {
+            if (context->measuring_mode != DWRITE_MEASURING_MODE_NATURAL)
+                FIXME("Use outline anchor point for glyph %u.\n", context->u.pos.glyphs[glyph_index]);
+
+            *x = opentype_scale_gpos_be_value(format2->x_coord, context->emsize, cache->upem);
+            *y = opentype_scale_gpos_be_value(format2->y_coord, context->emsize, cache->upem);
+        }
+    }
+    else if (format == 3)
+    {
+        const struct ot_gpos_anchor_format3 *format3 = table_read_ensure(&cache->gpos.table, anchor_offset,
+                sizeof(*format3));
+
+        if (format3)
+        {
+            *x = opentype_scale_gpos_be_value(format3->x_coord, context->emsize, cache->upem);
+            *y = opentype_scale_gpos_be_value(format3->y_coord, context->emsize, cache->upem);
+
+            if (context->measuring_mode != DWRITE_MEASURING_MODE_NATURAL)
+            {
+                if (format3->x_dev_offset)
+                    *x += opentype_layout_gpos_get_dev_value(context, anchor_offset + GET_BE_WORD(format3->x_dev_offset));
+                if (format3->y_dev_offset)
+                    *y += opentype_layout_gpos_get_dev_value(context, anchor_offset + GET_BE_WORD(format3->y_dev_offset));
+            }
+        }
+    }
+    else
+        WARN("Unknown anchor format %u.\n", format);
+}
+
 static BOOL opentype_layout_apply_gpos_cursive_attachment(struct scriptshaping_context *context,
         struct glyph_iterator *iter, const struct lookup *lookup)
 {
+    struct scriptshaping_cache *cache = context->cache;
+    unsigned int i;
+
+    for (i = 0; i < lookup->subtable_count; ++i)
+    {
+        unsigned int subtable_offset = opentype_layout_get_gpos_subtable(cache, lookup->offset, i);
+        WORD format;
+
+        format = table_read_be_word(&cache->gpos.table, subtable_offset);
+
+        if (format == 1)
+        {
+            WORD coverage_offset = table_read_be_word(&cache->gpos.table, subtable_offset +
+                    FIELD_OFFSET(struct ot_gpos_cursive_format1, coverage));
+            unsigned int glyph_index, entry_count, entry_anchor, exit_anchor;
+            float entry_x, entry_y, exit_x, exit_y, delta;
+            struct glyph_iterator prev_iter;
+
+            if (!coverage_offset)
+                continue;
+
+            entry_count = table_read_be_word(&cache->gpos.table, subtable_offset +
+                    FIELD_OFFSET(struct ot_gpos_cursive_format1, count));
+
+            glyph_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset +
+                    coverage_offset, context->u.pos.glyphs[iter->pos]);
+            if (glyph_index == GLYPH_NOT_COVERED || glyph_index >= entry_count)
+                continue;
+
+            entry_anchor = table_read_be_word(&cache->gpos.table, subtable_offset +
+                    FIELD_OFFSET(struct ot_gpos_cursive_format1, anchors[glyph_index * 2]));
+            if (!entry_anchor)
+                continue;
+
+            glyph_iterator_init(context, iter->flags, iter->pos, 1, &prev_iter);
+            if (!glyph_iterator_prev(&prev_iter))
+                continue;
+
+            glyph_index = opentype_layout_is_glyph_covered(&cache->gpos.table, subtable_offset +
+                    coverage_offset, context->u.pos.glyphs[prev_iter.pos]);
+            if (glyph_index == GLYPH_NOT_COVERED || glyph_index >= entry_count)
+                continue;
+
+            exit_anchor = table_read_be_word(&cache->gpos.table, subtable_offset +
+                    FIELD_OFFSET(struct ot_gpos_cursive_format1, anchors[glyph_index * 2 + 1]));
+            if (!exit_anchor)
+                continue;
+
+            opentype_layout_gpos_get_anchor(context, subtable_offset + exit_anchor, prev_iter.pos, &exit_x, &exit_y);
+            opentype_layout_gpos_get_anchor(context, subtable_offset + entry_anchor, iter->pos, &entry_x, &entry_y);
+
+            if (context->is_rtl)
+            {
+                delta = exit_x + context->offsets[prev_iter.pos].advanceOffset;
+                context->advances[prev_iter.pos] -= delta;
+                context->advances[iter->pos] = entry_x + context->offsets[iter->pos].advanceOffset;
+                context->offsets[prev_iter.pos].advanceOffset -= delta;
+            }
+            else
+            {
+                delta = entry_x + context->offsets[iter->pos].advanceOffset;
+                context->advances[prev_iter.pos] = exit_x + context->offsets[prev_iter.pos].advanceOffset;
+                context->advances[iter->pos] -= delta;
+                context->offsets[iter->pos].advanceOffset -= delta;
+            }
+
+            if (lookup->flags & LOOKUP_FLAG_RTL)
+                context->offsets[prev_iter.pos].ascenderOffset = entry_y - exit_y;
+            else
+                context->offsets[iter->pos].ascenderOffset = exit_y - entry_y;
+
+            break;
+        }
+        else
+            WARN("Unknown cursive attachment format %u.\n", format);
+
+    }
+
     return FALSE;
 }
 




More information about the wine-cvs mailing list