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