[vte/wip/egmont/bidi: 14/21] etap12



commit bc306da3067dd6bc6116f82f415c9cee0719a197
Author: Egmont Koblinger <egmont gmail com>
Date:   Sat May 25 13:29:41 2019 +0200

    etap12

 src/bidi.cc     |  6 ++--
 src/ringview.cc | 15 +++++-----
 src/ringview.hh |  4 +--
 src/vte.cc      | 87 +++++++++++++++++++++++++++++++++++----------------------
 4 files changed, 66 insertions(+), 46 deletions(-)
---
diff --git a/src/bidi.cc b/src/bidi.cc
index dfee836b..1a3b0ee8 100644
--- a/src/bidi.cc
+++ b/src/bidi.cc
@@ -203,7 +203,7 @@ void BidiRunner::explicit_line_shape(vte::grid::row_t row)
         if (G_UNLIKELY (row_data == nullptr))
                 return;
 
-        BidiRow *bidirow = m_ringview->get_row_map_writable(row);
+        BidiRow *bidirow = m_ringview->get_bidirow_writable(row);
 
         auto width = m_ringview->get_width();
 
@@ -318,7 +318,7 @@ void BidiRunner::explicit_line(vte::grid::row_t row, bool rtl, bool shape)
 {
         int i;
 
-        BidiRow *bidirow = m_ringview->get_row_map_writable(row);
+        BidiRow *bidirow = m_ringview->get_bidirow_writable(row);
         if (G_UNLIKELY (bidirow == nullptr))
                 return;
         bidirow->m_base_rtl = rtl;
@@ -588,7 +588,7 @@ bool BidiRunner::implicit_paragraph(vte::grid::row_t start, vte::grid::row_t end
 
         /* Reshuffle line by line. */
         for (row = start, line = 0; row < end; row++, line++) {
-                bidirow = m_ringview->get_row_map_writable(row);
+                bidirow = m_ringview->get_bidirow_writable(row);
                 if (bidirow == nullptr)
                         continue;
 
diff --git a/src/ringview.cc b/src/ringview.cc
index 5138f7f3..82c428db 100644
--- a/src/ringview.cc
+++ b/src/ringview.cc
@@ -93,13 +93,12 @@ void RingView::unpause()
                 m_bidirows[i] = new BidiRow();
         }
 
-        m_invalid = true;
         m_paused = false;
 }
 
 void RingView::set_ring(Ring *ring)
 {
-        if (ring == m_ring)
+        if (G_LIKELY (ring == m_ring))
                 return;
 
         m_ring = ring;
@@ -108,7 +107,7 @@ void RingView::set_ring(Ring *ring)
 
 void RingView::set_width(vte::grid::column_t width)
 {
-        if (width == m_width)
+        if (G_LIKELY (width == m_width))
                 return;
 
         m_width = width;
@@ -117,12 +116,12 @@ void RingView::set_width(vte::grid::column_t width)
 
 void RingView::set_rows(vte::grid::row_t start, vte::grid::row_t len)
 {
-        g_assert_cmpint (len, >=, 1);
-
         if (start == m_start && len == m_len)
                 return;
 
-        /* m_rows is expended on demand in update() */
+        g_assert_cmpint (len, >=, 1);
+
+        /* m_rows is expanded on demand in update() */
 
         /* m_bidirows needs exactly these many lines */
         if (G_UNLIKELY (!m_paused && len > m_bidirows_alloc_len)) {
@@ -234,7 +233,7 @@ void RingView::update()
         m_invalid = false;
 }
 
-BidiRow const* RingView::get_row_map(vte::grid::row_t row) const
+BidiRow const* RingView::get_bidirow(vte::grid::row_t row) const
 {
         g_assert_cmpint (row, >=, m_start);
         g_assert_cmpint (row, <, m_start + m_len);
@@ -246,7 +245,7 @@ BidiRow const* RingView::get_row_map(vte::grid::row_t row) const
 
 /* For internal use by BidiRunner. Get where the BiDi mapping for the given row
  * needs to be stored, of nullptr if it's a context row. */
-BidiRow* RingView::get_row_map_writable(vte::grid::row_t row) const
+BidiRow* RingView::get_bidirow_writable(vte::grid::row_t row) const
 {
         if (row < m_start || row >= m_start + m_len)
                 return nullptr;
diff --git a/src/ringview.hh b/src/ringview.hh
index 3a68fdb9..77bac334 100644
--- a/src/ringview.hh
+++ b/src/ringview.hh
@@ -76,8 +76,8 @@ public:
 
         VteRowData *get_row(vte::grid::row_t row);
 
-        BidiRow const* get_row_map(vte::grid::row_t row) const;
-        BidiRow* get_row_map_writable(vte::grid::row_t row) const;
+        BidiRow const* get_bidirow(vte::grid::row_t row) const;
+        BidiRow* get_bidirow_writable(vte::grid::row_t row) const;
 
 private:
         Ring *m_ring;
diff --git a/src/vte.cc b/src/vte.cc
index 23863f7c..9b8969d7 100644
--- a/src/vte.cc
+++ b/src/vte.cc
@@ -1567,7 +1567,7 @@ Terminal::grid_coords_from_view_coords(vte::view::coords const& pos) const
         vte::grid::row_t row = pixel_to_row(pos.y);
 
         /* BiDi: convert to logical column. */
-        vte::base::BidiRow const* bidirow = m_ringview.get_row_map(confine_grid_row(row));
+        vte::base::BidiRow const* bidirow = m_ringview.get_bidirow(confine_grid_row(row));
         col = bidirow->vis2log(col);
 
         return vte::grid::coords(row, col);
@@ -1675,7 +1675,7 @@ Terminal::selection_grid_halfcoords_from_view_coords(vte::view::coords const& po
 
         if (!m_selection_block_mode) {
                 /* BiDi: convert from visual to logical half column. */
-                vte::base::BidiRow const* bidirow = m_ringview.get_row_map(confine_grid_row(row));
+                vte::base::BidiRow const* bidirow = m_ringview.get_bidirow(confine_grid_row(row));
 
                 if (bidirow->vis_is_rtl(col))
                         half = 1 - half;
@@ -5014,21 +5014,21 @@ Terminal::widget_key_press(GdkEventKey *event)
                /* If the above switch statement didn't do the job, try mapping
                 * it to a literal or capability name. */
                 if (handled == FALSE) {
-                        /* In keyboard arrow swapping mode, the left and right arrows
-                         * are swapped if the cursor stands inside an RTL paragraph. */
-                        if (m_modes_private.VTE_BIDI_SWAP_ARROW_KEYS() &&
-                            (keyval == GDK_KEY_Left ||
-                             keyval == GDK_KEY_Right ||
-                             keyval == GDK_KEY_KP_Left ||
-                             keyval == GDK_KEY_KP_Right)) {
-                                /* m_ringview is for the onscreen contents and the cursor may be
-                                 * offscreen, so use a temporary ringview for the cursor's row. */
-                                vte::base::RingView *ringview = new vte::base::RingView();
-                                ringview->set_ring(m_screen->row_data);
-                                ringview->set_rows(m_screen->cursor.row, 1);
-                                ringview->set_width(m_column_count);
-                                ringview->update();
-                                if (ringview->get_row_map(m_screen->cursor.row)->base_is_rtl()) {
+                        if (G_UNLIKELY (m_modes_private.VTE_BIDI_SWAP_ARROW_KEYS() &&
+                                        (keyval == GDK_KEY_Left ||
+                                         keyval == GDK_KEY_Right ||
+                                         keyval == GDK_KEY_KP_Left ||
+                                         keyval == GDK_KEY_KP_Right))) {
+                                /* In keyboard arrow swapping mode, the left and right arrows are swapped
+                                 * if the cursor stands inside a (possibly autodetected) RTL paragraph.
+                                 * m_ringview is for the onscreen contents and the cursor may be offscreen.
+                                 * Better leave that alone and use a temporary ringview for the cursor's 
row. */
+                                vte::base::RingView ringview;
+                                ringview.set_ring(m_screen->row_data);
+                                ringview.set_rows(m_screen->cursor.row, 1);
+                                ringview.set_width(m_column_count);
+                                ringview.update();
+                                if (ringview.get_bidirow(m_screen->cursor.row)->base_is_rtl()) {
                                         switch (keyval) {
                                         case GDK_KEY_Left:
                                                 keyval = GDK_KEY_Right;
@@ -5044,7 +5044,6 @@ Terminal::widget_key_press(GdkEventKey *event)
                                                 break;
                                         }
                                 }
-                                delete ringview;
                         }
 
                        _vte_keymap_map(keyval, m_modifiers,
@@ -5596,7 +5595,7 @@ Terminal::cell_is_selected_vis(vte::grid::column_t col,
         if (m_selection_block_mode) {
                 /* In block mode, make sure CJKs and TABs aren't cut in half. */
                 /* BiDi: convert to logical column... */
-                vte::base::BidiRow const* bidirow = m_ringview.get_row_map(row);
+                vte::base::BidiRow const* bidirow = m_ringview.get_bidirow(row);
                 col = bidirow->vis2log(col);
                 while (col > 0) {
                         VteCell const* cell = find_charcell(col, row);
@@ -5609,7 +5608,7 @@ Terminal::cell_is_selected_vis(vte::grid::column_t col,
                 return m_selection_resolved.box_contains ({ row, col });
         } else {
                 /* BiDi: convert to logical column. */
-                vte::base::BidiRow const* bidirow = m_ringview.get_row_map(row);
+                vte::base::BidiRow const* bidirow = m_ringview.get_bidirow(row);
                 col = bidirow->vis2log(col);
                 /* In normal modes, resolve_selection() made sure to generate such boundaries for 
m_selection_resolved. */
                 return m_selection_resolved.contains ({ row, col });
@@ -6072,7 +6071,7 @@ Terminal::match_hilite_update()
         glong row = pixel_to_row(pos.y);
 
         /* BiDi: convert to logical column. */
-        vte::base::BidiRow const* bidirow = m_ringview.get_row_map(confine_grid_row(row));
+        vte::base::BidiRow const* bidirow = m_ringview.get_bidirow(confine_grid_row(row));
         col = bidirow->vis2log(col);
 
        _vte_debug_print(VTE_DEBUG_EVENTS,
@@ -6295,9 +6294,9 @@ Terminal::get_text(vte::grid::row_t start_row,
         if (block) {
                 /* Rectangular selection operates on the visual contents, not the logical.
                  * m_ringview corresponds to the currently onscreen bits, therefore does not
-                 * necessarily include the entire selection.
-                 * Modifying m_ringview and then reverting would be a bit cumbersome,
-                 * creating a new one for the selection is simpler. */
+                 * necessarily include the entire selection. Also we want m_ringview's size
+                 * to be limited, even if the user selects a giant rectangle.
+                 * So use a new ringview for the selection. */
                 ringview = new vte::base::RingView();
                 ringview->set_ring(m_screen->row_data);
                 ringview->set_rows(start_row, end_row - start_row + 1);
@@ -6320,7 +6319,7 @@ Terminal::get_text(vte::grid::row_t start_row,
                attr.column = col;  // FIXME is attr.column supposed to contain logical or visual? What is it 
used for?
                pcell = NULL;
                if (row_data != NULL) {
-                        bidirow = ringview ? ringview->get_row_map(row) : nullptr;
+                        bidirow = ringview ? ringview->get_bidirow(row) : nullptr;
                         while (col < line_last_column &&
                                (pcell = _vte_row_data_get (row_data, col))) {
 
@@ -7019,8 +7018,6 @@ Terminal::widget_motion_notify(GdkEventMotion *event)
                          "Motion notify %s %s\n",
                          pos.to_string(), rowcol.to_string());
 
-        ringview_update();
-
        read_modifiers(base_event);
 
        switch (event->type) {
@@ -9114,7 +9111,7 @@ Terminal::draw_rows(VteScreen *screen_,
                 if (row_data == nullptr)
                         continue; /* Skip row. FIXME: just paint this row empty? */
 
-                bidirow = m_ringview.get_row_map(row);
+                bidirow = m_ringview.get_bidirow(row);
                 i = j = 0;
                 /* Walk the line.
                  * Locate runs of identical bg colors within a row, and paint each run as a single 
rectangle. */
@@ -9194,7 +9191,7 @@ Terminal::draw_rows(VteScreen *screen_,
                 /* Ensure that drawing is restricted to the cell (plus the overdraw area) */
                 _vte_draw_autoclip_t clipper{m_draw, &rect};
 
-                bidirow = m_ringview.get_row_map(row);
+                bidirow = m_ringview.get_bidirow(row);
 
                 /* Walk the line in logical order.
                  * Locate runs of identical attributes within a row, and draw each run using a single 
draw_cells() call. */
@@ -9273,6 +9270,30 @@ Terminal::draw_rows(VteScreen *screen_,
                                 }
                         }
 
+                        /* There are certain mandatory ligatures in Arabic, e.g.
+                         * LAM U+0644 (on the right) + ALEF U+0627 (on the left)
+                         * needs to become a single symbol (U+FEFB or U+FEFC in the
+                         * legacy presentation form characters).
+                         * FriBidi replaces the first (right) character with ZWNBSP U+FEFF and
+                         * the second (left) character with the desired presentational form.
+                         * Detect if we're about to render this glyph, and shift by half a cell
+                         * to the right. */
+                        vteunistr c_shaped = bidirow->vis_get_shaped_char(vcol, c);
+                        int xoff = 0;
+                        if (G_UNLIKELY (c_shaped != c && lcol > 0 && vcol < column_count - 1)) {
+                                int vcol2 = vcol + 1;
+                                int lcol2 = bidirow->vis2log(vcol2);
+                                if (lcol2 == lcol - 1) {
+                                        const VteCell *cell2 = _vte_row_data_get (row_data, lcol2);
+                                        g_assert(cell2 != nullptr);
+                                        vteunistr c2 = cell2->c;
+                                        vteunistr c2_shaped = bidirow->vis_get_shaped_char(vcol2, c2);
+                                        if (c2 != 0xFEFF && c2_shaped == 0xFEFF) {
+                                                xoff = column_width / 2;
+                                        }
+                                }
+                        }
+
                         attr = nattr;
                         fore = nfore;
                         back = nback;
@@ -9283,7 +9304,7 @@ Terminal::draw_rows(VteScreen *screen_,
                         g_assert_cmpint (item_count, <, column_count);
                         items[item_count].c = bidirow->vis_get_shaped_char(vcol, c);
                         items[item_count].columns = j - lcol;
-                        items[item_count].x = (vcol - (bidirow->vis_is_rtl(vcol) ? items[item_count].columns 
- 1 : 0)) * column_width;
+                        items[item_count].x = (vcol - (bidirow->vis_is_rtl(vcol) ? items[item_count].columns 
- 1 : 0)) * column_width + xoff;
                         items[item_count].y = y;
                         items[item_count].mirror = bidirow->vis_is_rtl(vcol);
                         items[item_count].box_mirror = !!(row_data->attr.bidi_flags & VTE_BIDI_BOX_MIRROR);
@@ -9343,7 +9364,7 @@ Terminal::paint_cursor()
         /* Find the first cell of the character "under" the cursor.
          * This is for CJK.  For TAB, paint the cursor where it really is. */
         VteRowData const *row_data = find_row_data(drow);
-        vte::base::BidiRow const *bidirow = m_ringview.get_row_map(drow);
+        vte::base::BidiRow const *bidirow = m_ringview.get_bidirow(drow);
 
        auto cell = find_charcell(col, drow);
         while (cell != NULL && cell->attr.fragment() && cell->c != '\t' && col > 0) {
@@ -9496,7 +9517,7 @@ Terminal::paint_im_preedit_string()
         row = m_screen->cursor.row;
         if (row < first_displayed_row() || row > last_displayed_row())
                 return;
-        vte::base::BidiRow const *bidirow = m_ringview.get_row_map(row);
+        vte::base::BidiRow const *bidirow = m_ringview.get_bidirow(row);
 
        /* Keep local copies of rendering information. */
        width = m_cell_width;
@@ -9721,7 +9742,7 @@ Terminal::widget_scroll(GdkEventScroll *event)
 
         GdkEvent *base_event = reinterpret_cast<GdkEvent*>(event);
 
-        ringview_update();
+//        ringview_update();  // needed?
 
        read_modifiers(base_event);
 


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