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