diff src/redisplay-x.c @ 3094:ad2f4ae9895b

[xemacs-hg @ 2005-11-26 11:45:47 by stephent] Xft merge. <87k6ev4p8q.fsf@tleepslib.sk.tsukuba.ac.jp>
author stephent
date Sat, 26 Nov 2005 11:46:25 +0000
parents 3d8143fc88e1
children d1754e7f0cea
line wrap: on
line diff
--- a/src/redisplay-x.c	Fri Nov 25 22:51:38 2005 +0000
+++ b/src/redisplay-x.c	Sat Nov 26 11:46:25 2005 +0000
@@ -58,7 +58,7 @@
 #include <X11/bitmaps/gray>
 
 /* Number of pixels below each line. */
-int x_interline_space; /* #### implement me */
+int x_interline_space; /* #### this needs to be implemented, but per-font */
 
 #define EOL_CURSOR_WIDTH	5
 
@@ -73,6 +73,11 @@
 static void x_clear_frame (struct frame *f);
 static void x_clear_frame_windows (Lisp_Object window);
 
+#ifdef USE_XFT
+#define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
+		   ? ((unsigned long) (x)) : ((unsigned long) (y)))
+#endif /* USE_XFT */
+
 
      /* Note: We do not use the Xmb*() functions and XFontSets.
 	Those functions are generally losing for a number of reasons:
@@ -83,6 +88,11 @@
 	    to try to deal with this, but that would generally
 	    fail because an XFontSet is tied to one locale and
 	    won't have the other character sets in it.
+
+	The following aren't true any more, but that doesn't make Xmb*()
+	usable.  One wonders about Xft and Pango, etc, tho'.  Except they
+	aren't cross-platform solutions.  FMH, as jwz would say. -- sjt
+	[[
 	 2) Not all (or even very many) OS's support the useful
 	    locales.  For example, as far as I know SunOS and
 	    Solaris only support the Japanese locale if you get the
@@ -98,8 +108,10 @@
 	    I can find what the multi-byte text format for the
 	    Japanese locale under SunOS and Solaris is, but I assume
 	    it's EUC.
+	]]
       */
 
