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