[PATCH 3/5] dwrite: Implement leading and trailing text alignment modes

Nikolay Sivov nsivov at codeweavers.com
Mon Jul 6 01:05:41 CDT 2015


---

-------------- next part --------------
From dc9c58e8b2c11a752ce435a54d76c981cfce90fa Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Mon, 6 Jul 2015 08:41:46 +0300
Subject: [PATCH 3/5] dwrite: Implement leading and trailing text alignment
 modes

---
 dlls/dwrite/layout.c       | 127 ++++++++++++++++++++++++++++++++++++++++++---
 dlls/dwrite/tests/layout.c |  54 ++++++++++++++++++-
 2 files changed, 173 insertions(+), 8 deletions(-)

diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 13a9ce0..18462b0 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -180,6 +180,8 @@ struct layout_effective_run {
     UINT32 glyphcount;      /* total glyph count in this run */
     FLOAT origin_x;         /* baseline X position */
     FLOAT origin_y;         /* baseline Y position */
+    FLOAT align_dx;         /* adjustment from text alignment */
+    FLOAT width;            /* run width */
     UINT16 *clustermap;     /* effective clustermap, allocated separately, is not reused from nominal map */
     UINT32 line;
 };
@@ -190,6 +192,8 @@ struct layout_effective_inline {
     IUnknown *effect;
     FLOAT origin_x;
     FLOAT origin_y;
+    FLOAT align_dx;
+    FLOAT width;
     BOOL  is_sideways;
     BOOL  is_rtl;
     UINT32 line;
@@ -328,10 +332,12 @@ static inline const char *debugstr_run(const struct regular_layout_run *run)
         run->descr.stringLength);
 }
 
-static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment)
+static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
+    BOOL *changed)
 {
     if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
         return E_INVALIDARG;
+    if (changed) *changed = format->textalignment != alignment;
     format->textalignment = alignment;
     return S_OK;
 }
@@ -934,6 +940,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
         inlineobject->object = r->u.object.object;
         inlineobject->origin_x = origin_x;
         inlineobject->origin_y = 0.0; /* FIXME */
+        inlineobject->align_dx = 0.0;
+        inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
         /* It's not clear how these two are set, possibly directionality
            is derived from surrounding text (replaced text could have
            different ranges which differ in reading direction). */
@@ -969,6 +977,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
     run->length = length;
     run->origin_x = origin_x;
     run->origin_y = 0.0; /* set after line is built */
