changeset 88903:d32a3736c4fe

(Qprepend, Qappend): New variables. (FONTSET_CHARSET_ALIST, FONTSET_FACE_ALIST): These macros deleted. (FONTSET_NOFONT_FACE, FONTSET_REPERTORY): New macros. (FONTSET_REF): Optimize if FONTSET is Vdefault_fontset. (FONTSET_REF_AND_RANGE, FONTSET_ADD): New macros. (fontset_ref_and_range, fontset_add, reorder_font_vector) (load_font_get_repertory): New functions. (fontset_set): This function deleted. (fontset_face): New arg FACE. Return face ID, not face. Completely re-written to handle new fontset structure. Caller changed. (free_face_fontset): Use ASET istead of AREF (X) = Y. (face_for_char): Don't call lookup_face. (make_fontset_for_ascii_face): New arg FACE. (fs_load_font): New arg CHARSET_ID. Don't check Vfont_encoding_alist here. (find_font_encoding): New function. (list_fontsets): Use STRINGP, not ! NILP. (accumulate_script_ranges): New function. (Fset_fontset_font, Fnew_fontset, Ffontset_info): Completely re-written to handle new fontset structure. (Ffontset_font): Return a copy of element. (syms_of_fontset): Define symbols Qprepend and Qappend. Fix docstring of font-encoding-alist.
author Kenichi Handa <handa@m17n.org>
date Fri, 26 Jul 2002 04:06:25 +0000
parents 8975795eb087
children da66b8fcc88c
files src/fontset.c
diffstat 1 files changed, 770 insertions(+), 435 deletions(-) [+]
line wrap: on
line diff
--- a/src/fontset.c	Fri Jul 26 04:06:05 2002 +0000
+++ b/src/fontset.c	Fri Jul 26 04:06:25 2002 +0000
@@ -54,61 +54,105 @@
 /* FONTSET
 
    A fontset is a collection of font related information to give
-   similar appearance (style, etc) of characters.  There are two kinds
-   of fontsets; base and realized.  A base fontset is created by
-   `new-fontset' from Emacs Lisp explicitly.  A realized fontset is
-   created implicitly when a face is realized for ASCII characters.  A
-   face is also realized for non-ASCII characters based on an ASCII
-   face.  All of non-ASCII faces based on the same ASCII face share
-   the same realized fontset.
+   similar appearance (style, etc) of characters.  A fontset has two
+   roles.  One is to use for the frame parameter `font' as if it is an
+   ASCII font.  In that case, Emacs uses the font specified for
+   `ascii' script for the frame's default font.
+
+   Another role, the more important one, is to provide information
+   about which font to use for each non-ASCII character.
+
+   There are two kinds of fontsets; base and realized.  A base fontset
+   is created by `new-fontset' from Emacs Lisp explicitly.  A realized
+   fontset is created implicitly when a face is realized for ASCII
+   characters.  A face is also realized for non-ASCII characters based
+   on an ASCII face.  All of non-ASCII faces based on the same ASCII
+   face share the same realized fontset.
    
    A fontset object is implemented by a char-table whose default value
    and parent are always nil.
 
-   An element of a base fontset is a font specification of the form:
-	[ FAMILY WEIGHT SLANT SWIDTH REGISTRY ] (vector of size 5)
+   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 ]
    or
-	FONT-NAME (strig)
+	FONT-NAME
+   where FAMILY, WEIGHT, SLANT, SWIDTH, ADSTYLE, REGISTRY, and
+   FONT-NAME are strings.
 
-   FAMILY and REGISTRY are strings.
+   ENCODING is a charset ID or a char-table that can convert
+   characters to glyph codes of the corresponding font.
 
-   WEIGHT, SLANT, and SWIDTH must be symbols that set-face-attribute
-   accepts as attribute values for :weight, :slant, :swidth
-   respectively.
+   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 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.
 
 
-   A fontset has 7 extra slots.
+   An element of a realized fontset is nil or t, or has this form:
+
+	( CHARSET-PRIORITY-LIST-TICK . FONT-VECTOR )
 
-   The 1st slot is an ID number of the fontset.
+   FONT-VECTOR is a vector whose elements have this form:
+
+	[ FACE-ID FONT-INDEX FONT-DEF ]
+
+   FONT-VECTOR is automatically reordered by the current charset
+   priority list.
 
-   The 2nd slot is a name of the fontset in a base fontset, and nil in
-   a realized fontset.
+   The value nil means that we have not yet generated FONT-VECTOR from
+   the base of the fontset.
 
-   The 3rd slot is nil in a base fontset, and a base fontset in a
-   realized fontset.
+   The value t means that no font is available for the corresponding
+   range of characters.
+
+
+   A fontset has 5 extra slots.
+
+   The 1st slot: the ID number of the fontset
 
-   The 4th slot is a frame that the fontset belongs to.  This is nil
-   in a base fontset.
+   The 2nd slot:
+	base: the name of the fontset
+	realized: nil
 
-   The 5th slot is a cons of 0 and fontname for ASCII characters in a
-   base fontset, and nil in a realized face.
+   The 3rd slot:
+	base: nli
+	realized: the base fontset
+
+   The 4th slot:
+	base: nil
+	realized: the frame that the fontset belongs to
 
-   The 6th slot is an alist of a charset vs. the corresponding font
-   specification.
+   The 5th slot:
+	base: the font name for ASCII characters
+	realized: nil
 
-   The 7th slot is an alist of a font specification vs. the
-   corresponding face ID.  In a base fontset, the face IDs are all
-   nil.
+   The 6th slot:
+	base: nil
+	realized: the ID number of a face to use for characters that
+		  has no font in a realized fontset.
 
-   All fontsets are recorded in Vfontset_table.
+   The 7th slot:
+	base: nil
+	realized: Alist of font index vs the corresponding repertory
+	char-table.
+	
+
+   All fontsets are recorded in the vector Vfontset_table.
 
 
    DEFAULT FONTSET
 
-   There's a special fontset named `default fontset' which defines the
-   default font specifications.  When a base fontset doesn't specify a
-   font for a specific character, the corresponding value in the
-   default fontset is used.  The format is the same as a base fontset.
+   There's a special base fontset named `default fontset' which
+   defines the default font specifications.  When a base fontset
+   doesn't specify a font for a specific character, the corresponding
+   value in the default fontset is used.
 
    The parent of a realized fontset created for such a face that has
    no fontset is the default fontset.
@@ -118,7 +162,7 @@
    The other codes handle fontsets only by their ID numbers.  They
    usually use the variable name `fontset' for IDs.  But, in this
    file, we always use varialbe name `id' for IDs, and name `fontset'
-   for the actual fontset objects (i.e. char-table objects).
+   for an actual fontset object, i.e., char-table.
 
 */
 
