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