File: | /rootdir/_build/../src/ringview.cc |
Warning: | line 279, column 26 Assigned value is garbage or undefined |
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_cmpnum ("BTE", "../src/ringview.cc" , 78, ((const char*) (__PRETTY_FUNCTION__)), "m_len" " " ">=" " " "1", (long double) __n1, ">=", (long double) __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_; if ( ring == m_ring) _g_boolean_var_ = 1; else _g_boolean_var_ = 0 ; _g_boolean_var_; }), 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_; if ( width == m_width) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_; if ( !m_paused && len > m_bidirows_alloc_len) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_cmpnum ("BTE", "../src/ringview.cc" , 166, ((const char*) (__PRETTY_FUNCTION__)), "row" " " ">=" " " "m_top", (long double) __n1, ">=", (long double) __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_cmpnum ("BTE", "../src/ringview.cc" , 167, ((const char*) (__PRETTY_FUNCTION__)), "row" " " "<" " " "m_top + m_rows_len", (long double) __n1, "<", (long double ) __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_; if ( enable_bidi == m_enable_bidi) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_; if ( enable_shaping == m_enable_shaping) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_; if ( m_rows_len == m_rows_alloc_len) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_; if ( row_data != nullptr) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_; if ( ((m_rows[m_rows_len])->len + 0) > m_width) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_cmpnum ("BTE", "../src/ringview.cc" , 299, ((const char*) (__PRETTY_FUNCTION__)), "row" " " ">=" " " "m_start", (long double) __n1, ">=", (long double) __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_cmpnum ("BTE", "../src/ringview.cc" , 300, ((const char*) (__PRETTY_FUNCTION__)), "row" " " "<" " " "m_start + m_len", (long double) __n1, "<", (long double ) __n2, 'i'); } while (0); | |||
301 | g_assert_false (m_invalid)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_ ; if (!(m_invalid)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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_ ; if (!(m_paused)) _g_boolean_var_ = 1; else _g_boolean_var_ = 0; _g_boolean_var_; }), 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 | } |