]> code.delx.au - gnu-emacs/blob - src/xftfont.c
Parallelize documentation builds.
[gnu-emacs] / src / xftfont.c
1 /* xftfont.c -- XFT font driver.
2 Copyright (C) 2006-2013 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7 This file is part of GNU Emacs.
8
9 GNU Emacs is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 GNU Emacs is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <X11/Xlib.h>
25 #include <X11/Xft/Xft.h>
26
27 #include "lisp.h"
28 #include "dispextern.h"
29 #include "xterm.h"
30 #include "frame.h"
31 #include "blockinput.h"
32 #include "character.h"
33 #include "charset.h"
34 #include "composite.h"
35 #include "fontset.h"
36 #include "font.h"
37 #include "ftfont.h"
38
39 /* Xft font driver. */
40
41 Lisp_Object Qxft;
42 static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden,
43 QClcdfilter;
44
45 /* The actual structure for Xft font that can be casted to struct
46 font. */
47
48 struct xftfont_info
49 {
50 struct font font;
51 /* The following five members must be here in this order to be
52 compatible with struct ftfont_info (in ftfont.c). */
53 #ifdef HAVE_LIBOTF
54 bool maybe_otf; /* Flag to tell if this may be OTF or not. */
55 OTF *otf;
56 #endif /* HAVE_LIBOTF */
57 FT_Size ft_size;
58 int index;
59 FT_Matrix matrix;
60 Display *display;
61 int screen;
62 XftFont *xftfont;
63 };
64
65 /* Structure pointed by (struct face *)->extra */
66
67 struct xftface_info
68 {
69 XftColor xft_fg; /* color for face->foreground */
70 XftColor xft_bg; /* color for face->background */
71 };
72
73 static void xftfont_get_colors (FRAME_PTR, struct face *, GC gc,
74 struct xftface_info *,
75 XftColor *fg, XftColor *bg);
76
77
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
82 static void
83 xftfont_get_colors (FRAME_PTR f, struct face *face, GC gc, struct xftface_info *xftface_info, XftColor *fg, XftColor *bg)
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 bool 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))
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
138
139 struct font_driver xftfont_driver;
140
141 static Lisp_Object
142 xftfont_list (Lisp_Object frame, Lisp_Object spec)
143 {
144 Lisp_Object list = ftfont_driver.list (frame, spec), tail;
145
146 for (tail = list; CONSP (tail); tail = XCDR (tail))
147 ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
148 return list;
149 }
150
151 static Lisp_Object
152 xftfont_match (Lisp_Object frame, Lisp_Object spec)
153 {
154 Lisp_Object entity = ftfont_driver.match (frame, spec);
155
156 if (! NILP (entity))
157 ASET (entity, FONT_TYPE_INDEX, Qxft);
158 return entity;
159 }
160
161 static FcChar8 ascii_printable[95];
162
163 static void
164 xftfont_fix_match (FcPattern *pat, FcPattern *match)
165 {
166 /* These values are not used for matching (except antialias), but for
167 rendering, so make sure they are carried over to the match.
168 We also put antialias here because most fonts are antialiased, so
169 the match will have antialias true. */
170
171 FcBool b = FcTrue;
172 int i;
173 double dpi;
174
175 FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b);
176 if (! b)
177 {
178 FcPatternDel (match, FC_ANTIALIAS);
179 FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
180 }
181 FcPatternGetBool (pat, FC_HINTING, 0, &b);
182 if (! b)
183 {
184 FcPatternDel (match, FC_HINTING);
185 FcPatternAddBool (match, FC_HINTING, FcFalse);
186 }
187 #ifndef FC_HINT_STYLE
188 # define FC_HINT_STYLE "hintstyle"
189 #endif
190 if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i))
191 {
192 FcPatternDel (match, FC_HINT_STYLE);
193 FcPatternAddInteger (match, FC_HINT_STYLE, i);
194 }
195 #ifndef FC_LCD_FILTER
196 /* Older fontconfig versions don't have FC_LCD_FILTER. */
197 #define FC_LCD_FILTER "lcdfilter"
198 #endif
199 if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i))
200 {
201 FcPatternDel (match, FC_LCD_FILTER);
202 FcPatternAddInteger (match, FC_LCD_FILTER, i);
203 }
204 if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i))
205 {
206 FcPatternDel (match, FC_RGBA);
207 FcPatternAddInteger (match, FC_RGBA, i);
208 }
209 if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi))
210 {
211 FcPatternDel (match, FC_DPI);
212 FcPatternAddDouble (match, FC_DPI, dpi);
213 }
214 }
215
216 static void
217 xftfont_add_rendering_parameters (FcPattern *pat, Lisp_Object entity)
218 {
219 Lisp_Object tail;
220 int ival;
221
222 for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
223 {
224 Lisp_Object key = XCAR (XCAR (tail));
225 Lisp_Object val = XCDR (XCAR (tail));
226
227 if (EQ (key, QCantialias))
228 FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
229 else if (EQ (key, QChinting))
230 FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
231 else if (EQ (key, QCautohint))
232 FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
233 else if (EQ (key, QChintstyle))
234 {
235 if (INTEGERP (val))
236 FcPatternAddInteger (pat, FC_HINT_STYLE, XINT (val));
237 else if (SYMBOLP (val)
238 && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
239 FcPatternAddInteger (pat, FC_HINT_STYLE, ival);
240 }
241 else if (EQ (key, QCrgba))
242 {
243 if (INTEGERP (val))
244 FcPatternAddInteger (pat, FC_RGBA, XINT (val));
245 else if (SYMBOLP (val)
246 && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
247 FcPatternAddInteger (pat, FC_RGBA, ival);
248 }
249 else if (EQ (key, QClcdfilter))
250 {
251 if (INTEGERP (val))
252 FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XINT (val));
253 else if (SYMBOLP (val)
254 && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
255 FcPatternAddInteger (pat, FC_LCD_FILTER, ival);
256 }
257 #ifdef FC_EMBOLDEN
258 else if (EQ (key, QCembolden))
259 FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
260 #endif
261 }
262 }
263
264 static Lisp_Object
265 xftfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
266 {
267 FcResult result;
268 Display *display = FRAME_X_DISPLAY (f);
269 Lisp_Object val, filename, idx, font_object;
270 FcPattern *pat = NULL, *match;
271 struct xftfont_info *xftfont_info = NULL;
272 struct font *font;
273 double size = 0;
274 XftFont *xftfont = NULL;
275 int spacing;
276 char name[256];
277 int len, i;
278 XGlyphInfo extents;
279 FT_Face ft_face;
280 FcMatrix *matrix;
281
282 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
283 if (! CONSP (val))
284 return Qnil;
285 val = XCDR (val);
286 filename = XCAR (val);
287 idx = XCDR (val);
288 size = XINT (AREF (entity, FONT_SIZE_INDEX));
289 if (size == 0)
290 size = pixel_size;
291 pat = FcPatternCreate ();
292 FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
293 i = FONT_SLANT_NUMERIC (entity) - 100;
294 if (i < 0) i = 0;
295 FcPatternAddInteger (pat, FC_SLANT, i);
296 FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
297 FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
298 val = AREF (entity, FONT_FAMILY_INDEX);
299 if (! NILP (val))
300 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
301 val = AREF (entity, FONT_FOUNDRY_INDEX);
302 if (! NILP (val))
303 FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
304 val = AREF (entity, FONT_SPACING_INDEX);
305 if (! NILP (val))
306 FcPatternAddInteger (pat, FC_SPACING, XINT (val));
307 val = AREF (entity, FONT_DPI_INDEX);
308 if (! NILP (val))
309 {
310 double dbl = XINT (val);
311
312 FcPatternAddDouble (pat, FC_DPI, dbl);
313 }
314 val = AREF (entity, FONT_AVGWIDTH_INDEX);
315 if (INTEGERP (val) && XINT (val) == 0)
316 FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
317 /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
318 over 10x20-ISO8859-1.pcf.gz). */
319 FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
320
321 xftfont_add_rendering_parameters (pat, entity);
322
323 FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
324 FcPatternAddInteger (pat, FC_INDEX, XINT (idx));
325
326
327 block_input ();
328 /* Make sure that the Xrender extension is added before the Xft one.
329 Otherwise, the close-display hook set by Xft is called after the
330 one for Xrender, and the former tries to re-add the latter. This
331 results in inconsistency of internal states and leads to X
332 protocol error when one reconnects to the same X server.
333 (Bug#1696) */
334 {
335 int event_base, error_base;
336 XRenderQueryExtension (display, &event_base, &error_base);
337 }
338
339 /* Substitute in values from X resources and XftDefaultSet. */
340 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
341 match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
342 xftfont_fix_match (pat, match);
343
344 FcPatternDestroy (pat);
345 xftfont = XftFontOpenPattern (display, match);
346 if (!xftfont)
347 {
348 unblock_input ();
349 XftPatternDestroy (match);
350 return Qnil;
351 }
352 ft_face = XftLockFace (xftfont);
353 unblock_input ();
354
355 /* We should not destroy PAT here because it is kept in XFTFONT and
356 destroyed automatically when XFTFONT is closed. */
357 font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
358 ASET (font_object, FONT_TYPE_INDEX, Qxft);
359 len = font_unparse_xlfd (entity, size, name, 256);
360 if (len > 0)
361 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
362 len = font_unparse_fcname (entity, size, name, 256);
363 if (len > 0)
364 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
365 else
366 ASET (font_object, FONT_FULLNAME_INDEX,
367 AREF (font_object, FONT_NAME_INDEX));
368 ASET (font_object, FONT_FILE_INDEX, filename);
369 ASET (font_object, FONT_FORMAT_INDEX,
370 ftfont_font_format (xftfont->pattern, filename));
371 font = XFONT_OBJECT (font_object);
372 font->pixel_size = size;
373 font->driver = &xftfont_driver;
374 font->encoding_charset = font->repertory_charset = -1;
375
376 xftfont_info = (struct xftfont_info *) font;
377 xftfont_info->display = display;
378 xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
379 xftfont_info->xftfont = xftfont;
380 /* This means that there's no need of transformation. */
381 xftfont_info->matrix.xx = 0;
382 if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix)
383 == FcResultMatch)
384 {
385 xftfont_info->matrix.xx = 0x10000L * matrix->xx;
386 xftfont_info->matrix.yy = 0x10000L * matrix->yy;
387 xftfont_info->matrix.xy = 0x10000L * matrix->xy;
388 xftfont_info->matrix.yx = 0x10000L * matrix->yx;
389 }
390 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
391 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
392 else
393 spacing = FC_PROPORTIONAL;
394 if (! ascii_printable[0])
395 {
396 int ch;
397 for (ch = 0; ch < 95; ch++)
398 ascii_printable[ch] = ' ' + ch;
399 }
400 block_input ();
401
402 /* Unfortunately Xft doesn't provide a way to get minimum char
403 width. So, we set min_width to space_width. */
404
405 if (spacing != FC_PROPORTIONAL
406 #ifdef FC_DUAL
407 && spacing != FC_DUAL
408 #endif /* FC_DUAL */
409 )
410 {
411 font->min_width = font->max_width = font->average_width
412 = font->space_width = xftfont->max_advance_width;
413 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
414 }
415 else
416 {
417 XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
418 font->min_width = font->max_width = font->space_width
419 = extents.xOff;
420 if (font->space_width <= 0)
421 /* dirty workaround */
422 font->space_width = pixel_size;
423 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
424 font->average_width = (font->space_width + extents.xOff) / 95;
425 }
426 unblock_input ();
427
428 font->ascent = xftfont->ascent;
429 font->descent = xftfont->descent;
430 if (pixel_size >= 5)
431 {
432 /* The above condition is a dirty workaround because
433 XftTextExtents8 behaves strangely for some fonts
434 (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */
435 if (font->ascent < extents.y)
436 font->ascent = extents.y;
437 if (font->descent < extents.height - extents.y)
438 font->descent = extents.height - extents.y;
439 }
440 font->height = font->ascent + font->descent;
441
442 if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
443 {
444 int upEM = ft_face->units_per_EM;
445
446 font->underline_position = -ft_face->underline_position * size / upEM;
447 font->underline_thickness = ft_face->underline_thickness * size / upEM;
448 if (font->underline_thickness > 2)
449 font->underline_position -= font->underline_thickness / 2;
450 }
451 else
452 {
453 font->underline_position = -1;
454 font->underline_thickness = 0;
455 }
456 #ifdef HAVE_LIBOTF
457 xftfont_info->maybe_otf = (ft_face->face_flags & FT_FACE_FLAG_SFNT) != 0;
458 xftfont_info->otf = NULL;
459 #endif /* HAVE_LIBOTF */
460 xftfont_info->ft_size = ft_face->size;
461
462 font->baseline_offset = 0;
463 font->relative_compose = 0;
464 font->default_ascent = 0;
465 font->vertical_centering = 0;
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
482
483 return font_object;
484 }
485
486 static void
487 xftfont_close (FRAME_PTR f, struct font *font)
488 {
489 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
490
491 #ifdef HAVE_LIBOTF
492 if (xftfont_info->otf)
493 OTF_close (xftfont_info->otf);
494 #endif
495 block_input ();
496 XftUnlockFace (xftfont_info->xftfont);
497 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
498 unblock_input ();
499 }
500
501 static int
502 xftfont_prepare_face (FRAME_PTR f, struct face *face)
503 {
504 struct xftface_info *xftface_info;
505
506 #if 0
507 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
508 if (face != face->ascii_face)
509 {
510 face->extra = face->ascii_face->extra;
511 return 0;
512 }
513 #endif
514
515 xftface_info = malloc (sizeof *xftface_info);
516 if (! xftface_info)
517 return -1;
518 xftfont_get_colors (f, face, face->gc, NULL,
519 &xftface_info->xft_fg, &xftface_info->xft_bg);
520 face->extra = xftface_info;
521 return 0;
522 }
523
524 static void
525 xftfont_done_face (FRAME_PTR f, struct face *face)
526 {
527 struct xftface_info *xftface_info;
528
529 #if 0
530 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
531 if (face != face->ascii_face
532 || ! face->extra)
533 return;
534 #endif
535
536 xftface_info = (struct xftface_info *) face->extra;
537 if (xftface_info)
538 {
539 free (xftface_info);
540 face->extra = NULL;
541 }
542 }
543
544 static int
545 xftfont_has_char (Lisp_Object font, int c)
546 {
547 struct xftfont_info *xftfont_info;
548 struct charset *cs = NULL;
549
550 if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
551 && charset_jisx0208 >= 0)
552 cs = CHARSET_FROM_ID (charset_jisx0208);
553 else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
554 && charset_ksc5601 >= 0)
555 cs = CHARSET_FROM_ID (charset_ksc5601);
556 if (cs)
557 return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
558
559 if (FONT_ENTITY_P (font))
560 return ftfont_driver.has_char (font, c);
561 xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font);
562 return (XftCharExists (xftfont_info->display, xftfont_info->xftfont,
563 (FcChar32) c) == FcTrue);
564 }
565
566 static unsigned
567 xftfont_encode_char (struct font *font, int c)
568 {
569 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
570 unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
571 (FcChar32) c);
572
573 return (code ? code : FONT_INVALID_CODE);
574 }
575
576 static int
577 xftfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
578 {
579 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
580 XGlyphInfo extents;
581
582 block_input ();
583 XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
584 &extents);
585 unblock_input ();
586 if (metrics)
587 {
588 metrics->lbearing = - extents.x;
589 metrics->rbearing = - extents.x + extents.width;
590 metrics->width = extents.xOff;
591 metrics->ascent = extents.y;
592 metrics->descent = extents.height - extents.y;
593 }
594 return extents.xOff;
595 }
596
597 static XftDraw *
598 xftfont_get_xft_draw (FRAME_PTR f)
599 {
600 XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
601
602 if (! xft_draw)
603 {
604 block_input ();
605 xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
606 FRAME_X_WINDOW (f),
607 FRAME_X_VISUAL (f),
608 FRAME_X_COLORMAP (f));
609 unblock_input ();
610 eassert (xft_draw != NULL);
611 font_put_frame_data (f, &xftfont_driver, xft_draw);
612 }
613 return xft_draw;
614 }
615
616 static int
617 xftfont_draw (struct glyph_string *s, int from, int to, int x, int y,
618 bool with_background)
619 {
620 FRAME_PTR f = s->f;
621 struct face *face = s->face;
622 struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font;
623 struct xftface_info *xftface_info = NULL;
624 XftDraw *xft_draw = xftfont_get_xft_draw (f);
625 FT_UInt *code;
626 XftColor fg, bg;
627 int len = to - from;
628 int i;
629
630 if (s->font == face->font)
631 xftface_info = (struct xftface_info *) face->extra;
632 xftfont_get_colors (f, face, s->gc, xftface_info,
633 &fg, with_background ? &bg : NULL);
634 block_input ();
635 if (s->num_clips > 0)
636 XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips);
637 else
638 XftDrawSetClip (xft_draw, NULL);
639
640 if (with_background)
641 XftDrawRect (xft_draw, &bg,
642 x, y - s->font->ascent, s->width, s->font->height);
643 code = alloca (sizeof (FT_UInt) * len);
644 for (i = 0; i < len; i++)
645 code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
646 | XCHAR2B_BYTE2 (s->char2b + from + i));
647
648 if (s->padding_p)
649 for (i = 0; i < len; i++)
650 XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
651 x + i, y, code + i, 1);
652 else
653 XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
654 x, y, code, len);
655 unblock_input ();
656
657 return len;
658 }
659
660 #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
661 static Lisp_Object
662 xftfont_shape (Lisp_Object lgstring)
663 {
664 struct font *font;
665 struct xftfont_info *xftfont_info;
666 FT_Face ft_face;
667 Lisp_Object val;
668
669 CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
670 xftfont_info = (struct xftfont_info *) font;
671 ft_face = XftLockFace (xftfont_info->xftfont);
672 xftfont_info->ft_size = ft_face->size;
673 val = ftfont_driver.shape (lgstring);
674 XftUnlockFace (xftfont_info->xftfont);
675 return val;
676 }
677 #endif
678
679 static int
680 xftfont_end_for_frame (FRAME_PTR f)
681 {
682 XftDraw *xft_draw;
683
684 /* Don't do anything if display is dead */
685 if (FRAME_X_DISPLAY (f) == NULL) return 0;
686
687 xft_draw = font_get_frame_data (f, &xftfont_driver);
688
689 if (xft_draw)
690 {
691 block_input ();
692 XftDrawDestroy (xft_draw);
693 unblock_input ();
694 font_put_frame_data (f, &xftfont_driver, NULL);
695 }
696 return 0;
697 }
698
699 static bool
700 xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
701 Lisp_Object entity)
702 {
703 struct xftfont_info *info = (struct xftfont_info *) XFONT_OBJECT (font_object);
704 FcPattern *oldpat = info->xftfont->pattern;
705 Display *display = FRAME_X_DISPLAY (f);
706 FcPattern *pat = FcPatternCreate ();
707 FcBool b1, b2;
708 bool ok = 0;
709 int i1, i2, r1, r2;
710
711 xftfont_add_rendering_parameters (pat, entity);
712 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
713
714 r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1);
715 r2 = FcPatternGetBool (oldpat, FC_ANTIALIAS, 0, &b2);
716 if (r1 != r2 || b1 != b2) goto out;
717 r1 = FcPatternGetBool (pat, FC_HINTING, 0, &b1);
718 r2 = FcPatternGetBool (oldpat, FC_HINTING, 0, &b2);
719 if (r1 != r2 || b1 != b2) goto out;
720 r1 = FcPatternGetBool (pat, FC_AUTOHINT, 0, &b1);
721 r2 = FcPatternGetBool (oldpat, FC_AUTOHINT, 0, &b2);
722 if (r1 != r2 || b1 != b2) goto out;
723 #ifdef FC_EMBOLDEN
724 r1 = FcPatternGetBool (pat, FC_EMBOLDEN, 0, &b1);
725 r2 = FcPatternGetBool (oldpat, FC_EMBOLDEN, 0, &b2);
726 if (r1 != r2 || b1 != b2) goto out;
727 #endif
728 r1 = FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i1);
729 r2 = FcPatternGetInteger (oldpat, FC_HINT_STYLE, 0, &i2);
730 if (r1 != r2 || i1 != i2) goto out;
731 r1 = FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i1);
732 r2 = FcPatternGetInteger (oldpat, FC_LCD_FILTER, 0, &i2);
733 if (r1 != r2 || i1 != i2) goto out;
734 r1 = FcPatternGetInteger (pat, FC_RGBA, 0, &i1);
735 r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2);
736 if (r1 != r2 || i1 != i2) goto out;
737
738 ok = 1;
739 out:
740 FcPatternDestroy (pat);
741 return ok;
742 }
743
744 void
745 syms_of_xftfont (void)
746 {
747 DEFSYM (Qxft, "xft");
748 DEFSYM (QChinting, ":hinting");
749 DEFSYM (QCautohint, ":autohint");
750 DEFSYM (QChintstyle, ":hintstyle");
751 DEFSYM (QCrgba, ":rgba");
752 DEFSYM (QCembolden, ":embolden");
753 DEFSYM (QClcdfilter, ":lcdfilter");
754
755 ascii_printable[0] = 0;
756
757 xftfont_driver = ftfont_driver;
758 xftfont_driver.type = Qxft;
759 xftfont_driver.get_cache = xfont_driver.get_cache;
760 xftfont_driver.list = xftfont_list;
761 xftfont_driver.match = xftfont_match;
762 xftfont_driver.open = xftfont_open;
763 xftfont_driver.close = xftfont_close;
764 xftfont_driver.prepare_face = xftfont_prepare_face;
765 xftfont_driver.done_face = xftfont_done_face;
766 xftfont_driver.has_char = xftfont_has_char;
767 xftfont_driver.encode_char = xftfont_encode_char;
768 xftfont_driver.text_extents = xftfont_text_extents;
769 xftfont_driver.draw = xftfont_draw;
770 xftfont_driver.end_for_frame = xftfont_end_for_frame;
771 xftfont_driver.cached_font_ok = xftfont_cached_font_ok;
772 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
773 xftfont_driver.shape = xftfont_shape;
774 #endif
775
776 register_font_driver (&xftfont_driver, NULL);
777 }