1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "vt_logical_visual.h"
4 
5 #include <pobl/bl_mem.h>   /* realloc/free */
6 #include <pobl/bl_debug.h> /* bl_msg_printf */
7 #include <pobl/bl_str.h>   /* strcmp */
8 #include "vt_ctl_loader.h"
9 #include "vt_shape.h" /* vt_is_arabic_combining */
10 
11 #define CURSOR_LINE(logvis) (vt_model_get_line((logvis)->model, (logvis)->cursor->row))
12 
13 #define MSB32 0x80000000
14 
15 #if 0
16 #define __DEBUG
17 #endif
18 
19 #if 0
20 #define CURSOR_DEBUG
21 #endif
22 
23 typedef struct container_logical_visual {
24   vt_logical_visual_t logvis;
25 
26   /*
27    * visual : children[0] => children[1] => ... => children[n]
28    * logical: children[n] => ... => children[1] => children[0]
29    */
30   vt_logical_visual_t **children;
31   u_int num_children;
32 
33 } container_logical_visual_t;
34 
35 typedef struct comb_logical_visual {
36   vt_logical_visual_t logvis;
37 
38   int cursor_logical_char_index;
39   int cursor_logical_col;
40 
41 } comb_logical_visual_t;
42 
43 typedef struct vert_logical_visual {
44   vt_logical_visual_t logvis;
45 
46   vt_model_t logical_model;
47   vt_model_t visual_model;
48 
49   int cursor_logical_char_index;
50   int cursor_logical_col;
51   int cursor_logical_row;
52 
53   int8_t is_init;
54 
55 } vert_logical_visual_t;
56 
57 typedef struct ctl_logical_visual {
58   vt_logical_visual_t logvis;
59 
60   int cursor_logical_char_index;
61   int cursor_logical_col;
62   u_int32_t cursor_meet_pos_info;
63   vt_bidi_mode_t bidi_mode;
64   const char *separators;
65   void *term;
66 
67 } ctl_logical_visual_t;
68 
69 /* --- static variables --- */
70 
71 /* Order of this table must be same as x_vertical_mode_t. */
72 static char *vertical_mode_name_table[] = {
73     "none", "mongol", "cjk",
74 };
75 
76 /* --- static functions --- */
77 
container_destroy(vt_logical_visual_t * logvis)78 static int container_destroy(vt_logical_visual_t *logvis) {
79   container_logical_visual_t *container;
80   int count;
81 
82   container = (container_logical_visual_t*)logvis;
83 
84   if (container->num_children) {
85     for (count = container->num_children - 1; count >= 0; count--) {
86       (*container->children[count]->destroy)(container->children[count]);
87     }
88   }
89 
90   free(container->children);
91 
92   free(logvis);
93 
94   return 1;
95 }
96 
container_init(vt_logical_visual_t * logvis,vt_model_t * model,vt_cursor_t * cursor)97 static int container_init(vt_logical_visual_t *logvis, vt_model_t *model, vt_cursor_t *cursor) {
98   container_logical_visual_t *container;
99   u_int count;
100 
101   logvis->model = model;
102   logvis->cursor = cursor;
103 
104   container = (container_logical_visual_t*)logvis;
105 
106   for (count = 0; count < container->num_children; count++) {
107     (*container->children[count]->init)(container->children[count], model, cursor);
108   }
109 
110   return 1;
111 }
112 
container_logical_cols(vt_logical_visual_t * logvis)113 static u_int container_logical_cols(vt_logical_visual_t *logvis) {
114   container_logical_visual_t *container;
115 
116   container = (container_logical_visual_t*)logvis;
117 
118   if (container->num_children > 0) {
119     return (*container->children[container->num_children - 1]->logical_cols)(
120         container->children[container->num_children - 1]);
121   } else {
122     return logvis->model->num_cols;
123   }
124 }
125 
container_logical_rows(vt_logical_visual_t * logvis)126 static u_int container_logical_rows(vt_logical_visual_t *logvis) {
127   container_logical_visual_t *container;
128 
129   container = (container_logical_visual_t*)logvis;
130 
131   if (container->num_children > 0) {
132     return (*container->children[container->num_children - 1]->logical_rows)(
133         container->children[container->num_children - 1]);
134   } else {
135     return logvis->model->num_rows;
136   }
137 }
138 
container_render(vt_logical_visual_t * logvis)139 static void container_render(vt_logical_visual_t *logvis) {
140   container_logical_visual_t *container;
141   u_int count;
142 
143   container = (container_logical_visual_t*)logvis;
144 
145   /*
146    * XXX
147    * only the first children can render correctly.
148    */
149   for (count = 0; count < container->num_children; count++) {
150     (*container->children[count]->render)(container->children[count]);
151   }
152 }
153 
container_visual(vt_logical_visual_t * logvis)154 static int container_visual(vt_logical_visual_t *logvis) {
155   container_logical_visual_t *container;
156   u_int count;
157 
158   if (logvis->is_visual) {
159     return 0;
160   }
161 
162   container = (container_logical_visual_t*)logvis;
163 
164   for (count = 0; count < container->num_children; count++) {
165     (*container->children[count]->visual)(container->children[count]);
166   }
167 
168   logvis->is_visual = 1;
169 
170   return 1;
171 }
172 
container_logical(vt_logical_visual_t * logvis)173 static int container_logical(vt_logical_visual_t *logvis) {
174   container_logical_visual_t *container;
175   int count;
176 
177   if (!logvis->is_visual) {
178     return 0;
179   }
180 
181   container = (container_logical_visual_t*)logvis;
182 
183   if (container->num_children == 0) {
184     return 1;
185   }
186 
187   for (count = container->num_children - 1; count >= 0; count--) {
188     (*container->children[count]->logical)(container->children[count]);
189   }
190 
191   logvis->is_visual = 0;
192 
193   return 1;
194 }
195 
container_visual_line(vt_logical_visual_t * logvis,vt_line_t * line)196 static void container_visual_line(vt_logical_visual_t *logvis, vt_line_t *line) {
197   container_logical_visual_t *container;
198   u_int count;
199 
200   container = (container_logical_visual_t*)logvis;
201 
202   for (count = 0; count < container->num_children; count++) {
203     (*container->children[count]->visual_line)(container->children[count], line);
204   }
205 }
206 
207 /*
208  * dynamic combining
209  */
210 
comb_destroy(vt_logical_visual_t * logvis)211 static int comb_destroy(vt_logical_visual_t *logvis) {
212   free(logvis);
213 
214   return 1;
215 }
216 
comb_init(vt_logical_visual_t * logvis,vt_model_t * model,vt_cursor_t * cursor)217 static int comb_init(vt_logical_visual_t *logvis, vt_model_t *model, vt_cursor_t *cursor) {
218   logvis->model = model;
219   logvis->cursor = cursor;
220 
221   return 1;
222 }
223 
comb_logical_cols(vt_logical_visual_t * logvis)224 static u_int comb_logical_cols(vt_logical_visual_t *logvis) { return logvis->model->num_cols; }
225 
comb_logical_rows(vt_logical_visual_t * logvis)226 static u_int comb_logical_rows(vt_logical_visual_t *logvis) { return logvis->model->num_rows; }
227 
comb_render(vt_logical_visual_t * logvis)228 static void comb_render(vt_logical_visual_t *logvis) {}
229 
comb_visual(vt_logical_visual_t * logvis)230 static int comb_visual(vt_logical_visual_t *logvis) {
231   int row;
232 
233   if (logvis->is_visual) {
234     return 0;
235   }
236 
237   ((comb_logical_visual_t*)logvis)->cursor_logical_char_index = logvis->cursor->char_index;
238   ((comb_logical_visual_t*)logvis)->cursor_logical_col = logvis->cursor->col;
239 
240   for (row = 0; row < logvis->model->num_rows; row++) {
241     vt_line_t *line;
242     int dst_pos;
243     int src_pos;
244     vt_char_t *cur;
245 
246     line = vt_model_get_line(logvis->model, row);
247 
248     dst_pos = 0;
249     cur = line->chars;
250     for (src_pos = 0; src_pos < line->num_filled_chars; src_pos++) {
251       if (dst_pos > 0 &&
252           (vt_char_is_comb(cur) ||
253            vt_is_arabic_combining(dst_pos >= 2 ? vt_char_at(line, dst_pos - 2) : NULL,
254                                   vt_char_at(line, dst_pos - 1), cur))) {
255         vt_char_combine_simple(vt_char_at(line, dst_pos - 1), cur);
256 
257 #if 0
258         /*
259          * This doesn't work as expected, for example, when
260          * one of combined two characters is destroyed.
261          */
262         if (vt_line_is_modified(line)) {
263           int beg;
264           int end;
265 
266           beg = vt_line_get_beg_of_modified(line);
267           end = vt_line_get_end_of_modified(line);
268 
269           if (beg > dst_pos - 1) {
270             beg--;
271           }
272 
273           if (end > dst_pos - 1) {
274             end--;
275           }
276 
277           vt_line_set_updated(line);
278           vt_line_set_modified(line, beg, end);
279         }
280 #endif
281       } else {
282         vt_char_copy(vt_char_at(line, dst_pos++), cur);
283       }
284 
285       if (row == logvis->cursor->row && src_pos == logvis->cursor->char_index) {
286         logvis->cursor->char_index = dst_pos - 1;
287         logvis->cursor->col =
288             vt_convert_char_index_to_col(CURSOR_LINE(logvis), logvis->cursor->char_index, 0) +
289             logvis->cursor->col_in_char;
290       }
291 
292       cur++;
293     }
294 
295 #if 1
296     if (vt_line_is_modified(line)) {
297       /*
298        * (Logical)    AbcdEfgHij  (bcdfg are combining characters)
299        * => (Visual)  AEH
300        * => (Logical) AbcEfgHij
301        *                 ^^^^^^^ (^ means redrawn characters)
302        * => (Visual)  AE
303        *                 ^^^^^^^
304        *              ^^^^^^^^^^ <= vt_line_set_modified( line , 0 , ...)
305        * => (Logical) AkcEfgHij
306        *               ^
307        * => (Visual)  AEH
308        *               ^
309        *              ^^ <= vt_line_set_modified( line , 0 , ...)
310        */
311       vt_line_set_modified(line, 0, vt_line_get_end_of_modified(line));
312     }
313 #endif
314 
315     line->num_filled_chars = dst_pos;
316   }
317 
318   logvis->is_visual = 1;
319 
320   return 1;
321 }
322 
comb_logical(vt_logical_visual_t * logvis)323 static int comb_logical(vt_logical_visual_t *logvis) {
324   vt_char_t *buf;
325   int row;
326 
327   if (!logvis->is_visual) {
328     return 0;
329   }
330 
331   if ((buf = vt_str_alloca(logvis->model->num_cols)) == NULL) {
332     return 0;
333   }
334   vt_str_init(buf, logvis->model->num_cols);
335 
336   for (row = 0; row < logvis->model->num_rows; row++) {
337     vt_line_t *line;
338     int src_pos;
339     u_int src_len;
340     vt_char_t *c;
341 
342     line = vt_model_get_line(logvis->model, row);
343 
344     vt_str_copy(buf, line->chars, line->num_filled_chars);
345 
346     src_len = line->num_filled_chars;
347     line->num_filled_chars = 0;
348     c = buf;
349     for (src_pos = 0; src_pos < src_len && line->num_filled_chars < line->num_chars;
350          src_pos++) {
351       vt_char_t *comb;
352       u_int size;
353 
354       if ((comb = vt_get_combining_chars(c, &size))
355 #if 1
356           /* XXX Hack for inline pictures (see x_picture.c) */
357           &&
358           vt_char_cs(comb) != PICTURE_CHARSET
359 #endif
360           ) {
361         int count;
362 
363         vt_char_copy(vt_char_at(line, line->num_filled_chars++), vt_get_base_char(c));
364 
365         for (count = 0; count < size; count++) {
366           if (line->num_filled_chars >= line->num_chars) {
367             break;
368           }
369 
370 #if 0
371           /*
372            * This doesn't work as expected, for example, when
373            * one of combined two characters is destroyed.
374            */
375           if (vt_line_is_modified(line)) {
376             int beg;
377             int end;
378             int is_cleared_to_end;
379 
380             beg = vt_line_get_beg_of_modified(line);
381             end = vt_line_get_end_of_modified(line);
382 
383             if (beg > src_pos) {
384               beg++;
385             }
386 
387             if (end > src_pos) {
388               end++;
389             }
390 
391             vt_line_set_updated(line);
392             vt_line_set_modified(line, beg, end);
393           }
394 #endif
395 
396           vt_char_copy(vt_char_at(line, line->num_filled_chars++), comb);
397 
398           comb++;
399         }
400       } else {
401         vt_char_copy(vt_char_at(line, line->num_filled_chars++), c);
402       }
403 
404       c++;
405     }
406   }
407 
408   vt_str_final(buf, logvis->model->num_cols);
409 
410   logvis->cursor->char_index = ((comb_logical_visual_t*)logvis)->cursor_logical_char_index;
411   logvis->cursor->col = ((comb_logical_visual_t*)logvis)->cursor_logical_col;
412 
413   logvis->is_visual = 0;
414 
415   return 1;
416 }
417 
comb_visual_line(vt_logical_visual_t * logvis,vt_line_t * line)418 static void comb_visual_line(vt_logical_visual_t *logvis, vt_line_t *line) {
419   int dst_pos;
420   int src_pos;
421   vt_char_t *cur;
422 
423   dst_pos = 0;
424   cur = line->chars;
425   for (src_pos = 0; src_pos < line->num_filled_chars; src_pos++) {
426     if (dst_pos > 0 && (vt_char_is_comb(cur) ||
427                         vt_is_arabic_combining(dst_pos >= 2 ? vt_char_at(line, dst_pos - 2) : NULL,
428                                                vt_char_at(line, dst_pos - 1), cur))) {
429       vt_char_combine_simple(vt_char_at(line, dst_pos - 1), cur);
430     } else {
431       vt_char_copy(vt_char_at(line, dst_pos++), cur);
432     }
433 
434     cur++;
435   }
436 
437   line->num_filled_chars = dst_pos;
438 }
439 
440 /*
441  * vertical view logical <=> visual methods
442  */
443 
vert_destroy(vt_logical_visual_t * logvis)444 static int vert_destroy(vt_logical_visual_t *logvis) {
445   vert_logical_visual_t *vert_logvis;
446 
447   if (logvis->model) {
448     vert_logvis = (vert_logical_visual_t*)logvis;
449     vt_model_final(&vert_logvis->visual_model);
450   }
451 
452   free(logvis);
453 
454   return 1;
455 }
456 
vert_init(vt_logical_visual_t * logvis,vt_model_t * model,vt_cursor_t * cursor)457 static int vert_init(vt_logical_visual_t *logvis, vt_model_t *model, vt_cursor_t *cursor) {
458   vert_logical_visual_t *vert_logvis;
459 
460   vert_logvis = (vert_logical_visual_t*)logvis;
461 
462   if (vert_logvis->is_init) {
463     vt_model_resize(&vert_logvis->visual_model, model->num_rows, model->num_cols, 0);
464   } else {
465     vt_model_init(&vert_logvis->visual_model, model->num_rows, model->num_cols);
466     vert_logvis->is_init = 1;
467   }
468 
469   vert_logvis->logical_model = *model;
470 
471   logvis->model = model;
472   logvis->cursor = cursor;
473 
474   return 1;
475 }
476 
vert_logical_cols(vt_logical_visual_t * logvis)477 static u_int vert_logical_cols(vt_logical_visual_t *logvis) {
478   if (logvis->is_visual) {
479     return ((vert_logical_visual_t*)logvis)->logical_model.num_cols;
480   } else {
481     return logvis->model->num_cols;
482   }
483 }
484 
vert_logical_rows(vt_logical_visual_t * logvis)485 static u_int vert_logical_rows(vt_logical_visual_t *logvis) {
486   if (logvis->is_visual) {
487     return ((vert_logical_visual_t*)logvis)->logical_model.num_rows;
488   } else {
489     return logvis->model->num_rows;
490   }
491 }
492 
vert_render(vt_logical_visual_t * logvis)493 static void vert_render(vt_logical_visual_t *logvis) {}
494 
vert_set_modified(vt_line_t * vis_line,vt_line_t * log_line,int log_char_index)495 static void vert_set_modified(vt_line_t *vis_line, vt_line_t *log_line, int log_char_index) {
496   /*
497    * a:hankaku AA:zenkaku
498    *
499    * 012 3     0 1
500    * 012345    0123
501    * abAABB => AABB  : change_beg_col=0, change_end_col=3, beg_of_modified=0, end_of_modified=1
502    *
503    * 0 aa   => AA : should be redraw from 0 column to 3 column
504    * 1 bb      BB
505    * 2 AA
506    * 3 BB
507    *
508    *    ||
509    *
510    * call vt_line_set_modified() from vt_line_get_beg_of_modified(log_line) to
511    * log_line->change_end_col.
512    */
513   if (vt_line_is_modified(log_line) && vt_line_get_beg_of_modified(log_line) <= log_char_index &&
514       (vt_line_is_cleared_to_end(log_line) || log_char_index <= log_line->change_end_col)) {
515     vt_line_set_modified(vis_line, vis_line->num_filled_chars - 1,
516                          vis_line->num_filled_chars - 1);
517   }
518 }
519 
vert_visual_intern(vt_logical_visual_t * logvis,vt_vertical_mode_t mode)520 static int vert_visual_intern(vt_logical_visual_t *logvis, vt_vertical_mode_t mode) {
521   vert_logical_visual_t *vert_logvis;
522   vt_line_t *log_line;
523   vt_line_t *vis_line;
524   int row;
525   int count;
526 
527   if (logvis->is_visual) {
528     return 0;
529   }
530 
531 #ifdef CURSOR_DEBUG
532   bl_debug_printf(BL_DEBUG_TAG " logical cursor [col %d index %d row %d]\n", logvis->cursor->col,
533                   logvis->cursor->char_index, logvis->cursor->row);
534 #endif
535 
536   vert_logvis = (vert_logical_visual_t*)logvis;
537 
538   if (vert_logvis->logical_model.num_rows != logvis->model->num_rows ||
539       vert_logvis->logical_model.num_cols != logvis->model->num_cols) {
540     /* vt_model_t is resized */
541 
542     vt_model_resize(&vert_logvis->visual_model, logvis->model->num_rows,
543                     logvis->model->num_cols, 0);
544   }
545 
546   vt_model_reset(&vert_logvis->visual_model);
547 
548   if (mode & VERT_LTR) {
549     /* Mongol */
550 
551     count = -1;
552   } else {
553     /* CJK */
554 
555     count = logvis->model->num_rows;
556   }
557 
558   while (1) {
559     if (mode & VERT_LTR) {
560       /* Mongol */
561 
562       if (++count >= logvis->model->num_rows) {
563         break;
564       }
565     } else {
566       /* CJK */
567 
568       if (--count < 0) {
569         break;
570       }
571     }
572 
573     log_line = vt_model_get_line(logvis->model, count);
574 
575     for (row = 0; row < log_line->num_filled_chars; row++) {
576       vis_line = vt_model_get_line(&vert_logvis->visual_model, row);
577 
578       if (vis_line == NULL || vis_line->num_filled_chars >= vis_line->num_chars) {
579         continue;
580       }
581 
582       vt_char_copy(vt_char_at(vis_line, vis_line->num_filled_chars++),
583                    vt_char_at(log_line, row));
584 
585       vert_set_modified(vis_line, log_line, row);
586     }
587 
588     for (; row < vert_logvis->visual_model.num_rows; row++) {
589       vis_line = vt_model_get_line(&vert_logvis->visual_model, row);
590 
591       if (vis_line == NULL || vis_line->num_filled_chars >= vis_line->num_chars) {
592         continue;
593       }
594 
595       vt_char_copy(vt_char_at(vis_line, vis_line->num_filled_chars++), vt_sp_ch());
596 
597       vert_set_modified(vis_line, log_line, row);
598     }
599   }
600 
601   vert_logvis->logical_model = *logvis->model;
602   *logvis->model = vert_logvis->visual_model;
603 
604   vert_logvis->cursor_logical_char_index = logvis->cursor->char_index;
605   vert_logvis->cursor_logical_col = logvis->cursor->col;
606   vert_logvis->cursor_logical_row = logvis->cursor->row;
607 
608   logvis->cursor->row = vert_logvis->cursor_logical_char_index;
609   logvis->cursor->char_index = logvis->cursor->col = 0;
610 
611   if (mode & VERT_LTR) {
612     /* Mongol */
613 
614     logvis->cursor->col = logvis->cursor->char_index = vert_logvis->cursor_logical_row;
615   } else {
616     /* CJK */
617 
618     logvis->cursor->col = logvis->cursor->char_index =
619         vert_logvis->logical_model.num_rows - vert_logvis->cursor_logical_row - 1;
620   }
621 
622 #ifdef CURSOR_DEBUG
623   bl_debug_printf(BL_DEBUG_TAG " visual cursor [col %d index %d row %d]\n", logvis->cursor->col,
624                   logvis->cursor->char_index, logvis->cursor->row);
625 #endif
626 
627   logvis->is_visual = 1;
628 
629   return 1;
630 }
631 
cjk_vert_visual(vt_logical_visual_t * logvis)632 static int cjk_vert_visual(vt_logical_visual_t *logvis) {
633   return vert_visual_intern(logvis, VERT_RTL);
634 }
635 
mongol_vert_visual(vt_logical_visual_t * logvis)636 static int mongol_vert_visual(vt_logical_visual_t *logvis) {
637   return vert_visual_intern(logvis, VERT_LTR);
638 }
639 
vert_logical(vt_logical_visual_t * logvis)640 static int vert_logical(vt_logical_visual_t *logvis) {
641   vert_logical_visual_t *vert_logvis;
642 
643   if (!logvis->is_visual) {
644     return 0;
645   }
646 
647   vert_logvis = (vert_logical_visual_t*)logvis;
648 
649   *logvis->model = vert_logvis->logical_model;
650 
651   logvis->cursor->char_index = vert_logvis->cursor_logical_char_index;
652   logvis->cursor->col = vert_logvis->cursor_logical_col;
653   logvis->cursor->row = vert_logvis->cursor_logical_row;
654 
655 #ifdef CURSOR_DEBUG
656   bl_debug_printf(BL_DEBUG_TAG " logical cursor [col %d index %d row %d]\n", logvis->cursor->col,
657                   logvis->cursor->char_index, logvis->cursor->row);
658 #endif
659 
660   logvis->is_visual = 0;
661 
662   return 1;
663 }
664 
vert_visual_line(vt_logical_visual_t * logvis,vt_line_t * line)665 static void vert_visual_line(vt_logical_visual_t *logvis, vt_line_t *line) {}
666 
667 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_FRIBIDI) || defined(USE_IND) || \
668     defined(USE_OT_LAYOUT)
669 
670 /*
671  * Ctl logical <=> visual methods
672  */
673 
ctl_destroy(vt_logical_visual_t * logvis)674 static int ctl_destroy(vt_logical_visual_t *logvis) {
675   int row;
676 
677   if (logvis->model) {
678     for (row = 0; row < logvis->model->num_rows; row++) {
679       vt_line_unuse_ctl(&logvis->model->lines[row]);
680     }
681   }
682 
683   free(logvis);
684 
685   return 1;
686 }
687 
ctl_init(vt_logical_visual_t * logvis,vt_model_t * model,vt_cursor_t * cursor)688 static int ctl_init(vt_logical_visual_t *logvis, vt_model_t *model, vt_cursor_t *cursor) {
689   int row;
690 
691   if (logvis->model) {
692     for (row = 0; row < logvis->model->num_rows; row++) {
693       vt_line_unuse_ctl(&logvis->model->lines[row]);
694     }
695   }
696 
697   logvis->model = model;
698   logvis->cursor = cursor;
699 
700   return 1;
701 }
702 
ctl_logical_cols(vt_logical_visual_t * logvis)703 static u_int ctl_logical_cols(vt_logical_visual_t *logvis) { return logvis->model->num_cols; }
704 
ctl_logical_rows(vt_logical_visual_t * logvis)705 static u_int ctl_logical_rows(vt_logical_visual_t *logvis) { return logvis->model->num_rows; }
706 
ctl_render_line(vt_logical_visual_t * logvis,vt_line_t * line)707 static void ctl_render_line(vt_logical_visual_t *logvis, vt_line_t *line) {
708   if (!vt_line_is_empty(line) && vt_line_is_modified(line)) {
709     vt_line_ctl_render(line, ((ctl_logical_visual_t*)logvis)->bidi_mode,
710                        ((ctl_logical_visual_t*)logvis)->separators,
711                        ((ctl_logical_visual_t*)logvis)->term);
712   }
713 }
714 
ctl_render(vt_logical_visual_t * logvis)715 static void ctl_render(vt_logical_visual_t *logvis) {
716   if (!logvis->is_visual) {
717     int row;
718 
719     /*
720      * all lines(not only filled lines) should be rendered.
721      */
722     for (row = 0; row < logvis->model->num_rows; row++) {
723       ctl_render_line(logvis, vt_model_get_line(logvis->model, row));
724     }
725   }
726 }
727 
ctl_visual(vt_logical_visual_t * logvis)728 static int ctl_visual(vt_logical_visual_t *logvis) {
729   int row;
730 
731   if (logvis->is_visual) {
732     return 0;
733   }
734 
735 #ifdef CURSOR_DEBUG
736   bl_debug_printf(BL_DEBUG_TAG " [cursor(index)%d (col)%d (row)%d (ltrmeet)%d] ->",
737                   logvis->cursor->char_index, logvis->cursor->col, logvis->cursor->row,
738                   ((ctl_logical_visual_t*)logvis)->cursor_meet_pos_info);
739 #endif
740 
741   for (row = 0; row < logvis->model->num_rows; row++) {
742     if (!vt_line_ctl_visual(vt_model_get_line(logvis->model, row))) {
743 #ifdef __DEBUG
744       bl_debug_printf(BL_DEBUG_TAG " visualize row %d failed.\n", row);
745 #endif
746     }
747   }
748 
749   ((ctl_logical_visual_t*)logvis)->cursor_logical_char_index = logvis->cursor->char_index;
750   ((ctl_logical_visual_t*)logvis)->cursor_logical_col = logvis->cursor->col;
751 
752   logvis->cursor->char_index = vt_line_convert_logical_char_index_to_visual(
753       CURSOR_LINE(logvis), logvis->cursor->char_index,
754       &((ctl_logical_visual_t*)logvis)->cursor_meet_pos_info);
755   /*
756    * XXX
757    * col_in_char should not be plused to col, because the character pointed by
758    * vt_line_bidi_convert_logical_char_index_to_visual() is not the same as the
759    * one
760    * in logical order.
761    */
762   logvis->cursor->col =
763       vt_convert_char_index_to_col(CURSOR_LINE(logvis), logvis->cursor->char_index, 0) +
764       logvis->cursor->col_in_char;
765 
766 #ifdef CURSOR_DEBUG
767   bl_msg_printf("-> [cursor(index)%d (col)%d (row)%d (ltrmeet)%d]\n", logvis->cursor->char_index,
768                 logvis->cursor->col, logvis->cursor->row,
769                 ((bidi_logical_visual_t*)logvis)->cursor_meet_pos_info);
770 #endif
771 
772   logvis->is_visual = 1;
773 
774   return 1;
775 }
776 
ctl_logical(vt_logical_visual_t * logvis)777 static int ctl_logical(vt_logical_visual_t *logvis) {
778   int row;
779 
780   if (!logvis->is_visual) {
781     return 0;
782   }
783 
784 #ifdef CURSOR_DEBUG
785   bl_debug_printf(BL_DEBUG_TAG " [cursor(index)%d (col)%d (row)%d] ->", logvis->cursor->char_index,
786                   logvis->cursor->col, logvis->cursor->row);
787 #endif
788 
789   for (row = 0; row < logvis->model->num_rows; row++) {
790     vt_line_t *line;
791 
792     line = vt_model_get_line(logvis->model, row);
793 
794     if (!vt_line_ctl_logical(line)) {
795 #ifdef __DEBUG
796       bl_debug_printf(BL_DEBUG_TAG " logicalize row %d failed.\n", row);
797 #endif
798     }
799 
800 #if 1
801     /* XXX See vt_iscii_visual */
802     if (line->num_chars > logvis->model->num_cols) {
803       vt_str_final(line->chars + logvis->model->num_cols,
804                    line->num_chars - logvis->model->num_cols);
805       line->num_chars = logvis->model->num_cols;
806 
807       /*
808        * line->num_filled_chars is equal or less than line->num_chars
809        * because line is logicalized.
810        */
811     }
812 #endif
813   }
814 
815   if (((ctl_logical_visual_t*)logvis)->cursor_meet_pos_info & MSB32) {
816     /* cursor position is adjusted */
817     vt_line_t *line = vt_model_get_line(logvis->model, logvis->cursor->row);
818     int idx = vt_line_convert_visual_char_index_to_logical(line, logvis->cursor->char_index);
819     vt_line_set_modified(line, idx, idx);
820   }
821 
822   logvis->cursor->char_index = ((ctl_logical_visual_t*)logvis)->cursor_logical_char_index;
823   logvis->cursor->col = ((ctl_logical_visual_t*)logvis)->cursor_logical_col;
824 
825 #ifdef CURSOR_DEBUG
826   bl_msg_printf("-> [cursor(index)%d (col)%d (row)%d]\n", logvis->cursor->char_index,
827                 logvis->cursor->col, logvis->cursor->row);
828 #endif
829 
830   logvis->is_visual = 0;
831 
832   return 1;
833 }
834 
ctl_visual_line(vt_logical_visual_t * logvis,vt_line_t * line)835 static void ctl_visual_line(vt_logical_visual_t *logvis, vt_line_t *line) {
836   ctl_render_line(logvis, line);
837   vt_line_ctl_visual(line);
838 }
839 
840 #endif
841 
842 /* --- global functions --- */
843 
vt_logvis_container_new(void)844 vt_logical_visual_t *vt_logvis_container_new(void) {
845   container_logical_visual_t *container;
846 
847   if ((container = calloc(1, sizeof(container_logical_visual_t))) == NULL) {
848     return NULL;
849   }
850 
851   container->logvis.destroy = container_destroy;
852   container->logvis.init = container_init;
853   container->logvis.logical_cols = container_logical_cols;
854   container->logvis.logical_rows = container_logical_rows;
855   container->logvis.render = container_render;
856   container->logvis.visual = container_visual;
857   container->logvis.logical = container_logical;
858   container->logvis.visual_line = container_visual_line;
859 
860   container->logvis.is_reversible = 1;
861 
862   return (vt_logical_visual_t*)container;
863 }
864 
865 /*
866  * logvis_comb can coexist with another logvise, but must be added to
867  * logvis_container first of all.
868  * vert_logvis, ctl_logvis and iscii_logvis can't coexist with each other
869  * for now.
870  */
vt_logvis_container_add(vt_logical_visual_t * logvis,vt_logical_visual_t * child)871 int vt_logvis_container_add(vt_logical_visual_t *logvis, vt_logical_visual_t *child) {
872   void *p;
873   container_logical_visual_t *container;
874 
875   container = (container_logical_visual_t*)logvis;
876 
877   if ((p = realloc(container->children,
878                    (container->num_children + 1) * sizeof(vt_logical_visual_t))) == NULL) {
879     return 0;
880   }
881 
882   container->children = p;
883 
884   container->children[container->num_children++] = child;
885 
886   if (!child->is_reversible) {
887     container->logvis.is_reversible = 0;
888   }
889 
890   return 1;
891 }
892 
vt_logvis_comb_new(void)893 vt_logical_visual_t *vt_logvis_comb_new(void) {
894   comb_logical_visual_t *comb_logvis;
895 
896   if ((comb_logvis = calloc(1, sizeof(comb_logical_visual_t))) == NULL) {
897     return NULL;
898   }
899 
900   comb_logvis->logvis.destroy = comb_destroy;
901   comb_logvis->logvis.init = comb_init;
902   comb_logvis->logvis.logical_cols = comb_logical_cols;
903   comb_logvis->logvis.logical_rows = comb_logical_rows;
904   comb_logvis->logvis.render = comb_render;
905   comb_logvis->logvis.visual = comb_visual;
906   comb_logvis->logvis.logical = comb_logical;
907   comb_logvis->logvis.visual_line = comb_visual_line;
908 
909   comb_logvis->logvis.is_reversible = 1;
910 
911   return (vt_logical_visual_t*)comb_logvis;
912 }
913 
vt_logvis_vert_new(vt_vertical_mode_t vertical_mode)914 vt_logical_visual_t *vt_logvis_vert_new(vt_vertical_mode_t vertical_mode) {
915   vert_logical_visual_t *vert_logvis;
916 
917   if (vertical_mode != VERT_RTL && vertical_mode != VERT_LTR) {
918     return NULL;
919   }
920 
921   if ((vert_logvis = calloc(1, sizeof(vert_logical_visual_t))) == NULL) {
922     return NULL;
923   }
924 
925   vert_logvis->logvis.destroy = vert_destroy;
926   vert_logvis->logvis.init = vert_init;
927   vert_logvis->logvis.logical_cols = vert_logical_cols;
928   vert_logvis->logvis.logical_rows = vert_logical_rows;
929   vert_logvis->logvis.render = vert_render;
930   vert_logvis->logvis.logical = vert_logical;
931   vert_logvis->logvis.visual_line = vert_visual_line;
932 
933   if (vertical_mode == VERT_RTL) {
934     /*
935      * CJK type vertical view
936      */
937 
938     vert_logvis->logvis.visual = cjk_vert_visual;
939   } else /* if( vertical_mode == VERT_LTR) */
940   {
941     /*
942      * mongol type vertical view
943      */
944 
945     vert_logvis->logvis.visual = mongol_vert_visual;
946   }
947 
948   return (vt_logical_visual_t*)vert_logvis;
949 }
950 
vt_get_vertical_mode_by_name(const char * name)951 vt_vertical_mode_t vt_get_vertical_mode_by_name(const char *name) {
952   vt_vertical_mode_t mode;
953 
954   for (mode = 0; mode < VERT_MODE_MAX; mode++) {
955     if (strcmp(vertical_mode_name_table[mode], name) == 0) {
956       return mode;
957     }
958   }
959 
960   /* default value */
961   return 0;
962 }
963 
vt_get_vertical_mode_name(vt_vertical_mode_t mode)964 char *vt_get_vertical_mode_name(vt_vertical_mode_t mode) {
965   if (mode < 0 || VERT_MODE_MAX <= mode) {
966     /* default value */
967     mode = 0;
968   }
969 
970   return vertical_mode_name_table[mode];
971 }
972 
973 #if !defined(NO_DYNAMIC_LOAD_CTL) || defined(USE_FRIBIDI) || defined(USE_IND) || \
974     defined(USE_OT_LAYOUT)
975 
vt_logvis_ctl_new(vt_bidi_mode_t bidi_mode,const char * separators,void * term)976 vt_logical_visual_t *vt_logvis_ctl_new(vt_bidi_mode_t bidi_mode, const char *separators,
977                                        void *term) {
978   ctl_logical_visual_t *ctl_logvis;
979 
980 #ifndef USE_OT_LAYOUT
981 #ifndef NO_DYNAMIC_LOAD_CTL
982   if (!vt_load_ctl_bidi_func(VT_LINE_SET_USE_BIDI) &&
983       !vt_load_ctl_iscii_func(VT_LINE_SET_USE_ISCII)) {
984     return NULL;
985   }
986 #endif
987 #endif
988 
989   if ((ctl_logvis = calloc(1, sizeof(ctl_logical_visual_t))) == NULL) {
990     return NULL;
991   }
992 
993   ctl_logvis->bidi_mode = bidi_mode;
994   ctl_logvis->separators = separators;
995   ctl_logvis->term = term;
996 
997   ctl_logvis->logvis.destroy = ctl_destroy;
998   ctl_logvis->logvis.init = ctl_init;
999   ctl_logvis->logvis.logical_cols = ctl_logical_cols;
1000   ctl_logvis->logvis.logical_rows = ctl_logical_rows;
1001   ctl_logvis->logvis.render = ctl_render;
1002   ctl_logvis->logvis.visual = ctl_visual;
1003   ctl_logvis->logvis.logical = ctl_logical;
1004   ctl_logvis->logvis.visual_line = ctl_visual_line;
1005 
1006   ctl_logvis->logvis.is_reversible = 1;
1007 
1008   return (vt_logical_visual_t*)ctl_logvis;
1009 }
1010 
vt_logical_visual_cursor_is_rtl(vt_logical_visual_t * logvis)1011 int vt_logical_visual_cursor_is_rtl(vt_logical_visual_t *logvis) {
1012   if (logvis->init == ctl_init) {
1013     vt_line_t *line;
1014     int ret = 0;
1015 
1016     if ((line = vt_model_get_line(logvis->model, logvis->cursor->row))) {
1017       int lidx = ((ctl_logical_visual_t*)logvis)->cursor_logical_char_index;
1018       int vidx1 = vt_line_convert_logical_char_index_to_visual(line, lidx > 0 ? lidx - 1 : 0, NULL);
1019       int vidx2 = vt_line_convert_logical_char_index_to_visual(line, lidx, NULL);
1020       int vidx3 = vt_line_convert_logical_char_index_to_visual(line, lidx + 1, NULL);
1021 
1022       if (vt_line_is_rtl(line) ? (vidx1 >= vidx2 && vidx2 >= vidx3) :
1023                                  (vidx1 > vidx2 || vidx2 > vidx3)) {
1024         ret = 1;
1025       }
1026     }
1027 
1028     if (((ctl_logical_visual_t*)logvis)->cursor_meet_pos_info & MSB32) {
1029       ret = !ret;
1030     }
1031 
1032     return ret;
1033   } else if (logvis->init == container_init) {
1034     u_int count;
1035     container_logical_visual_t *container = (container_logical_visual_t*)logvis;
1036 
1037     for (count = 0; count < container->num_children; count++) {
1038       if (vt_logical_visual_cursor_is_rtl(container->children[count])) {
1039         return 1;
1040       }
1041     }
1042   }
1043 
1044   return 0;
1045 }
1046 
1047 #endif
1048