[vte/wip/egmont/bidi: 91/107] etap3



commit 15450c88fb5865c3fa3628291bc59ca3598036da
Author: Egmont Koblinger <egmont gmail com>
Date:   Fri May 24 01:35:14 2019 +0200

    etap3

 src/bidi.cc | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
 src/bidi.hh |   7 ++--
 2 files changed, 108 insertions(+), 21 deletions(-)
---
diff --git a/src/bidi.cc b/src/bidi.cc
index c7411a2f..4514ac8b 100644
--- a/src/bidi.cc
+++ b/src/bidi.cc
@@ -42,6 +42,7 @@ using namespace vte::base;
 
 BidiRow::BidiRow()
 {
+        /* The value of 0 is a valid representation of the trivial LTR mapping. */
         m_width = 0;
 
         /* These will be initialized / allocated on demand, when some RTL is encountered. */
@@ -144,7 +145,7 @@ bool BidiRow::base_is_rtl() const
         return m_base_rtl;
 }
 
-/* Whether the paragraph contains a foreign directionality character.
+/* Whether the implicit paragraph contains a foreign directionality character.
  * This is used in the cursor, showing the character's directionality. */
 bool BidiRow::has_foreign() const
 {
@@ -159,8 +160,33 @@ BidiRunner::BidiRunner(RingView *ringview)
 
 BidiRunner::~BidiRunner() {}
 
-/* Set up the mapping according to explicit mode for a given line. */
-void BidiRunner::explicit_line(vte::grid::row_t row, bool rtl)
+/* Returns whether there's an Arabic character in the row so that shaping might be required. */
+bool BidiRunner::needs_shaping(vte::grid::row_t row)
+{
+        const gulong MIN_SHAPING = 0x0600;
+        const gulong MAX_SHAPING = 0x06FF;
+
+        const VteRowData *row_data = m_ringview->get_row(row);
+
+        for (int i = 0; i < row_data->len; i++) {
+                const VteCell *cell = _vte_row_data_get(row_data, i);
+                if (cell != nullptr) {
+                        gunichar c = _vte_unistr_get_base(cell->c);
+                        if (G_UNLIKELY (c >= MIN_SHAPING && c <= MAX_SHAPING))
+                                return true;
+                }
+        }
+        return false;
+}
+
+/* Set up the mapping according to explicit mode for a given line.
+ *
+ * If @shape then perform Arabic shaping on the visual string, independently
+ * from the paragraph direction (the @rtl parameter). This is done using
+ * presentation form characters, until we have something better (e.g. HarfBuzz)
+ * in place.
+ */
+void BidiRunner::explicit_line(vte::grid::row_t row, bool rtl, bool shape)
 {
         int i;
 
@@ -170,27 +196,87 @@ void BidiRunner::explicit_line(vte::grid::row_t row, bool rtl)
         bidirow->m_base_rtl = rtl;
         bidirow->m_has_foreign = false;
 
-        if (G_UNLIKELY (rtl)) {
-                auto width = m_ringview->get_width();
+        auto width = m_ringview->get_width();
+
+        if (G_LIKELY (!rtl)) {
+                if (!shape || !needs_shaping(row)) {
+                        /* Shortcut notation: a width of 0 means the trivial LTR mapping. */
+                        bidirow->set_width(0);
+                        return;
+                }
+                bidirow->set_width(width);
+                for (i = 0; i < width; i++) {
+                        bidirow->m_log2vis[i] = bidirow->m_vis2log[i] = i;
+                        bidirow->m_vis_rtl[i] = false;
+                        bidirow->m_vis_shaped_char[i] = 0;
+                }
+        } else {
                 bidirow->set_width(width);
                 for (i = 0; i < width; i++) {
                         bidirow->m_log2vis[i] = bidirow->m_vis2log[i] = width - 1 - i;
                         bidirow->m_vis_rtl[i] = true;
                         bidirow->m_vis_shaped_char[i] = 0;
                 }
-        } else {
-                /* Shortcut: bidirow->m_width == 0 might denote a fully LTR line,
-                 * m_width_alloc might even be 0 along with log2vis and friends being nullptr in this case. 
*/
-                bidirow->set_width(0);
+                if (!shape || !needs_shaping(row)) {
+                        return;
+               }
+        }
+
+        /* Perform Arabic shaping on an explicit line (which could be explicit LTR or explicit RTL).
+         * Don't do shaping across (soft) linebreaks (I'm unsure about it).
+         * The FriBiDi API doesn't have such a method, so we need to extract Arabic words ourselves,
+         * by walking in the visual order from right to left. */
+
+        // FIXME this is going to be freaking cumbersome.
+
+#if 0 // bleeeeh
+        GArray *fribidi_chars_array = nullptr;
+        
+        VteCell *cell;
+        gunichar c;
+        gunichar base;
+        i = width - 1;
+        while (i >= 0) {
+                cell = _vte_row_data_get(row_data, bidirow->m_vis2log[i]);
+                c = cell->c;
+                base = _vte_unistr_get_base(c);
+                if (base < MIN_SHAPING || base > MAX_SHAPING) {
+                        i--;
+                        continue;
+                }
+
+                /* Found an Arabic character. Keep walking to the left, extracting the word. */
+                       fribidi_chars_array = g_array_new (FALSE, FALSE, sizeof (FriBidiChar));
+                       j = i;
+                do {
+                        auto prev_len = fribidi_chars_array->len;
+                        _vte_unistr_append_to_gunichars (cell->c, fribidi_chars_array);
+                        g_assert_cmpint (fribidi_chars_array->len, >, prev_len);
+
+                        j--;
+                        if (j >= 0) {
+                                cell = _vte_row_data_get(row_data, bidirow->m_vis2log[j]);
+                                c = cell->c;
+                                base = _vte_unistr_get_base(c);
+                       } else {
+                               base = 0;
+                       }
+                } while (base >= MIN_SHAPING && base <= MAX_SHAPING);
+
+
+
         }
+#endif
+
+
 }
 
 /* Set up the mapping according to explicit mode, for all the lines
  * of a paragraph between the given lines. */
-void BidiRunner::explicit_paragraph(vte::grid::row_t start, vte::grid::row_t end, bool rtl)
+void BidiRunner::explicit_paragraph(vte::grid::row_t start, vte::grid::row_t end, bool rtl, bool shape)
 {
         for (; start < end; start++) {
-                explicit_line(start, rtl);
+                explicit_line(start, rtl, shape);
         }
 }
 
@@ -199,7 +285,7 @@ void BidiRunner::paragraph(vte::grid::row_t start, vte::grid::row_t end)
 {
 #ifndef WITH_FRIBIDI
         const VteRowData *row_data = m_ringview->get_row(start);
-        explicit_paragraph(start, end, row_data->attr.bidi_flags & VTE_BIDI_RTL);
+        explicit_paragraph(start, end, row_data->attr.bidi_flags & VTE_BIDI_RTL, false);
 #else
         const VteCell *cell;
         const VteRowData *row_data;
@@ -222,7 +308,7 @@ void BidiRunner::paragraph(vte::grid::row_t start, vte::grid::row_t end)
         row_data = m_ringview->get_row(start);
         if (!(row_data->attr.bidi_flags & VTE_BIDI_IMPLICIT) ||
             end - start > VTE_RINGVIEW_PARAGRAPH_LENGTH_MAX) {
-                explicit_paragraph(start, end, row_data->attr.bidi_flags & VTE_BIDI_RTL);
+                explicit_paragraph(start, end, row_data->attr.bidi_flags & VTE_BIDI_RTL, true);
                 return;
         }
 
@@ -366,7 +452,7 @@ void BidiRunner::paragraph(vte::grid::row_t start, vte::grid::row_t end)
                 g_array_free (fribidi_chars_array, TRUE);
                 g_array_free (fribidi_map_array, TRUE);
                 g_array_free (fribidi_to_term_array, TRUE);
-                explicit_paragraph (start, end, rtl);
+                explicit_paragraph (start, end, rtl, true);
                 return;
         }
 #endif
@@ -396,7 +482,7 @@ void BidiRunner::paragraph(vte::grid::row_t start, vte::grid::row_t end)
                 g_array_free (fribidi_chars_array, TRUE);
                 g_array_free (fribidi_map_array, TRUE);
                 g_array_free (fribidi_to_term_array, TRUE);
-                explicit_paragraph (start, end, rtl);
+                explicit_paragraph (start, end, rtl, false);
                 return;
         }
 
@@ -429,7 +515,7 @@ void BidiRunner::paragraph(vte::grid::row_t start, vte::grid::row_t end)
                 g_array_free (fribidi_chars_array, TRUE);
                 g_array_free (fribidi_map_array, TRUE);
                 g_array_free (fribidi_to_term_array, TRUE);
-                explicit_paragraph (start, end, false);
+                explicit_paragraph (start, end, false, false);
                 return;
         }
 