+/* #### Break me out into a separate header */
 struct textual_run
 {
   Lisp_Object charset;
@@ -120,6 +132,25 @@
 
    Returns the number of runs actually used. */
 
+/* Notes on Xft implementation
+
+   - Xft Reloaded, v.4, uses a function like that in redisplay-msw.c to
+   handle all characters.  However, instead of using an appropriate
+   character width for each run, it just uses UTF-8 for all runs.  This
+   is not obviously a bad idea, but (for Han characters etc) the estimate
+   of TEXT_STORAGE allocation needed is (3 * len), and for characters not
+   in the BMP, it's (4 * len).
+   - With Unicode, we're no longer going to have repertoires reified as
+   charsets.  (Not that we ever really did, what with corporate variants,
+   and so on.)  So we really should be querying the face for the desired
+   font, rather than the character for the charset, and that's what would
+   determine the separation into runs.
+   - The widechar versions of fontconfig (and therefore Xft) functions
+   seem to be just bigendian Unicode.  So there's actually no need to use
+   the 8-bit versions in computing runs and runes, it would seem.
+   - Mule won't "just work"; substantially more effort seems needed.
+*/
+
 static int
 separate_textual_runs (unsigned char *text_storage,
 		       struct textual_run *run_storage,
@@ -139,7 +170,7 @@
     {
       Ichar ch = str[i];
       Lisp_Object charset;
-      int byte1, byte2;
+      int byte1, byte2;		/* #### why aren't these UExtbytes? */
       int dimension;
       int graphic;
 
@@ -151,7 +182,11 @@
 	{
 	  run_storage[runs_so_far].ptr       = text_storage;
 	  run_storage[runs_so_far].charset   = charset;
+#ifdef USE_XFT
+	  run_storage[runs_so_far].dimension = 2;
+#else
 	  run_storage[runs_so_far].dimension = dimension;
+#endif
 
 	  if (runs_so_far)
 	    {
@@ -172,6 +207,7 @@
 #endif
 	}
 
+#ifndef USE_XFT
       if (graphic == 0)
 	{
 	  byte1 &= 0x7F;
@@ -192,10 +228,53 @@
 	  byte1 = char_converter.reg[1];
 	  byte2 = char_converter.reg[2];
 	}
-#endif
+#endif /* MULE */
       *text_storage++ = (unsigned char) byte1;
       if (dimension == 2)
 	*text_storage++ = (unsigned char) byte2;
+#else /* USE_XFT */
+      /* #### This is bogus as hell.  XftChar16, aka FcChar16, is actually
+	 unsigned short, and therefore is not suitable for indexing matrix
+	 fonts such as the JIS fonts supplied with X11.  But if this were
+	 consistent, the XftDraw*8 and XftDraw*16 functions are pretty
+	 incoherent, as then we not should allow anything but ISO 8859/1
+	 (ie, the first 256 code points of Unicode) in XftDraw*8.  So it
+	 looks like this depends on the font, not the charset. */
+      {
+	XftChar16 xftchar16 = 0xFFFD; /* unsigned short */
+#ifndef MULE
+	int unicode = ch;
+#else
+	int unicode = ichar_to_unicode (ch);
+	if (unicode < 0)
+	  /* abort(); */	  /* #### serious error, tables are corrupt
+	     Unfortunately, not a valid assumption; this can happen with
+	     composite characters.  Fake it. */
+	  unicode = 0xFFFD; /* REPLACEMENT CHARACTER, can't represent */
+	else if (need_ccl_conversion)
+	  /* #### maybe we should just ignore this and hope the font wins? */
+	  unicode = 0xFFFD; /* REPLACEMENT CHARACTER, can't represent */
+	else if (unicode > 65535)
+	  unicode = 0xFFFD; /* REPLACEMENT CHARACTER, can't represent */
+	else
+#endif
+	  xftchar16 = (XftChar16) unicode;
+	/* #### endianness dependency?  No,
+	   apparently xft handles endianness for us;
+	   the "big-endian" code works on Intel and PPC */
+#if 1
+	/* big-endian or auto-endian */
+	byte1 = ((unsigned char *) (&xftchar16))[0];
+	byte2 = ((unsigned char *) (&xftchar16))[1];
+#else
+	/* little-endian */
+	byte1 = ((unsigned char *) (&xftchar16))[1];
+	byte2 = ((unsigned char *) (&xftchar16))[0];
+#endif
+      }
+      *text_storage++ = (unsigned char) byte1;
+      *text_storage++ = (unsigned char) byte2;      
+#endif /* USE_XFT */
     }
 
   if (runs_so_far)
@@ -216,13 +295,34 @@
 /****************************************************************************/
 
 static int
-x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
+x_text_width_single_run (struct frame * USED_IF_XFT (f),
+			 struct face_cachel *cachel, struct textual_run *run)
 {
   Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
   Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
   if (!fi->proportional_p)
     return fi->width * run->len;
-  else
+#ifdef USE_XFT
+  else if (FONT_INSTANCE_X_XFTFONT(fi))
+    {
+      static XGlyphInfo glyphinfo;
+      struct device *d = XDEVICE (f->device);
+      Display *dpy = DEVICE_X_DISPLAY (d);
+
+      if (run->dimension == 2) {
+	XftTextExtents16 (dpy,
+			  FONT_INSTANCE_X_XFTFONT(fi),
+			  (XftChar16 *) run->ptr, run->len, &glyphinfo);
+      } else {
+	XftTextExtents8 (dpy,
+			 FONT_INSTANCE_X_XFTFONT(fi),
+			 run->ptr, run->len, &glyphinfo);
+      }
+    
+      return glyphinfo.xOff;
+    }
+#endif
+  else if (FONT_INSTANCE_X_FONT (fi))
     {
       if (run->dimension == 2)
 	return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
@@ -231,17 +331,23 @@
 	return XTextWidth (FONT_INSTANCE_X_FONT (fi),
 			   (char *) run->ptr, run->len);
     }
+  else
+    abort();
+  return 0;			/* shut up GCC */
 }
 
 /*
    x_text_width
 
-   Given a string and a face, return the string's length in pixels when
-   displayed in the font associated with the face.
+   Given a string and a merged face, return the string's length in pixels
+   when displayed in the fonts associated with the face.
    */
 
-static int
-x_text_width (struct frame *UNUSED (f), struct face_cachel *cachel,
+/* #### Break me out into a separate header */
+int x_text_width (struct frame *f, struct face_cachel *cachel,
+		  const Ichar *str, Charcount len);
+int
+x_text_width (struct frame *f, struct face_cachel *cachel,
 	      const Ichar *str, Charcount len)
 {
   /* !!#### Needs review */
@@ -254,7 +360,7 @@
   nruns = separate_textual_runs (text_storage, runs, str, len);
 
   for (i = 0; i < nruns; i++)
-    width_so_far += x_text_width_single_run (cachel, runs + i);
+    width_so_far += x_text_width_single_run (f, cachel, runs + i);
 
   return width_so_far;
 }
@@ -319,7 +425,9 @@
 			int start, int end, int start_pixpos, int cursor_start,
 			int cursor_width, int cursor_height)
 {
+#ifndef USE_XFT
   struct frame *f = XFRAME (w->frame);
+#endif
   Ichar_dynarr *buf = Dynarr_new (Ichar);
   Lisp_Object window;
 
@@ -502,13 +610,17 @@
     x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
 		     0, cursor_start, cursor_width, cursor_height);
 
-  /* #### This is really conditionalized well for optimized
-     performance. */
   if (dl->modeline
       && !EQ (Qzero, w->modeline_shadow_thickness)
+#ifndef USE_XFT
+      /* This optimization doesn't work right with some Xft fonts, which
+	 leave antialiasing turds at the boundary.  I don't know if this
+	 is an Xft bug or not, but I think it is.   See x_output_string. */
       && (f->clear
 	  || f->windows_structure_changed
-	  || w->shadow_thickness_changed))
+	  || w->shadow_thickness_changed)
+#endif
+      )
     bevel_modeline (w, dl);
 
   Dynarr_free (buf);
@@ -662,7 +774,13 @@
   mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
   mask |= GCFillStyle;
 
-  if (!NILP (font))
+  if (!NILP (font)
+#ifdef USE_XFT
+      /* Only set the font if it's a core font */
+      /* the renderfont will be set elsewhere (not part of gc) */
+      && !FONT_INSTANCE_X_XFTFONT (XFONT_INSTANCE (font))
+#endif
+      )
     {
       gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
       mask |= GCFont;
@@ -671,7 +789,7 @@
   /* evil kludge! */
   if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
     {
-      /* #### I fixed once case where this was getting it.  It was a
+      /* #### I fixed one case where this was getting hit.  It was a
          bad macro expansion (compiler bug). */
       stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
       debug_print (fg);
@@ -729,6 +847,9 @@
       mask |= GCLineWidth;
     }
 
+#if 0
+  debug_out ("\nx_get_gc: calling gc_cache_lookup\n");
+#endif
   return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
 }
 
@@ -774,7 +895,7 @@
   /* General variables */
   struct frame *f = XFRAME (w->frame);
   struct device *d = XDEVICE (f->device);
-  Lisp_Object window;
+  Lisp_Object window = wrap_window (w);
   Display *dpy = DEVICE_X_DISPLAY (d);
   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
 
@@ -790,7 +911,8 @@
   /* Text-related variables */
   Lisp_Object bg_pmap;
   GC bgc, gc;
-  int height;
+  int height = DISPLAY_LINE_HEIGHT (dl);
+  int ypos = DISPLAY_LINE_YPOS (dl);
   int len = Dynarr_length (buf);
   unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len);
   struct textual_run *runs = alloca_array (struct textual_run, len);
