Merged in changes from CVS trunk.
[bpt/emacs.git] / src / xdisp.c
index bb7ce74..67049a1 100644 (file)
@@ -198,8 +198,6 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #ifdef MAC_OS
 #include "macterm.h"
-
-Cursor No_Cursor;
 #endif
 
 #ifndef FRAME_X_OUTPUT
@@ -301,7 +299,10 @@ extern Lisp_Object Qface, Qinvisible, Qwidth;
 Lisp_Object Vdisplay_pixels_per_inch;
 Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
 Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
+Lisp_Object Qslice;
+Lisp_Object Qcenter;
 Lisp_Object Qmargin, Qpointer;
+Lisp_Object Qline_height, Qtotal;
 extern Lisp_Object Qheight;
 extern Lisp_Object QCwidth, QCheight, QCascent;
 extern Lisp_Object Qscroll_bar;
@@ -314,7 +315,7 @@ Lisp_Object Vshow_trailing_whitespace;
 extern Lisp_Object Voverflow_newline_into_fringe;
 
 /* Test if overflow newline into fringe.  Called with iterator IT
-   at or past right window margin, and with IT->current_x set.  */ 
+   at or past right window margin, and with IT->current_x set.  */
 
 #define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it)    \
   (!NILP (Voverflow_newline_into_fringe)       \
@@ -406,7 +407,7 @@ Lisp_Object Vglobal_mode_string;
 
 /* List of variables (symbols) which hold markers for overlay arrows.
    The symbols on this list are examined during redisplay to determine
-   where to display overlay arrows.  */ 
+   where to display overlay arrows.  */
 
 Lisp_Object Voverlay_arrow_variable_list;
 
@@ -792,6 +793,9 @@ int help_echo_pos;
 
 Lisp_Object previous_help_echo_string;
 
+/* Null glyph slice */
+
+static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 };
 
 \f
 /* Function prototypes.  */
@@ -844,8 +848,8 @@ static void insert_left_trunc_glyphs P_ ((struct it *));
 static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *,
                                                          Lisp_Object));
 static void extend_face_to_end_of_line P_ ((struct it *));
-static int append_space P_ ((struct it *, int));
-static int make_cursor_line_fully_visible P_ ((struct window *));
+static int append_space_for_newline P_ ((struct it *, int));
+static int make_cursor_line_fully_visible P_ ((struct window *, int));
 static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int));
 static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
 static int trailing_whitespace_p P_ ((int));
@@ -1230,9 +1234,9 @@ line_bottom_y (it)
    and header-lines heights.  */
 
 int
-pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
+pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
      struct window *w;
-     int charpos, *fully, exact_mode_line_heights_p;
+     int charpos, *fully, *x, *y, exact_mode_line_heights_p;
 {
   struct it it;
   struct text_pos top;
@@ -1280,14 +1284,27 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
          visible_p = 1;
          *fully = bottom_y <= it.last_visible_y;
        }
+      if (visible_p && x)
+       {
+         *x = it.current_x;
+         *y = max (top_y + it.max_ascent - it.ascent, window_top_y);
+       }
     }
   else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
     {
+      struct it it2;
+
+      it2 = it;
       move_it_by_lines (&it, 1, 0);
       if (charpos < IT_CHARPOS (it))
        {
          visible_p = 1;
-         *fully  = 0;
+         if (x)
+           {
+             move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
+             *x = it2.current_x;
+             *y = it2.current_y + it2.max_ascent - it2.ascent;
+           }
        }
     }
 
@@ -1295,6 +1312,7 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
     set_buffer_internal_1 (old_buffer);
 
   current_header_line_height = current_mode_line_height = -1;
+
   return visible_p;
 }
 
@@ -1788,8 +1806,9 @@ get_glyph_string_clip_rect (s, nr)
       height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
       if (height < r.height)
        {
-         r.y = s->ybase + glyph->descent - height;
-         r.height = height;
+         int max_y = r.y + r.height;
+         r.y = min (max_y, s->ybase + glyph->descent - height);
+         r.height = min (max_y - r.y, height);
        }
     }
 
@@ -2048,6 +2067,9 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
     {
       if (NATNUMP (current_buffer->extra_line_spacing))
        it->extra_line_spacing = XFASTINT (current_buffer->extra_line_spacing);
+      else if (FLOATP (current_buffer->extra_line_spacing))
+       it->extra_line_spacing = (XFLOAT_DATA (current_buffer->extra_line_spacing)
+                                 * FRAME_LINE_HEIGHT (it->f));
       else if (it->f->extra_line_spacing > 0)
        it->extra_line_spacing = it->f->extra_line_spacing;
     }
@@ -2061,9 +2083,11 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
   if (FRAME_FACE_CACHE (it->f)->used == 0)
     recompute_basic_faces (it->f);
 
-  /* Current value of the `space-width', and 'height' properties.  */
+  /* Current value of the `slice', `space-width', and 'height' properties.  */
+  it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
   it->space_width = Qnil;
   it->font_height = Qnil;
+  it->override_ascent = -1;
 
   /* Are control characters displayed as `^C'?  */
   it->ctl_arrow_p = !NILP (current_buffer->ctl_arrow);
@@ -2704,19 +2728,10 @@ next_overlay_change (pos)
   int noverlays;
   int endpos;
   Lisp_Object *overlays;
-  int len;
   int i;
 
   /* Get all overlays at the given position.  */
-  len = 10;
-  overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-  noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
-  if (noverlays > len)
-    {
-      len = noverlays;
-      overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-      noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
-    }
+  GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1);
 
   /* If any of these overlays ends before endpos,
      use its ending point instead.  */
@@ -3269,8 +3284,9 @@ handle_display_prop (it)
     }
 
   /* Reset those iterator values set from display property values.  */
-  it->font_height = Qnil;
+  it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
   it->space_width = Qnil;
+  it->font_height = Qnil;
   it->voffset = 0;
 
   /* We don't support recursive `display' properties, i.e. string
@@ -3289,6 +3305,7 @@ handle_display_prop (it)
       && !EQ (XCAR (prop), Qimage)
       && !EQ (XCAR (prop), Qspace)
       && !EQ (XCAR (prop), Qwhen)
+      && !EQ (XCAR (prop), Qslice)
       && !EQ (XCAR (prop), Qspace_width)
       && !EQ (XCAR (prop), Qheight)
       && !EQ (XCAR (prop), Qraise)
@@ -3484,6 +3501,30 @@ handle_single_display_prop (it, prop, object, position,
       if (NUMBERP (value) && XFLOATINT (value) > 0)
        it->space_width = value;
     }
+  else if (CONSP (prop)
+          && EQ (XCAR (prop), Qslice))
+    {
+      /* `(slice X Y WIDTH HEIGHT)'.  */
+      Lisp_Object tem;
+
+      if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+       return 0;
+
+      if (tem = XCDR (prop), CONSP (tem))
+       {
+         it->slice.x = XCAR (tem);
+         if (tem = XCDR (tem), CONSP (tem))
+           {
+             it->slice.y = XCAR (tem);
+             if (tem = XCDR (tem), CONSP (tem))
+               {
+                 it->slice.width = XCAR (tem);
+                 if (tem = XCDR (tem), CONSP (tem))
+                   it->slice.height = XCAR (tem);
+               }
+           }
+       }
+    }
   else if (CONSP (prop)
           && EQ (XCAR (prop), Qraise)
           && CONSP (XCDR (prop)))
@@ -3603,16 +3644,11 @@ handle_single_display_prop (it, prop, object, position,
          value = prop;
        }
 
