emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

variable line spacing


From: Werner LEMBERG
Subject: variable line spacing
Date: Sun, 10 Mar 2002 10:31:14 +0100 (CET)

Here is my preliminary patch for implementing variable line spacing.

  . It defines a buffer/frame variable `line-spacing-no-overlap'.  If
    non-nil, increase line space for lines with over-sized ascents
    and/or descents.

    Currently, it automatically increases the line spacing by one
    pixel above and below for such lines.  Eventually I will make the
    amount configurable.

    Another question: Shall this be a user variable?  I wonder why
    `line-spacing' itself isn't a user variable...

  . I tried to improve the drawing of extra line spacing (set with the
    `line-spacing' variable).  Currently, it looks very ugly if
    line-spacing is set to a large value since it is only applied to
    the descender.  My fix tries to add extra line spacing to both the
    ascent and the descent.

    Nevertheless, my solution isn't completely satisfactory.
    Cf. the places marked with `XXX'.  Gerd, any idea how to handle
    this gracefully?


Please comment.


    Werner


PS: The changes to macfns.c are missing in the patch.

======================================================================

Index: src/buffer.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/buffer.c,v
retrieving revision 1.380
diff -u -r1.380 buffer.c
--- src/buffer.c        4 Mar 2002 23:20:06 -0000       1.380
+++ src/buffer.c        7 Mar 2002 05:39:32 -0000
@@ -646,6 +646,7 @@
   b->enable_multibyte_characters = buffer_defaults.enable_multibyte_characters;
   b->cursor_type = buffer_defaults.cursor_type;
   b->extra_line_spacing = buffer_defaults.extra_line_spacing;
+  b->line_spacing_no_overlap = buffer_defaults.line_spacing_no_overlap;
 
   b->display_error_modiff = 0;
 }
@@ -4824,6 +4825,7 @@
   buffer_defaults.direction_reversed = Qnil;
   buffer_defaults.cursor_type = Qt;
   buffer_defaults.extra_line_spacing = Qnil;
+  buffer_defaults.line_spacing_no_overlap = Qnil;
 
 #ifdef DOS_NT
   buffer_defaults.buffer_file_type = Qnil; /* TEXT */
@@ -4905,6 +4907,7 @@
   XSETFASTINT (buffer_local_flags.header_line_format, idx); ++idx;
   XSETFASTINT (buffer_local_flags.cursor_type, idx); ++idx;
   XSETFASTINT (buffer_local_flags.extra_line_spacing, idx); ++idx;
+  XSETFASTINT (buffer_local_flags.line_spacing_no_overlap, idx); ++idx;
 
   /* Need more room? */
   if (idx >= MAX_PER_BUFFER_VARS)
@@ -5082,6 +5085,11 @@
                     doc: /* Default value of `line-spacing' for buffers that 
don't override it.
 This is the same as (default-value 'line-spacing).  */);
 
+  DEFVAR_LISP_NOPRO ("default-line-spacing-no-overlap",
+                    &buffer_defaults.line_spacing_no_overlap,
+                    doc: /* Default value of `line-spacing-no-overlap' for 
buffers that don't override it.
+This is the same as (default-value 'line-spacing-no-overlap).  */);
+
   DEFVAR_LISP_NOPRO ("default-abbrev-mode",
                     &buffer_defaults.abbrev_mode,
                     doc: /* Default value of `abbrev-mode' for buffers that do 
not override it.
@@ -5613,6 +5621,16 @@
                     &current_buffer->extra_line_spacing, Qnil,
                     doc: /* Additional space to put between lines when 
displaying a buffer.
 The space is measured in pixels, and put below lines on window systems.  */);
+
+  DEFVAR_PER_BUFFER ("line-spacing-no-overlap",
+                    &current_buffer->line_spacing_no_overlap, Qnil,
+                    doc: /* Non-nil means glyph ascenders and descenders won't 
overlap.
+By default, Emacs doesn't increase the line space if it encounters
+glyphs that draw vertically outside of their logical bounds.  This
+can cause overlapping, making the affected glyphs unreadable.
+
+Contrary to `line-spacing', only lines with over-sized glyphs are
+moved apart; other lines are not affected.  */);
 
   DEFVAR_LISP ("kill-buffer-query-functions", &Vkill_buffer_query_functions,
               doc: /* List of functions called with no args to query before 
killing a buffer.  */);
Index: src/buffer.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/buffer.h,v
retrieving revision 1.85
diff -u -r1.85 buffer.h
--- src/buffer.h        10 Jan 2002 11:13:17 -0000      1.85
+++ src/buffer.h        7 Mar 2002 05:39:34 -0000
@@ -743,6 +743,10 @@
   /* An integer > 0 means put that number of pixels below text lines
      in the display of this buffer.  */
   Lisp_Object extra_line_spacing;