@@ -798,11 +920,31 @@
   int i;
   struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
 
-  window = wrap_window (w);
+  int use_x_font = 1;		/* #### bogus!!
+				   The logic of this function needs review! */
+#ifdef USE_XFT
+  Colormap cmap = DEVICE_X_COLORMAP (d);
+  Visual *visual = DEVICE_X_VISUAL (d);
+  static XftColor fg, bg;
+  XftDraw *xftDraw;
+
+  /* Lazily initialize frame's xftDraw member. */
+  if (!FRAME_X_XFTDRAW (f)) {
+    FRAME_X_XFTDRAW (f) = XftDrawCreate (dpy, x_win, visual, cmap);
+  }
+  xftDraw = FRAME_X_XFTDRAW (f);
+
+  /* #### This will probably cause asserts when passed a Lisp integer for a
+     color.  See ca. line 759 this file.
+     #### Maybe xft_convert_color should take an XColor, not a pixel. */
+#define XFT_FROB_LISP_COLOR(color, dim) \
+  xft_convert_color (dpy, cmap, visual, \
+		     COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color)).pixel, \
+		     (dim))
+#endif
 
   if (width < 0)
     width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
-  height = DISPLAY_LINE_HEIGHT (dl);
 
   /* Regularize the variables passed in. */
 