+      valid_p = (STRINGP (value)
 #ifdef HAVE_WINDOW_SYSTEM
-      if (FRAME_TERMCAP_P (it->f))
-       valid_p = STRINGP (value);
-      else
-       valid_p = (STRINGP (value)
-                  || (CONSP (value) && EQ (XCAR (value), Qspace))
-                  || valid_image_p (value));
-#else /* not HAVE_WINDOW_SYSTEM */
-      valid_p = STRINGP (value);
+                || (!FRAME_TERMCAP_P (it->f) && valid_image_p (value))
 #endif /* not HAVE_WINDOW_SYSTEM */
+                || (CONSP (value) && EQ (XCAR (value), Qspace)));
 
       if ((EQ (location, Qleft_margin)
           || EQ (location, Qright_margin)
@@ -4330,6 +4366,7 @@ push_it (it)
   p->string_nchars = it->string_nchars;
   p->area = it->area;
   p->multibyte_p = it->multibyte_p;
+  p->slice = it->slice;
   p->space_width = it->space_width;
   p->font_height = it->font_height;
   p->voffset = it->voffset;
@@ -4362,6 +4399,7 @@ pop_it (it)
   it->string_nchars = p->string_nchars;
   it->area = p->area;
   it->multibyte_p = p->multibyte_p;
+  it->slice = p->slice;
   it->space_width = p->space_width;
   it->font_height = p->font_height;
   it->voffset = p->voffset;
@@ -4519,6 +4557,14 @@ back_to_previous_visible_line_start (it)
            visible_p = 0;
        }
 
+      if (visible_p)
+       {
+         struct it it2 = *it;
+
+         if (handle_display_prop (&it2) == HANDLED_RETURN)
+           visible_p = 0;
+       }
+
       /* Back one more newline if the current one is invisible.  */
       if (!visible_p)
        back_to_previous_line_start (it);
@@ -5594,15 +5640,18 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
   saved_glyph_row = it->glyph_row;
   it->glyph_row = NULL;
 
+#define BUFFER_POS_REACHED_P()                     \
+  ((op & MOVE_TO_POS) != 0                         \
+   && BUFFERP (it->object)                         \
+   && IT_CHARPOS (*it) >= to_charpos)
+
   while (1)
     {
       int x, i, ascent = 0, descent = 0;
 
       /* Stop when ZV or TO_CHARPOS reached.  */
       if (!get_next_display_element (it)
-         || ((op & MOVE_TO_POS) != 0
-             && BUFFERP (it->object)
-             && IT_CHARPOS (*it) >= to_charpos))
+         || BUFFER_POS_REACHED_P ())
        {
          result = MOVE_POS_MATCH_OR_ZV;
          break;
@@ -5689,7 +5738,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
 #ifdef HAVE_WINDOW_SYSTEM
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
-                             if (!get_next_display_element (it))
+                             if (!get_next_display_element (it)
+                                 || BUFFER_POS_REACHED_P ())
                                {
                                  result = MOVE_POS_MATCH_OR_ZV;
                                  break;
@@ -5761,7 +5811,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
 #ifdef HAVE_WINDOW_SYSTEM
          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
            {
-             if (!get_next_display_element (it))
+             if (!get_next_display_element (it)
+                 || BUFFER_POS_REACHED_P ())
                {
                  result = MOVE_POS_MATCH_OR_ZV;
                  break;
@@ -5778,6 +5829,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
        }
     }
 
+#undef BUFFER_POS_REACHED_P
+
   /* Restore the iterator settings altered at the beginning of this
      function.  */
   it->glyph_row = saved_glyph_row;
@@ -8360,7 +8413,7 @@ update_tool_bar (f, save_match_data)
          /* Redisplay the tool-bar if we changed it.  */
          if (! NILP (Fequal (old_tool_bar, f->tool_bar_items)))
            w->update_mode_line = Qt;
-         
+
          UNGCPRO;
 
          unbind_to (count, Qnil);
@@ -9420,7 +9473,7 @@ update_overlay_arrows (up_to_date)
       if (!SYMBOLP (var))
        continue;
 
-      if (up_to_date)
+      if (up_to_date > 0)
        {
          Lisp_Object val = find_symbol_value (var);
          Fput (var, Qlast_arrow_position,
@@ -9459,7 +9512,7 @@ overlay_arrow_at_row (f, row, pbitmap)
        continue;
 
       val = find_symbol_value (var);
-      
+
       if (MARKERP (val)
          && current_buffer == XMARKER (val)->buffer
          && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
@@ -10726,12 +10779,17 @@ run_window_scroll_functions (window, startp)
    A value of 1 means there is nothing to be done.
    (Either the line is fully visible, or it cannot be made so,
    or we cannot tell.)
+
+   If FORCE_P is non-zero, return 0 even if partial visible cursor row
+   is higher than window.
+
    A value of 0 means the caller should do scrolling
    as if point had gone off the screen.  */
 
 static int
-make_cursor_line_fully_visible (w)
+make_cursor_line_fully_visible (w, force_p)
      struct window *w;
+     int force_p;
 {
   struct glyph_matrix *matrix;
   struct glyph_row *row;
@@ -10753,8 +10811,10 @@ make_cursor_line_fully_visible (w)
      it's not clear what to do, so do nothing.  */
   window_height = window_box_height (w);
   if (row->height >= window_height)
-    return 1;
-
+    {
+      if (!force_p || w->vscroll)
+       return 1;
+    }
   return 0;
 
 #if 0
@@ -10845,7 +10905,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   int amount_to_scroll = 0;
   Lisp_Object aggressive;
   int height;
-  int end_scroll_margin;
+  int extra_scroll_margin_lines = last_line_misfit ? 1 : 0;
 
 #if GLYPH_DEBUG
   debug_method_add (w, "try_scrolling");
@@ -10863,6 +10923,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   else
     this_scroll_margin = 0;
 
+  /* Force scroll_conservatively to have a reasonable value so it doesn't
+     cause an overflow while computing how much to scroll.  */
+  if (scroll_conservatively)
+    scroll_conservatively = min (scroll_conservatively,
+                                 MOST_POSITIVE_FIXNUM / FRAME_LINE_HEIGHT (f));
+
   /* Compute how much we should try to scroll maximally to bring point
      into view.  */
   if (scroll_step || scroll_conservatively || temp_scroll_step)
@@ -10888,11 +10954,13 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   CHARPOS (scroll_margin_pos) = XINT (window_end);
   BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos));
 
-  end_scroll_margin = this_scroll_margin + !!last_line_misfit;
-  if (end_scroll_margin)
+  if (this_scroll_margin || extra_scroll_margin_lines)
     {
       start_display (&it, w, scroll_margin_pos);
-      move_it_vertically (&it, - end_scroll_margin);
+      if (this_scroll_margin)
+       move_it_vertically (&it, - this_scroll_margin);
+      if (extra_scroll_margin_lines)
+       move_it_by_lines (&it, - extra_scroll_margin_lines, 0);
       scroll_margin_pos = it.current.pos;
     }
 
@@ -10936,7 +11004,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
          aggressive = current_buffer->scroll_up_aggressively;
          height = WINDOW_BOX_TEXT_HEIGHT (w);
          if (NUMBERP (aggressive))
-           amount_to_scroll = XFLOATINT (aggressive) * height;
+           {
+             double float_amount = XFLOATINT (aggressive) * height;
+             amount_to_scroll = float_amount;
+             if (amount_to_scroll == 0 && float_amount > 0)
+               amount_to_scroll = 1;
+           }
        }
 
       if (amount_to_scroll <= 0)
@@ -10994,7 +11067,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
              aggressive = current_buffer->scroll_down_aggressively;
              height = WINDOW_BOX_TEXT_HEIGHT (w);
              if (NUMBERP (aggressive))
-               amount_to_scroll = XFLOATINT (aggressive) * height;
+               {
+                 double float_amount = XFLOATINT (aggressive) * height;
+                 amount_to_scroll = float_amount;
+                 if (amount_to_scroll == 0 && float_amount > 0)
+                   amount_to_scroll = 1;
+               }
            }
 
          if (amount_to_scroll <= 0)
@@ -11027,10 +11105,10 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
-      if (! make_cursor_line_fully_visible (w))
+      if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1))
        {
          clear_glyph_matrix (w->desired_matrix);
-         last_line_misfit = 1;
+         ++extra_scroll_margin_lines;
          goto too_near_end;
        }
       rc = SCROLLING_SUCCESS;
@@ -11319,7 +11397,7 @@ try_cursor_movement (window, startp, scroll_step)
              else
                {
                  set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
-                 if (!make_cursor_line_fully_visible (w))
+                 if (!make_cursor_line_fully_visible (w, 0))
                    rc = CURSOR_MOVEMENT_MUST_SCROLL;
                  else
                    rc = CURSOR_MOVEMENT_SUCCESS;
@@ -11349,7 +11427,7 @@ set_vertical_scroll_bar (w)
      which reflect the whole buffer size, with special markers
      indicating narrowing, and scrollbars which reflect only the
      visible region.
-     
+
      Note that mini-buffers sometimes aren't displaying any text.  */
   if (!MINI_WINDOW_P (w)
       || (w == XWINDOW (minibuf_window)
@@ -11361,7 +11439,7 @@ set_vertical_scroll_bar (w)
       /* I don't think this is guaranteed to be right.  For the
         moment, we'll pretend it is.  */
       end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf);
-      
+
       if (end < start)
        end = start;
       if (whole < (end - start))
@@ -11652,7 +11730,7 @@ redisplay_window (window, just_this_one_p)
          new_vpos = window_box_height (w) / 2;
        }
 
-      if (!make_cursor_line_fully_visible (w))
+      if (!make_cursor_line_fully_visible (w, 0))
        {
          /* Point does appear, but on a line partly visible at end of window.
             Move it back to a fully-visible line.  */
@@ -11789,7 +11867,7 @@ redisplay_window (window, just_this_one_p)
            /* Forget any recorded base line for line number display.  */
            w->base_line_number = Qnil;
 
-         if (!make_cursor_line_fully_visible (w))
+         if (!make_cursor_line_fully_visible (w, 1))
            {
              clear_glyph_matrix (w->desired_matrix);
              last_line_misfit = 1;
@@ -11949,7 +12027,7 @@ redisplay_window (window, just_this_one_p)
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
 
-  if (!make_cursor_line_fully_visible (w))
+  if (!make_cursor_line_fully_visible (w, centering_position > 0))
     {
       /* If vscroll is enabled, disable it and try again.  */
       if (w->vscroll)
@@ -11962,6 +12040,7 @@ redisplay_window (window, just_this_one_p)
       /* If centering point failed to make the whole line visible,
         put point at the top instead.  That has to make the whole line
         visible, if it can be done.  */
+      clear_glyph_matrix (w->desired_matrix);
       centering_position = 0;
       goto point_at_top;
     }
@@ -13332,36 +13411,36 @@ try_window_id (w)
            {
              /* Scroll last_unchanged_at_beg_row to the end of the
                 window down dvpos lines.  */
-             set_terminal_window (end);
+             set_terminal_window (f, end);
 
              /* On dumb terminals delete dvpos lines at the end
                 before inserting dvpos empty lines.  */
              if (!FRAME_SCROLL_REGION_OK (f))
-               ins_del_lines (end - dvpos, -dvpos);
+               ins_del_lines (f, end - dvpos, -dvpos);
 
              /* Insert dvpos empty lines in front of
                  last_unchanged_at_beg_row.  */
-             ins_del_lines (from, dvpos);
+             ins_del_lines (f, from, dvpos);
            }
          else if (dvpos < 0)
            {
              /* Scroll up last_unchanged_at_beg_vpos to the end of
                 the window to last_unchanged_at_beg_vpos - |dvpos|.  */
-             set_terminal_window (end);
+             set_terminal_window (f, end);
 
              /* Delete dvpos lines in front of
                 last_unchanged_at_beg_vpos.  ins_del_lines will set
                 the cursor to the given vpos and emit |dvpos| delete
                 line sequences.  */
-             ins_del_lines (from + dvpos, dvpos);
+             ins_del_lines (f, from + dvpos, dvpos);
 
              /* On a dumb terminal insert dvpos empty lines at the
                  end.  */
              if (!FRAME_SCROLL_REGION_OK (f))
-               ins_del_lines (end + dvpos, -dvpos);
+               ins_del_lines (f, end + dvpos, -dvpos);
            }
 
-         set_terminal_window (0);
+         set_terminal_window (f, 0);
        }
 
       update_end (f);
@@ -14080,8 +14159,7 @@ compute_line_metrics (it)
 
 
 /* Append one space to the glyph row of iterator IT if doing a
-   window-based redisplay.  DEFAULT_FACE_P non-zero means let the
-   space have the default face, otherwise let it have the same face as
+   window-based redisplay.  The space has the same face as
    IT->face_id.  Value is non-zero if a space was added.
 
    This function is called to make sure that there is always one glyph
@@ -14093,7 +14171,7 @@ compute_line_metrics (it)
    end of the line if the row ends in italic text.  */
 
 static int
-append_space (it, default_face_p)
+append_space_for_newline (it, default_face_p)
      struct it *it;
      int default_face_p;
 {
@@ -14107,7 +14185,7 @@ append_space (it, default_face_p)
          /* Save some values that must not be changed.
             Must save IT->c and IT->len because otherwise
             ITERATOR_AT_END_P wouldn't work anymore after
-            append_space has been called.  */
+            append_space_for_newline has been called.  */
          enum display_element_type saved_what = it->what;
          int saved_c = it->c, saved_len = it->len;
          int saved_x = it->current_x;
@@ -14134,6 +14212,8 @@ append_space (it, default_face_p)
 
          PRODUCE_GLYPHS (it);
 
+         it->override_ascent = -1;
+         it->constrain_row_ascent_descent_p = 0;
          it->current_x = saved_x;
          it->object = saved_object;
          it->position = saved_pos;
@@ -14415,7 +14495,7 @@ display_line (it)
            row->exact_window_width_line_p = 1;
          else
 #endif /* HAVE_WINDOW_SYSTEM */
-         if ((append_space (it, 1) && row->used[TEXT_AREA] == 1)
+         if ((append_space_for_newline (it, 1) && row->used[TEXT_AREA] == 1)
              || row->used[TEXT_AREA] == 0)
            {
              row->glyphs[TEXT_AREA]->charpos = -1;
@@ -14657,7 +14737,7 @@ display_line (it)
          /* Add a space at the end of the line that is used to
             display the cursor there.  */
          if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
-           append_space (it, 0);
+           append_space_for_newline (it, 0);
 #endif /* HAVE_WINDOW_SYSTEM */
 
          /* Extend the face to the end of the line.  */
@@ -15064,6 +15144,8 @@ display_mode_line (w, face_id, format)
   init_iterator (&it, w, -1, -1, NULL, face_id);
   prepare_desired_row (it.glyph_row);
 
+  it.glyph_row->mode_line_p = 1;
+
   if (! mode_line_inverse_video)
     /* Force the mode-line to be displayed in the default face.  */
     it.base_face_id = it.face_id = DEFAULT_FACE_ID;
@@ -15080,7 +15162,6 @@ display_mode_line (w, face_id, format)
 
   compute_line_metrics (&it);
   it.glyph_row->full_width_p = 1;
-  it.glyph_row->mode_line_p = 1;
   it.glyph_row->continued_p = 0;
   it.glyph_row->truncated_on_left_p = 0;
   it.glyph_row->truncated_on_right_p = 0;
@@ -16292,8 +16373,8 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
          {
            /* No need to mention EOL here--the terminal never needs
               to do EOL conversion.  */
-           p = decode_mode_spec_coding (keyboard_coding.symbol, p, 0);
-           p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
+           p = decode_mode_spec_coding (FRAME_KEYBOARD_CODING (f)->symbol, p, 0);
+           p = decode_mode_spec_coding (FRAME_TERMINAL_CODING (f)->symbol, p, 0);
          }
        p = decode_mode_spec_coding (b->buffer_file_coding_system,
                                     p, eol_flag);
@@ -16694,6 +16775,252 @@ invisible_p (propval, list)
   return 0;
 }
 
+/* Calculate a width or height in pixels from a specification using
+   the following elements:
+
+   SPEC ::=
+     NUM      - a (fractional) multiple of the default font width/height
+     (NUM)    - specifies exactly NUM pixels
+     UNIT     - a fixed number of pixels, see below.
+     ELEMENT  - size of a display element in pixels, see below.
+     (NUM . SPEC) - equals NUM * SPEC
+     (+ SPEC SPEC ...)  - add pixel values
+     (- SPEC SPEC ...)  - subtract pixel values
+     (- SPEC)           - negate pixel value
+
+   NUM ::=
+     INT or FLOAT   - a number constant
+     SYMBOL         - use symbol's (buffer local) variable binding.
+
+   UNIT ::=
+     in       - pixels per inch  *)
+     mm       - pixels per 1/1000 meter  *)
+     cm       - pixels per 1/100 meter   *)
+     width    - width of current font in pixels.
+     height   - height of current font in pixels.
+
+     *) using the ratio(s) defined in display-pixels-per-inch.
+
+   ELEMENT ::=
+
+     left-fringe          - left fringe width in pixels
+     right-fringe         - right fringe width in pixels
+
+     left-margin          - left margin width in pixels
+     right-margin         - right margin width in pixels
+
+     scroll-bar           - scroll-bar area width in pixels
+
+   Examples:
+
+   Pixels corresponding to 5 inches:
+     (5 . in)
+
+   Total width of non-text areas on left side of window (if scroll-bar is on left):
+     '(space :width (+ left-fringe left-margin scroll-bar))
+
+   Align to first text column (in header line):
+     '(space :align-to 0)
+
+   Align to middle of text area minus half the width of variable `my-image'
+   containing a loaded image:
+     '(space :align-to (0.5 . (- text my-image)))
+
+   Width of left margin minus width of 1 character in the default font:
+     '(space :width (- left-margin 1))
+
+   Width of left margin minus width of 2 characters in the current font:
+     '(space :width (- left-margin (2 . width)))
+
+   Center 1 character over left-margin (in header line):
+     '(space :align-to (+ left-margin (0.5 . left-margin) -0.5))
+
+   Different ways to express width of left fringe plus left margin minus one pixel:
+     '(space :width (- (+ left-fringe left-margin) (1)))
+     '(space :width (+ left-fringe left-margin (- (1))))
+     '(space :width (+ left-fringe left-margin (-1)))
+
+*/
+
+#define NUMVAL(X)                              \
+     ((INTEGERP (X) || FLOATP (X))             \
+      ? XFLOATINT (X)                          \
+      : - 1)
+
+int
+calc_pixel_width_or_height (res, it, prop, font, width_p, align_to)
+     double *res;
+     struct it *it;
+     Lisp_Object prop;
+     void *font;
+     int width_p, *align_to;
+{
+  double pixels;
+
+#define OK_PIXELS(val) ((*res = (double)(val)), 1)
+#define OK_ALIGN_TO(val) ((*align_to = (int)(val)), 1)
+
+  if (NILP (prop))
+    return OK_PIXELS (0);
+
+  if (SYMBOLP (prop))
+    {
+      if (SCHARS (SYMBOL_NAME (prop)) == 2)
+       {
+         char *unit =  SDATA (SYMBOL_NAME (prop));
+
+         if (unit[0] == 'i' && unit[1] == 'n')
+           pixels = 1.0;
+         else if (unit[0] == 'm' && unit[1] == 'm')
+           pixels = 25.4;
+         else if (unit[0] == 'c' && unit[1] == 'm')
+           pixels = 2.54;
+         else
+           pixels = 0;
+         if (pixels > 0)
+           {
+             double ppi;
+             if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
+                 || (CONSP (Vdisplay_pixels_per_inch)
+                     && (ppi = (width_p
+                                ? NUMVAL (XCAR (Vdisplay_pixels_per_inch))
+                                : NUMVAL (XCDR (Vdisplay_pixels_per_inch))),
+                         ppi > 0)))
+               return OK_PIXELS (ppi / pixels);
+
+             return 0;
+           }
+       }
+
+#ifdef HAVE_WINDOW_SYSTEM
+      if (EQ (prop, Qheight))
+       return OK_PIXELS (font ? FONT_HEIGHT ((XFontStruct *)font) : FRAME_LINE_HEIGHT (it->f));
+      if (EQ (prop, Qwidth))
+       return OK_PIXELS (font ? FONT_WIDTH ((XFontStruct *)font) : FRAME_COLUMN_WIDTH (it->f));
+#else
+      if (EQ (prop, Qheight) || EQ (prop, Qwidth))
+       return OK_PIXELS (1);
+#endif
+
+      if (EQ (prop, Qtext))
+         return OK_PIXELS (width_p
+                           ? window_box_width (it->w, TEXT_AREA)
+                           : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w));
+
+      if (align_to && *align_to < 0)
+       {
+         *res = 0;
+         if (EQ (prop, Qleft))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA));
+         if (EQ (prop, Qright))
+           return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA));
+         if (EQ (prop, Qcenter))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
+                               + window_box_width (it->w, TEXT_AREA) / 2);
+         if (EQ (prop, Qleft_fringe))
+           return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+                               ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w)
+                               : window_box_right_offset (it->w, LEFT_MARGIN_AREA));
+         if (EQ (prop, Qright_fringe))
+           return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+                               ? window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
+                               : window_box_right_offset (it->w, TEXT_AREA));
+         if (EQ (prop, Qleft_margin))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA));
+         if (EQ (prop, Qright_margin))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA));
+         if (EQ (prop, Qscroll_bar))
+           return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
+                               ? 0
+                               : (window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
+                                  + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+                                     ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
+                                     : 0)));
+       }
+      else
+       {
+         if (EQ (prop, Qleft_fringe))
+           return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w));
+         if (EQ (prop, Qright_fringe))
+           return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w));
+         if (EQ (prop, Qleft_margin))
+           return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w));
+         if (EQ (prop, Qright_margin))
+           return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w));
+         if (EQ (prop, Qscroll_bar))
+           return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
+       }
+
+      prop = Fbuffer_local_value (prop, it->w->buffer);
+    }
+
+  if (INTEGERP (prop) || FLOATP (prop))
+    {
+      int base_unit = (width_p
+                      ? FRAME_COLUMN_WIDTH (it->f)
+                      : FRAME_LINE_HEIGHT (it->f));
+      return OK_PIXELS (XFLOATINT (prop) * base_unit);
+    }
+
+  if (CONSP (prop))
+    {
+      Lisp_Object car = XCAR (prop);
+      Lisp_Object cdr = XCDR (prop);
+
+      if (SYMBOLP (car))
+       {
+#ifdef HAVE_WINDOW_SYSTEM
+         if (valid_image_p (prop))
+           {
+             int id = lookup_image (it->f, prop);
+             struct image *img = IMAGE_FROM_ID (it->f, id);
+
+             return OK_PIXELS (width_p ? img->width : img->height);
+           }
+#endif
+         if (EQ (car, Qplus) || EQ (car, Qminus))
+           {
+             int first = 1;
+             double px;
+
+             pixels = 0;
+             while (CONSP (cdr))
+               {
+                 if (!calc_pixel_width_or_height (&px, it, XCAR (cdr),
+                                                  font, width_p, align_to))
+                   return 0;
+                 if (first)
+                   pixels = (EQ (car, Qplus) ? px : -px), first = 0;
+                 else
+                   pixels += px;
+                 cdr = XCDR (cdr);
+               }
+             if (EQ (car, Qminus))
+               pixels = -pixels;
+             return OK_PIXELS (pixels);
+           }
+
+         car = Fbuffer_local_value (car, it->w->buffer);
+       }
+
+      if (INTEGERP (car) || FLOATP (car))
+       {
+         double fact;
+         pixels = XFLOATINT (car);
+         if (NILP (cdr))
+           return OK_PIXELS (pixels);
+         if (calc_pixel_width_or_height (&fact, it, cdr,
+                                         font, width_p, align_to))
+           return OK_PIXELS (pixels * fact);
+         return 0;
+       }
+
+      return 0;
+    }
+
+  return 0;
+}
+
 \f
 /***********************************************************************
                             Glyph Display
@@ -17033,6 +17360,7 @@ fill_image_glyph_string (s)
   xassert (s->first_glyph->type == IMAGE_GLYPH);
   s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
   xassert (s->img);
+  s->slice = s->first_glyph->slice;
   s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
   s->font = s->face->font;
   s->width = s->first_glyph->pixel_width;
@@ -17777,6 +18105,7 @@ append_glyph (it)
       glyph->glyph_not_available_p = it->glyph_not_available_p;
       glyph->face_id = it->face_id;
       glyph->u.ch = it->char_to_display;
+      glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
@@ -17813,6 +18142,7 @@ append_composite_glyph (it)
       glyph->glyph_not_available_p = 0;
       glyph->face_id = it->face_id;
       glyph->u.cmp_id = it->cmp_id;
+      glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
@@ -17831,7 +18161,7 @@ take_vertical_position_into_account (it)
       if (it->voffset < 0)
        /* Increase the ascent so that we can display the text higher
           in the line.  */
