X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/a263e4f607af0edf3aadcde29be577660d84fe2d..33f07e9636e80bb17f25f97145ca2e0eb262db30:/terminal.c diff --git a/terminal.c b/terminal.c index db024adf..bf531eee 100644 --- a/terminal.c +++ b/terminal.c @@ -201,7 +201,7 @@ static void power_on(Terminal *term) term->in_vbell = FALSE; term->cursor_on = 1; term->big_cursor = 0; - term->save_attr = term->curr_attr = ATTR_DEFAULT; + term->default_attr = term->save_attr = term->curr_attr = ATTR_DEFAULT; term->term_editing = term->term_echoing = FALSE; term->app_cursor_keys = term->cfg.app_cursor; term->app_keypad_keys = term->cfg.app_keypad; @@ -237,6 +237,15 @@ void term_update(Terminal *term) term->seen_disp_event = 0; need_sbar_update = TRUE; } + + /* Allocate temporary buffers for Arabic shaping and bidi. */ + if (!term->cfg.arabicshaping || !term->cfg.bidi) + { + term->wcFrom = sresize(term->wcFrom, term->cols, bidi_char); + term->ltemp = sresize(term->ltemp, term->cols+1, unsigned long); + term->wcTo = sresize(term->wcTo, term->cols, bidi_char); + } + if (need_sbar_update) update_sbar(term); do_paint(term, ctx, TRUE); @@ -428,6 +437,12 @@ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata, term->resize_fn = NULL; term->resize_ctx = NULL; term->in_term_out = FALSE; + term->ltemp = NULL; + term->wcFrom = NULL; + term->wcTo = NULL; + + term->bidi_cache_size = 0; + term->pre_bidi_cache = term->post_bidi_cache = NULL; return term; } @@ -436,6 +451,7 @@ void term_free(Terminal *term) { unsigned long *line; struct beeptime *beep; + int i; while ((line = delpos234(term->scrollback, 0)) != NULL) sfree(line); @@ -457,6 +473,17 @@ void term_free(Terminal *term) printer_finish_job(term->print_job); bufchain_clear(&term->printer_buf); sfree(term->paste_buffer); + sfree(term->ltemp); + sfree(term->wcFrom); + sfree(term->wcTo); + + for (i = 0; i < term->bidi_cache_size; i++) { + sfree(term->pre_bidi_cache[i]); + sfree(term->post_bidi_cache[i]); + } + sfree(term->pre_bidi_cache); + sfree(term->post_bidi_cache); + sfree(term); } @@ -850,26 +877,29 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) */ seltop = sb ? -term->savelines : topline; - if (term->selstart.y >= seltop && - term->selstart.y <= botline) { - term->selstart.y--; - if (term->selstart.y < seltop) { - term->selstart.y = seltop; - term->selstart.x = 0; + if (term->selstate != NO_SELECTION) { + if (term->selstart.y >= seltop && + term->selstart.y <= botline) { + term->selstart.y--; + if (term->selstart.y < seltop) { + term->selstart.y = seltop; + term->selstart.x = 0; + } } - } - if (term->selend.y >= seltop && term->selend.y <= botline) { - term->selend.y--; - if (term->selend.y < seltop) { - term->selend.y = seltop; - term->selend.x = 0; + if (term->selend.y >= seltop && term->selend.y <= botline) { + term->selend.y--; + if (term->selend.y < seltop) { + term->selend.y = seltop; + term->selend.x = 0; + } } - } - if (term->selanchor.y >= seltop && term->selanchor.y <= botline) { - term->selanchor.y--; - if (term->selanchor.y < seltop) { - term->selanchor.y = seltop; - term->selanchor.x = 0; + if (term->selanchor.y >= seltop && + term->selanchor.y <= botline) { + term->selanchor.y--; + if (term->selanchor.y < seltop) { + term->selanchor.y = seltop; + term->selanchor.x = 0; + } } } @@ -1697,7 +1727,7 @@ void term_out(Terminal *term) term_update(term); } } - term->disptop = 0; + term->seen_disp_event = TRUE; } break; case '\b': /* BS: Back space */ @@ -2376,7 +2406,7 @@ void term_out(Terminal *term) for (i = 0; i < term->esc_nargs; i++) { switch (def(term->esc_args[i], 0)) { case 0: /* restore defaults */ - term->curr_attr = ATTR_DEFAULT; + term->curr_attr = term->default_attr; break; case 1: /* enable bold */ compatibility(VT100AVO); @@ -2782,21 +2812,27 @@ void term_out(Terminal *term) case ANSI('F', '='): /* set normal foreground */ compatibility(SCOANSI); if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) { - term->curr_attr &= ~ATTR_FGMASK; - term->curr_attr |= - (sco2ansicolour[term->esc_args[0] & 0x7] | + long colour = + (sco2ansicolour[term->esc_args[0] & 0x7] | ((term->esc_args[0] & 0x8) << 1)) << ATTR_FGSHIFT; + term->curr_attr &= ~ATTR_FGMASK; + term->curr_attr |= colour; + term->default_attr &= ~ATTR_FGMASK; + term->default_attr |= colour; } break; case ANSI('G', '='): /* set normal background */ compatibility(SCOANSI); if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) { - term->curr_attr &= ~ATTR_BGMASK; - term->curr_attr |= - (sco2ansicolour[term->esc_args[0] & 0x7] | + long colour = + (sco2ansicolour[term->esc_args[0] & 0x7] | ((term->esc_args[0] & 0x8) << 1)) << ATTR_BGSHIFT; + term->curr_attr &= ~ATTR_BGMASK; + term->curr_attr |= colour; + term->default_attr &= ~ATTR_BGMASK; + term->default_attr |= colour; } break; case ANSI('L', '='): @@ -3294,12 +3330,65 @@ static int linecmp(Terminal *term, unsigned long *a, unsigned long *b) #endif /* + * To prevent having to run the reasonably tricky bidi algorithm + * too many times, we maintain a cache of the last lineful of data + * fed to the algorithm on each line of the display. + */ +static int term_bidi_cache_hit(Terminal *term, int line, + unsigned long *lbefore, int width) +{ + if (!term->pre_bidi_cache) + return FALSE; /* cache doesn't even exist yet! */ + + if (line >= term->bidi_cache_size) + return FALSE; /* cache doesn't have this many lines */ + + if (!term->pre_bidi_cache[line]) + return FALSE; /* cache doesn't contain _this_ line */ + + if (!memcmp(term->pre_bidi_cache[line], lbefore, + width * sizeof(unsigned long))) + return TRUE; /* aha! the line matches the cache */ + + return FALSE; /* it didn't match. */ +} + +static void term_bidi_cache_store(Terminal *term, int line, + unsigned long *lbefore, + unsigned long *lafter, int width) +{ + if (!term->pre_bidi_cache || term->bidi_cache_size <= line) { + int j = term->bidi_cache_size; + term->bidi_cache_size = line+1; + term->pre_bidi_cache = sresize(term->pre_bidi_cache, + term->bidi_cache_size, + unsigned long *); + term->post_bidi_cache = sresize(term->post_bidi_cache, + term->bidi_cache_size, + unsigned long *); + while (j < term->bidi_cache_size) { + term->pre_bidi_cache[j] = term->post_bidi_cache[j] = NULL; + j++; + } + } + + sfree(term->pre_bidi_cache[line]); + sfree(term->post_bidi_cache[line]); + + term->pre_bidi_cache[line] = snewn(width, unsigned long); + term->post_bidi_cache[line] = snewn(width, unsigned long); + + memcpy(term->pre_bidi_cache[line], lbefore, width * sizeof(unsigned long)); + memcpy(term->post_bidi_cache[line], lafter, width * sizeof(unsigned long)); +} + +/* * Given a context, update the window. Out of paranoia, we don't * allow WM_PAINT responses to do scrolling optimisations. */ static void do_paint(Terminal *term, Context ctx, int may_optimise) { - int i, j, our_curs_y, our_curs_x; + int i, it, j, our_curs_y, our_curs_x; unsigned long rv, cursor; pos scrpos; char ch[1024]; @@ -3315,8 +3404,8 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) if (term->in_vbell) { ticks = GETTICKCOUNT(); if (ticks - term->vbell_startpoint >= VBELL_TIMEOUT) - term->in_vbell = FALSE; - } + term->in_vbell = FALSE; + } rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0); @@ -3402,6 +3491,67 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) term->disptext[idx + term->cols]); term->disptext[idx + term->cols] = ldata[term->cols]; + /* Do Arabic shaping and bidi. */ + if(!term->cfg.bidi || !term->cfg.arabicshaping) { + + if (!term_bidi_cache_hit(term, i, ldata, term->cols)) { + + for(it=0; itcols ; it++) + { + int uc = (ldata[it] & 0xFFFF); + + switch (uc & CSET_MASK) { + case ATTR_LINEDRW: + if (!term->cfg.rawcnp) { + uc = term->ucsdata->unitab_xterm[uc & 0xFF]; + break; + } + case ATTR_ASCII: + uc = term->ucsdata->unitab_line[uc & 0xFF]; + break; + case ATTR_SCOACS: + uc = term->ucsdata->unitab_scoacs[uc&0xFF]; + break; + } + switch (uc & CSET_MASK) { + case ATTR_ACP: + uc = term->ucsdata->unitab_font[uc & 0xFF]; + break; + case ATTR_OEMCP: + uc = term->ucsdata->unitab_oemcp[uc & 0xFF]; + break; + } + + term->wcFrom[it].origwc = term->wcFrom[it].wc = uc; + term->wcFrom[it].index = it; + } + + if(!term->cfg.bidi) + do_bidi(term->wcFrom, term->cols); + + /* this is saved iff done from inside the shaping */ + if(!term->cfg.bidi && term->cfg.arabicshaping) + for(it=0; itcols; it++) + term->wcTo[it] = term->wcFrom[it]; + + if(!term->cfg.arabicshaping) + do_shape(term->wcFrom, term->wcTo, term->cols); + + for(it=0; itcols ; it++) + { + term->ltemp[it] = ldata[term->wcTo[it].index]; + + if (term->wcTo[it].origwc != term->wcTo[it].wc) + term->ltemp[it] = ((term->ltemp[it] & 0xFFFF0000) | + term->wcTo[it].wc); + } + term_bidi_cache_store(term, i, ldata, term->ltemp, term->cols); + ldata = term->ltemp; + } else { + ldata = term->post_bidi_cache[i]; + } + } + for (j = 0; j < term->cols; j++, idx++) { unsigned long tattr, tchar; unsigned long *d = ldata + j; @@ -3423,8 +3573,9 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) } tattr |= (tchar & CSET_MASK); tchar &= CHAR_MASK; - if ((d[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE) - tattr |= ATTR_WIDE; + if (j < term->cols-1 && + (d[1] & (CHAR_MASK | CSET_MASK)) == UCSWIDE) + tattr |= ATTR_WIDE; /* Video reversing things */ if (term->selstate == DRAGGING || term->selstate == SELECTED) { @@ -3790,9 +3941,13 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) void term_copyall(Terminal *term) { pos top; + pos bottom; + tree234 *screen = term->screen; top.y = -sblines(term); top.x = 0; - clipme(term, top, term->curs, 0, TRUE); + bottom.y = find_last_nonempty_line(term, screen); + bottom.x = term->cols; + clipme(term, top, bottom, 0, TRUE); } /* @@ -4786,8 +4941,6 @@ int term_ldisc(Terminal *term, int option) int term_data(Terminal *term, int is_stderr, const char *data, int len) { - assert(len > 0); - bufchain_add(&term->inbuf, data, len); if (!term->in_term_out) {