Add bug reference.
[bpt/emacs.git] / src / xftfont.c
index 27fbd72..abe8419 100644 (file)
@@ -38,6 +38,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 /* Xft font driver.  */
 
 static Lisp_Object Qxft;
+static Lisp_Object QChinting , QCautohint, QChintstyle, QCrgba, QCembolden;
 
 /* The actual structure for Xft font that can be casted to struct
    font.  */
@@ -45,13 +46,16 @@ static Lisp_Object Qxft;
 struct xftfont_info
 {
   struct font font;
-  Display *display;
-  int screen;
-  XftFont *xftfont;
+  /* The following three members must be here in this order to be
+     compatible with struct ftfont_info (in ftfont.c).  */
 #ifdef HAVE_LIBOTF
   int maybe_otf;         /* Flag to tell if this may be OTF or not.  */
   OTF *otf;
 #endif /* HAVE_LIBOTF */
+  FT_Size ft_size;
+  Display *display;
+  int screen;
+  XftFont *xftfont;
 };
 
 /* Structure pointed by (struct face *)->extra  */
@@ -143,9 +147,6 @@ static unsigned xftfont_encode_char P_ ((struct font *, int));
 static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
                                     struct font_metrics *));
 static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
-
-static int xftfont_anchor_point P_ ((struct font *, unsigned, int,
-                                    int *, int *));
 static int xftfont_end_for_frame P_ ((FRAME_PTR f));
 
 struct font_driver xftfont_driver;
@@ -174,7 +175,9 @@ xftfont_match (frame, spec)
   return entity;
 }
 
-extern Lisp_Object ftfont_font_format P_ ((FcPattern *));
+extern Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object));
+extern FcCharSet *ftfont_get_fc_charset P_ ((Lisp_Object));
+extern Lisp_Object QCantialias;
 
 static FcChar8 ascii_printable[95];
 
@@ -184,9 +187,10 @@ xftfont_open (f, entity, pixel_size)
      Lisp_Object entity;
      int pixel_size;
 {
+  FcResult result;
   Display *display = FRAME_X_DISPLAY (f);
-  Lisp_Object val, filename, font_object;
-  FcPattern *pat = NULL;
+  Lisp_Object val, filename, index, tail, font_object;
+  FcPattern *pat = NULL, *match;
   struct xftfont_info *xftfont_info = NULL;
   struct font *font;
   double size = 0;
@@ -202,43 +206,99 @@ xftfont_open (f, entity, pixel_size)
     return Qnil;
   val = XCDR (val);
   filename = XCAR (val);
+  index = XCDR (val);
   size = XINT (AREF (entity, FONT_SIZE_INDEX));
   if (size == 0)
     size = pixel_size;
   pat = FcPatternCreate ();
-  FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
+  FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
+  i = FONT_SLANT_NUMERIC (entity) - 100;
+  if (i < 0) i = 0;
+  FcPatternAddInteger (pat, FC_SLANT, i);
+  FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
   FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
-  /*FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);*/
   val = AREF (entity, FONT_FAMILY_INDEX);
   if (! NILP (val))
     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
-  FcConfigSubstitute (NULL, pat, FcMatchPattern);
+  val = AREF (entity, FONT_FOUNDRY_INDEX);
+  if (! NILP (val))
+    FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
+  val = AREF (entity, FONT_SPACING_INDEX);
+  if (! NILP (val))
+    FcPatternAddInteger (pat, FC_SPACING, XINT (val));
+  val = AREF (entity, FONT_DPI_INDEX);
+  if (! NILP (val))
+    {
+      double dbl = XINT (val);
+
+      FcPatternAddDouble (pat, FC_DPI, dbl);
+    }
+  val = AREF (entity, FONT_AVGWIDTH_INDEX);
+  if (INTEGERP (val) && XINT (val) == 0)
+    FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
+  /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
+     over 10x20-ISO8859-1.pcf.gz).  */
+  FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
+
+  for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
+    {
+      Lisp_Object key, val;
+
+      key = XCAR (XCAR (tail)), val = XCDR (XCAR (tail));
+      if (EQ (key, QCantialias))
+       FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QChinting))
+       FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QCautohint))
+       FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
+      else if (EQ (key, QChintstyle))
+       {
+         if (INTEGERP (val))
+           FcPatternAddInteger (pat, FC_RGBA, XINT (val));
+       }
+      else if (EQ (key, QCrgba))
+       {
+         if (INTEGERP (val))
+           FcPatternAddInteger (pat, FC_RGBA, XINT (val));
+       }
+#ifdef FC_EMBOLDEN
+      else if (EQ (key, QCembolden))
+       FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
+#endif
+    }
+
+  FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
+  FcPatternAddInteger (pat, FC_INDEX, XINT (index));
+                      
 
   BLOCK_INPUT;
