[PATCH 1/5] dwrite/analyzer: Preserve inter-cluster spacing when apply spacing properties.

Nikolay Sivov nsivov at codeweavers.com
Sat Jan 26 23:55:23 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/analyzer.c       | 209 ++++++++++++++++-------------------
 dlls/dwrite/tests/analyzer.c | 158 +++++++++++++++++++-------
 2 files changed, 215 insertions(+), 152 deletions(-)

diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index a1d9f25ad1..7ee3675d2e 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -1397,124 +1397,121 @@ static inline FLOAT get_cluster_advance(const FLOAT *advances, UINT32 start, UIN
     return advance;
 }
 
-static void apply_single_glyph_spacing(FLOAT leading_spacing, FLOAT trailing_spacing,
-    FLOAT min_advance_width, UINT32 g, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets,
-    DWRITE_SHAPING_GLYPH_PROPERTIES const *props, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
+static HRESULT apply_cluster_spacing(float leading_spacing, float trailing_spacing, float min_advance_width,
+        unsigned int start, unsigned int end, float const *advances, DWRITE_GLYPH_OFFSET const *offsets,
+        DWRITE_SHAPING_GLYPH_PROPERTIES const *glyph_props, float *modified_advances,
+        DWRITE_GLYPH_OFFSET *modified_offsets)
 {
     BOOL reduced = leading_spacing < 0.0f || trailing_spacing < 0.0f;
-    FLOAT advance = advances[g];
-    FLOAT origin = 0.0f;
+    unsigned int first_spacing, last_spacing, i;
+    float advance, origin = 0.0f, *deltas;
+    BOOL is_spacing_cluster = FALSE;
 
-    if (props[g].isZeroWidthSpace) {
-        modified_advances[g] = advances[g];
-        modified_offsets[g] = offsets[g];
-        return;
-    }
+    if (modified_advances != advances)
+        memcpy(&modified_advances[start], &advances[start], (end - start + 1) * sizeof(*advances));
+    if (modified_offsets != offsets)
+        memcpy(&modified_offsets[start], &offsets[start], (end - start + 1) * sizeof(*offsets));
 
-    /* first apply negative spacing and check if we hit minimum width */
-    if (leading_spacing < 0.0f) {
-        advance += leading_spacing;
-        origin -= leading_spacing;
+    for (first_spacing = start; first_spacing <= end; ++first_spacing)
+    {
+        if ((is_spacing_cluster = !glyph_props[first_spacing].isZeroWidthSpace))
+            break;
     }
-    if (trailing_spacing < 0.0f)
-        advance += trailing_spacing;
 
-    if (advance < min_advance_width) {
-        FLOAT half = (min_advance_width - advance) / 2.0f;
-
-        if (!reduced)
-            origin -= half;
-        else if (leading_spacing < 0.0f && trailing_spacing < 0.0f)
-            origin -= half;
-        else if (leading_spacing < 0.0f)
-            origin -= min_advance_width - advance;
+    /* Nothing to adjust if there is no spacing glyphs. */
+    if (!is_spacing_cluster)
+        return S_OK;
 
-        advance = min_advance_width;
+    for (last_spacing = end; last_spacing >= start; --last_spacing)
+    {
+        if (!glyph_props[last_spacing].isZeroWidthSpace)
+            break;
     }
 
-    /* now apply positive spacing adjustments */
-    if (leading_spacing > 0.0f) {
-        advance += leading_spacing;
-        origin -= leading_spacing;
-    }
-    if (trailing_spacing > 0.0f)
-        advance += trailing_spacing;
+    deltas = heap_alloc((end - start + 1) * sizeof(*deltas));
+    if (!deltas)
+        return E_OUTOFMEMORY;
 
-    modified_advances[g] = advance;
-    modified_offsets[g].advanceOffset = offsets[g].advanceOffset - origin;
-    /* ascender is never touched, it's orthogonal to reading direction and is not
-       affected by advance adjustments */
-    modified_offsets[g].ascenderOffset = offsets[g].ascenderOffset;
-}
+    /* Cluster advance, note that properties are ignored. */
+    origin = offsets[start].advanceOffset;
+    for (i = start, advance = 0.0f; i <= end; ++i)
+    {
+        float cur = advance + offsets[i].advanceOffset;
 
-static void apply_cluster_spacing(FLOAT leading_spacing, FLOAT trailing_spacing, FLOAT min_advance_width,
-    UINT32 start, UINT32 end, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets,
-    FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
-{
-    BOOL reduced = leading_spacing < 0.0f || trailing_spacing < 0.0f;
-    FLOAT advance = get_cluster_advance(advances, start, end);
-    FLOAT origin = 0.0f;
-    UINT16 g;
+        deltas[i - start] = cur - origin;
 
-    modified_advances[start] = advances[start];
-    modified_advances[end-1] = advances[end-1];
+        advance += advances[i];
+        origin = cur;
+    }
 
-    /* first apply negative spacing and check if we hit minimum width */
-    if (leading_spacing < 0.0f) {
+    /* Negative spacing. */
+    if (leading_spacing < 0.0f)
+    {
         advance += leading_spacing;
-        modified_advances[start] += leading_spacing;
-        origin -= leading_spacing;
+        modified_advances[first_spacing] += leading_spacing;
+        modified_offsets[first_spacing].advanceOffset += leading_spacing;
     }
-    if (trailing_spacing < 0.0f) {
+
+    if (trailing_spacing < 0.0f)
+    {
         advance += trailing_spacing;
-        modified_advances[end-1] += trailing_spacing;
+        modified_advances[last_spacing] += trailing_spacing;
     }
 
+    /* Minimal advance. */
     advance = min_advance_width - advance;
     if (advance > 0.0f) {
-        /* additional spacing is only applied to leading and trailing glyph */
-        FLOAT half = advance / 2.0f;
+        /* Additional spacing is only applied to leading and trailing spacing glyphs. */
+        float half = advance / 2.0f;
 
-        if (!reduced) {
-            origin -= half;
-            modified_advances[start] += half;
-            modified_advances[end-1] += half;
+        if (!reduced)
+        {
+            modified_advances[first_spacing] += half;
+            modified_advances[last_spacing] += half;
+            modified_offsets[first_spacing].advanceOffset += half;
         }
-        else if (leading_spacing < 0.0f && trailing_spacing < 0.0f) {
-            origin -= half;
-            modified_advances[start] += half;
-            modified_advances[end-1] += half;
+        else if (leading_spacing < 0.0f && trailing_spacing < 0.0f)
+        {
+            modified_advances[first_spacing] += half;
+            modified_advances[last_spacing] += half;
+            modified_offsets[first_spacing].advanceOffset += half;
         }
-        else if (leading_spacing < 0.0f) {
-            origin -= advance;
-            modified_advances[start] += advance;
+        else if (leading_spacing < 0.0f)
+        {
+            modified_advances[first_spacing] += advance;
+            modified_offsets[first_spacing].advanceOffset += advance;
         }
         else
-            modified_advances[end-1] += advance;
+            modified_advances[last_spacing] += advance;
     }
 
-    /* now apply positive spacing adjustments */
-    if (leading_spacing > 0.0f) {
-        modified_advances[start] += leading_spacing;
-        origin -= leading_spacing;
+    /* Positive spacing. */
+    if (leading_spacing > 0.0f)
+    {
+        modified_advances[first_spacing] += leading_spacing;
+        modified_offsets[first_spacing].advanceOffset += leading_spacing;
     }
+
     if (trailing_spacing > 0.0f)
-        modified_advances[end-1] += trailing_spacing;
+        modified_advances[last_spacing] += trailing_spacing;
 
-    for (g = start; g < end; g++) {
-        if (g == start) {
-            modified_offsets[g].advanceOffset = offsets[g].advanceOffset - origin;
-            modified_offsets[g].ascenderOffset = offsets[g].ascenderOffset;
-        }
-        else if (g == end - 1)
-            /* trailing glyph offset is not adjusted */
-            modified_offsets[g] = offsets[g];
-        else {
-            /* for all glyphs within a cluster use original advances and offsets */
-            modified_advances[g] = advances[g];
-            modified_offsets[g] = offsets[g];
-        }
+    /* Update offsets to preserve original relative positions within cluster. */
+    for (i = first_spacing; i > start; --i)
+    {
+        unsigned int cur = i - 1;
+        modified_offsets[cur].advanceOffset = modified_advances[cur] + modified_offsets[i].advanceOffset -
+                deltas[i - start];
+    }
+
+    for (i = first_spacing + 1; i <= end; ++i)
+    {
+        modified_offsets[i].advanceOffset = deltas[i - start] + modified_offsets[i - 1].advanceOffset -
+                modified_advances[i - 1];
     }
+
+    heap_free(deltas);
+
+    return S_OK;
 }
 
 static inline UINT32 get_cluster_length(UINT16 const *clustermap, UINT32 start, UINT32 text_len)
@@ -1562,16 +1559,13 @@ static inline UINT32 get_cluster_length(UINT16 const *clustermap, UINT32 start,
 
    It's known that isZeroWidthSpace property keeps initial advance from changing.
 
-   TODO: test other properties; make isZeroWidthSpace work properly for clusters
-         with more than one glyph.
-
 */
 static HRESULT WINAPI dwritetextanalyzer1_ApplyCharacterSpacing(IDWriteTextAnalyzer2 *iface,
     FLOAT leading_spacing, FLOAT trailing_spacing, FLOAT min_advance_width, UINT32 len,
     UINT32 glyph_count, UINT16 const *clustermap, FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets,
     DWRITE_SHAPING_GLYPH_PROPERTIES const *props, FLOAT *modified_advances, DWRITE_GLYPH_OFFSET *modified_offsets)
 {
-    UINT16 start;
+    unsigned int i;
 
     TRACE("(%.2f %.2f %.2f %u %u %p %p %p %p %p %p)\n", leading_spacing, trailing_spacing, min_advance_width,
         len, glyph_count, clustermap, advances, offsets, props, modified_advances, modified_offsets);
@@ -1582,33 +1576,18 @@ static HRESULT WINAPI dwritetextanalyzer1_ApplyCharacterSpacing(IDWriteTextAnaly
         return E_INVALIDARG;
     }
 
-    /* minimum advance is not applied if no adjustments were made */
-    if (leading_spacing == 0.0f && trailing_spacing == 0.0f) {
-        memmove(modified_advances, advances, glyph_count*sizeof(*advances));
-        memmove(modified_offsets, offsets, glyph_count*sizeof(*offsets));
-        return S_OK;
-    }
-
-    for (start = 0; start < len;) {
-        UINT32 length = get_cluster_length(clustermap, start, len);
-
-        if (length == 1) {
-            UINT32 g = clustermap[start];
-
-            apply_single_glyph_spacing(leading_spacing, trailing_spacing, min_advance_width,
-                g, advances, offsets, props, modified_advances, modified_offsets);
-        }
-        else {
-            UINT32 g_start, g_end;
+    for (i = 0; i < len;)
+    {
+        unsigned int length = get_cluster_length(clustermap, i, len);
+        unsigned int start, end;
 
-            g_start = clustermap[start];
-            g_end = (start + length < len) ? clustermap[start + length] : glyph_count;
+        start = clustermap[i];
+        end = i + length < len ? clustermap[i + length] : glyph_count;
 
-            apply_cluster_spacing(leading_spacing, trailing_spacing, min_advance_width,
-                g_start, g_end, advances, offsets, modified_advances, modified_offsets);
-        }
+        apply_cluster_spacing(leading_spacing, trailing_spacing, min_advance_width, start, end - 1, advances,
+                offsets, props, modified_advances, modified_offsets);
 
-        start += length;
+        i += length;
     }
 
     return S_OK;
diff --git a/dlls/dwrite/tests/analyzer.c b/dlls/dwrite/tests/analyzer.c
index 77369a7ef9..251887f508 100644
--- a/dlls/dwrite/tests/analyzer.c
+++ b/dlls/dwrite/tests/analyzer.c
@@ -1738,7 +1738,17 @@ struct spacing_test {
     DWRITE_SHAPING_GLYPH_PROPERTIES props[3];
 };
 
-static const struct spacing_test spacing_tests[] = {
+static const struct spacing_test spacing_tests[] =
+{
+/* Default spacing glyph properties. */
+#define P_S { 0 }
+/* isZeroWidthSpace */
+#define P_Z { 0, 0, 0, 1, 0 }
+/* isDiacritic */
+#define P_D { 0, 0, 1, 0, 0 }
+/* isDiacritic + isZeroWidthSpace, that's how diacritics are shaped. */
+#define P_D_Z { 0, 0, 1, 1, 0 }
+
     {   0.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 } }, /* 0 */
     {   0.0,   0.0,  2.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 } },
     {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, {  3.0,  4.0 } },
@@ -1756,9 +1766,9 @@ static const struct spacing_test spacing_tests[] = {
     {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 } },
     { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, {  6.0,  6.0 }, { -1.0, -3.0 } }, /* 15 */
     /* cluster of more than 1 glyph */
-    {   0.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0, 3.0 }, TRUE },
-    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.5 }, { 11.0, 11.0 }, {  3.0, 3.5 }, TRUE },
-    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, {  3.0, 3.0 }, TRUE },
+    {  0.0f,   0.0f,  0.0f, { 10.0f, 11.0f }, { 2.0f, 3.0f }, { 10.0f, 11.0f }, {  2.0f, 3.0f }, TRUE },
+    {  1.0f,   0.0f,  0.0f, { 10.0f, 11.0f }, { 2.0f, 3.5f }, { 11.0f, 11.0f }, {  3.0f, 3.5f }, TRUE },
+    {  1.0f,   1.0f,  0.0f, { 10.0f, 11.0f }, { 2.0f, 3.0f }, { 11.0f, 12.0f }, {  3.0f, 3.0f }, TRUE },
     {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 10.0 }, {  3.0, 3.0 }, TRUE },
     {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0, 3.0 }, TRUE }, /* 20 */
     {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0, 3.0 }, TRUE },
@@ -1770,35 +1780,106 @@ static const struct spacing_test spacing_tests[] = {
     {   1.0, -10.0,  5.0, {  2.0,  1.0, 10.0 }, { 2.0, 3.0, 4.0 }, { 3.0,  1.0, 2.0 }, {  3.0, 3.0, 4.0 }, TRUE },
     { -10.0, -10.0,  5.0, { 11.0,  1.0, 11.0 }, { 2.0, 3.0, 4.0 }, { 2.0,  1.0, 2.0 }, { -7.0, 3.0, 4.0 }, TRUE },
     /* isZeroWidthSpace set */
-    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, {  2.0,  4.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } },
-    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, {  2.0,  4.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } }, /* 30 */
-    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  3.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } },
-    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0,  3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } },
-    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0, 11.0 }, { -1.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } },
-    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0, 0, 0, 1, 0 }} },
-    {   2.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  7.0,  2.0 }, {  6.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, /* 35 */
-    {   2.0,   1.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  8.0,  2.0 }, {  6.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } },
-    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0, 0, 0, 1, 0 } } },
-    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  6.0, 11.0 }, {  3.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } },
-    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0, 0, 0, 1, 0 } } },
-    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0, 11.0 }, {  2.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } }, /* 40 */
-    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, FALSE, { { 0, 0, 0, 1, 0 }, { 0 } } },
-    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, {  6.0, 11.0 }, { -1.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } },
+    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, {  2.0,  4.0 }, FALSE, { P_Z, P_S } },
+    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, {  2.0,  4.0 }, FALSE, { P_Z, P_S } }, /* 30 */
+    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  3.0,  3.0 }, FALSE, { P_S, P_Z } },
+    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0,  3.0 }, FALSE, { P_Z, P_S } },
+    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0, 11.0 }, { -1.0,  3.0 }, FALSE, { P_S, P_Z } },
+    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_Z, P_Z } },
+    {   2.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  7.0,  2.0 }, {  6.0,  3.0 }, FALSE, { P_S, P_Z } }, /* 35 */
+    {   2.0,   1.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  8.0,  2.0 }, {  6.0,  3.0 }, FALSE, { P_S, P_Z } },
+    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_Z, P_Z } },
+    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  6.0, 11.0 }, {  3.0,  3.0 }, FALSE, { P_S, P_Z } },
+    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_Z, P_Z } },
+    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_S, P_Z } }, /* 40 */
+    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, FALSE, { P_Z, P_S } },
+    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, {  6.0, 11.0 }, { -1.0,  3.0 }, FALSE, { P_S, P_Z } },
     /* isDiacritic */