-       it->ascent += abs (it->voffset);
+       it->ascent -= it->voffset;
       else
        /* Increase the descent so that we can display the text lower
           in the line.  */
@@ -17851,6 +18181,7 @@ produce_image_glyph (it)
   struct image *img;
   struct face *face;
   int face_ascent, glyph_ascent;
+  struct glyph_slice slice;
 
   xassert (it->what == IT_IMAGE);
 
@@ -17874,19 +18205,68 @@ produce_image_glyph (it)
   /* Make sure X resources of the image is loaded.  */
   prepare_image_for_display (it->f, img);
 
-  it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face);
-  it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
-  it->pixel_width = img->width + 2 * img->hmargin;
+  slice.x = slice.y = 0;
+  slice.width = img->width;
+  slice.height = img->height;
+
+  if (INTEGERP (it->slice.x))
+    slice.x = XINT (it->slice.x);
+  else if (FLOATP (it->slice.x))
+    slice.x = XFLOAT_DATA (it->slice.x) * img->width;
+
+  if (INTEGERP (it->slice.y))
+    slice.y = XINT (it->slice.y);
+  else if (FLOATP (it->slice.y))
+    slice.y = XFLOAT_DATA (it->slice.y) * img->height;
+
+  if (INTEGERP (it->slice.width))
+    slice.width = XINT (it->slice.width);
+  else if (FLOATP (it->slice.width))
+    slice.width = XFLOAT_DATA (it->slice.width) * img->width;
+
+  if (INTEGERP (it->slice.height))
+    slice.height = XINT (it->slice.height);
+  else if (FLOATP (it->slice.height))
+    slice.height = XFLOAT_DATA (it->slice.height) * img->height;
+
+  if (slice.x >= img->width)
+    slice.x = img->width;
+  if (slice.y >= img->height)
+    slice.y = img->height;
+  if (slice.x + slice.width >= img->width)
+    slice.width = img->width - slice.x;
+  if (slice.y + slice.height > img->height)
+    slice.height = img->height - slice.y;
+
+  if (slice.width == 0 || slice.height == 0)
+    return;
+
+  it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice);
+
+  it->descent = slice.height - glyph_ascent;
+  if (slice.y == 0)
+    it->descent += img->vmargin;
+  if (slice.y + slice.height == img->height)
+    it->descent += img->vmargin;
+  it->phys_descent = it->descent;
+
+  it->pixel_width = slice.width;
+  if (slice.x == 0)
+    it->pixel_width += img->hmargin;
+  if (slice.x + slice.width == img->width)
+    it->pixel_width += img->hmargin;
 
   /* It's quite possible for images to have an ascent greater than
      their height, so don't get confused in that case.  */
   if (it->descent < 0)
     it->descent = 0;
 
