X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/ac059c2eea817ebe83ecb449e5d78943f9170692..c6f1b8ed877667ff8b75e5dda5a89cd54ffccfbb:/terminal.c diff --git a/terminal.c b/terminal.c index 87f4a894..25c2cfda 100644 --- a/terminal.c +++ b/terminal.c @@ -177,6 +177,8 @@ static void cc_check(termline *line) j += (flags[i] != 0); assert(j == line->size); + + sfree(flags); } /* @@ -433,6 +435,9 @@ static void makerle(struct buf *b, termline *ldata, hdrpos = b->len; hdrsize = 0; add(b, 0); + /* And ensure this run doesn't interfere with the next. */ + prevlen = prevpos = 0; + prev2 = FALSE; continue; } else { @@ -634,6 +639,9 @@ static unsigned char *compressline(termline *ldata) /* * Diagnostics: ensure that the compressed data really does * decompress to the right thing. + * + * XXX-REMOVE-BEFORE-RELEASE: This is a bit performance-heavy + * to be leaving in production code. */ #ifndef CHECK_SB_COMPRESSION { @@ -845,9 +853,12 @@ static termline *decompressline(unsigned char *data, int *bytes_used) */ static void resizeline(Terminal *term, termline *line, int cols) { - int i, oldlen; + int i, oldcols; if (line->cols != cols) { + + oldcols = line->cols; + /* * This line is the wrong length, which probably means it * hasn't been accessed since a resize. Resize it now. @@ -856,24 +867,36 @@ static void resizeline(Terminal *term, termline *line, int cols) * out in the resize (if we're shrinking the line) and * return their cc lists to the cc free list. */ - for (i = cols; i < line->cols; i++) + for (i = cols; i < oldcols; i++) clear_cc(line, i); /* + * If we're shrinking the line, we now bodily move the + * entire cc section from where it started to where it now + * needs to be. (We have to do this before the resize, so + * that the data we're copying is still there. However, if + * we're expanding, we have to wait until _after_ the + * resize so that the space we're copying into is there.) + */ + if (cols < oldcols) + memmove(line->chars + cols, line->chars + oldcols, + (line->size - line->cols) * TSIZE); + + /* * Now do the actual resize, leaving the _same_ amount of * cc space as there was to begin with. */ - oldlen = line->cols; - line->size += cols - oldlen; + line->size += cols - oldcols; line->chars = sresize(line->chars, line->size, TTYPE); line->cols = cols; /* - * Bodily move the entire cc section from where it started - * to where it now needs to be. + * If we're expanding the line, _now_ we move the cc + * section. */ - memmove(line->chars + line->cols, line->chars + oldlen, - (line->size - line->cols) * TSIZE); + if (cols > oldcols) + memmove(line->chars + cols, line->chars + oldcols, + (line->size - line->cols) * TSIZE); /* * Go through what's left of the original line, and adjust @@ -882,18 +905,18 @@ static void resizeline(Terminal *term, termline *line, int cols) * relative offsets within the cc block.) Also do the same * to the head of the cc_free list. */ - for (i = 0; i < oldlen && i < line->cols; i++) + for (i = 0; i < oldcols && i < cols; i++) if (line->chars[i].cc_next) - line->chars[i].cc_next += cols - oldlen; + line->chars[i].cc_next += cols - oldcols; if (line->cc_free) - line->cc_free += cols - oldlen; + line->cc_free += cols - oldcols; /* * And finally fill in the new space with erase chars. (We * don't have to worry about cc lists here, because we * _know_ the erase char doesn't have one.) */ - for (i = oldlen; i < cols; i++) + for (i = oldcols; i < cols; i++) line->chars[i] = term->basic_erase_char; cc_check(line); /* XXX-REMOVE-BEFORE-RELEASE */ @@ -1119,6 +1142,22 @@ void term_reconfig(Terminal *term, Config *cfg) if (term->cfg.wordness[i] != cfg->wordness[i]) reset_charclass = 1; + /* + * If the bidi or shaping settings have changed, flush the bidi + * cache completely. + */ + if (term->cfg.arabicshaping != cfg->arabicshaping || + term->cfg.bidi != cfg->bidi) { + for (i = 0; i < term->bidi_cache_size; i++) { + sfree(term->pre_bidi_cache[i].chars); + sfree(term->post_bidi_cache[i].chars); + term->pre_bidi_cache[i].width = -1; + term->pre_bidi_cache[i].chars = NULL; + term->post_bidi_cache[i].width = -1; + term->post_bidi_cache[i].chars = NULL; + } + } + term->cfg = *cfg; /* STRUCTURE COPY */ if (reset_wrap) @@ -1279,8 +1318,8 @@ void term_free(Terminal *term) 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[i].chars); + sfree(term->post_bidi_cache[i].chars); } sfree(term->pre_bidi_cache); sfree(term->post_bidi_cache); @@ -1633,7 +1672,7 @@ static void scroll(Terminal *term, int topline, int botline, int lines, int sb) addpos234(term->scrollback, compressline(line), sblen); - line = newline(term, term->cols, TRUE); + /* now `line' itself can be reused as the bottom line */ /* * If the user is currently looking at part of the @@ -2430,6 +2469,8 @@ void term_out(Terminal *term) term->wrapnext = FALSE; /* destructive backspace might be disabled */ if (!term->cfg.no_dbackspace) { + check_boundary(term, term->curs.x, term->curs.y); + check_boundary(term, term->curs.x+1, term->curs.y); copy_termchar(scrlineptr(term->curs.y), term->curs.x, &term->erase_char); } @@ -2640,6 +2681,7 @@ void term_out(Terminal *term) term->curs.y++; term->curs.x = 0; term->wrapnext = FALSE; + cline = scrlineptr(term->curs.y); } if (term->insert && width > 0) insch(term, width); @@ -2716,8 +2758,26 @@ void term_out(Terminal *term) break; case 0: - add_cc(cline, term->curs.x - !term->wrapnext, c); - term->seen_disp_event = 1; + if (term->curs.x > 0) { + int x = term->curs.x - 1; + + /* If we're in wrapnext state, the character + * to combine with is _here_, not to our left. */ + if (term->wrapnext) + x++; + + /* + * If the previous character is + * UCSWIDE, back up another one. + */ + if (cline->chars[x].chr == UCSWIDE) { + assert(x > 0); + x--; + } + + add_cc(cline, x, c); + term->seen_disp_event = 1; + } continue; default: continue; @@ -4127,11 +4187,14 @@ static int term_bidi_cache_hit(Terminal *term, int line, if (line >= term->bidi_cache_size) return FALSE; /* cache doesn't have this many lines */ - if (!term->pre_bidi_cache[line]) + if (!term->pre_bidi_cache[line].chars) return FALSE; /* cache doesn't contain _this_ line */ + if (term->pre_bidi_cache[line].width != width) + return FALSE; /* line is wrong width */ + for (i = 0; i < width; i++) - if (!termchars_equal(term->pre_bidi_cache[line] + i, lbefore + i)) + if (!termchars_equal(term->pre_bidi_cache[line].chars+i, lbefore+i)) return FALSE; /* line doesn't match cache */ return TRUE; /* it didn't match. */ @@ -4145,24 +4208,29 @@ static void term_bidi_cache_store(Terminal *term, int line, termchar *lbefore, term->bidi_cache_size = line+1; term->pre_bidi_cache = sresize(term->pre_bidi_cache, term->bidi_cache_size, - termchar *); + struct bidi_cache_entry); term->post_bidi_cache = sresize(term->post_bidi_cache, term->bidi_cache_size, - termchar *); + struct bidi_cache_entry); while (j < term->bidi_cache_size) { - term->pre_bidi_cache[j] = term->post_bidi_cache[j] = NULL; + term->pre_bidi_cache[j].chars = + term->post_bidi_cache[j].chars = NULL; + term->pre_bidi_cache[j].width = + term->post_bidi_cache[j].width = -1; j++; } } - sfree(term->pre_bidi_cache[line]); - sfree(term->post_bidi_cache[line]); + sfree(term->pre_bidi_cache[line].chars); + sfree(term->post_bidi_cache[line].chars); - term->pre_bidi_cache[line] = snewn(width, termchar); - term->post_bidi_cache[line] = snewn(width, termchar); + term->pre_bidi_cache[line].width = width; + term->pre_bidi_cache[line].chars = snewn(width, termchar); + term->post_bidi_cache[line].width = width; + term->post_bidi_cache[line].chars = snewn(width, termchar); - memcpy(term->pre_bidi_cache[line], lbefore, width * TSIZE); - memcpy(term->post_bidi_cache[line], lafter, width * TSIZE); + memcpy(term->pre_bidi_cache[line].chars, lbefore, width * TSIZE); + memcpy(term->post_bidi_cache[line].chars, lafter, width * TSIZE); } /* @@ -4365,7 +4433,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) lchars = term->ltemp; } else { - lchars = term->post_bidi_cache[i]; + lchars = term->post_bidi_cache[i].chars; } } else lchars = ldata->chars; @@ -4379,6 +4447,10 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) tchar = d->chr; tattr = d->attr; + if (!term->cfg.ansi_colour) + tattr = (tattr & ~(ATTR_FGMASK | ATTR_BGMASK)) | + ATTR_DEFFG | ATTR_DEFBG; + switch (tchar & CSET_MASK) { case CSET_ASCII: tchar = term->ucsdata->unitab_line[tchar & 0xFF]; @@ -4664,7 +4736,7 @@ void term_paint(Terminal *term, Context ctx, if (bottom >= term->rows) bottom = term->rows-1; for (i = top; i <= bottom && i < term->rows; i++) { - if (term->disptext[i]->lattr == LATTR_NORM) + if ((term->disptext[i]->lattr & LATTR_MODE) == LATTR_NORM) for (j = left; j <= right && j < term->cols; j++) term->disptext[i]->chars[j].attr = ATTR_INVALID; else @@ -4743,6 +4815,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) */ if (!(ldata->lattr & LATTR_WRAPPED)) { while (IS_SPACE_CHR(ldata->chars[nlpos.x - 1].chr) && + !ldata->chars[nlpos.x - 1].cc_next && poslt(top, nlpos)) decpos(nlpos); if (poslt(nlpos, bottom)) @@ -5015,7 +5088,8 @@ static pos sel_spread_half(Terminal *term, pos p, int dir) */ if (!(ldata->lattr & LATTR_WRAPPED)) { termchar *q = ldata->chars + term->cols; - while (q > ldata->chars && IS_SPACE_CHR(q[-1].chr)) + while (q > ldata->chars && + IS_SPACE_CHR(q[-1].chr) && !q[-1].cc_next) q--; if (q == ldata->chars + term->cols) q--;