X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/9743ac48ddb1b5026ac05e5ab0f883fb74da55fb..f57e2426f0e8a6b251be71b6f62237fd286998ea:/src/xftfont.c diff --git a/src/xftfont.c b/src/xftfont.c index 8eadd06076..8aeb6397f0 100644 --- a/src/xftfont.c +++ b/src/xftfont.c @@ -1,6 +1,6 @@ /* xftfont.c -- XFT font driver. - Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. - Copyright (C) 2006, 2007, 2008 + Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 2006, 2007, 2008, 2009, 2010 National Institute of Advanced Industrial Science and Technology (AIST) Registration Number H13PRO009 @@ -21,6 +21,7 @@ along with GNU Emacs. If not, see . */ #include #include +#include #include #include @@ -38,7 +39,8 @@ along with GNU Emacs. If not, see . */ /* Xft font driver. */ static Lisp_Object Qxft; -static Lisp_Object QChinting , QCautohint, QChintstyle, QCrgba, QCembolden; +static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden, + QClcdfilter; /* The actual structure for Xft font that can be casted to struct font. */ @@ -46,13 +48,15 @@ static Lisp_Object QChinting , QCautohint, QChintstyle, QCrgba, QCembolden; struct xftfont_info { struct font font; - /* The following three members must be here in this order to be + /* The following five 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; + int index; + FT_Matrix matrix; Display *display; int screen; XftFont *xftfont; @@ -66,9 +70,9 @@ struct xftface_info XftColor xft_bg; /* color for face->background */ }; -static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc, - struct xftface_info *, - XftColor *fg, XftColor *bg)); +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 @@ -137,17 +141,18 @@ xftfont_get_colors (f, face, gc, xftface_info, fg, bg) } -static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object)); -static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object)); -static Lisp_Object xftfont_open P_ ((FRAME_PTR, Lisp_Object, int)); -static void xftfont_close P_ ((FRAME_PTR, struct font *)); -static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *)); -static void xftfont_done_face P_ ((FRAME_PTR, struct face *)); -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_end_for_frame P_ ((FRAME_PTR f)); +static Lisp_Object xftfont_list (Lisp_Object, Lisp_Object); +static Lisp_Object xftfont_match (Lisp_Object, Lisp_Object); +static Lisp_Object xftfont_open (FRAME_PTR, Lisp_Object, int); +static void xftfont_close (FRAME_PTR, struct font *); +static int xftfont_prepare_face (FRAME_PTR, struct face *); +static void xftfont_done_face (FRAME_PTR, struct face *); +static int xftfont_has_char (Lisp_Object, int); +static unsigned xftfont_encode_char (struct font *, int); +static int xftfont_text_extents (struct font *, unsigned *, int, + struct font_metrics *); +static int xftfont_draw (struct glyph_string *, int, int, int, int, int); +static int xftfont_end_for_frame (FRAME_PTR f); struct font_driver xftfont_driver; @@ -157,7 +162,7 @@ xftfont_list (frame, spec) Lisp_Object spec; { Lisp_Object list = ftfont_driver.list (frame, spec), tail; - + for (tail = list; CONSP (tail); tail = XCDR (tail)) ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft); return list; @@ -175,12 +180,113 @@ xftfont_match (frame, spec) return entity; } -extern Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object)); -extern FcCharSet *ftfont_get_fc_charset P_ ((Lisp_Object)); +extern Lisp_Object ftfont_font_format (FcPattern *, Lisp_Object); +extern FcCharSet *ftfont_get_fc_charset (Lisp_Object); extern Lisp_Object QCantialias; static FcChar8 ascii_printable[95]; +static void +xftfont_fix_match (pat, match) + FcPattern *pat, *match; +{ + /* These values are not used for matching (except antialias), but for + rendering, so make sure they are carried over to the match. + We also put antialias here because most fonts are antialiased, so + the match will have antialias true. */ + + FcBool b = FcTrue; + int i; + double dpi; + + FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b); + if (! b) + { + FcPatternDel (match, FC_ANTIALIAS); + FcPatternAddBool (match, FC_ANTIALIAS, FcFalse); + } + FcPatternGetBool (pat, FC_HINTING, 0, &b); + if (! b) + { + FcPatternDel (match, FC_HINTING); + FcPatternAddBool (match, FC_HINTING, FcFalse); + } + if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i)) + { + FcPatternDel (match, FC_HINT_STYLE); + FcPatternAddInteger (match, FC_HINT_STYLE, i); + } +#ifndef FC_LCD_FILTER + /* Older fontconfig versions don't have FC_LCD_FILTER. */ +#define FC_LCD_FILTER "lcdfilter" +#endif + if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i)) + { + FcPatternDel (match, FC_LCD_FILTER); + FcPatternAddInteger (match, FC_LCD_FILTER, i); + } + if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i)) + { + FcPatternDel (match, FC_RGBA); + FcPatternAddInteger (match, FC_RGBA, i); + } + if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi)) + { + FcPatternDel (match, FC_DPI); + FcPatternAddDouble (match, FC_DPI, dpi); + } +} + +static void +xftfont_add_rendering_parameters (pat, entity) + FcPattern *pat; + Lisp_Object entity; +{ + Lisp_Object tail; + int ival; + + for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail)) + { + Lisp_Object key = XCAR (XCAR (tail)); + Lisp_Object 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_HINT_STYLE, XINT (val)); + else if (SYMBOLP (val) + && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) + FcPatternAddInteger (pat, FC_HINT_STYLE, ival); + } + else if (EQ (key, QCrgba)) + { + if (INTEGERP (val)) + FcPatternAddInteger (pat, FC_RGBA, XINT (val)); + else if (SYMBOLP (val) + && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) + FcPatternAddInteger (pat, FC_RGBA, ival); + } + else if (EQ (key, QClcdfilter)) + { + if (INTEGERP (val)) + FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XINT (val)); + else if (SYMBOLP (val) + && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) + FcPatternAddInteger (pat, FC_LCD_FILTER, ival); + } +#ifdef FC_EMBOLDEN + else if (EQ (key, QCembolden)) + FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue); +#endif + } +} + static Lisp_Object xftfont_open (f, entity, pixel_size) FRAME_PTR f; @@ -189,7 +295,7 @@ xftfont_open (f, entity, pixel_size) { FcResult result; Display *display = FRAME_X_DISPLAY (f); - Lisp_Object val, filename, index, tail, font_object; + Lisp_Object val, filename, index, font_object; FcPattern *pat = NULL, *match; struct xftfont_info *xftfont_info = NULL; struct font *font; @@ -200,6 +306,7 @@ xftfont_open (f, entity, pixel_size) int len, i; XGlyphInfo extents; FT_Face ft_face; + FcMatrix *matrix; val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX)); if (! CONSP (val)) @@ -240,56 +347,50 @@ xftfont_open (f, entity, pixel_size) 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 - } + xftfont_add_rendering_parameters (pat, entity); FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename)); FcPatternAddInteger (pat, FC_INDEX, XINT (index)); - + 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); match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result); + xftfont_fix_match (pat, match); + FcPatternDestroy (pat); xftfont = XftFontOpenPattern (display, match); + if (!xftfont) + { + UNBLOCK_INPUT; + XftPatternDestroy (match); + return Qnil; + } ft_face = XftLockFace (xftfont); UNBLOCK_INPUT; - if (! xftfont) - 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), 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_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)); @@ -305,6 +406,16 @@ xftfont_open (f, entity, pixel_size) xftfont_info->display = display; xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f); xftfont_info->xftfont = xftfont; + /* This means that there's no need of transformation. */ + xftfont_info->matrix.xx = 0; + if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix) + == FcResultMatch) + { + xftfont_info->matrix.xx = 0x10000L * matrix->xx; + xftfont_info->matrix.yy = 0x10000L * matrix->yy; + xftfont_info->matrix.xy = 0x10000L * matrix->xy; + xftfont_info->matrix.yx = 0x10000L * matrix->yx; + } font->pixel_size = size; font->driver = &xftfont_driver; if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))) @@ -318,7 +429,7 @@ xftfont_open (f, entity, pixel_size) ascii_printable[i] = ' ' + i; } BLOCK_INPUT; - if (spacing != FC_PROPORTIONAL) + if (spacing != FC_PROPORTIONAL && spacing != FC_DUAL) { font->min_width = font->average_width = font->space_width = xftfont->max_advance_width; @@ -330,7 +441,7 @@ xftfont_open (f, entity, pixel_size) font->space_width = extents.xOff; if (font->space_width <= 0) /* dirty workaround */ - font->space_width = pixel_size; + font->space_width = pixel_size; XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents); font->average_width = (font->space_width + extents.xOff) / 95; } @@ -355,7 +466,7 @@ xftfont_open (f, entity, pixel_size) int upEM = ft_face->units_per_EM; font->underline_position = -ft_face->underline_position * size / upEM; - font->underline_thickness = -ft_face->underline_thickness * size / upEM; + font->underline_thickness = ft_face->underline_thickness * size / upEM; if (font->underline_thickness > 2) font->underline_position -= font->underline_thickness / 2; } @@ -446,7 +557,7 @@ xftfont_done_face (f, face) struct face *face; { struct xftface_info *xftface_info; - + #if 0 /* This doesn't work if face->ascii_face doesn't use an Xft font. */ if (face != face->ascii_face @@ -462,6 +573,32 @@ xftfont_done_face (f, face) } } +extern Lisp_Object Qja, Qko; + +static int +xftfont_has_char (font, c) + Lisp_Object font; + int c; +{ + struct xftfont_info *xftfont_info; + struct charset *cs = NULL; + + if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja) + && charset_jisx0208 >= 0) + cs = CHARSET_FROM_ID (charset_jisx0208); + else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko) + && charset_ksc5601 >= 0) + cs = CHARSET_FROM_ID (charset_ksc5601); + if (cs) + return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs)); + + if (FONT_ENTITY_P (font)) + return ftfont_driver.has_char (font, c); + xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font); + return (XftCharExists (xftfont_info->display, xftfont_info->xftfont, + (FcChar32) c) == FcTrue); +} + static unsigned xftfont_encode_char (font, c) struct font *font; @@ -470,7 +607,7 @@ xftfont_encode_char (font, c) struct xftfont_info *xftfont_info = (struct xftfont_info *) font; unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont, (FcChar32) c); - + return (code ? code : FONT_INVALID_CODE); } @@ -503,7 +640,7 @@ static XftDraw * xftfont_get_xft_draw (f) FRAME_PTR f; { - XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);; + XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver); if (! xft_draw) { @@ -569,7 +706,12 @@ static int xftfont_end_for_frame (f) FRAME_PTR f; { - XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver); + 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); if (xft_draw) { @@ -581,6 +723,53 @@ xftfont_end_for_frame (f) return 0; } +static int +xftfont_cached_font_ok (f, font_object, entity) + struct frame *f; + Lisp_Object font_object; + Lisp_Object entity; + +{ + struct xftfont_info *info = (struct xftfont_info *) XFONT_OBJECT (font_object); + FcPattern *oldpat = info->xftfont->pattern; + Display *display = FRAME_X_DISPLAY (f); + FcPattern *pat = FcPatternCreate (); + FcBool b1, b2; + int ok = 0, i1, i2, r1, r2; + + xftfont_add_rendering_parameters (pat, entity); + XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat); + + r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1); + r2 = FcPatternGetBool (oldpat, FC_ANTIALIAS, 0, &b2); + if (r1 != r2 || b1 != b2) goto out; + r1 = FcPatternGetBool (pat, FC_HINTING, 0, &b1); + r2 = FcPatternGetBool (oldpat, FC_HINTING, 0, &b2); + if (r1 != r2 || b1 != b2) goto out; + r1 = FcPatternGetBool (pat, FC_AUTOHINT, 0, &b1); + r2 = FcPatternGetBool (oldpat, FC_AUTOHINT, 0, &b2); + if (r1 != r2 || b1 != b2) goto out; +#ifdef FC_EMBOLDEN + r1 = FcPatternGetBool (pat, FC_EMBOLDEN, 0, &b1); + r2 = FcPatternGetBool (oldpat, FC_EMBOLDEN, 0, &b2); + if (r1 != r2 || b1 != b2) goto out; +#endif + r1 = FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i1); + r2 = FcPatternGetInteger (oldpat, FC_HINT_STYLE, 0, &i2); + if (r1 != r2 || i1 != i2) goto out; + r1 = FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i1); + r2 = FcPatternGetInteger (oldpat, FC_LCD_FILTER, 0, &i2); + if (r1 != r2 || i1 != i2) goto out; + r1 = FcPatternGetInteger (pat, FC_RGBA, 0, &i1); + r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2); + if (r1 != r2 || i1 != i2) goto out; + + ok = 1; + out: + FcPatternDestroy (pat); + return ok; +} + void syms_of_xftfont () { @@ -590,6 +779,7 @@ syms_of_xftfont () DEFSYM (QChintstyle, ":hintstyle"); DEFSYM (QCrgba, ":rgba"); DEFSYM (QCembolden, ":embolden"); + DEFSYM (QClcdfilter, ":lcdfilter"); xftfont_driver = ftfont_driver; xftfont_driver.type = Qxft; @@ -600,10 +790,12 @@ syms_of_xftfont () xftfont_driver.close = xftfont_close; xftfont_driver.prepare_face = xftfont_prepare_face; xftfont_driver.done_face = xftfont_done_face; + xftfont_driver.has_char = xftfont_has_char; xftfont_driver.encode_char = xftfont_encode_char; xftfont_driver.text_extents = xftfont_text_extents; xftfont_driver.draw = xftfont_draw; xftfont_driver.end_for_frame = xftfont_end_for_frame; + xftfont_driver.cached_font_ok = xftfont_cached_font_ok; register_font_driver (&xftfont_driver, NULL); }