+#if 0  /* this breaks image tiling */
   /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent.  */
   face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
   if (face_ascent > it->ascent)
     it->ascent = it->phys_ascent = face_ascent;
+#endif
 
   it->nglyphs = 1;
 
@@ -17894,13 +18274,15 @@ produce_image_glyph (it)
     {
       if (face->box_line_width > 0)
        {
-         it->ascent += face->box_line_width;
-         it->descent += face->box_line_width;
+         if (slice.y == 0)
+           it->ascent += face->box_line_width;
+         if (slice.y + slice.height == img->height)
+           it->descent += face->box_line_width;
        }
 
-      if (it->start_of_box_run_p)
+      if (it->start_of_box_run_p && slice.x == 0)
        it->pixel_width += abs (face->box_line_width);
-      if (it->end_of_box_run_p)
+      if (it->end_of_box_run_p && slice.x + slice.width == img->width)
        it->pixel_width += abs (face->box_line_width);
     }
 
@@ -17929,6 +18311,7 @@ produce_image_glyph (it)
          glyph->glyph_not_available_p = 0;
          glyph->face_id = it->face_id;
          glyph->u.img_id = img->id;
+         glyph->slice = slice;
          glyph->font_type = FONT_TYPE_UNKNOWN;
          ++it->glyph_row->used[area];
        }
