(describe-property-list): Sync to HEAD.
[bpt/emacs.git] / src / fontset.c
index db20345..e6dcc08 100644 (file)
@@ -39,6 +39,7 @@ Boston, MA 02111-1307, USA.  */
 #include "keyboard.h"
 #include "frame.h"
 #include "dispextern.h"
+#include "intervals.h"
 #include "fontset.h"
 #include "window.h"
 
@@ -84,39 +85,42 @@ EXFUN (Fclear_face_cache, 1);
    where FAMILY, WEIGHT, SLANT, SWIDTH, ADSTYLE, REGISTRY, and
    FONT-NAME are strings.
 
-   ENCODING is a charset ID or a char-table that can convert
-   characters to glyph codes of the corresponding font.
+   Note: Currently WEIGHT through ADSTYLE are ignored.
 
-   REPERTORY is a charset ID or nil.  If REPERTORY is a charset ID,
-   the repertory of the charset exactly matches with that of the font.
-   If REPERTORY is nil, we consult with the font itself to get the
-   repertory.
+   ENCODING is a charset ID that can convert characters to glyph codes
+   of the corresponding font.
+
+   REPERTORY is a charset ID, a char-table, or nil.  If REPERTORY is a
+   charset ID, the repertory of the charset exactly matches with that
+   of the font.  If REPERTORY is a char-table, all characters who have
+   a non-nil value in the table are supported.  If REPERTORY is nil,
+   we consult with the font itself to get the repertory.
 
    ENCODING and REPERTORY are extracted from the variable
-   Vfont_encoding_alist by using a font name generated form FONT-SPEC
-   (if it is a vector) or FONT-NAME as a key.
+   Vfont_encoding_alist by using a font name generated from FONT-SPEC
+   (if it is a vector) or FONT-NAME as a matching target.
 
 
    An element of a realized fontset is nil or t, or has this form:
 
-       [CHARSET-PRIORITY-LIST-TICK PREFERRED-CHARSET-ID PREFERRED-FONT-DEF
-        FONT-DEF0 FONT-DEF1 ...].
+       [CHARSET-ORDERED-LIST-TICK PREFERRED-CHARSET-ID
+        PREFERRED-RFONT-DEF RFONT-DEF0 RFONT-DEF1 ...].
 
-   FONT-DEFn has this form:
+   RFONT-DEFn (i.e. Realized FONT-DEF) has this form:
 
-       [ FACE-ID FONT-INDEX FONT-DEF ]
+       [ FACE-ID FONT-INDEX FONT-DEF OPENED-FONT-NAME ]
 
-   FONT-DEFn is automatically reordered by the current charset
+   RFONT-DEFn is automatically reordered by the current charset
    priority list.
 
-   The value nil means that we have not yet generated FONT-VECTOR from
-   the base of the fontset.
+   The value nil means that we have not yet generated the above vector
+   from the base of the fontset.
 
    The value t means that no font is available for the corresponding
    range of characters.
 
 
-   A fontset has 8 extra slots.
+   A fontset has 9 extra slots.
 
    The 1st slot: the ID number of the fontset
 
@@ -151,6 +155,10 @@ EXFUN (Fclear_face_cache, 1);
        realized: If the base is not the default fontset, a fontset
        realized from the default fontset, else nil.
 
+   The 9th slot:
+       base: Same as element value (but for fallback fonts).
+       realized: Likewise.
+
    All fontsets are recorded in the vector Vfontset_table.
 
 
@@ -239,6 +247,7 @@ void (*check_window_system_func) P_ ((void));
 /* Prototype declarations for static functions.  */
 static Lisp_Object fontset_add P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
                                    Lisp_Object));