@@ -816,11 +958,8 @@
   xpos -= xoffset;
 
   /* make sure the area we are about to display is subwindow free. */
-  redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
-				    clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
-
-  nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
-				 Dynarr_length (buf));
+  redisplay_unmap_subwindows_maybe (f, clip_start, ypos,
+				    clip_end - clip_start, height);
 
   cursor_clip = (cursor_start >= clip_start &&
 		 cursor_start < clip_end);
@@ -858,13 +997,20 @@
        && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
     bgc = 0;
   else
-    bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
-		    bg_pmap, Qnil);
+    {
+      bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
+		      bg_pmap, Qnil);
+    }
 
   if (bgc)
-    XFillRectangle (dpy, x_win, bgc, clip_start,
-		    DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
-		    height);
+    {
+      XFillRectangle (dpy, x_win, bgc, clip_start,
+		      ypos, clip_end - clip_start,
+		      height);
+    }
+
+  nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
+				 Dynarr_length (buf));
 
   for (i = 0; i < nruns; i++)
     {
@@ -876,7 +1022,7 @@
       if (EQ (font, Vthe_null_font_instance))
 	continue;
 
-      this_width = x_text_width_single_run (cachel, runs + i);
+      this_width = x_text_width_single_run (f, cachel, runs + i);
       need_clipping = (dl->clip || clip_start > xpos ||
 		       clip_end < xpos + this_width);
 
@@ -895,8 +1041,8 @@
 
 	      ypos1_string = dl->ypos - fi->ascent;
 	      ypos2_string = dl->ypos + fi->descent;
-	      ypos1_line = DISPLAY_LINE_YPOS (dl);
-	      ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
+	      ypos1_line = ypos;
+	      ypos2_line = ypos1_line + height;
 
 	      /* Make sure we don't clear below the real bottom of the
 		 line. */
@@ -922,14 +1068,20 @@
 	  else
 	    {
 	      redisplay_clear_region (window, findex, clear_start,
-			      DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
+			      ypos, clear_end - clear_start,
 			      height);
 	    }
 	}
 
       if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