+
+  /* True if lines with vertically oversized glyphs should not
+     overlap.  */
+  Lisp_Object line_spacing_no_overlap;
 };
 
 
Index: src/dispextern.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/dispextern.h,v
retrieving revision 1.130
diff -u -r1.130 dispextern.h
--- src/dispextern.h    4 Mar 2002 23:41:00 -0000       1.130
+++ src/dispextern.h    7 Mar 2002 05:39:44 -0000
@@ -1780,8 +1780,12 @@
   int last_visible_y;
 
   /* Additional space in pixels between lines (for window systems
-     only.)  */
+     only).  */
   int extra_line_spacing;
+
+  /* 1 means lines with vertically oversized glyphs don't overlap
+     (for window systems only).  */
+  unsigned line_spacing_no_overlap_p : 1;
 
   /* If non-null, glyphs are produced in glyph_row with each call to
      produce_glyphs.  */
Index: src/frame.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/frame.h,v
retrieving revision 1.95
diff -u -r1.95 frame.h
--- src/frame.h 16 Feb 2002 23:54:04 -0000      1.95
+++ src/frame.h 7 Mar 2002 05:39:46 -0000
@@ -369,6 +369,10 @@
   /* Additional space to put between text lines on this frame.  */
   int extra_line_spacing;
 
+  /* 1 means lines with vertically oversized glyphs don't overlap
+     (for window systems only).  */
+  unsigned line_spacing_no_overlap_p : 1;
+
   /* Set to non-zero in change_frame_size when size of frame changed
      Clear the frame in clear_garbaged_frames if set.  */
   unsigned resized_p : 1;
Index: src/w32fns.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/w32fns.c,v
retrieving revision 1.157
diff -u -r1.157 w32fns.c
--- src/w32fns.c        23 Feb 2002 18:14:06 -0000      1.157
+++ src/w32fns.c        7 Mar 2002 05:40:23 -0000
@@ -692,6 +692,8 @@
 /* TODO: Native Input Method support; see x_create_im.  */
 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_line_spacing_no_overlap P_ ((struct frame *, Lisp_Object,
+                                              Lisp_Object));
 static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
@@ -745,6 +747,7 @@
   {"tool-bar-lines", x_set_tool_bar_lines},
   {"screen-gamma", x_set_screen_gamma},
   {"line-spacing", x_set_line_spacing},
+  {"line-spacing-no-overlap", x_set_line_spacing_no_overlap},
   {"left-fringe", x_set_fringe_width},
   {"right-fringe", x_set_fringe_width},
   {"fullscreen", x_set_fullscreen},
@@ -2018,6 +2021,15 @@
                            Fcons (new_value, Qnil)));
   if (FRAME_VISIBLE_P (f))
     redraw_frame (f);
+}
+
+
+static void
+x_set_line_spacing_no_overlap (f, arg, oldval)
+     struct frame *f;
+     Lisp_Object arg, oldval;
+{
+  f->line_spacing_no_overlap_p = !EQ (Qnil, arg);
 }
 
 
Index: src/xdisp.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xdisp.c,v
retrieving revision 1.735
diff -u -r1.735 xdisp.c
--- src/xdisp.c 6 Mar 2002 14:03:07 -0000       1.735
+++ src/xdisp.c 7 Mar 2002 05:41:00 -0000
@@ -1526,6 +1526,10 @@
        it->extra_line_spacing = XFASTINT (current_buffer->extra_line_spacing);
       else if (it->f->extra_line_spacing > 0)
        it->extra_line_spacing = it->f->extra_line_spacing;
+
+      it->line_spacing_no_overlap_p
+       = (!NILP (current_buffer->line_spacing_no_overlap)
+          || it->f->line_spacing_no_overlap_p);
     }
 
   /* If realized faces have been removed, e.g. because of face
@@ -10818,7 +10822,7 @@
        return 0;
 
       IF_DEBUG (debug_method_add (w, "twu1"));
-      
+
       /* Display up to a row that can be reused.  The variable
         last_text_row is set to the last row displayed that displays
         text.  Note that it.vpos == 0 if or if not there is a
@@ -10827,7 +10831,14 @@
       first_row_y = it.current_y;
       w->cursor.vpos = -1;
       last_text_row = last_reused_text_row = NULL;
-      
+
+      /* XXX: Give up if we have some extra line spacing.  This is not the
+         correct solution, but I couldn't find out how add the ascent part
+         of the extra line spacing to the top row before scrolling (which
+         has been removed in `compute_line_metrics').  */
+      if (it.extra_line_spacing)
+       return 0;
+
       while (it.current_y < it.last_visible_y
             && IT_CHARPOS (it) < CHARPOS (start)
             && !fonts_changed_p)