+static Lisp_Object fontset_font P_ ((Lisp_Object, int, struct face *, int));
 static Lisp_Object make_fontset P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
 static Lisp_Object fontset_pattern_regexp P_ ((Lisp_Object));
 static void accumulate_script_ranges P_ ((Lisp_Object, Lisp_Object,
@@ -279,7 +288,10 @@ fontset_id_valid_p (id)
 #define FONTSET_FRAME(fontset)         XCHAR_TABLE (fontset)->extras[3]
 #define FONTSET_NOFONT_FACE(fontset)   XCHAR_TABLE (fontset)->extras[5]
 #define FONTSET_REPERTORY(fontset)     XCHAR_TABLE (fontset)->extras[6]
-#define FONTSET_FALLBACK(fontset)      XCHAR_TABLE (fontset)->extras[7]
+#define FONTSET_DEFAULT(fontset)       XCHAR_TABLE (fontset)->extras[7]
+
+/* For both base and realized fontset.  */
+#define FONTSET_FALLBACK(fontset)      XCHAR_TABLE (fontset)->extras[8]
 
 #define BASE_FONTSET_P(fontset)                (NILP (FONTSET_BASE (fontset)))
 
@@ -360,51 +372,54 @@ fontset_ref_and_range (fontset, c, from, to)
    replace with ELT, if ADD is `prepend', prepend ELT, otherwise,
    append ELT.  */
 
-#define FONTSET_ADD(fontset, range, elt, add)                          \
-  (NILP (add)                                                          \
-   ? Fset_char_table_range ((fontset), (range),                                \
-                           Fmake_vector (make_number (1), (elt)))      \
+#define FONTSET_ADD(fontset, range, elt, add)                               \
+  (NILP (add)                                                               \
+   ? (NILP (range)                                                          \
+      ? (FONTSET_FALLBACK (fontset) = Fmake_vector (make_number (1), (elt))) \
+      : Fset_char_table_range ((fontset), (range),                          \
+                              Fmake_vector (make_number (1), (elt))))       \
    : fontset_add ((fontset), (range), (elt), (add)))
 
 static Lisp_Object
 fontset_add (fontset, range, elt, add)
      Lisp_Object fontset, range, elt, add;
 {
-  int from, to, from1, to1;
-  Lisp_Object elt1;
-
-  from = XINT (XCAR (range));
-  to = XINT (XCDR (range));
-  do {
-    elt1 = char_table_ref_and_range (fontset, from, &from1, &to1);
-    if (to < to1)
-      to1 = to;
-    if (NILP (elt1))
-      elt1 = Fmake_vector (make_number (1), elt);
-    else
-      {
-       int i, i0 = 1, i1 = ASIZE (elt1) + 1;
-       Lisp_Object new;
-
-       new = Fmake_vector (make_number (i1), elt);
-       if (EQ (add, Qappend))
-         i0--, i1--;
-       for (i = 0; i0 < i1; i++, i0++)
-         ASET (new, i0, AREF (elt1, i));
-       elt1 = new;
-      }
-    char_table_set_range (fontset, from, to1, elt1);
-    from = to1 + 1;
-  } while (from < to);
+  Lisp_Object args[2];
+  int idx = (EQ (add, Qappend) ? 0 : 1);
+
+  args[1 - idx] = Fmake_vector (make_number (1), elt);
+
+  if (CONSP (range))
+    {
+      int from = XINT (XCAR (range));
+      int to = XINT (XCDR (range));
+      int from1, to1;
+
+      do {
+       args[idx] = char_table_ref_and_range (fontset, from, &from1, &to1);
+       if (to < to1)
+         to1 = to;
+       char_table_set_range (fontset, from, to1,
+                             NILP (args[idx]) ? args[1 - idx]
+                             : Fvconcat (2, args));
+       from = to1 + 1;
+      } while (from < to);
+    }
+  else
+    {
+      args[idx] = FONTSET_FALLBACK (fontset);
+      FONTSET_FALLBACK (fontset)
+       = NILP (args[idx]) ? args[1 - idx] : Fvconcat (2, args);
+    }
   return Qnil;
 }
 
 
 /* Update FONTSET_ELEMENT which has this form:
-       [CHARSET-PRIORITY-LIST-TICK PREFERRED-CHARSET-ID INDEX
-        FONT-DEF0 FONT-DEF1 ...].
-   Reorder FONT-DEFs according to the current order of charset
-   (Vcharset_ordered_list), and update CHARSET-PRIORITY-LIST-TICK to
+       [CHARSET-ORDERED-LIST-TICK PREFERRED-CHARSET-ID PREFERRED-RFONT-DEF
+        RFONT-DEF0 RFONT-DEF1 ...].
+   Reorder RFONT-DEFs according to the current order of charset
+   (Vcharset_ordered_list), and update CHARSET-ORDERED-LIST-TICK to
    the latest value.  */
 
 static void
@@ -420,7 +435,7 @@ reorder_font_vector (fontset_element)
   ASET (fontset_element, 0, make_number (charset_ordered_list_tick));
   size = ASIZE (fontset_element) - 3;
   if (size <= 1)
-    /* No need of reordering VEC.  */
+    /* No need to reorder VEC.  */
     return;
   charset_id_table = (int *) alloca (sizeof (int) * size);
   new_vec = (Lisp_Object *) alloca (sizeof (Lisp_Object) * size);
@@ -468,10 +483,7 @@ load_font_get_repertory (f, face, font_def, fontset)
   int charset;
 
   font_name = choose_face_font (f, face->lface, AREF (font_def, 0), NULL);
-  if (NATNUMP (AREF (font_def, 1)))
-    charset = XINT (AREF (font_def, 1));
-  else
-    charset = -1;
+  charset = XINT (AREF (font_def, 1));
   if (! (font_info = fs_load_font (f, font_name, charset)))
     return -1;
 
@@ -493,12 +505,13 @@ load_font_get_repertory (f, face, font_def, fontset)
 }
 
 
-/* Return a face ID registerd in the realized fontset FONTSET for the
-   character C.  If a face is not yet set, return -1 (if FACE is NULL)
-   or realize a proper face from FACE and return it.  */
+/* Return RFONT-DEF (vector) in the realized fontset FONTSET for the
+   character C.  If the corresponding font is not yet opened, open it
+   (if FACE is not NULL) or return Qnil (if FACE is NULL).
+   If no proper font is found for C, return Qnil.  */
 
-static int
-fontset_face (fontset, c, face, id)
+static Lisp_Object
+fontset_font (fontset, c, face, id)
      Lisp_Object fontset;
      int c;
      struct face *face;
@@ -510,47 +523,45 @@ fontset_face (fontset, c, face, id)
   FRAME_PTR f = XFRAME (FONTSET_FRAME (fontset));
 
   base_fontset = FONTSET_BASE (fontset);
-  elt = CHAR_TABLE_REF (fontset, c);
+  vec = CHAR_TABLE_REF (fontset, c);
+  if (EQ (vec, Qt))
+    goto try_fallback;
 
-  if (EQ (elt, Qt))
-    goto try_default;
-
-  if (NILP (elt))
+  if (NILP (vec))
     {
       /* We have not yet decided a face for C.  */
       Lisp_Object range;
 
       if (! face)
-       return -1;
+       return Qnil;
       elt = FONTSET_REF_AND_RANGE (base_fontset, c, from, to);
       range = Fcons (make_number (from), make_number (to));
       if (NILP (elt))
        {
          /* Record that we have no font for characters of this
             range.  */
-         FONTSET_SET (fontset, range, Qt);
-         goto try_default;
+         vec = Qt;
+         FONTSET_SET (fontset, range, vec);
+         goto try_fallback;
        }
       /* Build a vector [ -1 -1 nil NEW-ELT0 NEW-ELT1 NEW-ELT2 ... ],
         where the first -1 is to force reordering of NEW-ELTn,
-        NEW-ETLn is [nil nil AREF (elt, n)].  */
+        NEW-ETLn is [nil nil AREF (elt, n) nil].  */
       vec = Fmake_vector (make_number (ASIZE (elt) + 3), make_number (-1));
       ASET (vec, 2, Qnil);
       for (i = 0; i < ASIZE (elt); i++)
        {
          Lisp_Object tmp;
 
-         tmp = Fmake_vector (make_number (3), Qnil);
+         tmp = Fmake_vector (make_number (4), Qnil);
          ASET (tmp, 2, AREF (elt, i));
          ASET (vec, 3 + i, tmp);
        }
-      /* Then store it in the fontset.  -1 is to force
-        reordering of FONT-VECTOR.  */
+      /* Then store it in the fontset.  */
       FONTSET_SET (fontset, range, vec);
     }
-  else
-    vec = elt;
 
+ retry:
   if (XINT (AREF (vec, 0)) != charset_ordered_list_tick)
     /* The priority of charsets is changed after we selected a face
        for C last time.  */
@@ -578,7 +589,7 @@ fontset_face (fontset, c, face, id)
        }
     }
 
-  /* Find the first available font in the font vector VEC.  */
+  /* Find the first available font in the vector of RFONT-DEF.  */
   for (; i < ASIZE (vec); i++)
     {
       Lisp_Object font_def;
@@ -586,17 +597,17 @@ fontset_face (fontset, c, face, id)
       elt = AREF (vec, i);
       if (NILP (elt))
        continue;
-      /* ELT == [ FACE-ID FONT-INDEX [ FONT-SPEC ENCODING REPERTORY ] ] */
-      font_def = AREF (elt, 2);
+      /* ELT == [ FACE-ID FONT-INDEX FONT-DEF OPENED-FONT-NAME ] */
       if (INTEGERP (AREF (elt, 1)) && XINT (AREF (elt, 1)) < 0)
        /* We couldn't open this font last time.  */
        continue;
 
-      if (!face && (NILP (AREF (elt, 1)) || NILP (AREF (elt, 0))))
-       /* We have not yet opened the font, or we have not yet made a
-          realized face for the font.  */
-       return -1;
+      if (!face && NILP (AREF (elt, 1)))
+       /* We have not yet opened the font.  */
+       return Qnil;
 
+      font_def = AREF (elt, 2);
+      /* FONT_DEF == [ FONT-SPEC ENCODING REPERTORY ] */
       if (INTEGERP (AREF (font_def, 2)))
        {
          /* The repertory is specified by charset ID.  */
@@ -607,6 +618,13 @@ fontset_face (fontset, c, face, id)
            /* This font can't display C.  */
            continue;
        }
+      else if (CHAR_TABLE_P (AREF (font_def, 2)))
+       {
+         /* The repertory is specified by a char table.  */
+         if (NILP (CHAR_TABLE_REF (AREF (font_def, 2), c)))
+           /* This font can't display C.  */
+           continue;
+       }
       else
        {
          Lisp_Object slot;
@@ -616,68 +634,82 @@ fontset_face (fontset, c, face, id)
              /* We have not yet opened a font matching this spec.
                 Open the best matching font now and register the
                 repertory.  */
+             struct font_info *font_info;
+
              font_idx = load_font_get_repertory (f, face, font_def, fontset);
              ASET (elt, 1, make_number (font_idx));
              if (font_idx < 0)
                /* This means that we couldn't find a font matching
                   FONT_DEF.  */
                continue;
+             font_info = (*get_font_info_func) (f, font_idx);
+             ASET (elt, 3, build_string (font_info->full_name));
            }
 
          slot = Fassq (AREF (elt, 1), FONTSET_REPERTORY (fontset));
-         if (! CONSP (slot))
-           abort ();
+         xassert (CONSP (slot));
          if (NILP (CHAR_TABLE_REF (XCDR (slot), c)))
-           /* This fond can't display C.  */
+           /* This font can't display C.  */
            continue;
        }
 
       /* Now we have decided to use this font spec to display C.  */
-      if (INTEGERP (AREF (elt, 1)))
-       font_idx = XINT (AREF (elt, 1));
-      else
+      if (! INTEGERP (AREF (elt, 1)))
        {
          /* But not yet opened the best matching font.  */
+         struct font_info *font_info;
+
          font_idx = load_font_get_repertory (f, face, font_def, fontset);
          ASET (elt, 1, make_number (font_idx));
          if (font_idx < 0)
+           /* Can't open it.  Try the other one.  */
            continue;
+         font_info = (*get_font_info_func) (f, font_idx);
+         ASET (elt, 3, build_string (font_info->full_name));
        }
 
       /* Now we have the opened font.  */
-      if (NILP (AREF (elt, 0)))
+      return elt;
+    }
+
+ try_fallback:
+  if (! EQ (vec, FONTSET_FALLBACK (fontset)))
+    {
+      vec = FONTSET_FALLBACK (fontset);
+      if (VECTORP (vec))
+       goto retry;
+      if (EQ (vec, Qt))
+       goto try_default;
+      elt = FONTSET_FALLBACK (base_fontset);
+      if (! NILP (elt))
        {
-         /* But not yet made a realized face that uses this font.  */
-         int face_id = lookup_non_ascii_face (f, font_idx, face);
+         vec = Fmake_vector (make_number (ASIZE (elt) + 3), make_number (-1));
+         ASET (vec, 2, Qnil);
+         for (i = 0; i < ASIZE (elt); i++)
+           {
+             Lisp_Object tmp;
 
-         ASET (elt, 0, make_number (face_id));
+             tmp = Fmake_vector (make_number (4), Qnil);
+             ASET (tmp, 2, AREF (elt, i));
+             ASET (vec, 3 + i, tmp);
+           }
+         FONTSET_FALLBACK (fontset) = vec;       
+         goto retry;
        }
-
-      /* Ok, this face can display C.  */
-      return XINT (AREF (elt, 0));
+      /* Record that this fontset has no fallback fonts.  */
+      FONTSET_FALLBACK (fontset) = Qt;
     }
 
+  /* Try the default fontset.  */
  try_default:
   if (! EQ (base_fontset, Vdefault_fontset))
     {
-      if (NILP (FONTSET_FALLBACK (fontset)))
-       FONTSET_FALLBACK (fontset)
+      if (NILP (FONTSET_DEFAULT (fontset)))
+       FONTSET_DEFAULT (fontset)
          = make_fontset (FONTSET_FRAME (fontset), Qnil, Vdefault_fontset);
-      return fontset_face (FONTSET_FALLBACK (fontset), c, face, id);
+      return fontset_font (FONTSET_DEFAULT (fontset), c, face, id);
     }
-
-  /* We have tried all the fonts for C, but none of them can be opened
-     nor can display C.  */
-  if (NILP (FONTSET_NOFONT_FACE (fontset)))
-    {
-      int face_id;
-
-      if (! face)
-       return -1;
-      face_id = lookup_non_ascii_face (f, -1, face);
-      FONTSET_NOFONT_FACE (fontset) = make_number (face_id);
-    }
-  return XINT (FONTSET_NOFONT_FACE (fontset));
+  return Qnil;
 }
 
 
@@ -780,9 +812,9 @@ free_face_fontset (f, face)
   ASET (Vfontset_table, face->fontset, Qnil);
   if (face->fontset < next_fontset_id)
     next_fontset_id = face->fontset;
-  if (! NILP (FONTSET_FALLBACK (fontset)))
+  if (! NILP (FONTSET_DEFAULT (fontset)))
     {
-      int id = FONTSET_ID (FONTSET_FALLBACK (fontset));
+      int id = XINT (FONTSET_ID (FONTSET_DEFAULT (fontset)));
       
       fontset = AREF (Vfontset_table, id);
       xassert (!NILP (fontset) && ! BASE_FONTSET_P (fontset));
@@ -803,10 +835,13 @@ face_suitable_for_char_p (face, c)
      struct face *face;
      int c;
 {
-  Lisp_Object fontset;
+  Lisp_Object fontset, rfont_def;
 
   fontset = FONTSET_FROM_ID (face->fontset);
-  return (face->id == fontset_face (fontset, c, NULL, -1));
+  rfont_def = fontset_font (fontset, c, NULL, -1);
+  return (VECTORP (rfont_def)
+         && INTEGERP (AREF (rfont_def, 0))
+         && face->id == XINT (AREF (rfont_def, 0)));
 }
 
 
@@ -821,7 +856,8 @@ face_for_char (f, face, c, pos, object)
      int c, pos;
      Lisp_Object object;
 {
-  Lisp_Object fontset, charset;
+  Lisp_Object fontset, charset, rfont_def;
+  int face_id;
   int id;
 
   if (ASCII_CHAR_P (c))
@@ -840,7 +876,26 @@ face_for_char (f, face, c, pos, object)
       else if (CHARSETP (charset))
        id = XINT (CHARSET_SYMBOL_ID (charset));
     }
-  return fontset_face (fontset, c, face, id);
+  rfont_def = fontset_font (fontset, c, face, id);
+  if (VECTORP (rfont_def))
+    {
+      if (NILP (AREF (rfont_def, 0)))
+       {
+         /* We have not yet made a realized face that uses this font.  */
+         int font_idx = XINT (AREF (rfont_def, 1));
+
+         face_id = lookup_non_ascii_face (f, font_idx, face);
+         ASET (rfont_def, 0, make_number (face_id));
+       }
+      return XINT (AREF (rfont_def, 0));
+    }
+
+  if (NILP (FONTSET_NOFONT_FACE (fontset)))
+    {
+      face_id = lookup_non_ascii_face (f, -1, face);
+      FONTSET_NOFONT_FACE (fontset) = make_number (face_id);
+    }
+  return XINT (FONTSET_NOFONT_FACE (fontset));
 }
 
 
@@ -872,13 +927,20 @@ make_fontset_for_ascii_face (f, base_fontset_id, face)
 
   fontset = make_fontset (frame, Qnil, base_fontset);
   {
-    Lisp_Object elt;
+    Lisp_Object elt, rfont_def;
 
     elt = FONTSET_REF (base_fontset, 0);
-    elt = Fmake_vector (make_number (4), AREF (elt, 0));
+    xassert (VECTORP (elt) && ASIZE (elt) > 0);
+    rfont_def = Fmake_vector (make_number (4), Qnil);
+    ASET (rfont_def, 0, make_number (face->id));
+    ASET (rfont_def, 1, make_number (face->font_info_id));
+    ASET (rfont_def, 2, AREF (elt, 0));
+    ASET (rfont_def, 3, build_string (face->font_name));
+    elt = Fmake_vector (make_number (4), Qnil);
     ASET (elt, 0, make_number (charset_ordered_list_tick));
-    ASET (elt, 1, make_number (face->id));
-    ASET (elt, 2, make_number (face->font_info_id));
+    ASET (elt, 1, make_number (charset_ascii));
+    ASET (elt, 2, rfont_def);
+    ASET (elt, 3, rfont_def);
     char_table_set_range (fontset, 0, 127, elt);
   }
   return XINT (FONTSET_ID (fontset));
@@ -966,9 +1028,8 @@ find_font_encoding (fontname)
              : CONSP (XCDR (elt)) && CHARSETP (XCAR (XCDR (elt)))))
        return (XCDR (elt));
     }
-  /* We don't know the encoding of this font.  Let's assume Unicode
-     encoding.  */
-  return Qunicode;
+  /* We don't know the encoding of this font.  Let's assume `ascii'.  */
+  return Qascii;
 }
 
 
@@ -1236,34 +1297,66 @@ generate_ascii_font_name (name, ascii_spec)
   return build_font_name_from_vector (vec);
 }
 
