/* xftfont.c -- XFT font driver.
- Copyright (C) 2006-2015 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
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
#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 cast to struct
font. */
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,
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))
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;
double size = 0;
XftFont *xftfont = NULL;
int spacing;
- char name[256];
- int len, i;
+ int i;
XGlyphInfo extents;
FT_Face ft_face;
FcMatrix *matrix;
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);
/* 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;
font->ascent = xftfont->ascent;
font->descent = xftfont->descent;
- if (pixel_size >= 5)
+ /* The following workaround is unnecessary on most systems, and
+ causes annoying differences in glyph height between regular and
+ bold fonts (see bug#22383). However, with some fonts, such as
+ monaco, removing the workaround results in overlapping vertical
+ space of a line, see bug#23360. As long as the way to reconcile
+ these opposites is not known, we provide a user option to work
+ around the problem. */
+ if (pixel_size >= 5
+ && xft_font_ascent_descent_override)
{
/* The above condition is a dirty workaround because
XftTextExtents8 behaves strangely for some fonts
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))
{
}
}
-static int
+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
{
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)
xftface_info = (struct xftface_info *) face->extra;
if (xftface_info)
{
- free (xftface_info);
+ xfree (xftface_info);
face->extra = NULL;
}
}
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;
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 (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)
{
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;
}
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)
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);
/* 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;
}
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);
r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2);
if (r1 != r2 || i1 != i2) goto out;
- ok = 1;
+ ok = true;
out:
FcPatternDestroy (pat);
return ok;
DEFSYM (QCembolden, ":embolden");
DEFSYM (QClcdfilter, ":lcdfilter");
+ DEFVAR_BOOL ("xft-font-ascent-descent-override",
+ xft_font_ascent_descent_override,
+ doc: /* Non-nil means override the ascent and descent values for Xft font driver.
+This is needed with some fonts to correct vertical overlap of glyphs. */);
+ xft_font_ascent_descent_override = 0;
+
ascii_printable[0] = 0;
xftfont_driver = ftfont_driver;