*** empty log message ***
[m17n/m17n-lib.git] / src / m17n-X.c
index 5fdba28..f9ce59f 100644 (file)
@@ -1,5 +1,5 @@
 /* m17n-X.c -- implementation of the GUI API on X Windows.
 /* m17n-X.c -- implementation of the GUI API on X Windows.
-   Copyright (C) 2003, 2004
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H15PRO112
 
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
 
    You should have received a copy of the GNU Lesser General Public
    License along with the m17n library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    02111-1307, USA.  */
 
    02111-1307, USA.  */
 
+#include "config.h"
+
+#ifdef HAVE_X11
+
 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
 /*** @addtogroup m17nInternal
      @{ */
 
 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
 /*** @addtogroup m17nInternal
      @{ */
 
-#include "config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -43,6 +45,7 @@
 
 #ifdef HAVE_XFT2
 #include <X11/Xft/Xft.h>
 
 #ifdef HAVE_XFT2
 #include <X11/Xft/Xft.h>
+#include <fontconfig/fcfreetype.h>
 #endif /* HAVE_XFT2 */
 
 #include "m17n-gui.h"
 #endif /* HAVE_XFT2 */
 
 #include "m17n-gui.h"
 #include "fontset.h"
 #include "face.h"
 
 #include "fontset.h"
 #include "face.h"
 
-typedef struct {
-  MFont core;
-  /* Nth bit tells the existence of a font of size (N+1).
-     core.property[MFONT_SIZE] holds the smallest size.  */
-  unsigned int sizes;
-  /* If sizes is not 0, smallest and largest sizes.  */
-  unsigned short smallest, largest;
-} MXFont;
-
-/* S must satisfy the condition (S > 0 && S <= 32).  */
-#define SET_SIZE(sizes, s) ((sizes) |= (1 << ((s) - 1)))
-#define HAVE_SIZE(sizes, s) ((sizes) & (1 << ((s) - 1)))
-
-typedef struct {
-  int size, inc, used;
-  MXFont *fonts;
-} MXFontList;
-
 typedef struct
 {
   /* Common header for the m17n object.  */
 typedef struct
 {
   /* Common header for the m17n object.  */
@@ -87,14 +72,9 @@ typedef struct
 
   /** List of available X-core fonts on the display.  Keys are
       registries and values are plists whose keys are families and
 
   /** List of available X-core fonts on the display.  Keys are
       registries and values are plists whose keys are families and
-      values are pointers to MXFontList.  */
+      values are pointers to MFont.  */
   MPlist *font_list;
 
   MPlist *font_list;
 
-  /** List of available X-core fonts on the display.  Keys are
-      families and values are pointers to MFont.  For each MFont, only
-      these properties are important; FOUNDRY, FAMILY, REGISTRY.  */
-  MPlist *base_font_list;
-
   /** Nonzero means that <font_list> already contains all available
       fonts on the display.  */
   int all_fonts_scaned;
   /** Nonzero means that <font_list> already contains all available
       fonts on the display.  */
   int all_fonts_scaned;
@@ -104,6 +84,9 @@ typedef struct
   int alt_mask;
   int super_mask;
   int hyper_mask;
   int alt_mask;
   int super_mask;
   int hyper_mask;
+
+  Atom MULE_BASELINE_OFFSET;
+  Atom AVERAGE_WIDTH;
 } MDisplayInfo;
 
 /* Anchor of the chain of MDisplayInfo objects.  */
 } MDisplayInfo;
 
 /* Anchor of the chain of MDisplayInfo objects.  */
@@ -158,6 +141,8 @@ typedef struct
 
   GC scratch_gc;
 
 
   GC scratch_gc;
 
+  int resy;
+
 #ifdef HAVE_XFT2
   XftDraw *xft_draw;
 #endif
 #ifdef HAVE_XFT2
   XftDraw *xft_draw;
 #endif
@@ -165,8 +150,8 @@ typedef struct
   /** List of pointers to realized faces on the frame.  */
   MPlist *realized_face_list;
 
   /** List of pointers to realized faces on the frame.  */
   MPlist *realized_face_list;
 
-  /* List of information about each font.  Keys are font registries,
-     values are (MFontInfo *).  */
+  /* List of single element whose value is a root of chain of realized
+     fonts.  */
   MPlist *realized_font_list;
 
   /** List of pointers to realized fontsets on the frame.  */
   MPlist *realized_font_list;
 
   /** List of pointers to realized fontsets on the frame.  */
@@ -187,8 +172,7 @@ static MSymbol M_iso8859_1, M_iso10646_1;
 #define FRAME_VISUAL(frame) DefaultVisual (FRAME_DISPLAY (frame), \
                                           FRAME_SCREEN (frame))
 
 #define FRAME_VISUAL(frame) DefaultVisual (FRAME_DISPLAY (frame), \
                                           FRAME_SCREEN (frame))
 