@@ -17971,215 +18354,13 @@ append_stretch_glyph (it, object, width, height, ascent)
       glyph->face_id = it->face_id;
       glyph->u.stretch.ascent = ascent;
       glyph->u.stretch.height = height;
+      glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
 }
 
 
-/* Calculate a width or height in pixels from a specification using
-   the following elements:
-
-   SPEC ::= 
-     NUM      - a (fractional) multiple of the default font width/height
-     (NUM)    - specifies exactly NUM pixels
-     UNIT     - a fixed number of pixels, see below.
-     ELEMENT  - size of a display element in pixels, see below.
-     (NUM . SPEC) - equals NUM * SPEC
-     (+ SPEC SPEC ...)  - add pixel values
-     (- SPEC SPEC ...)  - subtract pixel values
-     (- SPEC)           - negate pixel value
-
-   NUM ::= 
-     INT or FLOAT   - a number constant
-     SYMBOL         - use symbol's (buffer local) variable binding.
-
-   UNIT ::=
-     in       - pixels per inch  *)
-     mm       - pixels per 1/1000 meter  *)
-     cm       - pixels per 1/100 meter   *)
-     width    - width of current font in pixels.
-     height   - height of current font in pixels.
-
-     *) using the ratio(s) defined in display-pixels-per-inch.
-
-   ELEMENT ::=
-
-     left-fringe         - left fringe width in pixels
-     (left-fringe . nil) - left fringe width if inside margins, else 0
-     (left-fringe . t)   - left fringe width if outside margins, else 0
-
-     right-fringe         - right fringe width in pixels
-     (right-fringe . nil) - right fringe width if inside margins, else 0
-     (right-fringe . t)   - right fringe width if outside margins, else 0
-
-     left-margin          - left margin width in pixels
-     right-margin         - right margin width in pixels
-
-     scroll-bar           - scroll-bar area width in pixels
-     (scroll-bar . left)  - scroll-bar width if on left, else 0
-     (scroll-bar . right) - scroll-bar width if on right, else 0
-
-   Examples:
-
-   Pixels corresponding to 5 inches:
-     (5 . in)     
-               
-   Total width of non-text areas on left side of window:
-     (+ left-fringe left-margin (scroll-bar . left))
-
-   Total width of fringes if inside display margins:
-     (+ (left-fringe) (right-fringe))
-
-   Width of left margin minus width of 1 character in the default font:
-     (- left-margin 1)
-
-   Width of left margin minus width of 2 characters in the current font:
-     (- left-margin (2 . width))
-
-   Width of left fringe plus left margin minus one pixel:
-     (- (+ left-fringe left-margin) (1))
-     (+ left-fringe left-margin (- (1)))
-     (+ left-fringe left-margin (-1))
-
-*/
-
-#define NUMVAL(X)                              \
-     ((INTEGERP (X) || FLOATP (X))             \
-      ? XFLOATINT (X)                          \
-      : - 1)
-
-static int
-calc_pixel_width_or_height (res, it, prop, font, width_p)
-     double *res;
-     struct it *it;
-     Lisp_Object prop;
-     XFontStruct *font;
-     int width_p;
-{
-  double pixels;
-
-#define OK_PIXELS(val) ((*res = (val)), 1)
-
-  if (SYMBOLP (prop))
-    {
-      if (SCHARS (SYMBOL_NAME (prop)) == 2)
-       {
-         char *unit =  SDATA (SYMBOL_NAME (prop));
-
-         if (unit[0] == 'i' && unit[1] == 'n')
-           pixels = 1.0;
-         else if (unit[0] == 'm' && unit[1] == 'm')
-           pixels = 25.4;
-         else if (unit[0] == 'c' && unit[1] == 'm')
-           pixels = 2.54;
-         else
-           pixels = 0;
-         if (pixels > 0)
-           {
-             double ppi;
-             if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
-                 || (CONSP (Vdisplay_pixels_per_inch)
-                     && (ppi = (width_p
-                                ? NUMVAL (XCAR (Vdisplay_pixels_per_inch))
-                                : NUMVAL (XCDR (Vdisplay_pixels_per_inch))),
-                         ppi > 0)))
-               return OK_PIXELS (ppi / pixels);
-
-             return 0;
-           }
-       }
-
-      if (EQ (prop, Qheight))
-       return OK_PIXELS (font ? FONT_HEIGHT (font) : FRAME_LINE_HEIGHT (it->f));
-      if (EQ (prop, Qwidth))
-       return OK_PIXELS (font ? FONT_WIDTH (font) : FRAME_COLUMN_WIDTH (it->f));
-      if (EQ (prop, Qleft_fringe))
-       return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w));
-      if (EQ (prop, Qright_fringe))
-       return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w));
-      if (EQ (prop, Qleft_margin))
-       return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w));
-      if (EQ (prop, Qright_margin))
-       return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w));
-      if (EQ (prop, Qscroll_bar))
-       return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
-
-      prop = Fbuffer_local_value (prop, it->w->buffer);
-    }
-
-  if (INTEGERP (prop) || FLOATP (prop))
-    {
-      int base_unit = (width_p
-                      ? FRAME_COLUMN_WIDTH (it->f)
-                      : FRAME_LINE_HEIGHT (it->f));
-      return OK_PIXELS (XFLOATINT (prop) * base_unit);
-    }
-
-  if (CONSP (prop))
-    {
-      Lisp_Object car = XCAR (prop);
-      Lisp_Object cdr = XCDR (prop);
-
-      if (SYMBOLP (car))
-       {
-         if (EQ (car, Qplus) || EQ (car, Qminus))
-           {
-             int first = 1;
-             double px;
-
-             pixels = 0;
-             while (CONSP (cdr))
-               {
-                 if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), font, width_p))
-                   return 0;
-                 if (first)
-                   pixels = (EQ (car, Qplus) ? px : -px), first = 0;
-                 else
-                   pixels += px;
-                 cdr = XCDR (cdr);
-               }
-             if (EQ (car, Qminus))
-               pixels = -pixels;
-             return OK_PIXELS (pixels);
-           }
-
-         if (EQ (car, Qleft_fringe))
-           return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
-                              == !NILP (cdr))
-                             ? WINDOW_LEFT_FRINGE_WIDTH (it->w)
-                             : 0);
-         if (EQ (car, Qright_fringe))
-           return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
-                              == !NILP (cdr))
-                             ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
-                             : 0);
-         if (EQ (car, Qscroll_bar))
-           return OK_PIXELS ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
-                               == EQ (cdr, Qleft))
-                              ? WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)
-                              : 0);
-
-         car = Fbuffer_local_value (car, it->w->buffer);
-       }
-
-      if (INTEGERP (car) || FLOATP (car))
-       {
-         double fact;
-         pixels = XFLOATINT (car);
-         if (NILP (cdr))
-           return OK_PIXELS (pixels);
-         if (calc_pixel_width_or_height (&fact, it, cdr, font, width_p))
-           return OK_PIXELS (pixels * fact);
-         return 0;
-       }
-
-      return 0;
-    }
-
-  return 0;
-}
-
 /* Produce a stretch glyph for iterator IT.  IT->object is the value
    of the glyph property displayed.  The value must be a list
    `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
@@ -18217,7 +18398,7 @@ produce_stretch_glyph (it)
 {
   /* (space :width WIDTH :height HEIGHT ...)  */
   Lisp_Object prop, plist;