-	gc = x_get_gc (d, font, cursor_cachel->foreground,
-		       cursor_cachel->background, Qnil, Qnil);
+	{
+#ifdef USE_XFT
+	  fg = XFT_FROB_LISP_COLOR (cursor_cachel->foreground, 0);
+	  bg = XFT_FROB_LISP_COLOR (cursor_cachel->background, 0);
+#endif
+	  gc = x_get_gc (d, font, cursor_cachel->foreground,
+			 cursor_cachel->background, Qnil, Qnil);
+	}
       else if (cachel->dim)
 	{
 	  /* Ensure the gray bitmap exists */
@@ -939,53 +1091,135 @@
 				     gray_width, gray_height);
 
 	  /* Request a GC with the gray stipple pixmap to draw dimmed text */
+#ifdef USE_XFT
+	  fg = XFT_FROB_LISP_COLOR (cachel->foreground, 1);
+	  bg = XFT_FROB_LISP_COLOR (cachel->background, 0);
+#endif
 	  gc = x_get_gc (d, font, cachel->foreground, cachel->background,
 			 Qdim, Qnil);
 	}
       else
-	gc = x_get_gc (d, font, cachel->foreground, cachel->background,
-		       Qnil, Qnil);
+	{
+#ifdef USE_XFT
+	  fg = XFT_FROB_LISP_COLOR (cachel->foreground, 0);
+	  bg = XFT_FROB_LISP_COLOR (cachel->background, 0);
+#endif
+	  gc = x_get_gc (d, font, cachel->foreground, cachel->background,
+			 Qnil, Qnil);
+	}
+#ifdef USE_XFT
+      {
+	XftFont *rf = FONT_INSTANCE_X_XFTFONT (fi);
 
-      if (need_clipping)
-	{
-	  XRectangle clip_box[1];
+	if (rf)
+	  {
+	    use_x_font = 0;
+	    if (need_clipping)
+	      {
+		Region clip_reg = XCreateRegion();
+		XRectangle clip_box = { clip_start, ypos,
+					clip_end - clip_start, height };
 
-	  clip_box[0].x = 0;
-	  clip_box[0].y = 0;
-	  clip_box[0].width = clip_end - clip_start;
-	  clip_box[0].height = height;
+		XUnionRectWithRegion (&clip_box, clip_reg, clip_reg); 
+		XftDrawSetClip(xftDraw, clip_reg);
+		XDestroyRegion(clip_reg);
+	      }
 
-	  XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
-			      clip_box, 1, Unsorted);
-	}
+	    if (!bgc)
+	      {
+		/* #### Neither rect_height nor XftTextExtents as computed
+		   below handles the vertical space taken up by antialiasing,
+		   which for some fonts (eg, Bitstream Vera Sans Mono-16 on
+		   my Mac PowerBook G4) leaves behind orphaned dots on
+		   insertion or deletion earlier in the line, especially in
+		   the case of the underscore character.
+		   Interestingly, insertion or deletion of a single character
+		   immediately after a refresh does not leave any droppings,
+		   but any further insertions or deletions do.
+		   While adding a pixel to rect_height (mostly) takes care of
+		   this, it trashes aggressively laid-out elements like the
+		   modeline (overwriting part of the bevel).
+		   OK, unconditionally redraw the bevel, and increment
+		   rect_height by 1.  See x_output_display_block. -- sjt */
+		struct textual_run *run = &runs[i];
+		int rect_width = x_text_width_single_run (f, cachel, run);
+#ifndef USE_XFTTEXTENTS_TO_AVOID_FONT_DROPPINGS
+		int rect_height = FONT_INSTANCE_ASCENT(fi)
+				  + FONT_INSTANCE_DESCENT(fi) + 1;
+#else
+		int rect_height = FONT_INSTANCE_ASCENT(fi)
+				  + FONT_INSTANCE_DESCENT(fi);
+		XGlyphInfo gi;
+		if (run->dimension == 2) {
+		  XftTextExtents16 (dpy,
+				    FONT_INSTANCE_X_XFTFONT(fi),
+				    (XftChar16 *) run->ptr, run->len, &gi);
+		} else {
+		  XftTextExtents8 (dpy,
+				   FONT_INSTANCE_X_XFTFONT(fi),
+				   run->ptr, run->len, &gi);
+		}
+		rect_height = rect_height > gi.height
+			      ? rect_height : gi.height;
+#endif
 
-      if (runs[i].dimension == 1)
-	(bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
-						dl->ypos, (char *) runs[i].ptr,
-						runs[i].len);
-      else
-	(bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
-						    dl->ypos,
-						    (XChar2b *) runs[i].ptr,
-						    runs[i].len);
+		XftDrawRect (xftDraw, &bg,
+			     xpos, ypos, rect_width, rect_height);
+	      }
+	
+	    if (runs[i].dimension == 1)
+	      XftDrawString8 (xftDraw, &fg, rf, xpos, dl->ypos,
+			      runs[i].ptr, runs[i].len);
+	    else
+	      XftDrawString16 (xftDraw, &fg, rf, xpos, dl->ypos,
+			       (XftChar16 *) runs[i].ptr, runs[i].len);
+	  }
+      }
+#endif
+      {
+	if (use_x_font)
+	  {
+	    if (need_clipping)
+	      {
+		XRectangle clip_box[1];
+
+		clip_box[0].x = 0;
+		clip_box[0].y = 0;
+		clip_box[0].width = clip_end - clip_start;
+		clip_box[0].height = height;
+
+		XSetClipRectangles (dpy, gc, clip_start, ypos,
+				    clip_box, 1, YXBanded);
+	      }
+
+	    if (runs[i].dimension == 1)
+	      (bgc ? XDrawString : XDrawImageString)
+		(dpy, x_win, gc, xpos, dl->ypos,
+		 (char *) runs[i].ptr, runs[i].len);
+	    else
+	      (bgc ? XDrawString16 : XDrawImageString16)
+		(dpy, x_win, gc, xpos, dl->ypos,
+		 (XChar2b *) runs[i].ptr, runs[i].len);
+	  }
+      }
 
       /* We draw underlines in the same color as the text. */
       if (cachel->underline)
 	{
 	  int upos, uthick;
 	  unsigned long upos_ext, uthick_ext;
-	  XFontStruct *xfont;
-
-	  xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
-	  if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos_ext))
-	    upos = dl->descent / 2;
+	  XFontStruct *fs =
+	    use_x_font ? FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)) : 0;
+	  /* #### the logic of the next two may be suboptimal: we may want
+	     to use the POSITION and/or THICKNESS information with Xft */
+	  if (fs && XGetFontProperty (fs, XA_UNDERLINE_POSITION, &upos_ext))
+	    upos = (int) upos_ext;
 	  else
