(MDisplayInfo): New member altgr_mask.
[m17n/m17n-lib.git] / src / m17n-X.c
index f45473b..09f57ca 100644 (file)
@@ -1,5 +1,5 @@
 /* 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
 
@@ -17,7 +17,7 @@
 
    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.  */
 
 #include "config.h"
 #include "fontset.h"
 #include "face.h"
 
-typedef struct _MFontX MFontX;
-
-struct _MFontX 
-{
-  /* Record a font of the smallest pixel size.  */
-  MFont core;
-  /* Nth bit tells the existence of a font of size N + 5.  So this is
-     for 5..36 pixel size fonts.  Usually this covers all sizes.  */
-  unsigned int size5_36;
-  /* Fonts of (size < 5 || size > 36) are listed here (except for a
-     scalable whose size is 0).  */
-  MFontX *next;
-};
-
-/* S must satisfy the condition (S >= 5 && S < 36).  */
-
-#define SET_SIZE(FONTX, S) ((FONTX)->size5_36 |= (1 << ((S) - 5)))
-
-#define HAVE_SIZE(FONTX, S) ((FONTX)->size5_36 & (1 << ((S) - 5)))
-
 typedef struct
 {
   /* Common header for the m17n object.  */
@@ -92,7 +72,7 @@ typedef struct
 
   /** 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 MFontX.  */
+      values are pointers to MFont.  */
   MPlist *font_list;
 
   /** Nonzero means that <font_list> already contains all available
@@ -104,8 +84,10 @@ typedef struct
   int alt_mask;
   int super_mask;
   int hyper_mask;
+  int altgr_mask;
 
   Atom MULE_BASELINE_OFFSET;
+  Atom AVERAGE_WIDTH;
 } MDisplayInfo;
 
 /* Anchor of the chain of MDisplayInfo objects.  */
@@ -210,15 +192,7 @@ free_display_info (void *object)
   MPLIST_DO (plist, disp_info->font_list)
     {
       MPLIST_DO (pl, MPLIST_VAL (plist))
-       {
-         MFontX *fontx, *next;
-
-         for (fontx = MPLIST_VAL (pl); fontx; fontx = next)
-           {
-             next = fontx->next;
-             free (fontx);
-           }
-       }
+       free (MPLIST_VAL (pl));
       M17N_OBJECT_UNREF (MPLIST_VAL (plist));
     }
   M17N_OBJECT_UNREF (disp_info->font_list);
@@ -285,6 +259,9 @@ find_modifier_bits (MDisplayInfo *disp_info)
   KeyCode super_r = XKeysymToKeycode (display, XK_Super_R);
   KeyCode hyper_l = XKeysymToKeycode (display, XK_Hyper_L);
   KeyCode hyper_r = XKeysymToKeycode (display, XK_Hyper_R);
+#ifdef XK_XKB_KEYS
+  KeyCode altgr = XKeysymToKeycode (display, XK_ISO_Level3_Shift);
+#endif
   int i, j;
 
   mods = XGetModifierMapping (display);
@@ -305,6 +282,10 @@ find_modifier_bits (MDisplayInfo *disp_info)
          disp_info->super_mask |= (1 << i);
        else if (code == hyper_l || code == hyper_r)
          disp_info->hyper_mask |= (1 << i);
+#ifdef XK_XKB_KEYS
+       else if (code == altgr)
+         disp_info->altgr_mask |= (1 << i);
+#endif
       }
 
   /* If meta keys are not in any modifier, use alt keys as meta
@@ -442,12 +423,14 @@ static unsigned xfont_encode_char (MFrame *, MFont *, MFont *, unsigned);
 static void xfont_render (MDrawWindow, int, int, MGlyphString *,
                          MGlyph *, MGlyph *, int, MDrawRegion);
 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,
     xfont_find_metric, xfont_has_char, xfont_encode_char,
-    xfont_render, xfont_list };
+    xfont_render, xfont_list, xfont_list_family_names, xfont_check_capability
+  };
 
 static int
 font_compare (const void *p1, const void *p2)
@@ -471,7 +454,7 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
   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);
@@ -489,24 +472,20 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
   memcpy (names, font_names, sizeof (char *) * nfonts);
   qsort (names, nfonts, sizeof (char *), font_compare);
   MFONT_INIT (&font);
-  for (i = 0, p = NULL; i < nfonts; i++)
+  for (i = 0; i < nfonts; i++)
     if (mfont__parse_name_into_font (names[i], Mx, &font) == 0
-       && (font.size >= 50 || font.property[MFONT_RESY] == 0))
+       && (font.size > 0 || font.property[MFONT_RESY] == 0))
       {
        MSymbol family = FONT_PROPERTY (&font, MFONT_FAMILY);
-       MFontX *fontx, *fontx2;
+       MFont *fontx;
        unsigned sizes[256];
        int nsizes = 0;
-       int size, smallest;
+       int limit;
+       int size, normal_size;
        char *base_end;
        int base_len;
        int fields;
        
-       if (p && MPLIST_KEY (p) != family)
-         p = mplist_find_by_key (plist, family);
-       if (! p)
-         p = mplist_push (plist, family, NULL);
-
        /* 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++)
@@ -515,44 +494,44 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
            break;
        base_len = base_end - names[i] + 1;
 
-       size = smallest = font.size / 10;
+       size = font.size / 10;
        sizes[nsizes++] = size;
-       for (j = i + 1; j < nfonts && ! strncmp (names[i], names[j], base_len);
+       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++)
          if (mfont__parse_name_into_font (names[j], Mx, &font) == 0
-             && (font.size >= 50 || font.property[MFONT_RESY] == 0))
+             && (font.size > 0 || font.property[MFONT_RESY] == 0))
            {
              size = font.size / 10;
-             if (size < smallest)
-               smallest = size;
-             if (nsizes < 256)
-               sizes[nsizes++] = size;
+             sizes[nsizes++] = size;
+             normal_size |= (size >= 6 && size <= 29);
            }
 
        font.for_full_width = for_full_width;
        font.type = MFONT_TYPE_OBJECT;
        font.source = MFONT_SOURCE_X;
-       MSTRUCT_CALLOC (fontx, MERROR_WIN);
-       fontx->core = font;
-       fontx->core.size = smallest * 10;
-       fontx->next = MPLIST_VAL (p);
-       MPLIST_VAL (p) = fontx;
-       if (smallest > 0)
-         for (j = 0; j < nsizes; j++)
+       if (normal_size)
+         {
+           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)
            {
-             if (sizes[j] <= 36)
-               {
-                 if (sizes[j] != smallest)
-                   SET_SIZE (fontx, sizes[j]);
-               }
-             else
-               {
-                 MSTRUCT_CALLOC (fontx2, MERROR_WIN);
-                 fontx2->core = font;
-                 fontx2->core.size = sizes[j] * 10;
-                 fontx2->next = MPLIST_VAL (p);
-                 MPLIST_VAL (p) = fontx2;
-               }
+             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);
@@ -623,14 +602,49 @@ close_xfont (void *object)
 static MRealizedFont *
 xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
 {
-  int size = spec->size;
+  int size;
   MRealizedFontX *x_rfont;
   char *name;
   Display *display = FRAME_DISPLAY (frame);
   XFontStruct *xfont;
-  int mdebug_mask = MDEBUG_FONT;
+  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)
@@ -639,6 +653,7 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
     }
 
   this = *font;
+  this.multiple_sizes = 0;
   this.size = size;
   /* This never fail to generate a valid fontname.  */
   name = mfont_unparse_name (&this, Mx);
