X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/b35f288d478ef137a4d9e8e5a6a5f368a86b01f5..e2b6daf4193bcfd81d6dc67eeee3d50888710818:/src/xftfont.c diff --git a/src/xftfont.c b/src/xftfont.c index 5a90b7d262..2b576c3d4a 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 Free Software Foundation, Inc. + Copyright (C) 2006, 2007, 2008, 2009 National Institute of Advanced Industrial Science and Technology (AIST) Registration Number H13PRO009 @@ -38,6 +38,7 @@ along with GNU Emacs. If not, see . */ /* 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,17 @@ static Lisp_Object Qxft; struct xftfont_info { struct font font; - Display *display; - int screen; - XftFont *xftfont; + /* The following four 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; + Display *display; + int screen; + XftFont *xftfont; }; /* Structure pointed by (struct face *)->extra */ @@ -139,13 +144,11 @@ 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 int xftfont_has_char P_ ((Lisp_Object, int)); 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; @@ -156,8 +159,7 @@ xftfont_list (frame, spec) Lisp_Object spec; { Lisp_Object list = ftfont_driver.list (frame, spec), tail; - int i; - + for (tail = list; CONSP (tail); tail = XCDR (tail)) ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft); return list; @@ -175,7 +177,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]; @@ -185,13 +189,11 @@ xftfont_open (f, entity, pixel_size) Lisp_Object entity; int pixel_size; { - Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + FcResult result; Display *display = FRAME_X_DISPLAY (f); - Lisp_Object val, font_object; - FcPattern *pattern, *pat = NULL; - FcChar8 *file; + Lisp_Object val, filename, index, tail, font_object; + FcPattern *pat = NULL, *match; struct xftfont_info *xftfont_info = NULL; - XFontStruct *xfont = NULL; struct font *font; double size = 0; XftFont *xftfont = NULL; @@ -202,52 +204,114 @@ xftfont_open (f, entity, pixel_size) FT_Face ft_face; val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX)); - if (! CONSP (val) - || XTYPE (XCDR (val)) != Lisp_Misc - || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value) + if (! CONSP (val)) return Qnil; - pattern = XSAVE_VALUE (XCDR (val))->pointer; - if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch) - 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, file); + 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_HINT_STYLE, 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); + /* 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); + } + match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result); + 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)); + 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, - make_unibyte_string ((char *) file, strlen ((char *) file))); - ASET (font_object, FONT_FORMAT_INDEX, ftfont_font_format (pattern)); + 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 = pixel_size; font->driver = &xftfont_driver; @@ -259,8 +323,9 @@ xftfont_open (f, entity, pixel_size) xftfont_info->xftfont = xftfont; font->pixel_size = size; font->driver = &xftfont_driver; - if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing) - != FcResultMatch) + if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))) + spacing = XINT (AREF (entity, FONT_SPACING_INDEX)); + else spacing = FC_PROPORTIONAL; if (! ascii_printable[0]) { @@ -281,27 +346,34 @@ 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; } 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; 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; } else { @@ -312,7 +384,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. */ @@ -322,6 +394,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; } @@ -338,6 +426,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; } @@ -373,7 +462,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 @@ -389,6 +478,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; @@ -397,7 +512,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); } @@ -430,7 +545,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) { @@ -459,7 +574,6 @@ xftfont_draw (s, from, to, x, y, with_background) XftDraw *xft_draw = xftfont_get_xft_draw (f); FT_UInt *code; XftColor fg, bg; - XRectangle r; int len = to - from; int i; @@ -493,32 +607,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; @@ -535,48 +623,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; @@ -587,16 +642,11 @@ 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.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); }