(Qfont_spec, Qfont_entity, Qfont_object): Extern them.
[bpt/emacs.git] / src / fontset.c
index 045e632..48a32ea 100644 (file)
@@ -1,8 +1,8 @@
 /* Fontset handler.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
      Free Software Foundation, Inc.
    Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-     2005, 2006, 2007
+     2005, 2006, 2007, 2008
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H14PRO021
    Copyright (C) 2003, 2006
@@ -57,9 +57,7 @@ Boston, MA 02110-1301, USA.  */
 #endif
 #include "termhooks.h"
 
-#ifdef USE_FONT_BACKEND
 #include "font.h"
-#endif /* USE_FONT_BACKEND */
 
 #undef xassert
 #ifdef FONTSET_DEBUG
@@ -96,14 +94,11 @@ EXFUN (Fclear_face_cache, 1);
    An element of a base fontset is a vector of FONT-DEFs which itself
    is a vector [ FONT-SPEC ENCODING REPERTORY ].
 
-   FONT-SPEC is:
-       [ FAMILY WEIGHT SLANT SWIDTH ADSTYLE REGISTRY ]
+   FONT-SPEC is a font-spec created by `font-spec' or
+       ( FAMILY . REGISTRY )
    or
        FONT-NAME
-   where FAMILY, WEIGHT, SLANT, SWIDTH, ADSTYLE, REGISTRY, and
-   FONT-NAME are strings.
-
-   Note: Currently WEIGHT through ADSTYLE are ignored.
+   where FAMILY, REGISTRY, and FONT-NAME are strings.
 
    ENCODING is a charset ID that can convert characters to glyph codes
    of the corresponding font.
@@ -121,8 +116,8 @@ EXFUN (Fclear_face_cache, 1);
 
    An element of a realized fontset is nil or t, or has this form:
 
-       [CHARSET-ORDERED-LIST-TICK PREFERRED-CHARSET-ID
-        PREFERRED-RFONT-DEF RFONT-DEF0 RFONT-DEF1 ...].
+       [CHARSET-ORDERED-LIST-TICK PREFERRED-CHARSET-ID PREFERRED-FAMILY
+        RFONT-DEF0 RFONT-DEF1 ...].
 
    RFONT-DEFn (i.e. Realized FONT-DEF) has this form:
 
@@ -219,6 +214,7 @@ static int next_fontset_id;
 static Lisp_Object Vdefault_fontset;
 
 Lisp_Object Vfont_encoding_alist;
+Lisp_Object Vfont_encoding_charset_alist;
 Lisp_Object Vuse_default_ascent;
 Lisp_Object Vignore_relative_composition;
 Lisp_Object Valternate_fontname_alist;
@@ -267,6 +263,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 void reorder_font_vector P_ ((Lisp_Object, int, 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));
@@ -306,6 +303,7 @@ fontset_id_valid_p (id)
 /* Macros to access special values of (realized) FONTSET.  */
 #define FONTSET_BASE(fontset)          XCHAR_TABLE (fontset)->extras[2]
 #define FONTSET_FRAME(fontset)         XCHAR_TABLE (fontset)->extras[3]
+#define FONTSET_OBJLIST(fontset)       XCHAR_TABLE (fontset)->extras[4]
 #define FONTSET_NOFONT_FACE(fontset)   XCHAR_TABLE (fontset)->extras[5]
 #define FONTSET_REPERTORY(fontset)     XCHAR_TABLE (fontset)->extras[6]
 #define FONTSET_DEFAULT(fontset)       XCHAR_TABLE (fontset)->extras[7]
@@ -341,43 +339,6 @@ fontset_ref (fontset, c)
   return elt;
 }
 
-
-/* Return the element of FONTSET for the character C, set FROM and TO
-   to the range of characters around C that have the same value as C.
-   If FONTSET is a base fontset other then the default fontset and
-   FONTSET doesn't contain information for C, return the information
-   in the default fontset.  */
-
-#define FONTSET_REF_AND_RANGE(fontset, c, form, to)    \
-  (EQ (fontset, Vdefault_fontset)                      \
-   ? char_table_ref_and_range (fontset, c, &from, &to) \
-   : fontset_ref_and_range (fontset, c, &from, &to))
-
-static Lisp_Object
-fontset_ref_and_range (fontset, c, from, to)
-     Lisp_Object fontset;
-     int c;
-     int *from, *to;
-{
-  Lisp_Object elt;
-
-  elt = char_table_ref_and_range (fontset, c, from, to);
-  if (NILP (elt) && ! EQ (fontset, Vdefault_fontset)
-      /* Don't check Vdefault_fontset for a realized fontset.  */
-      && NILP (FONTSET_BASE (fontset)))
-    {
-      int from1, to1;
-
-      elt = char_table_ref_and_range (Vdefault_fontset, c, &from1, &to1);
-      if (*from < from1)
-       *from = from1;
-      if (*to > to1)
-       *to = to1;
-    }
-  return elt;
-}
-
-
 /* Set elements of FONTSET for characters in RANGE to the value ELT.
    RANGE is a cons (FROM . TO), where FROM and TO are character codes
    specifying a range.  */
@@ -435,59 +396,97 @@ fontset_add (fontset, range, elt, add)
 }
 
 
-/* Update FONTSET_ELEMENT which has this form:
-       [CHARSET-ORDERED-LIST-TICK PREFERRED-CHARSET-ID PREFERRED-RFONT-DEF
+/* Update FONT-GROUP which has this form:
+       [CHARSET-ORDERED-LIST-TICK PREFERRED-CHARSET-ID PREFERRED-FAMILY
         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
-reorder_font_vector (fontset_element)
-     Lisp_Object fontset_element;
+reorder_font_vector (font_group, charset_id, family)
+     Lisp_Object font_group;
+     int charset_id;
+     Lisp_Object family;
 {
   Lisp_Object list, *new_vec;
-  Lisp_Object font_def;
   int size;
   int *charset_id_table;
   int i, idx;
+  Lisp_Object preferred_by_charset, preferred_by_family;
 
-  ASET (fontset_element, 0, make_number (charset_ordered_list_tick));
-  size = ASIZE (fontset_element) - 3;
-  if (size <= 1)
-    /* No need to reorder VEC.  */
-    return;
+  size = ASIZE (font_group) - 3;
+  /* Exclude the tailing nil elements from the reordering.  */
+  while (NILP (AREF (font_group, size - 1))) size--;
   charset_id_table = (int *) alloca (sizeof (int) * size);
   new_vec = (Lisp_Object *) alloca (sizeof (Lisp_Object) * size);
 
-  /* At first, extract ENCODING (a chaset ID) from each FONT-DEF.
-     FONT-DEF has this form:
-       [FACE-ID FONT-INDEX [ FONT-SPEC ENCODING REPERTORY ]] */
-  for (i = 0; i < size; i++)
+  /* At first, extract ENCODING (a chaset ID) from RFONT_DEF which
+     has this form:
+       [FACE-ID FONT-INDEX [ FONT-SPEC ENCODING REPERTORY ]]
+     In addtion, if RFONT_DEF is preferred by family or charset, store
+     it from the start of new_vec.  */
+  for (i = 0, idx = 0; i < size; i++)
     {
-      font_def = AREF (fontset_element, i + 3);
-      if (VECTORP (AREF (font_def, 2))
-         && INTEGERP (AREF (AREF (font_def, 2), 1)))
-       charset_id_table[i] = XINT (AREF (AREF (font_def, 2), 1));
-      else
-       charset_id_table[i] = -1;
+      Lisp_Object rfont_def = AREF (font_group, i + 3);
+      Lisp_Object font_spec = AREF (AREF (rfont_def, 2), 0);
+      Lisp_Object this_family = AREF (font_spec, FONT_FAMILY_INDEX);
+      int id = XINT (AREF (AREF (rfont_def, 2), 1));
+      struct charset *charset = CHARSET_FROM_ID (id);
+
+      charset_id_table[i] = -1;
+      if (! NILP (this_family)
+         && (fast_string_match_ignore_case (family, SYMBOL_NAME (this_family))
+             >= 0))
+       {
+         if (idx > 0)
+           memmove (new_vec + 1, new_vec, sizeof (Lisp_Object) * idx);
+         new_vec[0] = rfont_def;
+         idx++;
+         ASET (font_group, i + 3, Qnil);
+       }
+      else if (id == charset_id)
+       {
+         new_vec[idx++] = rfont_def;
+         ASET (font_group, i + 3, Qnil);
+       }
+      else if (! charset->supplementary_p)
+       charset_id_table[i] = id;
     }
 
-  /* Then, store FONT-DEFs in NEW_VEC in the correct order.  */
-  for (idx = 0, list = Vcharset_ordered_list;
-       idx < size && CONSP (list); list = XCDR (list))
+  if (idx == 0
+      && (XINT (AREF (font_group, 0)) == charset_ordered_list_tick))
+    /* No need of reordering.  */
+    return;
+
+  ASET (font_group, 0, make_number (charset_ordered_list_tick));
+  ASET (font_group, 1, make_number (charset_id));
+  ASET (font_group, 2, family);
+
+  /* Then, store the remaining RFONT-DEFs in NEW_VEC in the correct
+     order.  */
+  for (list = Vcharset_ordered_list; idx < size; list = XCDR (list))
     {
+      int id = XINT (XCAR (list));
+      struct charset *charset = CHARSET_FROM_ID (id);
+
+      if (charset->supplementary_p)
+       break;
       for (i = 0; i < size; i++)
-       if (charset_id_table[i] == XINT (XCAR (list)))
-         new_vec[idx++] = AREF (fontset_element, i + 3);
+       if (charset_id_table[i] == XINT (XCAR (list))
+           && ! NILP (AREF (font_group, i + 3)))
+         {
+           new_vec[idx++] = AREF (font_group, i + 3);
+           ASET (font_group, i + 3, Qnil);
+         }
     }
   for (i = 0; i < size; i++)
-    if (charset_id_table[i] < 0)
-      new_vec[idx++] = AREF (fontset_element, i + 3);
+    if (! NILP (AREF (font_group, i + 3)))
+      new_vec[idx++] = AREF (font_group, i + 3);
 
-  /* At last, update FONT-DEFs.  */
+  /* At last, update elements of FONT-GROUP.  */
   for (i = 0; i < size; i++)
-    ASET (fontset_element, i + 3, new_vec[i]);
+    ASET (font_group, i + 3, new_vec[i]);
 }
 
 
@@ -498,6 +497,8 @@ reorder_font_vector (fontset_element)
    If REPERTORY is nil, generate a char-table representing the font
    repertory by looking into the font itself.  */
 
+extern Lisp_Object QCname;
+
 static int
 load_font_get_repertory (f, face, font_def, fontset)
      FRAME_PTR f;
@@ -508,8 +509,14 @@ load_font_get_repertory (f, face, font_def, fontset)
   char *font_name;
   struct font_info *font_info;
   int charset;
+  Lisp_Object font_spec, name;
 
-  font_name = choose_face_font (f, face->lface, AREF (font_def, 0), NULL);
+  font_spec = AREF (font_def, 0);
+  name = Ffont_get (font_spec, QCname);
+  if (! NILP (name))
+    font_name = choose_face_font (f, face->lface, name, NULL);
+  else
+    font_name = choose_face_font (f, face->lface, font_spec, NULL);
   charset = XINT (AREF (font_def, 1));
   if (! (font_info = fs_load_font (f, font_name, charset)))
     return -1;
@@ -535,12 +542,17 @@ static Lisp_Object fontset_find_font P_ ((Lisp_Object, int, struct face *,
                                          int, int));
 
 /* 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.
+   character C.  If no font is found, return Qnil if there's a
+   possibility that the default fontset or the fallback font groups
+   have a proper font, and return Qt if not.
+
+   If a font is found but is not yet opened, open it (if FACE is not
+   NULL) or return Qnil (if FACE is NULL).
+
    ID is a charset-id that must be preferred, or -1 meaning no
    preference.
-   If FALLBACK if nonzero, search only fallback fonts.  */
+
+   If FALLBACK is nonzero, search only fallback fonts.  */
 
 static Lisp_Object
 fontset_find_font (fontset, c, face, id, fallback)
@@ -559,21 +571,31 @@ fontset_find_font (fontset, c, face, id, fallback)
     vec = CHAR_TABLE_REF (fontset, c);
   else
     vec = FONTSET_FALLBACK (fontset);
+
   if (NILP (vec))
     {
-      /* We have not yet decided a font for C.  */
       Lisp_Object range;
 
+      /* We have not yet decided a font for C.  */
       if (! face)
        return Qnil;
       if (! fallback)
-       elt = FONTSET_REF_AND_RANGE (base_fontset, c, from, to);
+       {
+         elt = char_table_ref_and_range (base_fontset, c, &from, &to);
+         range = Fcons (make_number (from), make_number (to));
+       }
       else
-       elt = FONTSET_FALLBACK (base_fontset);
-      range = Fcons (make_number (from), make_number (to));
+       {
+         elt = FONTSET_FALLBACK (base_fontset);
+       }
       if (NILP (elt))
        {
-         /* Qt means we have no font for characters of this range.  */
+         /* This fontset doesn't specify any font for C. */
+         vec = make_number (0);
+       }
+      else if (ASIZE (elt) == 1 && NILP (AREF (elt, 0)))
+       {
+         /* Explicitly specified no font.  */
          vec = Qt;
        }
       else
@@ -581,92 +603,50 @@ fontset_find_font (fontset, c, face, id, 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-ELTn is [nil nil AREF (elt, n) nil].  */
-#ifdef USE_FONT_BACKEND
-         if (! fallback
-             && enable_font_backend
-             && EQ (base_fontset, Vdefault_fontset))
-           /* Extra one element is for an automatically added
-              font-def specifying only a script.  */
-           vec = Fmake_vector (make_number (ASIZE (elt) + 4), Qnil);
-         else
-#endif /* not USE_FONT_BACKEND */
-           vec = Fmake_vector (make_number (ASIZE (elt) + 3), Qnil);
+         int size = ASIZE (elt);
+         int j;
+
+         vec = Fmake_vector (make_number (size + 3), Qnil);
          ASET (vec, 0, make_number (-1));
          ASET (vec, 1, make_number (-1));
-         for (i = 0; i < ASIZE (elt); i++)
-           {
-             Lisp_Object tmp;
-
-             tmp = Fmake_vector (make_number (5), Qnil);
-             ASET (tmp, 2, AREF (elt, i));
-             ASET (vec, 3 + i, tmp);
-           }
-#ifdef USE_FONT_BACKEND
-         if (! fallback
-             && enable_font_backend
-             && EQ (base_fontset, Vdefault_fontset))
-           {
-             Lisp_Object script, font_spec;
-
-             script = CHAR_TABLE_REF (Vchar_script_table, c);
-             if (NILP (script))
-               script = intern ("latin");
-             font_spec = Ffont_spec (0, NULL);
-             ASET (font_spec, FONT_REGISTRY_INDEX, Qiso10646_1);
-             ASET (font_spec, FONT_EXTRA_INDEX,
-                   Fcons (Fcons (QCscript, script), Qnil));
-             font_def = Fmake_vector (make_number (3), Qnil);
-             ASET (font_def, 0, font_spec);
-             elt = Fmake_vector (make_number (5), Qnil);
-             ASET (elt, 2, font_def);
-             ASET (vec, 3 + i, elt);
-           }
-#endif /* USE_FONT_BACKEND */
-
-         /* Then store it in the fontset.  */
-         if (! fallback)
-           FONTSET_SET (fontset, range, vec);
-         else
-           FONTSET_FALLBACK (fontset) = vec;
-       }
-    }
-  if (EQ (vec, Qt))
-    return Qnil;
-
-  if (XINT (AREF (vec, 0)) != charset_ordered_list_tick)
-    /* The priority of charsets is changed after we selected a face
-       for C last time.  */
-    reorder_font_vector (vec);
-
-  if (id < 0)
-    i = 3;
-  else if (id == XFASTINT (AREF (vec, 1)))
-    i = 2;
-  else
-    {
-      ASET (vec, 1, make_number (id));
-      for (i = 3; i < ASIZE (vec); i++)
-       if (id == XFASTINT (AREF (AREF (AREF (vec, i), 2), 1)))
-         break;
-      if (i < ASIZE (vec))
-       {
-         ASET (vec, 2, AREF (vec, i));
-         i = 2;
+         for (i = j = 0; i < size; i++)
+           if (! NILP (AREF (elt, i)))
+             {
+               Lisp_Object tmp;
+               tmp = Fmake_vector (make_number (5), Qnil);
+               ASET (tmp, 2, AREF (elt, i));
+               ASET (vec, j + 3, tmp);
+               j++;
+             }
        }
+      /* Then store it in the fontset.  */
+      if (! fallback)
+       FONTSET_SET (fontset, range, vec);
       else
-       {
-         ASET (vec, 2, Qnil);
-         i = 3;
-       }
+       FONTSET_FALLBACK (fontset) = vec;
+
     }
+  if (! VECTORP (vec))
+    return (EQ (vec, Qt) ? Qt : Qnil);
+
+  if (ASIZE (vec) > 4
+      && (XINT (AREF (vec, 0)) != charset_ordered_list_tick
+         || (id >= 0 && XINT (AREF (vec, 1)) != id)
+         || NILP (Fequal (AREF (vec, 2), face->lface[LFACE_FAMILY_INDEX]))))
+    /* We have just created VEC,
+       or the charset priorities were changed,
+       or the preferred charset was changed,
+       or the preferred family was changed.  */
+    reorder_font_vector (vec, id, face->lface[LFACE_FAMILY_INDEX]);
 
   /* Find the first available font in the vector of RFONT-DEF.  */
-  for (; i < ASIZE (vec); i++)
+  for (i = 3; i < ASIZE (vec); i++)
     {
       elt = AREF (vec, i);
       if (NILP (elt))
-       continue;
-      /* ELT == [ FACE-ID FONT-INDEX FONT-DEF OPENED-FONT-NAME ] */
+       /* This is the sign of not to try fallback fonts.  */
+       return Qt;
+      /* ELT == [ FACE-ID FONT-INDEX FONT-DEF ... ] */
       if (INTEGERP (AREF (elt, 1)) && XINT (AREF (elt, 1)) < 0)
        /* We couldn't open this font last time.  */
        continue;
@@ -681,58 +661,52 @@ fontset_find_font (fontset, c, face, id, fallback)
 #ifdef USE_FONT_BACKEND
       if (enable_font_backend)
        {
-         /* ELT == [ FACE-ID FONT-INDEX FONT-DEF FONT-ENTITY FONT-OBJECT ] */
+         /* ELT == [ FACE-ID FONT-INDEX FONT-DEF FONT-ENTITY ]
+            where FONT-ENTITY turns to a font-object once opened.  */
          Lisp_Object font_entity = AREF (elt, 3);
-         Lisp_Object font_object = AREF (elt, 4);
-         Lisp_Object font_spec = AREF (font_def, 0);
-         int has_char;
+         int has_char = 0;
 
          if (NILP (font_entity))
            {
-             if (! FONT_SPEC_P (font_spec))
-               {
-                 /* FONT_SPEC is FONT-NAME or (FAMILY . REGISTRY).  */
-                 font_spec = Ffont_spec (0, NULL);
-                 if (STRINGP (AREF (font_def, 0)))
-                   font_merge_old_spec (AREF (font_def, 0), Qnil, Qnil,
-                                        font_spec);
-                 else
-                   {
-                     Lisp_Object family = AREF (AREF (font_def, 0), 0);
-                     Lisp_Object registry = AREF (AREF (font_def, 0), 5);;
-
-                     font_merge_old_spec (Qnil, family, registry, font_spec);
-                   }
-                 ASET (font_def, 0, font_spec);
-               }
-             font_entity = font_find_for_lface (f, face->lface, font_spec);
-             ASET (elt, 3, font_entity);
+             font_entity = font_find_for_lface (f, face->lface,
+                                                AREF (font_def, 0), -1);
              if (NILP (font_entity))
                {
                  ASET (elt, 1, make_number (-1));
                  continue;
                }
-             font_object = Qnil;
+             ASET (elt, 3, font_entity);
+           }
+         else if (FONT_ENTITY_P (font_entity))
+           {
+             if (FONT_ENTITY_NOT_LOADABLE (font_entity))
+               continue;
            }
          has_char = font_has_char (f, font_entity, c);
-         if (has_char == 0)
+         if (! has_char)
            continue;
-         if (NILP (font_object))
+         if (! FONT_OBJECT_P (font_entity))
            {
-             font_object = font_open_for_lface (f, font_entity,
-                                                face->lface, font_spec);
-             ASET (elt, 4, font_object);
+             Lisp_Object font_object
+               = font_open_for_lface (f, font_entity, face->lface, Qnil);
+
              if (NILP (font_object))
                {
-                 ASET (elt, 1, make_number (-1));
+                 FONT_ENTITY_SET_NOT_LOADABLE (font_entity);
                  continue;
                }
+             FONTSET_OBJLIST (fontset)
+               = Fcons (font_object, FONTSET_OBJLIST (fontset));
+             ASET (elt, 3, font_object);
+             if (has_char < 0)
+               {
+                 has_char = font_has_char (f, font_object, c);
+                 if (! has_char)
+                   continue;
+               }
            }
+         /* Decide to use this font.  */
          ASET (elt, 1, make_number (0));
-         ASET (elt, 4, font_object);
-         if (has_char < 0
-             && font_encode_char (font_object, c) == FONT_INVALID_CODE)
-           continue;
        }
       else
 #endif /* USE_FONT_BACKEND */
@@ -796,10 +770,9 @@ fontset_find_font (fontset, c, face, id, fallback)
          font_info = (*get_font_info_func) (f, font_idx);
          ASET (elt, 3, build_string (font_info->full_name));
        }
-
-      /* Now we have the opened font.  */
       return elt;
     }
+
   return Qnil;
 }
 
@@ -816,8 +789,10 @@ fontset_font (fontset, c, face, id)
 
   /* Try a font-group for C. */
   rfont_def = fontset_find_font (fontset, c, face, id, 0);
-  if (! NILP (rfont_def))
+  if (VECTORP (rfont_def))
     return rfont_def;
+  if (EQ (rfont_def, Qt))
+    return Qnil;
   base_fontset = FONTSET_BASE (fontset);
   /* Try a font-group for C of the default fontset. */
   if (! EQ (base_fontset, Vdefault_fontset))
@@ -826,16 +801,24 @@ fontset_font (fontset, c, face, id)
        FONTSET_DEFAULT (fontset)
          = make_fontset (FONTSET_FRAME (fontset), Qnil, Vdefault_fontset);
       rfont_def = fontset_find_font (FONTSET_DEFAULT (fontset), c, face, id, 0);
+      if (VECTORP (rfont_def))
+       return (rfont_def);
+      if (! NILP (rfont_def))
+       /* Remeber that we have no font for C.  */
+       FONTSET_SET (fontset, make_number (c), Qt);
     }
-  if (! NILP (rfont_def))
-    return rfont_def;
+
   /* Try a fallback font-group. */
   rfont_def = fontset_find_font (fontset, c, face, id, 1);
-  if (! NILP (rfont_def))
-    return rfont_def;
-  /* Try a fallback font-group of the default fontset . */
-  if (! EQ (base_fontset, Vdefault_fontset))
+  if (! VECTORP (rfont_def)
+      && ! EQ (base_fontset, Vdefault_fontset))
+    /* Try a fallback font-group of the default fontset . */
     rfont_def = fontset_find_font (FONTSET_DEFAULT (fontset), c, face, id, 1);
+
+  if (! VECTORP (rfont_def))
+    /* Remeber that we have no font for C.  */
+    FONTSET_SET (fontset, make_number (c), Qt);
+
   return rfont_def;
 }
 
@@ -932,6 +915,21 @@ fontset_ascii (id)
   return elt;
 }
 
+void
+free_realized_fontset (f, fontset)
+     FRAME_PTR f;
+     Lisp_Object fontset;
+{
+  int i;
+  Lisp_Object tail;
+
+  return;
+  for (tail = FONTSET_OBJLIST (fontset); CONSP (tail); tail = XCDR (tail))
+    {
+      xassert (FONT_OBJECT_P (XCAR (tail)));
+      font_close_object (f, XCAR (tail));
+    }
+}
 
 /* Free fontset of FACE defined on frame F.  Called from
    free_realized_face.  */
@@ -943,9 +941,10 @@ free_face_fontset (f, face)
 {
   Lisp_Object fontset;
 
-  fontset = AREF (Vfontset_table, face->fontset);
+  fontset = FONTSET_FROM_ID (face->fontset);
   xassert (!NILP (fontset) && ! BASE_FONTSET_P (fontset));
   xassert (f == XFRAME (FONTSET_FRAME (fontset)));
+  free_realized_fontset (f, fontset);
   ASET (Vfontset_table, face->fontset, Qnil);
   if (face->fontset < next_fontset_id)
     next_fontset_id = face->fontset;
@@ -956,6 +955,7 @@ free_face_fontset (f, face)
       fontset = AREF (Vfontset_table, id);
       xassert (!NILP (fontset) && ! BASE_FONTSET_P (fontset));
       xassert (f == XFRAME (FONTSET_FRAME (fontset)));
+      free_realized_fontset (f, fontset);
       ASET (Vfontset_table, id, Qnil);
       if (id < next_fontset_id)
        next_fontset_id = face->fontset;
@@ -1011,7 +1011,14 @@ face_for_char (f, face, c, pos, object)
       if (NILP (charset))
        id = -1;
       else if (CHARSETP (charset))
-       id = XINT (CHARSET_SYMBOL_ID (charset));
+       {
+         Lisp_Object val;
+
+         val = assoc_no_quit (charset, Vfont_encoding_charset_alist);
+         if (CONSP (val) && CHARSETP (XCDR (val)))
+           charset = XCDR (val);
+         id = XINT (CHARSET_SYMBOL_ID (charset));
+       }
     }
   rfont_def = fontset_font (fontset, c, face, id);
   if (VECTORP (rfont_def))
@@ -1020,7 +1027,7 @@ face_for_char (f, face, c, pos, object)
       if (enable_font_backend
          && NILP (AREF (rfont_def, 0)))
        {
-         struct font *font = XSAVE_VALUE (AREF (rfont_def, 4))->pointer;
+         struct font *font = XSAVE_VALUE (AREF (rfont_def, 3))->pointer;
 
          face_id = face_for_font (f, font, face);
          ASET (rfont_def, 0, make_number (face_id));
@@ -1066,7 +1073,6 @@ make_fontset_for_ascii_face (f, base_fontset_id, face)
       base_fontset = FONTSET_FROM_ID (base_fontset_id);
       if (!BASE_FONTSET_P (base_fontset))
        base_fontset = FONTSET_BASE (base_fontset);
-      xassert (BASE_FONTSET_P (base_fontset));
       if (! BASE_FONTSET_P (base_fontset))
        abort ();
     }
@@ -1074,41 +1080,6 @@ make_fontset_for_ascii_face (f, base_fontset_id, face)
     base_fontset = Vdefault_fontset;
 
   fontset = make_fontset (frame, Qnil, base_fontset);
-  {
-    Lisp_Object elt, rfont_def, val;
-
-    elt = FONTSET_REF (base_fontset, 0);
-    xassert (VECTORP (elt) && ASIZE (elt) > 0);
-#ifdef USE_FONT_BACKEND
-    rfont_def = Fmake_vector (make_number (5), Qnil);
-    if (enable_font_backend && face->font_info)
-      {
-       struct font *font = (struct font *) face->font_info;
-
-       ASET (rfont_def, 3, font->entity);
-       ASET (rfont_def, 4, font_find_object (font));
-      }
-    else
-#endif  /* USE_FONT_BACKEND */
-    {
-      rfont_def = Fmake_vector (make_number (4), Qnil);
-      ASET (rfont_def, 3, build_string (face->font_name));
-    }
-    ASET (rfont_def, 1, make_number (face->font_info_id));
-    ASET (rfont_def, 2, AREF (elt, 0));
-    elt = Fmake_vector (make_number (4), Qnil);
-    ASET (elt, 0, make_number (charset_ordered_list_tick));
-    ASET (elt, 1, make_number (charset_ascii));
-    ASET (elt, 2, rfont_def);
-    ASET (elt, 3, rfont_def);
-
-    val = Fcons (Qlatin, Qnil);
-    map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table, val);
-    for (val = XCDR (val); CONSP (val); val = XCDR (val))
-      char_table_set_range (fontset, XINT (XCAR (XCAR (val))),
-                           XINT (XCDR (XCAR (val))), elt);
-    FONTSET_FALLBACK (fontset) = elt;
-  }
   return XINT (FONTSET_ID (fontset));
 }
 
@@ -1482,24 +1453,26 @@ accumulate_script_ranges (arg, range, val)
 
 
 /* Return an ASCII font name generated from fontset name NAME and
-   ASCII font specification ASCII_SPEC.  NAME is a string conforming
-   to XLFD.  ASCII_SPEC is a vector:
-       [FAMILY WEIGHT SLANT SWIDTH ADSTYLE REGISTRY].  */
+   font-spec ASCII_SPEC.  NAME is a string conforming to XLFD.  */
 
 static INLINE Lisp_Object
 generate_ascii_font_name (name, ascii_spec)
      Lisp_Object name, ascii_spec;
 {
+  Lisp_Object font_spec = Ffont_spec (0, NULL);
   Lisp_Object vec;
   int i;
+  char xlfd[256];
 
-  vec = split_font_name_into_vector (name);
-  for (i = FONT_SPEC_FAMILY_INDEX; i <= FONT_SPEC_ADSTYLE_INDEX; i++)
+  if (font_parse_xlfd (SDATA (name), font_spec) < 0)
+    error ("Not an XLFD font name: %s", SDATA (name));
+  for (i = FONT_FOUNDRY_INDEX; i <= FONT_WIDTH_INDEX; i++)
     if (! NILP (AREF (ascii_spec, i)))
-      ASET (vec, 1 + i, AREF (ascii_spec, i));
-  if (! NILP (AREF (ascii_spec, FONT_SPEC_REGISTRY_INDEX)))
-    ASET (vec, 12, AREF (ascii_spec, FONT_SPEC_REGISTRY_INDEX));
-  return build_font_name_from_vector (vec);
+      ASET (font_spec, i, AREF (ascii_spec, i));
+  i = font_unparse_xlfd (font_spec, 0, xlfd, 256);
+  if (i < 0)
+    error ("Not an XLFD font name: %s", SDATA (name));
+  return make_unibyte_string (xlfd, i);
 }
 
 /* Variables referred in set_fontset_font.  They are set before
@@ -1544,6 +1517,7 @@ set_fontset_font (fontset, range)
   FONTSET_ADD (fontset, range, font_def_arg, add_arg);
 }
 
+extern Lisp_Object QCfamily, QCregistry;
 
 DEFUN ("set-fontset-font", Fset_fontset_font, Sset_fontset_font, 3, 5, 0,
        doc: /*
@@ -1567,6 +1541,7 @@ FONT-SPEC may one of these:
    REGISTRY is a font registry name.  FAMILY may contains foundry
    name, and REGISTRY may contains encoding name.
  * A font name string.
+ * nil, which explicitly specifies that there's no font for TARGET.
 
 Optional 4th argument FRAME, if non-nil, is a frame.  This argument is
 kept for backward compatibility and has no meaning.
@@ -1593,77 +1568,75 @@ appended.  By default, FONT-SPEC overrides the previous settings.  */)
 
   if (VECTORP (font_spec))
     {
-      /* FONT_SPEC should have this form:
-               [ FAMILY WEIGHT SLANT WIDTH ADSTYLE REGISTRY ]
-        This is a feature not yet documented because WEIGHT thru
-        ADSTYLE are ignored for the moment.  */
-      int j;
-
-      if (ASIZE (font_spec) != FONT_SPEC_MAX_INDEX)
-       args_out_of_range (make_number (FONT_SPEC_MAX_INDEX),
-                          make_number (ASIZE (font_spec)));
-
-      font_spec = Fcopy_sequence (font_spec);
-      for (j = 0; j < FONT_SPEC_MAX_INDEX - 1; j++)
-       if (! NILP (AREF (font_spec, j)))
-         {
-           CHECK_STRING (AREF (font_spec, j));
-           ASET (font_spec, j, Fdowncase (AREF (font_spec, j)));
-         }
-      family = AREF (font_spec, FONT_SPEC_FAMILY_INDEX);
-      /* REGISTRY should not be omitted.  */
-      CHECK_STRING (AREF (font_spec, FONT_SPEC_REGISTRY_INDEX));
-      registry = AREF (font_spec, FONT_SPEC_REGISTRY_INDEX);
+      if (! FONT_SPEC_P (font_spec))
+       Fsignal (Qfont, list2 (build_string ("invalid font-spec"), font_spec));
     }
   else if (CONSP (font_spec))
     {
+      Lisp_Object args[4];
+      int i= 0;
+
       family = XCAR (font_spec);
       registry = XCDR (font_spec);
 
       if (! NILP (family))
        {
          CHECK_STRING (family);
-         family = Fdowncase (family);
+         args[i++] = QCfamily;
+         args[i++] = family;
        }
       CHECK_STRING (registry);
-      registry = Fdowncase (registry);
-      font_spec = Fmake_vector (make_number (FONT_SPEC_MAX_INDEX), Qnil);
-      ASET (font_spec, FONT_SPEC_FAMILY_INDEX, family);
-      ASET (font_spec, FONT_SPEC_REGISTRY_INDEX, registry);
+      args[i++] = QCregistry;
+      args[i++] = registry;
+      font_spec = Ffont_spec (i, args);
     }
-  else
+  else if (STRINGP (font_spec))
     {
-      CHECK_STRING (font_spec);
-      font_spec = Fdowncase (font_spec);
-    }
-
-  if (STRINGP (font_spec))
-    encoding = find_font_encoding (font_spec);
-  else
-    encoding = find_font_encoding (concat2 (family, registry));
-  if (NILP (encoding))
-    encoding = Qascii;
+      Lisp_Object args[2];
 
-  if (SYMBOLP (encoding))
-    {
-      CHECK_CHARSET (encoding);
-      encoding = repertory = CHARSET_SYMBOL_ID (encoding);
+      args[0] = QCname;
+      args[1] = font_spec;
+      font_spec = Ffont_spec (2, args);
     }
-  else
+  else if (! NILP (font_spec))
+    wrong_type_argument (intern ("font-spec"), font_spec);
+
+  if (! NILP (font_spec))
     {
-      repertory = XCDR (encoding);
-      encoding = XCAR (encoding);
-      CHECK_CHARSET (encoding);
-      encoding = CHARSET_SYMBOL_ID (encoding);
-      if (! NILP (repertory) && SYMBOLP (repertory))
+      family = AREF (font_spec, FONT_FAMILY_INDEX);
+      if (! NILP (family) && SYMBOLP (family))
+       family = SYMBOL_NAME (family);
+      registry = AREF (font_spec, FONT_REGISTRY_INDEX);
+      if (! NILP (registry) && SYMBOLP (registry))
+       registry = SYMBOL_NAME (registry);
+
+      encoding = find_font_encoding (concat2 (family, registry));
+      if (NILP (encoding))
+       encoding = Qascii;
+
+      if (SYMBOLP (encoding))
+       {
+         CHECK_CHARSET (encoding);
+         encoding = repertory = CHARSET_SYMBOL_ID (encoding);
+       }
+      else
        {
-         CHECK_CHARSET (repertory);
-         repertory = CHARSET_SYMBOL_ID (repertory);
+         repertory = XCDR (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);
     }
-  font_def = Fmake_vector (make_number (3), font_spec);
-  ASET (font_def, 1, encoding);
-  ASET (font_def, 2, repertory);
+  else
+    font_def = Qnil;
 
   if (CHARACTERP (target))
     range_list = Fcons (Fcons (target, target), Qnil);
@@ -1690,7 +1663,7 @@ appended.  By default, FONT-SPEC overrides the previous settings.  */)
          map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
                          val);
          range_list = XCDR (val);
-         if (EQ (target, Qlatin))
+         if (EQ (target, Qlatin) && NILP (FONTSET_ASCII (fontset)))
            {
              if (VECTORP (font_spec))
                val = generate_ascii_font_name (FONTSET_NAME (fontset),
@@ -1702,7 +1675,7 @@ appended.  By default, FONT-SPEC overrides the previous settings.  */)
        }
       if (CHARSETP (target))
        {
-         if (EQ (target, Qascii))
+         if (EQ (target, Qascii) && NILP (FONTSET_ASCII (fontset)))
            {
              if (VECTORP (font_spec))
                font_spec = generate_ascii_font_name (FONTSET_NAME (fontset),
@@ -1900,6 +1873,8 @@ new_fontset_from_font (font_object)
   font_spec = Fcons (SYMBOL_NAME (AREF (font_spec, FONT_FAMILY_INDEX)),
                     SYMBOL_NAME (AREF (font_spec, FONT_REGISTRY_INDEX)));
   Fset_fontset_font (name, Qlatin, font_spec, Qnil, Qnil);
+  XSETCDR (font_spec, build_string ("iso10646-1"));
+  Fset_fontset_font (name, Qlatin, font_spec, Qnil, Qappend);
   Fset_fontset_font (name, Qnil, font_spec, Qnil, Qnil);
   return XINT (FONTSET_ID (fontset));
 }
@@ -2011,7 +1986,7 @@ If the named font is not yet loaded, return nil.  */)
   XVECTOR (info)->contents[6] = make_number (fontp->default_ascent);
 
 #ifdef USE_FONT_BACKEND
-  if (! NILP (font_object))
+  if (enable_font_backend && ! NILP (font_object))
     font_close_object (f, font_object);
 #endif /* USE_FONT_BACKEND */
   return info;
@@ -2050,7 +2025,7 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 2, 0,
      (position, ch)
      Lisp_Object position, ch;
 {
-  int pos, pos_byte, dummy;
+  EMACS_INT pos, pos_byte, dummy;
   int face_id;
   int c;
   struct frame *f;
@@ -2104,16 +2079,19 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 2, 0,
 #ifdef USE_FONT_BACKEND
   if (enable_font_backend)
     {
-      if (VECTORP (rfont_def) && ! NILP (AREF (rfont_def, 4)))
+      if (VECTORP (rfont_def) && ! NILP (AREF (rfont_def, 3)))
        {
-         Lisp_Object font_object = AREF (rfont_def, 4);
+         Lisp_Object font_object = AREF (rfont_def, 3);
          struct font *font = XSAVE_VALUE (font_object)->pointer;
          unsigned code = font->driver->encode_char (font, c);
          Lisp_Object fontname = font_get_name (font_object);
+         /* Assignment to EMACS_INT stops GCC whining about limited range
+            of data type.  */
+         EMACS_INT cod = code;
 
          if (code == FONT_INVALID_CODE)
-           return Fcons (fontname, Qnil);
-         if (code <= MOST_POSITIVE_FIXNUM)
+           return Qnil;
+         if (cod <= MOST_POSITIVE_FIXNUM)
            return Fcons (fontname, make_number (code));
          return Fcons (fontname, Fcons (make_number (code >> 16),
                                         make_number (code & 0xFFFF)));
@@ -2233,7 +2211,12 @@ fontset.  The format is the same as abobe.  */)
 
              /* At first, set ALIST to ((FONT-SPEC) ...).  */
              for (alist = Qnil, i = 0; i < ASIZE (val); i++)
-               alist = Fcons (Fcons (AREF (AREF (val, i), 0), Qnil), alist);
+               {
+                 if (NILP (AREF (val, i)))
+                   alist = Fcons (Qnil, alist);
+                 else
+                   alist = Fcons (Fcons (AREF (AREF (val, i), 0), Qnil), alist);
+               }
              alist = Fnreverse (alist);
 
              /* Then store opend font names to cdr of each elements.  */
@@ -2245,29 +2228,63 @@ fontset.  The format is the same as abobe.  */)
                    val = FONTSET_FALLBACK (realized[k][i]);
                  if (! VECTORP (val))
                    continue;
-                 /* VAL is [int int ?
-                            [FACE-ID FONT-INDEX FONT-DEF FONT-NAME] ...].
-                    If a font of an element is already opened,
-                    FONT-NAME is the name of a opened font.  */
-                 for (j = 3; j < ASIZE (val); j++)
-                   if (STRINGP (AREF (AREF (val, j), 3)))
+#ifdef USE_FONT_BACKEND
+                 /* VAL: [int int ?
+                          [FACE-ID FONT-INDEX FONT-DEF FONT-ENTITY/OBJECT]
+                          ...]  */
+                 if (enable_font_backend)
+                   for (j = 3; j < ASIZE (val); j++)
                      {
-                       Lisp_Object font_idx;
-
-                       font_idx = AREF (AREF (val, j), 1);
-                       elt = Fassq (AREF (AREF (AREF (val, j), 2), 0), alist);
-                       if (CONSP (elt)
-                           && NILP (Fmemq (font_idx, XCDR(elt))))
-                         nconc2 (elt, Fcons (font_idx, Qnil));
+                       elt = AREF (val, j);
+                       if (INTEGERP (AREF (elt, 1))
+                           && XINT (AREF (elt, 1)) >= 0)
+                         {
+                           Lisp_Object font_object = AREF (elt, 3);
+
+                           if (FONT_OBJECT_P (font_object))
+                             {
+                               struct font *font
+                                 = XSAVE_VALUE (font_object)->pointer;
+                               char *name = font->font.full_name;
+                               int len = strlen (name);
+                               Lisp_Object slot;
+
+                               slot = Fassq (AREF (AREF (elt, 2), 0), alist);
+                               nconc2 (slot,
+                                       Fcons (make_unibyte_string (name, len),
+                                              Qnil));
+                             }
+                         }
                      }
+                 else
+#endif  /* not USE_FONT_BACKEND */
+                   {
+                     /* VAL is [int int ?
+                                [FACE-ID FONT-INDEX FONT-DEF FONT-NAME] ...].
+                        If a font of an element is already opened,
+                        FONT-NAME is the name of a opened font.  */
+                     for (j = 3; j < ASIZE (val); j++)
+                       if (STRINGP (AREF (AREF (val, j), 3)))
+                         {
+                           Lisp_Object font_idx;
+
+                           font_idx = AREF (AREF (val, j), 1);
+                           elt = Fassq (AREF (AREF (AREF (val, j), 2), 0),
+                                        alist);
+                           if (CONSP (elt)
+                               && NILP (Fmemq (font_idx, XCDR(elt))))
+                             nconc2 (elt, Fcons (font_idx, Qnil));
+                         }
+                     for (val = alist; CONSP (val); val = XCDR (val))
+                       for (elt = XCDR (XCAR (val)); CONSP (elt);
+                            elt = XCDR (elt))
+                         {
+                           struct font_info *font_info
+                             = (*get_font_info_func) (f, XINT (XCAR (elt)));
+                           XSETCAR (elt, build_string (font_info->full_name));
+                         }
+                   }
                }
-             for (val = alist; CONSP (val); val = XCDR (val))
-               for (elt = XCDR (XCAR (val)); CONSP (elt); elt = XCDR (elt))
-                 {
-                   struct font_info *font_info
-                     = (*get_font_info_func) (f, XINT (XCAR (elt)));
-                   XSETCAR (elt, build_string (font_info->full_name));
-                 }
 
              /* Store ALIST in TBL for characters C..TO.  */
              if (c <= MAX_5_BYTE_CHAR)
@@ -2438,7 +2455,7 @@ syms_of_fontset ()
   FONTSET_ID (Vdefault_fontset) = make_number (0);
   FONTSET_NAME (Vdefault_fontset)
     = build_string ("-*-*-*-*-*-*-*-*-*-*-*-*-fontset-default");
-  AREF (Vfontset_table, 0) = Vdefault_fontset;
+  ASET (Vfontset_table, 0, Vdefault_fontset);
   next_fontset_id = 1;
 
   auto_fontset_alist = Qnil;
@@ -2451,6 +2468,9 @@ Each element looks like (REGEXP . (ENCODING . REPERTORY)),
 where ENCODING is a charset or a char-table,
 and REPERTORY is a charset, a char-table, or nil.
 
+If ENCDING and REPERTORY are the same, the element can have the form
+\(REGEXP . ENCODING).
+
 ENCODING is for converting a character to a glyph code of the font.
 If ENCODING is a charset, encoding a character by the charset gives
 the corresponding glyph code.  If ENCODING is a char-table, looking up
@@ -2463,6 +2483,17 @@ non-nil value in the table are supported.  It REPERTORY is nil, Emacs
 gets the repertory information by an opened font and ENCODING.  */);
   Vfont_encoding_alist = Qnil;
 
+  DEFVAR_LISP ("font-encoding-charset-alist", &Vfont_encoding_charset_alist,
+              doc: /*
+Alist of charsets vs the charsets to determine the preferred font encoding.
+Each element looks like (CHARSET . ENCDOING-CHARSET),
+where ENCODING-CHARSET is a charset registered in the variable
+`font-encoding-alist' as ENCODING.
+
+When a text has a property `charset' and the value is CHARSET, a font
+whose encoding corresponds to ENCODING-CHARSET is preferred.  */);
+  Vfont_encoding_charset_alist = Qnil;
+
   DEFVAR_LISP ("use-default-ascent", &Vuse_default_ascent,
               doc: /*
 Char table of characters whose ascent values should be ignored.