@@ -126,6 +170,7 @@
 
 extern Lisp_Object Qfont;
 Lisp_Object Qfontset;
+static Lisp_Object Qprepend, Qappend;
 
 /* Vector containing all fontsets.  */
 static Lisp_Object Vfontset_table;
@@ -176,6 +221,9 @@
    This function set the member `encoder' of the structure.  */
 void (*find_ccl_program_func) P_ ((struct font_info *));
 
+Lisp_Object (*get_font_repertory_func) P_ ((struct frame *,
+					    struct font_info *));
+
 /* Check if any window system is used now.  */
 void (*check_window_system_func) P_ ((void));
 
@@ -184,6 +232,9 @@
 static Lisp_Object make_fontset P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
 static int fontset_id_valid_p P_ ((int));
 static Lisp_Object fontset_pattern_regexp P_ ((Lisp_Object));
+static void accumulate_script_ranges P_ ((Lisp_Object, Lisp_Object,
+					  Lisp_Object));
+
 
 
 /********** MACROS AND FUNCTIONS TO HANDLE FONTSET **********/
@@ -203,13 +254,19 @@
 /* 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_CHARSET_ALIST(fontset)	XCHAR_TABLE (fontset)->extras[5]
-#define FONTSET_FACE_ALIST(fontset)	XCHAR_TABLE (fontset)->extras[6]
+#define FONTSET_NOFONT_FACE(fontset)	XCHAR_TABLE (fontset)->extras[5]
+#define FONTSET_REPERTORY(fontset)	XCHAR_TABLE (fontset)->extras[6]
 
 
-/* Return the element of FONTSET (char-table) at index C (character).  */
+/* Return the element of FONTSET for the character 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(fontset, c, etl)	((elt) = fontset_ref ((fontset), (c)))
+#define FONTSET_REF(fontset, c)		\
+  (EQ (fontset, Vdefault_fontset)	\
+   ? CHAR_TABLE_REF (fontset, c)	\
+   : fontset_ref ((fontset), (c)))
 
 static Lisp_Object
 fontset_ref (fontset, c)
@@ -218,105 +275,336 @@
 {
   Lisp_Object elt;
 
-  while (1)
-    {
-      elt = CHAR_TABLE_REF (fontset, c);
-      if (NILP (elt) && ASCII_CHAR_P (c))
-	elt = FONTSET_ASCII (fontset);
-      if (NILP (elt))
-	{
-	  Lisp_Object tail;
-	  struct charset *charset;
+  elt = CHAR_TABLE_REF (fontset, c);
+  if (NILP (elt) && ! EQ (fontset, Vdefault_fontset)
+      /* Don't check Vdefault_fontset for a realized fontset.  */
+      && NILP (FONTSET_BASE (fontset)))
+    elt = CHAR_TABLE_REF (Vdefault_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))
 
-	  for (tail = FONTSET_CHARSET_ALIST (fontset);
-	       CONSP (tail);  tail = XCDR (tail))
-	    {
-	      charset = CHARSET_FROM_ID (XINT (XCAR (XCAR (tail))));
-	      if (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset))
-		{
-		  elt = XCDR (XCAR (tail));
-		  break;
-		}
-	    }
-	}
-      if (! NILP (elt) || EQ (fontset, Vdefault_fontset))
-	break;
-      fontset = Vdefault_fontset;
+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 the element of FONTSET at index IDX to the value ELT.  IDX may
-   be a character or a charset.  */
+/* 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.  */
+
+#define FONTSET_SET(fontset, range, elt)	\
+  Fset_char_table_range ((fontset), (range), (elt))
+
+
+/* Modify the elements of FONTSET for characters in RANGE by replacing
+   with ELT or adding ETL.  RANGE is a cons (FROM . TO), where FROM
+   and TO are character codes specifying a range.  If ADD is nil,
+   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)))	\
+   : fontset_add ((fontset), (range), (elt), (add)))
 
-#define FONTSET_SET(fontset, c, newelt) fontset_set(fontset, c, newelt)
+static void
+fontset_add (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 (NILP (elt1))
+      elt1 = Fmake_vector (make_number (1), elt);
+    else
+      {
+	int i, i0 = 1, i1 = ASIZE (elt1) + 1;
+	Lisp_Object new;
+
+	new = Fmake_vector (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);
+}
+
+
+/* Update FONTSET_ELEMENT which has this form:
+	( CHARSET-PRIORITY-LIST-TICK . FONT-VECTOR).
+   Reorder FONT-VECTOR according to the current order of charset
+   (Vcharset_ordered_list), and update CHARSET-PRIORITY-LIST-TICK to
+   the latest value.  */
 
 static void
-fontset_set (fontset, idx, elt)
-     Lisp_Object fontset, idx, elt;
+reorder_font_vector (fontset_element)
+     Lisp_Object fontset_element;
 {
-  if (SYMBOLP (idx))
+  Lisp_Object vec, list, *new_vec;
+  int size;
+  int *charset_id_table;
+  int i, idx;
+
+  XSETCAR (fontset_element, make_number (charset_ordered_list_tick));
+  vec = XCDR (fontset_element);
+  size = ASIZE (vec);
+  if (size < 2)
+    /* No need of reordering VEC.  */
+    return;
+  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 VEC.  VEC has this
+     form:
+	[[FACE-ID FONT-INDEX [ FONT-SPEC ENCODING REPERTORY ]] ...] */
+  for (i = 0; i < size; i++)
+    charset_id_table[i] = XINT (AREF (AREF (AREF (vec, i), 2), 1));
+
+  /* Then, store the elements of VEC in NEW_VEC in the correct
+     order.  */
+  idx = 0;
+  for (list = Vcharset_ordered_list; CONSP (list); list = XCDR (list))
     {
-      Lisp_Object id, slot, tail;
-      
-      id = CHARSET_SYMBOL_ID (idx);
-      if (XFASTINT (id) == charset_ascii)
-	Fset_char_table_range (fontset,
-			       Fcons (make_number (0), make_number (127)),
-			       elt);
-      else
-	{
-	  slot = Fassq (id, FONTSET_CHARSET_ALIST (fontset));
-	  if (CONSP (slot))
-	    XCDR (slot) = elt;
-	  else if (CONSP (FONTSET_CHARSET_ALIST (fontset)))
-	    {
-	      for (tail = FONTSET_CHARSET_ALIST (fontset);
-		   CONSP (XCDR (tail)); tail = XCDR (tail));
-	      XCDR (tail) = Fcons (Fcons (id, elt), Qnil);
-	    }
-	  else
-	    FONTSET_CHARSET_ALIST (fontset) = Fcons (Fcons (id, elt), Qnil);
-	}
+      for (i = 0; i < size; i++)
+	if (charset_id_table[i] == XINT (XCAR (list)))
+	  new_vec[idx++] = AREF (vec, i);
+      if (idx == size)
+	break;
     }
-  else
-    {
-      int from = XINT (XCAR (idx));
-      int to = XINT (XCDR (idx));
+
+  /* At last, update VEC.  */
+  for (i = 0; i < size; i++)
+    ASET (vec, i, new_vec[i]);
+}
+
+
+/* Load a font matching the font related attributes in FACE->lface and
+   font pattern in FONT_DEF of FONTSET, and return an index of the
+   font.  FONT_DEF has this form:
+	[ FONT-SPEC ENCODING REPERTORY ]
+   If REPERTORY is nil, generate a char-table representing the font
+   repertory by looking into the font itself.  */
 
-      if (from == to)
-	CHAR_TABLE_SET (fontset, from, elt);
-      else
-	Fset_char_table_range (fontset, idx, elt);
+static int
+load_font_get_repertory (f, face, font_def, fontset)
+     FRAME_PTR f;
+     struct face *face;
+     Lisp_Object font_def;
+     Lisp_Object fontset;
+{
+  char *font_name;
+  struct font_info *font_info;
+
+  font_name = choose_face_font (f, face->lface, AREF (font_def, 0));
+  if (! (font_info = fs_load_font (f, font_name, XINT (AREF (font_def, 1)))))
+    return -1;
+
+  if (NILP (AREF (font_def, 2))
+      && NILP (Fassq (make_number (font_info->font_idx),
+		      FONTSET_REPERTORY (fontset))))
+    {
+      /* We must look into the font to get the correct repertory as a
+	 char-table.  */
+      Lisp_Object repertory;
+
+      repertory = (*get_font_repertory_func) (f, font_info);
+      FONTSET_REPERTORY (fontset)
+	= Fcons (Fcons (make_number (font_info->font_idx), repertory),
+		 FONTSET_REPERTORY (fontset));	       
     }
+	
+  return font_info->font_idx;
 }
 
 
-/* Return a face registerd in the realized fontset FONTSET for the
-   character C.  Return -1 if a face ID is not yet set.  */
+/* Return a face ID registerd in the realized fontset FONTSET for the
+   character C.  If FACE is NULL, return -1 if a face is not yet
+   set.  Otherwise, realize a proper face from FACE and return it.  */
 
-static struct face *
-fontset_face (fontset, c)
+static int
+fontset_face (fontset, c, face)
      Lisp_Object fontset;
      int c;
+     struct face *face;
 {
-  Lisp_Object base, elt;
-  int id;
-  struct face *face;
+  Lisp_Object elt, vec;
+  int i, from, to;
+  int font_idx;
+  FRAME_PTR f = XFRAME (FONTSET_FRAME (fontset));
 
-  base = FONTSET_BASE (fontset);
-  FONTSET_REF (base, c, elt);
+  elt = CHAR_TABLE_REF (fontset, c);
 
+  if (EQ (elt, Qt))
+    goto font_not_found;
   if (NILP (elt))
-    return NULL;
+    {
+      /* We have not yet decided a face for C.  */
+      Lisp_Object base_fontset, range;
+
+      if (! face)
+	return -1;
+      base_fontset = FONTSET_BASE (fontset);
+      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 font_not_found;
+	}
+      elt = Fcopy_sequence (elt);
+      /* Now ELT is a vector of FONT-DEFs.  We at first change it to
+	 FONT-VECTOR, a vector of [ nil nil FONT-DEF ].  */
+      for (i = 0; i < ASIZE (elt); i++)
+	{
+	  Lisp_Object tmp;
+
+	  tmp = Fmake_vector (make_number (3), Qnil);
+	  ASET (tmp, 2, AREF (elt, i));
+	  ASET (elt, i, tmp);
+	}
+      /* Then store (-1 . FONT-VECTOR) in the fontset.  -1 is to force
+	 reordering of FONT-VECTOR.  */
+      elt = Fcons (make_number (-1), elt);
+      FONTSET_SET (fontset, range, elt);
+    }
+
+  if (XINT (XCAR (elt)) != charset_ordered_list_tick)
+    /* The priority of charsets is changed after we selected a face
+       for C last time.  */
+    reorder_font_vector (elt);
+
+  vec = XCDR (elt);
+  /* Find the first available font in the font vector VEC.  */
+  for (i = 0; i < ASIZE (vec); i++)
+    {
+      Lisp_Object font_def;
+
+      elt = AREF (vec, i);
+      /* ELT == [ FACE-ID FONT-INDEX [ FONT-SPEC ENCODING REPERTORY ] ] */
+      font_def = AREF (elt, 2);
+      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 (INTEGERP (AREF (font_def, 2)))
+	{
+	  /* The repertory is specified by charset ID.  */
+	  struct charset *charset
+	    = CHARSET_FROM_ID (XINT (AREF (font_def, 2)));
 
-  elt = Fassoc (elt, FONTSET_FACE_ALIST (fontset));
-  if (! CONSP (elt))
-    return NULL;
-  id = XINT (XCDR (elt));
-  face = FACE_FROM_ID (XFRAME (FONTSET_FRAME (fontset)), id);
-  return face;
+	  if (! CHAR_CHARSET_P (c, charset))
+	    /* This fond can't display C.  */
+	    continue;
+	}
+      else
+	{
+	  Lisp_Object slot;
+
+	  if (! INTEGERP (AREF (elt, 1)))
+	    {
+	      /* We have not yet opened a font matching this spec.
+		 Open the best matching font now and register the
+		 repertory.  */
+	      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;
+	    }
+
+	  slot = Fassq (AREF (elt, 1), FONTSET_REPERTORY (fontset));
+	  if (! CONSP (slot))
+	    abort ();
+	  if (NILP (CHAR_TABLE_REF (XCDR (slot), c)))
+	    /* This fond 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
+	{
+	  /* But not yet opened the best matching font.  */
+	  font_idx = load_font_get_repertory (f, face, font_def, fontset);
+	  ASET (elt, 1, make_number (font_idx));
+	  if (font_idx < 0)
+	    continue;
+	}
+
+      /* Now we have the opened font.  */
+      if (NILP (AREF (elt, 0)))
+	{
+	  /* But not yet made a realized face that uses this font.  */
+	  int face_id = lookup_non_ascii_face (f, font_idx, face);
+
+	  ASET (elt, 0, make_number (face_id));
+	}
+
+      /* Ok, this face can display C.  */
+      return XINT (AREF (elt, 0));
+    }
+
+ font_not_found:
+  /* 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));
 }
 
 
@@ -341,6 +629,7 @@
 
   if (id + 1 == size)
     {
+      /* We must grow Vfontset_table.  */
       Lisp_Object tem;
       int i;
 
@@ -371,9 +660,9 @@
 
 
 
-/********** INTERFACES TO xfaces.c and dispextern.h **********/
+/********** INTERFACES TO xfaces.c, xfns.c, and dispextern.h **********/
 
-/* Return name of the fontset with ID.  */
+/* Return the name of the fontset who has ID.  */
 
 Lisp_Object
 fontset_name (id)
@@ -386,16 +675,19 @@
 }
 
 
-/* Return ASCII font name of the fontset with ID.  */
+/* Return the ASCII font name of the fontset who has ID.  */
 
 Lisp_Object
 fontset_ascii (id)
      int id;
 {
-  Lisp_Object fontset;
+  Lisp_Object fontset, elt;
 
   fontset= FONTSET_FROM_ID (id);
-  return FONTSET_ASCII (fontset);
+  elt = FONTSET_ASCII (fontset);
+  /* It is assured that ELT is always a string (i.e. fontname
+     pattern).  */
+  return elt;
 }
 
 
@@ -407,7 +699,7 @@
      FRAME_PTR f;
      struct face *face;
 {
-  AREF (Vfontset_table, face->fontset) = Qnil;
+  ASET (Vfontset_table, face->fontset, Qnil);
   if (face->fontset < next_fontset_id)
     next_fontset_id = face->fontset;
 }
@@ -425,14 +717,13 @@
   Lisp_Object fontset;
 
   fontset = FONTSET_FROM_ID (face->fontset);
-  return (face == fontset_face (fontset, c));
+  return (face->id == fontset_face (fontset, c, NULL));
 }
 
 
 /* Return ID of face suitable for displaying character C on frame F.
-   The selection of face is done based on the fontset of FACE.  FACE
-   must be reazlied for ASCII characters in advance.  Called from the
-   macro FACE_FOR_CHAR when C is not an ASCII character.  */
+   FACE must be reazlied for ASCII characters in advance.  Called from
+   the macro FACE_FOR_CHAR.  */
 
 int
 face_for_char (f, face, c)
@@ -441,19 +732,17 @@
      int c;
 {
   Lisp_Object fontset;
-  struct face *new_face;
+  Lisp_Object elt, vec;
+  int font_idx;
+  int i;
+
+  if (ASCII_CHAR_P (c))
+    return face->ascii_face->id;
 
   xassert (fontset_id_valid_p (face->fontset));
   fontset = FONTSET_FROM_ID (face->fontset);
   xassert (!BASE_FONTSET_P (fontset));
-
-  new_face = fontset_face (fontset, c);
-  if (new_face)
-    return new_face->id;
-
-  /* No face is recorded for C in the fontset of FACE.  Make a new
-     realized face for C that has the same fontset.  */
-  return lookup_face (f, face->lface, c, face);
+  return fontset_face (fontset, c, face);
 }
 
 
@@ -463,9 +752,10 @@
    Called from realize_x_face.  */
 
 int
-make_fontset_for_ascii_face (f, base_fontset_id)
+make_fontset_for_ascii_face (f, base_fontset_id, face)
      FRAME_PTR f;
      int base_fontset_id;
+     struct face *face;
 {
   Lisp_Object base_fontset, fontset, frame;
 
@@ -476,53 +766,25 @@
       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 ();
     }
   else
     base_fontset = Vdefault_fontset;
 
   fontset = make_fontset (frame, Qnil, base_fontset);
-  return XINT (FONTSET_ID (fontset));
-}
-
-
-/* Return FONT-SPEC recorded in the fontset of FACE for character C.
-   If FACE is null, or the fontset doesn't contain information about
-   C, get the font name pattern from the default fontset.  Called from
-   choose_face_font.  */
-
-Lisp_Object
-fontset_font_pattern (f, face, c)
-     FRAME_PTR f;
-     struct face *face;
-     int c;
-{
-  Lisp_Object fontset, base, elt;
-  int id = face ? face->fontset : -1;
+  {
+    Lisp_Object elt;
 
-  if (id >= 0)
-    {
-      fontset = FONTSET_FROM_ID (id);
-      xassert (!BASE_FONTSET_P (fontset));
-      base = FONTSET_BASE (fontset);
-    }
-  else
-    {
-      base = Vdefault_fontset;
-    }
-
-  FONTSET_REF (base, c, elt);
-  if (face && ! NILP (elt))
-    {
-      Lisp_Object slot;
-
-      slot = Fassoc (elt, FONTSET_FACE_ALIST (fontset));
-      if (CONSP (slot))
-	XSETCDR (slot, make_number (face->id));
-      FONTSET_FACE_ALIST (fontset)      
-	= Fcons (Fcons (elt, make_number (face->id)),
-		 FONTSET_FACE_ALIST (fontset));
-    }
-  return elt;
+    elt = FONTSET_REF (base_fontset, 0);
+    elt = Fmake_vector (make_number (3), AREF (elt, 0));
+    ASET (elt, 0, make_number (face->id));
+    ASET (elt, 1, make_number (face->font_info_id));
+    elt = Fcons (make_number (charset_ordered_list_tick),
+		 Fmake_vector (make_number (1), elt));
+    char_table_set_range (fontset, 0, 127, elt);
+  }
+  return XINT (FONTSET_ID (fontset));
 }
 
 
@@ -532,49 +794,41 @@
 
 /* Load a font named FONTNAME on frame F.  Return a pointer to the
    struct font_info of the loaded font.  If loading fails, return
-   NULL.  */
+   NULL.  CHARSET_ID is an ID of charset to encode characters for this
+   font.  */
 
 struct font_info *
-fs_load_font (f, fontname)
+fs_load_font (f, fontname, charset_id)
      FRAME_PTR f;
      char *fontname;
+     int charset_id;
 {
-  Lisp_Object tail, elt;
   struct font_info *fontp;
 
   if (!fontname)
     /* No way to get fontname.  */
-    return 0;
+    return NULL;
 
   fontp = (*load_font_func) (f, fontname, 0);
   if (!fontp)
     return NULL;
 
   fontname = fontp->full_name;
-  /* Fill in members (charset, vertical_centering, encoding, etc) of
-     font_info structure that are not set by (*load_font_func).  */
-  for (tail = Vfont_encoding_alist; CONSP (tail); tail = XCDR (tail))
-    {
-      elt = XCAR (tail);
-      if (STRINGP (XCAR (elt)) && CHARSETP (XCDR (elt))
-	  && fast_c_string_match_ignore_case (XCAR (elt), fontname) >= 0)
-	{
-	  fontp->charset = XFASTINT (CHARSET_SYMBOL_ID (XCDR (elt)));
-	  break;
-	}
-    }
-  if (! CONSP (tail))
-    return NULL;
 
-  fontp->vertical_centering
-    = (STRINGP (Vvertical_centering_font_regexp)
-       && (fast_c_string_match_ignore_case
-	   (Vvertical_centering_font_regexp, fontname) >= 0));
-
+  fontp->charset = charset_id;
+  fontp->vertical_centering = 0;
   fontp->font_encoder = NULL;
 
-  if (find_ccl_program_func)
-    (*find_ccl_program_func) (fontp);
+  if (charset_id != charset_ascii)
+    {
+      fontp->vertical_centering
+	= (STRINGP (Vvertical_centering_font_regexp)
+	   && (fast_c_string_match_ignore_case
+	       (Vvertical_centering_font_regexp, fontname) >= 0));
+
+      if (find_ccl_program_func)
+	(*find_ccl_program_func) (fontp);
+    }
 
   return fontp;
 }
@@ -584,6 +838,34 @@
 #endif
 
 
+/* Return ENCODING or a cons(ENCODING REPERTORY) of the font FONTNAME.
+   ENCODING is a charset symbol that specifies the encoding of the
+   font.  REPERTORY is a charset symbol or nil.  */
+
+
+static Lisp_Object
+find_font_encoding (fontname)
+     char *fontname;
+{
+  Lisp_Object tail, elt;
+
+  for (tail = Vfont_encoding_alist; CONSP (tail); tail = XCDR (tail))
+    {
+      elt = XCAR (tail);
+      if (CONSP (elt)
+	  && STRINGP (XCAR (elt))
+	  && fast_c_string_match_ignore_case (XCAR (elt), fontname) >= 0
+	  && (SYMBOLP (XCDR (elt))
+	      ? CHARSETP (XCDR (elt))
+	      : 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;
+}
+
+
 /* Cache data used by fontset_pattern_regexp.  The car part is a
    pattern string containing at least one wild card, the cdr part is
    the corresponding regular expression.  */
@@ -738,7 +1020,7 @@
 	continue;
       name = XSTRING (FONTSET_NAME (fontset))->data;
 
-      if (!NILP (regexp)
+      if (STRINGP (regexp)
 	  ? (fast_c_string_match_ignore_case (regexp, name) < 0)
 	  : strcmp (XSTRING (pattern)->data, name))
 	continue;
@@ -811,84 +1093,183 @@
   return FONTSET_FROM_ID (id);
 }
 
-DEFUN ("set-fontset-font", Fset_fontset_font, Sset_fontset_font, 3, 4, 0,
-       doc: /* Modify fontset NAME to use FONT-SPEC for characters of CHARSETS.
+static void
+accumulate_script_ranges (arg, range, val)
+     Lisp_Object arg, range, val;
+{
+  if (EQ (XCAR (arg), val))
+    {
+      if (CONSP (range))
+	XSETCDR (arg, Fcons (Fcons (XCAR (range), XCDR (range)), XCDR (arg)));
+      else
+	XSETCDR (arg, Fcons (Fcons (range, range), XCDR (arg)));
+    }
+}
 
-CHARSET 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).
+
+DEFUN ("set-fontset-font", Fset_fontset_font, Sset_fontset_font, 3, 5, 0,
+       doc: /* 
+Modify fontset NAME to use FONT-SPEC for CHARACTER.
+
+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).
 
-FONT-SPEC is be a vector; [ FAMILY WEIGHT SLANT WIDTH ADSTYLE REGISTRY ]
+CHARACTER 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 who has :code-offset attribute and the
+attribute value is greater than the maximum Unicode character
+\(#x10FFFF).  In that case, use FONT-SPEC for all characters in the
+charset.
+
+FONT-SPEC is a vector; [ FAMILY WEIGHT SLANT ADSTYLE REGISTRY ].
+See the documentation of `set-face-attribute' for the detail of
+these vector elements.
 
