* font.c (toplevel): Adjust comment about font cache layout.
[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;
c2f5bfd6
KH
62};
63
64/* Structure pointed by (struct face *)->extra */
10aca0f7 65
c2f5bfd6
KH
66struct xftface_info
67{
10aca0f7
KH
68 XftColor xft_fg; /* color for face->foreground */
69 XftColor xft_bg; /* color for face->background */
c2f5bfd6
KH
70};
71
10aca0f7
KH
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
c2f5bfd6 76static void
a10c8269
DA
77xftfont_get_colors (struct frame *f, struct face *face, GC gc,
78 struct xftface_info *xftface_info,
79 XftColor *fg, XftColor *bg)
c2f5bfd6
KH
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;
a864ef14 90 bool fg_done = 0, bg_done = 0;
c2f5bfd6 91
4d7e6e51 92 block_input ();
c2f5bfd6
KH
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
a864ef14 109 if (! (fg_done & bg_done))
c2f5bfd6
KH
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 }
4d7e6e51 130 unblock_input ();
c2f5bfd6
KH
131 }
132}
133
c2f5bfd6 134
c2f5bfd6
KH
135struct font_driver xftfont_driver;
136
137static Lisp_Object
fdb396e2 138xftfont_list (struct frame *f, Lisp_Object spec)
c2f5bfd6 139{
fdb396e2 140 Lisp_Object list = ftfont_driver.list (f, spec), tail;
8510724d 141
3528e709
KH
142 for (tail = list; CONSP (tail); tail = XCDR (tail))
143 ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
144 return list;
c2f5bfd6
KH
145}
146
10aca0f7 147static Lisp_Object
fdb396e2 148xftfont_match (struct frame *f, Lisp_Object spec)
10aca0f7 149{
fdb396e2 150 Lisp_Object entity = ftfont_driver.match (f, spec);
10aca0f7 151
3528e709 152 if (! NILP (entity))
10aca0f7
KH
153 ASET (entity, FONT_TYPE_INDEX, Qxft);
154 return entity;
155}
156
c2f5bfd6
KH
157static FcChar8 ascii_printable[95];
158
637fa988 159static void
971de7fb 160xftfont_fix_match (FcPattern *pat, FcPattern *match)
637fa988
JD
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);
af59aa6e 172 if (! b)
637fa988
JD
173 {
174 FcPatternDel (match, FC_ANTIALIAS);
175 FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
176 }
177 FcPatternGetBool (pat, FC_HINTING, 0, &b);
af59aa6e 178 if (! b)
637fa988
JD
179 {
180 FcPatternDel (match, FC_HINTING);
181 FcPatternAddBool (match, FC_HINTING, FcFalse);
182 }
af59aa6e
PE
183#ifndef FC_HINT_STYLE
184# define FC_HINT_STYLE "hintstyle"
185#endif
637fa988
JD
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 }
21050de1 191#ifndef FC_LCD_FILTER
a6eb20d8 192 /* Older fontconfig versions don't have FC_LCD_FILTER. */
21050de1
JD
193#define FC_LCD_FILTER "lcdfilter"
194#endif
637fa988
JD
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
d0cf45b7 212static void
971de7fb 213xftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity)
d0cf45b7
JD
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
3528e709 260static Lisp_Object
a10c8269 261xftfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
c2f5bfd6 262{
81094fab 263 FcResult result;
c2f5bfd6 264 Display *display = FRAME_X_DISPLAY (f);
001a7ab4 265 Lisp_Object val, filename, idx, font_object;
81094fab 266 FcPattern *pat = NULL, *match;
2d93c6bd 267 struct xftfont_info *xftfont_info = NULL;
c2f5bfd6
KH
268 struct font *font;
269 double size = 0;
2d93c6bd 270 XftFont *xftfont = NULL;
c2f5bfd6 271 int spacing;
3528e709 272 char name[256];
d0cf45b7 273 int len, i;
91c5bb27 274 XGlyphInfo extents;
365131ac 275 FT_Face ft_face;
91ce2415 276 FcMatrix *matrix;
c2f5bfd6 277
3528e709 278 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
686ee703 279 if (! CONSP (val))
3528e709 280 return Qnil;
686ee703
KH
281 val = XCDR (val);
282 filename = XCAR (val);
001a7ab4 283 idx = XCDR (val);
c2f5bfd6
KH
284 size = XINT (AREF (entity, FONT_SIZE_INDEX));
285 if (size == 0)
286 size = pixel_size;
287 pat = FcPatternCreate ();
81094fab
KH
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));
c2f5bfd6 293 FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
3cc2aca0
KH
294 val = AREF (entity, FONT_FAMILY_INDEX);
295 if (! NILP (val))
296 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
dc2226d0
KH
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);
0fce2b40
KH
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));
dc2226d0 316
d0cf45b7 317 xftfont_add_rendering_parameters (pat, entity);
dcce3c58 318
0fce2b40 319 FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
001a7ab4 320 FcPatternAddInteger (pat, FC_INDEX, XINT (idx));
8510724d 321
0fce2b40 322
4d7e6e51 323 block_input ();
9cb363db
YM
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 }
637fa988
JD
334
335 /* Substitute in values from X resources and XftDefaultSet. */
336 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
81094fab 337 match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
637fa988 338 xftfont_fix_match (pat, match);
223e5fc6 339
81094fab
KH
340 FcPatternDestroy (pat);
341 xftfont = XftFontOpenPattern (display, match);
99061dfc 342 if (!xftfont)
5c629bf6 343 {
4d7e6e51 344 unblock_input ();
5c629bf6
CY
345 XftPatternDestroy (match);
346 return Qnil;
347 }
99061dfc 348 ft_face = XftLockFace (xftfont);
4d7e6e51 349 unblock_input ();
99061dfc 350
c2f5bfd6
KH
351 /* We should not destroy PAT here because it is kept in XFTFONT and
352 destroyed automatically when XFTFONT is closed. */
0fce2b40 353 font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
3528e709 354 ASET (font_object, FONT_TYPE_INDEX, Qxft);
3528e709
KH
355 len = font_unparse_xlfd (entity, size, name, 256);
356 if (len > 0)
2781b4e0 357 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
3528e709
KH
358 len = font_unparse_fcname (entity, size, name, 256);
359 if (len > 0)
2781b4e0 360 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
3528e709
KH
361 else
362 ASET (font_object, FONT_FULLNAME_INDEX,
363 AREF (font_object, FONT_NAME_INDEX));
686ee703
KH
364 ASET (font_object, FONT_FILE_INDEX, filename);
365 ASET (font_object, FONT_FORMAT_INDEX,
1cf6763f 366 ftfont_font_format (xftfont->pattern, filename));
3528e709 367 font = XFONT_OBJECT (font_object);
12645ae6 368 font->pixel_size = size;
3528e709
KH
369 font->driver = &xftfont_driver;
370 font->encoding_charset = font->repertory_charset = -1;
371
372 xftfont_info = (struct xftfont_info *) font;
c2f5bfd6 373 xftfont_info->display = display;
c2f5bfd6 374 xftfont_info->xftfont = xftfont;
91ce2415
KH
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 }
686ee703
KH
385 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
386 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
387 else
c2f5bfd6 388 spacing = FC_PROPORTIONAL;
91c5bb27
KH
389 if (! ascii_printable[0])
390 {
001a7ab4
PE
391 int ch;
392 for (ch = 0; ch < 95; ch++)
393 ascii_printable[ch] = ' ' + ch;
91c5bb27 394 }
4d7e6e51 395 block_input ();
032a42c8
CY
396
397 /* Unfortunately Xft doesn't provide a way to get minimum char
398 width. So, we set min_width to space_width. */
399
ea2460a0
KH
400 if (spacing != FC_PROPORTIONAL
401#ifdef FC_DUAL
402 && spacing != FC_DUAL
403#endif /* FC_DUAL */
404 )
91c5bb27 405 {
032a42c8
CY
406 font->min_width = font->max_width = font->average_width
407 = font->space_width = xftfont->max_advance_width;
91c5bb27
KH
408 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
409 }
c2f5bfd6
KH
410 else
411 {
c2f5bfd6 412 XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
032a42c8
CY
413 font->min_width = font->max_width = font->space_width
414 = extents.xOff;
3528e709 415 if (font->space_width <= 0)
c2f5bfd6 416 /* dirty workaround */
8510724d 417 font->space_width = pixel_size;
c2f5bfd6 418 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
3528e709 419 font->average_width = (font->space_width + extents.xOff) / 95;
c2f5bfd6 420 }
4d7e6e51 421 unblock_input ();
c2f5bfd6 422
91c5bb27 423 font->ascent = xftfont->ascent;
91c5bb27 424 font->descent = xftfont->descent;
81094fab
KH
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 }
3528e709 435 font->height = font->ascent + font->descent;
91c5bb27 436
3528e709 437 if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
c2f5bfd6 438 {
3528e709
KH
439 int upEM = ft_face->units_per_EM;
440
441 font->underline_position = -ft_face->underline_position * size / upEM;
bc981e4e 442 font->underline_thickness = ft_face->underline_thickness * size / upEM;
951b8112
KH
443 if (font->underline_thickness > 2)
444 font->underline_position -= font->underline_thickness / 2;
c2f5bfd6
KH
445 }
446 else
447 {
3528e709
KH
448 font->underline_position = -1;
449 font->underline_thickness = 0;
c2f5bfd6 450 }
3528e709 451#ifdef HAVE_LIBOTF
a864ef14 452 xftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
3528e709
KH
453 xftfont_info->otf = NULL;
454#endif /* HAVE_LIBOTF */
0fce2b40 455 xftfont_info->ft_size = ft_face->size;
c2f5bfd6 456
3528e709
KH
457 font->baseline_offset = 0;
458 font->relative_compose = 0;
459 font->default_ascent = 0;
460 font->vertical_centering = 0;
0fce2b40
KH
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
3528e709
KH
477
478 return font_object;
c2f5bfd6
KH
479}
480
481static void
78e0b35c 482xftfont_close (struct font *font)
c2f5bfd6
KH
483{
484 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
485
4613015e
KH
486#ifdef HAVE_LIBOTF
487 if (xftfont_info->otf)
78e0b35c
DA
488 {
489 OTF_close (xftfont_info->otf);
490 xftfont_info->otf = NULL;
491 }
4613015e 492#endif
78e0b35c 493
5ae356d9
DA
494 /* See comment in xfont_close. */
495 if (xftfont_info->xftfont
496 && x_display_info_for_display (xftfont_info->display))
78e0b35c
DA
497 {
498 block_input ();
499 XftUnlockFace (xftfont_info->xftfont);
500 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
501 unblock_input ();
502 xftfont_info->xftfont = NULL;
503 }
c2f5bfd6
KH
504}
505
c2f5bfd6 506static int
a10c8269 507xftfont_prepare_face (struct frame *f, struct face *face)
c2f5bfd6 508{
e2d0c925 509 struct xftface_info *xftface_info;
c2f5bfd6 510
a703d27d
KH
511#if 0
512 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
513 if (face != face->ascii_face)
514 {
515 face->extra = face->ascii_face->extra;
516 return 0;
517 }
a703d27d 518#endif
e2d0c925 519
38182d90 520 xftface_info = malloc (sizeof *xftface_info);
c2f5bfd6
KH
521 if (! xftface_info)
522 return -1;
c2f5bfd6
KH
523 xftfont_get_colors (f, face, face->gc, NULL,
524 &xftface_info->xft_fg, &xftface_info->xft_bg);
c2f5bfd6
KH
525 face->extra = xftface_info;
526 return 0;
527}
528
529static void
a10c8269 530xftfont_done_face (struct frame *f, struct face *face)
c2f5bfd6 531{
e2d0c925 532 struct xftface_info *xftface_info;
8510724d 533
a703d27d
KH
534#if 0
535 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
536 if (face != face->ascii_face
537 || ! face->extra)
538 return;
a703d27d 539#endif
c2f5bfd6 540
e2d0c925 541 xftface_info = (struct xftface_info *) face->extra;
773039e8
JD
542 if (xftface_info)
543 {
773039e8 544 free (xftface_info);
a92ee6bf 545 face->extra = NULL;
773039e8 546 }
c2f5bfd6
KH
547}
548
6570a1c4 549static int
971de7fb 550xftfont_has_char (Lisp_Object font, int c)
6570a1c4
KH
551{
552 struct xftfont_info *xftfont_info;
b840b299 553 struct charset *cs = NULL;
6570a1c4 554
b840b299
KH
555 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
556 && charset_jisx0208 >= 0)
557 cs = CHARSET_FROM_ID (charset_jisx0208);
558 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
559 && charset_ksc5601 >= 0)
560 cs = CHARSET_FROM_ID (charset_ksc5601);
561 if (cs)
562 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
563
ea12eb81
KH
564 if (FONT_ENTITY_P (font))
565 return ftfont_driver.has_char (font, c);
6570a1c4
KH
566 xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font);
567 return (XftCharExists (xftfont_info->display, xftfont_info->xftfont,
568 (FcChar32) c) == FcTrue);
569}
570
c2f5bfd6 571static unsigned
971de7fb 572xftfont_encode_char (struct font *font, int c)
c2f5bfd6
KH
573{
574 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
575 unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
576 (FcChar32) c);
8510724d 577
b5b2545a 578 return (code ? code : FONT_INVALID_CODE);
c2f5bfd6
KH
579}
580
581static int
971de7fb 582xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
c2f5bfd6
KH
583{
584 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
585 XGlyphInfo extents;
586
4d7e6e51 587 block_input ();
c2f5bfd6
KH
588 XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
589 &extents);
4d7e6e51 590 unblock_input ();
c2f5bfd6
KH
591 if (metrics)
592 {
593 metrics->lbearing = - extents.x;
594 metrics->rbearing = - extents.x + extents.width;
595 metrics->width = extents.xOff;
596 metrics->ascent = extents.y;
4b848612 597 metrics->descent = extents.height - extents.y;
c2f5bfd6
KH
598 }
599 return extents.xOff;
600}
601
a92ee6bf 602static XftDraw *
a10c8269 603xftfont_get_xft_draw (struct frame *f)
a92ee6bf 604{
8510724d 605 XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
a92ee6bf
KH
606
607 if (! xft_draw)
608 {
4d7e6e51 609 block_input ();
a92ee6bf
KH
610 xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
611 FRAME_X_WINDOW (f),
612 FRAME_X_VISUAL (f),
613 FRAME_X_COLORMAP (f));
4d7e6e51 614 unblock_input ();
4e6a86c6 615 eassert (xft_draw != NULL);
a92ee6bf
KH
616 font_put_frame_data (f, &xftfont_driver, xft_draw);
617 }
618 return xft_draw;
619}
620
c2f5bfd6 621static int
a864ef14
PE
622xftfont_draw (struct glyph_string *s, int from, int to, int x, int y,
623 bool with_background)
c2f5bfd6 624{
a10c8269 625 struct frame *f = s->f;
c2f5bfd6 626 struct face *face = s->face;
3528e709 627 struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font;
c78c1659 628 struct xftface_info *xftface_info = NULL;
a92ee6bf 629 XftDraw *xft_draw = xftfont_get_xft_draw (f);
c2f5bfd6
KH
630 FT_UInt *code;
631 XftColor fg, bg;
c2f5bfd6
KH
632 int len = to - from;
633 int i;
634
3528e709 635 if (s->font == face->font)
a92ee6bf 636 xftface_info = (struct xftface_info *) face->extra;
c2f5bfd6 637 xftfont_get_colors (f, face, s->gc, xftface_info,
322f8671 638 &fg, with_background ? &bg : NULL);
4d7e6e51 639 block_input ();
03d198e8
KH
640 if (s->num_clips > 0)
641 XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips);
642 else
643 XftDrawSetClip (xft_draw, NULL);
644
c2f5bfd6 645 if (with_background)
3528e709 646 XftDrawRect (xft_draw, &bg,
100d5755 647 x, y - s->font->ascent, s->width, s->font->height);
c2f5bfd6
KH
648 code = alloca (sizeof (FT_UInt) * len);
649 for (i = 0; i < len; i++)
650 code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
651 | XCHAR2B_BYTE2 (s->char2b + from + i));
652
785543da
KH
653 if (s->padding_p)
654 for (i = 0; i < len; i++)
655 XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
656 x + i, y, code + i, 1);
657 else
658 XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
659 x, y, code, len);
4d7e6e51 660 unblock_input ();
c2f5bfd6
KH
661
662 return len;
663}
664
0248044d
PE
665#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
666static Lisp_Object
31daa5e1
KH
667xftfont_shape (Lisp_Object lgstring)
668{
669 struct font *font;
670 struct xftfont_info *xftfont_info;
671 FT_Face ft_face;
672 Lisp_Object val;
673
674 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
675 xftfont_info = (struct xftfont_info *) font;
676 ft_face = XftLockFace (xftfont_info->xftfont);
677 xftfont_info->ft_size = ft_face->size;
678 val = ftfont_driver.shape (lgstring);
679 XftUnlockFace (xftfont_info->xftfont);
680 return val;
681}
0248044d 682#endif
31daa5e1 683
a92ee6bf 684static int
a10c8269 685xftfont_end_for_frame (struct frame *f)
a92ee6bf 686{
ece2d4ed
JD
687 XftDraw *xft_draw;
688
689 /* Don't do anything if display is dead */
690 if (FRAME_X_DISPLAY (f) == NULL) return 0;
691
692 xft_draw = font_get_frame_data (f, &xftfont_driver);
a92ee6bf
KH
693
694 if (xft_draw)
695 {
4d7e6e51 696 block_input ();
a92ee6bf 697 XftDrawDestroy (xft_draw);
4d7e6e51 698 unblock_input ();
a92ee6bf
KH
699 font_put_frame_data (f, &xftfont_driver, NULL);
700 }
701 return 0;
702}
c2f5bfd6 703
a864ef14
PE
704static bool
705xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
706 Lisp_Object entity)
d0cf45b7
JD
707{
708 struct xftfont_info *info = (struct xftfont_info *) XFONT_OBJECT (font_object);
709 FcPattern *oldpat = info->xftfont->pattern;
710 Display *display = FRAME_X_DISPLAY (f);
711 FcPattern *pat = FcPatternCreate ();
712 FcBool b1, b2;
a864ef14
PE
713 bool ok = 0;
714 int i1, i2, r1, r2;
d0cf45b7
JD
715
716 xftfont_add_rendering_parameters (pat, entity);
717 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
718
719 r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1);
720 r2 = FcPatternGetBool (oldpat, FC_ANTIALIAS, 0, &b2);
721 if (r1 != r2 || b1 != b2) goto out;
722 r1 = FcPatternGetBool (pat, FC_HINTING, 0, &b1);
723 r2 = FcPatternGetBool (oldpat, FC_HINTING, 0, &b2);
724 if (r1 != r2 || b1 != b2) goto out;
725 r1 = FcPatternGetBool (pat, FC_AUTOHINT, 0, &b1);
726 r2 = FcPatternGetBool (oldpat, FC_AUTOHINT, 0, &b2);
727 if (r1 != r2 || b1 != b2) goto out;
728#ifdef FC_EMBOLDEN
729 r1 = FcPatternGetBool (pat, FC_EMBOLDEN, 0, &b1);
730 r2 = FcPatternGetBool (oldpat, FC_EMBOLDEN, 0, &b2);
731 if (r1 != r2 || b1 != b2) goto out;
732#endif
733 r1 = FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i1);
734 r2 = FcPatternGetInteger (oldpat, FC_HINT_STYLE, 0, &i2);
735 if (r1 != r2 || i1 != i2) goto out;
736 r1 = FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i1);
737 r2 = FcPatternGetInteger (oldpat, FC_LCD_FILTER, 0, &i2);
738 if (r1 != r2 || i1 != i2) goto out;
739 r1 = FcPatternGetInteger (pat, FC_RGBA, 0, &i1);
740 r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2);
741 if (r1 != r2 || i1 != i2) goto out;
742
743 ok = 1;
744 out:
745 FcPatternDestroy (pat);
746 return ok;
747}
748
c2f5bfd6 749void
971de7fb 750syms_of_xftfont (void)
c2f5bfd6
KH
751{
752 DEFSYM (Qxft, "xft");
81094fab 753 DEFSYM (QChinting, ":hinting");
9743ac48 754 DEFSYM (QCautohint, ":autohint");
81094fab
KH
755 DEFSYM (QChintstyle, ":hintstyle");
756 DEFSYM (QCrgba, ":rgba");
757 DEFSYM (QCembolden, ":embolden");
223e5fc6 758 DEFSYM (QClcdfilter, ":lcdfilter");
c2f5bfd6 759
032a42c8
CY
760 ascii_printable[0] = 0;
761
c2f5bfd6
KH
762 xftfont_driver = ftfont_driver;
763 xftfont_driver.type = Qxft;
764 xftfont_driver.get_cache = xfont_driver.get_cache;
765 xftfont_driver.list = xftfont_list;
10aca0f7 766 xftfont_driver.match = xftfont_match;
c2f5bfd6
KH
767 xftfont_driver.open = xftfont_open;
768 xftfont_driver.close = xftfont_close;
769 xftfont_driver.prepare_face = xftfont_prepare_face;
770 xftfont_driver.done_face = xftfont_done_face;
6570a1c4 771 xftfont_driver.has_char = xftfont_has_char;
c2f5bfd6
KH
772 xftfont_driver.encode_char = xftfont_encode_char;
773 xftfont_driver.text_extents = xftfont_text_extents;
774 xftfont_driver.draw = xftfont_draw;
a92ee6bf 775 xftfont_driver.end_for_frame = xftfont_end_for_frame;
d0cf45b7 776 xftfont_driver.cached_font_ok = xftfont_cached_font_ok;
31daa5e1
KH
777#if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
778 xftfont_driver.shape = xftfont_shape;
779#endif
c2f5bfd6
KH
780
781 register_font_driver (&xftfont_driver, NULL);
782}