-	    upos = (int) upos_ext;
-	  if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick_ext))
+	    upos = dl->descent / 2;
+	  if (fs && XGetFontProperty (fs, XA_UNDERLINE_THICKNESS, &uthick_ext))
+	    uthick = (int) uthick_ext;
+	  else
 	    uthick = 1;
-	  else
-	    uthick = (int) uthick_ext;
-
 	  if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
 	    {
 	      if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
@@ -1008,22 +1242,29 @@
 	{
 	  int ascent, descent, upos, uthick;
 	  unsigned long ascent_ext, descent_ext, uthick_ext;
-	  XFontStruct *xfont;
-
-	  xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
+	  XFontStruct *fs = FONT_INSTANCE_X_FONT (fi);
 	  
-	  if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent_ext))
-	    ascent = xfont->ascent;
+	  if (!use_x_font)
+	    {
+	      ascent = dl->ascent;
+	      descent = dl->descent;
+	      uthick = 1;
+	    }
 	  else
-	    ascent = (int) ascent_ext;
-	  if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent_ext))
-	    descent = xfont->descent;
-	  else
-	    descent = (int) descent_ext;
-	  if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick_ext))
-	    uthick = 1;
-	  else
-	    uthick = (int) uthick_ext;
+	    {
+	      if (!XGetFontProperty (fs, XA_STRIKEOUT_ASCENT, &ascent_ext))
+		ascent = fs->ascent;
+	      else
+		ascent = (int) ascent_ext;
+	      if (!XGetFontProperty (fs, XA_STRIKEOUT_DESCENT, &descent_ext))
+		descent = fs->descent;
+	      else
+		descent = (int) descent_ext;
+	      if (!XGetFontProperty (fs, XA_UNDERLINE_THICKNESS, &uthick_ext))
+		uthick = 1;
+	      else
+		uthick = (int) uthick_ext;
+	    }
 
 	  upos = ascent - ((ascent + descent) / 2) + 1;
 
