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