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