+/* Variables referred in set_fontset_font.  They are set before
+   map_charset_chars is called in Fset_fontset_font.  */
+static Lisp_Object font_def_arg, add_arg;
+static int from_arg, to_arg;
+
+/* Callback function for map_charset_chars in Fset_fontset_font.  In
+   FONTSET, set font_def_arg in a fashion specified by add_arg for
+   characters in RANGE while ignoring the range between from_arg and
+   to_arg.  */
+
 static void
-set_fontset_font (arg, range)
-     Lisp_Object arg, range;
+set_fontset_font (fontset, range)
+     Lisp_Object fontset, range;
 {
-  Lisp_Object fontset, font_def, add;
+  if (from_arg < to_arg)
+    {
+      int from = XINT (XCAR (range)), to = XINT (XCDR (range));
 
-  fontset = XCAR (arg);
-  font_def = XCAR (XCDR (arg));
-  add = XCAR (XCDR (XCDR (arg)));
-  FONTSET_ADD (fontset, range, font_def, add);
-  free_realized_fontsets (fontset);
+      if (from < from_arg)
+       {
+         if (to > to_arg)
+           {
+             Lisp_Object range2;
+
+             range2 = Fcons (make_number (to_arg), XCDR (range));
+             FONTSET_ADD (fontset, range, font_def_arg, add_arg);
+             to = to_arg;
+           }
+         if (to > from_arg)
+           range = Fcons (XCAR (range), make_number (from_arg));
+       }
+      else if (to <= to_arg)
+       return;
+      else
+       {
+         if (from < to_arg)
+           range = Fcons (make_number (to_arg), XCDR (range));
+       }
+    }
+  FONTSET_ADD (fontset, range, font_def_arg, add_arg);
 }
 
 
 DEFUN ("set-fontset-font", Fset_fontset_font, Sset_fontset_font, 3, 5, 0,
        doc: /*
-Modify fontset NAME to use FONT-SPEC for CHARACTER.
+Modify fontset NAME to use FONT-SPEC for TARGET characters.
 
-CHARACTER may be a cons; (FROM . TO), where FROM and TO are
-characters.  In that case, use FONT-SPEC for all characters in the
-range FROM and TO (inclusive).
+TARGET may be a cons; (FROM . TO), where FROM and TO are characters.
+In that case, use FONT-SPEC for all characters in the range FROM and
+TO (inclusive).
 
-CHARACTER may be a script name symbol.  In that case, use FONT-SPEC
-for all characters that belong to the script.
+TARGET may be a script name symbol.  In that case, use FONT-SPEC for
+all characters that belong to the script.
 
-CHARACTER may be a charset.  In that case, use FONT-SPEC for all
+TARGET may be a charset.  In that case, use FONT-SPEC for all
 characters in the charset.
 
+TARGET may be nil.  In that case, use FONT-SPEC for any characters for
+that no FONT-SPEC is specified.
+
 FONT-SPEC may be:
  * A vector [ FAMILY WEIGHT SLANT WIDTH ADSTYLE REGISTRY ].
    See the documentation of `set-face-attribute' for the detail of
@@ -1276,16 +1369,17 @@ Optional 4th argument FRAME, if non-nil, is a frame.  This argument is
 kept for backward compatibility and has no meaning.
 
 Optional 5th argument ADD, if non-nil, specifies how to add FONT-SPEC
-to the font specifications for RANGE previously set.  If it is
+to the font specifications for TARGET previously set.  If it is
 `prepend', FONT-SPEC is prepended.  If it is `append', FONT-SPEC is
 appended.  By default, FONT-SPEC overrides the previous settings.  */)
