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