+    run->align_dx = 0.0;
+    run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
     run->line = line;
 
     if (r->u.regular.run.glyphCount) {
@@ -1083,6 +1093,95 @@ static inline struct layout_effective_inline *layout_get_next_inline_run(struct
     return LIST_ENTRY(e, struct layout_effective_inline, entry);
 }
 
+static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
+    struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
+{
+    FLOAT width = 0.0;
+
+    while (erun && erun->line == line) {
+        width += erun->width;
+        erun = layout_get_next_erun(layout, erun);
+        if (!erun)
+            break;
+    }
+
+    while (inrun && inrun->line == line) {
+        width += inrun->width;
+        inrun = layout_get_next_inline_run(layout, inrun);
+        if (!inrun)
+            break;
+    }
+
+    return width;
+}
+
+static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
+{
+    struct layout_effective_inline *inrun;
+    struct layout_effective_run *erun;
+
+    erun = layout_get_next_erun(layout, NULL);
+    inrun = layout_get_next_inline_run(layout, NULL);
+
+    while (erun) {
+        erun->align_dx = 0.0;
+        erun = layout_get_next_erun(layout, erun);
+    }
+
+    while (inrun) {
+        inrun->align_dx = 0.0;
+        inrun = layout_get_next_inline_run(layout, inrun);
+    }
+
+    layout->metrics.left = 0;
+}
+
+static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
+{
+    struct layout_effective_inline *inrun;
+    struct layout_effective_run *erun;
+    UINT32 line;
+
+    erun = layout_get_next_erun(layout, NULL);
+    inrun = layout_get_next_inline_run(layout, NULL);
+
+    for (line = 0; line < layout->metrics.lineCount; line++) {
+        FLOAT width = layout_get_line_width(layout, erun, inrun, line);
+        FLOAT shift = layout->metrics.layoutWidth - width;
+
+        while (erun && erun->line == line) {
+            erun->align_dx = shift;
+            erun = layout_get_next_erun(layout, erun);
+        }
+
+        while (inrun && inrun->line == line) {
+            erun->align_dx = shift;
+            inrun = layout_get_next_inline_run(layout, inrun);
+        }
+    }
+
+    layout->metrics.left = layout->metrics.layoutWidth - layout->metrics.width;
+}
+
+static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
+{
+    switch (layout->format.textalignment)
+    {
+    case DWRITE_TEXT_ALIGNMENT_LEADING:
+        layout_apply_leading_alignment(layout);
+        break;
+    case DWRITE_TEXT_ALIGNMENT_TRAILING:
+        layout_apply_trailing_alignment(layout);
+        break;
+    case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
+    case DWRITE_TEXT_ALIGNMENT_CENTER:
+        FIXME("alignment %d not implemented\n", layout->format.textalignment);
+        break;
+    default:
+        ;
+    }
+}
+
 static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
 {
     struct layout_effective_inline *inrun;
@@ -1251,6 +1350,10 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
         layout->metrics.height += layout->lines[line].height;
     }
 
+    /* initial alignment is always leading */
+    if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
+        layout_apply_text_alignment(layout);
+
     layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
 
     layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
@@ -2555,7 +2658,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
         /* return value is ignored */
         IDWriteTextRenderer_DrawGlyphRun(renderer,
             context,
-            run->origin_x + origin_x,
+            run->origin_x + run->align_dx + origin_x,
             run->origin_y + origin_y,
             DWRITE_MEASURING_MODE_NATURAL,
             &glyph_run,
@@ -2567,8 +2670,8 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
     LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
         IDWriteTextRenderer_DrawInlineObject(renderer,
             context,
-            inlineobject->origin_x,
-            inlineobject->origin_y,
+            inlineobject->origin_x + inlineobject->align_dx + origin_x,
+            inlineobject->origin_y + origin_y,
             inlineobject->object,
             inlineobject->is_sideways,
             inlineobject->is_rtl,
@@ -2978,8 +3081,20 @@ static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
 static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
 {
     struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
+    BOOL changed;
+    HRESULT hr;
+
     TRACE("(%p)->(%d)\n", This, alignment);
-    return format_set_textalignment(&This->format, alignment);
+
+    hr = format_set_textalignment(&This->format, alignment, &changed);
+    if (FAILED(hr))
+        return hr;
+
+    /* if layout is not ready there's nothing to align */
+    if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
+        layout_apply_text_alignment(This);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
@@ -3853,7 +3968,7 @@ static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *ifac
 {
     struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
     TRACE("(%p)->(%d)\n", This, alignment);
-    return format_set_textalignment(&This->format, alignment);
+    return format_set_textalignment(&This->format, alignment, NULL);
 }
 
 static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index 57d3a34..8e8651a 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -2865,12 +2865,15 @@ todo_wine {
 
 static void test_SetTextAlignment(void)
 {
-    static const WCHAR strW[] = {'a','b','c','d',0};
+    static const WCHAR strW[] = {'a',0};
+    DWRITE_CLUSTER_METRICS clusters[1];
+    DWRITE_TEXT_METRICS metrics;
     IDWriteTextFormat1 *format1;
     IDWriteTextFormat *format;
     IDWriteTextLayout *layout;
     IDWriteFactory *factory;
     DWRITE_TEXT_ALIGNMENT v;
+    UINT32 count;
     HRESULT hr;
 
     factory = create_factory();
@@ -2882,7 +2885,7 @@ static void test_SetTextAlignment(void)
     v = IDWriteTextFormat_GetTextAlignment(format);
     ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
 
-    hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 300.0, 100.0, &layout);
+    hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
     v = IDWriteTextLayout_GetTextAlignment(layout);
@@ -2891,6 +2894,9 @@ static void test_SetTextAlignment(void)
     hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
+    hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
     v = IDWriteTextFormat_GetTextAlignment(format);
     ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
 
@@ -2916,8 +2922,52 @@ static void test_SetTextAlignment(void)
     else
         win_skip("IDWriteTextFormat1 is not supported\n");
 
+    count = 0;
+    hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(count == 1, "got %u\n", count);
+
+    /* maxwidth is 500, leading alignment */
+    hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_LEADING);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
+    ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
+    ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
+    ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
+
+    /* maxwidth is 500, trailing alignment */
+    hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
+    ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
+    ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
+    ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
+    IDWriteTextLayout_Release(layout);
+
+    /* initially created with trailing alignment */
+    hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_TRAILING);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
 
+    hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+
+    ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
+    ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
+    ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
+    ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
     IDWriteTextLayout_Release(layout);
+
     IDWriteTextFormat_Release(format);
     IDWriteFactory_Release(factory);
 }
-- 
2.1.4



More information about the wine-patches mailing list