@@ -650,12 +665,11 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
       font->type = MFONT_TYPE_FAILURE;
       return NULL;
     }
-  MDEBUG_PRINT1 (" [XFONT] o %s\n", name);
-  free (name);
   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;
@@ -669,14 +683,20 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
 
     rfont->baseline_offset
       = (XGetFontProperty (xfont, disp_info->MULE_BASELINE_OFFSET, &value)
-        ? (int) value : 0);
+        ? (int) (value << 6) : 0);
+    rfont->average_width
+      = (XGetFontProperty (xfont, disp_info->AVERAGE_WIDTH, &value)
+        ? (int) (value << 6) / 10 : 0);
   }
-  rfont->ascent = xfont->ascent + rfont->baseline_offset;
-  rfont->descent = xfont->descent - rfont->baseline_offset;
-  rfont->max_advance = xfont->max_bounds.width;
+  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);
   return rfont;
 }
 
@@ -691,69 +711,72 @@ xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
   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;
-           }
-       }
-      g->ascent += rfont->baseline_offset;
-      g->descent -= rfont->baseline_offset;
-    }
+           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;
+      }
 }
 
 
@@ -777,11 +800,9 @@ xfont_encode_char (MFrame *frame, MFont *font, MFont *spec, unsigned code)
     rfont = (MRealizedFont *) font;
   else if (font->type == MFONT_TYPE_OBJECT)
     {
-      int size = spec->size;
-
       for (rfont = MPLIST_VAL (frame->realized_font_list); rfont;
           rfont = rfont->next)
-       if (rfont->font == font && rfont->spec.size == size)
+       if (rfont->font == font)
          break;
       if (! rfont)
        {
@@ -846,35 +867,35 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
   if (from == to)
     return;
 
-  baseline_offset = rface->rfont->baseline_offset;
+  baseline_offset = rface->rfont->baseline_offset >> 6;
   if (region)
     gc = set_region (rface->frame, gc, region);
   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[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)
-       x += g++->width;
+       x += g++->g.xadv;
       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)
        {
-         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.  */
-             int box_width = g->width;
+             int box_width = g->g.xadv;
              int box_height = gstring->ascent + gstring->descent;
 
              if (box_width > 4)
@@ -883,15 +904,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);
-             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,
-                        x + g->xoff, y + g->yoff - baseline_offset,
+                        x + g->g.xoff, y + g->g.yoff - baseline_offset,
                         code + (g - from), 1);