-FONT-SPEC may be a cons; (FAMILY . REGISTRY), where FAMILY is a family
-name of a font, REGSITRY is a registry name of a font.
+FONT-SPEC may be a cons; (FAMILY . REGISTRY).
+
+FONT-SPEC may be a font name string.
+
+Optional 4th argument FRAME, if non-nil, is a frame.  This argument is
+kept for backward compatibility and has no meaning.
 
-FONT-SPEC may be a font name string.  */)
-     (name, charset, font_spec, frame)
-     Lisp_Object name, charset, font_spec, frame;
+Optional 5th argument ADD, if non-nil, specifies how to add FONT-SPEC
+to the font specifications for RANGE 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;
 {
   Lisp_Object fontset;
-  Lisp_Object family, registry;
+  int i;
+  Lisp_Object font_def, registry;
+  Lisp_Object val, encoding, repertory;
+  Lisp_Object range_list;
 
   fontset = check_fontset_name (name);
 
-  if (VECTORP (font_spec))
-    {
-      int i;
-      Lisp_Object val;
-
-      font_spec = Fcopy_sequence (font_spec);
-      for (i = 0; i < 5; i++)
-	{
-	  val = Faref (font_spec, make_number (i));
-	  if (! NILP (val))
-	    {
-	      CHECK_STRING (val);
-	      ASET (font_spec, i, Fdowncase (val));
-	    }
-	}
-      val = Faref (font_spec, make_number (5));
-      CHECK_STRING (val);
-      ASET (font_spec, 5, Fdowncase (val));
-    }
-  else if (STRINGP (font_spec))
-    font_spec = Fdowncase (font_spec);
-  else if (CONSP (font_spec))
-    {
-      CHECK_CONS (font_spec);
-      family = XCAR (font_spec);
-      registry = XCDR (font_spec);
-      font_spec = Fmake_vector (make_number (6), Qnil);
-      if (!NILP (family))
-	{
-	  CHECK_STRING (family);
-	  ASET (font_spec, 0, Fdowncase (family));
-	}
-      CHECK_STRING (registry);
-      ASET (font_spec, 5, Fdowncase (registry));
-    }
-
-  if (SYMBOLP (charset))
-    {
-      CHECK_CHARSET (charset);
-    }
-  else
-    {
-      Lisp_Object from, to;
-
-      /* CHARSET should be (FROM . TO).  */
-      from = Fcar (charset);
-      to = Fcdr (charset);
-      CHECK_CHARACTER (from);
-      CHECK_CHARACTER (to);
-    }
-
   /* The arg FRAME is kept for backward compatibility.  We only check
      the validity.  */
   if (!NILP (frame))
     CHECK_LIVE_FRAME (frame);
 
-  FONTSET_SET (fontset, charset, font_spec);
+  if (VECTORP (font_spec))
+    {
+      int j;
+
+      if (ASIZE (font_spec) != 6)
+	args_out_of_range (make_number (6),
+			   make_number (ASIZE (font_spec)));
+
+      font_spec = Fcopy_sequence (font_spec);
+      for (j = 0; j < 5; j++)
+	if (! NILP (AREF (font_spec, j)))
+	  {
+	    CHECK_STRING (AREF (font_spec, j));
+	    ASET (font_spec, j, Fdowncase (AREF (font_spec, j)));
+	  }
+      /* REGISTRY should not be omitted.  */
+      CHECK_STRING (AREF (font_spec, 5));
+      registry = Fdowncase (AREF (font_spec, 5));
+      ASET (font_spec, 5, registry);
+
+    }
+  else if (CONSP (font_spec))
+    {
+      Lisp_Object family;
+
+      family = XCAR (font_spec);
+      registry = XCDR (font_spec);
+
+      if (! NILP (family))
+	{
+	  CHECK_STRING (family);
+	  family = Fdowncase (family);
+	}
+      CHECK_STRING (registry);
+      registry = Fdowncase (registry);
+      font_spec = Fmake_vector (make_number (6), Qnil);
+      ASET (font_spec, 0, family);
+      ASET (font_spec, 5, registry);
+    }
+  else
+    {
+      CHECK_STRING (font_spec);
+      font_spec = Fdowncase (font_spec);
+      registry = font_name_registry (font_spec);
+      if (NILP (registry))
+	error ("No XLFD: %s", XSTRING (font_spec)->data);
+    }
+
+  if (STRINGP (font_spec))
+    encoding = find_font_encoding ((char *) XSTRING (font_spec)->data);
+  else
+    encoding = find_font_encoding ((char *) XSTRING (registry)->data);
+  if (SYMBOLP (encoding))
+    encoding = repertory = CHARSET_SYMBOL_ID (encoding);
+  else
+    {
+      repertory = XCDR (encoding);
+      encoding = CHARSET_SYMBOL_ID (XCAR (encoding));
+    }
+  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))
+    {
+      Lisp_Object from, to;
+
+      from = Fcar (character);
+      to = Fcdr (character);
+      CHECK_CHARACTER (from);
+      CHECK_CHARACTER (to);
+      range_list = Fcons (character, Qnil);
+    }
+  else
+    {
+      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)))
+	{
+	  val = Fcons (character, Qnil);
+	  map_char_table (accumulate_script_ranges, Qnil, Vchar_script_table,
+			  val, 0, NULL);
+	  range_list = XCDR (val); 
+	  if (EQ (character, Qascii))
+	    {
+	      if (! STRINGP (font_spec))
+		font_spec = generate_ascii_font_name (FONTSET_NAME (fontset),
+						      font_spec);
+	      FONTSET_ASCII (fontset) = font_spec;
+	    }
+	}
+      else if (CHARSETP (character))
+	{
+	  struct charset *charset;
+
+	  CHECK_CHARSET_GET_CHARSET (character, charset);
+	  if (CHARSET_METHOD (charset) == CHARSET_METHOD_OFFSET)
+	    range_list
+	      = Fcons (Fcons (make_number (CHARSET_MIN_CHAR (charset)),
+			      make_number (CHARSET_MAX_CHAR (charset))),
+		       range_list);
+	}
+
+      if (NILP (range_list))
+	error ("Invalid script or charset name: %s",
+	       XSYMBOL (character)->name->data);
+    }
+
+  for (; CONSP (range_list); range_list = XCDR (range_list))
+    FONTSET_ADD (fontset, XCAR (range_list), font_def, add);
 
   /* Free all realized fontsets whose base is FONTSET.  This way, the
      specified character(s) are surely redisplayed by a correct
@@ -902,51 +1283,50 @@
 DEFUN ("new-fontset", Fnew_fontset, Snew_fontset, 2, 2, 0,
        doc: /* Create a new fontset NAME from font information in FONTLIST.
 
-FONTLIST is an alist of charsets vs corresponding font specifications.
-Each element of FONTLIST has the form (CHARSET . FONT-SPEC), where
-a character of CHARSET is displayed by a font that matches FONT-SPEC.
+FONTLIST is an alist of scripts vs the corresponding font specification list.
+Each element of FONTLIST has the form (SCRIPT FONT-SPEC ...), where
+a character of SCRIPT is displayed by a font that matches FONT-SPEC.
 
-FONT-SPEC is a vector [ FAMILY WEIGHT SLANT WIDTH ADSTYLE REGISTRY ], where
-FAMILY is a string specifying the font family,
-WEIGHT is a string specifying the weight of the font,
-SLANT is a string specifying the slant of the font,
-WIDTH is a string specifying the width of the font,
-ADSTYLE is a string specifying the adstyle of the font,
-REGISTRY is a string specifying the charset-registry of the font.
+SCRIPT is a symbol that appears in the variable `script-alist'.
 
-See also the documentation of `set-face-attribute' for the detail of
-these vector elements.
-
-FONT-SPEC may be a font name (string).  */)
+FONT-SPEC is a vector, a cons, or a string.  See the documentation of
+`set-fontset-font' for the meaning.  */)
   (name, fontlist)
      Lisp_Object name, fontlist;
 {
-  Lisp_Object fontset, ascii_font;
-  Lisp_Object tem, tail;
+  Lisp_Object fontset;
+  Lisp_Object val;
+  int id;
 
   CHECK_STRING (name);
   CHECK_LIST (fontlist);
 
-  name = Fdowncase (name);
-  tem = Fquery_fontset (name, Qnil);
-  if (! NILP (tem))
-    free_realized_fontsets (tem);
-
-  fontset = make_fontset (Qnil, name, Qnil);
+  /* Check if an ASCII font is specified in FONTLIST.  */
+  val = Fcar (Fcdr (Fassq (Qascii, fontlist)));
+  if (NILP (val))
+    error ("No ascii font specified");
 
-  /* Check the validity of FONTLIST.  */
-  ascii_font = Fcdr (Fassq (Qascii, fontlist));
-  if (NILP (ascii_font))
-    error ("No ascii font specified");
-  if (! STRINGP (ascii_font))
-    ascii_font = generate_ascii_font (name, ascii_font);
+  id = fs_query_fontset (name, 0);
+  if (id < 0)
+    fontset = make_fontset (Qnil, Fdowncase (name), Qnil);
+  else
+    {
+      fontset = FONTSET_FROM_ID (id);;
+      free_realized_fontsets (fontset);
+      Fset_char_table_range (fontset, Qt, Qnil);
+    }
 
-  fontlist = Fcopy_sequence (fontlist);
-  for (tail = fontlist; ! NILP (tail); tail = Fcdr (tail))
-    Fset_fontset_font (name, Fcar (Fcar (tail)), Fcdr (Fcar (tail)), Qnil);
+  for (; ! NILP (fontlist); fontlist = Fcdr (fontlist))
+    {
+      Lisp_Object elt, script;
 
-  FONTSET_ASCII (fontset) = ascii_font;
-
+      elt = Fcar (fontlist);
+      script = Fcar (elt);
+      elt = Fcdr (elt);
+      Fset_fontset_font (name, script, Fcar (elt), Qnil, Qnil);
+      for (elt = Fcdr (elt); ! NILP (elt); elt = Fcdr (elt))
+	Fset_fontset_font (name, script, XCAR (elt), Qnil, Qappend);
+    }
   return name;
 }
 
@@ -1051,170 +1431,108 @@
 }
 
 
-#if 0				/* unused */
-/* Called from Ffontset_info via map_char_table on each leaf of
-   fontset.  ARG is a list (LAST FONT-INFO ...), where LAST is `(last
-   ARG)' and FONT-INFOs have this form:
-	(CHAR FONT-SPEC) or ((FROM . TO) FONT-SPEC)
-   The current leaf is indexed by CHARACTER and has value ELT.  This
-   function add the information of the current leaf to ARG by
-   appending a new element or modifying the last element..  */
+DEFUN ("fontset-info", Ffontset_info, Sfontset_info, 1, 2, 0,
+       doc: /* Return information about a fontset FONTSET on frame FRAME.
+The value is a char-table of which elements has this form.
 
-static void
-accumulate_font_info (arg, character, elt)
-     Lisp_Object arg, character, elt;
-{
-  Lisp_Object last, last_char, last_elt;
+    ((FONT-PATTERN OPENED-FONT ...) ...)
 
-  if (!CONSP (elt) && !SINGLE_BYTE_CHAR_P (XINT (character)))
-    FONTSET_REF (Vdefault_fontset, XINT (character), elt);
-  if (!CONSP (elt))
-    return;
-  last = XCAR (arg);
-  last_char = XCAR (XCAR (last));
-  last_elt = XCAR (XCDR (XCAR (last)));
-  elt = XCDR (elt);
-  if (!NILP (Fequal (elt, last_elt)))
-    {
-      struct charset *this_charset = CHAR_CHARSET (XINT (character));
+FONT-PATTERN is a vector:
 
-      if (CONSP (last_char))	/* LAST_CHAR == (FROM . TO)  */
-	{
-	  if (this_charset == CHAR_CHARSET (XINT (XCAR (last_char))))
-	    {
-	      XSETCDR (last_char, character);
-	      return;
-	    }
-	}
-      else if (XINT (last_char) == XINT (character))
-	return;
-      else if (this_charset == CHAR_CHARSET (XINT (last_char)))
-	{
-	  XSETCAR (XCAR (last), Fcons (last_char, character));
-	  return;
-	}
-    }
-  XSETCDR (last, Fcons (Fcons (character, Fcons (elt, Qnil)), Qnil));
-  XSETCAR (arg, XCDR (last));
-}
-#endif /* 0 */
+	[ FAMILY WEIGHT SLANT SWIDTH ADSTYLE REGISTRY ]
+
+or a string of font name pattern.
 
