changeset 111309:19abdd4591a6

Implement various display methods for glyphless characters.
author Kenichi Handa <handa@m17n.org>
date Mon, 01 Nov 2010 16:56:16 +0900
parents d86b7e0aed88 (current diff) b08599321ca8 (diff)
children 8ddff723bc6f
files
diffstat 13 files changed, 1072 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Mon Nov 01 00:40:11 2010 -0700
+++ b/lisp/ChangeLog	Mon Nov 01 16:56:16 2010 +0900
@@ -1,3 +1,17 @@
+2010-11-01  Kenichi Handa  <handa@m17n.org>
+
+	* faces.el (glyphless-char): Inherit underline for tty.
+
+2010-10-28  Kenichi Handa  <handa@m17n.org>
+
+	Implement various display methods for glyphless characters.
+
+	* international/characters.el (char-acronym-table): New variable.
+	(glyphless-char-control): New variable.
+	(update-glyphless-char-display): New funciton.
+
+	* faces.el (glyphless-char): New face.
+
 2010-11-01  Glenn Morris  <rgm@gnu.org>
 
 	* calendar/holidays.el (general-holidays, oriental-holidays)
--- a/lisp/faces.el	Mon Nov 01 00:40:11 2010 -0700
+++ b/lisp/faces.el	Mon Nov 01 16:56:16 2010 +0900
@@ -2482,6 +2482,14 @@
 (defface help-argument-name '((((supports :slant italic)) :inherit italic))
   "Face to highlight argument names in *Help* buffers."
   :group 'help)
+
+(defface glyphless-char
+  '((((type tty)) :inherit underline)
+    (t :height 0.6))
+  "Face for displaying non-graphic characters (e.g. U+202A (LRE)).
+It is used for characters of no fonts too."
+  :version "24.1"
+  :group 'basic-faces)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Manipulating font names.
--- a/lisp/international/characters.el	Mon Nov 01 00:40:11 2010 -0700
+++ b/lisp/international/characters.el	Mon Nov 01 16:56:16 2010 +0900
@@ -1234,6 +1234,131 @@
 (optimize-char-table (standard-category-table))
 
 
+;; Display of glyphless characters.
+
+(defvar char-acronym-table
+  (make-char-table 'char-acronym-table nil)
+  "Char table of acronyms for non-graphic characters.")
+
+(let ((c0-acronyms '("NUL" "SOH" "STX" "ETX" "EOT" "ENQ" "ACK" "BEL"
+		     "BS"   nil   nil  "VT"  "FF"  "CR"  "SO"  "SI"
+		     "DLE" "DC1" "DC2" "DC3" "DC4" "NAK" "SYN" "ETB"
+		     "CAN" "EM"  "SUB" "ESC" "FC"  "GS"  "RS"  "US")))
+  (dotimes (i 32)
+    (aset char-acronym-table i (car c0-acronyms))
+    (setq c0-acronyms (cdr c0-acronyms))))
+
+(let ((c1-acronyms '("XXX" "XXX" "BPH" "NBH" "IND" "NEL" "SSA" "ESA"
+		     "HTS" "HTJ" "VTS" "PLD" "PLU" "R1"  "SS2" "SS1"
+		     "DCS" "PU1" "PU2" "STS" "CCH" "MW"  "SPA" "EPA"
+		     "SOS" "XXX" "SC1" "CSI" "ST"  "OSC" "PM"  "APC")))
+  (dotimes (i 32)
+    (aset char-acronym-table (+ #x0080 i) (car c1-acronyms))
+    (setq c1-acronyms (cdr c1-acronyms))))
+
+(aset char-acronym-table #x17B4 "KIVAQ")   ; KHMER VOWEL INHERENT AQ
+(aset char-acronym-table #x17B5 "KIVAA")   ; KHMER VOWEL INHERENT AA
+(aset char-acronym-table #x200B "ZWSP")    ; ZERO WIDTH SPACE
+(aset char-acronym-table #x200C "ZWNJ")    ; ZERO WIDTH NON-JOINER
+(aset char-acronym-table #x200D "ZWJ")	   ; ZERO WIDTH JOINER
+(aset char-acronym-table #x200E "LRM")	   ; LEFT-TO-RIGHT MARK
+(aset char-acronym-table #x200F "RLM")	   ; RIGHT-TO-LEFT MARK
+(aset char-acronym-table #x202A "LRE")	   ; LEFT-TO-RIGHT EMBEDDING
+(aset char-acronym-table #x202B "RLE")	   ; RIGHT-TO-LEFT EMBEDDING
+(aset char-acronym-table #x202C "PDF")	   ; POP DIRECTIONAL FORMATTING
+(aset char-acronym-table #x202D "LRO")	   ; LEFT-TO-RIGHT OVERRIDE
+(aset char-acronym-table #x202E "RLO")	   ; RIGHT-TO-LEFT OVERRIDE
+(aset char-acronym-table #x2060 "WJ")	   ; WORD JOINER
+(aset char-acronym-table #x206A "ISS")	   ; INHIBIT SYMMETRIC SWAPPING
+(aset char-acronym-table #x206B "ASS")	   ; ACTIVATE SYMMETRIC SWAPPING
+(aset char-acronym-table #x206C "IAFS")    ; INHIBIT ARABIC FORM SHAPING
+(aset char-acronym-table #x206D "AAFS")    ; ACTIVATE ARABIC FORM SHAPING
+(aset char-acronym-table #x206E "NADS")    ; NATIONAL DIGIT SHAPES
+(aset char-acronym-table #x206F "NODS")    ; NOMINAL DIGIT SHAPES
+(aset char-acronym-table #xFEFF "ZWNBSP")  ; ZERO WIDTH NO-BREAK SPACE
+(aset char-acronym-table #xFFF9 "IAA")	   ; INTERLINEAR ANNOTATION ANCHOR
+(aset char-acronym-table #xFFFA "IAS")     ; INTERLINEAR ANNOTATION SEPARATOR
+(aset char-acronym-table #xFFFB "IAT")     ; INTERLINEAR ANNOTATION TERMINATOR
+(aset char-acronym-table #x1D173 "BEGBM")  ; MUSICAL SYMBOL BEGIN BEAM
+(aset char-acronym-table #x1D174 "ENDBM")  ; MUSICAL SYMBOL END BEAM
+(aset char-acronym-table #x1D175 "BEGTIE") ; MUSICAL SYMBOL BEGIN TIE
+(aset char-acronym-table #x1D176 "END")	   ; MUSICAL SYMBOL END TIE
+(aset char-acronym-table #x1D177 "BEGSLR") ; MUSICAL SYMBOL BEGIN SLUR
+(aset char-acronym-table #x1D178 "ENDSLR") ; MUSICAL SYMBOL END SLUR
+(aset char-acronym-table #x1D179 "BEGPHR") ; MUSICAL SYMBOL BEGIN PHRASE
+(aset char-acronym-table #x1D17A "ENDPHR") ; MUSICAL SYMBOL END PHRASE
+(aset char-acronym-table #xE0001 "|->TAG") ; LANGUAGE TAG
+(aset char-acronym-table #xE0020 "SP TAG") ; TAG SPACE
+(dotimes (i 94)
+  (aset char-acronym-table (+ #xE0021 i) (format " %c TAG" (+ 33 i))))
+(aset char-acronym-table #xE007F "->|TAG") ; CANCEL TAG
+
+;;; Control of displaying glyphless characters.
+(defvar glyphless-char-control
+  '((format-control . thin-space)
+    (no-font . hexa-code))
+  "List of directives to control displaying of glyphless characters.
+
+Each element has the form (TARGET . METHOD), where TARGET is a
+symbol specifying the target character group to control, and
+METHOD is a symbol specifying the method of displaying them.
+
+TARGET must be one of these symbols:
+  `c0-control': U+0000..U+001F.
+  `c1-control': U+0080..U+009F.
+  `format-control': Characters of Unicode General Category `Cf'.
+     Ex: U+200C (ZWNJ), U+200E (LRM)), but don't include characters
+     that have graphic image such as U+00AD (SHY).
+  `no-font': characters for which no suitable font is found.
+
+METHOD must be one of these symbols:
+  `zero-width': don't display.
+  `thin-space': display a thin space (1-pixel width).
+  `empty-box': display an empty box.
+  `acronym': display an acronum string in a box.
+  `hexa-code': display a hexadecimal character code in a box.
+
+Just setting this variable does not take effect.  Call the
+function `update-glyphless-char-display' (which see) after
+setting this variable.")
+
+(defun update-glyphless-char-display ()
+  "Make the setting of `glyphless-char-control' take effect.
+This function updates the char-table `glyphless-char-display'."
+  (dolist (elt glyphless-char-control)
+    (let ((target (car elt))
+	  (method (cdr elt)))
+      (cond ((eq target 'c0-control)
+	     (set-char-table-range glyphless-char-display '(#x00 . #x1F)
+				   method))
+	    ((eq target 'c1-control)
+	     (set-char-table-range glyphless-char-display '(#x80 . #x9F)
+				   method))
+	    ((eq target 'format-control)
+	     (map-char-table
+	      #'(lambda (char category)
+		  (if (eq category 'Cf)
+		      (let ((this-method method)
+			    from to)
+			(if (consp char)
+			    (setq from (car char) to (cdr char))
+			  (setq from char to char))
+			(while (<= from to)
+			  (when (/= from #xAD)
+			    (if (eq method 'acronym)
+				(setq this-method 
+				      (aref char-acronym-table from)))
+			    (set-char-table-range glyphless-char-display
+						  from this-method))
+			  (setq from (1+ from))))))
+	      unicode-category-table))
+	    ((eq target 'no-font)
+	     (set-char-table-extra-slot glyphless-char-display 0 method))
+	    (t
+	     (error "Invalid target character group: %s" target))))))
+
+(update-glyphless-char-display)
+
 ;;; Setting word boundary.
 
 (setq word-combining-categories
--- a/src/ChangeLog	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/ChangeLog	Mon Nov 01 16:56:16 2010 +0900
@@ -1,3 +1,72 @@
+2010-11-01  Kenichi Handa  <handa@m17n.org>
+
+	* dispextern.h (lookup_glyphless_char_display): Extern it.
+
+	* termhooks.h (struct terminal): New member charset_list.
+
+	* coding.c (Fset_terminal_coding_system_internal): Set the
+	`charset_list' member of struct terminal.
+
+	* term.c (produce_glyphs): Handle the case it->what ==
+	IT_GLYPHLESS.
+	(append_glyphless_glyph, produce_glyphless_glyph): New functions.
+
+	* xdisp.c (lookup_glyphless_char_display): Make it non-static.
+	(lookup_glyphless_char_display): Set it->what at the end.
+	(last_glyphless_glyph_frame, last_glyphless_glyph_face_id)
+	(last_glyphless_glyph_merged_face_id): Make them non-static.
+
+	* w32term.c (x_draw_glyphless_glyph_string_foreground): Fix
+	the arg with_background for font->driver->draw.
+
+2010-10-29  Kenichi Handa  <handa@m17n.org>
+
+	* w32gui.h (STORE_XCHAR2B, XCHAR2B_BYTE1, XCHAR2B_BYTE2): Surround
+	chp by parentheses.
+
+2010-10-28  Kenichi Handa  <handa@m17n.org>
+
+	Implement various display methods for glyphless characters.
+
+	* xdisp.c (Qglyphless_char, Vglyphless_char_display)
+	(Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space)
+	(Qzero_width): New variables.
+	(THIN_SPACE_WIDTH): New macro.
+	(lookup_glyphless_char_display): New funciton.
+	(last_glyphless_glyph_frame, last_glyphless_glyph_face_id)
+	(last_glyphless_glyph_merged_face_id): New variables.
+	(get_next_display_element): Check glyphless characters.
+	(redisplay_internal): Initialize last_glyphless_glyph_frame and
+	last_glyphless_glyph_face_id.
+	(fill_glyphless_glyph_string): New function.
+	(BUILD_GLYPHLESS_GLYPH_STRING): New macro.
+	(BUILD_GLYPH_STRINGS): Handle the case GLYPHLESS_GLYPH.
+	(append_glyphless_glyph, produce_glyphless_glyph): New functions.
+	(x_produce_glyphs): If a suitable font is not found, produce a
+	glyphless glyph.  Handle the case it->what == IT_GLYPHLESS.
+	(syms_of_xdisp): Intern and staticpro Qglyphless_char,
+	Qglyphless_char_display, Qhexa_code, Qempty_box, Qthin_space, and
+	Qzero_width.
+	(Vglyphless_char_display): Declare it as a Lisp variable.
+
+	* dispextern.h (enum glyph_type): Add GLYPHLESS_GLYPH.
+	(struct glyph): Change the size of the member "type" to 3.  Add
+	glyphless to the union slice and u.
+	(enum display_element_type): Add IT_GLYPHLESS.
+	(enum glyphless_display_method): New enum.
+	(struct it): New member glyphless_method.
+	(Vglyphless_char_display): Extern it.
+
+	* xterm.c (x_draw_glyphless_glyph_string_foreground): New function.
+	(x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH.
+
+	* w32term.c (x_draw_glyphless_glyph_string_foreground): New
+	function.
+	(x_draw_glyph_string): Handle the case GLYPHLESS_GLYPH.
+
+	* nsterm.m (ns_draw_glyph_string): Handle the case
+	GLYPHLESS_GLYPH (the detail is not yet implemented).
+
 2010-10-31  Glenn Morris  <rgm@gnu.org>
 
 	* xterm.c (x_connection_closed) [USE_X_TOOLKIT]: Fix merge, maybe.
--- a/src/coding.c	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/coding.c	Mon Nov 01 16:56:16 2010 +0900
@@ -9297,7 +9297,8 @@
        doc: /* Internal use only.  */)
   (Lisp_Object coding_system, Lisp_Object terminal)
 {
-  struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (get_terminal (terminal, 1));
+  struct terminal *term = get_terminal (terminal, 1);
+  struct coding_system *terminal_coding = TERMINAL_TERMINAL_CODING (term);
   CHECK_SYMBOL (coding_system);
   setup_coding_system (Fcheck_coding_system (coding_system), terminal_coding);
   /* We had better not send unsafe characters to terminal.  */
@@ -9306,6 +9307,10 @@
   terminal_coding->common_flags &= ~CODING_ANNOTATE_COMPOSITION_MASK;
   terminal_coding->src_multibyte = 1;
   terminal_coding->dst_multibyte = 0;
+  if (terminal_coding->common_flags & CODING_REQUIRE_ENCODING_MASK)
+    term->charset_list = coding_charset_list (terminal_coding);
+  else
+    term->charset_list = Fcons (Qascii, Qnil);
   return Qnil;
 }
 
--- a/src/dispextern.h	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/dispextern.h	Mon Nov 01 16:56:16 2010 +0900
@@ -279,6 +279,9 @@
   /* Glyph describes a static composition.  */
   COMPOSITE_GLYPH,
 
+  /* Glyph describes a glyphless character.  */
+  GLYPHLESS_GLYPH,
+
   /* Glyph describes an image.  */
   IMAGE_GLYPH,
 
@@ -333,7 +336,7 @@
 
   /* Which kind of glyph this is---character, image etc.  Value
      should be an enumerator of type enum glyph_type.  */
-  unsigned type : 2;
+  unsigned type : 3;
 
   /* 1 means this glyph was produced from multibyte text.  Zero
      means it was produced from unibyte text, i.e. charsets aren't
@@ -402,6 +405,11 @@
     /* Start and end indices of glyphs of a graphme cluster of a
        composition (type == COMPOSITE_GLYPH).  */
     struct { int from, to; } cmp;
+    /* Pixel offsets for upper and lower part of the acronym.  */
+    struct {
+      short upper_xoff, upper_yoff;
+      short lower_xoff, lower_yoff;
+    } glyphless;
   } slice;
 
   /* A union of sub-structures for different glyph types.  */
@@ -433,6 +441,19 @@
     }
     stretch;
 
+    /* Sub-stretch for type == GLYPHLESS_GLYPH.  */
+    struct
+    {
+      /* Value is an enum of the type glyphless_display_method.  */
+      unsigned method : 2;
+      /* 1 iff this glyph is for a character of no font. */
+      unsigned for_no_font : 1;
+      /* Length of acronym or hexadecimal code string (at most 8).  */
+      unsigned len : 4;
+      /* Character to display.  Actually we need only 22 bits.  */
+      unsigned ch : 26;
+    } glyphless;
+
     /* Used to compare all bit-fields above in one step.  */
     unsigned val;
   } u;
@@ -1918,6 +1939,9 @@
   /* A composition (static and automatic).  */
   IT_COMPOSITION,
 
+  /* A glyphless character (e.g. ZWNJ, LRE).  */
+  IT_GLYPHLESS,
+
   /* An image.  */
   IT_IMAGE,
 
@@ -1964,6 +1988,20 @@
   WINDOW_WRAP
 };
 
+/* An enumerator for the method of displaying glyphless characters.  */
+
+enum glyphless_display_method
+  {
+    /* Display a thin (1-pixel width) space.  */
+    GLYPHLESS_DISPLAY_THIN_SPACE,
+    /* Display an empty box of proper width.  */
+    GLYPHLESS_DISPLAY_EMPTY_BOX,
+    /* Display an acronym string in a box.  */
+    GLYPHLESS_DISPLAY_ACRONYM,
+    /* Display a hexadecimal character code in a box.  */
+    GLYPHLESS_DISPLAY_HEXA_CODE
+  };
+
 struct it_slice
 {
   Lisp_Object x;
@@ -2295,6 +2333,10 @@
      PRODUCE_GLYPHS, this should be set beforehand too.  */
   int char_to_display;
 
+  /* If what == IT_GLYPHLESS, the method to display such a
+     character.  */
+  enum glyphless_display_method glyphless_method;
+
   /* If what == IT_IMAGE, the id of the image to display.  */
   int image_id;
 
@@ -2976,9 +3018,10 @@
 extern Lisp_Object Vmouse_autoselect_window;
 extern int unibyte_display_via_language_environment;
 extern EMACS_INT underline_minimum_offset;
+extern Lisp_Object Vglyphless_char_display;
 
 extern void reseat_at_previous_visible_line_start (struct it *);
-
+extern Lisp_Object lookup_glyphless_char_display (int, struct it *);
 extern int calc_pixel_width_or_height (double *, struct it *, Lisp_Object,
                                        struct font *, int, int *);
 
--- a/src/nsterm.m	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/nsterm.m	Mon Nov 01 16:56:16 2010 +0900
@@ -2983,6 +2983,22 @@
       ns_unfocus (s->f);
       break;
 
+    case GLYPHLESS_GLYPH:
+      n = ns_get_glyph_string_clip_rect (s, r);
+      ns_focus (s->f, r, n);
+
+      if (s->for_overlaps || (s->cmp_from > 0
+			      && ! s->first_glyph->u.cmp.automatic))
+        s->background_filled_p = 1;
+      else
+        ns_maybe_dumpglyphs_background
+          (s, s->first_glyph->type == COMPOSITE_GLYPH);
+      /* ... */ 
+      /* Not yet implemented.  */
+      /* ... */ 
+      ns_unfocus (s->f);
+      break;
+
     default:
       abort ();
     }
--- a/src/term.c	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/term.c	Mon Nov 01 16:56:16 2010 +0900
@@ -1501,6 +1501,8 @@
 static void produce_stretch_glyph (struct it *);
 static void append_composite_glyph (struct it *);
 static void produce_composite_glyph (struct it *);
+static void append_glyphless_glyph (struct it *, int, char *);
+static void produce_glyphless_glyph (struct it *, int, Lisp_Object);
 
 /* Append glyphs to IT's glyph_row.  Called from produce_glyphs for
    terminal frames if IT->glyph_row != NULL.  IT->char_to_display is
@@ -1609,6 +1611,12 @@
       goto done;
     }
 
+  if (it->what == IT_GLYPHLESS)
+    {
+      produce_glyphless_glyph (it, 0, Qnil);
+      goto done;
+    }
+
   if (it->char_to_display >= 040 && it->char_to_display < 0177)
     {
       it->pixel_width = it->nglyphs = 1;
@@ -1660,11 +1668,22 @@
     }
   else
     {
-      it->pixel_width = CHAR_WIDTH (it->char_to_display);
-      it->nglyphs = it->pixel_width;
-
-      if (it->glyph_row)
-	append_glyph (it);
+      Lisp_Object charset_list = FRAME_TERMINAL (it->f)->charset_list;
+
+      if (char_charset (it->char_to_display, charset_list, NULL))
+	{
+	  it->pixel_width = CHAR_WIDTH (it->char_to_display);
+	  it->nglyphs = it->pixel_width;
+	  if (it->glyph_row)
+	    append_glyph (it);
+	}
+      else
+	{
+	  Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
+
+	  xassert (it->what == IT_GLYPHLESS);
+	  produce_glyphless_glyph (it, 1, acronym);
+	}
     }
 
  done:
@@ -1844,6 +1863,161 @@
 }
 
 
+/* Append a glyph for a glyphless character to IT->glyph_row.  FACE_ID
+   is a face ID to be used for the glyph.  What actually appended are
+   glyphs of type CHAR_GLYPH of which characters are in STR
+   (it->nglyphs bytes).  */
+
+static void
+append_glyphless_glyph (struct it *it, int face_id, char *str)
+{
+  struct glyph *glyph, *end;
+  bidi_type_t bidi_type;
+  int resolved_level;
+  int i;
+
+  xassert (it->glyph_row);
+  glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
+  end = it->glyph_row->glyphs[1 + it->area];
+
+  /* If the glyph row is reversed, we need to prepend the glyph rather
+     than append it.  */
+  if (it->glyph_row->reversed_p && it->area == TEXT_AREA)
+    {
+      struct glyph *g;
+      int move_by = it->pixel_width;
+
+      /* Make room for the new glyphs.  */
+      if (move_by > end - glyph) /* don't overstep end of this area */
+	move_by = end - glyph;
+      for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
+	g[move_by] = *g;
+      glyph = it->glyph_row->glyphs[it->area];
+      end = glyph + move_by;
+    }
+
+  if (glyph >= end)
+    return;
+  glyph->type = CHAR_GLYPH;
+  glyph->pixel_width = 1;
+  glyph->face_id = face_id;
+  glyph->padding_p = 0;
+  glyph->charpos = CHARPOS (it->position);
+  glyph->object = it->object;
+  if (it->bidi_p)
+    {
+      glyph->resolved_level = it->bidi_it.resolved_level;
+      if ((it->bidi_it.type & 7) != it->bidi_it.type)
+	abort ();
+      glyph->bidi_type = it->bidi_it.type;
+    }
+  else
+    {
+      glyph->resolved_level = 0;
+      glyph->bidi_type = UNKNOWN_BT;
+    }
+
+  /* BIDI Note: we put the glyphs of characters left to right, even in
+     the REVERSED_P case because we write to the terminal
+     left-to-right.  */
+  for (i = 0; i < it->nglyphs && glyph < end; ++i)
+    {
+      if (i > 0)
+	glyph[0] = glyph[-1];
+      glyph->u.ch = str[i];
+      ++it->glyph_row->used[it->area];
+      ++glyph;
+    }
+}
+
+/* Declared in xdisp.c */
+extern struct frame *last_glyphless_glyph_frame;
+extern unsigned last_glyphless_glyph_face_id;
+extern int last_glyphless_glyph_merged_face_id;
+extern Lisp_Object Qglyphless_char;
+
+/* Produce glyphs for a glyphless character for iterator IT.
+   IT->glyphless_method specifies which method to use for displaying
+   the character.  See the description of enum
+   glyphless_display_method in dispextern.h for the detail.
+
+   FOR_NO_FONT is nonzero if and only if this is for a character that
+   is not supproted by the coding system of the terminal.  ACRONYM, if
+   non-nil, is an acronym string for the character.
+
+   The glyphs actually produced are of type CHAR_GLYPH.  */
+
+static void
+produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
+{
+  int face_id;
+  struct face *face;
+  int width, len;
+  char buf[9], *str = "    ";
+
+  /* Get a face ID for the glyph by utilizing a cache (the same way as
+     doen for `escape-glyph' in get_next_display_element).  */
+  if (it->f == last_glyphless_glyph_frame
+      && it->face_id == last_glyphless_glyph_face_id)
+    {
+      face_id = last_glyphless_glyph_merged_face_id;
+    }
+  else
+    {
+      /* Merge the `glyphless-char' face into the current face.  */
+      face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
+      last_glyphless_glyph_frame = it->f;
+      last_glyphless_glyph_face_id = it->face_id;
+      last_glyphless_glyph_merged_face_id = face_id;
+    }
+
+  if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
+    {
+      /* As there's no way to produce a thin space, we produce
+	 a space of canonical width..  */
+      len = 1;
+    }
+  else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
+    {
+      len = CHAR_WIDTH (it->c);
+      if (len == 0)
+	len = 1;
+      else if (width > 4)
+	len = 4;
+    }
+  else
+    {
+      if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
+	{
+	  int i;
+
+	  if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
+	    acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
+	  buf[0] = '[';
+	  str = STRINGP (acronym) ? (char *) SDATA (acronym) : "";
+	  for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++)
+	    buf[1 + len] = str[len];
+	  buf[1 + len] = ']';
+	  len += 2;
+	}
+      else
+	{
+	  xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEXA_CODE);
+	  len = (it->c < 0x100 ? sprintf (buf, "U+%02X", it->c)
+		 : it->c < 0x10000 ? sprintf (buf, "U+%04X", it->c)
+		 : it->c <= MAX_UNICODE_CHAR ? sprintf (buf, "U+%06X", it->c)
+		 : sprintf (buf, "E+%06X", it->c));
+	}
+      str = buf;
+    }
+
+  it->pixel_width = len;
+  it->nglyphs = len;
+  if (len > 0 && it->glyph_row)
+    append_glyphless_glyph (it, face_id, str);
+}
+
+
 /* Get information about special display element WHAT in an
    environment described by IT.  WHAT is one of IT_TRUNCATION or
    IT_CONTINUATION.  Maybe produce glyphs for WHAT if IT has a
--- a/src/termhooks.h	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/termhooks.h	Mon Nov 01 16:56:16 2010 +0900
@@ -328,6 +328,11 @@
   /* Parameter alist of this terminal.  */
   Lisp_Object param_alist;
 
+  /* List of charsets supported by the terminal.  It is set by
+     Fset_terminal_coding_system_internal along with
+     the member terminal_coding.  */
+  Lisp_Object charset_list;
+
   /* All fields before `next_terminal' should be Lisp_Object and are traced
      by the GC.  All fields afterwards are ignored by the GC.  */
 
--- a/src/w32gui.h	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/w32gui.h	Mon Nov 01 16:56:16 2010 +0900
@@ -59,13 +59,13 @@
 
 /* Dealing with bits of wchar_t as if they were an XChar2b.  */
 #define STORE_XCHAR2B(chp, byte1, byte2) \
-  ((*chp) = ((XChar2b)((((byte1) & 0x00ff) << 8) | ((byte2) & 0x00ff))))
+  ((*(chp)) = ((XChar2b)((((byte1) & 0x00ff) << 8) | ((byte2) & 0x00ff))))
 
 #define XCHAR2B_BYTE1(chp) \
- (((*chp) & 0xff00) >> 8)
+  (((*(chp)) & 0xff00) >> 8)
 
 #define XCHAR2B_BYTE2(chp) \
- ((*chp) & 0x00ff)
+  ((*(chp)) & 0x00ff)
 
 
 /* Windows equivalent of XImage.  */
--- a/src/w32term.c	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/w32term.c	Mon Nov 01 16:56:16 2010 +0900
@@ -1394,6 +1394,94 @@
 }
 
 
+/* Draw the foreground of glyph string S for glyphless characters.  */
+
+static void
+x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
+{
+  struct glyph *glyph = s->first_glyph;
+  XChar2b char2b[8];
+  int x, i, j;
+  int with_background;
+
+  /* If first glyph of S has a left box line, start drawing the text
+     of S to the right of that box line.  */
+  if (s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->x + eabs (s->face->box_line_width);
+  else
+    x = s->x;
+
+  SetTextColor (s->hdc, s->gc->foreground);
+  SetBkColor (s->hdc, s->gc->background);
+  SetTextAlign (s->hdc, TA_BASELINE | TA_LEFT);
+
+  s->char2b = char2b;
+  with_background = ! (s->for_overlaps
+		       || (s->background_filled_p && s->hl != DRAW_CURSOR));
+  for (i = 0; i < s->nchars; i++, glyph++)
+    {
+      char buf[7], *str = NULL;
+      int len = glyph->u.glyphless.len;
+
+      if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
+	{
+	  if (len > 1
+	      && CHAR_TABLE_P (Vglyphless_char_display)
+	      && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
+		  >= 1))
+	    {
+	      Lisp_Object acronym
+		= (! glyph->u.glyphless.for_no_font
+		   ? CHAR_TABLE_REF (Vglyphless_char_display,
+				     glyph->u.glyphless.ch)
+		   : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+	      if (STRINGP (acronym))
+		str = (char *) SDATA (acronym);
+	    }
+	}
+      else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEXA_CODE)
+	{
+	  sprintf ((char *) buf, "%0*X",
+		   glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
+		   glyph->u.glyphless.ch);
+	  str = buf;
+	}
+
+      if (str)
+	{
+	  struct font *font = s->font;
+	  int upper_len = (len + 1) / 2;
+	  unsigned code;
+	  HFONT old_font;
+
+	  old_font = SelectObject (s->hdc, FONT_HANDLE (font));
+	  /* It is assured that all LEN characters in STR is ASCII.  */
+	  for (j = 0; j < len; j++)
+	    {
+	      code = font->driver->encode_char (font, str[j]);
+	      STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
+	    }
+	  font->driver->draw (s, 0, upper_len,
+			      x + glyph->slice.glyphless.upper_xoff,
+			      s->ybase + glyph->slice.glyphless.upper_yoff,
+			      with_background);
+	  font->driver->draw (s, upper_len, len,
+			      x + glyph->slice.glyphless.lower_xoff,
+			      s->ybase + glyph->slice.glyphless.lower_yoff,
+			      with_background);
+	  SelectObject (s->hdc, old_font);
+	}
+      if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
+	w32_draw_rectangle (s->hdc, s->gc,
+			    x, s->ybase - glyph->ascent,
+			    glyph->pixel_width - 1,
+			    glyph->ascent + glyph->descent - 1);
+      x += glyph->pixel_width;
+   }
+}
+
+
 /* Brightness beyond which a color won't have its highlight brightness
    boosted.
 
@@ -2282,6 +2370,14 @@
       x_draw_composite_glyph_string_foreground (s);
       break;
 
+    case GLYPHLESS_GLYPH:
+      if (s->for_overlaps)
+	s->background_filled_p = 1;
+      else
+	x_draw_glyph_string_background (s, 0);
+      x_draw_glyphless_glyph_string_foreground (s);
+      break;
+
     default:
       abort ();
     }
--- a/src/xdisp.c	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/xdisp.c	Mon Nov 01 16:56:16 2010 +0900
@@ -932,6 +932,21 @@
 /* Number of seconds to wait before displaying an hourglass cursor.  */
 Lisp_Object Vhourglass_delay;
 
+/* Name of the face used to display glyphless characters.  */
+Lisp_Object Qglyphless_char;
+
+/* Char-table to control the display of glyphless characters.  */
+Lisp_Object Vglyphless_char_display;
+
+/* Symbol for the purpose of Vglyphless_char_display.  */
+Lisp_Object Qglyphless_char_display;
+
+/* Method symbols for Vglyphless_char_display.  */
+static Lisp_Object Qhexa_code, Qempty_box, Qthin_space, Qzero_width;
+
+/* Default pixel width of `thin-space' display method.  */
+#define THIN_SPACE_WIDTH 1
+
 /* Default number of seconds to wait before displaying an hourglass
    cursor.  */
 #define DEFAULT_HOURGLASS_DELAY 1
@@ -5732,6 +5747,57 @@
 				 (IT)->string)))
 
 
+/* Lookup the char-table Vglyphless_char_display for character C (-1
+   if we want information for no-font case), and return the display
+   method symbol.  By side-effect, update it->what and
+   it->glyphless_method.  This function is called from
+   get_next_display_element for each character element, and from
+   x_produce_glyphs when no suitable font was found.  */
+
+Lisp_Object
+lookup_glyphless_char_display (int c, struct it *it)
+{
+  Lisp_Object glyphless_method = Qnil;
+
+  if (CHAR_TABLE_P (Vglyphless_char_display)
+      && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) >= 1)
+    glyphless_method = (c >= 0
+			? CHAR_TABLE_REF (Vglyphless_char_display, c)
+			: XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+ retry:
+  if (NILP (glyphless_method))
+    {
+      if (c >= 0)
+	/* The default is to display the character by a proper font.  */
+	return Qnil;
+      /* The default for the no-font case is to display an empty box.  */
+      glyphless_method = Qempty_box;
+    }
+  if (EQ (glyphless_method, Qzero_width))
+    {
+      if (c >= 0)
+	return glyphless_method;
+      /* This method can't be used for the no-font case.  */
+      glyphless_method = Qempty_box;
+    }
+  if (EQ (glyphless_method, Qthin_space))
+    it->glyphless_method = GLYPHLESS_DISPLAY_THIN_SPACE;
+  else if (EQ (glyphless_method, Qempty_box))
+    it->glyphless_method = GLYPHLESS_DISPLAY_EMPTY_BOX;
+  else if (EQ (glyphless_method, Qhexa_code))
+    it->glyphless_method = GLYPHLESS_DISPLAY_HEXA_CODE;
+  else if (STRINGP (glyphless_method))
+    it->glyphless_method = GLYPHLESS_DISPLAY_ACRONYM;
+  else
+    {
+      /* Invalid value.  We use the default method.  */
+      glyphless_method = Qnil;
+      goto retry;
+    }
+  it->what = IT_GLYPHLESS;
+  return glyphless_method;
+}
+
 /* Load IT's display element fields with information about the next
    display element from the current position of IT.  Value is zero if
    end of buffer (or C string) is reached.  */
@@ -5740,6 +5806,10 @@
 static unsigned last_escape_glyph_face_id = (1 << FACE_ID_BITS);
 static int last_escape_glyph_merged_face_id = 0;
 
+struct frame *last_glyphless_glyph_frame = NULL;
+unsigned last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
+int last_glyphless_glyph_merged_face_id = 0;
+
 int
 get_next_display_element (struct it *it)
 {
@@ -5818,6 +5888,15 @@
 	      goto get_next;
 	    }
 
+	  if (! NILP (lookup_glyphless_char_display (c, it)))
+	    {
+	      if (it->what == IT_GLYPHLESS)
+		goto done;
+	      /* Don't display this character.  */
+	      set_iterator_to_next (it, 0);
+	      goto get_next;
+	    }
+
 	  if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
 	    nbsp_or_shy = (c == 0xA0   ? char_is_nbsp
 			   : c == 0xAD ? char_is_soft_hyphen
@@ -6032,6 +6111,7 @@
     }
 #endif
 
+ done:
   /* Is this character the last one of a run of characters with
      box?  If yes, set IT->end_of_box_run_p to 1.  */
   if (it->face_box_p
@@ -11579,6 +11659,8 @@
   reconsider_clip_changes (w, current_buffer);
   last_escape_glyph_frame = NULL;
   last_escape_glyph_face_id = (1 << FACE_ID_BITS);
+  last_glyphless_glyph_frame = NULL;
+  last_glyphless_glyph_face_id = (1 << FACE_ID_BITS);
 
   /* If new fonts have been loaded that make a glyph matrix adjustment
      necessary, do it.  */
@@ -20657,6 +20739,42 @@
 }
 
 
+/* Fill glyph string S from a sequence glyphs for glyphless characters.
+   See the comment of fill_glyph_string for arguments.
+   Value is the index of the first glyph not in S.  */
+
+
+static int
+fill_glyphless_glyph_string (struct glyph_string *s, int face_id,
+			     int start, int end, int overlaps)
+{
+  struct glyph *glyph, *last;
+  int voffset;
+
+  xassert (s->first_glyph->type == GLYPHLESS_GLYPH);
+  s->for_overlaps = overlaps;
+  glyph = s->row->glyphs[s->area] + start;
+  last = s->row->glyphs[s->area] + end;
+  voffset = glyph->voffset;
+  s->face = FACE_FROM_ID (s->f, face_id);
+  s->font = s->face->font;
+  s->nchars = 1;
+  s->width = glyph->pixel_width;
+  glyph++;
+  while (glyph < last
+	 && glyph->type == GLYPHLESS_GLYPH
+	 && glyph->voffset == voffset
+	 && glyph->face_id == face_id)
+    {
+      s->nchars++;
+      s->width += glyph->pixel_width;
+      glyph++;
+    }
+  s->ybase += voffset;
+  return glyph - s->row->glyphs[s->area];
+}
+
+
 /* Fill glyph string S from a sequence of character glyphs.
 
    FACE_ID is the face id of the string.  START is the index of the
@@ -21167,6 +21285,28 @@
   } while (0)
 
 
+/* Add a glyph string for a sequence of glyphless character's glyphs
+   to the list of strings between HEAD and TAIL.  The meanings of
+   arguments are the same as those of BUILD_CHAR_GLYPH_STRINGS.  */
+
+#define BUILD_GLYPHLESS_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+  do									    \
+    {									    \
+      int face_id;							    \
+      XChar2b *char2b;							    \
+									    \
+      face_id = (row)->glyphs[area][START].face_id;			    \
+									    \
+      s = (struct glyph_string *) alloca (sizeof *s);			    \
+      INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL);		    \
+      append_glyph_string (&HEAD, &TAIL, s);				    \
+      s->x = (X);							    \
+      START = fill_glyphless_glyph_string (s, face_id, START, END,	    \
+					   overlaps);			    \
+    }									    \
+  while (0)
+
+
 /* Build a list of glyph strings between HEAD and TAIL for the glyphs
    of AREA of glyph row ROW on window W between indices START and END.
    HL overrides the face for drawing glyph strings, e.g. it is
@@ -21190,7 +21330,7 @@
 	      BUILD_CHAR_GLYPH_STRINGS (START, END, HEAD, TAIL,		\
 					HL, X, LAST_X);			\
 	      break;							\
-	      								\
+									\
 	    case COMPOSITE_GLYPH:					\
 	      if (first_glyph->u.cmp.automatic)				\
 		BUILD_GSTRING_GLYPH_STRING (START, END, HEAD, TAIL,	\
@@ -21199,21 +21339,26 @@
 		BUILD_COMPOSITE_GLYPH_STRING (START, END, HEAD, TAIL,	\
 					      HL, X, LAST_X);		\
 	      break;							\
-	      								\
+									\
 	    case STRETCH_GLYPH:						\
 	      BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL,	\
 					  HL, X, LAST_X);		\
 	      break;							\
-	      								\
+									\
 	    case IMAGE_GLYPH:						\
 	      BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL,		\
 					HL, X, LAST_X);			\
 	      break;							\
-	      								\
+									\
+	    case GLYPHLESS_GLYPH:					\
+	      BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL,	\
+					    HL, X, LAST_X);		\
+	      break;							\
+									\
 	    default:							\
 	      abort ();							\
 	    }								\
-	  								\
+									\
 	  if (s)							\
 	    {								\
 	      set_glyph_string_background_width (s, START, LAST_X);	\
@@ -22109,6 +22254,229 @@
 }
 
 
+/* Append a glyph for a glyphless character to IT->glyph_row.  FACE_ID
+   is a face ID to be used for the glyph.  FOR_NO_FONT is nonzero if
+   and only if this is for a character for which no font was found.
+
+   If the display method (it->glyphless_method) is
+   GLYPHLESS_DISPLAY_ACRONYM or GLYPHLESS_DISPLAY_HEXA_CODE, LEN is a
+   length of the acronym or the hexadecimal string, UPPER_XOFF and
+   UPPER_YOFF are pixel offsets for the upper part of the string,
+   LOWER_XOFF and LOWER_YOFF are for the lower part.
+
+   For the other display methods, LEN through LOWER_YOFF are zero.  */
+
+static void
+append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len,
+			short upper_xoff, short upper_yoff,
+			short lower_xoff, short lower_yoff)
+{
+  struct glyph *glyph;
+  enum glyph_row_area area = it->area;
+
+  glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+  if (glyph < it->glyph_row->glyphs[area + 1])
+    {
+      /* If the glyph row is reversed, we need to prepend the glyph
+	 rather than append it.  */
+      if (it->glyph_row->reversed_p && area == TEXT_AREA)
+	{
+	  struct glyph *g;
+
+	  /* Make room for the additional glyph.  */
+	  for (g = glyph - 1; g >= it->glyph_row->glyphs[area]; g--)
+	    g[1] = *g;
+	  glyph = it->glyph_row->glyphs[area];
+	}
+      glyph->charpos = CHARPOS (it->position);
+      glyph->object = it->object;
+      glyph->pixel_width = it->pixel_width;
+      glyph->ascent = it->ascent;
+      glyph->descent = it->descent;
+      glyph->voffset = it->voffset;
+      glyph->type = GLYPHLESS_GLYPH;
+      glyph->u.glyphless.method = it->glyphless_method;
+      glyph->u.glyphless.for_no_font = for_no_font;
+      glyph->u.glyphless.len = len;
+      glyph->u.glyphless.ch = it->c;
+      glyph->slice.glyphless.upper_xoff = upper_xoff;
+      glyph->slice.glyphless.upper_yoff = upper_yoff;
+      glyph->slice.glyphless.lower_xoff = lower_xoff;
+      glyph->slice.glyphless.lower_yoff = lower_yoff;
+      glyph->avoid_cursor_p = it->avoid_cursor_p;
+      glyph->multibyte_p = it->multibyte_p;
+      glyph->left_box_line_p = it->start_of_box_run_p;
+      glyph->right_box_line_p = it->end_of_box_run_p;
+      glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+				      || it->phys_descent > it->descent);
+      glyph->padding_p = 0;
+      glyph->glyph_not_available_p = 0;
+      glyph->face_id = face_id;
+      glyph->font_type = FONT_TYPE_UNKNOWN;
+      if (it->bidi_p)
+	{
+	  glyph->resolved_level = it->bidi_it.resolved_level;
+	  if ((it->bidi_it.type & 7) != it->bidi_it.type)
+	    abort ();
+	  glyph->bidi_type = it->bidi_it.type;
+	}
+      ++it->glyph_row->used[area];
+    }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
+}
+
+
+/* Produce a glyph for a glyphless character for iterator IT.
+   IT->glyphless_method specifies which method to use for displaying
+   the character.  See the description of enum
+   glyphless_display_method in dispextern.h for the detail.
+
+   FOR_NO_FONT is nonzero if and only if this is for a character for
+   which no font was found.  ACRONYM, if non-nil, is an acronym string
+   for the character.  */
+
+static void
+produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
+{
+  int face_id;
+  struct face *face;
+  struct font *font;
+  int base_width, base_height, width, height;
+  short upper_xoff, upper_yoff, lower_xoff, lower_yoff;
+  int len;
+
+  /* Get the metrics of the base font.  We always refer to the current
+     ASCII face.  */
+  face = FACE_FROM_ID (it->f, it->face_id)->ascii_face;
+  font = face->font ? face->font : FRAME_FONT (it->f);
+  it->ascent = FONT_BASE (font) + font->baseline_offset;
+  it->descent = FONT_DESCENT (font) - font->baseline_offset;
+  base_height = it->ascent + it->descent;
+  base_width = font->average_width;
+
+  /* Get a face ID for the glyph by utilizing a cache (the same way as
+     doen for `escape-glyph' in get_next_display_element).  */
+  if (it->f == last_glyphless_glyph_frame
+      && it->face_id == last_glyphless_glyph_face_id)
+    {
+      face_id = last_glyphless_glyph_merged_face_id;
+    }
+  else
+    {
+      /* Merge the `glyphless-char' face into the current face.  */
+      face_id = merge_faces (it->f, Qglyphless_char, 0, it->face_id);
+      last_glyphless_glyph_frame = it->f;
+      last_glyphless_glyph_face_id = it->face_id;
+      last_glyphless_glyph_merged_face_id = face_id;
+    }
+
+  if (it->glyphless_method == GLYPHLESS_DISPLAY_THIN_SPACE)
+    {
+      it->pixel_width = THIN_SPACE_WIDTH;
+      len = 0;
+      upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0;
+    }
+  else if (it->glyphless_method == GLYPHLESS_DISPLAY_EMPTY_BOX)
+    {
+      width = CHAR_WIDTH (it->c);
+      if (width == 0)
+	width = 1;
+      else if (width > 4)
+	width = 4;
+      it->pixel_width = base_width * width;
+      len = 0;
+      upper_xoff = upper_yoff = lower_xoff = lower_yoff = 0;
+    }
+  else
+    {
+      char buf[7], *str;
+      unsigned int code[6];
+      int upper_len;
+      int ascent, descent;
+      struct font_metrics metrics_upper, metrics_lower;
+
+      face = FACE_FROM_ID (it->f, face_id);
+      font = face->font ? face->font : FRAME_FONT (it->f);
+      PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+      if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
+	{
+	  if (! STRINGP (acronym) && CHAR_TABLE_P (Vglyphless_char_display))
+	    acronym = CHAR_TABLE_REF (Vglyphless_char_display, it->c);
+	  str = STRINGP (acronym) ? (char *) SDATA (acronym) : "";
+	}
+      else
+	{
+	  xassert (it->glyphless_method == GLYPHLESS_DISPLAY_HEXA_CODE);
+	  sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
+	  str = buf;
+	}
+      for (len = 0; str[len] && ASCII_BYTE_P (str[len]); len++)
+	code[len] = font->driver->encode_char (font, str[len]);
+      upper_len = (len + 1) / 2;
+      font->driver->text_extents (font, code, upper_len,
+				  &metrics_upper);
+      font->driver->text_extents (font, code + upper_len, len - upper_len,
+				  &metrics_lower);
+
+
+
+      /* +4 is for vertical bars of a box plus 1-pixel spaces at both side.  */
+      width = max (metrics_upper.width, metrics_lower.width) + 4;
+      upper_xoff = upper_yoff = 2; /* the typical case */
+      if (base_width >= width)
+	{
+	  /* Align the upper to the left, the lower to the right.  */
+	  it->pixel_width = base_width;
+	  lower_xoff = base_width - 2 - metrics_lower.width;
+	}
+      else
+	{
+	  /* Center the shorter one.  */
+	  it->pixel_width = width;
+	  if (metrics_upper.width >= metrics_lower.width)
+	    lower_xoff = (width - metrics_lower.width) / 2;
+	  else
+	    upper_xoff = (width - metrics_upper.width) / 2;
+	}
+  
+      /* +5 is for horizontal bars of a box plus 1-pixel spaces at
+	 top, bottom, and between upper and lower strings.  */
+      height = (metrics_upper.ascent + metrics_upper.descent
+		+ metrics_lower.ascent + metrics_lower.descent) + 5;
+      /* Center vertically.
+	 H:base_height, D:base_descent
+	 h:height, ld:lower_descent, la:lower_ascent, ud:upper_descent
+
+	 ascent = - (D - H/2 - h/2 + 1); "+ 1" for rounding up
+	 descent = D - H/2 + h/2;
+	 lower_yoff = descent - 2 - ld;
+	 upper_yoff = lower_yoff - la - 1 - ud;  */
+      ascent = - (it->descent - (base_height + height + 1) / 2);
+      descent = it->descent - (base_height - height) / 2;
+      lower_yoff = descent - 2 - metrics_lower.descent;
+      upper_yoff = (lower_yoff - metrics_lower.ascent - 1
+		    - metrics_upper.descent);
+      /* Don't make the height shorter than the base height. */
+      if (height > base_height)
+	{
+	  it->ascent = ascent;
+	  it->descent = descent;
+	}
+    }
+
+  it->phys_ascent = it->ascent;
+  it->phys_descent = it->descent;
+  if (it->glyph_row)
+    append_glyphless_glyph (it, face_id, for_no_font, len,
+			    upper_xoff, upper_yoff,
+			    lower_xoff, lower_yoff);
+  it->nglyphs = 1;
+  take_vertical_position_into_account (it);
+}
+
+
 /* RIF:
    Produce glyphs/get display metrics for the display element IT is
    loaded with.  See the description of struct it in dispextern.h
@@ -22126,28 +22494,24 @@
       XChar2b char2b;
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
       struct font *font = face->font;
-      int font_not_found_p = font == NULL;
       struct font_metrics *pcm = NULL;
       int boff;			/* baseline offset */
 
-      if (font_not_found_p)
-	{
-	  /* When no suitable font found, display an empty box based
-	     on the metrics of the font of the default face (or what
-	     remapped).  */
-	  struct face *no_font_face
-	    = FACE_FROM_ID (it->f,
-			    NILP (Vface_remapping_alist) ? DEFAULT_FACE_ID
-			    : lookup_basic_face (it->f, DEFAULT_FACE_ID));
-	  font = no_font_face->font;
-	  boff = font->baseline_offset;
-	}
-      else
-	{
-	  boff = font->baseline_offset;
-	  if (font->vertical_centering)
-	    boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
-	}
+      if (font == NULL)
+	{
+	  /* When no suitable font is found, display this character by
+	     the method specified in the first extra slot of
+	     Vglyphless_char_display.  */
+	  Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
+
+	  xassert (it->what == IT_GLYPHLESS);
+	  produce_glyphless_glyph (it, 1, STRINGP (acronym) ? acronym : Qnil);
+	  goto done;
+	}
+
+      boff = font->baseline_offset;
+      if (font->vertical_centering)
+	boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
 
       if (it->char_to_display != '\n' && it->char_to_display != '\t')
 	{
@@ -22167,8 +22531,7 @@
  	      it->descent = FONT_DESCENT (font) - boff;
  	    }
 
-	  if (! font_not_found_p
-	      && get_char_glyph_code (it->char_to_display, font, &char2b))
+	  if (get_char_glyph_code (it->char_to_display, font, &char2b))
 	    {
 	      pcm = get_per_char_metric (it->f, font, &char2b);
 	      if (pcm->width == 0
@@ -22758,11 +23121,14 @@
       if (it->glyph_row)
 	append_composite_glyph (it);
     }
+  else if (it->what == IT_GLYPHLESS)
+    produce_glyphless_glyph (it, 0, Qnil);
   else if (it->what == IT_IMAGE)
     produce_image_glyph (it);
   else if (it->what == IT_STRETCH)
     produce_stretch_glyph (it);
 
+ done:
   /* Accumulate dimensions.  Note: can't assume that it->descent > 0
      because this isn't true for images with `:ascent 100'.  */
   xassert (it->ascent >= 0 && it->descent >= 0);
@@ -26592,6 +26958,35 @@
 
   hourglass_atimer = NULL;
   hourglass_shown_p = 0;
+
+  DEFSYM (Qglyphless_char, "glyphless-char");
+  DEFSYM (Qhexa_code, "hexa-code");
+  DEFSYM (Qempty_box, "empty-box");
+  DEFSYM (Qthin_space, "thin-space");
+  DEFSYM (Qzero_width, "zero-width");
+
+  DEFSYM (Qglyphless_char_display, "glyphless-char-display");
+  /* Intern this now in case it isn't already done.
+     Setting this variable twice is harmless.
+     But don't staticpro it here--that is done in alloc.c.  */
+  Qchar_table_extra_slots = intern_c_string ("char-table-extra-slots");
+  Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_number (1));
+
+  DEFVAR_LISP ("glyphless-char-display", &Vglyphless_char_display,
+	       doc: /* Char-table to control displaying of glyphless characters.
+Each element, if non-nil, is an ASCII acronym string (displayed in a box)
+or one of these symbols:
+  hexa-code: display with hexadecimal character code in a box
+  empty-box: display with an empty box
+  thin-space: display with 1-pixel width space
+  zero-width: don't display
+
+It has one extra slot to control the display of a character for which
+no font is found.  The value of the slot is `hexa-code' or `empty-box'.
+The default is `empty-box'.  */);
+  Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil);
+  Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0),
+			      Qempty_box);
 }
 
 
--- a/src/xterm.c	Mon Nov 01 00:40:11 2010 -0700
+++ b/src/xterm.c	Mon Nov 01 16:56:16 2010 +0900
@@ -1330,6 +1330,83 @@
 }
 
 
+/* Draw the foreground of glyph string S for glyphless characters.  */
+
+static void
+x_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
+{
+  struct glyph *glyph = s->first_glyph;
+  XChar2b char2b[8];
+  int x, i, j;
+
+  /* If first glyph of S has a left box line, start drawing the text
+     of S to the right of that box line.  */
+  if (s->face && s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->x + eabs (s->face->box_line_width);
+  else
+    x = s->x;
+
+  s->char2b = char2b;
+
+  for (i = 0; i < s->nchars; i++, glyph++)
+    {
+      char buf[7], *str = NULL;
+      int len = glyph->u.glyphless.len;
+
+      if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
+	{
+	  if (len > 0
+	      && CHAR_TABLE_P (Vglyphless_char_display)
+	      && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
+		  >= 1))
+	    {
+	      Lisp_Object acronym
+		= (! glyph->u.glyphless.for_no_font
+		   ? CHAR_TABLE_REF (Vglyphless_char_display,
+				     glyph->u.glyphless.ch)
+		   : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
+	      if (STRINGP (acronym))
+		str = (char *) SDATA (acronym);
+	    }
+	}
+      else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEXA_CODE)
+	{
+	  sprintf ((char *) buf, "%0*X",
+		   glyph->u.glyphless.ch < 0x10000 ? 4 : 6,
+		   glyph->u.glyphless.ch);
+	  str = buf;
+	}
+
+      if (str)
+	{
+	  int upper_len = (len + 1) / 2;
+	  unsigned code;
+
+	  /* It is assured that all LEN characters in STR is ASCII.  */
+	  for (j = 0; j < len; j++)
+	    {
+	      code = s->font->driver->encode_char (s->font, str[j]);
+	      STORE_XCHAR2B (char2b + j, code >> 8, code & 0xFF);
+	    }
+	  s->font->driver->draw (s, 0, upper_len,
+				 x + glyph->slice.glyphless.upper_xoff,
+				 s->ybase + glyph->slice.glyphless.upper_yoff,
+				 0);
+	  s->font->driver->draw (s, upper_len, len,
+				 x + glyph->slice.glyphless.lower_xoff,
+				 s->ybase + glyph->slice.glyphless.lower_yoff,
+				 0);
+	}
+      if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
+	XDrawRectangle (s->display, s->window, s->gc,
+			x, s->ybase - glyph->ascent,
+			glyph->pixel_width - 1,
+			glyph->ascent + glyph->descent - 1);
+      x += glyph->pixel_width;
+   }
+}
+
 #ifdef USE_X_TOOLKIT
 
 static struct frame *x_frame_of_widget (Widget);
@@ -2656,6 +2733,14 @@
       x_draw_composite_glyph_string_foreground (s);
       break;
 
+    case GLYPHLESS_GLYPH:
+      if (s->for_overlaps)
+	s->background_filled_p = 1;
+      else
+	x_draw_glyph_string_background (s, 1);
+      x_draw_glyphless_glyph_string_foreground (s);
+      break;
+
     default:
       abort ();
     }