| File: | _build/../src/ringview.cc |
| Warning: | line 261, column 25 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright © 2018–2019 Egmont Koblinger | |||
| 3 | * | |||
| 4 | * This library is free software; you can redistribute it and/or | |||
| 5 | * modify it under the terms of the GNU Lesser General Public | |||
| 6 | * License as published by the Free Software Foundation; either | |||
| 7 | * version 2.1 of the License, or (at your option) any later version. | |||
| 8 | * | |||
| 9 | * This library is distributed in the hope that it will be useful, | |||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| 12 | * Lesser General Public License for more details. | |||
| 13 | * | |||
| 14 | * You should have received a copy of the GNU Lesser General Public | |||
| 15 | * License along with this library; if not, write to the Free Software | |||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| 17 | */ | |||
| 18 | ||||
| 19 | #include <config.h> | |||
| 20 | ||||
| 21 | #include "bidi.hh" | |||
| 22 | #include "debug.h" | |||
| 23 | #include "btedefines.hh" | |||
| 24 | #include "bteinternal.hh" | |||
| 25 | ||||
| 26 | using namespace bte::base; | |||
| 27 | ||||
| 28 | RingView::RingView() | |||
| 29 | { | |||
| 30 | m_bidirunner = std::make_unique<BidiRunner>(this); | |||
| 31 | } | |||
| 32 | ||||
| 33 | RingView::~RingView() | |||
| 34 | { | |||
| 35 | pause(); | |||
| 36 | } | |||
| 37 | ||||
| 38 | /* Pausing a RingView frees up pretty much all of its memory. | |||
| 39 | * | |||
| 40 | * This is to be used when the terminal is unlikely to be painted or interacted with | |||
| 41 | * in the near future, e.g. the widget is unmapped. Not to be called too frequently, | |||
| 42 | * in order to avoid memory fragmentation. | |||
| 43 | * | |||
| 44 | * The RingView is resumed automatically on demand. | |||
| 45 | */ | |||
| 46 | void | |||
| 47 | RingView::pause() | |||
| 48 | { | |||
| 49 | int i; | |||
| 50 | ||||
| 51 | if (m_paused) | |||
| 52 | return; | |||
| 53 | ||||
| 54 | _bte_debug_print (BTE_DEBUG_RINGVIEW, "Ringview: pause, freeing %d rows, %d bidirows.\n",do { } while(0) | |||
| 55 | m_rows_alloc_len, m_bidirows_alloc_len)do { } while(0); | |||
| 56 | ||||
| 57 | for (i = 0; i < m_rows_alloc_len; i++) { | |||
| 58 | _bte_row_data_fini(m_rows[i]); | |||
| 59 | g_free (m_rows[i]); | |||
| 60 | } | |||
| 61 | g_free (m_rows); | |||
| 62 | m_rows_alloc_len = 0; | |||
| 63 | ||||
| 64 | for (i = 0; i < m_bidirows_alloc_len; i++) { | |||
| 65 | delete m_bidirows[i]; | |||
| 66 | } | |||
| 67 | g_free (m_bidirows); | |||
| 68 | m_bidirows_alloc_len = 0; | |||
| 69 | ||||
| 70 | m_invalid = true; | |||
| 71 | m_paused = true; | |||
| 72 | } | |||
| 73 | ||||
| 74 | /* Allocate (again) the required memory. */ | |||
| 75 | void | |||
| 76 | RingView::resume() | |||
| 77 | { | |||
| 78 | g_assert_cmpint (m_len, >=, 1)do { gint64 __n1 = (m_len), __n2 = (1); if (__n1 >= __n2) ; else g_assertion_message_cmpint ("BTE", "../src/ringview.cc" , 78, ((const char*) (__PRETTY_FUNCTION__)), "m_len" " " ">=" " " "1", (guint64)__n1, ">=", (guint64)__n2, 'i'); } while (0); | |||
| 79 | ||||
| 80 | /* +16: A bit of arbitrary heuristics to likely prevent a quickly following | |||
| 81 | * realloc for the required context lines. */ | |||
| 82 | m_rows_alloc_len = m_len + 16; | |||
| 83 | m_rows = (BteRowData **) g_malloc (sizeof (BteRowData *) * m_rows_alloc_len); | |||
| 84 | for (int i = 0; i < m_rows_alloc_len; i++) { | |||
| 85 | m_rows[i] = (BteRowData *) g_malloc (sizeof (BteRowData)); | |||
| 86 | _bte_row_data_init (m_rows[i]); | |||
| 87 | } | |||
| 88 | ||||
| 89 | /* +2: Likely prevent a quickly following realloc. | |||
| 90 | * The number of lines of interest keeps jumping up and down by one | |||
| 91 | * due to per-pixel scrolling, and by another one due sometimes having | |||
| 92 | * to reshuffle another line below the bottom for the overflowing bits | |||
| 93 | * of the outline rectangle cursor. */ | |||
| 94 | m_bidirows_alloc_len = m_len + 2; | |||
| 95 | m_bidirows = (BidiRow **) g_malloc (sizeof (BidiRow *) * m_bidirows_alloc_len); | |||
| 96 | for (int i = 0; i < m_bidirows_alloc_len; i++) { | |||
| 97 | m_bidirows[i] = new BidiRow(); | |||
| 98 | } | |||
| 99 | ||||
| 100 | _bte_debug_print (BTE_DEBUG_RINGVIEW, "Ringview: resume, allocating %d rows, %d bidirows\n",do { } while(0) | |||
| 101 | m_rows_alloc_len, m_bidirows_alloc_len)do { } while(0); | |||
| 102 | ||||
| 103 | m_paused = false; | |||
| 104 | } | |||
| 105 | ||||
| 106 | void | |||
| 107 | RingView::set_ring(Ring *ring) | |||
| 108 | { | |||
| 109 | if (G_LIKELY (ring == m_ring)(__builtin_expect (__extension__ ({ int _g_boolean_var_25 = 0 ; if (ring == m_ring) _g_boolean_var_25 = 1; _g_boolean_var_25 ; }), 1))) | |||
| 110 | return; | |||
| 111 | ||||
| 112 | m_ring = ring; | |||
| 113 | m_invalid = true; | |||
| 114 | } | |||
| 115 | ||||
| 116 | void | |||
| 117 | RingView::set_width(bte::grid::column_t width) | |||
| 118 | { | |||
| 119 | if (G_LIKELY (width == m_width)(__builtin_expect (__extension__ ({ int _g_boolean_var_26 = 0 ; if (width == m_width) _g_boolean_var_26 = 1; _g_boolean_var_26 ; }), 1))) | |||
| 120 | return; | |||
| 121 | ||||
| 122 | m_width = width; | |||
| 123 | m_invalid = true; | |||
| 124 | } | |||
| 125 | ||||
| 126 | void | |||
| 127 | RingView::set_rows(bte::grid::row_t start, bte::grid::row_t len) | |||
| 128 | { | |||
| 129 | /* Force at least 1 row, see bug 134. */ | |||
| 130 | len = MAX(len, 1)(((len) > (1)) ? (len) : (1)); | |||
| 131 | ||||
| 132 | if (start == m_start && len == m_len) | |||
| 133 | return; | |||
| 134 | ||||
| 135 | /* With per-pixel scrolling, the desired viewport often shrinks by | |||
| 136 | * one row at one end, and remains the same at the other end. | |||
| 137 | * Save work by just keeping the current valid data in this case. */ | |||
| 138 | if (!m_invalid && start >= m_start && start + len <= m_start + m_len) | |||
| 139 | return; | |||
| 140 | ||||
| 141 | /* m_rows is expanded on demand in update() */ | |||
| 142 | ||||
| 143 | /* m_bidirows needs exactly this many lines */ | |||
| 144 | if (G_UNLIKELY (!m_paused && len > m_bidirows_alloc_len)(__builtin_expect (__extension__ ({ int _g_boolean_var_27 = 0 ; if (!m_paused && len > m_bidirows_alloc_len) _g_boolean_var_27 = 1; _g_boolean_var_27; }), 0))) { | |||
| 145 | int i = m_bidirows_alloc_len; | |||
| 146 | while (len > m_bidirows_alloc_len) { | |||
| 147 | /* Don't realloc too aggressively. */ | |||
| 148 | m_bidirows_alloc_len = std::max(m_bidirows_alloc_len + 1, m_bidirows_alloc_len * 5 / 4 /* whatever */); | |||
| 149 | } | |||
| 150 | _bte_debug_print (BTE_DEBUG_RINGVIEW, "Ringview: reallocate to %d bidirows\n",do { } while(0) | |||
| 151 | m_bidirows_alloc_len)do { } while(0); | |||
| 152 | m_bidirows = (BidiRow **) g_realloc (m_bidirows, sizeof (BidiRow *) * m_bidirows_alloc_len); | |||
| 153 | for (; i < m_bidirows_alloc_len; i++) { | |||
| 154 | m_bidirows[i] = new BidiRow(); | |||
| 155 | } | |||
| 156 | } | |||
| 157 | ||||
| 158 | m_start = start; | |||
| 159 | m_len = len; | |||
| 160 | m_invalid = true; | |||
| 161 | } | |||
| 162 | ||||
| 163 | BteRowData const* | |||
| 164 | RingView::get_row(bte::grid::row_t row) const | |||
| 165 | { | |||
| 166 | g_assert_cmpint(row, >=, m_top)do { gint64 __n1 = (row), __n2 = (m_top); if (__n1 >= __n2 ) ; else g_assertion_message_cmpint ("BTE", "../src/ringview.cc" , 166, ((const char*) (__PRETTY_FUNCTION__)), "row" " " ">=" " " "m_top", (guint64)__n1, ">=", (guint64)__n2, 'i'); } while (0); | |||
| 167 | g_assert_cmpint(row, <, m_top + m_rows_len)do { gint64 __n1 = (row), __n2 = (m_top + m_rows_len); if (__n1 < __n2) ; else g_assertion_message_cmpint ("BTE", "../src/ringview.cc" , 167, ((const char*) (__PRETTY_FUNCTION__)), "row" " " "<" " " "m_top + m_rows_len", (guint64)__n1, "<", (guint64)__n2 , 'i'); } while (0); | |||
| 168 | ||||
| 169 | return m_rows[row - m_top]; | |||
| 170 | } | |||
| 171 | ||||
| 172 | void | |||
| 173 | RingView::set_enable_bidi(bool enable_bidi) | |||
| 174 | { | |||
| 175 | if (G_LIKELY (enable_bidi == m_enable_bidi)(__builtin_expect (__extension__ ({ int _g_boolean_var_28 = 0 ; if (enable_bidi == m_enable_bidi) _g_boolean_var_28 = 1; _g_boolean_var_28 ; }), 1))) | |||
| 176 | return; | |||
| 177 | ||||
| 178 | m_enable_bidi = enable_bidi; | |||
| 179 | m_invalid = true; | |||
| 180 | } | |||
| 181 | ||||
| 182 | void | |||
| 183 | RingView::set_enable_shaping(bool enable_shaping) | |||
| 184 | { | |||
| 185 | if (G_LIKELY (enable_shaping == m_enable_shaping)(__builtin_expect (__extension__ ({ int _g_boolean_var_29 = 0 ; if (enable_shaping == m_enable_shaping) _g_boolean_var_29 = 1; _g_boolean_var_29; }), 1))) | |||
| 186 | return; | |||
| 187 | ||||
| 188 | m_enable_shaping = enable_shaping; | |||
| 189 | m_invalid = true; | |||
| 190 | } | |||
| 191 | ||||
| 192 | void | |||
| 193 | RingView::update() | |||
| 194 | { | |||
| 195 | if (!m_invalid) | |||
| ||||
| 196 | return; | |||
| 197 | if (m_paused) | |||
| 198 | resume(); | |||
| 199 | ||||
| 200 | /* Find the beginning of the topmost paragraph. | |||
| 201 | * | |||
| 202 | * Extract at most BTE_RINGVIEW_PARAGRAPH_LENGTH_MAX context rows. | |||
| 203 | * If this safety limit is reached then together with the first | |||
| 204 | * non-context row this paragraph fragment is already longer | |||
| 205 | * than BTE_RINGVIEW_PARAGRAPH_LENGTH_MAX lines, and thus the | |||
| 206 | * BiDi code will skip it. */ | |||
| 207 | bte::grid::row_t row = m_start; | |||
| 208 | const BteRowData *row_data; | |||
| 209 | ||||
| 210 | _bte_debug_print (BTE_DEBUG_RINGVIEW, "Ringview: updating for [%ld..%ld] (%ld rows).\n",do { } while(0) | |||
| 211 | m_start, m_start + m_len - 1, m_len)do { } while(0); | |||
| 212 | ||||
| 213 | int i = BTE_RINGVIEW_PARAGRAPH_LENGTH_MAX500; | |||
| 214 | while (i--) { | |||
| 215 | if (!m_ring->is_soft_wrapped(row - 1)) | |||
| 216 | break; | |||
| 217 | row--; | |||
| 218 | } | |||
| 219 | ||||
| 220 | /* Extract the data beginning at the found row. | |||
| 221 | * | |||
| 222 | * Extract at most BTE_RINGVIEW_PARAGRAPH_LENGTH_MAX rows | |||
| 223 | * beyond the end of the specified area. Again, if this safety | |||
| 224 | * limit is reached then together with the last non-context row | |||
| 225 | * this paragraph fragment is already longer than | |||
| 226 | * BTE_RINGVIEW_PARAGRAPH_LENGTH_MAX lines, and thus the | |||
| 227 | * BiDi code will skip it. */ | |||
| 228 | m_top = row; | |||
| 229 | m_rows_len = 0; | |||
| 230 | while (row < m_start + m_len + BTE_RINGVIEW_PARAGRAPH_LENGTH_MAX500) { | |||
| 231 | if (G_UNLIKELY (m_rows_len == m_rows_alloc_len)(__builtin_expect (__extension__ ({ int _g_boolean_var_30 = 0 ; if (m_rows_len == m_rows_alloc_len) _g_boolean_var_30 = 1; _g_boolean_var_30 ; }), 0))) { | |||
| 232 | /* Don't realloc too aggressively. */ | |||
| 233 | m_rows_alloc_len = std::max(m_rows_alloc_len + 1, m_rows_alloc_len * 5 / 4 /* whatever */); | |||
| 234 | _bte_debug_print (BTE_DEBUG_RINGVIEW, "Ringview: reallocate to %d rows\n",do { } while(0) | |||
| 235 | m_rows_alloc_len)do { } while(0); | |||
| 236 | m_rows = (BteRowData **) g_realloc (m_rows, sizeof (BteRowData *) * m_rows_alloc_len); | |||
| 237 | for (int j = m_rows_len; j < m_rows_alloc_len; j++) { | |||
| 238 | m_rows[j] = (BteRowData *) g_malloc (sizeof (BteRowData)); | |||
| 239 | _bte_row_data_init (m_rows[j]); | |||
| 240 | } | |||
| 241 | } | |||
| 242 | ||||
| 243 | row_data = _bte_ring_contains(m_ring, row) ? m_ring->index(row) : nullptr; | |||
| 244 | if (G_LIKELY (row_data != nullptr)(__builtin_expect (__extension__ ({ int _g_boolean_var_31 = 0 ; if (row_data != nullptr) _g_boolean_var_31 = 1; _g_boolean_var_31 ; }), 1))) { | |||
| 245 | _bte_row_data_copy (row_data, m_rows[m_rows_len]); | |||
| 246 | /* Make sure that the extracted data is not wider than the screen, | |||
| 247 | * something that can happen if the window was narrowed with rewrapping disabled. | |||
| 248 | * Also make sure that we won't end up with unfinished characters. | |||
| 249 | * FIXME remove this once bug 135 is addressed. */ | |||
| 250 | if (G_UNLIKELY (_bte_row_data_length(m_rows[m_rows_len]) > m_width)(__builtin_expect (__extension__ ({ int _g_boolean_var_32 = 0 ; if (((m_rows[m_rows_len])->len + 0) > m_width) _g_boolean_var_32 = 1; _g_boolean_var_32; }), 0))) { | |||
| 251 | int j = m_width; | |||
| 252 | while (j > 0) { | |||
| 253 | BteCell const* cell = _bte_row_data_get(m_rows[m_rows_len], j); | |||
| 254 | if (!cell->attr.fragment()) | |||
| 255 | break; | |||
| 256 | j--; | |||
| 257 | } | |||
| 258 | _bte_row_data_shrink(m_rows[m_rows_len], j); | |||
| 259 | } | |||
| 260 | } else { | |||
| 261 | _bte_row_data_clear (m_rows[m_rows_len]); | |||
| ||||
| 262 | } | |||
| 263 | m_rows_len++; | |||
| 264 | row++; | |||
| 265 | ||||
| 266 | /* Once the bottom of the specified area is reached, stop at a hard newline. */ | |||
| 267 | if (row >= m_start + m_len && (!row_data || !row_data->attr.soft_wrapped)) | |||
| 268 | break; | |||
| 269 | } | |||
| 270 | ||||
| 271 | _bte_debug_print (BTE_DEBUG_RINGVIEW, "Ringview: extracted %ld+%ld context lines: [%ld..%ld] (%d rows).\n",do { } while(0) | |||
| 272 | m_start - m_top, (m_top + m_rows_len) - (m_start + m_len),do { } while(0) | |||
| 273 | m_top, m_top + m_rows_len - 1, m_rows_len)do { } while(0); | |||
| 274 | ||||
| 275 | /* Loop through paragraphs of the extracted text, and do whatever we need to do on each paragraph. */ | |||
| 276 | auto top = m_top; | |||
| 277 | row = top; | |||
| 278 | while (row < m_top + m_rows_len) { | |||
| 279 | row_data = m_rows[row - m_top]; | |||
| 280 | if (!row_data->attr.soft_wrapped || row == m_top + m_rows_len - 1) { | |||
| 281 | /* Found a paragraph from @top to @row, inclusive. */ | |||
| 282 | ||||
| 283 | /* Run the BiDi algorithm. */ | |||
| 284 | m_bidirunner->paragraph(top, row + 1, | |||
| 285 | m_enable_bidi, m_enable_shaping); | |||
| 286 | ||||
| 287 | /* Doing syntax highlighting etc. come here in the future. */ | |||
| 288 | ||||
| 289 | top = row + 1; | |||
| 290 | } | |||
| 291 | row++; | |||
| 292 | } | |||
| 293 | ||||
| 294 | m_invalid = false; | |||
| 295 | } | |||
| 296 | ||||
| 297 | BidiRow const* RingView::get_bidirow(bte::grid::row_t row) const | |||
| 298 | { | |||
| 299 | g_assert_cmpint (row, >=, m_start)do { gint64 __n1 = (row), __n2 = (m_start); if (__n1 >= __n2 ) ; else g_assertion_message_cmpint ("BTE", "../src/ringview.cc" , 299, ((const char*) (__PRETTY_FUNCTION__)), "row" " " ">=" " " "m_start", (guint64)__n1, ">=", (guint64)__n2, 'i'); } while (0); | |||
| 300 | g_assert_cmpint (row, <, m_start + m_len)do { gint64 __n1 = (row), __n2 = (m_start + m_len); if (__n1 < __n2) ; else g_assertion_message_cmpint ("BTE", "../src/ringview.cc" , 300, ((const char*) (__PRETTY_FUNCTION__)), "row" " " "<" " " "m_start + m_len", (guint64)__n1, "<", (guint64)__n2, 'i'); } while (0); | |||
| 301 | g_assert_false (m_invalid)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_33 = 0; if (!(m_invalid)) _g_boolean_var_33 = 1; _g_boolean_var_33 ; }), 1)) ; else g_assertion_message ("BTE", "../src/ringview.cc" , 301, ((const char*) (__PRETTY_FUNCTION__)), "'" "m_invalid" "' should be FALSE"); } while (0); | |||
| 302 | g_assert_false (m_paused)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_34 = 0; if (!(m_paused)) _g_boolean_var_34 = 1; _g_boolean_var_34 ; }), 1)) ; else g_assertion_message ("BTE", "../src/ringview.cc" , 302, ((const char*) (__PRETTY_FUNCTION__)), "'" "m_paused" "' should be FALSE" ); } while (0); | |||
| 303 | ||||
| 304 | return m_bidirows[row - m_start]; | |||
| 305 | } | |||
| 306 | ||||
| 307 | /* For internal use by BidiRunner. Get where the BiDi mapping for the given row | |||
| 308 | * needs to be stored, of nullptr if it's a context row. */ | |||
| 309 | BidiRow* RingView::get_bidirow_writable(bte::grid::row_t row) const | |||
| 310 | { | |||
| 311 | if (row < m_start || row >= m_start + m_len) | |||
| 312 | return nullptr; | |||
| 313 | ||||
| 314 | return m_bidirows[row - m_start]; | |||
| 315 | } |