-  int width = 0, height = 0;
+  int width = 0, height = 0, align_to = -1;
   int zero_width_ok_p = 0, zero_height_ok_p = 0;
   int ascent = 0;
   double tem;
@@ -18232,7 +18413,7 @@ produce_stretch_glyph (it)
 
   /* Compute the width of the stretch.  */
   if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
-      && calc_pixel_width_or_height (&tem, it, prop, font, 1))
+      && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0))
     {
       /* Absolute width `:width WIDTH' specified and valid.  */
       zero_width_ok_p = 1;
@@ -18263,9 +18444,15 @@ produce_stretch_glyph (it)
       width = NUMVAL (prop) * it2.pixel_width;
     }
   else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
-          && calc_pixel_width_or_height (&tem, it, prop, font, 1))
-    {
-      width = max (0, (int)tem - it->current_x);
+          && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to))
+    {
+      if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
+       align_to = (align_to < 0
+                   ? 0
+                   : align_to - window_box_left_offset (it->w, TEXT_AREA));
+      else if (align_to < 0)
+       align_to = window_box_left_offset (it->w, TEXT_AREA);
+      width = max (0, (int)tem + align_to - it->current_x);
       zero_width_ok_p = 1;
     }
   else
@@ -18277,7 +18464,7 @@ produce_stretch_glyph (it)
 
   /* Compute height.  */
   if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