@@ -11000,6 +11011,13 @@
       xassert (first_row_to_display->y < yb);
       init_to_row_start (&it, w, first_row_to_display);
 
+      /* XXX: Give up if we have some extra line spacing.  This is not the
+         correct solution, but I couldn't find out how remove the ascent
+         part of the extra line spacing in the top row after scrolling
+         (similar to `compute_line_metrics').  */
+      if (it.extra_line_spacing)
+       return 0;
+
       nrows_scrolled = (MATRIX_ROW_VPOS (first_reusable_row, w->current_matrix)
                        - start_vpos);
       it.vpos = (MATRIX_ROW_VPOS (first_row_to_display, w->current_matrix)
@@ -12564,14 +12582,42 @@
       row->overlapping_p = (MATRIX_ROW_OVERLAPS_SUCC_P (row)
                            || MATRIX_ROW_OVERLAPS_PRED_P (row));
 
+      /* If `line_spacing_no_overlap_p' is true, make the row taller
+         for over-sized descents.  */
+      if (row->phys_height - row->phys_ascent > row->height - row->ascent
+         && it->line_spacing_no_overlap_p)
+       row->height += (row->phys_height - row->phys_ascent)
+                      - (row->height - row->ascent)
+                      + 1;
+
+      /* Remove first line's ascent part of the extra line spacing */
+      if (row == MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix))
+       {
+         row->ascent -= it->extra_line_spacing / 2;
+         row->height -= it->extra_line_spacing / 2;
+       }
+
       /* If first line's physical ascent is larger than its logical
          ascent, use the physical ascent, and make the row taller.
-         This makes accented characters fully visible.  */
-      if (row == MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix)
-         && row->phys_ascent > row->ascent)
+         This makes accented characters fully visible.
+         If `line_spacing_no_overlap_p' is true, do this for all
+         affected lines.  */
+      if (row->phys_ascent > row->ascent
+         && (row == MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix)
+             || it->line_spacing_no_overlap_p))
        {
          row->height += row->phys_ascent - row->ascent;
          row->ascent = row->phys_ascent;
+
+         /* Similar to over-sized descents, we add one pixel if
+             `line_spacing_no_overlap_p' is true and we are not
+             in the first row.  */
+         if (row != MATRIX_FIRST_TEXT_ROW (it->w->desired_matrix)
+             && it->line_spacing_no_overlap_p)
+           {
+             row->height += 1;
+             row->ascent += 1;
+           }
        }
 
       /* Compute how much of the line is visible.  */
Index: src/xfns.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xfns.c,v
retrieving revision 1.540
diff -u -r1.540 xfns.c
--- src/xfns.c  3 Mar 2002 20:07:42 -0000       1.540
+++ src/xfns.c  7 Mar 2002 05:41:45 -0000
@@ -736,6 +736,8 @@
 static void x_disable_image P_ ((struct frame *, struct image *));
 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_line_spacing_no_overlap P_ ((struct frame *, Lisp_Object,
+                                              Lisp_Object));
 static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object));
 static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
@@ -808,6 +810,7 @@
   {"scroll-bar-background",    x_set_scroll_bar_background},
   {"screen-gamma",             x_set_screen_gamma},
   {"line-spacing",             x_set_line_spacing},
+  {"line-spacing-no-overlap",  x_set_line_spacing_no_overlap},
   {"left-fringe",              x_set_fringe_width},
   {"right-fringe",             x_set_fringe_width},
   {"wait-for-wm",              x_set_wait_for_wm},
@@ -1423,6 +1426,15 @@
                            Fcons (new_value, Qnil)));
   if (FRAME_VISIBLE_P (f))
     redraw_frame (f);
+}
+
+
+static void
+x_set_line_spacing_no_overlap (f, arg, oldval)
+     struct frame *f;
+     Lisp_Object arg, oldval;
+{
+  f->line_spacing_no_overlap_p = !EQ (Qnil, arg);
 }
 
 
Index: src/xterm.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xterm.c,v
retrieving revision 1.710
diff -u -r1.710 xterm.c
--- src/xterm.c 4 Mar 2002 23:40:59 -0000       1.710
+++ src/xterm.c 7 Mar 2002 05:42:29 -0000
@@ -2323,8 +2323,9 @@
   xassert (it->ascent >= 0 && it->descent >= 0);
   if (it->area == TEXT_AREA)
     it->current_x += it->pixel_width;
-  
-  it->descent += it->extra_line_spacing;
+
+  it->ascent += it->extra_line_spacing / 2;
+  it->descent += it->extra_line_spacing - it->extra_line_spacing / 2;
   
   it->max_ascent = max (it->max_ascent, it->ascent);
   it->max_descent = max (it->max_descent, it->descent);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]