-         x += g->width;
+         x += g->g.xadv;
          g++;
        }
       else
@@ -900,9 +921,9 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
          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++)
-             x += g->width;
+             x += g->g.xadv;
          XDrawString16 (display, (Window) win, gc,
                         orig_x, y - baseline_offset, code + code_idx, i);
        }
@@ -918,7 +939,7 @@ xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
   int size = font ? font->size : 0;
   MPlist *pl, *p;
   int num = 0;
-  int mdebug_mask = MDEBUG_FONT;
+  int mdebug_flag = MDEBUG_FONT;
 
   MDEBUG_PRINT2 (" [X-FONT] listing %s-%s...",
                 family ? msymbol_name (family) : "*",
@@ -930,62 +951,86 @@ xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
     xfont_registry_list (frame, registry);
 
   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))
+           {
+             MFont *fontx = MPLIST_VAL (p);
+
+             if (! font || (mfont__match_p (fontx, font, MFONT_REGISTRY)))
+               {
+                 if (fontx->size != 0 && size)
+                   {
+                     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;
+               }
+           }
+      }
+
+ 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++)
     {
-      if (registry != Mnil && registry != MPLIST_KEY (pl))
+      MSymbol family;
+      char foundry[256], fam[256];
+      MPlist *p;
+      
+      if (sscanf (font_names[i], "-%s-%s-", foundry, fam) < 2)
        continue;
-      MPLIST_DO (p, MPLIST_VAL (pl))
-       {
-         MFontX *fontx;
+      family = msymbol (fam);
+      if (family == last_family)
+       continue;
+      last_family = family;
 
-         if (family != Mnil && family != MPLIST_KEY (p))
-           continue;
-         for (fontx = MPLIST_VAL (p); fontx; fontx = fontx->next)
-           if (! font
-               || (mfont__match_p (&fontx->core, font, MFONT_REGISTRY)))
-             {
-               if (fontx->core.size == size
-                   || fontx->core.size == 0)
-                 {
-                   mplist_push (plist, MPLIST_KEY (p), fontx);
-                   num++;
-                 }
-               else if (size == 0
-                        || (size <= 360 && HAVE_SIZE (fontx, (size / 10))))
-                 {
-                   unsigned size5_36 = fontx->size5_36;
-                   MFontX *fontx2;
-                   int i;
+      MPLIST_DO (p, plist)
+       {
+         MSymbol sym = MPLIST_SYMBOL (p);
 
-                   fontx->size5_36 = 0;
-                   for (i = fontx->core.size / 10; i <= 36; i++)
-                     if (size5_36 & (1 << (i - 5)))
-                       {
-                         MSTRUCT_CALLOC (fontx2, MERROR_WIN);
-                         fontx2->core = fontx->core;
-                         fontx2->core.size = i * 10;
-                         fontx2->next = fontx->next;
-                         fontx->next = fontx2;
-                         fontx = fontx2;
-                         if ((size == 0 || size == fontx->core.size)
-                             && (maxnum == 0 || num < maxnum))
-                           {
-                             mplist_push (plist, MPLIST_KEY (p), fontx);
-                             num++;
-                           }
-                       }
-                 }
-               if (maxnum > 0 && maxnum == num)
-                 break;
-             }
-         if (maxnum > 0 && maxnum == num)
+         if (sym == family)
            break;
+         if (strcmp (MSYMBOL_NAME (sym), fam) > 0)
+           {
+             mplist_push (p, Msymbol, family);
+             break;
+           }
        }
-      if (maxnum > 0 && maxnum == num)
-       break;
+      if (MPLIST_TAIL_P (p))
+       mplist_push (p, Msymbol, family);
     }
+  if (font_names)
+    XFreeFontNames (font_names);
+}
 
