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