-  XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
-  xftfont = XftFontOpenPattern (display, pat);
+  match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
+  FcPatternDestroy (pat);
+  xftfont = XftFontOpenPattern (display, match);
+  ft_face = XftLockFace (xftfont);
   UNBLOCK_INPUT;
+
   if (! xftfont)
-    return Qnil;
+    {
+      XftPatternDestroy (match);
+      return Qnil;
+    }
   /* We should not destroy PAT here because it is kept in XFTFONT and
      destroyed automatically when XFTFONT is closed.  */
-  font_object = font_make_object (VECSIZE (struct xftfont_info));
+  font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
   ASET (font_object, FONT_TYPE_INDEX, Qxft);
-  for (i = 1; i < FONT_ENTITY_MAX; i++)
-    ASET (font_object, i, AREF (entity, i));
-  ASET (font_object, FONT_SIZE_INDEX, make_number (size));
   len = font_unparse_xlfd (entity, size, name, 256);
   if (len > 0)
-    ASET (font_object, FONT_NAME_INDEX, make_unibyte_string (name, len));
+    ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
   len = font_unparse_fcname (entity, size, name, 256);
   if (len > 0)
-    ASET (font_object, FONT_FULLNAME_INDEX, make_unibyte_string (name, len));
+    ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
   else
     ASET (font_object, FONT_FULLNAME_INDEX,
          AREF (font_object, FONT_NAME_INDEX));
   ASET (font_object, FONT_FILE_INDEX, filename);
   ASET (font_object, FONT_FORMAT_INDEX,
-       ftfont_font_format (xftfont->pattern));
+       ftfont_font_format (xftfont->pattern, filename));
   font = XFONT_OBJECT (font_object);
   font->pixel_size = pixel_size;
   font->driver = &xftfont_driver;
@@ -280,14 +340,19 @@ xftfont_open (f, entity, pixel_size)
   UNBLOCK_INPUT;
 
   font->ascent = xftfont->ascent;
-  if (font->ascent < extents.y)
-    font->ascent = extents.y;
   font->descent = xftfont->descent;
-  if (font->descent < extents.height - extents.y)
-    font->descent = extents.height - extents.y;
+  if (pixel_size >= 5)
+    {
+      /* The above condition is a dirty workaround because
+        XftTextExtents8 behaves strangely for some fonts
+        (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */
+      if (font->ascent < extents.y)
+       font->ascent = extents.y;
+      if (font->descent < extents.height - extents.y)
+       font->descent = extents.height - extents.y;
+    }
   font->height = font->ascent + font->descent;
 
-  ft_face = XftLockFace (xftfont);
   if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
     {
       int upEM = ft_face->units_per_EM;
@@ -306,7 +371,7 @@ xftfont_open (f, entity, pixel_size)
   xftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
   xftfont_info->otf = NULL;
 #endif /* HAVE_LIBOTF */
-  XftUnlockFace (xftfont);
+  xftfont_info->ft_size = ft_face->size;
 
   /* Unfortunately Xft doesn't provide a way to get minimum char
      width.  So, we use space_width instead.  */
@@ -316,6 +381,22 @@ xftfont_open (f, entity, pixel_size)
   font->relative_compose = 0;
   font->default_ascent = 0;
   font->vertical_centering = 0;
+#ifdef FT_BDF_H
+  if (! (ft_face->face_flags & FT_FACE_FLAG_SFNT))
+    {
+      BDF_PropertyRec rec;
+
+      if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &rec) == 0
+         && rec.type == BDF_PROPERTY_TYPE_INTEGER)
+       font->baseline_offset = rec.u.integer;
+      if (FT_Get_BDF_Property (ft_face, "_MULE_RELATIVE_COMPOSE", &rec) == 0
+         && rec.type == BDF_PROPERTY_TYPE_INTEGER)
+       font->relative_compose = rec.u.integer;
+      if (FT_Get_BDF_Property (ft_face, "_MULE_DEFAULT_ASCENT", &rec) == 0
+         && rec.type == BDF_PROPERTY_TYPE_INTEGER)
+       font->default_ascent = rec.u.integer;
+    }
+#endif
 
   return font_object;
 }