-#define DEFAULT_FONT "-misc-fixed-medium-r-normal--*-120-*-*-*-*-iso8859-1"
-#define FALLBACK_FONT "-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1"
+#define DEFAULT_FONT "-*-*-medium-r-normal--13-*-*-*-c-*-iso8859-1"
 
 typedef struct
 {
 
 typedef struct
 {
@@ -202,18 +186,15 @@ static void
 free_display_info (void *object)
 {
   MDisplayInfo *disp_info = (MDisplayInfo *) object;
 free_display_info (void *object)
 {
   MDisplayInfo *disp_info = (MDisplayInfo *) object;
-  MPlist *plist, *p;
+  MPlist *plist, *pl;
 
   MPLIST_DO (plist, disp_info->font_list)
     {
 
   MPLIST_DO (plist, disp_info->font_list)
     {
-      MPLIST_DO (p, MPLIST_VAL (plist))
-       free (MPLIST_VAL (p));
+      MPLIST_DO (pl, MPLIST_VAL (plist))
+       free (MPLIST_VAL (pl));
       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
     }
   M17N_OBJECT_UNREF (disp_info->font_list);
       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
     }
   M17N_OBJECT_UNREF (disp_info->font_list);
-  MPLIST_DO (plist, disp_info->base_font_list)
-    free (MPLIST_VAL (plist));
-  M17N_OBJECT_UNREF (disp_info->base_font_list);
 
   if (disp_info->auto_display)
     XCloseDisplay (disp_info->display);
 
   if (disp_info->auto_display)
     XCloseDisplay (disp_info->display);
@@ -232,8 +213,8 @@ free_device (void *object)
     mfont__free_realized_fontset ((MRealizedFontset *) mplist_value (plist));
   M17N_OBJECT_UNREF (device->realized_fontset_list);
 
     mfont__free_realized_fontset ((MRealizedFontset *) mplist_value (plist));
   M17N_OBJECT_UNREF (device->realized_fontset_list);
 
-  MPLIST_DO (plist, device->realized_font_list)
-    mfont__free_realized ((MRealizedFont *) MPLIST_VAL (plist));
+  if (MPLIST_VAL (device->realized_font_list))
+    mfont__free_realized (MPLIST_VAL (device->realized_font_list));
   M17N_OBJECT_UNREF (device->realized_font_list);
 
   MPLIST_DO (plist, device->realized_face_list)
   M17N_OBJECT_UNREF (device->realized_font_list);
 
   MPLIST_DO (plist, device->realized_face_list)
@@ -426,19 +407,22 @@ set_region (MFrame *frame, GC gc, MDrawRegion region)
 \f
 /** X font handler */
 
 \f
 /** X font handler */
 
-static MRealizedFont *xfont_select (MFrame *, MFont *, MFont *, int);
-static int xfont_open (MRealizedFont *);
+static MFont *xfont_select (MFrame *, MFont *, int);
+static MRealizedFont *xfont_open (MFrame *, MFont *, MFont *, MRealizedFont *);
 static void xfont_find_metric (MRealizedFont *, MGlyphString *, int, int);
 static void xfont_find_metric (MRealizedFont *, MGlyphString *, int, int);
-static unsigned xfont_encode_char (MRealizedFont *, unsigned);
+static int xfont_has_char (MFrame *, MFont *, MFont *, int, unsigned);
+static unsigned xfont_encode_char (MFrame *, MFont *, MFont *, unsigned);
 static void xfont_render (MDrawWindow, int, int, MGlyphString *,
                          MGlyph *, MGlyph *, int, MDrawRegion);
 static void xfont_render (MDrawWindow, int, int, MGlyphString *,
                          MGlyph *, MGlyph *, int, MDrawRegion);
-static int xfont_list (MFrame *frame, MPlist *plist,
-                       MFont *font, MSymbol language, int maxnum);
-
+static int xfont_list (MFrame *, MPlist *, MFont *, int);
+static void xfont_list_family_names (MFrame *, MPlist *);
+static int xfont_check_capability (MRealizedFont *rfont, MSymbol capability);
 
 static MFontDriver xfont_driver =
   { xfont_select, xfont_open,
 
 static MFontDriver xfont_driver =
   { xfont_select, xfont_open,
-    xfont_find_metric, xfont_encode_char, xfont_render, xfont_list };
+    xfont_find_metric, xfont_has_char, xfont_encode_char,
+    xfont_render, xfont_list, xfont_list_family_names, xfont_check_capability
+  };
 
 static int
 font_compare (const void *p1, const void *p2)
 
 static int
 font_compare (const void *p1, const void *p2)
@@ -451,55 +435,49 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
 {
   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
   MPlist *font_list = disp_info->font_list;
 {
   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
   MPlist *font_list = disp_info->font_list;
-  MPlist *base_font_list = disp_info->base_font_list;
   MPlist *plist, *p;
   char pattern[1024];
   char **font_names, **names;
   int nfonts;
   int i, j;
   MPlist *plist, *p;
   char pattern[1024];
   char **font_names, **names;
   int nfonts;
   int i, j;
-  MXFont font;
-  MFont *bfont = NULL;
+  MFont font;
+  int for_full_width;
 
   plist = mplist_get (font_list, registry);
   if (plist)
     return plist;
 
   plist = mplist_get (font_list, registry);
   if (plist)
     return plist;
-  plist = mplist ();
+  p = plist = mplist ();
   mplist_add (font_list, registry, plist);
   sprintf (pattern, "-*-*-*-*-*-*-*-*-*-*-*-*-%s", msymbol_name (registry));
   font_names = XListFonts (disp_info->display, pattern, 0x8000, &nfonts);
   if (nfonts == 0)
     return plist;
   mplist_add (font_list, registry, plist);
   sprintf (pattern, "-*-*-*-*-*-*-*-*-*-*-*-*-%s", msymbol_name (registry));
   font_names = XListFonts (disp_info->display, pattern, 0x8000, &nfonts);
   if (nfonts == 0)
     return plist;
+  {
+    char *reg_name = msymbol_name (registry);
+
+    for_full_width = (strncmp (reg_name, "jis", 3) == 0
+                     || strncmp (reg_name, "gb", 2) == 0
+                     || strncmp (reg_name, "big5", 4) == 0
+                     || strncmp (reg_name, "ksc", 3) == 0);
+  }
   names = alloca (sizeof (char *) * nfonts);
   memcpy (names, font_names, sizeof (char *) * nfonts);
   qsort (names, nfonts, sizeof (char *), font_compare);
   names = alloca (sizeof (char *) * nfonts);
   memcpy (names, font_names, sizeof (char *) * nfonts);
   qsort (names, nfonts, sizeof (char *), font_compare);
-  for (i = 0, p = NULL; i < nfonts; i++)
-    if (mfont__parse_name_into_font (names[i], Mx, (MFont *) &font) == 0
-       && (font.core.property[MFONT_SIZE] > 0
-           || font.core.property[MFONT_RESY] == 0))
+  MFONT_INIT (&font);
+  for (i = 0; i < nfonts; i++)
+    if (mfont__parse_name_into_font (names[i], Mx, &font) == 0
+       && (font.size > 0 || font.property[MFONT_RESY] == 0))
       {
       {
-       MSymbol family = FONT_PROPERTY ((MFont *) &font, MFONT_FAMILY);
-       MXFontList *xfont_table;
-       int sizes[256];
-       int sizes_idx = 0;
-       int size, smallest, largest;
-       int have_scalable;
-       unsigned int size_bits = 0;
+       MSymbol family = FONT_PROPERTY (&font, MFONT_FAMILY);
+       MFont *fontx;
+       unsigned sizes[256];
+       int nsizes = 0;
+       int limit;
+       int size, normal_size;
        char *base_end;
        int base_len;
        int fields;
        
        char *base_end;
        int base_len;
        int fields;
        
-       if (p && MPLIST_KEY (p) != family)
-         p = mplist_find_by_key (plist, family);
-       if (p)
-         xfont_table = MPLIST_VAL (p);
-       else
-         {
-           p = plist;
-           MSTRUCT_MALLOC (xfont_table, MERROR_WIN);
-           MLIST_INIT1 (xfont_table, fonts, 4);
-           mplist_push (p, family, xfont_table);
-         }
-
        /* Calculate how many bytes to compare to detect fonts of the
           same base name.  */
        for (base_end = names[i], fields = 0; *base_end; base_end++)
        /* Calculate how many bytes to compare to detect fonts of the
           same base name.  */
        for (base_end = names[i], fields = 0; *base_end; base_end++)
@@ -508,70 +486,45 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
            break;
        base_len = base_end - names[i] + 1;
 
            break;
        base_len = base_end - names[i] + 1;
 
-       size = font.core.property[MFONT_SIZE] / 10;
-       have_scalable = size == 0;
-       sizes[sizes_idx++] = size;
-       for (j = i + 1; j < nfonts && ! strncmp (names[i], names[j], base_len);
+       size = font.size / 10;
+       sizes[nsizes++] = size;
+       normal_size = (size >= 6 && size <= 29);
+       limit = (i + 256 < nfonts ? i + 256 : nfonts);
+       for (j = i + 1; j < limit && ! memcmp (names[i], names[j], base_len);
             i = j++)
             i = j++)
-         if (mfont__parse_name_into_font (names[j], Mx, (MFont *) &font) == 0
-             && (font.core.property[MFONT_SIZE] > 0
-                 || font.core.property[MFONT_RESY] == 0))
+         if (mfont__parse_name_into_font (names[j], Mx, &font) == 0
+             && (font.size > 0 || font.property[MFONT_RESY] == 0))
            {
            {
-             int k;
-
-             size = font.core.property[MFONT_SIZE] / 10;
-             if (! have_scalable)
-               have_scalable = size == 0;              
-             for (k = 0; k < sizes_idx && sizes[k] != size; k++);
-             if (k == sizes_idx && sizes_idx < 256)
-               sizes[sizes_idx++] = size;
+             size = font.size / 10;
+             sizes[nsizes++] = size;
+             normal_size |= (size >= 6 && size <= 29);
            }
 
            }
 
-       for (j = 0, smallest = 0; j < sizes_idx; j++)
+       font.for_full_width = for_full_width;
+       font.type = MFONT_TYPE_OBJECT;
+       font.source = MFONT_SOURCE_X;
+       if (normal_size)
          {
          {
-           size = sizes[j];
-           if (size <= 32)
-             {
-               if (size != 0)
-                 {
-                   if (smallest == 0)
-                     smallest = largest = size;
-                   else if (size < smallest)
-                     smallest = size;
-                   else if (size > largest)
-                     largest = size;
-                   SET_SIZE (size_bits, size);
-                 }
-             }
-           else
-             {
-               font.core.property[MFONT_SIZE] = size * 10;
-               font.sizes = 0;
-               MLIST_APPEND1 (xfont_table, fonts, font, MERROR_WIN);
-             }
-         }
-
-       if (size_bits || have_scalable == 1)
-         {
-           font.sizes = size_bits;
-           font.smallest = smallest;
-           font.largest = largest;
-           font.core.property[MFONT_SIZE] = have_scalable ? 0 : smallest * 10;
-           MLIST_APPEND1 (xfont_table, fonts, font, MERROR_WIN);
-         }
-       if (! bfont
-           || (font.core.property[MFONT_FOUNDRY]
-               != bfont->property[MFONT_FOUNDRY])
-           || (font.core.property[MFONT_FAMILY]
-               != bfont->property[MFONT_FAMILY]))
-         {
-           MSTRUCT_MALLOC (bfont, MERROR_WIN);
-           *bfont = font.core;
-           for (j = MFONT_WEIGHT; j <= MFONT_ADSTYLE; j++)
-             bfont->property[j] = 0;
-           bfont->property[MFONT_SIZE] = bfont->property[MFONT_RESY] = 0;
-           mplist_push (base_font_list, family, bfont);
+           MSTRUCT_CALLOC (fontx, MERROR_WIN);
+           *fontx = font;
+           fontx->multiple_sizes = 1;
+           fontx->size = 0;
+           for (j = 0; j < nsizes; j++)
+             if (sizes[j] >= 6 && sizes[j] <= 29)
+               fontx->size |= 1 << (sizes[j] - 6);
+           p = mplist_add (p, family, fontx);
          }
          }
+       for (j = 0; j < nsizes; j++)
+         if (sizes[j] < 6 || sizes[j] > 29)
+           {
+             MSTRUCT_CALLOC (fontx, MERROR_WIN);
+             *fontx = font;
+             fontx->multiple_sizes = 0;
+             fontx->size = sizes[j] * 10;
+             if (sizes[j] == 0)
+               fontx->property[MFONT_RESY] = 0;
+             p = mplist_add (p, family, fontx);
+           }
       }
   XFreeFontNames (font_names);
   return plist;
       }
   XFreeFontNames (font_names);
   return plist;
@@ -593,153 +546,150 @@ xfont_list_all (MFrame *frame)
     xfont_registry_list (frame, MPLIST_KEY (p));
 }
 
     xfont_registry_list (frame, MPLIST_KEY (p));
 }
 
-
 typedef struct
 {
   M17NObject control;
   Display *display;
   XFontStruct *xfont;
 typedef struct
 {
   M17NObject control;
   Display *display;
   XFontStruct *xfont;
-} MXFontInfo;
+} MRealizedFontX;
 
 /* The X font driver function SELECT.  */
 
 
 /* The X font driver function SELECT.  */
 
-static MRealizedFont *
-xfont_select (MFrame *frame, MFont *spec, MFont *request, int limited_size)
+static MFont *
+xfont_select (MFrame *frame, MFont *font, int limited_size)
 {
 {
-  MSymbol family = FONT_PROPERTY (spec, MFONT_FAMILY);
-  MSymbol registry = FONT_PROPERTY (spec, MFONT_REGISTRY);
-  int requested_size = request->property[MFONT_SIZE] / 10;
-  MRealizedFont *rfont;
-  MPlist *plist;
-  int i;
-  MFont *best_font;
-  int best_size, best_score, score;
-
-  if (registry == Mnil
-      || ! strchr (MSYMBOL_NAME (registry), '-'))
-    return NULL;
+  MPlist *plist = mplist (), *pl;
+  int num = xfont_list (frame, plist, font, 0);
+  MFont *found = NULL;
 
 
-  plist = xfont_registry_list (frame, registry);
-  if (MPLIST_TAIL_P (plist))
-    return NULL;
-  best_score = -1, best_font = NULL;
-  MPLIST_DO (plist, plist)
-    {
-      if (family == Mnil || family == MPLIST_KEY (plist))
-       {
-         MXFontList *xfont_table = MPLIST_VAL (plist);
-
-         for (i = 0; i < xfont_table->used; i++)
-           {
-             MXFont *xfont = xfont_table->fonts + i;
-             MFont *font = (MFont *) xfont;
-             unsigned int sizes = xfont->sizes;
-             int orig_size = font->property[MFONT_SIZE];
-             int size;
-
-             if (sizes == 0)
-               size = orig_size / 10;
-             else if (requested_size < xfont->smallest)
-               size = orig_size == 0 ? 0 : xfont->smallest;
-             else if (requested_size > xfont->largest)
-               size = orig_size == 0 ? 0 : xfont->largest;
-             else if (HAVE_SIZE (sizes, requested_size))
-               size = requested_size;
-             else if (orig_size == 0)
-               size = 0;
-             else
-               {
-                 for (size = requested_size - 1;
-                      size > xfont->smallest && ! HAVE_SIZE (sizes, size);
-                      size--);
-                 if (! limited_size)
-                   {
-                     int s;
-                     for (s = requested_size;
-                          s < xfont->largest && ! HAVE_SIZE (sizes, s);
-                          s++);
-                     if (s - requested_size < requested_size - size)
-                       size = s;
-                   }
-               }
-             font->property[MFONT_SIZE] = size * 10;
-             score = mfont__score (font, spec, request, limited_size);
-             font->property[MFONT_SIZE] = orig_size;
-             if (score >= 0 && (best_score < 0 || score < best_score))
-               {
-                 best_size = size * 10;
-                 best_score = score;
-                 best_font = (MFont *) (xfont_table->fonts + i);
-                 if (best_score == 0)
-                   break;
-               }
-           }
-         if (best_score == 0)
+  if (num > 0)
+    MPLIST_DO (pl, plist)
+      {
+       font = MPLIST_VAL (pl);
+       if (limited_size == 0
+           || font->size == 0
+           || font->size <= limited_size)
+         {
+           found = font;
            break;
            break;
-       }
-    }
-  if (! best_font)
-    return NULL;
-
-  MSTRUCT_CALLOC (rfont, MERROR_WIN);
-  rfont->frame = frame;
-  rfont->spec = *spec;
-  rfont->request = *request;
-  rfont->font = *best_font;
-  if (best_size == 0)
-    rfont->font.property[MFONT_SIZE] = request->property[MFONT_SIZE];
-  else
-    rfont->font.property[MFONT_SIZE] = best_size;
-  rfont->score = best_score;
-  return rfont;
+         }
+      }
+  M17N_OBJECT_UNREF (plist);
+  return found;
 }
 
 }
 
-
 /* The X font driver function CLOSE.  */
 
 static void
 close_xfont (void *object)
 {
 /* The X font driver function CLOSE.  */
 
 static void
 close_xfont (void *object)
 {
-  MXFontInfo *xfont_info = object;
+  MRealizedFontX *x_rfont = object;
 
 
-  XFreeFont (xfont_info->display, xfont_info->xfont);
-  free (object);
+  XFreeFont (x_rfont->display, x_rfont->xfont);
+  free (x_rfont);
 }
 
 }
 
-
 /* The X font driver function OPEN.  */
 
 /* The X font driver function OPEN.  */
 
-static int
-xfont_open (MRealizedFont *rfont)
+static MRealizedFont *
+xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
 {
 {
+  int size;
+  MRealizedFontX *x_rfont;
   char *name;
   char *name;
-  MXFontInfo *xfont_info;
-  MFrame *frame = rfont->frame;
-  int mdebug_mask = MDEBUG_FONT;
-
-  /* This never fail to generate a valid fontname because open_spec
-     should correspond to a font available on the system.  */
-  name = mfont_unparse_name (&rfont->font, Mx);
-  M17N_OBJECT (xfont_info, close_xfont, MERROR_WIN);
-  xfont_info->display = FRAME_DISPLAY (frame);
-  xfont_info->xfont = XLoadQueryFont (FRAME_DISPLAY (frame), name);
-  if (! xfont_info->xfont)
+  Display *display = FRAME_DISPLAY (frame);
+  XFontStruct *xfont;
+  int mdebug_flag = MDEBUG_FONT;
+  MFont this;
+
+  size = spec->size;
+  if (size)
+    {
+      int ratio = mfont_resize_ratio (font);
+
+      if (ratio != 100)
+       size = size * ratio / 100;
+    }
+  else
+    size = 120;
+
+  if (font->size)
+    {
+      /* non-scalable font */
+      if (font->multiple_sizes)
+       {
+         int i;
+
+         if (size < 60)
+           size = 60;
+         else if (size > 290)
+           size = 290;
+         for (i = size / 10 - 6; i >= 0; i--)
+           if (font->size & (1 << i))
+             break;
+         if (i == 0)
+           for (i = size / 10 - 5; i < 24; i++)
+             if (font->size & (1 << i))
+               break;
+         size = (i + 6) * 10;
+       }
+      else
+       size = font->size;
+    }
+
+  if (rfont)
+    {
+      for (; rfont; rfont = rfont->next)
+       if (rfont->font == font && rfont->spec.size == size)
+         return rfont;
+    }
+
+  this = *font;
+  this.multiple_sizes = 0;
+  this.size = size;
+  /* This never fail to generate a valid fontname.  */
+  name = mfont_unparse_name (&this, Mx);
+  xfont = XLoadQueryFont (FRAME_DISPLAY (frame), name);
+  if (! xfont)
     {
     {
-      rfont->status = -1;
-      free (xfont_info);
       MDEBUG_PRINT1 (" [XFONT] x %s\n", name);
       free (name);
       MDEBUG_PRINT1 (" [XFONT] x %s\n", name);
       free (name);
-      return -1;
+      font->type = MFONT_TYPE_FAILURE;
+      return NULL;
     }
     }
-  rfont->info = xfont_info;
+  M17N_OBJECT (x_rfont, close_xfont, MERROR_FONT_X);
+  x_rfont->display = display;
+  x_rfont->xfont = xfont;
+  MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
+  rfont->id = msymbol (name);
+  rfont->spec = this;
+  rfont->spec.type = MFONT_TYPE_REALIZED;
+  rfont->spec.source = MFONT_SOURCE_X;
+  rfont->frame = frame;
+  rfont->font = font;
+  rfont->driver = &xfont_driver;
+  rfont->info = x_rfont;
+  {
+    MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
+    unsigned long value;
+
+    rfont->baseline_offset
+      = (XGetFontProperty (xfont, disp_info->MULE_BASELINE_OFFSET, &value)
+        ? (int) (value << 6) : 0);
+    rfont->average_width
+      = (XGetFontProperty (xfont, disp_info->AVERAGE_WIDTH, &value)
+        ? (int) (value << 6) / 10 : 0);
+  }
+  rfont->ascent = (xfont->ascent << 6) + rfont->baseline_offset;
+  rfont->descent = (xfont->descent << 6) - rfont->baseline_offset;
+  rfont->max_advance = xfont->max_bounds.width << 6;
+  rfont->x_ppem = rfont->y_ppem = size / 10;
+  rfont->fontp = xfont;
+  rfont->next = MPLIST_VAL (frame->realized_font_list);
+  MPLIST_VAL (frame->realized_font_list) = rfont;
   MDEBUG_PRINT1 (" [XFONT] o %s\n", name);
   free (name);
   MDEBUG_PRINT1 (" [XFONT] o %s\n", name);
   free (name);
-  rfont->status = 1;
-  rfont->ascent = xfont_info->xfont->ascent;
-  rfont->descent = xfont_info->xfont->descent;
-  rfont->type = Mx;
-  rfont->fontp = xfont_info->xfont;
-  return 0;
+  return rfont;
 }
 
 
 }
 
 
@@ -749,94 +699,113 @@ static void
 xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
                   int from, int to)
 {
 xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
                   int from, int to)
 {
-  MXFontInfo *xfont_info = rfont->info;
-  XFontStruct *xfont = xfont_info->xfont;
+  XFontStruct *xfont = rfont->fontp;
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
-    {
-      if (g->code == MCHAR_INVALID_CODE)
-       {
-         g->lbearing = xfont->max_bounds.lbearing;
-         g->rbearing = xfont->max_bounds.rbearing;
-         g->width = xfont->max_bounds.width;
-         g->ascent = xfont->ascent;
-         g->descent = xfont->descent;
-       }
-      else
-       {
-         int byte1 = g->code >> 8, byte2 = g->code & 0xFF;
-         XCharStruct *pcm = NULL;
+    if (! g->g.measured)
+      {
+       if (g->g.code == MCHAR_INVALID_CODE)
+         {
+           g->g.lbearing = xfont->max_bounds.lbearing << 6;
+           g->g.rbearing = xfont->max_bounds.rbearing << 6;
+           g->g.xadv = xfont->max_bounds.width << 6;
+           g->g.ascent = xfont->ascent << 6;
+           g->g.descent = xfont->descent << 6;
+         }
+       else
+         {
+           int byte1 = g->g.code >> 8, byte2 = g->g.code & 0xFF;
+           XCharStruct *pcm = NULL;
 
 
-         if (xfont->per_char != NULL)
-           {
-             if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
-               {
-                 if (byte1 == 0
-                     && byte2 >= xfont->min_char_or_byte2
-                     && byte2 <= xfont->max_char_or_byte2)
-                   pcm = xfont->per_char + byte2 - xfont->min_char_or_byte2;
-               }
-             else
-               {
-                 if (byte1 >= xfont->min_byte1
-                     && byte1 <= xfont->max_byte1
-                     && byte2 >= xfont->min_char_or_byte2
-                     && byte2 <= xfont->max_char_or_byte2)
-                   {
-                     pcm = (xfont->per_char
-                            + ((xfont->max_char_or_byte2
-                                - xfont->min_char_or_byte2 + 1)
-                               * (byte1 - xfont->min_byte1))
-                            + (byte2 - xfont->min_char_or_byte2));
-                   }
-               }
-           }
+           if (xfont->per_char != NULL)
+             {
+               if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
+                 {
+                   if (byte1 == 0
+                       && byte2 >= xfont->min_char_or_byte2
+                       && byte2 <= xfont->max_char_or_byte2)
+                     pcm = xfont->per_char + byte2 - xfont->min_char_or_byte2;
+                 }
+               else
+                 {
+                   if (byte1 >= xfont->min_byte1
+                       && byte1 <= xfont->max_byte1
+                       && byte2 >= xfont->min_char_or_byte2
+                       && byte2 <= xfont->max_char_or_byte2)
+                     {
+                       pcm = (xfont->per_char
+                              + ((xfont->max_char_or_byte2
+                                  - xfont->min_char_or_byte2 + 1)
+                                 * (byte1 - xfont->min_byte1))
+                              + (byte2 - xfont->min_char_or_byte2));
+                     }
+                 }
+             }
 
 
-         if (pcm)
-           {
-             g->lbearing = pcm->lbearing;
-             g->rbearing = pcm->rbearing;
-             g->width = pcm->width;
-             g->ascent = pcm->ascent;
-             g->descent = pcm->descent;
-           }
-         else
-           {
-             /* If the per_char pointer is null, all glyphs between
-                the first and last character indexes inclusive have
-                the same information, as given by both min_bounds and
-                max_bounds.  */
-             g->lbearing = 0;
-             g->rbearing = xfont->max_bounds.width;
-             g->width = xfont->max_bounds.width;
-             g->ascent = xfont->ascent;
-             g->descent = xfont->descent;
-           }
-       }
-    }
+           if (pcm)
+             {
+               g->g.lbearing = pcm->lbearing << 6;
+               g->g.rbearing = pcm->rbearing << 6;
+               g->g.xadv = pcm->width << 6;
+               g->g.ascent = pcm->ascent << 6;
+               g->g.descent = pcm->descent << 6;
+             }
+           else
+             {
+               /* If the per_char pointer is null, all glyphs between
+                  the first and last character indexes inclusive have
+                  the same information, as given by both min_bounds and
+                  max_bounds.  */
+               g->g.lbearing = 0;
+               g->g.rbearing = xfont->max_bounds.width << 6;
+               g->g.xadv = xfont->max_bounds.width << 6;
+               g->g.ascent = xfont->ascent << 6;
+               g->g.descent = xfont->descent << 6;
+             }
+         }
+       g->g.yadv = 0;
+       g->g.ascent += rfont->baseline_offset;
+       g->g.descent -= rfont->baseline_offset;
+       g->g.measured = 1;
+      }
 }
 
 
 }
 
 
+static int
+xfont_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
+{
+  return (xfont_encode_char (frame, font, spec, code) != MCHAR_INVALID_CODE);
+}
+
 /* The X font driver function GET_GLYPH_ID.  */
 
 static unsigned
 /* The X font driver function GET_GLYPH_ID.  */
 
 static unsigned
-xfont_encode_char (MRealizedFont *rfont, unsigned code)
+xfont_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
 {
 {
-  MXFontInfo *xfont_info;
+  MRealizedFont *rfont;
   XFontStruct *xfont;
   unsigned min_byte1, max_byte1, min_byte2, max_byte2;
   int all_chars_exist;
 
   XFontStruct *xfont;
   unsigned min_byte1, max_byte1, min_byte2, max_byte2;
   int all_chars_exist;
 
-  if (rfont->status < 0 || code >= 0x10000)
-    return MCHAR_INVALID_CODE;
-  if (rfont->status == 0)
+  if (font->type == MFONT_TYPE_REALIZED)
+    rfont = (MRealizedFont *) font;
+  else if (font->type == MFONT_TYPE_OBJECT)
     {
     {
-      if (xfont_open (rfont) < 0)
-       return MCHAR_INVALID_CODE;
+      for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
+          rfont = rfont->next)
+       if (rfont->font == font)
+         break;
+      if (! rfont)
+       {
+         rfont = xfont_open (frame, font, spec, NULL);
+         if (! rfont)
+           return MCHAR_INVALID_CODE;
+       }
     }
     }
-  xfont_info = rfont->info;
-  xfont = xfont_info->xfont;
+  else
+    MFATAL (MERROR_FONT_X);
+  xfont = rfont->fontp;
   all_chars_exist = (! xfont->per_char || xfont->all_chars_exist == True);
   min_byte1 = xfont->min_byte1;
   max_byte1 = xfont->max_byte1;
   all_chars_exist = (! xfont->per_char || xfont->all_chars_exist == True);
   min_byte1 = xfont->min_byte1;
   max_byte1 = xfont->max_byte1;
@@ -880,48 +849,45 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
              MGlyph *from, MGlyph *to, int reverse, MDrawRegion region)
 {
   MRealizedFace *rface = from->rface;
              MGlyph *from, MGlyph *to, int reverse, MDrawRegion region)
 {
   MRealizedFace *rface = from->rface;
-  MXFontInfo *xfont_info = rface->rfont->info;
-  Display *display;
+  Display *display = FRAME_DISPLAY (rface->frame);
   XChar2b *code;
   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
   MGlyph *g;
   int i;
   XChar2b *code;
   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
   MGlyph *g;
   int i;
+  int baseline_offset;
 
   if (from == to)
     return;
 
 
   if (from == to)
     return;
 
-  /* It is assured that the all glyphs in the current range use the
-     same realized face.  */
-  display = FRAME_DISPLAY (rface->frame);
-
+  baseline_offset = rface->rfont->baseline_offset >> 6;
   if (region)
     gc = set_region (rface->frame, gc, region);
   if (region)
     gc = set_region (rface->frame, gc, region);
-  XSetFont (display, gc, xfont_info->xfont->fid);
+  XSetFont (display, gc, ((XFontStruct *) rface->rfont->fontp)->fid);
   code = (XChar2b *) alloca (sizeof (XChar2b) * (to - from));
   for (i = 0, g = from; g < to; i++, g++)
     {
   code = (XChar2b *) alloca (sizeof (XChar2b) * (to - from));
   for (i = 0, g = from; g < to; i++, g++)
     {
-      code[i].byte1 = g->code >> 8;
-      code[i].byte2 = g->code & 0xFF;
+      code[i].byte1 = g->g.code >> 8;
+      code[i].byte2 = g->g.code & 0xFF;
     }
 
   g = from;
   while (g < to)
     {
       if (g->type == GLYPH_PAD)
     }
 
   g = from;
   while (g < to)
     {
       if (g->type == GLYPH_PAD)
-       x += g++->width;
+       x += g++->g.xadv;
       else if (g->type == GLYPH_SPACE)
        for (; g < to && g->type == GLYPH_SPACE; g++)
       else if (g->type == GLYPH_SPACE)
        for (; g < to && g->type == GLYPH_SPACE; g++)
-         x += g->width;
+         x += g->g.xadv;
       else if (! g->rface->rfont)
        {
       else if (! g->rface->rfont)
        {
-         if ((g->c >= 0x200B && g->c <= 0x200F)
-             || (g->c >= 0x202A && g->c <= 0x202E))
-           x += g++->width;
+         if ((g->g.c >= 0x200B && g->g.c <= 0x200F)
+             || (g->g.c >= 0x202A && g->g.c <= 0x202E))
+           x += g++->g.xadv;
          else
            {
              /* As a font is not found for this character, draw an
                 empty box.  */
          else
            {
              /* As a font is not found for this character, draw an
                 empty box.  */
-             int box_width = g->width;
+             int box_width = g->g.xadv;
              int box_height = gstring->ascent + gstring->descent;
 
              if (box_width > 4)
              int box_height = gstring->ascent + gstring->descent;
 
              if (box_width > 4)
@@ -930,14 +896,15 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
                box_height -= 2;
              XDrawRectangle (display, (Window) win, gc,
                              x, y - gstring->ascent, box_width, box_height);
                box_height -= 2;
              XDrawRectangle (display, (Window) win, gc,
                              x, y - gstring->ascent, box_width, box_height);
-             x += g++->width;
+             x += g++->g.xadv;
            }
        }
            }
        }
-      else if (g->xoff != 0 || g->yoff != 0 || g->right_padding)
+      else if (g->g.xoff != 0 || g->g.yoff != 0 || g->right_padding)
        {
          XDrawString16 (display, (Window) win, gc,
        {
          XDrawString16 (display, (Window) win, gc,
-                        x + g->xoff, y + g->yoff, code + (g - from), 1);
-         x += g->width;
+                        x + g->g.xoff, y + g->g.yoff - baseline_offset,
+                        code + (g - from), 1);
+         x += g->g.xadv;
          g++;
        }
       else
          g++;
        }
       else
@@ -946,85 +913,116 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
          int code_idx = g - from;
 
          for (i = 0;
          int code_idx = g - from;
 
          for (i = 0;
-              g < to && g->type == GLYPH_CHAR && g->xoff == 0 && g->yoff == 0;
+              g < to && g->type == GLYPH_CHAR && g->g.xoff == 0 && g->g.yoff == 0;
               i++, g++)
               i++, g++)
-             x += g->width;
-         XDrawString16 (display, (Window) win, gc, orig_x, y,
-                        code + code_idx, i);
+             x += g->g.xadv;
+         XDrawString16 (display, (Window) win, gc,
+                        orig_x, y - baseline_offset, code + code_idx, i);
        }
     }
 }
 
 static int
        }
     }
 }
 
 static int