-  MDEBUG_PRINT1 (" %d found\n", num);
-  return num;
+static int 
+xfont_check_capability (MRealizedFont *rfont, MSymbol capability)
+{
+  /* Currently X font driver doesn't support any capability.  */
+  return -1;
 }
 
 \f
@@ -996,10 +1041,10 @@ xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
 typedef struct
 {
   M17NObject control;
+  FT_Face ft_face;             /* This must be the 2nd member. */
   Display *display;
   XftFont *font_aa;
   XftFont *font_no_aa;
-  FT_Face ft_face;
   /* Pointer to MRealizedFontFT */
   void *info;
 } MRealizedFontXft;
@@ -1013,10 +1058,26 @@ static unsigned xft_encode_char (MFrame *frame, MFont *font, MFont *spec,
 static void xft_find_metric (MRealizedFont *, MGlyphString *, int, int);
 static void xft_render (MDrawWindow, int, int, MGlyphString *,
                        MGlyph *, MGlyph *, int, MDrawRegion);
-
-MFontDriver xft_driver =
+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 };
+    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)
@@ -1056,9 +1117,21 @@ xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   FT_Face ft_face;
   MRealizedFontXft *rfont_xft;
   FcBool anti_alias = FRAME_DEVICE (frame)->depth > 1 ? FcTrue : FcFalse;
-  double size = font->size ? font->size : spec->size;
+  int size;
   XftFont *xft_font;