@@ -332,6 +413,7 @@ xftfont_close (f, font)
     OTF_close (xftfont_info->otf);
 #endif
   BLOCK_INPUT;
+  XftUnlockFace (xftfont_info->xftfont);
   XftFontClose (xftfont_info->display, xftfont_info->xftfont);
   UNBLOCK_INPUT;
 }
@@ -486,32 +568,6 @@ xftfont_draw (s, from, to, x, y, with_background)
   return len;
 }
 
-static int
-xftfont_anchor_point (font, code, index, x, y)
-     struct font *font;
-     unsigned code;
-     int index;
-     int *x, *y;
-{
-  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
-  FT_Face ft_face = XftLockFace (xftfont_info->xftfont);
-  int result;
-
-  if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
-    result = -1;
-  else if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
-    result = -1;
-  else if (index >= ft_face->glyph->outline.n_points)
-    result = -1;
-  else
-    {
-      *x = ft_face->glyph->outline.points[index].x;
-      *y = ft_face->glyph->outline.points[index].y;
-    }
-  XftUnlockFace (xftfont_info->xftfont);
-  return result;
-}
-
 static int
 xftfont_end_for_frame (f)
      FRAME_PTR f;
@@ -528,48 +584,15 @@ xftfont_end_for_frame (f)
   return 0;
 }
 
-#ifdef HAVE_LIBOTF
-#ifdef HAVE_M17N_FLT
-static Lisp_Object
-xftfont_shape (lgstring)
-     Lisp_Object lgstring;
-{
-  struct font *font;
-  struct xftfont_info *xftfont_info;
-  Lisp_Object result;
-  FT_Face ft_face;
-
-  CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
-  xftfont_info = (struct xftfont_info *) font;
-  if (! xftfont_info->maybe_otf)
-    return Qnil;
-  ft_face = XftLockFace (xftfont_info->xftfont);
-  if (! xftfont_info->otf)
-    {
-      OTF *otf = OTF_open_ft_face (ft_face);
-
-      if (! otf || OTF_get_table (otf, "head") < 0)
-       {
-         if (otf)
-           OTF_close (otf);
-         xftfont_info->maybe_otf = 0;
-         XftUnlockFace (xftfont_info->xftfont);
-         return Qnil;
-       }
-      xftfont_info->otf = otf;
-    }
-
-  result = ftfont_shape_by_flt (lgstring, font, ft_face, xftfont_info->otf);
-  XftUnlockFace (xftfont_info->xftfont);
-  return result;
-}
-#endif /* HAVE_M17N_FLT */
-#endif /* HAVE_LIBOTF */
-
 void
 syms_of_xftfont ()
 {
   DEFSYM (Qxft, "xft");
+  DEFSYM (QChinting, ":hinting");
+  DEFSYM (QCautohint, ":autohint");
+  DEFSYM (QChintstyle, ":hintstyle");
+  DEFSYM (QCrgba, ":rgba");
+  DEFSYM (QCembolden, ":embolden");
 
   xftfont_driver = ftfont_driver;
   xftfont_driver.type = Qxft;
@@ -583,13 +606,7 @@ syms_of_xftfont ()
   xftfont_driver.encode_char = xftfont_encode_char;
   xftfont_driver.text_extents = xftfont_text_extents;
   xftfont_driver.draw = xftfont_draw;
-  xftfont_driver.anchor_point = xftfont_anchor_point;
   xftfont_driver.end_for_frame = xftfont_end_for_frame;
-#ifdef HAVE_LIBOTF
-#ifdef HAVE_M17N_FLT
-  xftfont_driver.shape = xftfont_shape;
-#endif /* HAVE_M17N_FLT */
-#endif /* HAVE_LIBOTF */
 
   register_font_driver (&xftfont_driver, NULL);
 }