-xfont_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language,
-           int maxnum)
+xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
 {
   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
   MSymbol registry = font ? FONT_PROPERTY (font, MFONT_REGISTRY) : Mnil;
   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
 {
   MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
   MSymbol registry = font ? FONT_PROPERTY (font, MFONT_REGISTRY) : Mnil;
   MSymbol family = font ? FONT_PROPERTY (font, MFONT_FAMILY) : Mnil;
-  MPlist *p, *pl;
+  int size = font ? font->size : 0;
+  MPlist *pl, *p;
   int num = 0;
   int num = 0;
+  int mdebug_flag = MDEBUG_FONT;
 
 
-  if (registry != Mnil)
-    xfont_registry_list (frame, registry);
-  else
-    xfont_list_all (frame);
+  MDEBUG_PRINT2 (" [X-FONT] listing %s-%s...",
+                family ? msymbol_name (family) : "*",
+                registry ? msymbol_name (registry) : "*");
 
 
-  /* As we have not yet implemented the language check, return all
-     base fonts.  */
-  if (! font)
-    MPLIST_DO (p, disp_info->base_font_list)
-      {
-       mplist_add (plist, MPLIST_KEY (p), MPLIST_VAL (p));
-       num++;
-       if (num == maxnum)
-         return num;
-      }
+  if (registry == Mnil)
+    xfont_list_all (frame);
   else
   else
-    {
-      MXFontList *xfontlist;
-      MXFont *xfont;
-      int i;
-
-      pl = disp_info->font_list;
-      if (registry != Mnil)
-       {
-         pl = mplist_find_by_key (pl, registry);
-         if (! pl)
-           return 0;
-       }
+    xfont_registry_list (frame, registry);
 
 
-      MPLIST_DO (pl, pl)
-       {
-         p = MPLIST_VAL (pl);
-         if (family != Mnil)
-           {
-             p = mplist_find_by_key (p, family);
-             if (! p)
-               return 0;
-           }
-         MPLIST_DO (p, p)
+  MPLIST_DO (pl, disp_info->font_list)
+    if (registry == Mnil || registry == MPLIST_KEY (pl))
+      {
+       MPLIST_DO (p, MPLIST_VAL (pl))
+         if (family == Mnil || family == MPLIST_KEY (p))
            {
            {
-             xfontlist = MPLIST_VAL (p);
-             for (i = 0; i < xfontlist->used; i++)
+             MFont *fontx = MPLIST_VAL (p);
+
+             if (! font || (mfont__match_p (fontx, font, MFONT_REGISTRY)))
                {
                {
-                 xfont = xfontlist->fonts + i;
-                 if (mfont__match_p (&xfont->core, font, MFONT_REGISTRY))
+                 if (fontx->size != 0 && size)
                    {
                    {
-                     mplist_add (plist, MPLIST_KEY (p), &xfont->core);
-                     num++;
-                     if (num == maxnum)
-                       return num;
+                     if (fontx->multiple_sizes)
+                       {
+                         if (size < 60 || size > 290
+                             || ! (fontx->size & (1 << (size / 10 - 6))))
+                           continue;
+                       }
+                     else if (fontx->size != size)
+                       continue;
                    }
                    }
+                 mplist_push (plist, MPLIST_KEY (p), fontx);
+                 num++;
+                 if (maxnum > 0 && maxnum == num)
+                   goto done;
                }
                }
-             if (family != Mnil)
-               break;
            }
            }
-         if (registry != Mnil)
+      }
+
+ done:
+  MDEBUG_PRINT1 (" %d found\n", num);
+  return num;
+}
+
+static void
+xfont_list_family_names (MFrame *frame, MPlist *plist)
+{
+  MDisplayInfo *disp_info = FRAME_DEVICE (frame)->display_info;
+  char **font_names;
+  int i, nfonts;
+  MSymbol last_family = Mnil;
+
+  font_names = XListFonts (disp_info->display,
+                          "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", 0x8000, &nfonts);
+  for (i = 0; i < nfonts; i++)
+    {
+      MSymbol family;
+      char foundry[256], fam[256];
+      MPlist *p;
+      
+      if (sscanf (font_names[i], "-%s-%s-", foundry, fam) < 2)
+       continue;
+      family = msymbol (fam);
+      if (family == last_family)
+       continue;
+      last_family = family;
+
+      MPLIST_DO (p, plist)
+       {
+         MSymbol sym = MPLIST_SYMBOL (p);
+
+         if (sym == family)
            break;
            break;
+         if (strcmp (MSYMBOL_NAME (sym), fam) > 0)
+           {
+             mplist_push (p, Msymbol, family);
+             break;
+           }
        }
        }
+      if (MPLIST_TAIL_P (p))
+       mplist_push (p, Msymbol, family);
     }
     }
-  return num;
+  if (font_names)
+    XFreeFontNames (font_names);
+}
+
+static int 
+xfont_check_capability (MRealizedFont *rfont, MSymbol capability)
+{
+  /* Currently X font driver doesn't support any capability.  */
+  return -1;
 }
 
 \f
 }
 
 \f
