From fd59420de626ce8af54dd90cf4ae37570793c9d1 Mon Sep 17 00:00:00 2001 From: simon Date: Fri, 17 Dec 2004 12:55:12 +0000 Subject: [PATCH] I _think_ I've just fixed `font-overflow'. term->disptext now tracks the start of every contiguous run passed to do_text() or do_cursor(), and arranges never to overwrite only part of such a run on the next update. I'm a bit worried about this checkin because I've also completely revamped cursor handling: the cursor was previously being drawn _outside_ the main loop over the display line, and is now drawn as part of that loop when it gets to the cursor location. It _seems_ to still work sensibly, even in complex cases involving LATTR_WIDE and double-width CJK characters etc, but I won't be entirely happy until it's had some beta use. git-svn-id: svn://svn.tartarus.org/sgt/putty@5003 cda61777-01e9-0310-a592-d414129be87e --- putty.h | 13 ++++++- terminal.c | 113 +++++++++++++++++++++++++++---------------------------------- 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/putty.h b/putty.h index f92efea3..b6aace7f 100644 --- a/putty.h +++ b/putty.h @@ -36,6 +36,11 @@ typedef struct terminal_tag Terminal; * * The LATTRs (line attributes) are an entirely disjoint space of * flags. + * + * The DATTRs (display attributes) are internal to terminal.c (but + * defined here because their values have to match the others + * here); they reuse the TATTR_* space but are always masked off + * before sending to the front end. * * ATTR_INVALID is an illegal colour combination. */ @@ -45,6 +50,12 @@ typedef struct terminal_tag Terminal; #define TATTR_RIGHTCURS 0x10000000UL /* cursor-on-RHS */ #define TATTR_COMBINING 0x80000000UL /* combining characters */ +#define DATTR_STARTRUN 0x80000000UL /* start of redraw run */ + +#define TDATTR_MASK 0xF0000000UL +#define TATTR_MASK (TDATTR_MASK) +#define DATTR_MASK (TDATTR_MASK) + #define LATTR_NORM 0x00000000UL #define LATTR_WIDE 0x00000001UL #define LATTR_TOP 0x00000002UL @@ -53,7 +64,7 @@ typedef struct terminal_tag Terminal; #define LATTR_WRAPPED 0x00000010UL #define LATTR_WRAPPED2 0x00000020UL -#define ATTR_INVALID 0x03FFU +#define ATTR_INVALID 0x03FFFFU /* Like Linux use the F000 page for direct to font. */ #define CSET_OEMCP 0x0000F000UL /* OEM Codepage DTF */ diff --git a/terminal.c b/terminal.c index 960b2129..ea5f503f 100644 --- a/terminal.c +++ b/terminal.c @@ -271,7 +271,7 @@ static int termchars_equal_override(termchar *a, termchar *b, /* FULL-TERMCHAR */ if (a->chr != bchr) return FALSE; - if (a->attr != battr) + if ((a->attr &~ DATTR_MASK) != (battr &~ DATTR_MASK)) return FALSE; while (a->cc_next || b->cc_next) { if (!a->cc_next || !b->cc_next) @@ -4539,14 +4539,11 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) pos scrpos; wchar_t *ch; int chlen; - termchar cursor_background; #ifdef OPTIMISE_SCROLL struct scrollregion *sr; #endif /* OPTIMISE_SCROLL */ termchar *newline; - cursor_background = term->basic_erase_char; - chlen = 1024; ch = snewn(chlen, wchar_t); @@ -4646,6 +4643,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) int start = 0; int ccount = 0; int last_run_dirty = 0; + int laststart, dirtyrect; int *backward; scrpos.y = i + term->disptop; @@ -4727,22 +4725,15 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) */ if (tchar != term->disptext[i]->chars[j].chr || tattr != (term->disptext[i]->chars[j].attr &~ - ATTR_NARROW)) { + (ATTR_NARROW | DATTR_MASK))) { if ((tattr & ATTR_WIDE) == 0 && char_width(ctx, tchar) == 2) tattr |= ATTR_NARROW; } else if (term->disptext[i]->chars[j].attr & ATTR_NARROW) tattr |= ATTR_NARROW; - /* Cursor here ? Save the 'background' */ if (i == our_curs_y && j == our_curs_x) { - /* FULL-TERMCHAR */ - cursor_background.chr = tchar; - cursor_background.attr = tattr; - /* For once, this cc_next field is an absolute index in lchars */ - if (d->cc_next) - cursor_background.cc_next = d->cc_next + j; - else - cursor_background.cc_next = 0; + tattr |= cursor; + term->curstype = cursor; term->dispcursx = j; term->dispcursy = i; } @@ -4757,12 +4748,38 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) /* * Now loop over the line again, noting where things have * changed. + * + * During this loop, we keep track of where we last saw + * DATTR_STARTRUN. Any mismatch automatically invalidates + * _all_ of the containing run that was last printed: that + * is, any rectangle that was drawn in one go in the + * previous update should be either left completely alone + * or overwritten in its entirety. This, along with the + * expectation that front ends clip all text runs to their + * bounding rectangle, should solve any possible problems + * with fonts that overflow their character cells. */ + laststart = 0; + dirtyrect = FALSE; for (j = 0; j < term->cols; j++) { + if (term->disptext[i]->chars[j].attr & DATTR_STARTRUN) { + laststart = j; + dirtyrect = FALSE; + } + if (term->disptext[i]->chars[j].chr != newline[j].chr || - term->disptext[i]->chars[j].attr != newline[j].attr) { - term->disptext[i]->chars[j].attr |= ATTR_INVALID; + (term->disptext[i]->chars[j].attr &~ DATTR_MASK) + != newline[j].attr) { + int k; + + for (k = laststart; k < j; k++) + term->disptext[i]->chars[k].attr |= ATTR_INVALID; + + dirtyrect = TRUE; } + + if (dirtyrect) + term->disptext[i]->chars[j].attr |= ATTR_INVALID; } /* @@ -4805,7 +4822,7 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) if (!term->ucsdata->dbcs_screenfont && !dirty_line) { if (term->disptext[i]->chars[j].chr == tchar && - term->disptext[i]->chars[j].attr == tattr) + (term->disptext[i]->chars[j].attr &~ DATTR_MASK) == tattr) break_run = TRUE; else if (!dirty_run && ccount == 1) break_run = TRUE; @@ -4813,7 +4830,13 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) if (break_run) { if ((dirty_run || last_run_dirty) && ccount > 0) { - do_text(ctx, start, i, ch, ccount, attr, ldata->lattr); + if (attr & (TATTR_ACTCURS | TATTR_PASCURS)) + do_cursor(ctx, our_curs_x, i, ch, ccount, attr, + ldata->lattr); + else + do_text(ctx, start, i, ch, ccount, attr, + ldata->lattr); + updated_line = 1; } start = j; @@ -4873,6 +4896,8 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) copy_termchar(term->disptext[i], j, d); term->disptext[i]->chars[j].chr = tchar; term->disptext[i]->chars[j].attr = tattr; + if (start == j) + term->disptext[i]->chars[j].attr |= DATTR_STARTRUN; } /* If it's a wide char step along to the next one. */ @@ -4892,52 +4917,14 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) } } if (dirty_run && ccount > 0) { - do_text(ctx, start, i, ch, ccount, attr, ldata->lattr); - updated_line = 1; - } - - /* Cursor on this line ? (and changed) */ - if (i == our_curs_y && (term->curstype != cursor || updated_line)) { - ch[0] = (wchar_t) cursor_background.chr; - attr = cursor_background.attr | cursor; - ccount = 1; - - if (cursor_background.cc_next) { - termchar *dd = ldata->chars + cursor_background.cc_next; - - while (1) { - unsigned long schar; - - schar = dd->chr; - switch (schar & CSET_MASK) { - case CSET_ASCII: - schar = term->ucsdata->unitab_line[schar & 0xFF]; - break; - case CSET_LINEDRW: - schar = term->ucsdata->unitab_xterm[schar & 0xFF]; - break; - case CSET_SCOACS: - schar = term->ucsdata->unitab_scoacs[schar&0xFF]; - break; - } - - if (ccount >= chlen) { - chlen = ccount + 256; - ch = sresize(ch, chlen, wchar_t); - } - ch[ccount++] = (wchar_t) schar; - - if (dd->cc_next) - dd += dd->cc_next; - else - break; - } - - attr |= TATTR_COMBINING; - } + if (attr & (TATTR_ACTCURS | TATTR_PASCURS)) + do_cursor(ctx, our_curs_x, i, ch, ccount, attr, + ldata->lattr); + else + do_text(ctx, start, i, ch, ccount, attr, + ldata->lattr); - do_cursor(ctx, our_curs_x, i, ch, ccount, attr, ldata->lattr); - term->curstype = cursor; + updated_line = 1; } unlineptr(ldata); -- 2.11.0