-DEFUN ("fontset-info", Ffontset_info, Sfontset_info, 1, 2, 0,
-       doc: /* Return information about a fontset named NAME on frame FRAME.
-The value is a vector:
-  [ SIZE HEIGHT ((CHARSET-OR-RANGE FONT-SPEC OPENED ...) ...) ],
-where,
-  SIZE is the maximum bound width of ASCII font in the fontset,
-  HEIGHT is the maximum bound height of ASCII font in the fontset,
-  CHARSET-OR-RANGE is a charset or a cons of two characters specifying
-    the range of characters.
-  FONT-SPEC is a fontname pattern string or a vector
-    [ FAMILY WEIGHT SLANT WIDTH ADSTYLE REGISTRY ].
-    See the documentation of `new-fontset' for the meanings those elements.
-  OPENEDs are names of fonts actually opened.
-If the ASCII font is not yet opened, SIZE and HEIGHT are 0.
-If FRAME is omitted, it defaults to the currently selected frame.  */)
-     (name, frame)
-     Lisp_Object name, frame;
+OPENED-FONT is a name of a font actually opened.  */)
+     (fontset, frame)
+     Lisp_Object fontset, frame;
 {
-  Lisp_Object fontset;
   FRAME_PTR f;
-  Lisp_Object val, tail, elt;
+  Lisp_Object table, val, elt;
   Lisp_Object *realized;
   struct font_info *fontp = NULL;
   int n_realized = 0;
-  int i;
+  int c, i, j;
 
   (*check_window_system_func) ();
 
-  fontset = check_fontset_name (name);
+  fontset = check_fontset_name (fontset);
 
   if (NILP (frame))
     frame = selected_frame;
   CHECK_LIVE_FRAME (frame);
   f = XFRAME (frame);
 
-  /* Recode realized fontsets whose base is FONTSET in the table
-     `realized'.  */
+  /* 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++)
     {
       elt = FONTSET_FROM_ID (i);
       if (!NILP (elt)
-	  && EQ (FONTSET_BASE (elt), fontset))
+	  && EQ (FONTSET_BASE (elt), fontset)
+	  && EQ (FONTSET_FRAME (elt), frame))
 	realized[n_realized++] = elt;
     }
 
-  /* Accumulate information of the fontset in VAL.  The format is
-     (LAST FONT-INFO FONT-INFO ...), where FONT-INFO is (CHAR-OR-RANGE
-     FONT-SPEC).  See the comment for accumulate_font_info for the
-     detail.  */
-  val = Fcons (Fcons (Qascii, Fcons (FONTSET_ASCII (fontset), Qnil)), Qnil);
-  val = Fcons (val, val);
-  for (i = 128; i <= MAX_CHAR; )
+
+  table = Fmake_char_table (Qnil, Qnil);
+  /* Accumulate information of the fontset in TABLE.  The format of
+     each element is ((FONT-SPEC OPENED-FONT ...) ...).  */
+  for (c = 0; c <= MAX_CHAR; )
     {
-      Lisp_Object elt;
       int from, to;
 
-      elt = char_table_ref_and_range (fontset, i, &from, &to);
-      if (! NILP (elt))
+      val = FONTSET_REF_AND_RANGE (fontset, c, from, to);
+      if (VECTORP (val))
 	{
-	  elt = Fcons (Fcons (make_number (from), make_number (to)),
-		       Fcons (elt, Qnil));
-	  XSETCDR (XCAR (val), Fcons (elt, Qnil));
-	  XSETCAR (val, XCDR (XCAR (val)));
-	}
-      i = to + 1;
-    }
+	  Lisp_Object alist;
+
+	  /* 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);
+	  alist = Fnreverse (alist);
 
-  for (tail = FONTSET_CHARSET_ALIST (fontset);
-       CONSP (tail); tail = XCDR (tail))
-    {
-      elt = XCAR (tail);
-      elt = Fcons ((INTEGERP (XCAR (elt))
-		    ? CHARSET_NAME (CHARSET_FROM_ID (XFASTINT (XCAR (elt))))
-		    : XCAR (elt)),
-		   Fcons (XCDR (elt), Qnil));
-      XSETCDR (XCAR (val), Fcons (elt, Qnil));
-      XSETCAR (val, XCDR (XCAR (val)));
+	  /* Then store opend font names to cdr of each elements.  */
+	  for (i = 0; i < n_realized; i++)
+	    {
+	      val = FONTSET_REF (realized[i], c);
+	      if (NILP (val))
+		continue;
+	      val = XCDR (val);
+	      /* Now VAL is [[FACE-ID FONT-INDEX FONT-DEF] ...].
+		 If a font of an element is already opened,
+		 FONT-INDEX of the element is integer.  */
+	      for (j = 0; j < ASIZE (val); j++)
+		if (INTEGERP (AREF (AREF (val, j), 0)))
+		  {
+		    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));
+	      }
+
+	  /* Store ALIST in TABLE for characters C..TO.  */
+	  char_table_set_range (table, c, to, alist);
+	}
+      c = to + 1;
     }
 