@@ -1046,37 +1287,88 @@
       /* Restore the GC */
       if (need_clipping)
 	{
-	  XSetClipMask (dpy, gc, None);
-	  XSetClipOrigin (dpy, gc, 0, 0);
+#ifdef USE_XFT
+	  if (!use_x_font)
+	    {
+	      XftDrawSetClip(xftDraw, 0);
+	    }
+	  else
+	    {
+#endif
+	      XSetClipMask (dpy, gc, None);
+	      XSetClipOrigin (dpy, gc, 0, 0);
+#ifdef USE_XFT
+	    }
+#endif
 	}
 
       /* If we are actually superimposing the cursor then redraw with just
 	 the appropriate section highlighted. */
       if (cursor_clip && !cursor && focus && cursor_cachel)
 	{
-	  GC cgc;
-	  XRectangle clip_box[1];
+#ifdef USE_XFT
+	  if (!use_x_font)	/* Xft */
+	    {
+	      XftFont *rf = FONT_INSTANCE_X_XFTFONT (fi);
+	  
+	      { /* set up clipping */
+		Region clip_reg = XCreateRegion();
+		XRectangle clip_box = { cursor_start, ypos,
+					cursor_width, height };
+	    
+		XUnionRectWithRegion (&clip_box, clip_reg, clip_reg); 
+		XftDrawSetClip(xftDraw, clip_reg);
+		XDestroyRegion(clip_reg);
+	      }
+	      { /* draw background rectangle & draw text */
+		int rect_height = FONT_INSTANCE_ASCENT(fi)
+				  + FONT_INSTANCE_DESCENT(fi);
+		int rect_width = x_text_width_single_run(f, cachel, &runs[i]);
+		XftColor xft_color;
 
-	  cgc = x_get_gc (d, font, cursor_cachel->foreground,
-			  cursor_cachel->background, Qnil, Qnil);
-
-	  clip_box[0].x = 0;
-	  clip_box[0].y = 0;
-	  clip_box[0].width = cursor_width;
-	  clip_box[0].height = height;
+		xft_color = XFT_FROB_LISP_COLOR (cursor_cachel->background, 0);
+		XftDrawRect (xftDraw, &xft_color,
+			     xpos, ypos, rect_width, rect_height);
 
-	  XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
-			      clip_box, 1, Unsorted);
+		xft_color = XFT_FROB_LISP_COLOR (cursor_cachel->foreground, 0);
+		if (runs[i].dimension == 1)
+		  XftDrawString8 (xftDraw, &xft_color, rf, xpos, dl->ypos,
+				  runs[i].ptr, runs[i].len);
+		else
+		  XftDrawString16 (xftDraw, &xft_color, rf, xpos, dl->ypos,
+				   (XftChar16 *) runs[i].ptr, runs[i].len);
+	      }
+
+	      XftDrawSetClip(xftDraw, 0);
+	    }
+	  else			/* core font, not Xft */
+	    {
+#endif
+	      GC cgc;
+	      XRectangle clip_box[1];
+	
+	      cgc = x_get_gc (d, font, cursor_cachel->foreground,
+			      cursor_cachel->background, Qnil, Qnil);
 
-	  if (runs[i].dimension == 1)
-	    XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
-			      (char *) runs[i].ptr, runs[i].len);
-	  else
-	    XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
-				(XChar2b *) runs[i].ptr, runs[i].len);
-
-	  XSetClipMask (dpy, cgc, None);
-	  XSetClipOrigin (dpy, cgc, 0, 0);
+	      clip_box[0].x = 0;
+	      clip_box[0].y = 0;
+	      clip_box[0].width = cursor_width;
+	      clip_box[0].height = height;
+	
+	      XSetClipRectangles (dpy, cgc, cursor_start, ypos,
+				  clip_box, 1, YXBanded);
+	      if (runs[i].dimension == 1)
+		XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
+				  (char *) runs[i].ptr, runs[i].len);
+	      else
+		XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
+				    (XChar2b *) runs[i].ptr, runs[i].len);
+	
+	      XSetClipMask (dpy, cgc, None);
+	      XSetClipOrigin (dpy, cgc, 0, 0);
+#ifdef USE_XFT
+	    }
+#endif
 	}
 
       xpos += this_width;
