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