@@ -1035,127 +1033,228 @@ xfont_list (MFrame *frame, MPlist *plist, MFont *font, MSymbol language,
 typedef struct
 {
   M17NObject control;
 typedef struct
 {
   M17NObject control;
+  FT_Face ft_face;             /* This must be the 2nd member. */
   Display *display;
   XftFont *font_aa;
   XftFont *font_no_aa;
   Display *display;
   XftFont *font_aa;
   XftFont *font_no_aa;
-} MXftFontInfo;
-
-static int xft_open (MRealizedFont *);
+  /* Pointer to MRealizedFontFT */
+  void *info;
+} MRealizedFontXft;
+
+static MRealizedFont *xft_open (MFrame *frame, MFont *font, MFont *spec,
+                               MRealizedFont *);
+static int xft_has_char (MFrame *frame, MFont *font, MFont *spec,
+                        int c, unsigned code);
+static unsigned xft_encode_char (MFrame *frame, MFont *font, MFont *spec,
+                                unsigned code);
 static void xft_find_metric (MRealizedFont *, MGlyphString *, int, int);
 static void xft_render (MDrawWindow, int, int, MGlyphString *,
                        MGlyph *, MGlyph *, int, MDrawRegion);
 static void xft_find_metric (MRealizedFont *, MGlyphString *, int, int);
 static void xft_render (MDrawWindow, int, int, MGlyphString *,
                        MGlyph *, MGlyph *, int, MDrawRegion);
-
-MFontDriver xft_driver =
-  { NULL,                      /* Set to ft_select in device_init (). */
-    xft_open, xft_find_metric,
-    NULL,                      /* Set to ft_encode_char in device_init (). */
-    xft_render,
-    NULL                       /* Set to ft_list in device_init (). */
+static int xft_check_capability (MRealizedFont *rfont, MSymbol capability);
+static int xft_check_otf (MFLTFont *font, MFLTOtfSpec *spec);
+static int xft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
+                         MFLTGlyphString *in, int from, int to,
+                         MFLTGlyphString *out,
+                         MFLTGlyphAdjustment *adjustment);
+static int xft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
+                       MFLTGlyphString *in, int from, int to);
+static int xft_iterate_otf_feature (struct _MFLTFont *font, MFLTOtfSpec *spec,
+                                   int from, int to, unsigned char *table);
+
+
+static MFontDriver xft_driver =
+  { NULL, xft_open,
+    xft_find_metric, xft_has_char, xft_encode_char, xft_render, NULL, NULL,
+    xft_check_capability, NULL, NULL, xft_check_otf, xft_drive_otf, xft_try_otf,
+#ifdef HAVE_OTF
+    xft_iterate_otf_feature
+#endif /* HAVE_OTF */
   };
 
   };
 
