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