]> code.delx.au - gnu-emacs/blobdiff - src/dispnew.c
Merge from emacs-23 branch
[gnu-emacs] / src / dispnew.c
index 6ba834ba339b562d0bfd5ff118f109cf74e39da9..9e57bbb28bf8dba49b228560998b0c4d95cc3792 100644 (file)
@@ -1,5 +1,5 @@
 /* Updating of data structures for redisplay.
-   Copyright (C) 1985-1988, 1993-1995, 1997-2011 Free Software Foundation, Inc.
+   Copyright (C) 1985-1988, 1993-1995, 1997-2012 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -62,7 +62,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <errno.h>
 
 /* Get number of chars of output now in the buffer of a stdio stream.
-   This ought to be built in in stdio, but it isn't.  Some s- files
+   This ought to be built in stdio, but it isn't.  Some s- files
    override this because their stdio internals differ.  */
 
 #ifdef __GNU_LIBRARY__
@@ -434,18 +434,7 @@ margin_glyphs_to_reserve (struct window *w, int total_glyphs, Lisp_Object margin
 int
 verify_row_hash (struct glyph_row *row)
 {
-  int area, k;
-  unsigned row_hash = 0;
-
-  for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
-    for (k = 0; k < row->used[area]; ++k)
-      row_hash = ((((row_hash << 4) + (row_hash >> 24)) & 0x0fffffff)
-                 + row->glyphs[area][k].u.val
-                 + row->glyphs[area][k].face_id
-                 + row->glyphs[area][k].padding_p
-                 + (row->glyphs[area][k].type << 2));
-
-  return row_hash == row->hash;
+  return row->hash == row_hash (row);
 }
 #endif
 
@@ -619,7 +608,6 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
                  row->glyphs[LAST_AREA]
                    = row->glyphs[LEFT_MARGIN_AREA] + dim.width;
                }
-             xassert (!row->enabled_p || verify_row_hash (row));
              ++row;
            }
        }
@@ -1083,37 +1071,55 @@ swap_glyphs_in_rows (struct glyph_row *a, struct glyph_row *b)
 
 #endif /* 0 */
 