-     (name, character, font_spec, frame, add)
-     Lisp_Object name, character, font_spec, frame, add;
+     (name, target, font_spec, frame, add)
+     Lisp_Object name, target, font_spec, frame, add;
 {
   Lisp_Object fontset;
   Lisp_Object font_def, registry;
   Lisp_Object encoding, repertory;
   Lisp_Object range_list;
+  struct charset *charset = NULL;
 
   fontset = check_fontset_name (name);
 
@@ -1344,49 +1438,55 @@ appended.  By default, FONT-SPEC overrides the previous settings.  */)
   else
     encoding = find_font_encoding ((char *) SDATA (registry));
   if (SYMBOLP (encoding))
-    encoding = repertory = CHARSET_SYMBOL_ID (encoding);
+    {
+      CHECK_CHARSET (encoding);
+      encoding = repertory = CHARSET_SYMBOL_ID (encoding);
+    }
   else
     {
       repertory = XCDR (encoding);
-      encoding = CHARSET_SYMBOL_ID (XCAR (encoding));
+      encoding = XCAR (encoding);
+      CHECK_CHARSET (encoding);
+      encoding = CHARSET_SYMBOL_ID (encoding);
+      if (! NILP (repertory) && SYMBOLP (repertory))
+       {
+         CHECK_CHARSET (repertory);
+         repertory = CHARSET_SYMBOL_ID (repertory);
+       }
     }
   font_def = Fmake_vector (make_number (3), font_spec);
   ASET (font_def, 1, encoding);
   ASET (font_def, 2, repertory);
 