-  val = XCDR (val);
-
-  /* If fonts are opened for FONT-SPEC, append the names of the fonts to
-     FONT-SPEC.  */
-  for (tail = val; CONSP (tail); tail = XCDR (tail))
-    {
-      elt = XCAR (tail);
-      for (i = 0; i < n_realized; i++)
-	{
-	  Lisp_Object face_list, fontname;
-
-	  for (face_list = FONTSET_FACE_ALIST (realized[i]);
-	       CONSP (face_list); face_list = XCDR (face_list))
-	    {
-	      int face_id = XINT (XCDR (XCAR (face_list)));
-	      struct face *face = FACE_FROM_ID (f, face_id);
+  return table;
+}
 
-	      if (face->font && face->font_name)
-		{
-		  fontname = build_string (face->font_name);
-		  if (NILP (Fmember (fontname, XCDR (XCDR (elt)))))
-		    XSETCDR (XCDR (elt), Fcons (fontname, XCDR (XCDR (elt))));
-		}
-	    }
-	}
-    }
-
-  elt = XCDR (XCDR (XCAR (val)));
-  if (CONSP (elt))
-    fontp = (*query_font_func) (f, XSTRING (XCAR (elt))->data);
-  val = Fmake_vector (make_number (3), val);
-  AREF (val, 0) = fontp ? make_number (fontp->size) : make_number (0);
-  AREF (val, 1) = fontp ? make_number (fontp->height) : make_number (0);
-  return val;
-}
 
 DEFUN ("fontset-font", Ffontset_font, Sfontset_font, 2, 2, 0,
        doc: /* Return a font name pattern for character CH in fontset NAME.
@@ -1229,8 +1547,8 @@
 
   CHECK_CHARACTER (ch);
   c = XINT (ch);
-  FONTSET_REF (fontset, c, elt);
-  return elt;
+  elt = FONTSET_REF (fontset, c);
+  return Fcopy_sequence (elt);
 }
 
 DEFUN ("fontset-list", Ffontset_list, Sfontset_list, 0, 0, 0,
@@ -1259,10 +1577,12 @@
     /* Window system initializer should have set proper functions.  */
     abort ();
 
-  Qfontset = intern ("fontset");
-  staticpro (&Qfontset);
+  DEFSYM (Qfontset, "fontset");
   Fput (Qfontset, Qchar_table_extra_slots, make_number (7));
 
+  DEFSYM (Qprepend, "prepend");
+  DEFSYM (Qappend, "append");
+
   Vcached_fontset_data = Qnil;
   staticpro (&Vcached_fontset_data);
 
@@ -1293,13 +1613,27 @@
   next_fontset_id = 1;
 
   DEFVAR_LISP ("font-encoding-alist", &Vfont_encoding_alist,
-	       doc: /* Alist of fontname patterns vs corresponding encoding info.
-Each element looks like (REGEXP . CHARSET), where CHARSET is an
-Emacs charset symbol.  */);
+	       doc: /*
+Alist of fontname patterns vs the corresponding encoding and repertory info.
+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.  
+
+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
+the table by a character gives the corresponding glyph code.
+
+REPERTORY specifies a repertory of characters supported by the font.
+If REPERTORY is a charset, all characters beloging to the charset are
+supported.  If REPERTORY is a char-table, all characters who have a
+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 ("use-default-ascent", &Vuse_default_ascent,
-	       doc: /* Char table of characters whose ascent values should be ignored.
+	       doc: /*
+Char table of characters whose ascent values should be ignored.
 If an entry for a character is non-nil, the ascent value of the glyph
 is assumed to be what specified by _MULE_DEFAULT_ASCENT property of a font.
 
@@ -1308,7 +1642,8 @@
   Vuse_default_ascent = Qnil;
 
   DEFVAR_LISP ("ignore-relative-composition", &Vignore_relative_composition,
-	       doc: /* Char table of characters which is not composed relatively.
+	       doc: /*
+Char table of characters which is not composed relatively.
 If an entry for a character is non-nil, a composition sequence
 which contains that character is displayed so that
 the glyph of that character is put without considering