@@ -1102,11 +1394,11 @@
 
 	 This is bogus as all hell, however.  The cursor handling in
 	 this function is way bogus and desperately needs to be
-	 cleaned up. (In particular, the drawing of the cursor should
+	 cleaned up.  (In particular, the drawing of the cursor should
 	 really really be separated out of this function.  This may be
 	 a bit tricky now because this function itself does way too
 	 much stuff, a lot of which needs to be moved into
-	 redisplay.c) This is the only way to be able to easily add
+	 redisplay.c.)  This is the only way to be able to easily add
 	 new cursor types or (e.g.) make the bar cursor be able to
 	 span two characters instead of overlaying just one. */
       int bogusly_obtained_ascent_value =
@@ -1125,12 +1417,12 @@
 
       tmp_y = dl->ypos - bogusly_obtained_ascent_value;
       tmp_height = cursor_height;
-      if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
+      if (tmp_y + tmp_height > (int) (ypos + height))
 	{
-	  tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
-	  if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
-	    tmp_y = DISPLAY_LINE_YPOS (dl);
-	  tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
+	  tmp_y = ypos + height - tmp_height;
+	  if (tmp_y < (int) ypos)
+	    tmp_y = ypos;
+	  tmp_height = ypos + height - tmp_y;
 	}
 
       if (need_clipping)
@@ -1141,7 +1433,8 @@
 	  clip_box[0].width = clip_end - clip_start;
 	  clip_box[0].height = tmp_height;
 	  XSetClipRectangles (dpy, gc, clip_start, tmp_y,
-			      clip_box, 1, Unsorted);
+			      /* #### why not Unsorted? */
+			      clip_box, 1, YXBanded);
 	}
 
       if (!focus && NILP (bar_cursor_value))
@@ -1162,6 +1455,11 @@
 	  XSetClipOrigin (dpy, gc, 0, 0);
 	}
     }
+
+#ifdef USE_XFT
+#undef XFT_FROB_LISP_COLOR
+#endif
+
 }
 
 void
@@ -1625,7 +1923,7 @@
       topc.red   = MINL (65535, (unsigned long) topc.red   * 6 / 5);
       topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
       topc.blue  = MINL (65535, (unsigned long) topc.blue  * 6 / 5);
-      if (allocate_nearest_color (dpy, cmap, visual, &topc))
+      if (x_allocate_nearest_color (dpy, cmap, visual, &topc))
 	{
 	  *top_shadow = topc.pixel;
 	  top_frobbed = 1;
@@ -1641,7 +1939,7 @@
       botc.red   = (unsigned short) ((unsigned long) botc.red   * 3 / 5);
       botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
       botc.blue  = (unsigned short) ((unsigned long) botc.blue  * 3 / 5);
-      if (allocate_nearest_color (dpy, cmap, visual, &botc))
+      if (x_allocate_nearest_color (dpy, cmap, visual, &botc))
 	{
 	  *bottom_shadow = botc.pixel;
 	  bottom_frobbed = 1;