-  if (CHARACTERP (character))
-    range_list = Fcons (Fcons (character, character), Qnil);
-  else if (CONSP (character))
+  if (CHARACTERP (target))
+    range_list = Fcons (Fcons (target, target), Qnil);
+  else if (CONSP (target))
     {
       Lisp_Object from, to;
 
-      from = Fcar (character);
-      to = Fcdr (character);
+      from = Fcar (target);
+      to = Fcdr (target);
       CHECK_CHARACTER (from);
       CHECK_CHARACTER (to);
-      range_list = Fcons (character, Qnil);
+      range_list = Fcons (target, Qnil);
     }
-  else
+  else if (SYMBOLP (target) && !NILP (target))
     {
       Lisp_Object script_list;
       Lisp_Object val;
 
-      CHECK_SYMBOL (character);
       range_list = Qnil;
       script_list = XCHAR_TABLE (Vchar_script_table)->extras[0];
-      if (! NILP (Fmemq (character, script_list)))
+      if (! NILP (Fmemq (target, script_list)))
        {
-         val = Fcons (character, Qnil);
+         val = Fcons (target, Qnil);
          map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
                          val);
          range_list = XCDR (val);
        }
-      else if (CHARSETP (character))
+      if (CHARSETP (target))
        {
-         struct charset *charset;
-
-         CHECK_CHARSET_GET_CHARSET (character, charset);
-         if (EQ (character, Qascii))
+         if (EQ (target, Qascii))
            {
              if (VECTORP (font_spec))
                font_spec = generate_ascii_font_name (FONTSET_NAME (fontset),
@@ -1397,19 +1497,33 @@ appended.  By default, FONT-SPEC overrides the previous settings.  */)
            }
          else
            {
-             map_charset_chars (set_fontset_font, Qnil,
-                                list3 (fontset, font_def, add), charset,
-                                CHARSET_MIN_CODE (charset),
-                                CHARSET_MAX_CODE (charset));
-             return Qnil;
+             CHECK_CHARSET_GET_CHARSET (target, charset);
            }
        }
