| 1 | /* xftfont.c -- XFT font driver. |
| 2 | Copyright (C) 2006-2013 Free Software Foundation, Inc. |
| 3 | Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 |
| 4 | National Institute of Advanced Industrial Science and Technology (AIST) |
| 5 | Registration Number H13PRO009 |
| 6 | |
| 7 | This file is part of GNU Emacs. |
| 8 | |
| 9 | GNU Emacs is free software: you can redistribute it and/or modify |
| 10 | it under the terms of the GNU General Public License as published by |
| 11 | the Free Software Foundation, either version 3 of the License, or |
| 12 | (at your option) any later version. |
| 13 | |
| 14 | GNU Emacs is distributed in the hope that it will be useful, |
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | GNU General Public License for more details. |
| 18 | |
| 19 | You should have received a copy of the GNU General Public License |
| 20 | along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ |
| 21 | |
| 22 | #include <config.h> |
| 23 | #include <stdio.h> |
| 24 | #include <X11/Xlib.h> |
| 25 | #include <X11/Xft/Xft.h> |
| 26 | |
| 27 | #include "lisp.h" |
| 28 | #include "dispextern.h" |
| 29 | #include "xterm.h" |
| 30 | #include "frame.h" |
| 31 | #include "blockinput.h" |
| 32 | #include "character.h" |
| 33 | #include "charset.h" |
| 34 | #include "composite.h" |
| 35 | #include "fontset.h" |
| 36 | #include "font.h" |
| 37 | #include "ftfont.h" |
| 38 | |
| 39 | /* Xft font driver. */ |
| 40 | |
| 41 | Lisp_Object Qxft; |
| 42 | static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden, |
| 43 | QClcdfilter; |
| 44 | |
| 45 | /* The actual structure for Xft font that can be casted to struct |
| 46 | font. */ |
| 47 | |
| 48 | struct xftfont_info |
| 49 | { |
| 50 | struct font font; |
| 51 | /* The following five members must be here in this order to be |
| 52 | compatible with struct ftfont_info (in ftfont.c). */ |
| 53 | #ifdef HAVE_LIBOTF |
| 54 | bool maybe_otf; /* Flag to tell if this may be OTF or not. */ |
| 55 | OTF *otf; |
| 56 | #endif /* HAVE_LIBOTF */ |
| 57 | FT_Size ft_size; |
| 58 | int index; |
| 59 | FT_Matrix matrix; |
| 60 | Display *display; |
| 61 | XftFont *xftfont; |
| 62 | }; |
| 63 | |
| 64 | /* Structure pointed by (struct face *)->extra */ |
| 65 | |
| 66 | struct xftface_info |
| 67 | { |
| 68 | XftColor xft_fg; /* color for face->foreground */ |
| 69 | XftColor xft_bg; /* color for face->background */ |
| 70 | }; |
| 71 | |
| 72 | /* Setup foreground and background colors of GC into FG and BG. If |
| 73 | XFTFACE_INFO is not NULL, reuse the colors in it if possible. BG |
| 74 | may be NULL. */ |
| 75 | |
| 76 | static void |
| 77 | xftfont_get_colors (struct frame *f, struct face *face, GC gc, |
| 78 | struct xftface_info *xftface_info, |
| 79 | XftColor *fg, XftColor *bg) |
| 80 | { |
| 81 | if (xftface_info && face->gc == gc) |
| 82 | { |
| 83 | *fg = xftface_info->xft_fg; |
| 84 | if (bg) |
| 85 | *bg = xftface_info->xft_bg; |
| 86 | } |
| 87 | else |
| 88 | { |
| 89 | XGCValues xgcv; |
| 90 | bool fg_done = 0, bg_done = 0; |
| 91 | |
| 92 | block_input (); |
| 93 | XGetGCValues (FRAME_X_DISPLAY (f), gc, |
| 94 | GCForeground | GCBackground, &xgcv); |
| 95 | if (xftface_info) |
| 96 | { |
| 97 | if (xgcv.foreground == face->foreground) |
| 98 | *fg = xftface_info->xft_fg, fg_done = 1; |
| 99 | else if (xgcv.foreground == face->background) |
| 100 | *fg = xftface_info->xft_bg, fg_done = 1; |
| 101 | if (! bg) |
| 102 | bg_done = 1; |
| 103 | else if (xgcv.background == face->background) |
| 104 | *bg = xftface_info->xft_bg, bg_done = 1; |
| 105 | else if (xgcv.background == face->foreground) |
| 106 | *bg = xftface_info->xft_fg, bg_done = 1; |
| 107 | } |
| 108 | |
| 109 | if (! (fg_done & bg_done)) |
| 110 | { |
| 111 | XColor colors[2]; |
| 112 | |
| 113 | colors[0].pixel = fg->pixel = xgcv.foreground; |
| 114 | if (bg) |
| 115 | colors[1].pixel = bg->pixel = xgcv.background; |
| 116 | XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, |
| 117 | bg ? 2 : 1); |
| 118 | fg->color.alpha = 0xFFFF; |
| 119 | fg->color.red = colors[0].red; |
| 120 | fg->color.green = colors[0].green; |
| 121 | fg->color.blue = colors[0].blue; |
| 122 | if (bg) |
| 123 | { |
| 124 | bg->color.alpha = 0xFFFF; |
| 125 | bg->color.red = colors[1].red; |
| 126 | bg->color.green = colors[1].green; |
| 127 | bg->color.blue = colors[1].blue; |
| 128 | } |
| 129 | } |
| 130 | unblock_input (); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | |
| 135 | struct font_driver xftfont_driver; |
| 136 | |
| 137 | static Lisp_Object |
| 138 | xftfont_list (struct frame *f, Lisp_Object spec) |
| 139 | { |
| 140 | Lisp_Object list = ftfont_driver.list (f, spec), tail; |
| 141 | |
| 142 | for (tail = list; CONSP (tail); tail = XCDR (tail)) |
| 143 | ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft); |
| 144 | return list; |
| 145 | } |
| 146 | |
| 147 | static Lisp_Object |
| 148 | xftfont_match (struct frame *f, Lisp_Object spec) |
| 149 | { |
| 150 | Lisp_Object entity = ftfont_driver.match (f, spec); |
| 151 | |
| 152 | if (! NILP (entity)) |
| 153 | ASET (entity, FONT_TYPE_INDEX, Qxft); |
| 154 | return entity; |
| 155 | } |
| 156 | |
| 157 | static FcChar8 ascii_printable[95]; |
| 158 | |
| 159 | static void |
| 160 | xftfont_fix_match (FcPattern *pat, FcPattern *match) |
| 161 | { |
| 162 | /* These values are not used for matching (except antialias), but for |
| 163 | rendering, so make sure they are carried over to the match. |
| 164 | We also put antialias here because most fonts are antialiased, so |
| 165 | the match will have antialias true. */ |
| 166 | |
| 167 | FcBool b = FcTrue; |
| 168 | int i; |
| 169 | double dpi; |
| 170 | |
| 171 | FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b); |
| 172 | if (! b) |
| 173 | { |
| 174 | FcPatternDel (match, FC_ANTIALIAS); |
| 175 | FcPatternAddBool (match, FC_ANTIALIAS, FcFalse); |
| 176 | } |
| 177 | FcPatternGetBool (pat, FC_HINTING, 0, &b); |
| 178 | if (! b) |
| 179 | { |
| 180 | FcPatternDel (match, FC_HINTING); |
| 181 | FcPatternAddBool (match, FC_HINTING, FcFalse); |
| 182 | } |
| 183 | #ifndef FC_HINT_STYLE |
| 184 | # define FC_HINT_STYLE "hintstyle" |
| 185 | #endif |
| 186 | if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i)) |
| 187 | { |
| 188 | FcPatternDel (match, FC_HINT_STYLE); |
| 189 | FcPatternAddInteger (match, FC_HINT_STYLE, i); |
| 190 | } |
| 191 | #ifndef FC_LCD_FILTER |
| 192 | /* Older fontconfig versions don't have FC_LCD_FILTER. */ |
| 193 | #define FC_LCD_FILTER "lcdfilter" |
| 194 | #endif |
| 195 | if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i)) |
| 196 | { |
| 197 | FcPatternDel (match, FC_LCD_FILTER); |
| 198 | FcPatternAddInteger (match, FC_LCD_FILTER, i); |
| 199 | } |
| 200 | if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i)) |
| 201 | { |
| 202 | FcPatternDel (match, FC_RGBA); |
| 203 | FcPatternAddInteger (match, FC_RGBA, i); |
| 204 | } |
| 205 | if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi)) |
| 206 | { |
| 207 | FcPatternDel (match, FC_DPI); |
| 208 | FcPatternAddDouble (match, FC_DPI, dpi); |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | static void |
| 213 | xftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity) |
| 214 | { |
| 215 | Lisp_Object tail; |
| 216 | int ival; |
| 217 | |
| 218 | for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail)) |
| 219 | { |
| 220 | Lisp_Object key = XCAR (XCAR (tail)); |
| 221 | Lisp_Object val = XCDR (XCAR (tail)); |
| 222 | |
| 223 | if (EQ (key, QCantialias)) |
| 224 | FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue); |
| 225 | else if (EQ (key, QChinting)) |
| 226 | FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue); |
| 227 | else if (EQ (key, QCautohint)) |
| 228 | FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue); |
| 229 | else if (EQ (key, QChintstyle)) |
| 230 | { |
| 231 | if (INTEGERP (val)) |
| 232 | FcPatternAddInteger (pat, FC_HINT_STYLE, XINT (val)); |
| 233 | else if (SYMBOLP (val) |
| 234 | && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) |
| 235 | FcPatternAddInteger (pat, FC_HINT_STYLE, ival); |
| 236 | } |
| 237 | else if (EQ (key, QCrgba)) |
| 238 | { |
| 239 | if (INTEGERP (val)) |
| 240 | FcPatternAddInteger (pat, FC_RGBA, XINT (val)); |
| 241 | else if (SYMBOLP (val) |
| 242 | && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) |
| 243 | FcPatternAddInteger (pat, FC_RGBA, ival); |
| 244 | } |
| 245 | else if (EQ (key, QClcdfilter)) |
| 246 | { |
| 247 | if (INTEGERP (val)) |
| 248 | FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XINT (val)); |
| 249 | else if (SYMBOLP (val) |
| 250 | && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival)) |
| 251 | FcPatternAddInteger (pat, FC_LCD_FILTER, ival); |
| 252 | } |
| 253 | #ifdef FC_EMBOLDEN |
| 254 | else if (EQ (key, QCembolden)) |
| 255 | FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue); |
| 256 | #endif |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | static Lisp_Object |
| 261 | xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size) |
| 262 | { |
| 263 | FcResult result; |
| 264 | Display *display = FRAME_X_DISPLAY (f); |
| 265 | Lisp_Object val, filename, idx, font_object; |
| 266 | FcPattern *pat = NULL, *match; |
| 267 | struct xftfont_info *xftfont_info = NULL; |
| 268 | struct font *font; |
| 269 | double size = 0; |
| 270 | XftFont *xftfont = NULL; |
| 271 | int spacing; |
| 272 | char name[256]; |
| 273 | int len, i; |
| 274 | XGlyphInfo extents; |
| 275 | FT_Face ft_face; |
| 276 | FcMatrix *matrix; |
| 277 | |
| 278 | val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX)); |
| 279 | if (! CONSP (val)) |
| 280 | return Qnil; |
| 281 | val = XCDR (val); |
| 282 | filename = XCAR (val); |
| 283 | idx = XCDR (val); |
| 284 | size = XINT (AREF (entity, FONT_SIZE_INDEX)); |
| 285 | if (size == 0) |
| 286 | size = pixel_size; |
| 287 | pat = FcPatternCreate (); |
| 288 | FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity)); |
| 289 | i = FONT_SLANT_NUMERIC (entity) - 100; |
| 290 | if (i < 0) i = 0; |
| 291 | FcPatternAddInteger (pat, FC_SLANT, i); |
| 292 | FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity)); |
| 293 | FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size); |
| 294 | val = AREF (entity, FONT_FAMILY_INDEX); |
| 295 | if (! NILP (val)) |
| 296 | FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); |
| 297 | val = AREF (entity, FONT_FOUNDRY_INDEX); |
| 298 | if (! NILP (val)) |
| 299 | FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val))); |
| 300 | val = AREF (entity, FONT_SPACING_INDEX); |
| 301 | if (! NILP (val)) |
| 302 | FcPatternAddInteger (pat, FC_SPACING, XINT (val)); |
| 303 | val = AREF (entity, FONT_DPI_INDEX); |
| 304 | if (! NILP (val)) |
| 305 | { |
| 306 | double dbl = XINT (val); |
| 307 | |
| 308 | FcPatternAddDouble (pat, FC_DPI, dbl); |
| 309 | } |
| 310 | val = AREF (entity, FONT_AVGWIDTH_INDEX); |
| 311 | if (INTEGERP (val) && XINT (val) == 0) |
| 312 | FcPatternAddBool (pat, FC_SCALABLE, FcTrue); |
| 313 | /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz |
| 314 | over 10x20-ISO8859-1.pcf.gz). */ |
| 315 | FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity)); |
| 316 | |
| 317 | xftfont_add_rendering_parameters (pat, entity); |
| 318 | |
| 319 | FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename)); |
| 320 | FcPatternAddInteger (pat, FC_INDEX, XINT (idx)); |
| 321 | |
| 322 | |
| 323 | block_input (); |
| 324 | /* Make sure that the Xrender extension is added before the Xft one. |
| 325 | Otherwise, the close-display hook set by Xft is called after the |
| 326 | one for Xrender, and the former tries to re-add the latter. This |
| 327 | results in inconsistency of internal states and leads to X |
| 328 | protocol error when one reconnects to the same X server. |
| 329 | (Bug#1696) */ |
| 330 | { |
| 331 | int event_base, error_base; |
| 332 | XRenderQueryExtension (display, &event_base, &error_base); |
| 333 | } |
| 334 | |
| 335 | /* Substitute in values from X resources and XftDefaultSet. */ |
| 336 | XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat); |
| 337 | match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result); |
| 338 | xftfont_fix_match (pat, match); |
| 339 | |
| 340 | FcPatternDestroy (pat); |
| 341 | xftfont = XftFontOpenPattern (display, match); |
| 342 | if (!xftfont) |
| 343 | { |
| 344 | unblock_input (); |
| 345 | XftPatternDestroy (match); |
| 346 | return Qnil; |
| 347 | } |
| 348 | ft_face = XftLockFace (xftfont); |
| 349 | unblock_input (); |
| 350 | |
| 351 | /* We should not destroy PAT here because it is kept in XFTFONT and |
| 352 | destroyed automatically when XFTFONT is closed. */ |
| 353 | font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size); |
| 354 | ASET (font_object, FONT_TYPE_INDEX, Qxft); |
| 355 | len = font_unparse_xlfd (entity, size, name, 256); |
| 356 | if (len > 0) |
| 357 | ASET (font_object, FONT_NAME_INDEX, make_string (name, len)); |
| 358 | len = font_unparse_fcname (entity, size, name, 256); |
| 359 | if (len > 0) |
| 360 | ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len)); |
| 361 | else |
| 362 | ASET (font_object, FONT_FULLNAME_INDEX, |
| 363 | AREF (font_object, FONT_NAME_INDEX)); |
| 364 | ASET (font_object, FONT_FILE_INDEX, filename); |
| 365 | ASET (font_object, FONT_FORMAT_INDEX, |
| 366 | ftfont_font_format (xftfont->pattern, filename)); |
| 367 | font = XFONT_OBJECT (font_object); |
| 368 | font->pixel_size = size; |
| 369 | font->driver = &xftfont_driver; |
| 370 | font->encoding_charset = font->repertory_charset = -1; |
| 371 | |
| 372 | xftfont_info = (struct xftfont_info *) font; |
| 373 | xftfont_info->display = display; |
| 374 | xftfont_info->xftfont = xftfont; |
| 375 | /* This means that there's no need of transformation. */ |
| 376 | xftfont_info->matrix.xx = 0; |
| 377 | if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix) |
| 378 | == FcResultMatch) |
| 379 | { |
| 380 | xftfont_info->matrix.xx = 0x10000L * matrix->xx; |
| 381 | xftfont_info->matrix.yy = 0x10000L * matrix->yy; |
| 382 | xftfont_info->matrix.xy = 0x10000L * matrix->xy; |
| 383 | xftfont_info->matrix.yx = 0x10000L * matrix->yx; |
| 384 | } |
| 385 | if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))) |
| 386 | spacing = XINT (AREF (entity, FONT_SPACING_INDEX)); |
| 387 | else |
| 388 | spacing = FC_PROPORTIONAL; |
| 389 | if (! ascii_printable[0]) |
| 390 | { |
| 391 | int ch; |
| 392 | for (ch = 0; ch < 95; ch++) |
| 393 | ascii_printable[ch] = ' ' + ch; |
| 394 | } |
| 395 | block_input (); |
| 396 | |
| 397 | /* Unfortunately Xft doesn't provide a way to get minimum char |
| 398 | width. So, we set min_width to space_width. */ |
| 399 | |
| 400 | if (spacing != FC_PROPORTIONAL |
| 401 | #ifdef FC_DUAL |
| 402 | && spacing != FC_DUAL |
| 403 | #endif /* FC_DUAL */ |
| 404 | ) |
| 405 | { |
| 406 | font->min_width = font->max_width = font->average_width |
| 407 | = font->space_width = xftfont->max_advance_width; |
| 408 | XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents); |
| 409 | } |
| 410 | else |
| 411 | { |
| 412 | XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents); |
| 413 | font->min_width = font->max_width = font->space_width |
| 414 | = extents.xOff; |
| 415 | if (font->space_width <= 0) |
| 416 | /* dirty workaround */ |
| 417 | font->space_width = pixel_size; |
| 418 | XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents); |
| 419 | font->average_width = (font->space_width + extents.xOff) / 95; |
| 420 | } |
| 421 | unblock_input (); |
| 422 | |
| 423 | font->ascent = xftfont->ascent; |
| 424 | font->descent = xftfont->descent; |
| 425 | if (pixel_size >= 5) |
| 426 | { |
| 427 | /* The above condition is a dirty workaround because |
| 428 | XftTextExtents8 behaves strangely for some fonts |
| 429 | (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */ |
| 430 | if (font->ascent < extents.y) |
| 431 | font->ascent = extents.y; |
| 432 | if (font->descent < extents.height - extents.y) |
| 433 | font->descent = extents.height - extents.y; |
| 434 | } |
| 435 | font->height = font->ascent + font->descent; |
| 436 | |
| 437 | if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0) |
| 438 | { |
| 439 | int upEM = ft_face->units_per_EM; |
| 440 | |
| 441 | font->underline_position = -ft_face->underline_position * size / upEM; |
| 442 | font->underline_thickness = ft_face->underline_thickness * size / upEM; |
| 443 | if (font->underline_thickness > 2) |
| 444 | font->underline_position -= font->underline_thickness / 2; |
| 445 | } |
| 446 | else |
| 447 | { |
| 448 | font->underline_position = -1; |
| 449 | font->underline_thickness = 0; |
| 450 | } |
| 451 | #ifdef HAVE_LIBOTF |
| 452 | xftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0; |
| 453 | xftfont_info->otf = NULL; |
| 454 | #endif /* HAVE_LIBOTF */ |
| 455 | xftfont_info->ft_size = ft_face->size; |
| 456 | |
| 457 | font->baseline_offset = 0; |
| 458 | font->relative_compose = 0; |
| 459 | font->default_ascent = 0; |
| 460 | font->vertical_centering = 0; |
| 461 | #ifdef FT_BDF_H |
| 462 | if (! (ft_face->face_flags & FT_FACE_FLAG_SFNT)) |
| 463 | { |
| 464 | BDF_PropertyRec rec; |
| 465 | |
| 466 | if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &rec) == 0 |
| 467 | && rec.type == BDF_PROPERTY_TYPE_INTEGER) |
| 468 | font->baseline_offset = rec.u.integer; |
| 469 | if (FT_Get_BDF_Property (ft_face, "_MULE_RELATIVE_COMPOSE", &rec) == 0 |
| 470 | && rec.type == BDF_PROPERTY_TYPE_INTEGER) |
| 471 | font->relative_compose = rec.u.integer; |
| 472 | if (FT_Get_BDF_Property (ft_face, "_MULE_DEFAULT_ASCENT", &rec) == 0 |
| 473 | && rec.type == BDF_PROPERTY_TYPE_INTEGER) |
| 474 | font->default_ascent = rec.u.integer; |
| 475 | } |
| 476 | #endif |
| 477 | |
| 478 | return font_object; |
| 479 | } |
| 480 | |
| 481 | static void |
| 482 | xftfont_close (struct font *font) |
| 483 | { |
| 484 | struct xftfont_info *xftfont_info = (struct xftfont_info *) font; |
| 485 | |
| 486 | #ifdef HAVE_LIBOTF |
| 487 | if (xftfont_info->otf) |
| 488 | { |
| 489 | OTF_close (xftfont_info->otf); |
| 490 | xftfont_info->otf = NULL; |
| 491 | } |
| 492 | #endif |
| 493 | |
| 494 | if (xftfont_info->xftfont) |
| 495 | { |
| 496 | block_input (); |
| 497 | XftUnlockFace (xftfont_info->xftfont); |
| 498 | XftFontClose (xftfont_info->display, xftfont_info->xftfont); |
| 499 | unblock_input (); |
| 500 | xftfont_info->xftfont = NULL; |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | static int |
| 505 | xftfont_prepare_face (struct frame *f, struct face *face) |
| 506 | { |
| 507 | struct xftface_info *xftface_info; |
| 508 | |
| 509 | #if 0 |
| 510 | /* This doesn't work if face->ascii_face doesn't use an Xft font. */ |
| 511 | if (face != face->ascii_face) |
| 512 | { |
| 513 | face->extra = face->ascii_face->extra; |
| 514 | return 0; |
| 515 | } |
| 516 | #endif |
| 517 | |
| 518 | xftface_info = malloc (sizeof *xftface_info); |
| 519 | if (! xftface_info) |
| 520 | return -1; |
| 521 | xftfont_get_colors (f, face, face->gc, NULL, |
| 522 | &xftface_info->xft_fg, &xftface_info->xft_bg); |
| 523 | face->extra = xftface_info; |
| 524 | return 0; |
| 525 | } |
| 526 | |
| 527 | static void |
| 528 | xftfont_done_face (struct frame *f, struct face *face) |
| 529 | { |
| 530 | struct xftface_info *xftface_info; |
| 531 | |
| 532 | #if 0 |
| 533 | /* This doesn't work if face->ascii_face doesn't use an Xft font. */ |
| 534 | if (face != face->ascii_face |
| 535 | || ! face->extra) |
| 536 | return; |
| 537 | #endif |
| 538 | |
| 539 | xftface_info = (struct xftface_info *) face->extra; |
| 540 | if (xftface_info) |
| 541 | { |
| 542 | free (xftface_info); |
| 543 | face->extra = NULL; |
| 544 | } |
| 545 | } |
| 546 | |
| 547 | static int |
| 548 | xftfont_has_char (Lisp_Object font, int c) |
| 549 | { |
| 550 | struct xftfont_info *xftfont_info; |
| 551 | struct charset *cs = NULL; |
| 552 | |
| 553 | if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja) |
| 554 | && charset_jisx0208 >= 0) |
| 555 | cs = CHARSET_FROM_ID (charset_jisx0208); |
| 556 | else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko) |
| 557 | && charset_ksc5601 >= 0) |
| 558 | cs = CHARSET_FROM_ID (charset_ksc5601); |
| 559 | if (cs) |
| 560 | return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs)); |
| 561 | |
| 562 | if (FONT_ENTITY_P (font)) |
| 563 | return ftfont_driver.has_char (font, c); |
| 564 | xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font); |
| 565 | return (XftCharExists (xftfont_info->display, xftfont_info->xftfont, |
| 566 | (FcChar32) c) == FcTrue); |
| 567 | } |
| 568 | |
| 569 | static unsigned |
| 570 | xftfont_encode_char (struct font *font, int c) |
| 571 | { |
| 572 | struct xftfont_info *xftfont_info = (struct xftfont_info *) font; |
| 573 | unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont, |
| 574 | (FcChar32) c); |
| 575 | |
| 576 | return (code ? code : FONT_INVALID_CODE); |
| 577 | } |
| 578 | |
| 579 | static int |
| 580 | xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics) |
| 581 | { |
| 582 | struct xftfont_info *xftfont_info = (struct xftfont_info *) font; |
| 583 | XGlyphInfo extents; |
| 584 | |
| 585 | block_input (); |
| 586 | XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs, |
| 587 | &extents); |
| 588 | unblock_input (); |
| 589 | if (metrics) |
| 590 | { |
| 591 | metrics->lbearing = - extents.x; |
| 592 | metrics->rbearing = - extents.x + extents.width; |
| 593 | metrics->width = extents.xOff; |
| 594 | metrics->ascent = extents.y; |
| 595 | metrics->descent = extents.height - extents.y; |
| 596 | } |
| 597 | return extents.xOff; |
| 598 | } |
| 599 | |
| 600 | static XftDraw * |
| 601 | xftfont_get_xft_draw (struct frame *f) |
| 602 | { |
| 603 | XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver); |
| 604 | |
| 605 | if (! xft_draw) |
| 606 | { |
| 607 | block_input (); |
| 608 | xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f), |
| 609 | FRAME_X_WINDOW (f), |
| 610 | FRAME_X_VISUAL (f), |
| 611 | FRAME_X_COLORMAP (f)); |
| 612 | unblock_input (); |
| 613 | eassert (xft_draw != NULL); |
| 614 | font_put_frame_data (f, &xftfont_driver, xft_draw); |
| 615 | } |
| 616 | return xft_draw; |
| 617 | } |
| 618 | |
| 619 | static int |
| 620 | xftfont_draw (struct glyph_string *s, int from, int to, int x, int y, |
| 621 | bool with_background) |
| 622 | { |
| 623 | struct frame *f = s->f; |
| 624 | struct face *face = s->face; |
| 625 | struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font; |
| 626 | struct xftface_info *xftface_info = NULL; |
| 627 | XftDraw *xft_draw = xftfont_get_xft_draw (f); |
| 628 | FT_UInt *code; |
| 629 | XftColor fg, bg; |
| 630 | int len = to - from; |
| 631 | int i; |
| 632 | |
| 633 | if (s->font == face->font) |
| 634 | xftface_info = (struct xftface_info *) face->extra; |
| 635 | xftfont_get_colors (f, face, s->gc, xftface_info, |
| 636 | &fg, with_background ? &bg : NULL); |
| 637 | block_input (); |
| 638 | if (s->num_clips > 0) |
| 639 | XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips); |
| 640 | else |
| 641 | XftDrawSetClip (xft_draw, NULL); |
| 642 | |
| 643 | if (with_background) |
| 644 | XftDrawRect (xft_draw, &bg, |
| 645 | x, y - s->font->ascent, s->width, s->font->height); |
| 646 | code = alloca (sizeof (FT_UInt) * len); |
| 647 | for (i = 0; i < len; i++) |
| 648 | code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8) |
| 649 | | XCHAR2B_BYTE2 (s->char2b + from + i)); |
| 650 | |
| 651 | if (s->padding_p) |
| 652 | for (i = 0; i < len; i++) |
| 653 | XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont, |
| 654 | x + i, y, code + i, 1); |
| 655 | else |
| 656 | XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont, |
| 657 | x, y, code, len); |
| 658 | unblock_input (); |
| 659 | |
| 660 | return len; |
| 661 | } |
| 662 | |
| 663 | #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF |
| 664 | static Lisp_Object |
| 665 | xftfont_shape (Lisp_Object lgstring) |
| 666 | { |
| 667 | struct font *font; |
| 668 | struct xftfont_info *xftfont_info; |
| 669 | FT_Face ft_face; |
| 670 | Lisp_Object val; |
| 671 | |
| 672 | CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font); |
| 673 | xftfont_info = (struct xftfont_info *) font; |
| 674 | ft_face = XftLockFace (xftfont_info->xftfont); |
| 675 | xftfont_info->ft_size = ft_face->size; |
| 676 | val = ftfont_driver.shape (lgstring); |
| 677 | XftUnlockFace (xftfont_info->xftfont); |
| 678 | return val; |
| 679 | } |
| 680 | #endif |
| 681 | |
| 682 | static int |
| 683 | xftfont_end_for_frame (struct frame *f) |
| 684 | { |
| 685 | XftDraw *xft_draw; |
| 686 | |
| 687 | /* Don't do anything if display is dead */ |
| 688 | if (FRAME_X_DISPLAY (f) == NULL) return 0; |
| 689 | |
| 690 | xft_draw = font_get_frame_data (f, &xftfont_driver); |
| 691 | |
| 692 | if (xft_draw) |
| 693 | { |
| 694 | block_input (); |
| 695 | XftDrawDestroy (xft_draw); |
| 696 | unblock_input (); |
| 697 | font_put_frame_data (f, &xftfont_driver, NULL); |
| 698 | } |
| 699 | return 0; |
| 700 | } |
| 701 | |
| 702 | static bool |
| 703 | xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object, |
| 704 | Lisp_Object entity) |
| 705 | { |
| 706 | struct xftfont_info *info = (struct xftfont_info *) XFONT_OBJECT (font_object); |
| 707 | FcPattern *oldpat = info->xftfont->pattern; |
| 708 | Display *display = FRAME_X_DISPLAY (f); |
| 709 | FcPattern *pat = FcPatternCreate (); |
| 710 | FcBool b1, b2; |
| 711 | bool ok = 0; |
| 712 | int i1, i2, r1, r2; |
| 713 | |
| 714 | xftfont_add_rendering_parameters (pat, entity); |
| 715 | XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat); |
| 716 | |
| 717 | r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1); |
| 718 | r2 = FcPatternGetBool (oldpat, FC_ANTIALIAS, 0, &b2); |
| 719 | if (r1 != r2 || b1 != b2) goto out; |
| 720 | r1 = FcPatternGetBool (pat, FC_HINTING, 0, &b1); |
| 721 | r2 = FcPatternGetBool (oldpat, FC_HINTING, 0, &b2); |
| 722 | if (r1 != r2 || b1 != b2) goto out; |
| 723 | r1 = FcPatternGetBool (pat, FC_AUTOHINT, 0, &b1); |
| 724 | r2 = FcPatternGetBool (oldpat, FC_AUTOHINT, 0, &b2); |
| 725 | if (r1 != r2 || b1 != b2) goto out; |
| 726 | #ifdef FC_EMBOLDEN |
| 727 | r1 = FcPatternGetBool (pat, FC_EMBOLDEN, 0, &b1); |
| 728 | r2 = FcPatternGetBool (oldpat, FC_EMBOLDEN, 0, &b2); |
| 729 | if (r1 != r2 || b1 != b2) goto out; |
| 730 | #endif |
| 731 | r1 = FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i1); |
| 732 | r2 = FcPatternGetInteger (oldpat, FC_HINT_STYLE, 0, &i2); |
| 733 | if (r1 != r2 || i1 != i2) goto out; |
| 734 | r1 = FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i1); |
| 735 | r2 = FcPatternGetInteger (oldpat, FC_LCD_FILTER, 0, &i2); |
| 736 | if (r1 != r2 || i1 != i2) goto out; |
| 737 | r1 = FcPatternGetInteger (pat, FC_RGBA, 0, &i1); |
| 738 | r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2); |
| 739 | if (r1 != r2 || i1 != i2) goto out; |
| 740 | |
| 741 | ok = 1; |
| 742 | out: |
| 743 | FcPatternDestroy (pat); |
| 744 | return ok; |
| 745 | } |
| 746 | |
| 747 | void |
| 748 | syms_of_xftfont (void) |
| 749 | { |
| 750 | DEFSYM (Qxft, "xft"); |
| 751 | DEFSYM (QChinting, ":hinting"); |
| 752 | DEFSYM (QCautohint, ":autohint"); |
| 753 | DEFSYM (QChintstyle, ":hintstyle"); |
| 754 | DEFSYM (QCrgba, ":rgba"); |
| 755 | DEFSYM (QCembolden, ":embolden"); |
| 756 | DEFSYM (QClcdfilter, ":lcdfilter"); |
| 757 | |
| 758 | ascii_printable[0] = 0; |
| 759 | |
| 760 | xftfont_driver = ftfont_driver; |
| 761 | xftfont_driver.type = Qxft; |
| 762 | xftfont_driver.get_cache = xfont_driver.get_cache; |
| 763 | xftfont_driver.list = xftfont_list; |
| 764 | xftfont_driver.match = xftfont_match; |
| 765 | xftfont_driver.open = xftfont_open; |
| 766 | xftfont_driver.close = xftfont_close; |
| 767 | xftfont_driver.prepare_face = xftfont_prepare_face; |
| 768 | xftfont_driver.done_face = xftfont_done_face; |
| 769 | xftfont_driver.has_char = xftfont_has_char; |
| 770 | xftfont_driver.encode_char = xftfont_encode_char; |
| 771 | xftfont_driver.text_extents = xftfont_text_extents; |
| 772 | xftfont_driver.draw = xftfont_draw; |
| 773 | xftfont_driver.end_for_frame = xftfont_end_for_frame; |
| 774 | xftfont_driver.cached_font_ok = xftfont_cached_font_ok; |
| 775 | #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF) |
| 776 | xftfont_driver.shape = xftfont_shape; |
| 777 | #endif |
| 778 | |
| 779 | register_font_driver (&xftfont_driver, NULL); |
| 780 | } |