-
 static void
 close_xft (void *object)
 {
 static void
 close_xft (void *object)
 {
-  MXftFontInfo *font_info = object;
+  MRealizedFontXft *rfont_xft = object;
 
 
-  XftFontClose (font_info->display, font_info->font_aa);
-  XftFontClose (font_info->display, font_info->font_no_aa);
-  free (font_info);
+  if (rfont_xft->font_aa)
+    XftFontClose (rfont_xft->display, rfont_xft->font_aa);
+  if (rfont_xft->font_no_aa)
+    XftFontClose (rfont_xft->display, rfont_xft->font_no_aa);
+  M17N_OBJECT_UNREF (rfont_xft->info);
+  free (rfont_xft);
 }
 
 
 static XftFont *
 }
 
 
 static XftFont *
-xft_open_font (MFrame *frame, MFTInfo *ft_info, int size, int anti_alias)
+xft_open_font (Display *display, MSymbol file, double size,
+              FcBool anti_alias)
 {
 {
-  XftPattern *pattern;
-  XftFontInfo *xft_font_info;
+  FcPattern *pattern;
   XftFont *font;
 
   XftFont *font;
 
-  pattern = XftPatternCreate ();
-  XftPatternAddString (pattern, XFT_FILE, ft_info->filename);
-  XftPatternAddDouble (pattern, XFT_PIXEL_SIZE, (double) size);
-  XftPatternAddBool (pattern, XFT_ANTIALIAS, anti_alias);
-  xft_font_info = XftFontInfoCreate (FRAME_DISPLAY (frame), pattern);
-  if (! xft_font_info)
-    return NULL;
-  font = XftFontOpenInfo (FRAME_DISPLAY (frame), pattern, xft_font_info);
-  XftFontInfoDestroy (FRAME_DISPLAY (frame), xft_font_info);
+  pattern = FcPatternCreate ();
+  FcPatternAddString (pattern, FC_FILE, (FcChar8 *) msymbol_name (file));
+  FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
+  FcPatternAddBool (pattern, FC_ANTIALIAS, anti_alias);
+  font = XftFontOpenPattern (display, pattern);
   return font;
 }
 
 
   return font;
 }
 
 
