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