-  int ascent, descent, max_advance, baseline_offset;
+  int ascent, descent, max_advance, average_width, baseline_offset;
+
+  if (font->size)
+    /* non-scalable font */
+    size = font->size;
+  else if (spec->size)
+    {
+      int ratio = mfont_resize_ratio (font);
+
+      size = ratio == 100 ? spec->size : spec->size * ratio / 100;
+    }
+  else
+    size = 120;
 
   if (rfont)
     {
@@ -1083,6 +1156,7 @@ xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   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;
@@ -1099,7 +1173,9 @@ xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   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;
@@ -1107,7 +1183,10 @@ xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   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;
@@ -1123,27 +1202,30 @@ xft_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
   MGlyph *g = MGLYPH (from), *gend = MGLYPH (to);
 
   for (; g != gend; g++)
-    {
-      if (g->code == MCHAR_INVALID_CODE)
-       {
-         g->lbearing = 0;
-         g->rbearing = xft_font->max_advance_width;
-         g->width = g->rbearing;
-         g->ascent = xft_font->ascent;
-         g->descent = xft_font->descent;
-       }
-      else
-       {
-         XGlyphInfo extents;
-
-         XftGlyphExtents (display, xft_font, &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;
-       }
-    }
+    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;
+      }
 }
 
 static int
@@ -1243,12 +1325,12 @@ xft_render (MDrawWindow win, int x, int y,
   XftDrawChange (xft_draw, (Drawable) win);
   XftDrawSetClip (xft_draw, (Region) region);
       
-  y -= rfont->baseline_offset;
+  y -= rfont->baseline_offset >> 6;
   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)
@@ -1256,14 +1338,80 @@ xft_render (MDrawWindow win, int x, int y,
                           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);
 }
 
+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
@@ -1429,9 +1577,9 @@ mwin__draw_empty_boxes (MDrawWindow win, int x, int y,
   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);
-      x += from->width;
+      x += from->g.xadv;
     }
 }
 
@@ -1492,9 +1640,9 @@ mwin__draw_box (MFrame *frame, MDrawWindow win, MGlyphString *gstring,
       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
-       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++)
@@ -1710,6 +1858,12 @@ mwin__create_window (MFrame *frame, MDrawWindow parent)
 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);
 }
 
@@ -1859,7 +2013,7 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
   int len;
   char buf[512];
   KeySym keysym;
-  MSymbol key = Mnil;
+  MSymbol key;
 
   *modifiers = 0;
   if (event->xany.type != KeyPress
@@ -1869,26 +2023,21 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
   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;
+#ifdef XK_XKB_KEYS
+  if ((keysym & 0xff00) == 0xfe00)
+    return Mnil;
+#endif
+  if (len == 1 && keysym >= XK_space && keysym <= XK_asciitilde)
     {
       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);
+      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);
 
@@ -1897,9 +2046,9 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
       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)
@@ -1908,7 +2057,10 @@ mwin__parse_event (MFrame *frame, void *arg, int *modifiers)
     *modifiers |= MINPUT_KEY_SUPER_MODIFIER;
   if (((XKeyEvent *) event)->state & disp_info->hyper_mask)
     *modifiers |= MINPUT_KEY_HYPER_MODIFIER;
-
+#ifdef XK_XKB_KEYS
+  if (((XKeyEvent *) event)->state & disp_info->altgr_mask)
+    *modifiers |= MINPUT_KEY_ALTGR_MODIFIER;
+#endif
   return key;
 }
 
@@ -1972,6 +2124,7 @@ device_init ()
 #ifdef HAVE_XFT2
   xft_driver.select = mfont__ft_driver.select;
   xft_driver.list = mfont__ft_driver.list;
+  xft_driver.list_family_names = mfont__ft_driver.list_family_names;
 #endif
 
   Mxim = msymbol ("xim");
@@ -2130,6 +2283,8 @@ device_open (MFrame *frame, MPlist *param)
       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);
     }  
 
@@ -2196,7 +2351,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_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;
@@ -2471,7 +2626,7 @@ xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
 /*** @addtogroup m17nInputMethodWin */
 
 /*** @{ */
-
+/*=*/
 /***en
     @brief Input method driver for XIM.
 
@@ -2529,9 +2684,9 @@ xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
 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; }