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