-static int
-xft_open (MRealizedFont *rfont)
+static MRealizedFont *
+xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
 {
 {
-  MFrame *frame;
-  MFTInfo *ft_info;
-  MXftFontInfo *font_info;
+  Display *display = FRAME_DISPLAY (frame);
+  int reg = spec->property[MFONT_REGISTRY];
+  FT_Face ft_face;
+  MRealizedFontXft *rfont_xft;
+  FcBool anti_alias = FRAME_DEVICE (frame)->depth > 1 ? FcTrue : FcFalse;
   int size;
   int size;
+  XftFont *xft_font;
+  int ascent, descent, max_advance, average_width, baseline_offset;
 
 
-  if ((mfont__ft_driver.open) (rfont) < 0)
-    return -1;
+  if (font->size)
+    /* non-scalable font */
+    size = font->size;
+  else if (spec->size)
+    {
+      int ratio = mfont_resize_ratio (font);
 
 
-  size = rfont->font.property[MFONT_SIZE] / 10;
-  frame = rfont->frame;
+      size = ratio == 100 ? spec->size : spec->size * ratio / 100;
+    }
+  else
+    size = 120;
 
 
-  ft_info = rfont->info;
-  M17N_OBJECT (font_info, close_xft, MERROR_WIN);
-  ft_info->extra_info = font_info;
-  font_info->display = FRAME_DISPLAY (frame);
-  font_info->font_aa = xft_open_font (frame, ft_info, size, 1);
-  if (font_info->font_aa)
+  if (rfont)
     {
     {
-      font_info->font_no_aa = xft_open_font (frame, ft_info, size, 0);
-      if (font_info->font_no_aa)
-       {
-         rfont->type = Mxft;
-         rfont->fontp = font_info->font_no_aa;
-         return 0;
-       }
-      XftFontClose (FRAME_DISPLAY (rfont->frame), font_info->font_aa);
+      MRealizedFont *save = NULL;
+
+      for (; rfont; rfont = rfont->next)
+       if (rfont->font == font
+           && (rfont->font->size ? rfont->font->size == size
+               : rfont->spec.size == size)
+           && rfont->spec.property[MFONT_REGISTRY] == reg)
+         {
+           if (! save)
+             save = rfont;
+           if (rfont->driver == &xft_driver)
+             return rfont;
+         }
+      rfont = save;
     }
     }
-  free (font_info);  
-  ft_info->extra_info = NULL;
-  rfont->status = -1;
-  return -1;
+  rfont = (mfont__ft_driver.open) (frame, font, spec, rfont);
+  if (! rfont)
+    return NULL;
+  ascent = rfont->ascent;
+  descent = rfont->descent;
+  max_advance = rfont->max_advance;
+  average_width = rfont->average_width;
+  baseline_offset = rfont->baseline_offset;
+  spec = &rfont->spec;
+  ft_face = rfont->fontp;
+  xft_font = xft_open_font (display, font->file, size / 10, anti_alias);
+  if (! xft_font)
+    return NULL;
+  M17N_OBJECT (rfont_xft, close_xft, MERROR_WIN);
+  rfont_xft->display = display;
+  if (anti_alias == FcTrue)
+    rfont_xft->font_aa = xft_font;
+  else
+    rfont_xft->font_no_aa = xft_font;
+  rfont_xft->ft_face = ft_face;
+  rfont_xft->info = rfont->info;
+  M17N_OBJECT_REF (rfont->info);
+  MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
+  rfont->id = font->file;
+  rfont->spec = *spec;
+  rfont->spec.size = size;
+  rfont->frame = frame;
+  rfont->font = font;
+  rfont->driver = &xft_driver;
+  rfont->info = rfont_xft;
+  rfont->ascent = ascent;
+  rfont->descent = descent;
+  rfont->max_advance = max_advance;
+  rfont->average_width = average_width;
+  rfont->baseline_offset = baseline_offset;
+  rfont->x_ppem = ft_face->size->metrics.x_ppem;
+  rfont->y_ppem = ft_face->size->metrics.y_ppem;
+  rfont->fontp = xft_font;
+  rfont->next = MPLIST_VAL (frame->realized_font_list);
+  MPLIST_VAL (frame->realized_font_list) = rfont;
+  return rfont;
 }
 
 }
 
-
 static void
 xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
                int from, int to)
 {
 static void
 xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
                int from, int to)
 {
-  MFTInfo *ft_info = rfont->info;
-  MXftFontInfo *font_info = ft_info->extra_info;
+  Display *display = FRAME_DISPLAY (rfont->frame);
+  XftFont *xft_font = rfont->fontp;
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
-    {
-      if (g->code == MCHAR_INVALID_CODE)
-       {
-         MGlyph *start = g++;
+    if (! g->g.measured)
+      {
+       if (g->g.code == MCHAR_INVALID_CODE)
+         {
+           g->g.lbearing = 0;
+           g->g.rbearing = xft_font->max_advance_width << 6;
+           g->g.xadv = g->g.rbearing << 6;
+           g->g.ascent = xft_font->ascent << 6;
+           g->g.descent = xft_font->descent << 6;
+         }
+       else
+         {
+           XGlyphInfo extents;
+
+           XftGlyphExtents (display, xft_font, &g->g.code, 1, &extents);
+           g->g.lbearing = (- extents.x) << 6;
+           g->g.rbearing = (extents.width - extents.x) << 6;
+           g->g.xadv = extents.xOff << 6;
+           g->g.ascent = extents.y << 6;
+           g->g.descent = (extents.height - extents.y) << 6;
+         }
+       g->g.yadv = 0;
+       g->g.measured = 1;
+      }
+}
 
 
-         while (g != gend && g->code == MCHAR_INVALID_CODE) g++;
-         (mfont__ft_driver.find_metric) (rfont, gstring, GLYPH_INDEX (start),
-                                         GLYPH_INDEX (g));
-         g--;
-       }
-      else
-       {
-         XGlyphInfo extents;
-
-         XftGlyphExtents (FRAME_DISPLAY (gstring->frame),
-                          font_info->font_aa, &g->code, 1, &extents);
-         g->lbearing = - extents.x;
-         g->rbearing = extents.width - extents.x;
-         g->width = extents.xOff;
-         g->ascent = extents.y;
-         g->descent = extents.height - extents.y;
-       }
+static int
+xft_has_char (MFrame *frame, MFont *font, MFont *spec, int c, unsigned code)
+{
+  int result;
+
+  if (font->type == MFONT_TYPE_REALIZED)
+    {
+      MRealizedFont *rfont = (MRealizedFont *) font;
+      MRealizedFontXft *rfont_xft = rfont->info;
+      
+      rfont->info = rfont_xft->info;
+      result = mfont__ft_driver.has_char (frame, font, spec, c, code);
+      rfont->info = rfont_xft;
     }
     }
+  else
+    result = mfont__ft_driver.has_char (frame, font, spec, c, code);
+  return result;
 }
 
 }
 