-/* Exchange pointers to glyph memory between glyph rows A and B.  */
+/* Exchange pointers to glyph memory between glyph rows A and B.  Also
+   exchange the used[] array and the hash values of the rows, because
+   these should all go together for the row's hash value to be
+   correct.  */
 
 static inline void
 swap_glyph_pointers (struct glyph_row *a, struct glyph_row *b)
 {
   int i;
+  unsigned hash_tem = a->hash;
+
   for (i = 0; i < LAST_AREA + 1; ++i)
     {
       struct glyph *temp = a->glyphs[i];
+      short used_tem = a->used[i];
+
       a->glyphs[i] = b->glyphs[i];
       b->glyphs[i] = temp;
+      a->used[i] = b->used[i];
+      b->used[i] = used_tem;
     }
+  a->hash = b->hash;
+  b->hash = hash_tem;
 }
 
 
 /* Copy glyph row structure FROM to glyph row structure TO, except
-   that glyph pointers in the structures are left unchanged.  */
+   that glyph pointers, the `used' counts, and the hash values in the
+   structures are left unchanged.  */
 
 static inline void
 copy_row_except_pointers (struct glyph_row *to, struct glyph_row *from)
 {
   struct glyph *pointers[1 + LAST_AREA];
+  short used[1 + LAST_AREA];
+  unsigned hashval;
 
   /* Save glyph pointers of TO.  */
   memcpy (pointers, to->glyphs, sizeof to->glyphs);
+  memcpy (used, to->used, sizeof to->used);
+  hashval = to->hash;
 
   /* Do a structure assignment.  */
   *to = *from;
 
   /* Restore original pointers of TO.  */
   memcpy (to->glyphs, pointers, sizeof to->glyphs);
+  memcpy (to->used, used, sizeof to->used);
+  to->hash = hashval;
 }
 
 
@@ -3569,12 +3575,11 @@ update_window (struct window *w, int force_p)
 
       rif->update_window_begin_hook (w);
       yb = window_text_bottom_y (w);
-
-      /* If window has a header line, update it before everything else.
-        Adjust y-positions of other rows by the header line height.  */
       row = desired_matrix->rows;
       end = row + desired_matrix->nrows - 1;
 
+      /* Take note of the header line, if there is one.  We will
+        update it below, after updating all of the window's lines.  */
       if (row->mode_line_p)
        {
          header_line_row = row;
@@ -3619,6 +3624,8 @@ update_window (struct window *w, int force_p)
 
       /* Update the rest of the lines.  */
       for (; row < end && (force_p || !input_pending); ++row)
+       /* scrolling_window resets the enabled_p flag of the rows it
+          reuses from current_matrix.  */
        if (row->enabled_p)
          {
            int vpos = MATRIX_ROW_VPOS (row, desired_matrix);
@@ -4233,6 +4240,7 @@ add_row_entry (struct glyph_row *row)
   ptrdiff_t i = row->hash % row_table_size;
 
   entry = row_table[i];
+  xassert (entry || verify_row_hash (row));
   while (entry && !row_equal_p (entry->row, row, 1))
     entry = entry->next;
 
@@ -4543,18 +4551,69 @@ scrolling_window (struct window *w, int header_line_p)
          {
            rif->clear_window_mouse_face (w);
            rif->scroll_run_hook (w, r);
+         }
 
-           /* Invalidate runs that copy from where we copied to.  */
-           for (j = i + 1; j < nruns; ++j)
+       /* Truncate runs that copy to where we copied to, and
+          invalidate runs that copy from where we copied to.  */
+       for (j = nruns - 1; j > i; --j)
+         {
+           struct run *p = runs[j];
+           int truncated_p = 0;
+
+           if (p->nrows > 0
+               && p->desired_y < r->desired_y + r->height
+               && p->desired_y + p->height > r->desired_y)
              {
-               struct run *p = runs[j];
+               if (p->desired_y < r->desired_y)
+                 {
+                   p->nrows = r->desired_vpos - p->desired_vpos;
+                   p->height = r->desired_y - p->desired_y;
+                   truncated_p = 1;
+                 }
+               else
+                 {
+                   int nrows_copied = (r->desired_vpos + r->nrows
+                                       - p->desired_vpos);
+
+                   if (p->nrows <= nrows_copied)
+                     p->nrows = 0;
+                   else
+                     {
+                       int height_copied = (r->desired_y + r->height
+                                            - p->desired_y);
+
+                       p->current_vpos += nrows_copied;
+                       p->desired_vpos += nrows_copied;
+                       p->nrows -= nrows_copied;
+                       p->current_y += height_copied;
+                       p->desired_y += height_copied;
+                       p->height -= height_copied;
+                       truncated_p = 1;
+                     }
+                 }
+             }
 
-               if ((p->current_y >= r->desired_y
+           if (r->current_y != r->desired_y
+               /* The condition below is equivalent to
+                  ((p->current_y >= r->desired_y
                     && p->current_y < r->desired_y + r->height)
-                   || (p->current_y + p->height >= r->desired_y
+                   || (p->current_y + p->height > r->desired_y
                        && (p->current_y + p->height
-                           < r->desired_y + r->height)))
-                 p->nrows = 0;
+                           <= r->desired_y + r->height)))
+                  because we have 0 < p->height <= r->height.  */
+               && p->current_y < r->desired_y + r->height
+               && p->current_y + p->height > r->desired_y)
+             p->nrows = 0;
+
+           /* Reorder runs by copied pixel lines if truncated.  */
+           if (truncated_p && p->nrows > 0)
+             {
+               int k = nruns - 1;
+
+               while (runs[k]->nrows == 0 || runs[k]->height < p->height)
+                 k--;
+               memmove (runs + j, runs + j + 1, (k - j) * sizeof (*runs));
+               runs[k] = p;
              }
          }
 
@@ -4569,7 +4628,14 @@ scrolling_window (struct window *w, int header_line_p)
            to_overlapped_p = to->overlapped_p;
            from->redraw_fringe_bitmaps_p = from->fringe_bitmap_periodic_p;
            assign_row (to, from);
-           to->enabled_p = 1, from->enabled_p = 0;
+           /* The above `assign_row' actually does swap, so if we had
+              an overlap in the copy destination of two runs, then
+              the second run would assign a previously disabled bogus
+              row.  But thanks to the truncation code in the
+              preceding for-loop, we no longer have such an overlap,
+              and thus the assigned row should always be enabled.  */
+           xassert (to->enabled_p);
+           from->enabled_p = 0;
            to->overlapped_p = to_overlapped_p;
          }
       }