-
-      if (NILP (range_list))
+      else if (NILP (range_list))
        error ("Invalid script or charset name: %s",
-              SDATA (SYMBOL_NAME (character)));
+              SDATA (SYMBOL_NAME (target)));
     }
+  else if (NILP (target))
+    range_list = Fcons (Qnil, Qnil);
+  else
+    error ("Invalid target for setting a font");
+
 
+  if (charset)
+    {
+      font_def_arg = font_def;
+      add_arg = add;
+      if (NILP (range_list))
+       from_arg = to_arg = 0;
+      else
+       from_arg = XINT (XCAR (XCAR (range_list))),
+         to_arg = XINT (XCDR (XCAR (range_list)));
+
+      map_charset_chars (set_fontset_font, Qnil, fontset, charset,
+                        CHARSET_MIN_CODE (charset),
+                        CHARSET_MAX_CODE (charset));
+    }
   for (; CONSP (range_list); range_list = XCDR (range_list))
     FONTSET_ADD (fontset, XCAR (range_list), font_def, add);
 
@@ -1516,16 +1630,16 @@ new_fontset_from_font_name (Lisp_Object fontname)
   else
     {
       char temp[20];
-      int len = Flength (auto_fontset_alist);
+      int len = XINT (Flength (auto_fontset_alist));
 
       sprintf (temp, "auto%d", len);
       ASET (vec, 13, build_string (temp));
       name = build_font_name_from_vector (vec);
     }