@@ -456,14 +542,14 @@ void BidiRunner::paragraph(vte::grid::row_t start, vte::grid::row_t end)
 
                 if (level == 0) {
                         /* error, what should we do? */
-                        explicit_line (row, rtl);
+                        explicit_line (row, rtl, true);
                         bidirow->m_has_foreign = true;
                         continue;
                 }
 
                 if (!rtl && level == 1) {
                         /* Fast shortcut for LTR-only lines. */
-                        explicit_line (row, false);
+                        explicit_line (row, false, false);
                         bidirow->m_has_foreign = true;
                         continue;
                 }
diff --git a/src/bidi.hh b/src/bidi.hh
index a257f7d9..b0c277a7 100644
--- a/src/bidi.hh
+++ b/src/bidi.hh
@@ -73,7 +73,7 @@ private:
 };
 
 
-/* BidiRunner is not a real class, rather the collection of methods that run the BiDi algorithm. */
+/* BidiRunner is not a "real" class, rather the collection of methods that run the BiDi algorithm. */
 class BidiRunner {
 public:
         BidiRunner(RingView *ringview);
@@ -92,8 +92,9 @@ public:
 private:
         RingView *m_ringview;
 
-        void explicit_line(vte::grid::row_t row, bool rtl);
-        void explicit_paragraph(vte::grid::row_t start, vte::grid::row_t end, bool rtl);
+        bool needs_shaping(vte::grid::row_t row);
+        void explicit_line(vte::grid::row_t row, bool rtl, bool shape);
+        void explicit_paragraph(vte::grid::row_t start, vte::grid::row_t end, bool rtl, bool shape);
 };
 
 }; /* namespace base */


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