]> code.delx.au - gnu-emacs/blobdiff - src/xftfont.c
Merge from origin/emacs-25
[gnu-emacs] / src / xftfont.c
index 166a70acd850f55e7fcb457fb203f3af932407bb..7926325419c10195d8a8681579f7e1009216a0fc 100644 (file)
@@ -1,5 +1,5 @@
 /* xftfont.c -- XFT font driver.
-   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Copyright (C) 2006-2016 Free Software Foundation, Inc.
    Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H13PRO009
@@ -8,8 +8,8 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,24 +25,18 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <X11/Xft/Xft.h>
 
 #include "lisp.h"
-#include "dispextern.h"
 #include "xterm.h"
 #include "frame.h"
 #include "blockinput.h"
-#include "character.h"
 #include "charset.h"
 #include "composite.h"
-#include "fontset.h"
 #include "font.h"
 #include "ftfont.h"
 
 /* Xft font driver.  */
 
-Lisp_Object Qxft;
-static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden,
-  QClcdfilter;
 
-/* The actual structure for Xft font that can be casted to struct
+/* The actual structure for Xft font that can be cast to struct
    font.  */
 
 struct xftfont_info
@@ -58,8 +52,8 @@ struct xftfont_info
   int index;
   FT_Matrix matrix;
   Display *display;
-  int screen;
   XftFont *xftfont;
+  unsigned x_display_id;
 };
 
 /* Structure pointed by (struct face *)->extra  */
@@ -70,17 +64,14 @@ struct xftface_info
   XftColor xft_bg;             /* color for face->background */
 };
 
-static void xftfont_get_colors (FRAME_PTR, struct face *, GC gc,
-                                struct xftface_info *,
-                                XftColor *fg, XftColor *bg);
-
-
 /* Setup foreground and background colors of GC into FG and BG.  If
    XFTFACE_INFO is not NULL, reuse the colors in it if possible.  BG
    may be NULL.  */
 
 static void
