changeset 55029:01ecdd56871c

(Qslice): New variable. (syms_of_xdisp): Intern and staticpro it. (pos_visible_p): Return pixel position in new x and y args. (init_iterator): Reset it->slice info. (handle_display_prop): Parse (slice ...) property. (push_it, pop_it): Save/restore slice info. (make_cursor_line_fully_visible): Fix 2004-04-14 change. Do not force repositioning of tall row if window is vscrolled, as that would reset vscroll. (append_space): Set it->constrain_row_ascent_descent_p to avoid increasing row height if row is non-empty. (fill_image_glyph_string): Copy slice info. (take_vertical_position_into_account): Simplify. (produce_image_glyph): Handle iterator slice info, setup glyph slice info. Do not force minimum line height. (x_produce_glyphs): If it->constrain_row_ascent_descent_p is set, do not increase height (ascent/descent) of non-empty row when adding normal character glyph; instead reduce glyph ascent/descent appropriately; if row is higher than current glyph, adjust glyph descent/ascent to reposition glyph within the existing row. Likewise, when char is newline, only set ascent/descent if row is currently empty. (note_mouse_highlight): Handle hotspots with sliced image.
author Kim F. Storm <storm@cua.dk>
date Tue, 20 Apr 2004 22:19:09 +0000
parents 0f5f3d0c5f4c
children 44eb66585062
files src/xdisp.c
diffstat 1 files changed, 177 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/src/xdisp.c	Tue Apr 20 22:18:43 2004 +0000
+++ b/src/xdisp.c	Tue Apr 20 22:19:09 2004 +0000
@@ -301,6 +301,7 @@
 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;
 extern Lisp_Object Qheight;
@@ -1235,9 +1236,9 @@
    and header-lines heights.  */
 
 int
-pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
-     struct window *w;
-     int 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, *x, *y, exact_mode_line_heights_p;
 {
   struct it it;
   struct text_pos top;
@@ -1285,14 +1286,27 @@
 	  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;
+	    }
 	}
     }
 
@@ -1300,6 +1314,7 @@
     set_buffer_internal_1 (old_buffer);
 
   current_header_line_height = current_mode_line_height = -1;
+
   return visible_p;
 }
 
@@ -2067,7 +2082,8 @@
   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;
 
@@ -3275,8 +3291,9 @@
     }
 
   /* Reset those iterator values set from display property values.  */
+  it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
+  it->space_width = Qnil;
   it->font_height = Qnil;
-  it->space_width = Qnil;
   it->voffset = 0;
 
   /* We don't support recursive `display' properties, i.e. string
@@ -3295,6 +3312,7 @@
       && !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)
@@ -3491,6 +3509,30 @@
 	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)))
     {
@@ -4331,6 +4373,7 @@
   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;
@@ -4363,6 +4406,7 @@
   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;
@@ -10762,15 +10806,14 @@
   if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
     return 1;
 
-  if (force_p)
-    return 0;
-
   /* If the row the cursor is in is taller than the window's height,
      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
@@ -14154,8 +14197,12 @@
 	  face = FACE_FROM_ID (it->f, it->face_id);
 	  it->face_id = FACE_FOR_CHAR (it->f, face, 0);
 
+	  if (it->max_ascent > 0 || it->max_descent > 0)
+	    it->constrain_row_ascent_descent_p = 1;
+
 	  PRODUCE_GLYPHS (it);
 
+	  it->constrain_row_ascent_descent_p = 0;
 	  it->current_x = saved_x;
 	  it->object = saved_object;
 	  it->position = saved_pos;
@@ -17302,6 +17349,7 @@
   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;
@@ -18100,7 +18148,7 @@
       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.  */
@@ -18120,6 +18168,7 @@
   struct image *img;
   struct face *face;
   int face_ascent, glyph_ascent;
+  struct glyph_slice slice;
 
   xassert (it->what == IT_IMAGE);
 
@@ -18143,19 +18192,68 @@
   /* 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;
 
@@ -18163,13 +18261,15 @@
     {
       if (face->box_line_width > 0)
 	{
-	  it->ascent += face->box_line_width;
-	  it->descent += face->box_line_width;
-	}
-
-      if (it->start_of_box_run_p)
+	  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 && 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);
     }
 
@@ -18198,6 +18298,7 @@
 	  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];
 	}
@@ -18491,6 +18592,7 @@
 
 	  pcm = rif->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;
 
@@ -18503,11 +18605,27 @@
 	  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);
+	    }
+
 	  /* 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);
@@ -18540,6 +18658,14 @@
 	  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.  */
@@ -18566,13 +18692,31 @@
 	}
       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 */
+
 	  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
+
+	  it->ascent = FONT_BASE (font) + boff;
+	  it->descent = FONT_DESCENT (font) - boff;
+
+	  if (it->max_ascent > 0 || it->max_descent > 0)
+	    {
+	      it->ascent = it->descent = 0;
+	    }
+	  else
+	    {
+	      it->ascent = FONT_BASE (font) + boff;
+	      it->descent = FONT_DESCENT (font) - boff;
+	    }
+
+	  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;
@@ -20547,7 +20691,9 @@
 	      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)))
 		{
@@ -21584,6 +21730,8 @@
   staticpro (&Qspace_width);
   Qraise = intern ("raise");
   staticpro (&Qraise);
+  Qslice = intern ("slice");
+  staticpro (&Qslice);
   Qspace = intern ("space");
   staticpro (&Qspace);
   Qmargin = intern ("margin");