+static unsigned
+xft_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
+{
+  if (font->type == MFONT_TYPE_REALIZED)
+    {
+      MRealizedFont *rfont = (MRealizedFont *) font;
+      MRealizedFontXft *rfont_xft = rfont->info;
+      
+      rfont->info = rfont_xft->info;
+      code = mfont__ft_driver.encode_char (frame, font, spec, code);
+      rfont->info = rfont_xft;
+    }
+  else
+    code = mfont__ft_driver.encode_char (frame, font, spec, code);
+  return code;
+}
 
 static void 
 xft_render (MDrawWindow win, int x, int y,
 
 static void 
 xft_render (MDrawWindow win, int x, int y,
@@ -1164,15 +1263,16 @@ xft_render (MDrawWindow win, int x, int y,
 {
   MRealizedFace *rface = from->rface;
   MFrame *frame = rface->frame;
 {
   MRealizedFace *rface = from->rface;
   MFrame *frame = rface->frame;
-  MFTInfo *ft_info = rface->rfont->info;
-  MXftFontInfo *font_info = ft_info->extra_info;
+  Display *display = FRAME_DISPLAY (frame);
+  MRealizedFont *rfont = rface->rfont;
+  MRealizedFontXft *rfont_xft = rfont->info;
   XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
   XftColor *xft_color = (! reverse
                         ? &((GCInfo *) rface->info)->xft_color_fore
                         : &((GCInfo *) rface->info)->xft_color_back);
   XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
   XftColor *xft_color = (! reverse
                         ? &((GCInfo *) rface->info)->xft_color_fore
                         : &((GCInfo *) rface->info)->xft_color_back);
-  XftFont *xft_font = (gstring->control.anti_alias
-                      && FRAME_DEVICE (frame)->depth > 1
-                      ? font_info->font_aa : font_info->font_no_aa);
+  int anti_alias = (gstring->control.anti_alias
+                   && FRAME_DEVICE (frame)->depth > 1);
+  XftFont *xft_font;
   MGlyph *g;
   FT_UInt *glyphs;
   int last_x;
   MGlyph *g;
   FT_UInt *glyphs;
   int last_x;
@@ -1181,14 +1281,48 @@ xft_render (MDrawWindow win, int x, int y,
   if (from == to)
     return;
 
   if (from == to)
     return;
 
+  if (anti_alias)
+    {
+      if (rfont_xft->font_aa)
+       xft_font = rfont_xft->font_aa;
+      else
+       {
+         double size = rfont->spec.size;
+
+         xft_font = xft_open_font (display, rfont->spec.file, size / 10,
+                                   FcTrue);
+         if (xft_font)
+           rfont_xft->font_aa = xft_font;
+         else
+           xft_font = rfont->fontp;
+       }
+    }
+  else
+    {
+      if (rfont_xft->font_no_aa)
+       xft_font = rfont_xft->font_no_aa;
+      else
+       {
+         double size = rfont->spec.size;
+
+         xft_font = xft_open_font (display, rfont->spec.file, size / 10,
+                                   FcTrue);
+         if (xft_font)
+           rfont_xft->font_no_aa = xft_font;
+         else
+           xft_font = rfont->fontp;
+       }
+    }
+
   XftDrawChange (xft_draw, (Drawable) win);
   XftDrawSetClip (xft_draw, (Region) region);
       
   XftDrawChange (xft_draw, (Drawable) win);
   XftDrawSetClip (xft_draw, (Region) region);
       
+  y -= rfont->baseline_offset >> 6;
   glyphs = alloca (sizeof (FT_UInt) * (to - from));
   glyphs = alloca (sizeof (FT_UInt) * (to - from));
-  for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->width)
+  for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->g.xadv)
     {
     {
-      if (g->xoff == 0 && g->yoff == 0 && !g->left_padding && !g->right_padding)
-       glyphs[nglyphs++] = g->code;
+      if (! g->g.adjusted && !g->left_padding && !g->right_padding)
+       glyphs[nglyphs++] = g->g.code;
       else
        {
          if (nglyphs > 0)
       else
        {
          if (nglyphs > 0)
@@ -1196,15 +1330,81 @@ xft_render (MDrawWindow win, int x, int y,
                           last_x, y, glyphs, nglyphs);
          nglyphs = 0;
          XftDrawGlyphs (xft_draw, xft_color, xft_font,
                           last_x, y, glyphs, nglyphs);
          nglyphs = 0;
          XftDrawGlyphs (xft_draw, xft_color, xft_font,
-                        x + g->xoff, y + g->yoff, (FT_UInt *) &g->code, 1);
-         last_x = x + g->width;
+                        x + g->g.xoff, y + g->g.yoff, (FT_UInt *) &g->g.code, 1);
+         last_x = x + g->g.xadv;
        }
     }
   if (nglyphs > 0)
     XftDrawGlyphs (xft_draw, xft_color, xft_font, last_x, y, glyphs, nglyphs);
 }
 
        }
     }
   if (nglyphs > 0)
     XftDrawGlyphs (xft_draw, xft_color, xft_font, last_x, y, glyphs, nglyphs);
 }
 
-#endif
+static int
+xft_check_capability (MRealizedFont *rfont, MSymbol capability)
+{
+  MRealizedFontXft *rfont_xft = rfont->info;
+  int result;
+      
+  rfont->info = rfont_xft->info;
+  result = mfont__ft_driver.check_capability (rfont, capability);
+  rfont->info = rfont_xft;
+  return result;
+}
+
+static int
+xft_check_otf (MFLTFont *font, MFLTOtfSpec *spec)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFontXft *rfont_xft = rfont->info;
+  int result;
+      
+  rfont->info = rfont_xft->info;
+  result = mfont__ft_driver.check_otf (font, spec);
+  rfont->info = rfont_xft;
+  return result;
+}
+
+static int
+xft_drive_otf (MFLTFont *font, MFLTOtfSpec *spec,
+              MFLTGlyphString *in, int from, int to,
+              MFLTGlyphString *out,
+              MFLTGlyphAdjustment *adjustment)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFontXft *rfont_xft = rfont->info;
+  int result;
+      
+  rfont->info = rfont_xft->info;
+  result = mfont__ft_driver.drive_otf (font, spec, in, from, to, out,
+                                      adjustment);
+  rfont->info = rfont_xft;
+  return result;
+}
+
+static int
+xft_try_otf (MFLTFont *font, MFLTOtfSpec *spec,
+            MFLTGlyphString *in, int from, int to)
+{
+  return xft_drive_otf (font, spec, in, from, to, NULL, NULL);
+}
+
+#ifdef HAVE_OTF
+
+static int
+xft_iterate_otf_feature (struct _MFLTFont *font, MFLTOtfSpec *spec,
+                        int from, int to, unsigned char *table)
+{
+  MRealizedFont *rfont = ((MFLTFontForRealized *) font)->rfont;
+  MRealizedFontXft *rfont_xft = rfont->info;
+  int result;
+      
+  rfont->info = rfont_xft->info;
+  result = mfont__ft_driver.iterate_otf_feature (font, spec, from, to, table);
+  rfont->info = rfont_xft;
+  return result;
+}
+#endif /* HAVE_OTF */
+
+#endif /* HAVE_XFT2 */
 
 \f
 /* Functions for the device driver.  */
 
 \f
 /* Functions for the device driver.  */
@@ -1290,7 +1490,7 @@ mwin__realize_face (MRealizedFace *rface)
                           MSYMBOL_NAME (background),
                           &info->xft_color_back))
     mdebug_hook ();
                           MSYMBOL_NAME (background),
                           &info->xft_color_back))
     mdebug_hook ();
-#endif
+#endif /* HAVE_XFT2 */
 
   hline = rface->hline;
   if (hline)
 
   hline = rface->hline;
   if (hline)
@@ -1369,9 +1569,9 @@ mwin__draw_empty_boxes (MDrawWindow win, int x, int y,
   for (; from < to; from++)
     {
       XDrawRectangle (display, (Window) win, gc,
   for (; from < to; from++)
     {
       XDrawRectangle (display, (Window) win, gc,
-                     x, y - gstring->ascent + 1, from->width - 1,
+                     x, y - gstring->ascent + 1, from->g.xadv - 1,
                      gstring->ascent + gstring->descent - 2);
                      gstring->ascent + gstring->descent - 2);
-      x += from->width;
+      x += from->g.xadv;
     }
 }
 
     }
 }
 
@@ -1432,9 +1632,9 @@ mwin__draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
       int x0, x1;
 
       if (g->left_padding)
       int x0, x1;
 
       if (g->left_padding)
-       x0 = x + box->outer_hmargin, x1 = x + g->width - 1;
+       x0 = x + box->outer_hmargin, x1 = x + g->g.xadv - 1;
       else
       else
-       x0 = x, x1 = x + g->width - box->outer_hmargin - 1;
+       x0 = x, x1 = x + g->g.xadv - box->outer_hmargin - 1;
 
       /* Draw the top side.  */
       for (i = 0; i < box->width; i++)
 
       /* Draw the top side.  */
       for (i = 0; i < box->width; i++)
@@ -1650,6 +1850,12 @@ mwin__create_window (MFrame *frame, MDrawWindow parent)
 static void
 mwin__destroy_window (MFrame *frame, MDrawWindow win)
 {
 static void
 mwin__destroy_window (MFrame *frame, MDrawWindow win)
 {
+#ifdef HAVE_XFT2
+  XftDraw *xft_draw = FRAME_DEVICE (frame)->xft_draw;
+
+  if (XftDrawDrawable (xft_draw) == (Drawable) win)
+    XftDrawChange (xft_draw, FRAME_DEVICE (frame)->drawable);
+#endif /* HAVE_XFT2 */
   XDestroyWindow (FRAME_DISPLAY (frame), (Window) win);
 }
 
   XDestroyWindow (FRAME_DISPLAY (frame), (Window) win);
 }
 
@@ -1799,7 +2005,7 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
   int len;
   char buf[512];
   KeySym keysym;
   int len;
   char buf[512];
   KeySym keysym;
-  MSymbol key = Mnil;
+  MSymbol key;
 
   *modifiers = 0;
   if (event->xany.type != KeyPress
 
   *modifiers = 0;
   if (event->xany.type != KeyPress
@@ -1809,26 +2015,17 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
   len = XLookupString ((XKeyEvent *) event, (char *) buf, 512, &keysym, NULL);
   if (len > 1)
     return Mnil;
   len = XLookupString ((XKeyEvent *) event, (char *) buf, 512, &keysym, NULL);
   if (len > 1)
     return Mnil;
-  if (len == 1)
+  if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
+    return Mnil;
+  if (len == 1 && keysym >= XK_space && keysym <= XK_asciitilde)
     {
       int c = keysym;
 
     {
       int c = keysym;
 
-      if (c < XK_space || c > XK_asciitilde)
-       c = buf[0];
-      if ((c == ' ' || c == 127) && ((XKeyEvent *) event)->state & ShiftMask)
-       *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
-      if (((XKeyEvent *) event)->state & ControlMask)
-       {
-         if (c >= 'a' && c <= 'z')
-           c += 'A' - 'a';
-         if (c >= ' ' && c < 127)
-           *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
-       }
       key = minput__char_to_key (c);
       key = minput__char_to_key (c);
+      if (c == ' ' && ((XKeyEvent *) event)->state & ShiftMask)
+       *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
     }
     }
-  else if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
-    return Mnil;
-  if (key == Mnil)
+  else
     {
       char *str = XKeysymToString (keysym);
 
     {
       char *str = XKeysymToString (keysym);
 
@@ -1837,9 +2034,9 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
       key = msymbol (str);
       if (((XKeyEvent *) event)->state & ShiftMask)
        *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
       key = msymbol (str);
       if (((XKeyEvent *) event)->state & ShiftMask)
        *modifiers |= MINPUT_KEY_SHIFT_MODIFIER;
-      if (((XKeyEvent *) event)->state & ControlMask)
-       *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
     }
     }
+  if (((XKeyEvent *) event)->state & ControlMask)
+    *modifiers |= MINPUT_KEY_CONTROL_MODIFIER;
   if (((XKeyEvent *) event)->state & disp_info->meta_mask)
     *modifiers |= MINPUT_KEY_META_MODIFIER;
   if (((XKeyEvent *) event)->state & disp_info->alt_mask)
   if (((XKeyEvent *) event)->state & disp_info->meta_mask)
     *modifiers |= MINPUT_KEY_META_MODIFIER;
   if (((XKeyEvent *) event)->state & disp_info->alt_mask)
@@ -1911,8 +2108,8 @@ device_init ()
 
 #ifdef HAVE_XFT2
   xft_driver.select = mfont__ft_driver.select;
 
 #ifdef HAVE_XFT2
   xft_driver.select = mfont__ft_driver.select;
-  xft_driver.encode_char = mfont__ft_driver.encode_char;
   xft_driver.list = mfont__ft_driver.list;
   xft_driver.list = mfont__ft_driver.list;
+  xft_driver.list_family_names = mfont__ft_driver.list_family_names;
 #endif
 
   Mxim = msymbol ("xim");
 #endif
 
   Mxim = msymbol ("xim");
@@ -1929,6 +2126,23 @@ device_fini ()
   return 0;
 }
 
   return 0;
 }
 
