[vte/wip/egmont/bidi: 72/107] mirrors chars with combining accents



commit bba40e0f066e0883dd11825d573393a5749779d1
Author: Egmont Koblinger <egmont gmail com>
Date:   Sun Nov 11 13:21:29 2018 +0100

    mirrors chars with combining accents

 src/bidi.cc      | 35 ++++++++++++++++++++++++-----------
 src/bidi.hh      |  3 ++-
 src/vteunistr.cc | 33 +++++++++++++++++++++++++++++++++
 src/vteunistr.h  | 23 +++++++++++++++++++++++
 4 files changed, 82 insertions(+), 12 deletions(-)
---
diff --git a/src/bidi.cc b/src/bidi.cc
index 6db2b92a..9646fd17 100644
--- a/src/bidi.cc
+++ b/src/bidi.cc
@@ -509,7 +509,13 @@ next_line:
 }
 
 
-gboolean vte_bidi_get_mirror_char (gunichar ch, gboolean mirror_box_drawing, gunichar *mirrored_ch)
+/* Find the mirrored counterpart of a codepoint, just like
+ * fribidi_get_mirror_char() or g_unichar_get_mirror_char() does.
+ * Two additions:
+ * - works with vteunistr, that is, preserves combining accents;
+ * - optionally mirrors box drawing characters.
+ */
+gboolean vte_bidi_get_mirror_char (vteunistr unistr, gboolean mirror_box_drawing, vteunistr *out)
 {
         static const unsigned char mirrored_2500[0x80] = {
                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10, 0x11, 0x12, 
0x13,
@@ -521,18 +527,25 @@ gboolean vte_bidi_get_mirror_char (gunichar ch, gboolean mirror_box_drawing, gun
                 0x63, 0x5e, 0x5f, 0x60, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6e, 0x6d, 
0x70,
                 0x6f, 0x72, 0x71, 0x73, 0x76, 0x75, 0x74, 0x77, 0x7a, 0x79, 0x78, 0x7b, 0x7e, 0x7d, 0x7c, 
0x7f };
 
-        if (G_UNLIKELY (mirror_box_drawing && ch >= 0x2500 && ch < 0x2580)) {
-                gunichar mir = 0x2500 + mirrored_2500[ch - 0x2500];
-                if (mirrored_ch)
-                        *mirrored_ch = mir;
-                return mir == ch;
-        }
+        gunichar base_ch = _vte_unistr_get_base (unistr);
+        gunichar base_ch_mirrored = base_ch;
 
+        if (G_UNLIKELY (base_ch >= 0x2500 && base_ch < 0x2580)) {
+                if (G_UNLIKELY (mirror_box_drawing))
+                        base_ch_mirrored = 0x2500 + mirrored_2500[base_ch - 0x2500];
+        } else {
 #ifdef WITH_FRIBIDI
-        /* Prefer the FriBidi variant as that's more likely to be in sync with the rest of our BiDi stuff. */
-        return fribidi_get_mirror_char (ch, mirrored_ch);
+                /* Prefer the FriBidi variant as that's more likely to be in sync with the rest of our BiDi 
stuff. */
+                fribidi_get_mirror_char (base_ch, &base_ch_mirrored);
 #else
-        /* Fall back to glib, so that we still get mirrored characters in explicit RTL mode. */
-        return g_unichar_get_mirror_char (ch, mirrored_ch);
+                /* Fall back to glib, so that we still get mirrored characters in explicit RTL mode without 
BiDi support. */
+                g_unichar_get_mirror_char (base_ch, &base_ch_mirrored);
 #endif
+        }
+
+        vteunistr unistr_mirrored = _vte_unistr_replace_base (unistr, base_ch_mirrored);
+
+        if (out)
+                *out = unistr_mirrored;
+        return unistr_mirrored == unistr;
 }
diff --git a/src/bidi.hh b/src/bidi.hh
index 7044af74..b1a8da7e 100644
--- a/src/bidi.hh
+++ b/src/bidi.hh
@@ -23,6 +23,7 @@
 #include "ring.hh"
 #include "vterowdata.hh"
 #include "vtetypes.hh"
+#include "vteunistr.h"
 
 namespace vte {
 
@@ -113,6 +114,6 @@ private:
 
 G_BEGIN_DECLS
 
-gboolean vte_bidi_get_mirror_char (gunichar ch, gboolean mirror_box_drawing, gunichar *mirrored_ch);
+gboolean vte_bidi_get_mirror_char (vteunistr unistr, gboolean mirror_box_drawing, vteunistr 
*unistr_mirrored);
 
 G_END_DECLS
diff --git a/src/vteunistr.cc b/src/vteunistr.cc
index 69c47fe0..d60d2d01 100644
--- a/src/vteunistr.cc
+++ b/src/vteunistr.cc
@@ -162,6 +162,39 @@ _vte_unistr_get_base (vteunistr s)
        return (gunichar) s;
 }
 
+static void
+unistr_append_to_gunichars (vteunistr s, GArray *a)
+{
+        if (G_UNLIKELY (s >= VTE_UNISTR_START)) {
+                struct VteUnistrDecomp *decomp;
+                decomp = &DECOMP_FROM_UNISTR (s);
+                unistr_append_to_gunichars (decomp->prefix, a);
+                s = decomp->suffix;
+        }
+        gunichar val = (gunichar) s;
+        g_array_append_val (a, val);
+}
+
+vteunistr
+_vte_unistr_replace_base (vteunistr s, gunichar c)
+{
+        g_return_val_if_fail (s < unistr_next, s);
+
+        if (G_LIKELY (_vte_unistr_get_base(s) == c))
+                return s;
+
+        GArray *a = g_array_new (FALSE, FALSE, sizeof (gunichar));
+        unistr_append_to_gunichars (s, a);
+        g_assert_cmpint(a->len, >=, 1);
+
+        s = c;
+        for (glong i = 1; i < a->len; i++)
+                s = _vte_unistr_append_unichar (s, g_array_index (a, gunichar, i));
+
+        g_array_free (a, TRUE);
+        return s;
+}
+
 void
 _vte_unistr_append_to_string (vteunistr s, GString *gs)
 {
diff --git a/src/vteunistr.h b/src/vteunistr.h
index 9bde6b2c..84cb0562 100644
--- a/src/vteunistr.h
+++ b/src/vteunistr.h
@@ -73,6 +73,19 @@ _vte_unistr_append_unistr (vteunistr s, vteunistr t);
 gunichar
 _vte_unistr_get_base (vteunistr s);
 
+/**
+ * _vte_unistr_append_to_string:
+ * @s: a #vteunistr
+ * @c: Unicode character to replace the base character of @s.
+ *
+ * Creates a vteunistr value where the base character from @s is
+ * replaced by @c, while the combining characters from @s are carried over.
+ *
+ * Returns: the new #vteunistr value
+ */
+vteunistr
+_vte_unistr_replace_base (vteunistr s, gunichar c);
+
 /**
  * _vte_unistr_append_to_string:
  * @s: a #vteunistr
@@ -84,6 +97,16 @@ _vte_unistr_get_base (vteunistr s);
 void
 _vte_unistr_append_to_string (vteunistr s, GString *gs);
 
+/**
+ * _vte_unistr_append_to_gunichars:
+ * @s: a #vteunistr
+ * @a: a #GArray of #gunichar items to append @s to
+ *
+ * Appends @s to @a.
+ **/
+void
+_vte_unistr_append_to_gunichars (vteunistr s, GArray *a);
+
 /**
  * _vte_unistr_strlen:
  * @s: a #vteunistr


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]