1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "vt_line.h"
4 
5 #include <string.h> /* memset */
6 #include <pobl/bl_debug.h>
7 #include <pobl/bl_util.h> /* BL_MIN */
8 #include <pobl/bl_mem.h>  /* alloca */
9 
10 #include "vt_ctl_loader.h"
11 #include "vt_ot_layout.h"
12 
13 #if 0
14 #define __DEBUG
15 #endif
16 
17 #ifdef __DEBUG
18 #define END_CHAR_INDEX(line)                                                              \
19   ((line)->num_filled_chars == 0 &&                                                    \
20            bl_debug_printf("END_CHAR_INDEX()" BL_DEBUG_TAG " num_filled_chars is 0.\n") \
21        ? 0                                                                                \
22        : (line)->num_filled_chars - 1)
23 #else
24 #define END_CHAR_INDEX(line) \
25   ((line)->num_filled_chars == 0 ? 0 : (line)->num_filled_chars - 1)
26 #endif
27 
28 #define IS_EMPTY(line) ((line)->num_filled_chars == 0)
29 
30 #define vt_line_is_using_bidi(line) ((line)->ctl_info_type == VINFO_BIDI)
31 #define vt_line_is_using_iscii(line) ((line)->ctl_info_type == VINFO_ISCII)
32 #define vt_line_is_using_ot_layout(line) ((line)->ctl_info_type == VINFO_OT_LAYOUT)
33 
34 /* You can specify this macro by configure script option. */
35 #if 0
36 #define OPTIMIZE_REDRAWING
37 #endif
38 
39 /* --- static functions --- */
40 
41 #ifndef NO_DYNAMIC_LOAD_CTL
42 
vt_line_set_use_bidi(vt_line_t * line,int flag)43 static int vt_line_set_use_bidi(vt_line_t *line, int flag) {
44   int (*func)(vt_line_t *, int);
45 
46   if (!(func = vt_load_ctl_bidi_func(VT_LINE_SET_USE_BIDI))) {
47     return 0;
48   }
49 
50   return (*func)(line, flag);
51 }
52 
vt_line_bidi_convert_visual_char_index_to_logical(vt_line_t * line,int char_index)53 static int vt_line_bidi_convert_visual_char_index_to_logical(vt_line_t *line, int char_index) {
54   int (*func)(vt_line_t *, int);
55 
56   if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_CONVERT_VISUAL_CHAR_INDEX_TO_LOGICAL))) {
57     return char_index;
58   }
59 
60   return (*func)(line, char_index);
61 }
62 
vt_line_bidi_copy_logical_str(vt_line_t * line,vt_char_t * dst,int beg,u_int len)63 static int vt_line_bidi_copy_logical_str(vt_line_t *line, vt_char_t *dst,
64                                          int beg, /* visual position */
65                                          u_int len) {
66   int (*func)(vt_line_t *, vt_char_t *, int, u_int);
67 
68   if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_COPY_LOGICAL_STR))) {
69     return 0;
70   }
71 
72   return (*func)(line, dst, beg, len);
73 }
74 
vt_line_bidi_is_rtl(vt_line_t * line)75 static int vt_line_bidi_is_rtl(vt_line_t *line) {
76   int (*func)(vt_line_t *);
77 
78   if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_IS_RTL))) {
79     return 0;
80   }
81 
82   return (*func)(line);
83 }
84 
vt_bidi_copy(vt_bidi_state_t dst,vt_bidi_state_t src,int optimize_ctl_info)85 static int vt_bidi_copy(vt_bidi_state_t dst, vt_bidi_state_t src, int optimize_ctl_info) {
86   int (*func)(vt_bidi_state_t, vt_bidi_state_t, int);
87 
88   if (!(func = vt_load_ctl_bidi_func(VT_BIDI_COPY))) {
89     return 0;
90   }
91 
92   return (*func)(dst, src, optimize_ctl_info);
93 }
94 
vt_bidi_reset(vt_bidi_state_t state)95 static int vt_bidi_reset(vt_bidi_state_t state) {
96   int (*func)(vt_bidi_state_t);
97 
98   if (!(func = vt_load_ctl_bidi_func(VT_BIDI_RESET))) {
99     return 0;
100   }
101 
102   return (*func)(state);
103 }
104 
vt_line_bidi_render(vt_line_t * line,vt_bidi_mode_t bidi_mode,const char * separators)105 static int vt_line_bidi_render(vt_line_t *line, vt_bidi_mode_t bidi_mode, const char *separators) {
106   int (*func)(vt_line_t *, vt_bidi_mode_t, const char *);
107 
108   if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_RENDER))) {
109     return 0;
110   }
111 
112   return (*func)(line, bidi_mode, separators);
113 }
114 
vt_line_bidi_visual(vt_line_t * line)115 static int vt_line_bidi_visual(vt_line_t *line) {
116   int (*func)(vt_line_t *);
117 
118   if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_VISUAL))) {
119     return 0;
120   }
121 
122   return (*func)(line);
123 }
124 
vt_line_bidi_logical(vt_line_t * line)125 static int vt_line_bidi_logical(vt_line_t *line) {
126   int (*func)(vt_line_t *);
127 
128   if (!(func = vt_load_ctl_bidi_func(VT_LINE_BIDI_LOGICAL))) {
129     return 0;
130   }
131 
132   return (*func)(line);
133 }
134 
vt_line_set_use_iscii(vt_line_t * line,int flag)135 static int vt_line_set_use_iscii(vt_line_t *line, int flag) {
136   int (*func)(vt_line_t *, int);
137 
138   if (!(func = vt_load_ctl_iscii_func(VT_LINE_SET_USE_ISCII))) {
139     return 0;
140   }
141 
142   return (*func)(line, flag);
143 }
144 
vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t * line,int char_index)145 static int vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t *line, int char_index) {
146   int (*func)(vt_line_t *, int);
147 
148   if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_CONVERT_VISUAL_CHAR_INDEX_TO_LOGICAL))) {
149     return char_index;
150   }
151 
152   return (*func)(line, char_index);
153 }
154 
vt_iscii_copy(vt_iscii_state_t dst,vt_iscii_state_t src,int optimize_ctl_info)155 static int vt_iscii_copy(vt_iscii_state_t dst, vt_iscii_state_t src, int optimize_ctl_info) {
156   int (*func)(vt_iscii_state_t, vt_iscii_state_t, int);
157 
158   if (!(func = vt_load_ctl_iscii_func(VT_ISCII_COPY))) {
159     return 0;
160   }
161 
162   return (*func)(dst, src, optimize_ctl_info);
163 }
164 
vt_iscii_reset(vt_iscii_state_t state)165 static int vt_iscii_reset(vt_iscii_state_t state) {
166   int (*func)(vt_iscii_state_t);
167 
168   if (!(func = vt_load_ctl_iscii_func(VT_ISCII_RESET))) {
169     return 0;
170   }
171 
172   return (*func)(state);
173 }
174 
vt_line_iscii_render(vt_line_t * line)175 static int vt_line_iscii_render(vt_line_t *line) {
176   int (*func)(vt_line_t *);
177 
178   if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_RENDER))) {
179     return 0;
180   }
181 
182   return (*func)(line);
183 }
184 
vt_line_iscii_visual(vt_line_t * line)185 static int vt_line_iscii_visual(vt_line_t *line) {
186   int (*func)(vt_line_t *);
187 
188   if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_VISUAL))) {
189     return 0;
190   }
191 
192   return (*func)(line);
193 }
194 
vt_line_iscii_logical(vt_line_t * line)195 static int vt_line_iscii_logical(vt_line_t *line) {
196   int (*func)(vt_line_t *);
197 
198   if (!(func = vt_load_ctl_iscii_func(VT_LINE_ISCII_LOGICAL))) {
199     return 0;
200   }
201 
202   return (*func)(line);
203 }
204 
205 #else /* NO_DYNAMIC_LOAD_CTL */
206 
207 #ifndef USE_FRIBIDI
208 #define vt_line_set_use_bidi(line, flag) (0)
209 #define vt_line_bidi_convert_visual_char_index_to_logical(line, char_index) (char_index)
210 #define vt_line_bidi_copy_logical_str(line, dst, beg, len) (0)
211 #define vt_line_bidi_is_rtl(line) (0)
212 #define vt_bidi_copy(dst, src, optimize) (0)
213 #define vt_bidi_reset(state) (0)
214 #define vt_line_bidi_render(line, bidi_mode, separators) (0)
215 #define vt_line_bidi_visual(line) (0)
216 #define vt_line_bidi_logical(line) (0)
217 #else
218 /* Link functions in libctl/vt_*bidi.c */
219 int vt_line_set_use_bidi(vt_line_t *line, int flag);
220 int vt_line_bidi_convert_visual_char_index_to_logical(vt_line_t *line, int char_index);
221 int vt_line_bidi_copy_logical_str(vt_line_t *line, vt_char_t *dst, int beg, u_int len);
222 int vt_line_bidi_is_rtl(vt_line_t *line);
223 int vt_bidi_copy(vt_bidi_state_t dst, vt_bidi_state_t src, int optimize);
224 int vt_bidi_reset(vt_bidi_state_t state);
225 int vt_line_bidi_convert_logical_char_index_to_visual(vt_line_t *line, int char_index,
226                                                       u_int32_t *meet_pos_info);
227 int vt_line_bidi_render(vt_line_t *line, vt_bidi_mode_t bidi_mode, const char *separators);
228 int vt_line_bidi_visual(vt_line_t *line);
229 int vt_line_bidi_logical(vt_line_t *line);
230 #endif /* USE_FRIBIDI */
231 
232 #ifndef USE_IND
233 #define vt_line_set_use_iscii(line, flag) (0)
234 #define vt_line_iscii_convert_visual_char_index_to_logical(line, char_index) (char_index)
235 #define vt_iscii_copy(dst, src, optimize) (0)
236 #define vt_iscii_reset(state) (0)
237 #define vt_line_iscii_render(line) (0)
238 #define vt_line_iscii_visual(line) (0)
239 #define vt_line_iscii_logical(line) (0)
240 #else
241 /* Link functions in libctl/vt_*iscii.c */
242 int vt_line_set_use_iscii(vt_line_t *line, int flag);
243 int vt_line_iscii_convert_visual_char_index_to_logical(vt_line_t *line, int visual_char_index);
244 int vt_iscii_copy(vt_iscii_state_t dst, vt_iscii_state_t src, int optimize);
245 int vt_iscii_reset(vt_iscii_state_t state);
246 int vt_line_iscii_convert_logical_char_index_to_visual(vt_line_t *line, int logical_char_index);
247 int vt_line_iscii_render(vt_line_t *line);
248 int vt_line_iscii_visual(vt_line_t *line);
249 int vt_line_iscii_logical(vt_line_t *line);
250 #endif /* USE_IND */
251 
252 #endif /* NO_DYNAMIC_LOAD_CTL */
253 
254 #ifdef USE_OT_LAYOUT
255 
vt_line_set_use_ot_layout(vt_line_t * line,int flag)256 static int vt_line_set_use_ot_layout(vt_line_t *line, int flag) {
257   if (flag) {
258     if (vt_line_is_using_ot_layout(line)) {
259       return 1;
260     } else if (line->ctl_info_type != 0) {
261       return 0;
262     }
263 
264     if ((line->ctl_info.ot_layout = vt_ot_layout_new()) == NULL) {
265       return 0;
266     }
267 
268     line->ctl_info_type = VINFO_OT_LAYOUT;
269   } else {
270     if (vt_line_is_using_ot_layout(line)) {
271       vt_ot_layout_destroy(line->ctl_info.ot_layout);
272       line->ctl_info_type = 0;
273     }
274   }
275 
276   return 1;
277 }
278 
279 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_visual(vt_line_t * line)280 static int vt_line_ot_layout_visual(vt_line_t *line) {
281   vt_char_t *src;
282   u_int src_len;
283   vt_char_t *dst;
284   u_int dst_len;
285   int dst_pos;
286   int src_pos;
287 
288   if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
289 #ifdef __DEBUG
290     bl_warn_printf(BL_DEBUG_TAG " Not need to visualize.\n");
291 #endif
292 
293     return 1;
294   }
295 
296   src_len = line->num_filled_chars;
297   if ((src = vt_str_alloca(src_len)) == NULL) {
298     return 0;
299   }
300   vt_str_init(src, src_len);
301 
302   vt_str_copy(src, line->chars, src_len);
303 
304   dst_len = line->ctl_info.ot_layout->size;
305   if (line->num_chars < dst_len) {
306     vt_char_t *chars;
307 
308     if ((chars = vt_str_new(dst_len))) {
309       /* XXX => shrunk at vt_screen.c and vt_logical_visual_ctl.c */
310       vt_str_destroy(line->chars, line->num_chars);
311       line->chars = chars;
312       line->num_chars = dst_len;
313     } else {
314       line->ctl_info.ot_layout->size = dst_len = line->num_chars;
315     }
316   }
317 
318   dst = line->chars;
319 
320   src_pos = 0;
321   for (dst_pos = 0; dst_pos < dst_len; dst_pos++) {
322     if (line->ctl_info.ot_layout->num_chars_array[dst_pos] == 0) {
323       /*
324        * (logical)ACD -> (visual)A0CD -> (shaped)abcd
325        *          B              B
326        * (B is combining char)
327        */
328       vt_char_copy(dst + dst_pos, vt_get_base_char(src + src_pos - 1));
329       vt_char_set_code(dst + dst_pos, 0);
330     } else {
331       u_int count;
332 
333       vt_char_copy(dst + dst_pos, src + (src_pos++));
334 
335       for (count = 1; count < line->ctl_info.ot_layout->num_chars_array[dst_pos]; count++) {
336         vt_char_t *comb;
337         u_int num;
338 
339 #ifdef DEBUG
340         if (vt_char_is_comb(vt_get_base_char(src + src_pos))) {
341           bl_debug_printf(BL_DEBUG_TAG " illegal ot_layout\n");
342         }
343 #endif
344 
345         vt_char_combine_simple(dst + dst_pos, vt_get_base_char(src + src_pos));
346 
347         comb = vt_get_combining_chars(src + (src_pos++), &num);
348         for (; num > 0; num--) {
349 #ifdef DEBUG
350           if (!vt_char_is_comb(comb)) {
351             bl_debug_printf(BL_DEBUG_TAG " illegal ot_layout\n");
352           }
353 #endif
354           vt_char_combine_simple(dst + dst_pos, comb++);
355         }
356       }
357     }
358   }
359 
360 #ifdef DEBUG
361   if (src_pos != src_len) {
362     bl_debug_printf(BL_DEBUG_TAG "vt_line_ot_layout_visual() failed: %d -> %d\n", src_len, src_pos);
363   }
364 #endif
365 
366   vt_str_final(src, src_len);
367 
368   line->num_filled_chars = dst_pos;
369 
370   return 1;
371 }
372 
373 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_logical(vt_line_t * line)374 static int vt_line_ot_layout_logical(vt_line_t *line) {
375   vt_char_t *src;
376   u_int src_len;
377   vt_char_t *dst;
378   int src_pos;
379 
380   if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
381 #ifdef __DEBUG
382     bl_warn_printf(BL_DEBUG_TAG " Not need to logicalize.\n");
383 #endif
384 
385     return 1;
386   }
387 
388   src_len = line->num_filled_chars;
389   if ((src = vt_str_alloca(src_len)) == NULL) {
390     return 0;
391   }
392   vt_str_init(src, src_len);
393 
394   vt_str_copy(src, line->chars, src_len);
395   dst = line->chars;
396 
397   for (src_pos = 0; src_pos < line->ctl_info.ot_layout->size; src_pos++) {
398     vt_char_t *comb;
399     u_int num;
400 
401     if (line->ctl_info.ot_layout->num_chars_array[src_pos] == 0) {
402       continue;
403     }
404 
405     if (vt_char_cs(src + src_pos) == ISO10646_UCS4_1_V) {
406       vt_char_set_cs(src + src_pos, ISO10646_UCS4_1);
407     }
408 
409     if (line->ctl_info.ot_layout->num_chars_array[src_pos] == 1) {
410       vt_char_copy(dst, src + src_pos);
411     } else {
412       vt_char_copy(dst, vt_get_base_char(src + src_pos));
413 
414       comb = vt_get_combining_chars(src + src_pos, &num);
415       for (; num > 0; num--, comb++) {
416         if (vt_char_cs(comb) == ISO10646_UCS4_1_V) {
417           vt_char_set_cs(comb, ISO10646_UCS4_1);
418         }
419 
420         if (vt_char_is_comb(comb)) {
421           vt_char_combine_simple(dst, comb);
422         } else {
423           vt_char_copy(++dst, comb);
424         }
425       }
426     }
427 
428     dst++;
429   }
430 
431   vt_str_final(src, src_len);
432 
433   line->num_filled_chars = dst - line->chars;
434 
435   return 1;
436 }
437 
438 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_convert_logical_char_index_to_visual(vt_line_t * line,int logical_char_index)439 static int vt_line_ot_layout_convert_logical_char_index_to_visual(vt_line_t *line,
440                                                                   int logical_char_index) {
441   int visual_char_index;
442 
443   if (vt_line_is_empty(line)) {
444     return 0;
445   }
446 
447   if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
448 #ifdef __DEBUG
449     bl_debug_printf(BL_DEBUG_TAG " logical char_index is same as visual one.\n");
450 #endif
451     return logical_char_index;
452   }
453 
454   for (visual_char_index = 0; visual_char_index < line->ctl_info.ot_layout->size;
455        visual_char_index++) {
456     if ((logical_char_index -= line->ctl_info.ot_layout->num_chars_array[visual_char_index]) < 0) {
457       break;
458     }
459   }
460 
461   return visual_char_index;
462 }
463 
464 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_convert_visual_char_index_to_logical(vt_line_t * line,int visual_char_index)465 static int vt_line_ot_layout_convert_visual_char_index_to_logical(vt_line_t *line,
466                                                                   int visual_char_index) {
467   int logical_char_index;
468   int count;
469 
470   if (vt_line_is_empty(line)) {
471     return 0;
472   }
473 
474   if (line->ctl_info.ot_layout->size == 0 || !line->ctl_info.ot_layout->substituted) {
475 #ifdef __DEBUG
476     bl_debug_printf(BL_DEBUG_TAG " visual char_index is same as logical one.\n");
477 #endif
478     return visual_char_index;
479   }
480 
481   if (line->ctl_info.ot_layout->size - 1 < visual_char_index) {
482     visual_char_index = line->ctl_info.ot_layout->size - 1;
483   }
484 
485   logical_char_index = 0;
486   for (count = 0; count < visual_char_index; count++) {
487     logical_char_index += line->ctl_info.ot_layout->num_chars_array[count];
488   }
489 
490   return logical_char_index;
491 }
492 
493 /* The caller should check vt_line_is_using_ot_layout() in advance. */
vt_line_ot_layout_render(vt_line_t * line,void * term)494 static int vt_line_ot_layout_render(vt_line_t *line, /* is always modified */
495                                     void *term) {
496   int ret;
497   int visual_mod_beg;
498   int visual_mod_end;
499 
500   /*
501    * Lower case: ASCII
502    * Upper case: GLYPH INDEX
503    *    (Logical) AAA == (Visual) BBBBB
504    * => (Logical) aaa == (Visual) aaa
505    * In this case vt_line_is_cleared_to_end() returns 0, so "BB" remains on
506    * the screen unless following vt_line_set_modified().
507    */
508   visual_mod_beg = vt_line_get_beg_of_modified(line);
509   if (line->ctl_info.ot_layout->substituted) {
510     visual_mod_beg = vt_line_ot_layout_convert_logical_char_index_to_visual(line, visual_mod_beg);
511   }
512 
513   if (vt_line_is_real_modified(line)) {
514     int char_index;
515     int complex_shape = line->ctl_info.ot_layout->complex_shape;
516     int has_var_width_char = line->ctl_info.ot_layout->has_var_width_char;
517     int count;
518 
519     line->ctl_info.ot_layout->term = term;
520 
521     if ((ret = vt_ot_layout(line->ctl_info.ot_layout, line->chars, line->num_filled_chars)) <= 0) {
522       if (complex_shape || has_var_width_char) {
523         vt_line_set_modified_all(line);
524       }
525 
526       return ret;
527     }
528 
529     complex_shape |= line->ctl_info.ot_layout->complex_shape;
530     has_var_width_char |= line->ctl_info.ot_layout->has_var_width_char;
531 
532     if (line->ctl_info.ot_layout->substituted) {
533       int beg;
534 
535       if ((beg = vt_line_ot_layout_convert_logical_char_index_to_visual(
536                    line, vt_line_get_beg_of_modified(line))) < visual_mod_beg) {
537         visual_mod_beg = beg;
538       }
539     }
540 
541     if (has_var_width_char) {
542       visual_mod_end = line->num_chars;
543     } else {
544       visual_mod_end = vt_line_ot_layout_convert_logical_char_index_to_visual(line,
545                          vt_line_get_end_of_modified(line));
546     }
547 
548     if (complex_shape) {
549       /*
550        * XXX
551        *
552        * Input  Logical    Visual
553        * !    => !      => !
554        *         ^         ^
555        * =    => !=     => =/=
556        *          ^        ^^^
557        * ('=' after '!' should be redrawn in logical, but the first '!' should
558        *  be also redrawn in visual.)
559        */
560       for (count = 0; visual_mod_beg > 0 && count < 4; count++, visual_mod_beg--) {
561         if (vt_char_code(line->chars + visual_mod_beg - 1) == 0x20 /* SP */) {
562           break;
563         }
564       }
565 
566       /* If trailing characters in this line are all spaces, visual_mod_end is not modified. */
567       for (char_index = visual_mod_end + 1; char_index < line->num_filled_chars; char_index++) {
568         if (vt_char_code(line->chars + char_index) != 0x20 /* SP */) {
569           visual_mod_end = line->num_chars;
570           break;
571         }
572       }
573     }
574   } else {
575     visual_mod_end = vt_line_ot_layout_convert_logical_char_index_to_visual(line,
576                        vt_line_get_end_of_modified(line));
577   }
578 
579   vt_line_set_modified(line, visual_mod_beg, visual_mod_end);
580 
581   return 1;
582 }
583 
584 #endif /* USE_OT_LAYOUT */
585 
set_real_modified(vt_line_t * line,int beg_char_index,int end_char_index)586 static void set_real_modified(vt_line_t *line, int beg_char_index, int end_char_index) {
587   vt_line_set_modified(line, beg_char_index, end_char_index);
588   line->is_modified = 2;
589 }
590 
copy_line(vt_line_t * dst,vt_line_t * src,int optimize_ctl_info)591 static void copy_line(vt_line_t *dst, vt_line_t *src, int optimize_ctl_info) {
592   u_int copy_len;
593 
594 #ifdef DEBUG
595   if (dst == src) {
596     bl_error_printf("copy_line() forbids src == dst\n");
597     abort();
598   }
599 #endif
600 
601   copy_len = BL_MIN(src->num_filled_chars, dst->num_chars);
602 
603   vt_str_copy(dst->chars, src->chars, copy_len);
604   dst->num_filled_chars = copy_len;
605 
606   dst->change_beg_col = BL_MIN(src->change_beg_col, dst->num_chars);
607   dst->change_end_col = BL_MIN(src->change_end_col, dst->num_chars);
608 
609   dst->is_modified = src->is_modified;
610   dst->is_continued_to_next = src->is_continued_to_next;
611   dst->size_attr = src->size_attr;
612   dst->mark = src->mark;
613 
614 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_FRIBIDI)
615   if (vt_line_is_using_bidi(src)) {
616     if (vt_line_is_using_bidi(dst) || vt_line_set_use_bidi(dst, 1)) {
617       /*
618        * Don't use vt_line_bidi_render() here,
619        * or it is impossible to call this function in visual context.
620        */
621       if (dst->num_chars < src->num_filled_chars) {
622 #ifdef DEBUG
623         bl_debug_printf(BL_DEBUG_TAG " Not copy vt_bidi.\n");
624 #endif
625         /*
626          * XXX
627          * Isn't set_real_modified(dst, 0, END_CHAR_INDEX(dst)) necessary here
628          * to force ctl_render() ?
629          */
630       } else if (vt_bidi_copy(dst->ctl_info.bidi, src->ctl_info.bidi, optimize_ctl_info) == -1) {
631         dst->ctl_info_type = 0;
632         dst->ctl_info.bidi = NULL;
633       }
634     }
635   } else if (vt_line_is_using_bidi(dst)) {
636     vt_line_set_use_bidi(dst, 0);
637   }
638 #endif
639 
640 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_IND)
641   if (vt_line_is_using_iscii(src)) {
642     if (vt_line_is_using_iscii(dst) || vt_line_set_use_iscii(dst, 1)) {
643       /*
644        * Don't use vt_line_iscii_render() here,
645        * or it is impossible to call this function in visual context.
646        */
647       if (dst->num_chars < src->num_filled_chars) {
648 #ifdef DEBUG
649         bl_debug_printf(BL_DEBUG_TAG " Not copy vt_iscii.\n");
650 #endif
651         /*
652          * XXX
653          * Isn't set_real_modified(dst, 0, END_CHAR_INDEX(dst)) necessary here
654          * to force ctl_render() ?
655          */
656       } else if (vt_iscii_copy(dst->ctl_info.iscii, src->ctl_info.iscii, optimize_ctl_info) == -1) {
657         dst->ctl_info_type = 0;
658         dst->ctl_info.iscii = NULL;
659       }
660     }
661   } else if (vt_line_is_using_iscii(dst)) {
662     vt_line_set_use_iscii(dst, 0);
663   }
664 #endif
665 
666 #ifdef USE_OT_LAYOUT
667   if (vt_line_is_using_ot_layout(src)) {
668     if (vt_line_is_using_ot_layout(dst) || vt_line_set_use_ot_layout(dst, 1)) {
669       /*
670        * Don't use vt_line_ot_layout_render() here,
671        * or it is impossible to call this function in visual context.
672        */
673       if (dst->num_chars < src->num_filled_chars) {
674 #ifdef DEBUG
675         bl_debug_printf(BL_DEBUG_TAG " Not copy vt_ot_layout.\n");
676 #endif
677         /*
678          * XXX
679          * Isn't set_real_modified(dst, 0, END_CHAR_INDEX(dst)) necessary here
680          * to force ctl_render() ?
681          */
682       } else if (vt_ot_layout_copy(dst->ctl_info.ot_layout, src->ctl_info.ot_layout,
683                                    optimize_ctl_info) == -1) {
684         dst->ctl_info_type = 0;
685         dst->ctl_info.ot_layout = NULL;
686       }
687     }
688   } else if (vt_line_is_using_ot_layout(dst)) {
689     vt_line_set_use_ot_layout(dst, 0);
690   }
691 #endif
692 }
693 
694 /* --- global functions --- */
695 
696 /*
697  * Functions which doesn't have to care about visual order.
698  */
699 
vt_line_init(vt_line_t * line,u_int num_chars)700 int vt_line_init(vt_line_t *line, u_int num_chars) {
701   memset(line, 0, sizeof(vt_line_t));
702 
703   if ((line->chars = vt_str_new(num_chars)) == NULL) {
704     return 0;
705   }
706 
707   line->num_chars = num_chars;
708 
709   return 1;
710 }
711 
712 /* For vt_log_add() */
vt_line_clone(vt_line_t * clone,vt_line_t * orig,u_int num_chars)713 int vt_line_clone(vt_line_t *clone, vt_line_t *orig, u_int num_chars) {
714   if (vt_line_init(clone, num_chars)) {
715     copy_line(clone, orig, 1 /* clone->ctl_info can be uncopied. */);
716 
717     return 1;
718   } else {
719     return 0;
720   }
721 }
722 
vt_line_final(vt_line_t * line)723 void vt_line_final(vt_line_t *line) {
724   if (vt_line_is_using_bidi(line)) {
725     vt_line_set_use_bidi(line, 0);
726   } else if (vt_line_is_using_iscii(line)) {
727     vt_line_set_use_iscii(line, 0);
728   }
729 #ifdef USE_OT_LAYOUT
730   else if (vt_line_is_using_ot_layout(line)) {
731     vt_line_set_use_ot_layout(line, 0);
732   }
733 #endif
734 
735   if (line->chars) {
736     vt_str_destroy(line->chars, line->num_chars);
737   }
738 }
739 
740 /*
741  * return: actually broken chars.
742  */
vt_line_break_boundary(vt_line_t * line,u_int size)743 u_int vt_line_break_boundary(vt_line_t *line, u_int size) {
744   int count;
745 
746   if (line->num_filled_chars + size > line->num_chars) {
747 /* over line length */
748 
749 #ifdef DEBUG
750     bl_warn_printf(BL_DEBUG_TAG " breaking from col %d by size %d failed.",
751                    line->num_filled_chars, size);
752 #endif
753 
754     size = line->num_chars - line->num_filled_chars;
755 
756 #ifdef DEBUG
757     bl_msg_printf(" ... size modified -> %d\n", size);
758 #endif
759   }
760 
761   if (size == 0) {
762     /* nothing is done */
763 
764     return 0;
765   }
766 
767   /* padding spaces */
768   for (count = line->num_filled_chars; count < line->num_filled_chars + size; count++) {
769     vt_char_copy(line->chars + count, vt_sp_ch());
770   }
771 
772 #if 0
773   set_real_modified(line, END_CHAR_INDEX(line) + 1, END_CHAR_INDEX(line) + size);
774 #else
775   if (vt_line_is_using_ctl(line) && !vt_line_is_real_modified(line)) {
776     /* ctl_render_line() should be called in ctl_render() in
777      * vt_logical_visual.c. */
778     set_real_modified(line, END_CHAR_INDEX(line) + size, END_CHAR_INDEX(line) + size);
779   }
780 #endif
781 
782   line->num_filled_chars += size;
783 
784   return size;
785 }
786 
vt_line_assure_boundary(vt_line_t * line,int char_index)787 int vt_line_assure_boundary(vt_line_t *line, int char_index) {
788   if (char_index >= line->num_filled_chars) {
789     u_int brk_size;
790 
791     brk_size = char_index - line->num_filled_chars + 1;
792 
793     if (vt_line_break_boundary(line, brk_size) < brk_size) {
794       return 0;
795     }
796   }
797 
798   return 1;
799 }
800 
vt_line_reset(vt_line_t * line)801 void vt_line_reset(vt_line_t *line) {
802   if (IS_EMPTY(line)) {
803     /* already reset */
804     return;
805   }
806 
807 #ifdef OPTIMIZE_REDRAWING
808   {
809     int count;
810 
811     count = END_CHAR_INDEX(line);
812     while (1) {
813       if (!vt_char_equal(line->chars + count, vt_sp_ch())) {
814         set_real_modified(line, 0, count);
815 
816         break;
817       } else if (--count < 0) {
818         break;
819       }
820     }
821   }
822 #else
823   set_real_modified(line, 0, END_CHAR_INDEX(line));
824 #endif
825 
826   line->num_filled_chars = 0;
827 
828   if (vt_line_is_using_bidi(line)) {
829     vt_bidi_reset(line->ctl_info.bidi);
830   } else if (vt_line_is_using_iscii(line)) {
831     vt_iscii_reset(line->ctl_info.iscii);
832   }
833 #ifdef USE_OT_LAYOUT
834   else if (vt_line_is_using_ot_layout(line)) {
835     vt_ot_layout_reset(line->ctl_info.ot_layout);
836   }
837 #endif
838 
839   line->is_continued_to_next = 0;
840   line->size_attr = 0;
841 }
842 
vt_line_clear(vt_line_t * line,int char_index)843 void vt_line_clear(vt_line_t *line, int char_index) {
844   if (char_index >= line->num_filled_chars) {
845     return;
846   }
847 
848 #ifdef OPTIMIZE_REDRAWING
849   {
850     int count;
851 
852     count = END_CHAR_INDEX(line);
853     while (1) {
854       if (!vt_char_equal(line->chars + count, vt_sp_ch())) {
855         set_real_modified(line, char_index, count);
856 
857         break;
858       } else if (--count < char_index) {
859         break;
860       }
861     }
862   }
863 #else
864   set_real_modified(line, char_index, END_CHAR_INDEX(line));
865 #endif
866 
867   vt_char_copy(line->chars + char_index, vt_sp_ch());
868   line->num_filled_chars = char_index + 1;
869   line->is_continued_to_next = 0;
870   line->size_attr = 0;
871 }
872 
vt_line_clear_with(vt_line_t * line,int char_index,vt_char_t * ch)873 int vt_line_clear_with(vt_line_t *line, int char_index, vt_char_t *ch) {
874   line->is_continued_to_next = 0;
875 
876   return vt_line_fill(
877       line, ch, char_index,
878       (line->num_chars - vt_str_cols(line->chars, char_index)) / vt_char_cols(ch));
879 }
880 
vt_line_overwrite(vt_line_t * line,int beg_char_index,vt_char_t * chars,u_int len,u_int cols)881 int vt_line_overwrite(vt_line_t *line, int beg_char_index, /* >= line->num_filled_chars is OK */
882                       vt_char_t *chars, u_int len, u_int cols) {
883   int count;
884   u_int cols_to_beg;
885   u_int cols_rest;
886   u_int padding;
887   u_int new_len;
888   u_int copy_len;
889   vt_char_t *copy_src;
890 
891   if (len == 0) {
892     return 1;
893   }
894 
895   if (beg_char_index + len > line->num_chars) {
896     if (beg_char_index >= line->num_chars) {
897 #ifdef DEBUG
898       bl_warn_printf(BL_DEBUG_TAG " beg[%d] is over num_chars[%d].\n", beg_char_index,
899                      line->num_chars);
900 #endif
901 
902       return 0;
903     }
904 
905 #ifdef DEBUG
906     bl_warn_printf(BL_DEBUG_TAG " beg_char_index[%d] + len[%d] is over num_chars[%d].\n",
907                    beg_char_index, len, line->num_chars);
908 #endif
909 
910     len = line->num_chars - beg_char_index;
911   }
912 
913   if (beg_char_index > 0) {
914     vt_line_assure_boundary(line, beg_char_index - 1);
915   }
916 
917 #ifdef OPTIMIZE_REDRAWING
918   if (len <= line->num_filled_chars - beg_char_index) {
919     if (vt_str_equal(line->chars + beg_char_index, chars, len)) {
920       return 1;
921     }
922   } else {
923     if (vt_str_equal(line->chars + beg_char_index, chars,
924                      line->num_filled_chars - beg_char_index)) {
925       chars += (line->num_filled_chars - beg_char_index);
926       len -= (line->num_filled_chars - beg_char_index);
927       beg_char_index = line->num_filled_chars;
928 
929       count = 0;
930       while (1) {
931         if (!vt_char_equal(chars + count, vt_sp_ch())) {
932           break;
933         } else if (++count >= len) {
934           vt_str_copy(line->chars + beg_char_index, chars, len);
935           line->num_filled_chars = beg_char_index + len;
936 
937           /* Not necessary vt_line_set_modified() */
938 
939           return 1;
940         }
941       }
942     }
943   }
944 #endif
945 
946   cols_to_beg = vt_str_cols(line->chars, beg_char_index);
947 
948   if (cols_to_beg + cols < line->num_chars) {
949     int char_index;
950 
951     char_index = vt_convert_col_to_char_index(line, &cols_rest, cols_to_beg + cols, 0);
952 
953     if (0 < cols_rest && cols_rest < vt_char_cols(line->chars + char_index)) {
954       padding = vt_char_cols(line->chars + char_index) - cols_rest;
955       char_index++;
956     } else {
957       padding = 0;
958     }
959 
960     if (line->num_filled_chars > char_index) {
961       copy_len = line->num_filled_chars - char_index;
962     } else {
963       copy_len = 0;
964     }
965 
966     copy_src = line->chars + char_index;
967   } else {
968     padding = 0;
969     copy_len = 0;
970     copy_src = NULL;
971   }
972 
973   new_len = beg_char_index + len + padding + copy_len;
974 
975   if (new_len > line->num_chars) {
976 #ifdef DEBUG
977     bl_warn_printf(BL_DEBUG_TAG " new line len %d(beg %d ow %d padding %d copy %d) is overflowed\n",
978                    new_len, beg_char_index, len, padding, copy_len);
979 #endif
980 
981     new_len = line->num_chars;
982 
983     if (new_len > padding + beg_char_index + len) {
984       copy_len = new_len - padding - beg_char_index - len;
985     } else {
986       copy_len = 0;
987       padding = new_len - beg_char_index - len;
988     }
989 
990 #ifdef DEBUG
991     bl_msg_printf(" ... modified -> new_len %d , copy_len %d\n", new_len, copy_len);
992 #endif
993   }
994 
995   if (copy_len > 0) {
996     /* making space */
997     vt_str_copy(line->chars + beg_char_index + len + padding, copy_src, copy_len);
998   }
999 
1000   for (count = 0; count < padding; count++) {
1001     vt_char_copy(line->chars + beg_char_index + len + count, vt_sp_ch());
1002   }
1003 
1004   vt_str_copy(line->chars + beg_char_index, chars, len);
1005 
1006   line->num_filled_chars = new_len;
1007 
1008   set_real_modified(line, beg_char_index, beg_char_index + len + padding - 1);
1009 
1010   return 1;
1011 }
1012 
1013 /*
1014  * Not used for now.
1015  */
1016 #if 0
1017 int vt_line_overwrite_all(vt_line_t *line, vt_char_t *chars, int len) {
1018   set_real_modified(line, 0, END_CHAR_INDEX(line));
1019 
1020   vt_str_copy(line->chars, chars, len);
1021   line->num_filled_chars = len;
1022 
1023   set_real_modified(line, 0, END_CHAR_INDEX(line));
1024 
1025   return 1;
1026 }
1027 #endif
1028 
vt_line_fill(vt_line_t * line,vt_char_t * ch,int beg,u_int num)1029 int vt_line_fill(vt_line_t *line, vt_char_t *ch, int beg, /* >= line->num_filled_chars is OK */
1030                  u_int num) {
1031   int count;
1032   int char_index;
1033   u_int left_cols;
1034   u_int copy_len;
1035 
1036   if (num == 0) {
1037     return 1;
1038   }
1039 
1040   if (beg >= line->num_chars) {
1041 #ifdef DEBUG
1042     bl_warn_printf(BL_DEBUG_TAG " beg[%d] is over num_chars[%d].\n", beg, line->num_chars);
1043 #endif
1044 
1045     return 0;
1046   }
1047 
1048   if (beg > 0) {
1049     vt_line_assure_boundary(line, beg - 1);
1050   }
1051 
1052 #ifdef OPTIMIZE_REDRAWING
1053   count = 0;
1054   while (1) {
1055     if (!vt_char_equal(line->chars + beg + count, ch)) {
1056       beg += count;
1057       num -= count;
1058 
1059       if (beg + num <= line->num_filled_chars) {
1060         count = 0;
1061         while (1) {
1062           if (!vt_char_equal(line->chars + beg + num - 1 - count, ch)) {
1063             num -= count;
1064 
1065             break;
1066           } else if (count++ == num) {
1067             /* Never happens */
1068 
1069             return 1;
1070           }
1071         }
1072       }
1073 
1074       break;
1075     } else if (++count >= num) {
1076       return 1;
1077     } else if (beg + count == line->num_filled_chars) {
1078       beg += count;
1079       num -= count;
1080 
1081       break;
1082     }
1083   }
1084 #endif
1085 
1086   num = BL_MIN(num, line->num_chars - beg);
1087 
1088   char_index = beg;
1089   left_cols = num * vt_char_cols(ch);
1090 
1091   while (1) {
1092     if (char_index >= line->num_filled_chars) {
1093       left_cols = 0;
1094       copy_len = 0;
1095 
1096       break;
1097     } else if (left_cols < vt_char_cols(line->chars + char_index)) {
1098       if (beg + num + left_cols > line->num_chars) {
1099         left_cols = line->num_chars - beg - num;
1100         copy_len = 0;
1101       } else {
1102         copy_len = line->num_filled_chars - char_index - left_cols;
1103 
1104         if (beg + num + left_cols + copy_len > line->num_chars) {
1105           /*
1106            * line->num_chars is equal to or larger than
1107            * beg + num + left_cols since
1108            * 'if( beg + num + left_cols > line->num_chars)'
1109            * is already passed here.
1110            */
1111           copy_len = line->num_chars - beg - num - left_cols;
1112         }
1113       }
1114 
1115       char_index += (left_cols / vt_char_cols(ch));
1116 
1117       break;
1118     } else {
1119       left_cols -= vt_char_cols(line->chars + char_index);
1120       char_index++;
1121     }
1122   }
1123 
1124   if (copy_len > 0) {
1125     /* making space */
1126     vt_str_copy(line->chars + beg + num + left_cols, line->chars + char_index, copy_len);
1127   }
1128 
1129   char_index = beg;
1130 
1131   for (count = 0; count < num; count++) {
1132     vt_char_copy(&line->chars[char_index++], ch);
1133   }
1134 
1135   /* padding */
1136   for (count = 0; count < left_cols; count++) {
1137     vt_char_copy(&line->chars[char_index++], vt_sp_ch());
1138   }
1139 
1140   line->num_filled_chars = char_index + copy_len;
1141 
1142   set_real_modified(line, beg, beg + num + left_cols);
1143 
1144   return 1;
1145 }
1146 
vt_char_at(vt_line_t * line,int at)1147 vt_char_t *vt_char_at(vt_line_t *line, int at) {
1148   if (at >= line->num_filled_chars) {
1149     return NULL;
1150   } else {
1151     return line->chars + at;
1152   }
1153 }
1154 
vt_line_set_modified(vt_line_t * line,int beg_char_index,int end_char_index)1155 int vt_line_set_modified(vt_line_t *line, int beg_char_index, int end_char_index) {
1156   int count;
1157   int beg_col;
1158   int end_col;
1159 
1160   if (beg_char_index > end_char_index) {
1161 #ifdef DEBUG
1162     bl_warn_printf(BL_DEBUG_TAG " beg_char_index %d > end_char_index %d\n", beg_char_index,
1163                    end_char_index);
1164 #endif
1165 
1166     return 0;
1167   }
1168 
1169   if (beg_char_index >= line->num_filled_chars) {
1170     beg_char_index = END_CHAR_INDEX(line);
1171   }
1172 
1173   beg_col = 0;
1174   for (count = 0; count < beg_char_index; count++) {
1175     beg_col += vt_char_cols(line->chars + count);
1176   }
1177 
1178   if (end_char_index >= line->num_filled_chars) {
1179     /*
1180      * '* 2' assures change_end_col should point over the end of line.
1181      * If triple width(or wider) characters(!) were to exist, this hack would
1182      * make
1183      * no sense...
1184      */
1185     end_col = line->num_chars * 2;
1186   } else {
1187     end_col = beg_col;
1188     for (; count <= end_char_index; count++) {
1189       /*
1190        * This will be executed at least once, because beg_char_index is never
1191        * greater than end_char_index.
1192        */
1193       end_col += vt_char_cols(line->chars + count);
1194     }
1195 
1196     /*
1197      * If vt_char_cols() returns 0, beg_col can be equals to end_col here.
1198      * If beg_col is equals to end_col, don't minus end_col.
1199      */
1200     if (beg_col < end_col) {
1201       end_col--;
1202     }
1203   }
1204 
1205   if (line->is_modified) {
1206     if (beg_col < line->change_beg_col) {
1207       line->change_beg_col = beg_col;
1208     }
1209 
1210     if (end_col > line->change_end_col) {
1211       line->change_end_col = end_col;
1212     }
1213   } else {
1214     line->change_beg_col = beg_col;
1215     line->change_end_col = end_col;
1216 
1217     line->is_modified = 1;
1218   }
1219 
1220   return 1;
1221 }
1222 
vt_line_set_modified_all(vt_line_t * line)1223 int vt_line_set_modified_all(vt_line_t *line) {
1224   line->change_beg_col = 0;
1225 
1226   /*
1227    * '* 2' assures change_end_col should point over the end of line.
1228    * If triple width(or wider) characters(!) were to exist, this hack would make
1229    * no sense...
1230    */
1231   line->change_end_col = line->num_chars * 2;
1232 
1233   /* Don't overwrite if line->is_modified == 2 (real modified) */
1234   if (!line->is_modified) {
1235     line->is_modified = 1;
1236   }
1237 
1238   return 1;
1239 }
1240 
vt_line_is_cleared_to_end(vt_line_t * line)1241 int vt_line_is_cleared_to_end(vt_line_t *line) {
1242   if (vt_line_get_num_filled_cols(line) < line->change_end_col + 1) {
1243     return 1;
1244   } else {
1245     return 0;
1246   }
1247 }
1248 
vt_line_is_modified(vt_line_t * line)1249 int vt_line_is_modified(vt_line_t *line) { return line->is_modified; }
1250 
vt_line_get_beg_of_modified(vt_line_t * line)1251 int vt_line_get_beg_of_modified(vt_line_t *line) {
1252   if (IS_EMPTY(line)) {
1253     return 0;
1254   } else {
1255     return vt_convert_col_to_char_index(line, NULL, line->change_beg_col, 0);
1256   }
1257 }
1258 
vt_line_get_end_of_modified(vt_line_t * line)1259 int vt_line_get_end_of_modified(vt_line_t *line) {
1260   if (IS_EMPTY(line)) {
1261     return 0;
1262   } else {
1263     return vt_convert_col_to_char_index(line, NULL, line->change_end_col, 0);
1264   }
1265 }
1266 
vt_line_get_num_redrawn_chars(vt_line_t * line,int to_end)1267 u_int vt_line_get_num_redrawn_chars(vt_line_t *line, int to_end) {
1268   if (IS_EMPTY(line)) {
1269     return 0;
1270   } else if (to_end) {
1271     return line->num_filled_chars - vt_line_get_beg_of_modified(line);
1272   } else {
1273     return vt_line_get_end_of_modified(line) - vt_line_get_beg_of_modified(line) + 1;
1274   }
1275 }
1276 
vt_line_set_updated(vt_line_t * line)1277 void vt_line_set_updated(vt_line_t *line) {
1278   line->is_modified = 0;
1279 
1280   line->change_beg_col = 0;
1281   line->change_end_col = 0;
1282 }
1283 
vt_line_is_continued_to_next(vt_line_t * line)1284 int vt_line_is_continued_to_next(vt_line_t *line) { return line->is_continued_to_next; }
1285 
vt_line_set_continued_to_next(vt_line_t * line,int flag)1286 void vt_line_set_continued_to_next(vt_line_t *line, int flag) { line->is_continued_to_next = flag; }
1287 
vt_convert_char_index_to_col(vt_line_t * line,int char_index,int flag)1288 int vt_convert_char_index_to_col(vt_line_t *line, int char_index, int flag /* BREAK_BOUNDARY */
1289                                  ) {
1290   int count;
1291   int col;
1292 
1293   if (char_index >= line->num_chars) {
1294 #ifdef __DEBUG
1295     bl_debug_printf(BL_DEBUG_TAG
1296                     " char index %d is larger than num_chars(%d) ... modified -> %d.\n",
1297                     char_index, line->num_chars, line->num_chars - 1);
1298 #endif
1299 
1300     char_index = line->num_chars - 1;
1301   }
1302 
1303   col = 0;
1304 
1305   if ((flag & BREAK_BOUNDARY) && line->num_filled_chars <= char_index) {
1306     for (count = 0; count < line->num_filled_chars; count++) {
1307       col += vt_char_cols(line->chars + count);
1308     }
1309 
1310     col += (char_index - count);
1311   } else if (line->num_filled_chars > 0) {
1312     /*
1313      * excluding the width of the last char.
1314      */
1315     int end = BL_MIN(char_index, END_CHAR_INDEX(line));
1316 
1317     for (count = 0; count < end; count++) {
1318       col += vt_char_cols(line->chars + count);
1319     }
1320   }
1321 
1322   return col;
1323 }
1324 
vt_convert_col_to_char_index(vt_line_t * line,u_int * cols_rest,int col,int flag)1325 int vt_convert_col_to_char_index(vt_line_t *line, u_int *cols_rest, int col,
1326                                  int flag /* BREAK_BOUNDARY */
1327                                  ) {
1328   int char_index;
1329 
1330 #ifdef DEBUG
1331   if (col >= line->num_chars * 2 && cols_rest) {
1332     bl_warn_printf(BL_DEBUG_TAG
1333                    " Since col [%d] is over line->num_chars * 2 [%d],"
1334                    " cols_rest will be corrupt...\n",
1335                    col, line->num_chars * 2);
1336   }
1337 #endif
1338 
1339   for (char_index = 0; char_index + 1 < line->num_filled_chars; char_index++) {
1340     int cols;
1341 
1342     cols = vt_char_cols(line->chars + char_index);
1343     if (col < cols) {
1344       goto end;
1345     }
1346 
1347     col -= cols;
1348   }
1349 
1350   if (flag & BREAK_BOUNDARY) {
1351     char_index += col;
1352     col = 0;
1353   }
1354 
1355 end:
1356   if (cols_rest != NULL) {
1357     *cols_rest = col;
1358   }
1359 
1360   return char_index;
1361 }
1362 
vt_line_reverse_color(vt_line_t * line,int char_index)1363 int vt_line_reverse_color(vt_line_t *line, int char_index) {
1364   if (char_index >= line->num_filled_chars) {
1365     return 0;
1366   }
1367 
1368   if (vt_char_reverse_color(line->chars + char_index)) {
1369     vt_line_set_modified(line, char_index, char_index);
1370   }
1371 
1372   return 1;
1373 }
1374 
vt_line_restore_color(vt_line_t * line,int char_index)1375 int vt_line_restore_color(vt_line_t *line, int char_index) {
1376   if (char_index >= line->num_filled_chars) {
1377     return 0;
1378   }
1379 
1380   if (vt_char_restore_color(line->chars + char_index)) {
1381     vt_line_set_modified(line, char_index, char_index);
1382   }
1383 
1384   return 1;
1385 }
1386 
1387 /*
1388  * This copys a line as it is and doesn't care about visual order.
1389  * But bidi parameters are also copyed as it is.
1390  */
vt_line_copy(vt_line_t * dst,vt_line_t * src)1391 int vt_line_copy(vt_line_t *dst, /* should be initialized ahead */
1392                  vt_line_t *src) {
1393   copy_line(dst, src, 0);
1394 
1395   return 1;
1396 }
1397 
vt_line_swap(vt_line_t * line1,vt_line_t * line2)1398 int vt_line_swap(vt_line_t *line1, vt_line_t *line2) {
1399   vt_line_t tmp;
1400 
1401   tmp = *line1;
1402   *line1 = *line2;
1403   *line2 = tmp;
1404 
1405   return 1;
1406 }
1407 
vt_line_share(vt_line_t * dst,vt_line_t * src)1408 int vt_line_share(vt_line_t *dst, vt_line_t *src) {
1409   memcpy(dst, src, sizeof(vt_line_t));
1410 
1411   return 1;
1412 }
1413 
vt_line_is_empty(vt_line_t * line)1414 int vt_line_is_empty(vt_line_t *line) { return IS_EMPTY(line); }
1415 
vt_line_beg_char_index_regarding_rtl(vt_line_t * line)1416 int vt_line_beg_char_index_regarding_rtl(vt_line_t *line) {
1417   int char_index;
1418 
1419   if (vt_line_is_rtl(line)) {
1420     for (char_index = 0; char_index < line->num_filled_chars; char_index++) {
1421       if (!vt_char_equal(line->chars + char_index, vt_sp_ch())) {
1422         return char_index;
1423       }
1424     }
1425   }
1426 
1427   return 0;
1428 }
1429 
vt_line_end_char_index(vt_line_t * line)1430 int vt_line_end_char_index(vt_line_t *line) {
1431   if (IS_EMPTY(line)) {
1432 #ifdef __DEBUG
1433     bl_debug_printf(BL_DEBUG_TAG " num_filled_chars is 0.\n");
1434 #endif
1435 
1436     return 0;
1437   } else {
1438     return line->num_filled_chars - 1;
1439   }
1440 }
1441 
vt_line_get_num_filled_cols(vt_line_t * line)1442 u_int vt_line_get_num_filled_cols(vt_line_t *line) {
1443   return vt_str_cols(line->chars, line->num_filled_chars);
1444 }
1445 
vt_line_get_num_filled_chars_except_sp_with_func(vt_line_t * line,int (* func)(vt_char_t *,vt_char_t *))1446 u_int vt_line_get_num_filled_chars_except_sp_with_func(vt_line_t *line,
1447                                                        int (*func)(vt_char_t *, vt_char_t *)) {
1448   if (IS_EMPTY(line)) {
1449     return 0;
1450   } else if (vt_line_is_rtl(line) || line->is_continued_to_next) {
1451     return line->num_filled_chars;
1452   } else {
1453     int char_index;
1454 
1455     for (char_index = END_CHAR_INDEX(line); char_index >= 0; char_index--) {
1456 #if 1
1457       /* >= 3.0.6 */
1458       if (!(*func)(line->chars + char_index, vt_sp_ch()))
1459 #else
1460       /* <= 3.0.5 */
1461       if (!vt_char_equal(line->chars + char_index, vt_sp_ch()))
1462 #endif
1463       {
1464         return char_index + 1;
1465       }
1466     }
1467 
1468     return 0;
1469   }
1470 }
1471 
vt_line_set_size_attr(vt_line_t * line,int size_attr)1472 void vt_line_set_size_attr(vt_line_t *line, int size_attr) {
1473   if (line->size_attr != size_attr) {
1474     line->size_attr = size_attr;
1475     vt_line_set_modified_all(line);
1476   }
1477 }
1478 
vt_line_convert_visual_char_index_to_logical(vt_line_t * line,int char_index)1479 int vt_line_convert_visual_char_index_to_logical(vt_line_t *line, int char_index) {
1480   if (vt_line_is_using_bidi(line)) {
1481     return vt_line_bidi_convert_visual_char_index_to_logical(line, char_index);
1482   }
1483 #ifdef USE_OT_LAYOUT
1484   else if (vt_line_is_using_ot_layout(line)) {
1485     return vt_line_ot_layout_convert_visual_char_index_to_logical(line, char_index);
1486   }
1487 #endif
1488   else if (vt_line_is_using_iscii(line)) {
1489     return vt_line_iscii_convert_visual_char_index_to_logical(line, char_index);
1490   } else {
1491     return char_index;
1492   }
1493 }
1494 
vt_line_is_rtl(vt_line_t * line)1495 int vt_line_is_rtl(vt_line_t *line) {
1496   if (vt_line_is_using_bidi(line)) {
1497     return vt_line_bidi_is_rtl(line);
1498   } else {
1499     return 0;
1500   }
1501 }
1502 
1503 /*
1504  * It is assumed that this function is called in *visual* context.
1505  */
vt_line_copy_logical_str(vt_line_t * line,vt_char_t * dst,int beg,u_int len)1506 int vt_line_copy_logical_str(vt_line_t *line, vt_char_t *dst, int beg, /* visual position */
1507                              u_int len) {
1508   if (vt_line_is_using_bidi(line)) {
1509     if (vt_line_bidi_copy_logical_str(line, dst, beg, len)) {
1510       return 1;
1511     }
1512   }
1513 
1514   return vt_str_copy(dst, line->chars + beg, len);
1515 }
1516 
vt_line_convert_logical_char_index_to_visual(vt_line_t * line,int char_index,u_int32_t * meet_pos_info)1517 int vt_line_convert_logical_char_index_to_visual(vt_line_t *line, int char_index,
1518                                                  u_int32_t *meet_pos_info) {
1519 #ifdef NO_DYNAMIC_LOAD_CTL
1520   if (line->ctl_info_type) {
1521 #ifdef USE_OT_LAYOUT
1522     if (vt_line_is_using_ot_layout(line)) {
1523       char_index = vt_line_ot_layout_convert_logical_char_index_to_visual(line, char_index);
1524     } else
1525 #endif
1526         if (vt_line_is_using_bidi(line)) {
1527 #ifdef USE_FRIBIDI
1528       char_index = vt_line_bidi_convert_logical_char_index_to_visual(line, char_index,
1529                                                                      meet_pos_info);
1530 #endif
1531     } else /* if( vt_line_is_using_iscii( line)) */
1532     {
1533 #ifdef USE_IND
1534       char_index = vt_line_iscii_convert_logical_char_index_to_visual(line, char_index);
1535 #endif
1536     }
1537   }
1538 
1539   return char_index;
1540 #else
1541   if (line->ctl_info_type) {
1542 #ifdef USE_OT_LAYOUT
1543     if (vt_line_is_using_ot_layout(line)) {
1544       char_index = vt_line_ot_layout_convert_logical_char_index_to_visual(line, char_index);
1545     } else
1546 #endif
1547         if (vt_line_is_using_bidi(line)) {
1548       int (*bidi_func)(vt_line_t *, int, int *);
1549 
1550       if ((bidi_func = vt_load_ctl_bidi_func(VT_LINE_BIDI_CONVERT_LOGICAL_CHAR_INDEX_TO_VISUAL))) {
1551         char_index = (*bidi_func)(line, char_index, meet_pos_info);
1552       }
1553     } else /* if( vt_line_is_using_iscii( line)) */
1554     {
1555       int (*iscii_func)(vt_line_t *, int);
1556 
1557       if ((iscii_func =
1558                vt_load_ctl_iscii_func(VT_LINE_ISCII_CONVERT_LOGICAL_CHAR_INDEX_TO_VISUAL))) {
1559         char_index = (*iscii_func)(line, char_index);
1560       }
1561     }
1562   }
1563 
1564   return char_index;
1565 #endif
1566 }
1567 
vt_line_unuse_ctl(vt_line_t * line)1568 int vt_line_unuse_ctl(vt_line_t *line) {
1569   if (line->ctl_info_type) {
1570     /* *_render() which may be called later works only if vt_line_t is really modified. */
1571     set_real_modified(line, 0, END_CHAR_INDEX(line));
1572 #ifdef USE_OT_LAYOUT
1573     if (vt_line_is_using_ot_layout(line)) {
1574       return vt_line_set_use_ot_layout(line, 0);
1575     } else
1576 #endif
1577         if (vt_line_is_using_bidi(line)) {
1578       return vt_line_set_use_bidi(line, 0);
1579     } else /* if( vt_line_is_using_iscii( line)) */
1580     {
1581       return vt_line_set_use_iscii(line, 0);
1582     }
1583   }
1584 
1585   return 0;
1586 }
1587 
vt_line_ctl_render(vt_line_t * line,vt_bidi_mode_t bidi_mode,const char * separators,void * term)1588 int vt_line_ctl_render(vt_line_t *line, vt_bidi_mode_t bidi_mode, const char *separators,
1589                        void *term) {
1590   int ret;
1591   int (*set_use_ctl)(vt_line_t *, int);
1592 
1593   if (!vt_line_is_using_ctl(line)) {
1594     if (
1595 #ifdef USE_OT_LAYOUT
1596         (!term || !vt_line_set_use_ot_layout(line, 1)) &&
1597 #endif
1598         !vt_line_set_use_bidi(line, 1) && !vt_line_set_use_iscii(line, 1)) {
1599       return 0;
1600     }
1601   }
1602 
1603   if (line->ctl_info_type) {
1604 #ifdef USE_OT_LAYOUT
1605     if (vt_line_is_using_ot_layout(line)) {
1606       if (!term) {
1607         ret = -1;
1608       } else if ((ret = vt_line_ot_layout_render(line, term)) >= 0) {
1609         return ret;
1610       }
1611 
1612       set_use_ctl = vt_line_set_use_ot_layout;
1613 
1614       if (ret == -1) {
1615         goto render_bidi;
1616       } else /* if( ret == -2) */
1617       {
1618         goto render_iscii;
1619       }
1620     } else
1621 #endif
1622         if (vt_line_is_using_bidi(line)) {
1623       if ((ret = vt_line_bidi_render(line, bidi_mode, separators)) >= 0) {
1624         return ret;
1625       }
1626 
1627 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_FRIBIDI)
1628       set_use_ctl = vt_line_set_use_bidi;
1629 #else
1630 /* Never enter here */
1631 #endif
1632 
1633       if (ret == -1) {
1634 #ifdef USE_OT_LAYOUT
1635         if (!term) {
1636           return 1;
1637         }
1638 
1639         goto render_ot_layout;
1640 #else
1641         return 1;
1642 #endif
1643       } else /* if( ret == -2) */
1644       {
1645         goto render_iscii;
1646       }
1647     } else /* if( vt_line_is_using_iscii( line)) */
1648     {
1649       if ((ret = vt_line_iscii_render(line)) >= 0) {
1650         return ret;
1651       }
1652 
1653 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_IND)
1654       set_use_ctl = vt_line_set_use_iscii;
1655 #else
1656 /* Never enter here */
1657 #endif
1658 
1659 #ifdef USE_OT_LAYOUT
1660       if (term) {
1661         goto render_ot_layout;
1662       } else
1663 #endif
1664       {
1665         goto render_bidi;
1666       }
1667     }
1668   }
1669 
1670   return 0;
1671 
1672 #ifdef USE_OT_LAYOUT
1673 render_ot_layout:
1674   (*set_use_ctl)(line, 0);
1675   vt_line_set_use_ot_layout(line, 1);
1676 
1677   if ((ret = vt_line_ot_layout_render(line, term) != -1)) {
1678     return ret;
1679   }
1680 
1681 /* Fall through */
1682 #endif
1683 
1684 render_bidi:
1685   if (
1686 #if !defined(NO_DYNAMIC_LOAD_CTL)
1687       vt_load_ctl_bidi_func(VT_LINE_SET_USE_BIDI)
1688 #elif defined(USE_FRIBIDI)
1689       1
1690 #else
1691       0
1692 #endif
1693           ) {
1694     (*set_use_ctl)(line, 0);
1695     vt_line_set_use_bidi(line, 1);
1696 
1697     return vt_line_bidi_render(line, bidi_mode, separators);
1698   } else {
1699     return 0;
1700   }
1701 
1702 render_iscii:
1703   if (
1704 #if !defined(NO_DYNAMIC_LOAD_CTL)
1705       vt_load_ctl_iscii_func(VT_LINE_SET_USE_ISCII)
1706 #elif defined(USE_ISCII)
1707       1
1708 #else
1709       0
1710 #endif
1711           ) {
1712     (*set_use_ctl)(line, 0);
1713     vt_line_set_use_iscii(line, 1);
1714 
1715     return vt_line_iscii_render(line);
1716   } else {
1717     return 0;
1718   }
1719 }
1720 
vt_line_ctl_visual(vt_line_t * line)1721 int vt_line_ctl_visual(vt_line_t *line) {
1722   if (line->ctl_info_type) {
1723 #ifdef USE_OT_LAYOUT
1724     if (vt_line_is_using_ot_layout(line)) {
1725       return vt_line_ot_layout_visual(line);
1726     } else
1727 #endif
1728         if (vt_line_is_using_bidi(line)) {
1729       return vt_line_bidi_visual(line);
1730     } else /* if( vt_line_is_using_iscii( line)) */
1731     {
1732       return vt_line_iscii_visual(line);
1733     }
1734   }
1735 
1736   return 0;
1737 }
1738 
vt_line_ctl_logical(vt_line_t * line)1739 int vt_line_ctl_logical(vt_line_t *line) {
1740   if (line->ctl_info_type) {
1741 #ifdef USE_OT_LAYOUT
1742     if (vt_line_is_using_ot_layout(line)) {
1743       return vt_line_ot_layout_logical(line);
1744     } else
1745 #endif
1746         if (vt_line_is_using_bidi(line)) {
1747       return vt_line_bidi_logical(line);
1748     } else /* if( vt_line_is_using_iscii( line)) */
1749     {
1750       return vt_line_iscii_logical(line);
1751     }
1752   }
1753 
1754   return 0;
1755 }
1756 
vt_line_clear_picture(vt_line_t * line)1757 int vt_line_clear_picture(vt_line_t *line) {
1758   int count;
1759   int rmpic = 0;
1760 
1761   for (count = 0; count < line->num_filled_chars; count++) {
1762     vt_char_t *ch;
1763 
1764     if ((ch = vt_get_picture_char(line->chars + count))) {
1765       rmpic = 1;
1766       vt_char_copy(ch, vt_sp_ch());
1767     }
1768   }
1769 
1770   return rmpic;
1771 }
1772 
1773 #ifdef DEBUG
1774 
vt_line_dump(vt_line_t * line)1775 void vt_line_dump(vt_line_t *line) {
1776   int count;
1777 
1778   for (count = 0; count < line->num_filled_chars; count++) {
1779     vt_char_dump(line->chars + count);
1780   }
1781 
1782   bl_msg_printf("\n");
1783 }
1784 
1785 #endif
1786