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