I _think_ I've just fixed `font-overflow'. term->disptext now tracks
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 17 Dec 2004 12:55:12 +0000 (12:55 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 17 Dec 2004 12:55:12 +0000 (12:55 +0000)
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
terminal.c

diff --git a/putty.h b/putty.h
index f92efea..b6aace7 100644 (file)
--- 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 */
index 960b212..ea5f503 100644 (file)
@@ -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);