-      && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+      && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
     {
       height = (int)tem;
       zero_height_ok_p = 1;
@@ -18298,7 +18485,7 @@ produce_stretch_glyph (it)
       NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
     ascent = height * NUMVAL (prop) / 100.0;
   else if (!NILP (prop)
-          && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+          && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
     ascent = min (max (0, (int)tem), height);
   else
     ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
@@ -18333,6 +18520,107 @@ produce_stretch_glyph (it)
   take_vertical_position_into_account (it);
 }
 
+/* Calculate line-height and line-spacing properties.
+   An integer value specifies explicit pixel value.
+   A float value specifies relative value to current face height.
+   A cons (float . face-name) specifies relative value to
+   height of specified face font.
+
+   Returns height in pixels, or nil.  */
+
+static Lisp_Object
+calc_line_height_property (it, prop, font, boff, total)
+     struct it *it;
+     Lisp_Object prop;
+     XFontStruct *font;
+     int boff, *total;
+{
+  Lisp_Object position, val;
+  Lisp_Object face_name = Qnil;
+  int ascent, descent, height, override;
+
+  if (STRINGP (it->object))
+    position = make_number (IT_STRING_CHARPOS (*it));
+  else
+    position = make_number (IT_CHARPOS (*it));
+
+  val = Fget_char_property (position, prop, it->object);
+
+  if (NILP (val))
+    return val;
+
+  if (total && CONSP (val) && EQ (XCAR (val), Qtotal))
+    {
+      *total = 1;
+      val = XCDR (val);
+    }
+
+  if (INTEGERP (val))
+    return val;
+
+  if (CONSP (val))
+    {
+      face_name = XCDR (val);
+      val = XCAR (val);
+    }
+  else if (SYMBOLP (val))
+    {
+      face_name = val;
+      val = Qnil;
+    }
+
+  override = EQ (prop, Qline_height);
+
+  if (NILP (face_name))
+    {
+      font = FRAME_FONT (it->f);
+      boff = FRAME_BASELINE_OFFSET (it->f);
+    }
+  else if (EQ (face_name, Qt))
+    {
+      override = 0;
+    }
+  else
+    {
+      int face_id;
+      struct face *face;
+      struct font_info *font_info;
+
+      face_id = lookup_named_face (it->f, face_name, ' ');
+      if (face_id < 0)
+       return make_number (-1);
+
+      face = FACE_FROM_ID (it->f, face_id);
+      font = face->font;
+      if (font == NULL)
+       return make_number (-1);
+
+      font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+      boff = font_info->baseline_offset;
+      if (font_info->vertical_centering)
+       boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+    }
+
+  ascent = FONT_BASE (font) + boff;
+  descent = FONT_DESCENT (font) - boff;
+
+  if (override)
+    {
+      it->override_ascent = ascent;
+      it->override_descent = descent;
+      it->override_boff = boff;
+    }
+
+  height = ascent + descent;
+  if (FLOATP (val))
+    height = (int)(XFLOAT_DATA (val) * height);
+  else if (INTEGERP (val))
+    height *= XINT (val);
+
+  return make_number (height);
+}
+
+
 /* RIF:
    Produce glyphs/get display metrics for the display element IT is
    loaded with.  See the description of struct display_iterator in
@@ -18342,6 +18630,8 @@ void
 x_produce_glyphs (it)
      struct it *it;
 {
+  int extra_line_spacing = it->extra_line_spacing;
+
   it->glyph_not_available_p = 0;
 
   if (it->what == IT_CHARACTER)
@@ -18417,10 +18707,20 @@ x_produce_glyphs (it)
 
          it->nglyphs = 1;
 
-         pcm = FRAME_RIF (it->f)->per_char_metric (font, &char2b,
-                                                    FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
-         it->ascent = FONT_BASE (font) + boff;
-         it->descent = FONT_DESCENT (font) - boff;
+          pcm = FRAME_RIF (it->f)->per_char_metric
+            (font, &char2b, FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
+
+         if (it->override_ascent >= 0)
+           {
+             it->ascent = it->override_ascent;
+             it->descent = it->override_descent;
+             boff = it->override_boff;
+           }
+         else
+           {
+             it->ascent = FONT_BASE (font) + boff;
+             it->descent = FONT_DESCENT (font) - boff;
+           }
 
          if (pcm)
            {
@@ -18431,11 +18731,28 @@ x_produce_glyphs (it)
          else
            {
              it->glyph_not_available_p = 1;
-              it->phys_ascent = FONT_BASE (font) + boff;
-              it->phys_descent = FONT_DESCENT (font) - boff;
+             it->phys_ascent = it->ascent;
+             it->phys_descent = it->descent;
              it->pixel_width = FONT_WIDTH (font);
            }
 
+         if (it->constrain_row_ascent_descent_p)
+           {
+             if (it->descent > it->max_descent)
+               {
+                 it->ascent += it->descent - it->max_descent;
+                 it->descent = it->max_descent;
+               }
+             if (it->ascent > it->max_ascent)
+               {
+                 it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
+                 it->ascent = it->max_ascent;
+               }
+             it->phys_ascent = min (it->phys_ascent, it->ascent);
+             it->phys_descent = min (it->phys_descent, it->descent);
+             extra_line_spacing = 0;
+           }
+
          /* If this is a space inside a region of text with
             `space-width' property, change its width.  */
          stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
@@ -18468,6 +18785,14 @@ x_produce_glyphs (it)
          if (face->overline_p)
            it->ascent += 2;
 
+         if (it->constrain_row_ascent_descent_p)
+           {
+             if (it->ascent > it->max_ascent)
+               it->ascent = it->max_ascent;
+             if (it->descent > it->max_descent)
+               it->descent = it->max_descent;
+           }
+
          take_vertical_position_into_account (it);
 
          /* If we have to actually produce glyphs, do it.  */
@@ -18494,17 +18819,73 @@ x_produce_glyphs (it)
        }
       else if (it->char_to_display == '\n')
        {
-         /* A newline has no width but we need the height of the line.  */
+         /* A newline has no width but we need the height of the line.
+            But if previous part of the line set a height, don't
+            increase that height */
+
+         Lisp_Object height;
+
+         it->override_ascent = -1;
          it->pixel_width = 0;
          it->nglyphs = 0;
-         it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
-         it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
 
-         if (face->box != FACE_NO_BOX
-             && face->box_line_width > 0)
+         height = calc_line_height_property(it, Qline_height, font, boff, 0);
+
+         if (it->override_ascent >= 0)
            {
-             it->ascent += face->box_line_width;
-             it->descent += face->box_line_width;
+             it->ascent = it->override_ascent;
+             it->descent = it->override_descent;
+             boff = it->override_boff;
+           }
+         else
+           {
+             it->ascent = FONT_BASE (font) + boff;
+             it->descent = FONT_DESCENT (font) - boff;
+           }
+
+         if (EQ (height, make_number(0)))
+           {
+             if (it->descent > it->max_descent)
+               {
+                 it->ascent += it->descent - it->max_descent;
+                 it->descent = it->max_descent;
+               }
+             if (it->ascent > it->max_ascent)
+               {
+                 it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
+                 it->ascent = it->max_ascent;
+               }
+             it->phys_ascent = min (it->phys_ascent, it->ascent);
+             it->phys_descent = min (it->phys_descent, it->descent);
+             it->constrain_row_ascent_descent_p = 1;
+             extra_line_spacing = 0;
+           }
+         else
+           {
+             Lisp_Object spacing;
+             int total = 0;
+
+             it->phys_ascent = it->ascent;
+             it->phys_descent = it->descent;
+
+             if ((it->max_ascent > 0 || it->max_descent > 0)
+                 && face->box != FACE_NO_BOX
+                 && face->box_line_width > 0)
+               {
+                 it->ascent += face->box_line_width;
+                 it->descent += face->box_line_width;
+               }
+             if (!NILP (height)
+                 && XINT (height) > it->ascent + it->descent)
+               it->ascent = XINT (height) - it->descent;
+
+             spacing = calc_line_height_property(it, Qline_spacing, font, boff, &total);
+             if (INTEGERP (spacing))
+               {
+                 extra_line_spacing = XINT (spacing);
+                 if (total)
+                   extra_line_spacing -= (it->phys_ascent + it->phys_descent);
+               }
            }
        }
       else if (it->char_to_display == '\t')
