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