Skip to content

Commit

Permalink
* vt_parser.c:
Browse files Browse the repository at this point in the history
  - Support U+FE0E and U+FE0F.
  - Make the 1st U+1F1E6 - U+1F1FF (regional indicator symbol letter a-z) char
    fullwidth and combine the 2nd char to the 1st.
  - Make U+1F3FB - U+1F3FF (emoji modifier fitzpatric type 1-6) char zerowidth.
* vt_screen.[ch]: Add vt_screen_unhighlight_cursor().
* vt_char.[ch]:
  Add vt_char_set_{fullwidth|zerowidth}() and vt_char_unset_picture().
  • Loading branch information
arakiken committed Feb 17, 2024
1 parent 4fdf36e commit 2d864e6
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 78 deletions.
13 changes: 13 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
2024-02-17 Araki Ken <arakiken@users.sf.net>

* vt_parser.c:
- Support U+FE0E and U+FE0F.
- Make the 1st U+1F1E6 - U+1F1FF (regional indicator symbol letter a-z) char
fullwidth and combine the 2nd char to the 1st.
- Make U+1F3FB - U+1F3FF (emoji modifier fitzpatric type 1-6) char zerowidth.

* vt_screen.[ch]: Add vt_screen_unhighlight_cursor().

* vt_char.[ch]:
Add vt_char_set_{fullwidth|zerowidth}() and vt_char_unset_picture().

2024-02-05 Araki Ken <arakiken@users.sf.net>

* vt_ot_layout.c: Skip pictures in layouting characters in vt_ot_layout().
Expand Down
101 changes: 78 additions & 23 deletions vtemu/vt_char.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#define IS_ITALIC(attr) ((attr) & (0x1 << 14))
#define IS_BOLD(attr) ((attr) & (0x1 << 13))
#define IS_FULLWIDTH(attr) ((attr) & (0x1 << 12))
#define SET_FULLWIDTH(attr, flag) (((attr) & ~(0x1 << 12)) | ((flag) << 12))
#define COLUMNS(attr) ((((attr) >> 12) & 0x1) + 1);
#define CHARSET(attr) \
(IS_UNICODE_AREA_CS(attr) ? (ISO10646_UCS4_1 | (((attr) >> 3) & 0x100)) : (((attr) >> 3) & 0x1ff))
Expand All @@ -55,6 +56,7 @@

#define IS_AWIDTH(c) ((c)->u.ch.attr2 & 0x2) /* Ambiguous width */
#define IS_ZEROWIDTH(c) ((c)->u.ch.attr2 & 0x1)
#define SET_ZEROWIDTH(c, flag) ((c)->u.ch.attr2 = ((c)->u.ch.attr2 & ~0x1) | (flag))