@@ -18882,7 +19263,8 @@ x_produce_glyphs (it)
   if (it->area == TEXT_AREA)
     it->current_x += it->pixel_width;
 
-  it->descent += it->extra_line_spacing;
+  if (extra_line_spacing > 0)
+    it->descent += extra_line_spacing;
 
   it->max_ascent = max (it->max_ascent, it->ascent);
   it->max_descent = max (it->max_descent, it->descent);
@@ -19778,7 +20160,7 @@ clear_mouse_face (dpyinfo)
 {
   int cleared = 0;
 
-  if (!NILP (dpyinfo->mouse_face_window))
+  if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window))
     {
       show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
       cleared = 1;
@@ -20143,7 +20525,7 @@ on_hot_spot_p (hot_spot, x, y)
          int x0, y0;
 
          /* Need an even number of coordinates, and at least 3 edges.  */
-         if (n < 6 || n & 1) 
+         if (n < 6 || n & 1)
            return 0;
 
          /* Count edge segments intersecting line from (X,Y) to (X,infinity).
@@ -20193,13 +20575,13 @@ find_hot_spot (map, x, y)
        return XCAR (map);
       map = XCDR (map);
     }
-  
+
   return Qnil;
 }
 
 DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map,
        3, 3, 0,
-       doc: /* Lookup in image map MAP coordinates X and Y.  
+       doc: /* Lookup in image map MAP coordinates X and Y.
 An image map is an alist where each element has the format (AREA ID PLIST).
 An AREA is specified as either a rectangle, a circle, or a polygon:
 A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the
@@ -20213,7 +20595,6 @@ Returns the alist element for the first matching AREA in MAP.  */)
      Lisp_Object map;
      Lisp_Object x, y;
 {
-  int ix, iy;
   if (NILP (map))
     return Qnil;
 
@@ -20253,11 +20634,7 @@ define_frame_cursor1 (f, cursor, pointer)
        cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
     }
 
-#ifndef HAVE_CARBON
   if (cursor != No_Cursor)
-#else
-  if (bcmp (&cursor, &No_Cursor, sizeof (Cursor)))
-#endif
     FRAME_RIF (f)->define_frame_cursor (f, cursor);
 }
 
@@ -20279,7 +20656,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
   Lisp_Object pointer = Qnil;
   int charpos, dx, dy, width, height;
   Lisp_Object string, object = Qnil;
-  Lisp_Object pos, help, image;
+  Lisp_Object pos, help;
 
   if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
     string = mode_line_string (w, area, &x, &y, &charpos,
@@ -20347,7 +20724,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
        pointer = Fget_text_property (pos, Qpointer, string);
 
      /* Change the mouse pointer according to what is under X/Y.  */
-      if (NILP (pointer) && area == ON_MODE_LINE)
+      if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)))
        {
          Lisp_Object map;
          map = Fget_text_property (pos, Qlocal_map, string);
@@ -20458,7 +20835,7 @@ note_mouse_highlight (f, x, y)
       Lisp_Object object;
       Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
       Lisp_Object *overlay_vec = NULL;
-      int len, noverlays;
+      int noverlays;
       struct buffer *obuf;
       int obegv, ozv, same_region;
 
@@ -20474,7 +20851,9 @@ note_mouse_highlight (f, x, y)
              Lisp_Object image_map, hotspot;
              if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
                   !NILP (image_map))
-                 && (hotspot = find_hot_spot (image_map, dx, dy),
+                 && (hotspot = find_hot_spot (image_map,
+                                              glyph->slice.x + dx,
+                                              glyph->slice.y + dy),
                      CONSP (hotspot))
                  && (hotspot = XCDR (hotspot), CONSP (hotspot)))
                {
@@ -20543,19 +20922,8 @@ note_mouse_highlight (f, x, y)
 
       if (BUFFERP (object))
        {
-         /* Put all the overlays we want in a vector in overlay_vec.
-            Store the length in len.  If there are more than 10, make
-            enough space for all, and try again.  */
-         len = 10;
-         overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-         noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
-         if (noverlays > len)
-           {
-             len = noverlays;
-             overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-             noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
-           }
-
+         /* Put all the overlays we want in a vector in overlay_vec.  */
+         GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
          /* Sort overlays into increasing priority order.  */
          noverlays = sort_overlays (overlay_vec, noverlays, w);
        }
@@ -21073,18 +21441,18 @@ phys_cursor_in_rect_p (w, r)
   cursor_glyph = get_phys_cursor_glyph (w);
   if (cursor_glyph)
     {
-      /* r is relative to W's box, but w->phys_cursor.x is relative 
+      /* r is relative to W's box, but w->phys_cursor.x is relative
         to left edge of W's TEXT area.  Adjust it.  */
       cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x;
       cr.y = w->phys_cursor.y;
       cr.width = cursor_glyph->pixel_width;
       cr.height = w->phys_cursor_height;
-      /* ++KFS: W32 version used W32-specific IntersectRect here, but 
+      /* ++KFS: W32 version used W32-specific IntersectRect here, but
         I assume the effect is the same -- and this is portable.  */
       return x_intersect_rectangles (&cr, r, &result);
     }
-  else
-    return 0;
+  /* If we don't understand the format, pretend we're not in the hot-spot.  */
+  return 0;
 }
 
 
@@ -21099,7 +21467,7 @@ x_draw_vertical_border (w)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   
   /* We could do better, if we knew what type of scroll-bar the adjacent
-     windows (on either side) have...  But we don't :-( 
+     windows (on either side) have...  But we don't :-(
      However, I think this works ok.  ++KFS 2003-04-25 */
 
   /* Redraw borders between horizontally adjacent windows.  Don't
@@ -21513,6 +21881,8 @@ syms_of_xdisp ()
   staticpro (&Qspace_width);
   Qraise = intern ("raise");
   staticpro (&Qraise);
+  Qslice = intern ("slice");
+  staticpro (&Qslice);
   Qspace = intern ("space");
   staticpro (&Qspace);
   Qmargin = intern ("margin");
@@ -21523,6 +21893,12 @@ syms_of_xdisp ()
   staticpro (&Qleft_margin);
   Qright_margin = intern ("right-margin");
   staticpro (&Qright_margin);
+  Qcenter = intern ("center");
+  staticpro (&Qcenter);
+  Qline_height = intern ("line-height");
+  staticpro (&Qline_height);
+  Qtotal = intern ("total");
+  staticpro (&Qtotal);
   QCalign_to = intern (":align-to");
   staticpro (&QCalign_to);
   QCrelative_width = intern (":relative-width");
@@ -21588,7 +21964,9 @@ syms_of_xdisp ()
   Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces");
   staticpro (&Qinhibit_free_realized_faces);
 
-  list_of_error = Fcons (intern ("error"), Qnil);
+  list_of_error = Fcons (Fcons (intern ("error"),
+                               Fcons (intern ("void-variable"), Qnil)),
+                        Qnil);
   staticpro (&list_of_error);
 
   Qlast_arrow_position = intern ("last-arrow-position");
@@ -21644,7 +22022,7 @@ The face used for trailing whitespace is `trailing-whitespace'.  */);
   DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer,
     doc: /* *The pointer shape to show in void text areas.
 Nil means to show the text pointer.  Other options are `arrow', `text',
-`hand', `vdrag', `hdrag', `modeline', and `hourglass'.  */); 
+`hand', `vdrag', `hdrag', `modeline', and `hourglass'.  */);
   Vvoid_text_area_pointer = Qarrow;
 
   DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,