changeset 102034:bebfd771aaeb

(MAX_SCREEN_BUF): New macro. (IT_write_glyphs): Make screen_buf[] always be MAX_SCREEN_BUF-long. Encode the entire run of glyphs sharing the same face, instead of doing that one glyph at a time (fixes a bug with displaying double-size characters).
author Eli Zaretskii <eliz@gnu.org>
date Sat, 14 Feb 2009 10:49:42 +0000
parents 4daf530ddfb0
children 6adcb5801c43
files src/msdos.c
diffstat 1 files changed, 39 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/src/msdos.c	Sat Feb 14 09:08:08 2009 +0000
+++ b/src/msdos.c	Sat Feb 14 10:49:42 2009 +0000
@@ -957,19 +957,20 @@
     }
 }
 
+/* According to RBIL (INTERRUP.A, V-1000), 160 is the maximum possible
+   width of a DOS display in any known text mode.  We multiply by 2 to
+   accomodate the screen attribute byte.  */
+#define MAX_SCREEN_BUF 160*2
+
 Lisp_Object Vdos_unsupported_char_glyph;
 extern unsigned char *encode_terminal_code (struct glyph *, int,
 					    struct coding_system *);
 static void
 IT_write_glyphs (struct frame *f, struct glyph *str, int str_len)
 {
-  unsigned char *screen_buf, *screen_bp, *screen_buf_end, *bp;
-  int unsupported_face = 0;
-  unsigned unsupported_char = '\177';
+  unsigned char screen_buf[MAX_SCREEN_BUF], *screen_bp, *bp;
   int offset = 2 * (new_pos_X + screen_size_X * new_pos_Y);
   register int sl = str_len;
-  register int tlen = GLYPH_TABLE_LENGTH;
-  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
   struct tty_display_info *tty = FRAME_TTY (f);
   struct frame *sf;
   unsigned char *conversion_buffer;
@@ -990,8 +991,6 @@
 
   if (str_len <= 0) return;
 
-  screen_buf = screen_bp = alloca (str_len * 2);
-  screen_buf_end = screen_buf + str_len * 2;
   sf = SELECTED_FRAME();
 
   /* Since faces get cached and uncached behind our back, we can't
@@ -1004,73 +1003,50 @@
   /* The mode bit CODING_MODE_LAST_BLOCK should be set to 1 only at
      the tail.  */
   coding->mode &= ~CODING_MODE_LAST_BLOCK;
+  screen_bp = &screen_buf[0];
   while (sl > 0)
     {
       int cf;
-
-      /* Glyphs with GLYPH_MASK_PADDING bit set are actually there
-	 only for the redisplay code to know how many columns does
-         this character occupy on the screen.  Skip padding glyphs.  */
-      if (CHAR_GLYPH_PADDING_P (*str))
-	{
-	  str++;
-	  sl--;
-	}
-      else
+      int n;
+
+      /* If the face of this glyph is different from the current
+	 screen face, update the screen attribute byte.  */
+      cf = str->face_id;
+      if (cf != screen_face)
+	IT_set_face (cf);	/* handles invalid faces gracefully */
+
+      /* Identify a run of glyphs with the same face.  */
+      for (n = 1; n < sl; ++n)
+	if (str[n].face_id != cf)
+	  break;
+
+      if (n >= sl)
+	/* This is the last glyph.  */
+	coding->mode |= CODING_MODE_LAST_BLOCK;
+
+      conversion_buffer = encode_terminal_code (str, n, coding);
+      if (coding->produced > 0)
 	{
-	  /* If the face of this glyph is different from the current
-	     screen face, update the screen attribute byte.  */
-	  cf = str->face_id;
-	  if (cf != screen_face)
-	    IT_set_face (cf);	/* handles invalid faces gracefully */
-
-	  if (sl <= 1)
-	    /* This is the last glyph.  */
-	    coding->mode |= CODING_MODE_LAST_BLOCK;
-
-	  conversion_buffer = encode_terminal_code (str, 1, coding);
-	  if (coding->produced > 0)
+	  /* Copy the encoded bytes to the screen buffer.  */
+	  for (bp = conversion_buffer; coding->produced--; bp++)
 	    {
-	      if (2*coding->produced > screen_buf_end - screen_bp)
+	      /* Paranoia: discard bytes that would overrun the end of
+		 the screen buffer.  */
+	      if (screen_bp - screen_buf <= MAX_SCREEN_BUF - 2)
 		{
-		  /* The allocated buffer for screen writes is too small.
-		     Flush it and loop again without incrementing STR, so
-		     that the next loop will begin with the same glyph.  */
-		  int nbytes = screen_bp - screen_buf;
-
-		  mouse_off_maybe ();
-		  dosmemput (screen_buf, nbytes, (int)ScreenPrimary + offset);
-		  if (screen_virtual_segment)
-		    dosv_refresh_virtual_screen (offset, nbytes / 2);
-		  new_pos_X += nbytes / 2;
-		  offset += nbytes;
-
-		  /* Prepare to reuse the same buffer again.  */
-		  screen_bp = screen_buf;
-		  continue;
+		  *screen_bp++ = (unsigned char)*bp;
+		  *screen_bp++ = ScreenAttrib;
 		}
-	      else
-		{
-		  /* There's enough place in the allocated buffer to add
-		     the encoding of this glyph.  */
-
-		  /* Copy the encoded bytes to the allocated buffer.  */
-		  for (bp = conversion_buffer; coding->produced--; bp++)
-		    {
-		      *screen_bp++ = (unsigned char)*bp;
-		      *screen_bp++ = ScreenAttrib;
-		      if (tty->termscript)
-			fputc (*bp, tty->termscript);
-		    }
-		}
+	      if (tty->termscript)
+		fputc (*bp, tty->termscript);
 	    }
-	  /* Update STR and its remaining length.  */
-	  str++;
-	  sl--;
 	}
+      /* Update STR and its remaining length.  */
+      str += n;
+      sl -= n;
     }
 
-  /* Dump whatever is left in the screen buffer.  */
+  /* Dump whatever we have in the screen buffer.  */
   mouse_off_maybe ();
   dosmemput (screen_buf, screen_bp - screen_buf, (int)ScreenPrimary + offset);
   if (screen_virtual_segment)