[vte/wip/egmont/bidi: 77/78] mirrors chars with combining accents



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

    mirrors chars with combining accents

 src/bidi.cc | 49 +++++++++++++++++++++++++++++++++++++------------
 src/bidi.hh |  3 ++-
 2 files changed, 39 insertions(+), 13 deletions(-)
---
diff --git a/src/bidi.cc b/src/bidi.cc
index 6db2b92a..74663578 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,37 @@ 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;
-        }
-
+        /* FIXME This is a bit ugly, doing an unnecessary ucs4->utf8->ucs4 conversion.
+         * Instead, there should be a _vte_unistr_append_to_ucs4string(). */
+        GString *utf8 = g_string_new("");
+        _vte_unistr_append_to_string(unistr, utf8);
+        glong ucs4_len;
+        gunichar *ucs4 = g_utf8_to_ucs4(utf8->str, -1, NULL, &ucs4_len, NULL);
+        g_assert_nonnull(ucs4);
+        g_assert_cmpint(ucs4_len, >=, 1);
+
+        gunichar base_ch = ucs4[0];
+        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 = base_ch_mirrored;
+        for (glong i = 1; i < ucs4_len; i++)
+                unistr_mirrored = _vte_unistr_append_unichar(unistr_mirrored, ucs4[i]);
+
+        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


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