X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/1c10e8497695c5789abf206a038024809183ec46..73feed4f401660e3374ea0f783ae7b7c6ea4c0c8:/terminal.c diff --git a/terminal.c b/terminal.c index 7bcbaf90..40ad4823 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); } /* @@ -634,6 +636,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 +850,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 +864,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 +902,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 +1139,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 +1315,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 +1669,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 +2466,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); } @@ -2717,8 +2755,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; @@ -4128,11 +4184,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. */ @@ -4146,24 +4205,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); } /* @@ -4366,7 +4430,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; @@ -4665,7 +4729,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 @@ -4744,6 +4808,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)) @@ -5016,7 +5081,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--;