-    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, {  3.0,  4.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } },
-    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 13.0 }, {  3.0,  4.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } },
-    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  3.0,  4.0 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, /* 45 */
-    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  1.0 }, {  2.0,  3.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } },
-    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  5.0 }, { -1.0, -0.5 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } },
-    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  5.0 }, { -0.5,  0.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 }} },
-    {   2.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  7.0,  7.0 }, {  6.0,  6.5 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } },
-    {   2.0,   1.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  8.0,  8.0 }, {  6.0,  6.5 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } }, /* 50 */
-    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  7.0,  7.0 }, {  4.0,  5.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 } } },
-    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  6.0, 11.0 }, {  3.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 0, 1, 0 } } },
-    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  6.0,  6.0 }, { -3.0, -3.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0 } } },
-    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  5.0 }, {  2.0,  3.0 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } },
-    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, FALSE, { { 0, 0, 1, 0, 0 }, { 0 } } }, /* 55 */
-    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, {  6.0,  6.0 }, { -1.0, -3.0 }, FALSE, { { 0 }, { 0, 0, 1, 0, 0 } } },
+    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, {  3.0,  4.0 }, FALSE, { P_D, P_S } },
+    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 13.0 }, {  3.0,  4.0 }, FALSE, { P_D, P_S } },
+    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  3.0,  4.0 }, FALSE, { P_S, P_D } }, /* 45 */
+    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  1.0 }, {  2.0,  3.0 }, FALSE, { P_D, P_S } },
+    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  5.0 }, { -1.0, -0.5 }, FALSE, { P_S, P_D } },
+    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  5.0 }, { -0.5,  0.0 }, FALSE, { P_D, P_D } },
+    {   2.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  7.0,  7.0 }, {  6.0,  6.5 }, FALSE, { P_S, P_D } },
+    {   2.0,   1.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  8.0,  8.0 }, {  6.0,  6.5 }, FALSE, { P_S, P_D } }, /* 50 */
+    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  7.0,  7.0 }, {  4.0,  5.0 }, FALSE, { P_D, P_D } },
+    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  6.0,  6.0 }, {  3.0,  4.0 }, FALSE, { P_S, P_D } },
+    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  6.0,  6.0 }, { -3.0, -3.0 }, FALSE, { P_D, P_D } },
+    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  5.0 }, {  2.0,  3.0 }, FALSE, { P_S, P_D } },
+    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, FALSE, { P_D, P_S } }, /* 55 */
+    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, {  6.0,  6.0 }, { -1.0, -3.0 }, FALSE, { P_S, P_D } },
+    /* isZeroWidthSpace in a cluster */
+    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, {  3.0,  4.0 }, TRUE, { P_Z, P_S } },
+    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, {  3.0,  4.0 }, TRUE, { P_Z, P_S } },
+    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  3.0,  4.0 }, TRUE, { P_S, P_Z } },
+    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0,  3.0 }, TRUE, { P_Z, P_S } }, /* 60 */
+    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  1.0, 11.0 }, { -3.0,  7.0 }, TRUE, { P_S, P_Z } },
+    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, TRUE, { P_Z, P_Z } },
+    {   0.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  3.0,  2.0 }, {  3.0,  2.0 }, TRUE, { P_S, P_Z } },
+    {   0.0,   0.0,  5.0, {  1.0,  2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.5, 2.0, 1.5 }, { 2.5, 3.0, 5.0 }, TRUE, { P_S, P_Z, P_S } },
+    {   0.0,   0.0,  5.0, {  1.0,  2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.5, 2.5, 1.0 }, { 2.5, 3.0, 4.5 }, TRUE, { P_S, P_S, P_Z } },
+    {   0.0,   0.0,  5.0, {  1.0,  2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 2.0, 2.0, 1.0 }, { 2.5, 2.5, 4.5 }, TRUE, { P_S, P_Z, P_Z } },
+    {   0.0,   0.0,  5.0, {  1.0,  2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, TRUE, { P_Z, P_Z, P_Z } },
+    {   2.0,   1.0,  1.0, {  1.0,  2.0, 3.0 }, { 2.0, 3.0, 4.0 }, {  3.0,  2.0, 4.0 }, {  4.0,  3.0, 4.0 }, TRUE, { P_S, P_Z, P_S } },
+    {   0.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, { 3.0, 2.0 }, { 3.0, 2.0 }, TRUE, { P_S, P_Z } },
+    {   0.0,   0.0,  5.0, {  1.0,  2.0, 6.0 }, { 2.0, 3.0, 4.0 }, { 1.0, 2.0, 6.0 }, { 2.0, 3.0, 4.0 }, TRUE, { P_S, P_Z, P_S } },
+    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, TRUE, { P_Z, P_Z } }, /* 65 */
+    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  1.0, 11.0 }, {  3.0, 13.0 }, TRUE, { P_S, P_Z } },
+    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, TRUE, { P_Z, P_Z } },
+    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0, 11.0 }, {  2.0, 13.0 }, TRUE, { P_S, P_Z } },
+    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, TRUE, { P_Z, P_S } },
+    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, { -1.0, 11.0 }, { -8.0,  2.0 }, TRUE, { P_S, P_Z } }, /* 70 */
+    /* isDiacritic in a cluster */
+    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 11.0 }, {  3.0,  3.0 }, TRUE, { P_D, P_S } },
+    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, {  3.0,  3.0 }, TRUE, { P_D, P_S } },
+    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 10.0 }, {  3.0,  3.0 }, TRUE, { P_S, P_D } },
+    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0,  3.0 }, TRUE, { P_D, P_S } },
+    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  7.0 }, { -3.0,  3.0 }, TRUE, { P_S, P_D } }, /* 75 */
+    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0,  6.0 }, { -3.0,  3.0 }, TRUE, { P_D, P_D } },
+    {   2.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  4.0,  3.0 }, {  5.0,  3.0 }, TRUE, { P_S, P_D } },
+    {   2.0,   1.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  4.0,  4.0 }, {  5.0,  3.0 }, TRUE, { P_S, P_D } },
+    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0,  1.0 }, {  4.0,  3.0 }, TRUE, { P_D, P_D } },
+    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0,  1.0 }, {  3.0,  3.0 }, TRUE, { P_S, P_D } }, /* 80 */
+    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0, 12.0 }, { -8.0,  3.0 }, TRUE, { P_D, P_D } },
+    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0,  3.0 }, TRUE, { P_S, P_D } },
+    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, TRUE, { P_D, P_S } },
+    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, { -2.0, 12.0 }, { -8.0,  3.0 }, TRUE, { P_S, P_D } },
+    /* isZeroWidthSpace + isDiacritic */
+    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, {  2.0,  4.0 }, FALSE, { P_D_Z, P_S } }, /* 85 */
+    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, {  2.0,  4.0 }, FALSE, { P_D_Z, P_S } },
+    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  3.0,  3.0 }, FALSE, { P_S, P_D_Z } },
+    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0,  3.0 }, FALSE, { P_D_Z, P_S } },
+    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0, 11.0 }, { -1.0,  3.0 }, FALSE, { P_S, P_D_Z } },
+    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_D_Z, P_D_Z } }, /* 90 */
+    {   2.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  7.0,  2.0 }, {  6.0,  3.0 }, FALSE, { P_S, P_D_Z } },
+    {   2.0,   1.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  8.0,  2.0 }, {  6.0,  3.0 }, FALSE, { P_S, P_D_Z } },
+    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_D_Z, P_D_Z } },
+    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  6.0, 11.0 }, {  3.0,  3.0 }, FALSE, { P_S, P_D_Z } },
+    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_D_Z, P_D_Z } }, /* 95 */
+    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  5.0, 11.0 }, {  2.0,  3.0 }, FALSE, { P_S, P_D_Z } },
+    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, FALSE, { P_D_Z, P_S } },
+    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, {  6.0, 11.0 }, { -1.0,  3.0 }, FALSE, { P_S, P_D_Z } },
+    /* isZeroWidthSpace + isDiacritic in a cluster */
+    {   1.0,   0.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, {  3.0,  4.0 }, TRUE, { P_D_Z, P_S } },
+    {   1.0,   1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, {  3.0,  4.0 }, TRUE, { P_D_Z, P_S } }, /* 100 */
+    {   1.0,  -1.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  3.0,  4.0 }, TRUE, { P_S, P_D_Z } },
+    {   0.0, -10.0,  0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0,  1.0 }, {  2.0,  3.0 }, TRUE, { P_D_Z, P_S } },
+    {  -5.0,  -4.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  1.0, 11.0 }, { -3.0,  7.0 }, TRUE, { P_S, P_D_Z } },
+    {  -5.0,  -5.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, TRUE, { P_D_Z, P_D_Z } },
+    {   2.0,   0.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  5.0,  2.0 }, {  5.0,  2.0 }, TRUE, { P_S, P_D_Z } }, /* 105 */
+    {   2.0,   1.0,  5.0, {  1.0,  2.0 }, { 2.0, 3.0 }, {  6.0,  2.0 }, {  5.0,  1.0 }, TRUE, { P_S, P_D_Z } },
+    {   2.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, TRUE, { P_D_Z, P_D_Z } },
+    {   1.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  1.0, 11.0 }, {  3.0, 13.0 }, TRUE, { P_S, P_D_Z } },
+    { -10.0,   1.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, {  2.0,  3.0 }, TRUE, { P_D_Z, P_D_Z } },
+    {   0.0, -10.0,  5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0, 11.0 }, {  2.0, 13.0 }, TRUE, { P_S, P_D_Z } }, /* 110 */
+    {   1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, {  0.0,  0.0 }, {  2.0,  3.0 }, TRUE, { P_D_Z, P_S } },
+    { -10.0,   1.0,  5.0, {  8.0, 11.0 }, { 2.0, 3.0 }, { -1.0, 11.0 }, { -8.0,  2.0 }, TRUE, { P_S, P_D_Z } },
+
+#undef P_S
+#undef P_D
+#undef P_Z
+#undef P_D_Z
 };
 
 static void test_ApplyCharacterSpacing(void)
@@ -1835,20 +1916,23 @@ static void test_ApplyCharacterSpacing(void)
         offsets[1].ascenderOffset = 32.0;
         offsets[2].ascenderOffset = 31.0;
 
+        advances[0] = advances[1] = 123.45f;
+        memcpy(props, ptr->props, sizeof(props));
         glyph_count = ptr->advances[2] > 0.0 ? 3 : 2;
-        if (ptr->single_cluster) {
+        if (ptr->single_cluster)
+        {
             clustermap[0] = 0;
             clustermap[1] = 0;
+            props[0].isClusterStart = 1;
         }
-        else {
+        else
+        {
             /* trivial case with one glyph per cluster */
             clustermap[0] = 0;
             clustermap[1] = 1;
+            props[0].isClusterStart = props[1].isClusterStart = 1;
         }
 
-        advances[0] = advances[1] = 123.45;
-        memcpy(props, ptr->props, sizeof(props));
-
         hr = IDWriteTextAnalyzer1_ApplyCharacterSpacing(analyzer1,
             ptr->leading,
             ptr->trailing,
-- 
2.20.1




More information about the wine-devel mailing list