*** empty log message ***
[m17n/m17n-lib.git] / src / m17n-X.c
index e3413cb..3bb06f4 100644 (file)
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307, USA.  */
 
+#include "config.h"
+
+#ifdef HAVE_X11
+
 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
 /*** @addtogroup m17nInternal
      @{ */
 
-#include "config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -102,6 +104,9 @@ typedef struct
   int alt_mask;
   int super_mask;
   int hyper_mask;
+
+  Atom MULE_BASELINE_OFFSET;
+  Atom AVERAGE_WIDTH;
 } MDisplayInfo;
 
 /* Anchor of the chain of MDisplayInfo objects.  */
@@ -156,6 +161,8 @@ typedef struct
 
   GC scratch_gc;
 
+  int resy;
+
 #ifdef HAVE_XFT2
   XftDraw *xft_draw;
 #endif
@@ -436,12 +443,13 @@ 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)
@@ -460,6 +468,7 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
   int nfonts;
   int i, j;
   MFont font;
+  int for_full_width;
 
   plist = mplist_get (font_list, registry);
   if (plist)
@@ -470,6 +479,14 @@ xfont_registry_list (MFrame *frame, MSymbol 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);
@@ -514,6 +531,7 @@ xfont_registry_list (MFrame *frame, MSymbol registry)
                sizes[nsizes++] = size;
            }
 
+       font.for_full_width = for_full_width;
        font.type = MFONT_TYPE_OBJECT;
        font.source = MFONT_SOURCE_X;
        MSTRUCT_CALLOC (fontx, MERROR_WIN);
@@ -607,7 +625,7 @@ 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);
@@ -615,6 +633,18 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   int mdebug_mask = MDEBUG_FONT;
   MFont this;
 
+  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)
     {
       for (; rfont; rfont = rfont->next)
@@ -622,7 +652,6 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
          return rfont;
     }
 
-
   this = *font;
   this.size = size;
   /* This never fail to generate a valid fontname.  */
@@ -648,6 +677,20 @@ xfont_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   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 : 0);
+    rfont->average_width
+      = (XGetFontProperty (xfont, disp_info->AVERAGE_WIDTH, &value)
+        ? (int) value / 10 : 0);
+  }
+  rfont->ascent = xfont->ascent + rfont->baseline_offset;
+  rfont->descent = xfont->descent - rfont->baseline_offset;
+  rfont->max_advance = xfont->max_bounds.width;
   rfont->fontp = xfont;
   rfont->next = MPLIST_VAL (frame->realized_font_list);
   MPLIST_VAL (frame->realized_font_list) = rfont;
@@ -725,6 +768,8 @@ xfont_find_metric (MRealizedFont *rfont, MGlyphString *gstring,
              g->descent = xfont->descent;
            }
        }
+      g->ascent += rfont->baseline_offset;
+      g->descent -= rfont->baseline_offset;
     }
 }
 
@@ -813,10 +858,12 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
   GC gc = ((GCInfo *) rface->info)->gc[reverse ? GC_INVERSE : GC_NORMAL];
   MGlyph *g;
   int i;
+  int baseline_offset;
 
   if (from == to)
     return;
 
+  baseline_offset = rface->rfont->baseline_offset;
   if (region)
     gc = set_region (rface->frame, gc, region);
   XSetFont (display, gc, ((XFontStruct *) rface->rfont->fontp)->fid);
@@ -859,7 +906,8 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
       else if (g->xoff != 0 || g->yoff != 0 || g->right_padding)
        {
          XDrawString16 (display, (Window) win, gc,
-                        x + g->xoff, y + g->yoff, code + (g - from), 1);
+                        x + g->xoff, y + g->yoff - baseline_offset,
+                        code + (g - from), 1);
          x += g->width;
          g++;
        }
