1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "ui_draw_str.h"
4 
5 #include <pobl/bl_mem.h> /* alloca */
6 #include <vt_drcs.h>
7 
8 #ifndef NO_IMAGE
9 #include "ui_picture.h"
10 
11 #define INLINEPIC_ID(glyph) (((glyph) >> PICTURE_POS_BITS) & (MAX_INLINE_PICTURES - 1))
12 #define INLINEPIC_POS(glyph) ((glyph) & ((1 << PICTURE_POS_BITS) - 1))
13 #endif
14 
15 #if 0
16 #define PERF_DEBUG
17 #endif
18 
19 #if 0
20 #define CLIP_LINE
21 #endif
22 
23 /* --- static functions --- */
24 
calculate_char_width(ui_font_t * font,u_int code,ef_charset_t cs,int is_awidth,vt_char_t * comb,u_int comb_size,int * draw_alone)25 static u_int calculate_char_width(ui_font_t *font, u_int code, ef_charset_t cs, int is_awidth,
26                                   vt_char_t *comb, u_int comb_size, int *draw_alone) {
27   u_int width;
28 
29   width = ui_calculate_char_width(font, code, cs, is_awidth, draw_alone);
30 
31   if (cs == ISO10646_UCS4_1_V) {
32     u_int w;
33 
34     for (; comb_size > 0; comb_size--, comb++) {
35 #ifdef DEBUG
36       if (vt_char_cs(comb) != ISO10646_UCS4_1_V) {
37         bl_debug_printf(BL_DEBUG_TAG
38                         " %x cs is unexpectedly"
39                         " combined to ISO10646_UCS4_1_V.\n");
40 
41         continue;
42       }
43 #endif
44 
45       if ((w = vt_char_get_advance(comb)) > width) {
46         width = w;
47       }
48     }
49   }
50 
51   return width;
52 }
53 
54 #ifndef USE_CONSOLE
draw_line(ui_window_t * window,ui_color_t * color,int is_vertical,int line_style,int x,int y,u_int width,u_int height,u_int ascent,int top_margin)55 static void draw_line(ui_window_t *window, ui_color_t *color, int is_vertical, int line_style,
56                       int x, int y, u_int width, u_int height, u_int ascent, int top_margin) {
57   u_int w;
58   u_int h;
59   int x2;
60   int y2;
61 
62   if (is_vertical) {
63     w = 1;
64     h = height;
65 
66     if (line_style == LS_UNDERLINE_DOUBLE) {
67       x2 = x + 2;
68       y2 = y;
69     } else {
70       w += ((ascent - top_margin) / 16);
71 
72       if (line_style == LS_CROSSED_OUT) {
73         x += ((width - 1) / 2);
74       } else if (line_style == LS_OVERLINE) {
75         x += (width - (width >= 2 ? 2 : 1));
76       }
77     }
78   } else {
79     w = width;
80     h = 1;
81 
82     if (line_style == LS_UNDERLINE_DOUBLE) {
83       x2 = x;
84 
85       if (ascent + 2 >= height) {
86         y2 = y + height - 1;
87         y = y2 - 2;
88       } else {
89         y += ascent;
90         y2 = y + 2;
91       }
92     } else {
93       h += ((ascent - top_margin) / 16);
94 
95       if (line_style == LS_CROSSED_OUT) {
96         y += ((height + 1) / 2);
97       } else if (line_style == LS_OVERLINE) {
98         /* do nothing */
99       } else {
100         y += ascent;
101       }
102     }
103   }
104 
105   ui_window_fill_with(window, color, x, y, w, h);
106 
107   if (line_style == LS_UNDERLINE_DOUBLE) {
108     ui_window_fill_with(window, color, x2, y2, w, h);
109   }
110 }
111 #endif
112 
113 #ifndef NO_IMAGE
draw_picture(ui_window_t * window,u_int32_t * glyphs,u_int num_glyphs,int dst_x,int dst_y,u_int ch_width,u_int line_height,ui_color_t * bg_xcolor)114 static int draw_picture(ui_window_t *window, u_int32_t *glyphs, u_int num_glyphs, int dst_x,
115                         int dst_y, u_int ch_width, u_int line_height, ui_color_t *bg_xcolor) {
116   u_int count;
117   ui_inline_picture_t *cur_pic;
118   u_int num_rows;
119   int src_x;
120   int src_y;
121   u_int src_width;
122   u_int src_height;
123   u_int dst_width;
124   int need_clear;
125   int is_end;
126 
127   cur_pic = NULL;
128   is_end = 0;
129 
130   for (count = 0; count < num_glyphs; count++) {
131     ui_inline_picture_t *pic;
132     int pos;
133     int x;
134     u_int w;
135 
136     if (!(pic = ui_get_inline_picture(INLINEPIC_ID(glyphs[count])))) {
137       dst_x += ch_width;
138 
139       continue;
140     }
141 
142     /*
143      * XXX
144      * pic->col_width isn't used in this function, so it can be
145      * removed in the future.
146      */
147 
148     if (pic != cur_pic) {
149       num_rows = (pic->height + pic->line_height - 1) / pic->line_height;
150     }
151 
152     pos = INLINEPIC_POS(glyphs[count]);
153     x = (pos / num_rows) * ch_width;
154 
155     if (x + ch_width > pic->width) {
156       w = pic->width > x ? pic->width - x : 0;
157     } else {
158       w = ch_width;
159     }
160 
161     if (count == 0) {
162       goto new_picture;
163     } else if (w > 0 && pic == cur_pic && src_x + src_width == x) {
164       if (!need_clear && w < ch_width) {
165         if (!bg_xcolor) {
166           ui_window_clear(window, dst_x + dst_width, dst_y, ch_width, line_height);
167         } else {
168           ui_window_fill_with(window, bg_xcolor, dst_x + dst_width, dst_y, ch_width, line_height);
169         }
170       }
171 
172       src_width += w;
173       dst_width += ch_width;
174 
175       if (count + 1 < num_glyphs) {
176         continue;
177       }
178 
179       is_end = 1;
180     }
181 
182     if (need_clear > 0) {
183       if (!bg_xcolor) {
184         ui_window_clear(window, dst_x, dst_y, dst_width, line_height);
185       } else {
186         ui_window_fill_with(window, bg_xcolor, dst_x, dst_y, dst_width, line_height);
187       }
188     }
189 
190     if (src_width > 0 && src_height > 0
191 #ifndef INLINE_PICTURE_MOVABLE_BETWEEN_DISPLAYS
192         && cur_pic->disp == window->disp
193 #endif
194         ) {
195 #ifdef __DEBUG
196       bl_debug_printf("Drawing picture at %d %d (pix %p mask %p x %d y %d w %d h %d)\n", dst_x,
197                       dst_y, cur_pic->pixmap, cur_pic->mask, src_x, src_y, src_width, src_height);
198 #endif
199 
200       ui_window_copy_area(window, cur_pic->pixmap, cur_pic->mask, src_x, src_y, src_width,
201                           src_height, dst_x, dst_y);
202     }
203 
204     if (is_end) {
205       return 1;
206     }
207 
208     dst_x += dst_width;
209 
210   new_picture:
211     src_y = (pos % num_rows) * line_height;
212     src_x = x;
213     dst_width = ch_width;
214     cur_pic = pic;
215     need_clear = 0;
216 
217     if (cur_pic->mask) {
218       need_clear = 1;
219     }
220 
221     if (src_y + line_height > pic->height) {
222       need_clear = 1;
223       src_height = pic->height > src_y ? pic->height - src_y : 0;
224     } else {
225       src_height = line_height;
226     }
227 
228     if (strstr(cur_pic->file_path, "mlterm/animx") && cur_pic->next_frame >= 0) {
229       /* Don't clear if cur_pic is 2nd or later GIF Animation frame. */
230       need_clear = -1;
231     }
232 
233     if ((src_width = w) < ch_width && !need_clear) {
234       if (!bg_xcolor) {
235         ui_window_clear(window, dst_x, dst_y, ch_width, line_height);
236       } else {
237         ui_window_fill_with(window, bg_xcolor, dst_x, dst_y, ch_width, line_height);
238       }
239     }
240   }
241 
242   if (need_clear > 0) {
243     if (!bg_xcolor) {
244       ui_window_clear(window, dst_x, dst_y, dst_width, line_height);
245     } else {
246       ui_window_fill_with(window, bg_xcolor, dst_x, dst_y, dst_width, line_height);
247     }
248   }
249 
250 #ifdef __DEBUG
251   bl_debug_printf("Drawing picture at %d %d (pix %p mask %p x %d y %d w %d h %d)\n", dst_x, dst_y,
252                   cur_pic->pixmap, cur_pic->mask, src_x, src_y, src_width, src_height);
253 #endif
254 
255   if (src_width > 0 && src_height > 0
256 #ifndef INLINE_PICTURE_MOVABLE_BETWEEN_DISPLAYS
257       && cur_pic->disp == window->disp
258 #endif
259       ) {
260     ui_window_copy_area(window, cur_pic->pixmap, cur_pic->mask, src_x, src_y, src_width, src_height,
261                         dst_x, dst_y);
262   }
263 
264   return 1;
265 }
266 #endif
267 
268 #ifndef USE_CONSOLE
get_drcs_bitmap(char * glyph,u_int width,int x,int y)269 static int get_drcs_bitmap(char *glyph, u_int width, int x, int y) {
270   return (glyph[(y / 6) * (width + 1) + x] - '?') & (1 << (y % 6));
271 }
272 
draw_drcs(ui_window_t * window,char ** glyphs,u_int num_glyphs,int x,int y,u_int ch_width,u_int line_height,ui_color_t * fg_xcolor,int size_attr)273 static int draw_drcs(ui_window_t *window, char **glyphs, u_int num_glyphs, int x, int y,
274                      u_int ch_width, u_int line_height, ui_color_t *fg_xcolor, int size_attr) {
275   int y_off = 0;
276 
277   if (size_attr >= DOUBLE_HEIGHT_TOP) {
278     if (size_attr == DOUBLE_HEIGHT_BOTTOM) {
279       y_off = line_height;
280     }
281 
282     line_height *= 2;
283   }
284 
285   for (; y_off < line_height; y_off++) {
286     u_int w;
287     int x_off_sum; /* x_off for all glyphs */
288     int x_off;     /* x_off for each glyph */
289     char *glyph;
290     u_int glyph_width;
291     u_int glyph_height;
292     u_int smpl_width;
293     u_int smpl_height;
294 
295     w = 0;
296 
297     for (x_off_sum = 0; x_off_sum < ch_width * num_glyphs; x_off_sum++) {
298       int left_x;
299       int top_y;
300       int hit;
301       int n_smpl;
302       int smpl_x;
303       int smpl_y;
304 
305       if ((x_off = x_off_sum % ch_width) == 0) {
306         glyph = glyphs[x_off_sum / ch_width];
307 
308         glyph_width = glyph[0];
309         glyph_height = glyph[1];
310         glyph += 2;
311 
312         if ((smpl_width = glyph_width / ch_width + 1) >= 3) {
313           smpl_width = 2;
314         }
315 
316         if ((smpl_height = glyph_height / line_height + 1) >= 3) {
317           smpl_height = 2;
318         }
319       }
320 
321       left_x = (x_off * glyph_width * 10 / ch_width + 5) / 10 - smpl_width / 2;
322       top_y = (y_off * glyph_height * 10 / line_height + 5) / 10 - smpl_height / 2;
323       /*
324        * If top_y < 0 or top_y >= glyph_height, w is always 0
325        * regardless of content of glyph.
326        */
327       if (top_y < 0) {
328         top_y = 0;
329       } else if (top_y >= glyph_height) {
330         top_y = glyph_height - 1;
331       }
332 
333 #if 0
334       bl_debug_printf(BL_DEBUG_TAG "x_off %d: center x %f -> %d\n", x_off,
335                       (double)(x_off * glyph_width) / (double)ch_width, left_x + smpl_width / 2);
336       bl_debug_printf(BL_DEBUG_TAG "y_off %d: center y %f -> %d\n", y_off,
337                       (double)(y_off * glyph_height) / (double)line_height,
338                       top_y + smpl_height / 2);
339 #endif
340 
341       hit = n_smpl = 0;
342 
343       for (smpl_y = 0; smpl_y < smpl_height; smpl_y++) {
344         for (smpl_x = 0; smpl_x < smpl_width; smpl_x++) {
345           if (0 <= left_x + smpl_x && left_x + smpl_x < glyph_width && 0 <= top_y + smpl_y &&
346               top_y + smpl_y < glyph_height) {
347             if (get_drcs_bitmap(glyph, glyph_width, left_x + smpl_x, top_y + smpl_y)) {
348               hit++;
349             }
350             n_smpl++;
351           }
352         }
353       }
354 
355       if (n_smpl <= hit * 2) {
356         w++;
357 
358         if (x_off_sum + 1 == ch_width * num_glyphs) {
359           /* for x_off - w */
360           x_off_sum++;
361         } else {
362           continue;
363         }
364       } else if (w == 0) {
365         continue;
366       }
367 
368       if (size_attr >= DOUBLE_HEIGHT_TOP) {
369         int exp_y;
370 
371         if (size_attr == DOUBLE_HEIGHT_TOP) {
372           if (y_off >= line_height / 2) {
373             return 1;
374           }
375 
376           exp_y = y + y_off;
377         } else {
378           exp_y = y + y_off - line_height / 2;
379         }
380 
381         ui_window_fill_with(window, fg_xcolor, x + x_off_sum - w, exp_y, w, 1);
382       } else {
383         ui_window_fill_with(window, fg_xcolor, x + x_off_sum - w, y + y_off, w, 1);
384       }
385 
386       w = 0;
387     }
388   }
389 
390   return 1;
391 }
392 #endif
393 
get_state(ef_charset_t ch_cs,u_int32_t ch_code,vt_char_t * comb_chars,u_int32_t * pic_glyph,char ** drcs_glyph,int * draw_alone)394 static int get_state(ef_charset_t ch_cs, u_int32_t ch_code, vt_char_t *comb_chars,
395                      u_int32_t *pic_glyph, char **drcs_glyph, int *draw_alone) {
396 #ifndef NO_IMAGE
397   if (comb_chars && vt_char_cs(comb_chars) == PICTURE_CHARSET) {
398     *draw_alone = 0; /* forcibly set 0 regardless of uifont. */
399     *pic_glyph = vt_char_code(comb_chars) | (vt_char_picture_id(comb_chars) << PICTURE_POS_BITS);
400     *drcs_glyph = NULL;
401 
402     return 4;
403   } else
404 #endif
405   {
406     *pic_glyph = 0;
407 
408     if ((*drcs_glyph = vt_drcs_get_glyph(ch_cs, ch_code))) {
409       *draw_alone = 0; /* forcibly set 0 regardless of uifont. */
410 
411       return 3;
412     } else {
413       if (comb_chars) {
414         *draw_alone = 1;
415       }
416 
417       if (ch_cs == DEC_SPECIAL) {
418         return 1;
419       } else {
420         return 0;
421       }
422     }
423   }
424 }
425 
426 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT) || defined(USE_TYPE_CAIRO)
427 
fc_draw_combining_chars(ui_window_t * window,ui_font_manager_t * font_man,ui_color_t * xcolor,vt_char_t * chars,u_int size,int x,int y)428 static void fc_draw_combining_chars(ui_window_t *window, ui_font_manager_t *font_man,
429                                     ui_color_t *xcolor, /* fg color */
430                                     vt_char_t *chars, u_int size, int x, int y) {
431   u_int count;
432   u_int32_t ch_code;
433   ef_charset_t ch_cs;
434   ui_font_t *uifont;
435 
436   for (count = 0; count < size; count++) {
437     if (vt_char_is_zerowidth(&chars[count])) {
438       continue;
439     }
440 
441     ch_code = vt_char_code(&chars[count]);
442     ch_cs = vt_char_cs(&chars[count]);
443     uifont = ui_get_font(font_man, vt_char_font(&chars[count]));
444 
445     if (ch_cs == DEC_SPECIAL) {
446       u_char c;
447 
448       c = ch_code;
449       ui_window_draw_decsp_string(window, uifont, xcolor, x, y, &c, 1);
450     }
451     /* ISCII characters never have combined ones. */
452     else if (ch_cs == US_ASCII || ch_cs == ISO8859_1_R /* || IS_ISCII(ch_cs) */) {
453       u_char c;
454 
455       c = ch_code;
456       ui_window_ft_draw_string8(window, uifont, xcolor, x, y, &c, 1);
457     } else {
458       /* FcChar32 */ u_int32_t ucs4;
459 
460       if (ch_cs == ISO10646_UCS4_1_V) {
461         ui_window_ft_draw_string32(window, uifont, xcolor, x + vt_char_get_xoffset(&chars[count]),
462                                    y - vt_char_get_yoffset(&chars[count]), &ch_code, 1);
463       } else if ((ucs4 = ui_convert_to_xft_ucs4(ch_code, ch_cs))) {
464         ui_window_ft_draw_string32(window, uifont, xcolor, x, y, &ucs4, 1);
465       }
466     }
467   }
468 }
469 
fc_draw_str(ui_window_t * window,ui_font_manager_t * font_man,ui_color_manager_t * color_man,u_int * updated_width,vt_char_t * chars,u_int num_chars,int x,int y,u_int height,u_int ascent,int top_margin,int hide_underline,int underline_offset)470 static int fc_draw_str(ui_window_t *window, ui_font_manager_t *font_man,
471                        ui_color_manager_t *color_man, u_int *updated_width, vt_char_t *chars,
472                        u_int num_chars, int x, int y, u_int height, u_int ascent,
473                        int top_margin, int hide_underline, int underline_offset) {
474   int count;
475   int start_draw;
476   int end_of_str;
477   u_int current_width;
478   /* FcChar8 */ u_int8_t *str8;
479   /* FcChar32 */ u_int32_t *str32;
480   u_int str_len;
481 
482   u_int32_t ch_code;
483   u_int ch_width;
484   ef_charset_t ch_cs;
485 
486   int state;
487   ui_font_t *uifont;
488   vt_font_t font;
489   vt_color_t fg_color;
490   vt_color_t bg_color;
491   int line_style;
492   vt_char_t *comb_chars;
493   u_int comb_size;
494   int draw_alone;
495   u_int32_t pic_glyph;
496   u_int32_t *pic_glyphs;
497   char *drcs_glyph;
498   char **drcs_glyphs;
499 
500   int next_state;
501   ui_font_t *next_uifont;
502   vt_font_t next_font;
503   vt_color_t next_fg_color;
504   vt_color_t next_bg_color;
505   int next_line_style;
506   vt_char_t *next_comb_chars;
507   u_int next_comb_size;
508   u_int next_ch_width;
509   int next_draw_alone;
510 
511 #ifdef PERF_DEBUG
512   int draw_count = 0;
513 #endif
514 
515   if (num_chars == 0) {
516 #ifdef __DEBUG
517     bl_debug_printf(BL_DEBUG_TAG " input chars length is 0(ui_window_draw_str).\n");
518 #endif
519 
520     return 1;
521   }
522 
523   start_draw = 0;
524   end_of_str = 0;
525 
526   count = 0;
527   while (vt_char_is_zerowidth(&chars[count])) {
528     if (++count >= num_chars) {
529       return 1;
530     }
531   }
532 
533   ch_code = vt_char_code(&chars[count]);
534   uifont = ui_get_font(font_man, (font = vt_char_font(&chars[count])));
535   ch_cs = FONT_CS(font);
536   comb_chars = vt_get_combining_chars(&chars[count], &comb_size);
537 
538   ch_width = calculate_char_width(uifont, ch_code, ch_cs, vt_char_is_awidth(&chars[count]),
539                                   comb_chars, comb_size, &draw_alone);
540 
541   if ((current_width = x + ch_width) > window->width || y + height > window->height) {
542 #ifdef DEBUG
543     bl_warn_printf(BL_DEBUG_TAG " draw string outside screen. (x %d w %d y %d h %d)\n", x, ch_width,
544                    y, height);
545 #endif
546 
547     return 0;
548   }
549 
550   if ((state = get_state(ch_cs, ch_code, comb_chars, &pic_glyph, &drcs_glyph, &draw_alone)) == 0 &&
551       ch_cs != US_ASCII && ch_cs != ISO8859_1_R && !IS_ISCII(ch_cs)) {
552     state = 2;
553   }
554 
555   fg_color = vt_char_fg_color(&chars[count]);
556   bg_color = vt_char_bg_color(&chars[count]);
557 
558   line_style = vt_char_line_style(&chars[count]);
559 
560   if (!(str8 = str32 = pic_glyphs = drcs_glyphs =
561             alloca(BL_MAX(sizeof(*str8),
562                           BL_MAX(sizeof(*str32),
563                                  BL_MAX(sizeof(*pic_glyphs), sizeof(*drcs_glyphs)))) *
564                    num_chars))) {
565     return 0;
566   }
567 
568   str_len = 0;
569 
570   while (1) {
571     if (state <= 1) {
572       str8[str_len++] = ch_code;
573     } else if (state >= 3) {
574       if (drcs_glyph) {
575         drcs_glyphs[str_len++] = drcs_glyph;
576       } else /* if(pic_glyph) */ {
577         pic_glyphs[str_len++] = pic_glyph;
578       }
579     } else /* if(state == 2) */ {
580       u_int32_t ucs4;
581 
582       /* state == 2 means that ch_cs is not US_ASCII, ISO8859_1_R and IS_ISCII */
583       if (!(ucs4 = ui_convert_to_xft_ucs4(ch_code, ch_cs))) {
584 #ifdef DEBUG
585         bl_warn_printf(BL_DEBUG_TAG " strange character 0x%x, ignored.\n", ch_code);
586 #endif
587       } else {
588         str32[str_len++] = ucs4;
589       }
590     }
591 
592     /*
593      * next character.
594      */
595 
596     do {
597       if (++count >= num_chars) {
598         start_draw = 1;
599         end_of_str = 1;
600 
601         break;
602       }
603     } while (vt_char_is_zerowidth(&chars[count]));
604 
605     if (!end_of_str) {
606       ch_code = vt_char_code(&chars[count]);
607       next_uifont = ui_get_font(font_man, (next_font = vt_char_font(&chars[count])));
608       ch_cs = FONT_CS(next_font);
609       next_fg_color = vt_char_fg_color(&chars[count]);
610       next_bg_color = vt_char_bg_color(&chars[count]);
611       next_line_style = vt_char_line_style(&chars[count]);
612       next_comb_chars = vt_get_combining_chars(&chars[count], &next_comb_size);
613       next_ch_width = calculate_char_width(next_uifont, ch_code, ch_cs,
614                                            vt_char_is_awidth(&chars[count]), next_comb_chars,
615                                            next_comb_size, &next_draw_alone);
616 
617       if ((next_state = get_state(ch_cs, ch_code, next_comb_chars, &pic_glyph, &drcs_glyph,
618                                   &next_draw_alone)) == 0 &&
619           ch_cs != US_ASCII && ch_cs != ISO8859_1_R && !IS_ISCII(ch_cs)) {
620         next_state = 2;
621       }
622 
623       if (current_width + next_ch_width > window->width) {
624         start_draw = 1;
625         end_of_str = 1;
626       }
627       /*
628        * !! Notice !!
629        * next_uifont != uifont doesn't necessarily detect change of 'state'
630        * (for example, same Unicode font is used for both US_ASCII and
631        * other half-width unicode characters) and 'bold'(ui_get_font()
632        * might substitute normal fonts for bold ones), 'next_state' and
633        * 'font & FONT_BOLD' is necessary.
634        */
635       else if (next_uifont != uifont || next_fg_color != fg_color || next_bg_color != bg_color ||
636                next_line_style != line_style ||
637                /* If line_style > 0, line is drawn one by one in vertical mode. */
638                (line_style && uifont->is_vertical) || state != next_state ||
639                draw_alone || next_draw_alone ||
640                /* FONT_BOLD flag is not the same. */
641                ((font ^ next_font) & FONT_BOLD)) {
642         start_draw = 1;
643       } else {
644         start_draw = 0;
645       }
646     }
647 
648     if (start_draw) {
649       /*
650        * status is changed.
651        */
652 
653       ui_color_t *fg_xcolor;
654       ui_color_t *bg_xcolor;
655 
656 #ifdef PERF_DEBUG
657       draw_count++;
658 #endif
659 
660       bg_xcolor = ui_get_xcolor(color_man, bg_color);
661 
662 #ifndef NO_IMAGE
663       if (state == 4) {
664         draw_picture(window, pic_glyphs, str_len, x, y, ch_width, height,
665                      bg_color == VT_BG_COLOR ? NULL : bg_xcolor);
666 
667         goto end_draw;
668       }
669 #endif
670 
671       fg_xcolor = ui_get_xcolor(color_man, fg_color);
672 
673       /*
674        * clearing background
675        */
676       if (bg_color == VT_BG_COLOR) {
677         if (updated_width) {
678           ui_window_clear(window, x, y, current_width - x, height);
679         }
680       } else {
681         ui_window_fill_with(window, bg_xcolor, x, y, current_width - x, height);
682       }
683 
684       /*
685        * drawing string
686        */
687       if (fg_color == bg_color) {
688         /* don't draw it */
689       } else if (state == 0) {
690         ui_window_ft_draw_string8(window, uifont, fg_xcolor, x, y + ascent, str8, str_len);
691       } else if (state == 1) {
692         ui_window_draw_decsp_string(window, uifont, fg_xcolor, x, y + ascent, str8, str_len);
693       } else if (state == 2) {
694         ui_window_ft_draw_string32(window, uifont, fg_xcolor, x, y + ascent, str32, str_len);
695       } else /* if (state == 3) */ {
696         draw_drcs(window, drcs_glyphs, str_len, x, y, ch_width, height, fg_xcolor,
697                   font_man->size_attr);
698       }
699 
700       if (comb_chars) {
701         /*
702          * 'current_width' is for some thai fonts which
703          * automatically draw combining chars.
704          * e.g.)
705          *  -thai-fixed-medium-r-normal--14-100-100-100-m-70-tis620.2529-1
706          *  (distributed by ZzzThai
707          *   http://zzzthai.fedu.uec.ac.jp/ZzzThai/)
708          *  win32 unicode font.
709          */
710 #if 0
711         fc_draw_combining_chars(window, font_man, fg_xcolor, comb_chars, comb_size,
712                                 current_width, y + ascent);
713 #else
714         fc_draw_combining_chars(window, font_man, fg_xcolor, comb_chars, comb_size,
715                                 current_width - ch_width, y + ascent);
716 #endif
717       }
718 
719       if (line_style) {
720         if ((line_style & LS_UNDERLINE) && !hide_underline) {
721           draw_line(window, fg_xcolor, uifont->is_vertical,
722                     line_style & LS_UNDERLINE,
723                     x, y, current_width - x, height, ascent + underline_offset, top_margin);
724         }
725 
726         if (line_style & LS_CROSSED_OUT) {
727           draw_line(window, fg_xcolor, uifont->is_vertical,
728                     LS_CROSSED_OUT, x, y, current_width - x, height, ascent, top_margin);
729         }
730 
731         if (line_style & LS_OVERLINE) {
732           draw_line(window, fg_xcolor, uifont->is_vertical,
733                     LS_OVERLINE, x, y, current_width - x, height, ascent, top_margin);
734         }
735       }
736 
737     end_draw:
738       start_draw = 0;
739 
740       x = current_width;
741       str_len = 0;
742     }
743 
744     if (end_of_str) {
745       break;
746     }
747 
748     line_style = next_line_style;
749     uifont = next_uifont;
750     font = next_font;
751     fg_color = next_fg_color;
752     bg_color = next_bg_color;
753     state = next_state;
754     draw_alone = next_draw_alone;
755     comb_chars = next_comb_chars;
756     comb_size = next_comb_size;
757     current_width += (ch_width = next_ch_width);
758   }
759 
760   if (updated_width != NULL) {
761     *updated_width = current_width;
762   }
763 
764 #ifdef PERF_DEBUG
765   bl_debug_printf(" drawing %d times in a line.\n", draw_count);
766 #endif
767 
768   return 1;
769 }
770 
771 #endif
772 
773 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
774 
775 #ifndef USE_CONSOLE
xcore_draw_combining_chars(ui_window_t * window,ui_font_manager_t * font_man,ui_color_t * xcolor,vt_char_t * chars,u_int size,int x,int y)776 static int xcore_draw_combining_chars(ui_window_t *window, ui_font_manager_t *font_man,
777                                       ui_color_t *xcolor, /* fg color */
778                                       vt_char_t *chars, u_int size, int x, int y) {
779   u_int count;
780   u_int32_t ch_code;
781   ef_charset_t ch_cs;
782   ui_font_t *uifont;
783   int x_off;
784   int y_off;
785 
786   for (count = 0; count < size; count++) {
787     if (vt_char_is_zerowidth(&chars[count])) {
788       continue;
789     }
790 
791     ch_code = vt_char_code(&chars[count]);
792     ch_cs = vt_char_cs(&chars[count]);
793     uifont = ui_get_font(font_man, vt_char_font(&chars[count]));
794 
795     if (ch_cs == DEC_SPECIAL) {
796       u_char c;
797 
798       c = ch_code;
799       ui_window_draw_decsp_string(window, uifont, xcolor, x, y, &c, 1);
800     } else {
801       if (ch_cs == ISO10646_UCS4_1_V) {
802         x_off = vt_char_get_xoffset(&chars[count]);
803         y_off = vt_char_get_yoffset(&chars[count]);
804       } else {
805         x_off = y_off = 0;
806       }
807 
808       if (ch_code < 0x100) {
809         u_char c;
810 
811         c = ch_code;
812         ui_window_draw_string(window, uifont, xcolor, x + x_off, y - y_off, &c, 1);
813       } else {
814         /* UCS4 */
815 
816         /* [2] is for surroage pair. */
817         XChar2b xch[2];
818         u_int len;
819 
820         if (IS_ISO10646_UCS4(ch_cs)) {
821           if ((len = ui_convert_ucs4_to_utf16(xch, ch_code) / 2) == 0) {
822             continue;
823           }
824         } else {
825           xch[0].byte1 = (ch_code >> 8) & 0xff;
826           xch[0].byte2 = ch_code & 0xff;
827           len = 1;
828         }
829 
830         ui_window_draw_string16(window, uifont, xcolor, x + x_off, y - y_off, xch, len);
831       }
832     }
833   }
834 
835   return 1;
836 }
837 #endif
838 
xcore_draw_str(ui_window_t * window,ui_font_manager_t * font_man,ui_color_manager_t * color_man,u_int * updated_width,vt_char_t * chars,u_int num_chars,int x,int y,u_int height,u_int ascent,int top_margin,int hide_underline,int underline_offset)839 static int xcore_draw_str(ui_window_t *window, ui_font_manager_t *font_man,
840                           ui_color_manager_t *color_man, u_int *updated_width, vt_char_t *chars,
841                           u_int num_chars, int x, int y, u_int height, u_int ascent,
842                           int top_margin, int hide_underline, int underline_offset) {
843   int count;
844   int start_draw;
845   int end_of_str;
846   u_int current_width;
847   u_char *str;
848   XChar2b *str2b;
849   u_int str_len;
850   u_int32_t ch_code;
851   ef_charset_t ch_cs;
852 
853   int state; /* 0(8bit),1(decsp),2(16bit) */
854   vt_char_t *comb_chars;
855   u_int comb_size;
856   u_int ch_width;
857   ui_font_t *uifont;
858   vt_font_t font;
859   vt_color_t fg_color;
860   vt_color_t bg_color;
861   int line_style;
862   int draw_alone;
863   u_int32_t pic_glyph;
864   u_int32_t *pic_glyphs;
865   char *drcs_glyph;
866   char **drcs_glyphs;
867 
868   int next_state;
869   vt_char_t *next_comb_chars;
870   u_int next_comb_size;
871   u_int next_ch_width;
872   ui_font_t *next_uifont;
873   vt_font_t next_font;
874   vt_color_t next_fg_color;
875   vt_color_t next_bg_color;
876   int next_line_style;
877   int next_draw_alone;
878 #ifdef PERF_DEBUG
879   int draw_count = 0;
880 #endif
881 
882   if (num_chars == 0) {
883 #ifdef DEBUG
884     bl_debug_printf(BL_DEBUG_TAG " input chars length is 0(ui_window_draw_str).\n");
885 #endif
886 
887     return 1;
888   }
889 
890   count = 0;
891   while (vt_char_is_zerowidth(&chars[count])) {
892     if (++count >= num_chars) {
893       return 1;
894     }
895   }
896 
897   start_draw = 0;
898   end_of_str = 0;
899 
900   ch_code = vt_char_code(&chars[count]);
901   uifont = ui_get_font(font_man, (font = vt_char_font(&chars[count])));
902   ch_cs = FONT_CS(font);
903   comb_chars = vt_get_combining_chars(&chars[count], &comb_size);
904 
905   ch_width = calculate_char_width(uifont, ch_code, ch_cs, vt_char_is_awidth(&chars[count]),
906                                   comb_chars, comb_size, &draw_alone);
907 
908   if ((current_width = x + ch_width) > window->width || y + height > window->height) {
909 #ifdef DEBUG
910     bl_warn_printf(BL_DEBUG_TAG " draw string outside screen. (x %d w %d y %d h %d)\n", x, ch_width,
911                    y, height);
912 #endif
913 
914     return 0;
915   }
916 
917   if ((state = get_state(ch_cs, ch_code, comb_chars, &pic_glyph, &drcs_glyph, &draw_alone)) == 0 &&
918       ch_code >= 0x100) {
919     state = 2;
920   }
921 
922   fg_color = vt_char_fg_color(&chars[count]);
923   bg_color = vt_char_bg_color(&chars[count]);
924   line_style = vt_char_line_style(&chars[count]);
925 
926   if (!(str2b = str = pic_glyphs = drcs_glyphs =
927             /* '* 2' is for UTF16 surrogate pair. */
928         alloca(BL_MAX(sizeof(*str2b) * 2,
929                       BL_MAX(sizeof(*str), BL_MAX(sizeof(*pic_glyphs), sizeof(*drcs_glyphs)))) *
930                num_chars))) {
931     return 0;
932   }
933 
934   str_len = 0;
935 
936   while (1) {
937     if (state <= 1) {
938       str[str_len++] = ch_code;
939     } else if (state >= 3) {
940       if (pic_glyph) {
941         pic_glyphs[str_len++] = pic_glyph;
942       } else /* if (drcs_glyph) */ {
943         drcs_glyphs[str_len++] = drcs_glyph;
944       }
945     } else if (!IS_ISO10646_UCS4(ch_cs)) {
946       str2b[str_len].byte1 = (ch_code >> 8) & 0xff;
947       str2b[str_len].byte2 = ch_code & 0xff;
948       str_len++;
949     } else {
950       /* UCS4 */
951 
952       str_len += (ui_convert_ucs4_to_utf16(str2b + str_len, ch_code) / 2);
953     }
954 
955     /*
956      * next character.
957      */
958 
959     do {
960       if (++count >= num_chars) {
961         start_draw = 1;
962         end_of_str = 1;
963 
964         break;
965       }
966     } while (vt_char_is_zerowidth(&chars[count]));
967 
968     if (!end_of_str) {
969       ch_code = vt_char_code(&chars[count]);
970       next_uifont = ui_get_font(font_man, (next_font = vt_char_font(&chars[count])));
971       ch_cs = FONT_CS(next_font);
972       next_fg_color = vt_char_fg_color(&chars[count]);
973       next_bg_color = vt_char_bg_color(&chars[count]);
974       next_line_style = vt_char_line_style(&chars[count]);
975       next_comb_chars = vt_get_combining_chars(&chars[count], &next_comb_size);
976       next_ch_width = calculate_char_width(next_uifont, ch_code, ch_cs,
977                                            vt_char_is_awidth(&chars[count]), next_comb_chars,
978                                            next_comb_size, &next_draw_alone);
979 
980       if ((next_state = get_state(ch_cs, ch_code, next_comb_chars, &pic_glyph, &drcs_glyph,
981                                   &next_draw_alone)) == 0 &&
982           ch_code >= 0x100) {
983         next_state = 2;
984       }
985 
986       if (current_width + next_ch_width > window->width) {
987         start_draw = 1;
988         end_of_str = 1;
989       }
990       /*
991        * !! Notice !!
992        * next_uifont != uifont doesn't necessarily detect change of 'state'
993        * (for example, same Unicode font is used for both US_ASCII and
994        * other half-width unicode characters) and 'bold'(ui_get_font()
995        * might substitute normal fonts for bold ones), 'next_state' and
996        * 'font & FONT_BOLD' is necessary.
997        */
998       else if (next_uifont != uifont || next_fg_color != fg_color || next_bg_color != bg_color ||
999                next_line_style != line_style ||
1000                /* If line_style > 0, line is drawn one by one in vertical mode. */
1001                (line_style && uifont->is_vertical) || next_state != state ||
1002                draw_alone || next_draw_alone ||
1003                /* FONT_BOLD flag is not the same */
1004                ((font ^ next_font) & FONT_BOLD)) {
1005         start_draw = 1;
1006       } else {
1007         start_draw = 0;
1008       }
1009     }
1010 
1011     if (start_draw) {
1012       /*
1013        * status is changed.
1014        */
1015 
1016       ui_color_t *fg_xcolor;
1017       ui_color_t *bg_xcolor;
1018 
1019 #ifdef PERF_DEBUG
1020       draw_count++;
1021 #endif
1022 
1023 #ifdef DRAW_SCREEN_IN_PIXELS
1024       if (ui_window_has_wall_picture(window) && bg_color == VT_BG_COLOR) {
1025         bg_xcolor = NULL;
1026       } else
1027 #endif
1028       {
1029         bg_xcolor = ui_get_xcolor(color_man, bg_color);
1030       }
1031 
1032 #ifndef NO_IMAGE
1033       if (state == 4) {
1034         draw_picture(window, pic_glyphs, str_len, x, y, ch_width, height,
1035                      bg_color == VT_BG_COLOR ? NULL : bg_xcolor);
1036 
1037         goto end_draw;
1038       }
1039 #endif
1040 
1041       fg_xcolor = ui_get_xcolor(color_man, fg_color);
1042 
1043 #ifdef USE_CONSOLE
1044       /* XXX DRCS (state == 3) is ignored */
1045       if (state < 3) {
1046         u_int comb_count;
1047 
1048         for (comb_count = 0; comb_count < comb_size; comb_count++) {
1049           u_int comb_code;
1050 
1051           comb_code = vt_char_code(&comb_chars[comb_count]);
1052 
1053           if (state <= 1) {
1054             str[str_len++] = comb_code;
1055           } else if (!IS_ISO10646_UCS4(ch_cs)) {
1056             str2b[str_len].byte1 = (comb_code >> 8) & 0xff;
1057             str2b[str_len].byte2 = comb_code & 0xff;
1058             str_len++;
1059           } else {
1060             /* UCS4 */
1061             str_len += (ui_convert_ucs4_to_utf16(str2b + str_len, comb_code) / 2);
1062           }
1063         }
1064 
1065         /* XXX Wall picture is overwritten by bg_xcolor. */
1066 
1067         if (state == 2) {
1068           ui_window_console_draw_string16(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str2b,
1069                                           str_len, line_style);
1070         } else if (state == 1) {
1071           ui_window_console_draw_decsp_string(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent,
1072                                               str, str_len, line_style);
1073         } else /* if (state == 0) */ {
1074           ui_window_console_draw_string(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str,
1075                                         str_len, line_style);
1076         }
1077       }
1078 #else /* !USE_CONSOLE */
1079 #ifdef USE_SDL2
1080       if (uifont->height != height || state == 3 ||
1081           (uifont->is_proportional && ui_window_has_wall_picture(window))) {
1082         if (bg_color == VT_BG_COLOR) {
1083           if (updated_width) {
1084             ui_window_clear(window, x, y, current_width - x, height);
1085           }
1086         } else {
1087           ui_window_fill_with(window, bg_xcolor, x, y, current_width - x, height);
1088         }
1089       }
1090 
1091       if (state == 2) {
1092         ui_window_draw_image_string16(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str2b,
1093                                       str_len);
1094       } else if (state == 1) {
1095         ui_window_draw_decsp_image_string(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str,
1096                                           str_len);
1097       } else if(state == 0) {
1098         ui_window_draw_image_string(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str,
1099                                     str_len);
1100       } else /* if (state == 3) */ {
1101         draw_drcs(window, drcs_glyphs, str_len, x, y, ch_width, height, fg_xcolor,
1102                   font_man->size_attr);
1103       }
1104 #else /* !USE_SDL2 */
1105 #ifndef NO_DRAW_IMAGE_STRING
1106       if (uifont->height != height || state == 3
1107 #ifdef DRAW_SCREEN_IN_PIXELS
1108 #ifdef USE_FREETYPE
1109           /*
1110            * ISCII or ISO10646_UCS4_1_V
1111            * (see #ifdef USE_FREETYPE #endif in draw_string() in ui_window.c)
1112            */
1113           || (uifont->is_proportional && ui_window_has_wall_picture(window))
1114 #endif
1115           /* || draw_alone */       /* draw_alone is always false on framebuffer. */
1116 #else /* DRAW_SCREEN_IN_PIXELS */
1117           || (ui_window_has_wall_picture(window) && bg_color == VT_BG_COLOR) || draw_alone
1118 #endif /* DRAW_SCREEN_IN_PIXELS */
1119          )
1120 #endif /* NO_DRAW_IMAGE_STRING */
1121       {
1122         if (bg_color == VT_BG_COLOR) {
1123           if (updated_width) {
1124             ui_window_clear(window, x, y, current_width - x, height);
1125           }
1126         } else {
1127           ui_window_fill_with(window, bg_xcolor, x, y, current_width - x, height);
1128         }
1129 
1130         if (fg_color == bg_color) {
1131           /* don't draw it */
1132         } else if (state == 2) {
1133           ui_window_draw_string16(window, uifont, fg_xcolor, x, y + ascent, str2b, str_len);
1134         } else if (state == 1) {
1135           ui_window_draw_decsp_string(window, uifont, fg_xcolor, x, y + ascent, str, str_len);
1136         } else if (state == 0) {
1137           ui_window_draw_string(window, uifont, fg_xcolor, x, y + ascent, str, str_len);
1138         } else /* if (state == 3) */ {
1139           draw_drcs(window, drcs_glyphs, str_len, x, y, ch_width, height, fg_xcolor,
1140                     font_man->size_attr);
1141         }
1142       }
1143 #ifndef NO_DRAW_IMAGE_STRING
1144       else {
1145         if (state == 2) {
1146           ui_window_draw_image_string16(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str2b,
1147                                         str_len);
1148         } else if (state == 1) {
1149           ui_window_draw_decsp_image_string(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str,
1150                                             str_len);
1151         } else /* if (state == 0) */ {
1152           ui_window_draw_image_string(window, uifont, fg_xcolor, bg_xcolor, x, y + ascent, str,
1153                                       str_len);
1154         }
1155       }
1156 #endif
1157 #endif /* USE_SDL2 */
1158 
1159       if (comb_chars) {
1160         xcore_draw_combining_chars(window, font_man, fg_xcolor, comb_chars, comb_size,
1161 /*
1162  * 'current_width' is for some thai fonts which automatically
1163  * draw combining chars.
1164  * e.g.)
1165  *  -thai-fixed-medium-r-normal--14-100-100-100-m-70-tis620.2529-1
1166  *  (distributed by ZzzThai http://zzzthai.fedu.uec.ac.jp/ZzzThai/)
1167  *  win32 unicode font.
1168  */
1169 #if 0
1170                                    current_width
1171 #else
1172                                    current_width - ch_width
1173 #endif
1174                                    ,
1175                                    y + ascent);
1176       }
1177 
1178       if (line_style) {
1179         if ((line_style & LS_UNDERLINE) && !hide_underline) {
1180           draw_line(window, fg_xcolor, uifont->is_vertical,
1181                     line_style & LS_UNDERLINE,
1182                     x, y, current_width - x, height, ascent + underline_offset, top_margin);
1183         }
1184 
1185         if (line_style & LS_CROSSED_OUT) {
1186           draw_line(window, fg_xcolor, uifont->is_vertical,
1187                     LS_CROSSED_OUT, x, y, current_width - x, height, ascent, top_margin);
1188         }
1189 
1190         if (line_style & LS_OVERLINE) {
1191           draw_line(window, fg_xcolor, uifont->is_vertical,
1192                     LS_OVERLINE, x, y, current_width - x, height, ascent, top_margin);
1193         }
1194       }
1195 #endif /* USE_CONSOLE */
1196 
1197     end_draw:
1198       start_draw = 0;
1199 
1200       x = current_width;
1201       str_len = 0;
1202     }
1203 
1204     if (end_of_str) {
1205       break;
1206     }
1207 
1208     uifont = next_uifont;
1209     font = next_font;
1210     fg_color = next_fg_color;
1211     bg_color = next_bg_color;
1212     line_style = next_line_style;
1213     state = next_state;
1214     draw_alone = next_draw_alone;
1215     comb_chars = next_comb_chars;
1216     comb_size = next_comb_size;
1217     current_width += (ch_width = next_ch_width);
1218   }
1219 
1220   if (updated_width != NULL) {
1221     *updated_width = current_width;
1222   }
1223 
1224 #ifdef PERF_DEBUG
1225   bl_debug_printf(" drawing %d times in a line.\n", draw_count);
1226 #endif
1227 
1228   return 1;
1229 }
1230 
1231 #endif
1232 
1233 /* --- global functions --- */
1234 
ui_draw_str(ui_window_t * window,ui_font_manager_t * font_man,ui_color_manager_t * color_man,vt_char_t * chars,u_int num_chars,int x,int y,u_int height,u_int ascent,int top_margin,int hide_underline,int underline_offset)1235 int ui_draw_str(ui_window_t *window, ui_font_manager_t *font_man, ui_color_manager_t *color_man,
1236                 vt_char_t *chars, u_int num_chars, int x, int y, u_int height, u_int ascent,
1237                 int top_margin, int hide_underline, int underline_offset) {
1238   u_int updated_width;
1239   int ret;
1240   int clip;
1241 
1242 #ifdef __DEBUG
1243   bl_debug_printf("Draw %d characters.\n", num_chars);
1244 #endif
1245 
1246   if (font_man->size_attr >= DOUBLE_HEIGHT_TOP) {
1247     ui_window_set_clip(window, x, y, window->width - x, height);
1248     clip = 1;
1249 
1250     ascent = height - (height - ascent) * 2;
1251     if (font_man->size_attr == DOUBLE_HEIGHT_TOP) {
1252       ascent += height;
1253     }
1254   }
1255 #ifdef CLIP_LINE
1256   else if (top_margin < 0) { /* XXX line_space = -1 -> top_margin == 0 */
1257     ui_window_set_clip(window, x, y, window->width - x, height);
1258     clip = 1;
1259   }
1260 #endif
1261   else {
1262     clip = 0;
1263   }
1264 
1265   switch (ui_get_type_engine(font_man)) {
1266     default:
1267       ret = 0;
1268       break;
1269 
1270 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT) || defined(USE_TYPE_CAIRO)
1271     case TYPE_XFT:
1272     case TYPE_CAIRO:
1273       ret = fc_draw_str(window, font_man, color_man, &updated_width, chars, num_chars, x, y,
1274                         height, ascent, top_margin, hide_underline, underline_offset);
1275 
1276       break;
1277 #endif
1278 
1279 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
1280     case TYPE_XCORE:
1281       ret = xcore_draw_str(window, font_man, color_man, &updated_width, chars, num_chars, x, y,
1282                            height, ascent, top_margin, hide_underline, underline_offset);
1283 
1284       break;
1285 #endif
1286   }
1287 
1288   if (clip) {
1289     ui_window_unset_clip(window);
1290   }
1291 
1292   return ret;
1293 }
1294 
ui_draw_str_to_eol(ui_window_t * window,ui_font_manager_t * font_man,ui_color_manager_t * color_man,vt_char_t * chars,u_int num_chars,int x,int y,u_int height,u_int ascent,int top_margin,int hide_underline,int underline_offset)1295 int ui_draw_str_to_eol(ui_window_t *window, ui_font_manager_t *font_man,
1296                        ui_color_manager_t *color_man, vt_char_t *chars, u_int num_chars, int x,
1297                        int y, u_int height, u_int ascent, int top_margin,
1298                        int hide_underline, int underline_offset) {
1299   u_int updated_width;
1300   int ret;
1301   int clip;
1302 
1303 #ifdef __DEBUG
1304   bl_debug_printf("Draw %d characters to eol.\n", num_chars);
1305 #endif
1306 
1307   if (font_man->size_attr >= DOUBLE_HEIGHT_TOP) {
1308     ui_window_set_clip(window, x, y, window->width - x, height);
1309     clip = 1;
1310 
1311     ascent = height - (height - ascent) * 2;
1312     if (font_man->size_attr == DOUBLE_HEIGHT_TOP) {
1313       ascent += height;
1314     }
1315   }
1316 #ifdef CLIP_LINE
1317   else if (top_margin < 0) { /* XXX line_space = -1 -> top_margin == 0 */
1318     ui_window_set_clip(window, x, y, window->width - x, height);
1319     clip = 1;
1320   }
1321 #endif
1322   else {
1323     clip = 0;
1324   }
1325 
1326   switch (ui_get_type_engine(font_man)) {
1327     default:
1328       ret = 0;
1329       break;
1330 
1331 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XFT) || defined(USE_TYPE_CAIRO)
1332     case TYPE_XFT:
1333     case TYPE_CAIRO:
1334       ui_window_clear(window, x, y, window->width - x, height);
1335 
1336       ret = fc_draw_str(window, font_man, color_man,
1337                         NULL /* NULL disables ui_window_clear() in fc_draw_str() */,
1338                         chars, num_chars, x, y, height, ascent, top_margin, hide_underline,
1339                         underline_offset);
1340 
1341       break;
1342 #endif
1343 
1344 #if !defined(NO_DYNAMIC_LOAD_TYPE) || defined(USE_TYPE_XCORE)
1345     case TYPE_XCORE:
1346 #ifndef USE_XLIB
1347       /* This shows indic scripts correctly. */
1348 
1349       ui_window_clear(window, x, y, window->width - x, height);
1350 
1351       ret = xcore_draw_str(window, font_man, color_man,
1352                            NULL /* NULL disables ui_window_clear() in fc_draw_str() */,
1353                            chars, num_chars, x, y, height, ascent, top_margin, hide_underline,
1354                            underline_offset);
1355 #else
1356       ret = xcore_draw_str(window, font_man, color_man, &updated_width,
1357                            chars, num_chars, x, y, height, ascent, top_margin, hide_underline,
1358                            underline_offset);
1359       if (updated_width < window->width) {
1360         ui_window_clear(window, updated_width, y, window->width - updated_width, height);
1361       }
1362 #endif
1363 
1364       break;
1365 #endif
1366   }
1367 
1368   if (clip) {
1369     ui_window_unset_clip(window);
1370   }
1371 
1372   return ret;
1373 }
1374 
ui_calculate_vtchar_width(ui_font_t * font,vt_char_t * ch,int * draw_alone)1375 u_int ui_calculate_vtchar_width(ui_font_t *font, vt_char_t *ch, int *draw_alone) {
1376   ef_charset_t cs;
1377   vt_char_t *comb;
1378   u_int comb_size;
1379 
1380   if ((cs = FONT_CS(font->id)) == ISO10646_UCS4_1_V) {
1381     comb = vt_get_combining_chars(ch, &comb_size);
1382   } else {
1383     comb = NULL;
1384     comb_size = 0;
1385   }
1386 
1387   return calculate_char_width(font, vt_char_code(ch), cs, vt_char_is_awidth(ch),
1388                               comb, comb_size, draw_alone);
1389 }
1390