-  name = Fnew_fontset (name, Fcons (Fcons (Fcons (make_number (0),
+  name = Fnew_fontset (name, list2 (list2 (Qascii, fontname),
+                                   list2 (Fcons (make_number (0),
                                                  make_number (MAX_CHAR)),
-                                          Fcons (fontname, Qnil)),
-                                   Qnil));
+                                          fontname)));
   id = fs_query_fontset (name, 0);
   auto_fontset_alist
     = Fcons (Fcons (fontname, make_number (id)), auto_fontset_alist);
@@ -1612,6 +1726,8 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 1, 0,
   struct window *w;
   struct frame *f;
   struct face *face;
+  Lisp_Object charset, rfont_def;
+  int charset_id;
 
   CHECK_NUMBER_COERCE_MARKER (position);
   pos = XINT (position);
@@ -1625,10 +1741,16 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 1, 0,
   w = XWINDOW (window);
   f = XFRAME (w->frame);
   face_id = face_at_buffer_position (w, pos, -1, -1, &dummy, pos + 100, 0);
-  face_id = FACE_FOR_CHAR (f, FACE_FROM_ID (f, face_id), c, pos, Qnil);
   face = FACE_FROM_ID (f, face_id);
-  return (face->font && face->font_name
-         ? build_string (face->font_name)
+  charset = Fget_char_property (position, Qcharset, Qnil);
+  if (CHARSETP (charset))
+    charset_id = XINT (CHARSET_SYMBOL_ID (charset));
+  else
+    charset_id = -1;
+  rfont_def = fontset_font (FONTSET_FROM_ID (face->fontset),
+                           c, face, charset_id);
+  return (VECTORP (rfont_def) && STRINGP (AREF (rfont_def, 3))
+         ? AREF (rfont_def, 3)
          : Qnil);
 }
 
@@ -1654,11 +1776,9 @@ fontset.  The format is the same as abobe.  */)
      Lisp_Object fontset, frame;
 {
   FRAME_PTR f;
-  Lisp_Object table, val, elt;
-  Lisp_Object *realized;
-  int n_realized = 0;
-  int fallback;
-  int c, i, j;
+  Lisp_Object *realized[2], fontsets[2], tables[2];
+  Lisp_Object val, elt;
+  int c, i, j, k;
 
   (*check_window_system_func) ();
 
@@ -1671,45 +1791,53 @@ fontset.  The format is the same as abobe.  */)
 
   /* Recode fontsets realized on FRAME from the base fontset FONTSET
      in the table `realized'.  */
-  realized = (Lisp_Object *) alloca (sizeof (Lisp_Object)
-                                    * ASIZE (Vfontset_table));
-  for (i = 0; i < ASIZE (Vfontset_table); i++)
+  realized[0] = (Lisp_Object *) alloca (sizeof (Lisp_Object)
+                                       * ASIZE (Vfontset_table));
+  for (i = j = 0; i < ASIZE (Vfontset_table); i++)
     {
       elt = FONTSET_FROM_ID (i);
       if (!NILP (elt)
          && EQ (FONTSET_BASE (elt), fontset)
          && EQ (FONTSET_FRAME (elt), frame))
-       realized[n_realized++] = elt;
+       realized[0][j++] = elt;
+    }
+  realized[0][j] = Qnil;
+
+  realized[1] = (Lisp_Object *) alloca (sizeof (Lisp_Object)
+                                       * ASIZE (Vfontset_table));
+  for (i = j = 0; ! NILP (realized[0][i]); i++)
+    {
+      elt = FONTSET_DEFAULT (realized[0][i]);
+      if (! NILP (elt))
+       realized[1][j++] = elt;
     }