-xftfont_get_colors (FRAME_PTR f, struct face *face, GC gc, struct xftface_info *xftface_info, XftColor *fg, XftColor *bg)
+xftfont_get_colors (struct frame *f, struct face *face, GC gc,
+                   struct xftface_info *xftface_info,
+                   XftColor *fg, XftColor *bg)
 {
   if (xftface_info && face->gc == gc)
     {
@@ -91,7 +82,7 @@ xftfont_get_colors (FRAME_PTR f, struct face *face, GC gc, struct xftface_info *
   else
     {
       XGCValues xgcv;
-      bool fg_done = 0, bg_done = 0;
+      bool fg_done = false, bg_done = false;
 
       block_input ();
       XGetGCValues (FRAME_X_DISPLAY (f), gc,
@@ -99,15 +90,15 @@ xftfont_get_colors (FRAME_PTR f, struct face *face, GC gc, struct xftface_info *
       if (xftface_info)
        {
          if (xgcv.foreground == face->foreground)
-           *fg = xftface_info->xft_fg, fg_done = 1;
+           *fg = xftface_info->xft_fg, fg_done = true;
          else if (xgcv.foreground == face->background)
-           *fg = xftface_info->xft_bg, fg_done = 1;
+           *fg = xftface_info->xft_bg, fg_done = true;
          if (! bg)
-           bg_done = 1;
+           bg_done = true;
          else if (xgcv.background == face->background)
-           *bg = xftface_info->xft_bg, bg_done = 1;
+           *bg = xftface_info->xft_bg, bg_done = true;
          else if (xgcv.background == face->foreground)
-           *bg = xftface_info->xft_fg, bg_done = 1;
+           *bg = xftface_info->xft_fg, bg_done = true;
        }
 
       if (! (fg_done & bg_done))
@@ -117,8 +108,7 @@ xftfont_get_colors (FRAME_PTR f, struct face *face, GC gc, struct xftface_info *
          colors[0].pixel = fg->pixel = xgcv.foreground;
          if (bg)
            colors[1].pixel = bg->pixel = xgcv.background;
-         XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors,
-                       bg ? 2 : 1);
+         x_query_colors (f, colors, bg ? 2 : 1);
          fg->color.alpha = 0xFFFF;
          fg->color.red = colors[0].red;
          fg->color.green = colors[0].green;
@@ -139,9 +129,9 @@ xftfont_get_colors (FRAME_PTR f, struct face *face, GC gc, struct xftface_info *
 struct font_driver xftfont_driver;
 
 static Lisp_Object
-xftfont_list (Lisp_Object frame, Lisp_Object spec)
+xftfont_list (struct frame *f, Lisp_Object spec)
 {
-  Lisp_Object list = ftfont_driver.list (frame, spec), tail;
+  Lisp_Object list = ftfont_driver.list (f, spec), tail;
 
   for (tail = list; CONSP (tail); tail = XCDR (tail))
     ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
@@ -149,9 +139,9 @@ xftfont_list (Lisp_Object frame, Lisp_Object spec)
 }
 
 static Lisp_Object
-xftfont_match (Lisp_Object frame, Lisp_Object spec)
+xftfont_match (struct frame *f, Lisp_Object spec)
 {
-  Lisp_Object entity = ftfont_driver.match (frame, spec);
+  Lisp_Object entity = ftfont_driver.match (f, spec);
 
   if (! NILP (entity))
     ASET (entity, FONT_TYPE_INDEX, Qxft);
@@ -262,7 +252,7 @@ xftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity)
 }
 
 static Lisp_Object
-xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
+xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
 {
   FcResult result;
   Display *display = FRAME_X_DISPLAY (f);
@@ -273,8 +263,7 @@ xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
   double size = 0;
   XftFont *xftfont = NULL;
   int spacing;
-  char name[256];
-  int len, i;
+  int i;
   XGlyphInfo extents;
   FT_Face ft_face;
   FcMatrix *matrix;
@@ -325,16 +314,6 @@ xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
 
 
   block_input ();
-  /* Make sure that the Xrender extension is added before the Xft one.
-     Otherwise, the close-display hook set by Xft is called after the
-     one for Xrender, and the former tries to re-add the latter.  This
-     results in inconsistency of internal states and leads to X
-     protocol error when one reconnects to the same X server.
-     (Bug#1696)  */
-  {
-    int event_base, error_base;
-    XRenderQueryExtension (display, &event_base, &error_base);
-  }
 
   /* Substitute in values from X resources and XftDefaultSet.  */
   XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
@@ -354,20 +333,9 @@ xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
 
   /* 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), entity, size);
-  ASET (font_object, FONT_TYPE_INDEX, Qxft);
-  len = font_unparse_xlfd (entity, size, name, 256);
-  if (len > 0)
-    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_string (name, len));
-  else
-    ASET (font_object, FONT_FULLNAME_INDEX,
-         AREF (font_object, FONT_NAME_INDEX));
+  font_object = font_build_object (VECSIZE (struct xftfont_info),
+                                  Qxft, entity, size);
   ASET (font_object, FONT_FILE_INDEX, filename);
-  ASET (font_object, FONT_FORMAT_INDEX,
-       ftfont_font_format (xftfont->pattern, filename));
   font = XFONT_OBJECT (font_object);
   font->pixel_size = size;
   font->driver = &xftfont_driver;
@@ -375,8 +343,8 @@ xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
 
   xftfont_info = (struct xftfont_info *) font;
   xftfont_info->display = display;
-  xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
   xftfont_info->xftfont = xftfont;
+  xftfont_info->x_display_id = FRAME_DISPLAY_INFO (f)->x_id;
   /* This means that there's no need of transformation.  */
   xftfont_info->matrix.xx = 0;
   if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix)
@@ -427,16 +395,6 @@ xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
 
   font->ascent = xftfont->ascent;
   font->descent = xftfont->descent;
-  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;
 
   if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
@@ -462,7 +420,7 @@ xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
   font->baseline_offset = 0;
   font->relative_compose = 0;
   font->default_ascent = 0;
-  font->vertical_centering = 0;
+  font->vertical_centering = false;
 #ifdef FT_BDF_H
   if (! (ft_face->face_flags & FT_FACE_FLAG_SFNT))
     {
@@ -484,49 +442,58 @@ xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
 }
 
 static void
-xftfont_close (FRAME_PTR f, struct font *font)
+xftfont_close (struct font *font)
 {
+  struct x_display_info *xdi;
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
 
 #ifdef HAVE_LIBOTF
   if (xftfont_info->otf)
-    OTF_close (xftfont_info->otf);
+    {
+      OTF_close (xftfont_info->otf);
+      xftfont_info->otf = NULL;
+    }
 #endif
-  block_input ();
-  XftUnlockFace (xftfont_info->xftfont);
-  XftFontClose (xftfont_info->display, xftfont_info->xftfont);
-  unblock_input ();
+
+  /* See comment in xfont_close.  */
+  if (xftfont_info->xftfont
+      && ((xdi = x_display_info_for_display (xftfont_info->display))
+         && xftfont_info->x_display_id == xdi->x_id))
+    {
+      block_input ();
+      XftUnlockFace (xftfont_info->xftfont);
+      XftFontClose (xftfont_info->display, xftfont_info->xftfont);
+      unblock_input ();
+      xftfont_info->xftfont = NULL;
+    }
 }
 
-static int
-xftfont_prepare_face (FRAME_PTR f, struct face *face)
+static void
+xftfont_prepare_face (struct frame *f, struct face *face)
 {
   struct xftface_info *xftface_info;
 
-#if 0
+#if false
   /* This doesn't work if face->ascii_face doesn't use an Xft font. */
   if (face != face->ascii_face)
     {
       face->extra = face->ascii_face->extra;
-      return 0;
+      return;
     }
 #endif
 
-  xftface_info = malloc (sizeof *xftface_info);
-  if (! xftface_info)
-    return -1;
+  xftface_info = xmalloc (sizeof *xftface_info);
   xftfont_get_colors (f, face, face->gc, NULL,
                      &xftface_info->xft_fg, &xftface_info->xft_bg);
   face->extra = xftface_info;
-  return 0;
 }
 
 static void
-xftfont_done_face (FRAME_PTR f, struct face *face)
+xftfont_done_face (struct frame *f, struct face *face)
 {
   struct xftface_info *xftface_info;
 
-#if 0
+#if false
   /* This doesn't work if face->ascii_face doesn't use an Xft font. */
   if (face != face->ascii_face
       || ! face->extra)
@@ -536,7 +503,7 @@ xftfont_done_face (FRAME_PTR f, struct face *face)
   xftface_info = (struct xftface_info *) face->extra;
   if (xftface_info)
     {
-      free (xftface_info);
+      xfree (xftface_info);
       face->extra = NULL;
     }
 }
@@ -573,8 +540,9 @@ xftfont_encode_char (struct font *font, int c)
   return (code ? code : FONT_INVALID_CODE);
 }
 
-static int
-xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
+static void
+xftfont_text_extents (struct font *font, unsigned int *code,
+                     int nglyphs, struct font_metrics *metrics)
 {
   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
   XGlyphInfo extents;
@@ -583,21 +551,18 @@ xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct
   XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
                   &extents);
   unblock_input ();
-  if (metrics)
-    {
-      metrics->lbearing = - extents.x;
-      metrics->rbearing = - extents.x + extents.width;
-      metrics->width = extents.xOff;
-      metrics->ascent = extents.y;
-      metrics->descent = extents.height - extents.y;
-    }
-  return extents.xOff;
+
+  metrics->lbearing = - extents.x;
+  metrics->rbearing = - extents.x + extents.width;
+  metrics->width = extents.xOff;
+  metrics->ascent = extents.y;
+  metrics->descent = extents.height - extents.y;
 }
 
 static XftDraw *
-xftfont_get_xft_draw (FRAME_PTR f)
+xftfont_get_xft_draw (struct frame *f)
 {
-  XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
+  XftDraw *xft_draw = font_get_frame_data (f, Qxft);
 
   if (! xft_draw)
     {
@@ -608,7 +573,7 @@ xftfont_get_xft_draw (FRAME_PTR f)
                               FRAME_X_COLORMAP (f));
       unblock_input ();
       eassert (xft_draw != NULL);
-      font_put_frame_data (f, &xftfont_driver, xft_draw);
+      font_put_frame_data (f, Qxft, xft_draw);
     }
   return xft_draw;
 }
@@ -617,7 +582,7 @@ static int
 xftfont_draw (struct glyph_string *s, int from, int to, int x, int y,
               bool with_background)
 {
-  FRAME_PTR f = s->f;
+  struct frame *f = s->f;
   struct face *face = s->face;
   struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font;
   struct xftface_info *xftface_info = NULL;
@@ -638,8 +603,26 @@ xftfont_draw (struct glyph_string *s, int from, int to, int x, int y,
     XftDrawSetClip (xft_draw, NULL);
 
   if (with_background)
-    XftDrawRect (xft_draw, &bg,
-                x, y - s->font->ascent, s->width, s->font->height);
+    {
+      int height = FONT_HEIGHT (s->font), ascent = FONT_BASE (s->font);
+
+      /* Font's global height and ascent values might be
+        preposterously large for some fonts.  We fix here the case
+        when those fonts are used for display of glyphless
+        characters, because drawing background with font dimensions
+        in those cases makes the display illegible.  There's only one
+        more call to the draw method with with_background set to
+        true, and that's in x_draw_glyph_string_foreground, when
+        drawing the cursor, where we have no such heuristics
+        available.  FIXME.  */
+      if (s->first_glyph->type == GLYPHLESS_GLYPH
+         && (s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE
+             || s->first_glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM))
+       height = ascent =
+         s->first_glyph->slice.glyphless.lower_yoff
+         - s->first_glyph->slice.glyphless.upper_yoff;
+      XftDrawRect (xft_draw, &bg, x, y - ascent, s->width, height);
+    }
   code = alloca (sizeof (FT_UInt) * len);
   for (i = 0; i < len; i++)
     code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
@@ -661,13 +644,11 @@ xftfont_draw (struct glyph_string *s, int from, int to, int x, int y,
 static Lisp_Object
 xftfont_shape (Lisp_Object lgstring)
 {
-  struct font *font;
-  struct xftfont_info *xftfont_info;
+  struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
+  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
   FT_Face ft_face;
   Lisp_Object val;
 
-  CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
-  xftfont_info = (struct xftfont_info *) font;
   ft_face = XftLockFace (xftfont_info->xftfont);
   xftfont_info->ft_size = ft_face->size;
   val = ftfont_driver.shape (lgstring);
@@ -677,21 +658,21 @@ xftfont_shape (Lisp_Object lgstring)
 #endif
 
 static int
-xftfont_end_for_frame (FRAME_PTR f)
+xftfont_end_for_frame (struct frame *f)
 {
   XftDraw *xft_draw;
 
   /* Don't do anything if display is dead */
   if (FRAME_X_DISPLAY (f) == NULL) return 0;
 
-  xft_draw = font_get_frame_data (f, &xftfont_driver);
+  xft_draw = font_get_frame_data (f, Qxft);
 
   if (xft_draw)
     {
       block_input ();
       XftDrawDestroy (xft_draw);
       unblock_input ();
-      font_put_frame_data (f, &xftfont_driver, NULL);
+      font_put_frame_data (f, Qxft, NULL);
     }
   return 0;
 }
@@ -705,7 +686,7 @@ xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
   Display *display = FRAME_X_DISPLAY (f);
   FcPattern *pat = FcPatternCreate ();
   FcBool b1, b2;
-  bool ok = 0;
+  bool ok = false;
   int i1, i2, r1, r2;
 
   xftfont_add_rendering_parameters (pat, entity);
@@ -735,7 +716,7 @@ xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
   r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2);
   if (r1 != r2 || i1 != i2) goto out;
 
-  ok = 1;
+  ok = true;
  out:
   FcPatternDestroy (pat);
   return ok;