Add 2012 to FSF copyright years for Emacs files
[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
42static Lisp_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;
ea2460a0
KH
417 if (spacing != FC_PROPORTIONAL
418#ifdef FC_DUAL
419 && spacing != FC_DUAL
420#endif /* FC_DUAL */
421 )
91c5bb27 422 {
3528e709 423 font->min_width = font->average_width = font->space_width
91c5bb27
KH
424 = xftfont->max_advance_width;
425 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
426 }
c2f5bfd6
KH
427 else
428 {
c2f5bfd6 429 XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
3528e709
KH
430 font->space_width = extents.xOff;
431 if (font->space_width <= 0)
c2f5bfd6 432 /* dirty workaround */
8510724d 433 font->space_width = pixel_size;
c2f5bfd6 434 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
3528e709 435 font->average_width = (font->space_width + extents.xOff) / 95;
c2f5bfd6 436 }
dcce3c58 437 UNBLOCK_INPUT;
c2f5bfd6 438
91c5bb27 439 font->ascent = xftfont->ascent;
91c5bb27 440 font->descent = xftfont->descent;
81094fab
KH
441 if (pixel_size >= 5)
442 {
443 /* The above condition is a dirty workaround because
444 XftTextExtents8 behaves strangely for some fonts
445 (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */
446 if (font->ascent < extents.y)
447 font->ascent = extents.y;
448 if (font->descent < extents.height - extents.y)
449 font->descent = extents.height - extents.y;
450 }
3528e709 451 font->height = font->ascent + font->descent;
91c5bb27 452
3528e709 453 if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
c2f5bfd6 454 {
3528e709
KH
455 int upEM = ft_face->units_per_EM;
456
457 font->underline_position = -ft_face->underline_position * size / upEM;
bc981e4e 458 font->underline_thickness = ft_face->underline_thickness * size / upEM;
951b8112
KH
459 if (font->underline_thickness > 2)
460 font->underline_position -= font->underline_thickness / 2;
c2f5bfd6
KH
461 }
462 else
463 {
3528e709
KH
464 font->underline_position = -1;
465 font->underline_thickness = 0;
c2f5bfd6 466 }
3528e709
KH
467#ifdef HAVE_LIBOTF
468 xftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
469 xftfont_info->otf = NULL;
470#endif /* HAVE_LIBOTF */
0fce2b40 471 xftfont_info->ft_size = ft_face->size;
c2f5bfd6 472
3528e709
KH
473 /* Unfortunately Xft doesn't provide a way to get minimum char
474 width. So, we use space_width instead. */
475 font->min_width = font->space_width;
2d93c6bd 476
3528e709
KH
477 font->baseline_offset = 0;
478 font->relative_compose = 0;
479 font->default_ascent = 0;
480 font->vertical_centering = 0;
0fce2b40
KH
481#ifdef FT_BDF_H
482 if (! (ft_face->face_flags & FT_FACE_FLAG_SFNT))
483 {
484 BDF_PropertyRec rec;
485
486 if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &rec) == 0
487 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
488 font->baseline_offset = rec.u.integer;
489 if (FT_Get_BDF_Property (ft_face, "_MULE_RELATIVE_COMPOSE", &rec) == 0
490 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
491 font->relative_compose = rec.u.integer;
492 if (FT_Get_BDF_Property (ft_face, "_MULE_DEFAULT_ASCENT", &rec) == 0
493 && rec.type == BDF_PROPERTY_TYPE_INTEGER)
494 font->default_ascent = rec.u.integer;
495 }
496#endif
3528e709
KH
497
498 return font_object;
c2f5bfd6
KH
499}
500
501static void
971de7fb 502xftfont_close (FRAME_PTR f, struct font *font)
c2f5bfd6
KH
503{
504 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
505
4613015e
KH
506#ifdef HAVE_LIBOTF
507 if (xftfont_info->otf)
508 OTF_close (xftfont_info->otf);
509#endif
3528e709 510 BLOCK_INPUT;
0fce2b40 511 XftUnlockFace (xftfont_info->xftfont);
c2f5bfd6 512 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
3528e709 513 UNBLOCK_INPUT;
c2f5bfd6
KH
514}
515
c2f5bfd6 516static int
971de7fb 517xftfont_prepare_face (FRAME_PTR f, struct face *face)
c2f5bfd6 518{
e2d0c925 519 struct xftface_info *xftface_info;
c2f5bfd6 520
a703d27d
KH
521#if 0
522 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
523 if (face != face->ascii_face)
524 {
525 face->extra = face->ascii_face->extra;
526 return 0;
527 }
a703d27d 528#endif
e2d0c925
KH
529
530 xftface_info = malloc (sizeof (struct xftface_info));
c2f5bfd6
KH
531 if (! xftface_info)
532 return -1;
c2f5bfd6
KH
533 xftfont_get_colors (f, face, face->gc, NULL,
534 &xftface_info->xft_fg, &xftface_info->xft_bg);
c2f5bfd6
KH
535 face->extra = xftface_info;
536 return 0;
537}
538
539static void
971de7fb 540xftfont_done_face (FRAME_PTR f, struct face *face)
c2f5bfd6 541{
e2d0c925 542 struct xftface_info *xftface_info;
8510724d 543
a703d27d
KH
544#if 0
545 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
546 if (face != face->ascii_face
547 || ! face->extra)
548 return;
a703d27d 549#endif
c2f5bfd6 550
e2d0c925 551 xftface_info = (struct xftface_info *) face->extra;
773039e8
JD
552 if (xftface_info)
553 {
773039e8 554 free (xftface_info);
a92ee6bf 555 face->extra = NULL;
773039e8 556 }
c2f5bfd6
KH
557}
558
6570a1c4 559static int
971de7fb 560xftfont_has_char (Lisp_Object font, int c)
6570a1c4
KH
561{
562 struct xftfont_info *xftfont_info;
b840b299 563 struct charset *cs = NULL;
6570a1c4 564
b840b299
KH
565 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
566 && charset_jisx0208 >= 0)
567 cs = CHARSET_FROM_ID (charset_jisx0208);
568 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
569 && charset_ksc5601 >= 0)
570 cs = CHARSET_FROM_ID (charset_ksc5601);
571 if (cs)
572 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
573
ea12eb81
KH
574 if (FONT_ENTITY_P (font))
575 return ftfont_driver.has_char (font, c);
6570a1c4
KH
576 xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font);
577 return (XftCharExists (xftfont_info->display, xftfont_info->xftfont,
578 (FcChar32) c) == FcTrue);
579}
580
c2f5bfd6 581static unsigned
971de7fb 582xftfont_encode_char (struct font *font, int c)
c2f5bfd6
KH
583{
584 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
585 unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
586 (FcChar32) c);
8510724d 587
b5b2545a 588 return (code ? code : FONT_INVALID_CODE);
c2f5bfd6
KH
589}
590
591static int
971de7fb 592xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
c2f5bfd6
KH
593{
594 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
595 XGlyphInfo extents;
596
597 BLOCK_INPUT;
598 XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
599 &extents);
600 UNBLOCK_INPUT;
601 if (metrics)
602 {
603 metrics->lbearing = - extents.x;
604 metrics->rbearing = - extents.x + extents.width;
605 metrics->width = extents.xOff;
606 metrics->ascent = extents.y;
4b848612 607 metrics->descent = extents.height - extents.y;
c2f5bfd6
KH
608 }
609 return extents.xOff;
610}
611
a92ee6bf 612static XftDraw *
971de7fb 613xftfont_get_xft_draw (FRAME_PTR f)
a92ee6bf 614{
8510724d 615 XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
a92ee6bf
KH
616
617 if (! xft_draw)
618 {
619 BLOCK_INPUT;
620 xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
621 FRAME_X_WINDOW (f),
622 FRAME_X_VISUAL (f),
623 FRAME_X_COLORMAP (f));
624 UNBLOCK_INPUT;
625 if (! xft_draw)
626 abort ();
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
KH
767
768 xftfont_driver = ftfont_driver;
769 xftfont_driver.type = Qxft;
770 xftfont_driver.get_cache = xfont_driver.get_cache;
771 xftfont_driver.list = xftfont_list;
10aca0f7 772 xftfont_driver.match = xftfont_match;
c2f5bfd6
KH
773 xftfont_driver.open = xftfont_open;
774 xftfont_driver.close = xftfont_close;
775 xftfont_driver.prepare_face = xftfont_prepare_face;
776 xftfont_driver.done_face = xftfont_done_face;
6570a1c4 777 xftfont_driver.has_char = xftfont_has_char;
c2f5bfd6
KH
778 xftfont_driver.encode_char = xftfont_encode_char;
779 xftfont_driver.text_extents = xftfont_text_extents;
780 xftfont_driver.draw = xftfont_draw;
a92ee6bf 781 xftfont_driver.end_for_frame = xftfont_end_for_frame;
d0cf45b7 782 xftfont_driver.cached_font_ok = xftfont_cached_font_ok;
31daa5e1
KH
783#if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
784 xftfont_driver.shape = xftfont_shape;
785#endif
c2f5bfd6
KH
786
787 register_font_driver (&xftfont_driver, NULL);
788}