+
+#ifdef X_SET_ERROR_HANDLER
+static int
+x_error_handler (Display *display, XErrorEvent *error)
+{
+  mdebug_hook ();
+  return 0;
+}
+
+static int
+x_io_error_handler (Display *display)
+{
+  mdebug_hook ();
+  return 0;
+}
+#endif
+
 /** Return an MWDevice object corresponding to a display specified in
     PLIST.
 
 /** Return an MWDevice object corresponding to a display specified in
     PLIST.
 
@@ -1953,6 +2167,7 @@ device_open (MFrame *frame, MPlist *param)
   unsigned depth = 0;
   MPlist *plist;
   AppData app_data;
   unsigned depth = 0;
   MPlist *plist;
   AppData app_data;
+  MFont *font = NULL;
   MFace *face;
   int use_xfont = 0, use_freetype = 0, use_xft = 0;
 
   MFace *face;
   int use_xfont = 0, use_freetype = 0, use_xft = 0;
 
@@ -2050,8 +2265,11 @@ device_open (MFrame *frame, MPlist *param)
       disp_info->display = display;
       disp_info->auto_display = auto_display;
       disp_info->font_list = mplist ();
       disp_info->display = display;
       disp_info->auto_display = auto_display;
       disp_info->font_list = mplist ();
-      disp_info->base_font_list = mplist ();
       find_modifier_bits (disp_info);
       find_modifier_bits (disp_info);
+      disp_info->MULE_BASELINE_OFFSET
+       = XInternAtom (display, "_MULE_BASELINE_OFFSET", False);
+      disp_info->AVERAGE_WIDTH
+       = XInternAtom (display, "AVERAGE_WIDTH", False);
       mplist_add (display_info_list, Mt, disp_info);
     }  
 
       mplist_add (display_info_list, Mt, disp_info);
     }  
 
@@ -2061,7 +2279,8 @@ device_open (MFrame *frame, MPlist *param)
       device = (MWDevice *) mplist_value (plist);
       if (device->display_info == disp_info
          && device->depth == depth
       device = (MWDevice *) mplist_value (plist);
       if (device->display_info == disp_info
          && device->depth == depth
-         && device->cmap == cmap)
+         && device->cmap == cmap
+         && device->screen_num == screen_num)
        break;
     }
 
        break;
     }
 
@@ -2071,6 +2290,7 @@ device_open (MFrame *frame, MPlist *param)
     {
       unsigned long valuemask = GCForeground;
       XGCValues values;
     {
       unsigned long valuemask = GCForeground;
       XGCValues values;
+      double pixels, mm;
 
       M17N_OBJECT (device, free_device, MERROR_WIN);
       device->display_info = disp_info;
 
       M17N_OBJECT (device, free_device, MERROR_WIN);
       device->display_info = disp_info;
@@ -2081,8 +2301,12 @@ device_open (MFrame *frame, MPlist *param)
                                        1, 1, depth);
       device->depth = depth;
       device->cmap = cmap;
                                        1, 1, depth);
       device->depth = depth;
       device->cmap = cmap;
+      pixels = DisplayHeight (display, screen_num);
+      mm = DisplayHeightMM (display, screen_num);
+      device->resy = (mm < 1) ? 100 : pixels * 25.4 / mm;
       device->realized_face_list = mplist ();
       device->realized_font_list = mplist ();
       device->realized_face_list = mplist ();
       device->realized_font_list = mplist ();
+      mplist_add (device->realized_font_list, Mt, NULL);
       device->realized_fontset_list = mplist ();
       device->gc_list = mplist ();
       values.foreground = BlackPixel (display, screen_num);
       device->realized_fontset_list = mplist ();
       device->gc_list = mplist ();
       values.foreground = BlackPixel (display, screen_num);
@@ -2097,6 +2321,7 @@ device_open (MFrame *frame, MPlist *param)
 
   frame->device = device;
   frame->device_type = MDEVICE_SUPPORT_OUTPUT | MDEVICE_SUPPORT_INPUT;
 
   frame->device = device;
   frame->device_type = MDEVICE_SUPPORT_OUTPUT | MDEVICE_SUPPORT_INPUT;
+  frame->dpi = device->resy;
   frame->driver = &x_driver;
   frame->font_driver_list = mplist ();
 #ifdef HAVE_XFT2
   frame->driver = &x_driver;
   frame->font_driver_list = mplist ();
 #ifdef HAVE_XFT2
@@ -2111,7 +2336,7 @@ device_open (MFrame *frame, MPlist *param)
     mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
 #endif /* HAVE_FREETYPE */
   if (use_xfont || MPLIST_TAIL_P (frame->font_driver_list))
     mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
 #endif /* HAVE_FREETYPE */
   if (use_xfont || MPLIST_TAIL_P (frame->font_driver_list))
-    mplist_push (frame->font_driver_list, Mx, &xfont_driver);
+    mplist_add (frame->font_driver_list, Mx, &xfont_driver);
 
   frame->realized_font_list = device->realized_font_list;
   frame->realized_face_list = device->realized_face_list;
 
   frame->realized_font_list = device->realized_font_list;
   frame->realized_face_list = device->realized_face_list;
@@ -2144,46 +2369,28 @@ device_open (MFrame *frame, MPlist *param)
       frame->videomode = Mnormal;
     }
 
       frame->videomode = Mnormal;
     }
 
-  {
-    int nfonts, i;
-    /* Try at least 32 fonts to obtain a non-autoscaled font.  */
-    char **names = XListFonts (display, app_data.font, 32, &nfonts);
-    MFont *font = NULL;
-
-    for (i = 0; ! font && i < nfonts; i++)
-      {
-       font = mfont_parse_name (names[i], Mx);
-       if (!font)
-         {
-           /* The font name does not conform to XLFD.  Try to open the
-              font and get XA_FONT property.  */
-           XFontStruct *xfont = XLoadQueryFont (display, names[i]);
-
-           if (xfont)
-             {
-               unsigned long value;
-               char *name;
-
-               if (XGetFontProperty (xfont, XA_FONT, &value)
-                   && (name = ((char *)
-                               XGetAtomName (display, (Atom) value))))
-                 font = mfont_parse_name (name, Mx);
-               XFreeFont (display, xfont);
-             }
-         }
-       if (font &&
-           font->property[MFONT_SIZE] == 0 && font->property[MFONT_RESY] > 0)
-         {
-           free (font);
-           font = NULL;
-         }
-      }
-    if (nfonts)
-      XFreeFontNames (names);
-    frame->font = font ? font : mfont_parse_name (FALLBACK_FONT, Mx);
-  }
+  if (strcmp (app_data.font, DEFAULT_FONT) != 0)
+    {
+      XFontStruct *xfont = XLoadQueryFont (display, app_data.font);
+      unsigned long value;
+      char *name;
 
 
-  face = mface_from_font (frame->font);
+      if (xfont)
+       {
+         font = mfont_parse_name (app_data.font, Mx);
+         if (! font
+             && XGetFontProperty (xfont, XA_FONT, &value)
+             && (name = ((char *) XGetAtomName (display, (Atom) value))))
+           font = mfont_parse_name (name, Mx);
+         XFreeFont (display, xfont);
+       }
+    }
+  if (! font)
+      font = mfont_parse_name (DEFAULT_FONT, Mx);
+  else if (! font->size)
+    font->size = 130;
+  face = mface_from_font (font);
+  free (font);
   face->property[MFACE_FONTSET] = mfontset (NULL);
   face->property[MFACE_FOREGROUND] = frame->foreground;
   face->property[MFACE_BACKGROUND] = frame->background;
   face->property[MFACE_FONTSET] = mfontset (NULL);
   face->property[MFACE_FOREGROUND] = frame->foreground;
   face->property[MFACE_BACKGROUND] = frame->background;
@@ -2200,7 +2407,6 @@ device_open (MFrame *frame, MPlist *param)
   XSetErrorHandler (x_error_handler);
   XSetIOErrorHandler (x_io_error_handler);
 #endif
   XSetErrorHandler (x_error_handler);
   XSetIOErrorHandler (x_io_error_handler);
 #endif
-
   return 0;
 }
 
   return 0;
 }
 
@@ -2395,23 +2601,6 @@ xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
 }
 
 \f
 }
 
 \f
-
-#ifdef X_SET_ERROR_HANDLER
-static int
-x_error_handler (Display *display, XErrorEvent *error)
-{
-  mdebug_hook ();
-  return 0;
-}
-
-static int
-x_io_error_handler (Display *display)
-{
-  mdebug_hook ();
-  return 0;
-}
-#endif
-
 /*=*/
 
 /*** @} */
 /*=*/
 
 /*** @} */
@@ -2420,9 +2609,9 @@ x_io_error_handler (Display *display)
 /* External API */
 
 /*** @addtogroup m17nInputMethodWin */
 /* External API */
 
 /*** @addtogroup m17nInputMethodWin */
-/*=*/
-/*** @{ */
 
 
+/*** @{ */
+/*=*/
 /***en
     @brief Input method driver for XIM.
 
 /***en
     @brief Input method driver for XIM.
 
@@ -2480,8 +2669,14 @@ x_io_error_handler (Display *display)
 MInputDriver minput_xim_driver =
   { xim_open_im, xim_close_im, xim_create_ic, xim_destroy_ic,
     xim_filter, xim_lookup, NULL };
 MInputDriver minput_xim_driver =
   { xim_open_im, xim_close_im, xim_create_ic, xim_destroy_ic,
     xim_filter, xim_lookup, NULL };
-
+/*=*/
 /*** @} */ 
 /*** @} */ 
+/*=*/
+#else  /* not HAVE_X11 */
+
+int device_open () { return -1; }
+
+#endif /* not HAVE_X11 */
 
 /*
   Local Variables:
 
 /*
   Local Variables: