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