Merge from trunk
[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;
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
73static void xftfont_get_colors P_ ((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
KH
82static void
83xftfont_get_colors (f, face, gc, xftface_info, fg, bg)
84 FRAME_PTR f;
85 struct face *face;
86 GC gc;
87 struct xftface_info *xftface_info;
88 XftColor *fg, *bg;
89{
90 if (xftface_info && face->gc == gc)
91 {
92 *fg = xftface_info->xft_fg;
93 if (bg)
94 *bg = xftface_info->xft_bg;
95 }
96 else
97 {
98 XGCValues xgcv;
99 int fg_done = 0, bg_done = 0;
100
101 BLOCK_INPUT;
102 XGetGCValues (FRAME_X_DISPLAY (f), gc,
103 GCForeground | GCBackground, &xgcv);
104 if (xftface_info)
105 {
106 if (xgcv.foreground == face->foreground)
107 *fg = xftface_info->xft_fg, fg_done = 1;
108 else if (xgcv.foreground == face->background)
109 *fg = xftface_info->xft_bg, fg_done = 1;
110 if (! bg)
111 bg_done = 1;
112 else if (xgcv.background == face->background)
113 *bg = xftface_info->xft_bg, bg_done = 1;
114 else if (xgcv.background == face->foreground)
115 *bg = xftface_info->xft_fg, bg_done = 1;
116 }
117
118 if (fg_done + bg_done < 2)
119 {
120 XColor colors[2];
121
122 colors[0].pixel = fg->pixel = xgcv.foreground;
123 if (bg)
124 colors[1].pixel = bg->pixel = xgcv.background;
125 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors,
126 bg ? 2 : 1);
127 fg->color.alpha = 0xFFFF;
128 fg->color.red = colors[0].red;
129 fg->color.green = colors[0].green;
130 fg->color.blue = colors[0].blue;
131 if (bg)
132 {
133 bg->color.alpha = 0xFFFF;
134 bg->color.red = colors[1].red;
135 bg->color.green = colors[1].green;
136 bg->color.blue = colors[1].blue;
137 }
138 }
139 UNBLOCK_INPUT;
140 }
141}
142
c2f5bfd6
KH
143
144static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
10aca0f7 145static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
3528e709 146static Lisp_Object xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
c2f5bfd6
KH
147static void xftfont_close P_ ((FRAME_PTR, struct font *));
148static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
149static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
6570a1c4 150static int xftfont_has_char P_ ((Lisp_Object, int));
c2f5bfd6
KH
151static unsigned xftfont_encode_char P_ ((struct font *, int));
152static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
153 struct font_metrics *));
154static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
a92ee6bf 155static int xftfont_end_for_frame P_ ((FRAME_PTR f));
c2f5bfd6
KH
156
157struct font_driver xftfont_driver;
158
159static Lisp_Object
160xftfont_list (frame, spec)
161 Lisp_Object frame;
162 Lisp_Object spec;
163{
3528e709 164 Lisp_Object list = ftfont_driver.list (frame, spec), tail;
8510724d 165
3528e709
KH
166 for (tail = list; CONSP (tail); tail = XCDR (tail))
167 ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
168 return list;
c2f5bfd6
KH
169}
170
10aca0f7
KH
171static Lisp_Object
172xftfont_match (frame, spec)
173 Lisp_Object frame;
174 Lisp_Object spec;
175{
176 Lisp_Object entity = ftfont_driver.match (frame, spec);
177
3528e709 178 if (! NILP (entity))
10aca0f7
KH
179 ASET (entity, FONT_TYPE_INDEX, Qxft);
180 return entity;
181}
182
1cf6763f 183extern Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object));
0fce2b40 184extern FcCharSet *ftfont_get_fc_charset P_ ((Lisp_Object));
81094fab 185extern Lisp_Object QCantialias;
98d12656 186
c2f5bfd6
KH
187static FcChar8 ascii_printable[95];
188
637fa988
JD
189static void
190xftfont_fix_match (pat, match)
191 FcPattern *pat, *match;
192{
193 /* These values are not used for matching (except antialias), but for
194 rendering, so make sure they are carried over to the match.
195 We also put antialias here because most fonts are antialiased, so
196 the match will have antialias true. */
197
198 FcBool b = FcTrue;
199 int i;
200 double dpi;
201
202 FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b);
203 if (! b)
204 {
205 FcPatternDel (match, FC_ANTIALIAS);
206 FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
207 }
208 FcPatternGetBool (pat, FC_HINTING, 0, &b);
209 if (! b)
210 {
211 FcPatternDel (match, FC_HINTING);
212 FcPatternAddBool (match, FC_HINTING, FcFalse);
213 }
214 if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i))
215 {
216 FcPatternDel (match, FC_HINT_STYLE);
217 FcPatternAddInteger (match, FC_HINT_STYLE, i);
218 }
21050de1 219#ifndef FC_LCD_FILTER
a6eb20d8 220 /* Older fontconfig versions don't have FC_LCD_FILTER. */
21050de1
JD
221#define FC_LCD_FILTER "lcdfilter"
222#endif
637fa988
JD
223 if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i))
224 {
225 FcPatternDel (match, FC_LCD_FILTER);
226 FcPatternAddInteger (match, FC_LCD_FILTER, i);
227 }
228 if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i))
229 {
230 FcPatternDel (match, FC_RGBA);
231 FcPatternAddInteger (match, FC_RGBA, i);
232 }
233 if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi))
234 {
235 FcPatternDel (match, FC_DPI);
236 FcPatternAddDouble (match, FC_DPI, dpi);
237 }
238}
239
3528e709 240static Lisp_Object
c2f5bfd6
KH
241xftfont_open (f, entity, pixel_size)
242 FRAME_PTR f;
243 Lisp_Object entity;
244 int pixel_size;
245{
81094fab 246 FcResult result;
c2f5bfd6 247 Display *display = FRAME_X_DISPLAY (f);
0fce2b40 248 Lisp_Object val, filename, index, tail, font_object;
81094fab 249 FcPattern *pat = NULL, *match;
2d93c6bd 250 struct xftfont_info *xftfont_info = NULL;
c2f5bfd6
KH
251 struct font *font;
252 double size = 0;
2d93c6bd 253 XftFont *xftfont = NULL;
c2f5bfd6 254 int spacing;
3528e709 255 char name[256];
223e5fc6 256 int len, i, ival;
91c5bb27 257 XGlyphInfo extents;
365131ac 258 FT_Face ft_face;
91ce2415 259 FcMatrix *matrix;
c2f5bfd6 260
3528e709 261 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
686ee703 262 if (! CONSP (val))
3528e709 263 return Qnil;
686ee703
KH
264 val = XCDR (val);
265 filename = XCAR (val);
0fce2b40 266 index = XCDR (val);
c2f5bfd6
KH
267 size = XINT (AREF (entity, FONT_SIZE_INDEX));
268 if (size == 0)
269 size = pixel_size;
270 pat = FcPatternCreate ();
81094fab
KH
271 FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
272 i = FONT_SLANT_NUMERIC (entity) - 100;
273 if (i < 0) i = 0;
274 FcPatternAddInteger (pat, FC_SLANT, i);
275 FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
c2f5bfd6 276 FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
3cc2aca0
KH
277 val = AREF (entity, FONT_FAMILY_INDEX);
278 if (! NILP (val))
279 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
dc2226d0
KH
280 val = AREF (entity, FONT_FOUNDRY_INDEX);
281 if (! NILP (val))
282 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
283 val = AREF (entity, FONT_SPACING_INDEX);
284 if (! NILP (val))
285 FcPatternAddInteger (pat, FC_SPACING, XINT (val));
286 val = AREF (entity, FONT_DPI_INDEX);
287 if (! NILP (val))
288 {
289 double dbl = XINT (val);
290
291 FcPatternAddDouble (pat, FC_DPI, dbl);
292 }
293 val = AREF (entity, FONT_AVGWIDTH_INDEX);
294 if (INTEGERP (val) && XINT (val) == 0)
295 FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
0fce2b40
KH
296 /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
297 over 10x20-ISO8859-1.pcf.gz). */
298 FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
dc2226d0 299
81094fab
KH
300 for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
301 {
302 Lisp_Object key, val;
303
304 key = XCAR (XCAR (tail)), val = XCDR (XCAR (tail));
305 if (EQ (key, QCantialias))
637fa988 306 FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
81094fab
KH
307 else if (EQ (key, QChinting))
308 FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
309 else if (EQ (key, QCautohint))
310 FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
311 else if (EQ (key, QChintstyle))
312 {
313 if (INTEGERP (val))
ea12eb81 314 FcPatternAddInteger (pat, FC_HINT_STYLE, XINT (val));
223e5fc6
JD
315 else if (SYMBOLP (val)
316 && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
317 FcPatternAddInteger (pat, FC_HINT_STYLE, ival);
81094fab
KH
318 }
319 else if (EQ (key, QCrgba))
320 {
321 if (INTEGERP (val))
322 FcPatternAddInteger (pat, FC_RGBA, XINT (val));
223e5fc6
JD
323 else if (SYMBOLP (val)
324 && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
325 FcPatternAddInteger (pat, FC_RGBA, ival);
326 }
327 else if (EQ (key, QClcdfilter))
328 {
329 if (INTEGERP (val))
330 FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XINT (val));
331 else if (SYMBOLP (val)
332 && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
333 FcPatternAddInteger (pat, FC_LCD_FILTER, ival);
81094fab 334 }
808dd567 335#ifdef FC_EMBOLDEN
81094fab
KH
336 else if (EQ (key, QCembolden))
337 FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
808dd567 338#endif
81094fab 339 }
dcce3c58 340
0fce2b40
KH
341 FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
342 FcPatternAddInteger (pat, FC_INDEX, XINT (index));
8510724d 343
0fce2b40 344
dcce3c58 345 BLOCK_INPUT;
9cb363db
YM
346 /* Make sure that the Xrender extension is added before the Xft one.
347 Otherwise, the close-display hook set by Xft is called after the
348 one for Xrender, and the former tries to re-add the latter. This
349 results in inconsistency of internal states and leads to X
350 protocol error when one reconnects to the same X server.
351 (Bug#1696) */
352 {
353 int event_base, error_base;
354 XRenderQueryExtension (display, &event_base, &error_base);
355 }
637fa988
JD
356
357 /* Substitute in values from X resources and XftDefaultSet. */
358 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
81094fab 359 match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
637fa988 360 xftfont_fix_match (pat, match);
223e5fc6 361
81094fab
KH
362 FcPatternDestroy (pat);
363 xftfont = XftFontOpenPattern (display, match);
99061dfc 364 if (!xftfont)
5c629bf6 365 {
99061dfc 366 UNBLOCK_INPUT;
5c629bf6
CY
367 XftPatternDestroy (match);
368 return Qnil;
369 }
99061dfc
CY
370 ft_face = XftLockFace (xftfont);
371 UNBLOCK_INPUT;
372
c2f5bfd6
KH
373 /* We should not destroy PAT here because it is kept in XFTFONT and
374 destroyed automatically when XFTFONT is closed. */
0fce2b40 375 font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
3528e709 376 ASET (font_object, FONT_TYPE_INDEX, Qxft);
3528e709
KH
377 len = font_unparse_xlfd (entity, size, name, 256);
378 if (len > 0)
2781b4e0 379 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
3528e709
KH
380 len = font_unparse_fcname (entity, size, name, 256);
381 if (len > 0)
2781b4e0 382 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
3528e709
KH
383 else
384 ASET (font_object, FONT_FULLNAME_INDEX,
385 AREF (font_object, FONT_NAME_INDEX));
686ee703
KH
386 ASET (font_object, FONT_FILE_INDEX, filename);
387 ASET (font_object, FONT_FORMAT_INDEX,
1cf6763f 388 ftfont_font_format (xftfont->pattern, filename));
3528e709
KH
389 font = XFONT_OBJECT (font_object);
390 font->pixel_size = pixel_size;
391 font->driver = &xftfont_driver;
392 font->encoding_charset = font->repertory_charset = -1;
393
394 xftfont_info = (struct xftfont_info *) font;
c2f5bfd6
KH
395 xftfont_info->display = display;
396 xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
397 xftfont_info->xftfont = xftfont;
91ce2415
KH
398 /* This means that there's no need of transformation. */
399 xftfont_info->matrix.xx = 0;
400 if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix)
401 == FcResultMatch)
402 {
403 xftfont_info->matrix.xx = 0x10000L * matrix->xx;
404 xftfont_info->matrix.yy = 0x10000L * matrix->yy;
405 xftfont_info->matrix.xy = 0x10000L * matrix->xy;
406 xftfont_info->matrix.yx = 0x10000L * matrix->yx;
407 }
c2f5bfd6
KH
408 font->pixel_size = size;
409 font->driver = &xftfont_driver;
686ee703
KH
410 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
411 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
412 else
c2f5bfd6 413 spacing = FC_PROPORTIONAL;
91c5bb27
KH
414 if (! ascii_printable[0])
415 {
416 int i;
417 for (i = 0; i < 95; i++)
418 ascii_printable[i] = ' ' + i;
419 }
3528e709 420 BLOCK_INPUT;
c2f5bfd6 421 if (spacing != FC_PROPORTIONAL)
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
502xftfont_close (f, font)
503 FRAME_PTR f;
504 struct font *font;
505{
506 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
507
4613015e
KH
508#ifdef HAVE_LIBOTF
509 if (xftfont_info->otf)
510 OTF_close (xftfont_info->otf);
511#endif
3528e709 512 BLOCK_INPUT;
0fce2b40 513 XftUnlockFace (xftfont_info->xftfont);
c2f5bfd6 514 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
3528e709 515 UNBLOCK_INPUT;
c2f5bfd6
KH
516}
517
c2f5bfd6
KH
518static int
519xftfont_prepare_face (f, face)
520 FRAME_PTR f;
521 struct face *face;
522{
e2d0c925 523 struct xftface_info *xftface_info;
c2f5bfd6 524
a703d27d
KH
525#if 0
526 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
527 if (face != face->ascii_face)
528 {
529 face->extra = face->ascii_face->extra;
530 return 0;
531 }
a703d27d 532#endif
e2d0c925
KH
533
534 xftface_info = malloc (sizeof (struct xftface_info));
c2f5bfd6
KH
535 if (! xftface_info)
536 return -1;
c2f5bfd6
KH
537 xftfont_get_colors (f, face, face->gc, NULL,
538 &xftface_info->xft_fg, &xftface_info->xft_bg);
c2f5bfd6
KH
539 face->extra = xftface_info;
540 return 0;
541}
542
543static void
544xftfont_done_face (f, face)
545 FRAME_PTR f;
546 struct face *face;
547{
e2d0c925 548 struct xftface_info *xftface_info;
8510724d 549
a703d27d
KH
550#if 0
551 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
552 if (face != face->ascii_face
553 || ! face->extra)
554 return;
a703d27d 555#endif
c2f5bfd6 556
e2d0c925 557 xftface_info = (struct xftface_info *) face->extra;
773039e8
JD
558 if (xftface_info)
559 {
773039e8 560 free (xftface_info);
a92ee6bf 561 face->extra = NULL;
773039e8 562 }
c2f5bfd6
KH
563}
564
b840b299
KH
565extern Lisp_Object Qja, Qko;
566
6570a1c4
KH
567static int
568xftfont_has_char (font, c)
569 Lisp_Object font;
570 int c;
571{
572 struct xftfont_info *xftfont_info;
b840b299 573 struct charset *cs = NULL;
6570a1c4 574
b840b299
KH
575 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
576 && charset_jisx0208 >= 0)
577 cs = CHARSET_FROM_ID (charset_jisx0208);
578 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
579 && charset_ksc5601 >= 0)
580 cs = CHARSET_FROM_ID (charset_ksc5601);
581 if (cs)
582 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
583
ea12eb81
KH
584 if (FONT_ENTITY_P (font))
585 return ftfont_driver.has_char (font, c);
6570a1c4
KH
586 xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font);
587 return (XftCharExists (xftfont_info->display, xftfont_info->xftfont,
588 (FcChar32) c) == FcTrue);
589}
590
c2f5bfd6
KH
591static unsigned
592xftfont_encode_char (font, c)
593 struct font *font;
594 int c;
595{
596 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
597 unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
598 (FcChar32) c);
8510724d 599
b5b2545a 600 return (code ? code : FONT_INVALID_CODE);
c2f5bfd6
KH
601}
602
603static int
604xftfont_text_extents (font, code, nglyphs, metrics)
605 struct font *font;
606 unsigned *code;
607 int nglyphs;
608 struct font_metrics *metrics;
609{
610 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
611 XGlyphInfo extents;
612
613 BLOCK_INPUT;
614 XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
615 &extents);
616 UNBLOCK_INPUT;
617 if (metrics)
618 {
619 metrics->lbearing = - extents.x;
620 metrics->rbearing = - extents.x + extents.width;
621 metrics->width = extents.xOff;
622 metrics->ascent = extents.y;
4b848612 623 metrics->descent = extents.height - extents.y;
c2f5bfd6
KH
624 }
625 return extents.xOff;
626}
627
a92ee6bf
KH
628static XftDraw *
629xftfont_get_xft_draw (f)
630 FRAME_PTR f;
631{
8510724d 632 XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
a92ee6bf
KH
633
634 if (! xft_draw)
635 {
636 BLOCK_INPUT;
637 xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
638 FRAME_X_WINDOW (f),
639 FRAME_X_VISUAL (f),
640 FRAME_X_COLORMAP (f));
641 UNBLOCK_INPUT;
642 if (! xft_draw)
643 abort ();
644 font_put_frame_data (f, &xftfont_driver, xft_draw);
645 }
646 return xft_draw;
647}
648
c2f5bfd6
KH
649static int
650xftfont_draw (s, from, to, x, y, with_background)
651 struct glyph_string *s;
652 int from, to, x, y, with_background;
653{
654 FRAME_PTR f = s->f;
655 struct face *face = s->face;
3528e709 656 struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font;
c78c1659 657 struct xftface_info *xftface_info = NULL;
a92ee6bf 658 XftDraw *xft_draw = xftfont_get_xft_draw (f);
c2f5bfd6
KH
659 FT_UInt *code;
660 XftColor fg, bg;
c2f5bfd6
KH
661 int len = to - from;
662 int i;
663
3528e709 664 if (s->font == face->font)
a92ee6bf 665 xftface_info = (struct xftface_info *) face->extra;
c2f5bfd6 666 xftfont_get_colors (f, face, s->gc, xftface_info,
322f8671 667 &fg, with_background ? &bg : NULL);
c2f5bfd6 668 BLOCK_INPUT;
03d198e8
KH
669 if (s->num_clips > 0)
670 XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips);
671 else
672 XftDrawSetClip (xft_draw, NULL);
673
c2f5bfd6 674 if (with_background)
3528e709
KH
675 XftDrawRect (xft_draw, &bg,
676 x, y - face->font->ascent, s->width, face->font->height);
c2f5bfd6
KH
677 code = alloca (sizeof (FT_UInt) * len);
678 for (i = 0; i < len; i++)
679 code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
680 | XCHAR2B_BYTE2 (s->char2b + from + i));
681
785543da
KH
682 if (s->padding_p)
683 for (i = 0; i < len; i++)
684 XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
685 x + i, y, code + i, 1);
686 else
687 XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
688 x, y, code, len);
c2f5bfd6
KH
689 UNBLOCK_INPUT;
690
691 return len;
692}
693
a92ee6bf
KH
694static int
695xftfont_end_for_frame (f)
696 FRAME_PTR f;
697{
ece2d4ed
JD
698 XftDraw *xft_draw;
699
700 /* Don't do anything if display is dead */
701 if (FRAME_X_DISPLAY (f) == NULL) return 0;
702
703 xft_draw = font_get_frame_data (f, &xftfont_driver);
a92ee6bf
KH
704
705 if (xft_draw)
706 {
707 BLOCK_INPUT;
708 XftDrawDestroy (xft_draw);
709 UNBLOCK_INPUT;
710 font_put_frame_data (f, &xftfont_driver, NULL);
711 }
712 return 0;
713}
c2f5bfd6
KH
714
715void
716syms_of_xftfont ()
717{
718 DEFSYM (Qxft, "xft");
81094fab 719 DEFSYM (QChinting, ":hinting");
9743ac48 720 DEFSYM (QCautohint, ":autohint");
81094fab
KH
721 DEFSYM (QChintstyle, ":hintstyle");
722 DEFSYM (QCrgba, ":rgba");
723 DEFSYM (QCembolden, ":embolden");
223e5fc6 724 DEFSYM (QClcdfilter, ":lcdfilter");
c2f5bfd6
KH
725
726 xftfont_driver = ftfont_driver;
727 xftfont_driver.type = Qxft;
728 xftfont_driver.get_cache = xfont_driver.get_cache;
729 xftfont_driver.list = xftfont_list;
10aca0f7 730 xftfont_driver.match = xftfont_match;
c2f5bfd6
KH
731 xftfont_driver.open = xftfont_open;
732 xftfont_driver.close = xftfont_close;
733 xftfont_driver.prepare_face = xftfont_prepare_face;
734 xftfont_driver.done_face = xftfont_done_face;
6570a1c4 735 xftfont_driver.has_char = xftfont_has_char;
c2f5bfd6
KH
736 xftfont_driver.encode_char = xftfont_encode_char;
737 xftfont_driver.text_extents = xftfont_text_extents;
738 xftfont_driver.draw = xftfont_draw;
a92ee6bf 739 xftfont_driver.end_for_frame = xftfont_end_for_frame;
c2f5bfd6
KH
740
741 register_font_driver (&xftfont_driver, NULL);
742}
885b7d09
MB
743
744/* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
745 (do not change this comment) */