@@ -872,8 +920,8 @@ xfont_render (MDrawWindow win, int x, int y, MGlyphString *gstring,
               g < to && g->type == GLYPH_CHAR && g->xoff == 0 && g->yoff == 0;
               i++, g++)
              x += g->width;
-         XDrawString16 (display, (Window) win, gc, orig_x, y,
-                        code + code_idx, i);
+         XDrawString16 (display, (Window) win, gc,
+                        orig_x, y - baseline_offset, code + code_idx, i);
        }
     }
 }
@@ -957,6 +1005,55 @@ xfont_list (MFrame *frame, MPlist *plist, MFont *font, int maxnum)
   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;
+         if (strcmp (MSYMBOL_NAME (sym), fam) > 0)
+           {
+             mplist_push (p, Msymbol, family);
+             break;
+           }
+       }
+      if (MPLIST_TAIL_P (p))
+       mplist_push (p, Msymbol, family);
+    }
+  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
 /* Xft Handler */
 
@@ -982,10 +1079,13 @@ 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);
+static int xft_check_capability (MRealizedFont *rfont, MSymbol capability);
 
-MFontDriver xft_driver =
+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
+  };
 
 static void
 close_xft (void *object)
@@ -1025,8 +1125,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, 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)
     {
@@ -1048,6 +1161,11 @@ xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   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);
@@ -1064,10 +1182,16 @@ xft_open (MFrame *frame, MFont *font, MFont *spec, MRealizedFont *rfont)
   M17N_OBJECT_REF (rfont->info);
   MSTRUCT_CALLOC (rfont, MERROR_FONT_X);
   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->fontp = xft_font;
   rfont->next = MPLIST_VAL (frame->realized_font_list);
   MPLIST_VAL (frame->realized_font_list) = rfont;
@@ -1203,6 +1327,7 @@ xft_render (MDrawWindow win, int x, int y,
   XftDrawChange (xft_draw, (Drawable) win);
   XftDrawSetClip (xft_draw, (Region) region);
       
+  y -= rfont->baseline_offset;
   glyphs = alloca (sizeof (FT_UInt) * (to - from));
   for (last_x = x, nglyphs = 0, g = from; g < to; x += g++->width)
     {
@@ -1223,6 +1348,18 @@ xft_render (MDrawWindow win, int x, int y,
     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;
+}
+
 #endif /* HAVE_XFT2 */
 
 \f
@@ -1669,6 +1806,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);
 }
 
@@ -1931,6 +2074,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");
@@ -2087,6 +2231,10 @@ device_open (MFrame *frame, MPlist *param)
       disp_info->auto_display = auto_display;
       disp_info->font_list = mplist ();
       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);
     }  
 
@@ -2096,7 +2244,8 @@ device_open (MFrame *frame, MPlist *param)
       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;
     }
 
@@ -2106,6 +2255,7 @@ device_open (MFrame *frame, MPlist *param)
     {
       unsigned long valuemask = GCForeground;
       XGCValues values;
+      double pixels, mm;
 
       M17N_OBJECT (device, free_device, MERROR_WIN);
       device->display_info = disp_info;
@@ -2116,6 +2266,9 @@ device_open (MFrame *frame, MPlist *param)
                                        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 ();
       mplist_add (device->realized_font_list, Mt, NULL);
@@ -2133,6 +2286,7 @@ device_open (MFrame *frame, MPlist *param)
 
   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
@@ -2420,7 +2574,7 @@ xim_lookup (MInputContext *ic, MSymbol key, void *arg, MText *mt)
 /* External API */
 
 /*** @addtogroup m17nInputMethodWin */
-/*=*/
+
 /*** @{ */
 
 /***en
@@ -2483,6 +2637,12 @@ MInputDriver minput_xim_driver =
 
 /*** @} */ 
 
+#else  /* not HAVE_X11 */
+
+int device_open () { return -1; }
+
+#endif /* not HAVE_X11 */
+
 /*
   Local Variables:
   coding: euc-japan