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