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