+  realized[1][j] = Qnil;
 
+  tables[0] = Fmake_char_table (Qfontset_info, Qnil);
+  tables[1] = Fmake_char_table (Qnil, Qnil);
+  XCHAR_TABLE (tables[0])->extras[0] = tables[1];
+  fontsets[0] = fontset;
+  fontsets[1] = Vdefault_fontset;
 
-  table = Fmake_char_table (Qfontset_info, Qnil);
-  XCHAR_TABLE (table)->extras[0] = Fmake_char_table (Qnil, Qnil);
   /* Accumulate information of the fontset in TABLE.  The format of
      each element is ((FONT-SPEC OPENED-FONT ...) ...).  */
-  for (fallback = 0; fallback <= 1; fallback++)
+  for (k = 0; k <= 1; k++)
     {
-      Lisp_Object this_fontset, this_table;
-
-      if (! fallback)
-       {
-         this_fontset = fontset;
-         this_table = table;
-       }
-      else
-       {
-         this_fontset = Vdefault_fontset;
-         this_table = XCHAR_TABLE (table)->extras[0];
-#if 0
-         for (i = 0; i < n_realized; i++)
-           realized[i] = FONTSET_FALLBACK (realized[i]);
-#endif
-       }
-      for (c = 0; c <= MAX_5_BYTE_CHAR; )
+      for (c = 0; c <= MAX_CHAR; )
        {
          int from, to;
 
-         val = char_table_ref_and_range (this_fontset, c, &from, &to);
+         if (c <= MAX_5_BYTE_CHAR)
+           {
+             val = char_table_ref_and_range (fontsets[k], c, &from, &to);
+             if (to > MAX_5_BYTE_CHAR)
+               to = MAX_5_BYTE_CHAR;
+           }
+         else
+           {
+             val = FONTSET_FALLBACK (fontsets[k]);
+             to = MAX_CHAR;
+           }
          if (VECTORP (val))
            {
              Lisp_Object alist;
@@ -1720,18 +1848,20 @@ fontset.  The format is the same as abobe.  */)
              alist = Fnreverse (alist);
 
              /* Then store opend font names to cdr of each elements.  */
-             for (i = 0; i < n_realized; i++)
+             for (i = 0; ! NILP (realized[k][i]); i++)
                {
-                 if (NILP (realized[i]))
-                   continue;
-                 val = FONTSET_REF (realized[i], c);
-                 if (NILP (val))
+                 if (c <= MAX_5_BYTE_CHAR)
+                   val = FONTSET_REF (realized[k][i], c);
+                 else
+                   val = FONTSET_FALLBACK (realized[k][i]);
+                 if (! VECTORP (val))
                    continue;
-                 /* VAL is [int int int [FACE-ID FONT-INDEX FONT-DEF] ...].
+                 /* VAL is [int int ?
+                            [FACE-ID FONT-INDEX FONT-DEF FONT-NAME] ...].
                     If a font of an element is already opened,
-                    FONT-INDEX of the element is integer.  */
+                    FONT-NAME is the name of a opened font.  */
                  for (j = 3; j < ASIZE (val); j++)
-                   if (INTEGERP (AREF (AREF (val, j), 0)))
+                   if (STRINGP (AREF (AREF (val, j), 3)))
                      {
                        Lisp_Object font_idx;
 
@@ -1751,13 +1881,16 @@ fontset.  The format is the same as abobe.  */)
                  }
 
              /* Store ALIST in TBL for characters C..TO.  */
-             char_table_set_range (this_table, c, to, alist);
+             if (c <= MAX_5_BYTE_CHAR)
+               char_table_set_range (tables[k], c, to, alist);
+             else
+               XCHAR_TABLE (tables[k])->defalt = alist;
            }
          c = to + 1;
        }
     }
 
-  return table;
+  return tables[0];
 }
 
 
@@ -1827,8 +1960,8 @@ dump_fontset (fontset)
          else
            ASET (vec, 1, Qt);
        }
-      if (!NILP (FONTSET_FALLBACK (fontset)))
-       ASET (vec, 2, FONTSET_ID (FONTSET_FALLBACK (fontset)));
+      if (!NILP (FONTSET_DEFAULT (fontset)))
+       ASET (vec, 2, FONTSET_ID (FONTSET_DEFAULT (fontset)));
     }
   return vec;
 }
@@ -1855,7 +1988,7 @@ syms_of_fontset ()
     abort ();
 
   DEFSYM (Qfontset, "fontset");
-  Fput (Qfontset, Qchar_table_extra_slots, make_number (8));
+  Fput (Qfontset, Qchar_table_extra_slots, make_number (9));
   DEFSYM (Qfontset_info, "fontset-info");
   Fput (Qfontset_info, Qchar_table_extra_slots, make_number (1));