#ifdef USE_COMPACT_TRUECOLOR
#define FG_COLOR(ch) ((ch)->u.ch.fg_color)
Expand Down Expand Up @@ -323,7 +325,7 @@ void vt_char_set(vt_char_t *ch, u_int32_t code, ef_charset_t cs, int is_fullwidt
int is_awidth, int is_comb, vt_color_t fg_color, vt_color_t bg_color,
int is_bold, int is_italic, int line_style, int is_blinking, int is_protected) {
u_int idx;
int is_zerowidth;
int is_zerowidth = 0;

vt_char_final(ch);

Expand All @@ -348,29 +350,32 @@ void vt_char_set(vt_char_t *ch, u_int32_t code, ef_charset_t cs, int is_fullwidt
idx = 0;
}

#if 1
/*
* 0 should be returned for all zero-width characters of Unicode,
* but 0 is returned for following characters alone for now.
* 200C;ZERO WIDTH NON-JOINER
* 200D;ZERO WIDTH JOINER
* 200E;LEFT-TO-RIGHT MARK
* 200F;RIGHT-TO-LEFT MARK
* 202A;LEFT-TO-RIGHT EMBEDDING
* 202B;RIGHT-TO-LEFT EMBEDDING
* 202C;POP DIRECTIONAL FORMATTING
* 202D;LEFT-TO-RIGHT OVERRIDE
* 202E;RIGHT-TO-LEFT OVERRIDE
*
* see is_noconv_unicode() in vt_parser.c
*/
if ((code & ~0x2f) == 0x2000 /* 0x2000-0x2000f or 0x2020-0x202f */ && cs == ISO10646_UCS4_1 &&
((0x200c <= code && code <= 0x200f) || (0x202a <= code && code <= 0x202e))) {
is_zerowidth = 1;
} else {
is_zerowidth = 0;
if (cs == ISO10646_UCS4_1) {
/*
* 0 should be returned for all zero-width characters of Unicode,
* but 0 is returned for following characters alone for now.
* 200C;ZERO WIDTH NON-JOINER
* 200D;ZERO WIDTH JOINER
* 200E;LEFT-TO-RIGHT MARK
* 200F;RIGHT-TO-LEFT MARK
* 202A;LEFT-TO-RIGHT EMBEDDING
* 202B;RIGHT-TO-LEFT EMBEDDING
* 202C;POP DIRECTIONAL FORMATTING
* 202D;LEFT-TO-RIGHT OVERRIDE
* 202E;RIGHT-TO-LEFT OVERRIDE
*
* see is_noconv_unicode() in vt_parser.c
*/
if ((code & ~0x2f) == 0x2000 /* 0x2000-0x2000f or 0x2020-0x202f */) {
if ((0x200c <= code && code <= 0x200f) || (0x202a <= code && code <= 0x202e)) {
is_zerowidth = 1;
}
}
/* 0xfe00 - 0xfe0f (EF_COMBINING) ... variation selectors */
else if ((code & ~0xf) == 0xfe00 /* 0xfe00 - 0xfe0f */) {
is_zerowidth = 1;
}
}
#endif

ch->u.ch.attr2 = (is_awidth ? 2 : 0) | is_zerowidth;

Expand Down Expand Up @@ -561,6 +566,32 @@ vt_char_t *vt_get_picture_char(vt_char_t *ch) {
return NULL;
}

int vt_char_unset_picture(vt_char_t *ch) {
if (!IS_SINGLE_CH(ch->u.ch.attr)) {
vt_char_t *multi_ch = ch->u.multi_ch;

if (IS_COMB_TRAILING(multi_ch->u.ch.attr) &&
CHARSET(multi_ch[1].u.ch.attr) == PICTURE_CHARSET) {
vt_char_t new_ch;
u_int count;

vt_char_init(&new_ch);
memcpy(&new_ch, multi_ch, sizeof(vt_char_t)); /* if (!IS_SINGLE_CH) block in vt_char_copy() */

for (count = 1; IS_COMB_TRAILING(ch[count].u.ch.attr); count++) {
vt_char_combine_simple(&new_ch, multi_ch + count + 1);
}

free(multi_ch); /* if (!IS_SINGLE_CH) block in vt_char_final() */
memcpy(ch, &new_ch, sizeof(vt_char_t));

return 1;
}
}

return 0;
}

/*
* Not used for now.
*/
Expand Down Expand Up @@ -688,6 +719,30 @@ u_int vt_char_cols(vt_char_t *ch) {
}
}

void vt_char_set_fullwidth(vt_char_t *ch, int is_fullwidth) {
u_int attr;

attr = ch->u.ch.attr;

if (IS_SINGLE_CH(attr)) {
ch->u.ch.attr = SET_FULLWIDTH(attr, is_fullwidth);
} else {
return vt_char_set_fullwidth(ch->u.multi_ch, is_fullwidth);
}
}

void vt_char_set_zerowidth(vt_char_t *ch, int is_zerowidth) {
u_int attr;

attr = ch->u.ch.attr;

if (IS_SINGLE_CH(attr)) {
SET_ZEROWIDTH(ch, is_zerowidth);
} else {
return vt_char_set_zerowidth(ch->u.multi_ch, is_zerowidth);
}
}

/*
* 'use_multi_col_char' not concerned.
*/
Expand Down
10 changes: 9 additions & 1 deletion vtemu/vt_char.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ vt_char_t *vt_get_combining_chars(vt_char_t *ch, u_int *size);

vt_char_t *vt_get_picture_char(vt_char_t *ch);

int vt_char_unset_picture(vt_char_t *ch);

#if 0
/*
* Not used for now.
Expand All @@ -192,6 +194,12 @@ vt_font_t vt_char_font(vt_char_t *ch);

u_int vt_char_cols(vt_char_t *ch);

/* is_fullwidth == 1 -> occupy 2 columns */
void vt_char_set_fullwidth(vt_char_t *ch, int is_fullwidth);

/* is_zerowidth == 1 -> draw nothing */
void vt_char_set_zerowidth(vt_char_t *ch, int is_zerowidth);

int vt_char_is_fullwidth(vt_char_t *ch);

int vt_char_is_zerowidth(vt_char_t *ch);
Expand All @@ -203,7 +211,7 @@ vt_color_t vt_char_fg_color(vt_char_t *ch);
void vt_char_set_fg_color(vt_char_t *ch, vt_color_t color);

#define vt_char_picture_id(ch) vt_char_fg_color(ch)
#define vt_char_set_picture_id(ch, idx) vt_char_set_fg_color(ch, idx)
#define vt_char_set_picture_id(ch, idx) vt_char_set_fg_color(ch, idx); vt_char_set_bg_color(ch, idx)

vt_color_t vt_char_bg_color(vt_char_t *ch);

Expand Down
131 changes: 92 additions & 39 deletions vtemu/vt_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,28 +1052,52 @@ static void put_char(vt_parser_t *vt_parser, u_int32_t ch, ef_charset_t cs,
fg_color = bg_color;
}

if (vt_parser->use_char_combining && is_comb) {
if (vt_parser->w_buf.filled_len == 0) {
/*
* vt_line_set_modified() is done in vt_screen_combine_with_prev_char()
* internally.
*/
if (vt_screen_combine_with_prev_char(vt_parser->screen, ch, cs, is_fullwidth, is_awidth,
is_comb, fg_color, bg_color, is_bold, is_italic,
line_style, is_blinking, is_protected)) {
return;
if (is_comb) {
if ((ch & ~0x01) == 0xfe0e) {
vt_char_t *prev_ch;

if (vt_parser->w_buf.filled_len < 1) {
prev_ch = vt_screen_get_n_prev_char(vt_parser->screen, 1);
} else {
prev_ch = &vt_parser->w_buf.chars[vt_parser->w_buf.filled_len - 1];
}
} else {
if (vt_char_combine(&vt_parser->w_buf.chars[vt_parser->w_buf.filled_len - 1], ch, cs,
is_fullwidth, is_awidth, is_comb, fg_color, bg_color, is_bold, is_italic,
line_style, is_blinking, is_protected)) {
return;

if (ch == 0xfe0f) {
(*vt_parser->xterm_listener->get_emoji_data)(vt_parser->xterm_listener->self,
prev_ch, NULL);
} else {
/* 0xfe0e */
vt_char_unset_picture(prev_ch);
}

if (vt_parser->w_buf.filled_len < 1) {
vt_screen_unhighlight_cursor(vt_parser->screen);
}
}

/*
* if combining failed , char is normally appended.
*/
if (vt_parser->use_char_combining) {
if (vt_parser->w_buf.filled_len == 0) {
/*
* vt_line_set_modified() is done in vt_screen_combine_with_prev_char()
* internally.
*/
if (vt_screen_combine_with_prev_char(vt_parser->screen, ch, cs, is_fullwidth, is_awidth,
is_comb, fg_color, bg_color, is_bold, is_italic,
line_style, is_blinking, is_protected)) {
return;
}
} else {
if (vt_char_combine(&vt_parser->w_buf.chars[vt_parser->w_buf.filled_len - 1], ch, cs,
is_fullwidth, is_awidth, is_comb, fg_color, bg_color, is_bold,
is_italic, line_style, is_blinking, is_protected)) {
return;
}
}

/*
* if combining failed , char is normally appended.
*/
}
}

#ifndef NO_IMAGE
Expand Down Expand Up @@ -1114,6 +1138,7 @@ static void put_char(vt_parser_t *vt_parser, u_int32_t ch, ef_charset_t cs,

vt_char_t *emoji1;
vt_char_t *emoji2;
int regional_indicator = 0;

emoji1 = &vt_parser->w_buf.chars[vt_parser->w_buf.filled_len - 1];
emoji2 = NULL;
Expand All @@ -1127,11 +1152,16 @@ static void put_char(vt_parser_t *vt_parser, u_int32_t ch, ef_charset_t cs,
prev_ch = emoji1 - 1;
}

if (prev_ch) {
if (0x1f1e6 <= vt_char_code(prev_ch) && vt_char_code(prev_ch) <= 0x1f1ff) {
emoji2 = emoji1;
emoji1 = prev_ch;
}
if (prev_ch && 0x1f1e6 <= vt_char_code(prev_ch) && vt_char_code(prev_ch) <= 0x1f1ff) {
emoji2 = emoji1;
emoji1 = prev_ch;

/*
* REGIONAL INDICATOR SYMBOL LETTER is half width by default,
* but forcibly set to full width. (emoji2 is combined to emoji1)
*/
vt_char_set_fullwidth(emoji1, 1);
regional_indicator = 1;
}
} else if (0x1f3fb <= ch && ch <= 0x1f3ff) /* EMOJI MODIFIER FITZPATRIC TYPE 1-6 */ {
vt_char_t *prev_ch;
Expand All @@ -1148,30 +1178,53 @@ static void put_char(vt_parser_t *vt_parser, u_int32_t ch, ef_charset_t cs,
}
}

if ((*vt_parser->xterm_listener->get_emoji_data)(vt_parser->xterm_listener->self, emoji1,
emoji2)) {
if ((*vt_parser->xterm_listener->get_emoji_data)(vt_parser->xterm_listener->self,
emoji1, emoji2)) {
if (emoji2) {
/* Base char: emoji1, Comb1: picture, Comb2: emoji2 */
if (emoji2 == emoji1 + 1) {
vt_char_combine(emoji1, ch, cs, is_fullwidth, is_awidth, is_comb, fg_color, bg_color,
is_bold, is_italic, line_style, is_blinking, is_protected);
if (regional_indicator) {
/*
* XXX
* The property of emoji2 is not EF_COMBINING, but it is forcibly combined
* to emoji1.
*
* Base char: emoji1, Comb1: picture, Comb2: emoji2
*/
if (emoji2 == emoji1 + 1) {
vt_char_combine(emoji1, ch, cs, is_fullwidth, is_awidth, is_comb, fg_color, bg_color,
is_bold, is_italic, line_style, is_blinking, is_protected);
} else {
/*
* vt_line_set_modified() is done in
* vt_screen_combine_with_prev_char() internally.
*/
vt_screen_combine_with_prev_char(vt_parser->screen, ch, cs, is_fullwidth, is_awidth,
is_comb, fg_color, bg_color, is_bold, is_italic,
line_style, is_blinking, is_protected);
}
vt_parser->w_buf.filled_len--;
} else {
/*
* vt_line_set_modified() is done in
* vt_screen_combine_with_prev_char() internally.
* The property of EMOJI MODIFIER FITZPATRIC TYPE 1-6 is EF_FULLWIDTH.
* Don't draw emoji2 by setting is_zerowidth to 1.
*/
vt_screen_combine_with_prev_char(vt_parser->screen, ch, cs, is_fullwidth, is_awidth,
is_comb, fg_color, bg_color, is_bold, is_italic,
line_style, is_blinking, is_protected);
vt_char_set_zerowidth(emoji2, 1);
}
vt_parser->w_buf.filled_len--;
}

/*
* Flush buffer before searching and deleting unused pictures
* in x_picture.c.
*/
/* Flush buffer before searching and deleting unused pictures in x_picture.c. */
flush_buffer(vt_parser);
} else {
if (emoji2) {
if (regional_indicator) {
/* revert to the original value. */
vt_char_set_fullwidth(emoji1, 0);
}

if ((*vt_parser->xterm_listener->get_emoji_data)(vt_parser->xterm_listener->self,
emoji2, NULL)) {
flush_buffer(vt_parser);
}
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions vtemu/vt_screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,15 @@ vt_line_t *vt_screen_get_line_in_screen(vt_screen_t *screen, int row) {
}
}

void vt_screen_unhighlight_cursor(vt_screen_t *screen) {
vt_line_t *line;

if ((line = vt_screen_get_cursor_line(screen)) && !vt_line_is_empty(line)) {
int char_index = vt_cursor_char_index(screen->edit);
vt_line_set_modified(line, char_index, char_index);
}
}

void vt_screen_set_modified_all(vt_screen_t *screen) {
int row;
vt_line_t *line;
Expand Down
2 changes: 2 additions & 0 deletions vtemu/vt_screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ vt_line_t *vt_screen_get_line_in_screen(vt_screen_t *screen, int row);
#define vt_screen_get_cursor_line(screen) \
vt_edit_get_line((screen)->edit, vt_cursor_row((screen)->edit))

void vt_screen_unhighlight_cursor(vt_screen_t *screen);

void vt_screen_set_modified_all(vt_screen_t *screen);

int vt_screen_add_logical_visual(vt_screen_t *screen, vt_logical_visual_t *logvis);
Expand Down
Loading

0 comments on commit 2d864e6

Please sign in to comment.