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
7 This file is part of GNU Emacs.
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.
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.
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/>. */
26 #include <X11/Xft/Xft.h>
29 #include "dispextern.h"
32 #include "blockinput.h"
33 #include "character.h"
39 /* Xft font driver. */
41 static Lisp_Object Qxft
;
42 static Lisp_Object QChinting
, QCautohint
, QChintstyle
, QCrgba
, QCembolden
;
44 /* The actual structure for Xft font that can be casted to struct
50 /* The following four members must be here in this order to be
51 compatible with struct ftfont_info (in ftfont.c). */
53 int maybe_otf
; /* Flag to tell if this may be OTF or not. */
55 #endif /* HAVE_LIBOTF */
63 /* Structure pointed by (struct face *)->extra */
67 XftColor xft_fg
; /* color for face->foreground */
68 XftColor xft_bg
; /* color for face->background */
71 static void xftfont_get_colors
P_ ((FRAME_PTR
, struct face
*, GC gc
,
72 struct xftface_info
*,
73 XftColor
*fg
, XftColor
*bg
));
76 /* Setup foreground and background colors of GC into FG and BG. If
77 XFTFACE_INFO is not NULL, reuse the colors in it if possible. BG
81 xftfont_get_colors (f
, face
, gc
, xftface_info
, fg
, bg
)
85 struct xftface_info
*xftface_info
;
88 if (xftface_info
&& face
->gc
== gc
)
90 *fg
= xftface_info
->xft_fg
;
92 *bg
= xftface_info
->xft_bg
;
97 int fg_done
= 0, bg_done
= 0;
100 XGetGCValues (FRAME_X_DISPLAY (f
), gc
,
101 GCForeground
| GCBackground
, &xgcv
);
104 if (xgcv
.foreground
== face
->foreground
)
105 *fg
= xftface_info
->xft_fg
, fg_done
= 1;
106 else if (xgcv
.foreground
== face
->background
)
107 *fg
= xftface_info
->xft_bg
, fg_done
= 1;
110 else if (xgcv
.background
== face
->background
)
111 *bg
= xftface_info
->xft_bg
, bg_done
= 1;
112 else if (xgcv
.background
== face
->foreground
)
113 *bg
= xftface_info
->xft_fg
, bg_done
= 1;
116 if (fg_done
+ bg_done
< 2)
120 colors
[0].pixel
= fg
->pixel
= xgcv
.foreground
;
122 colors
[1].pixel
= bg
->pixel
= xgcv
.background
;
123 XQueryColors (FRAME_X_DISPLAY (f
), FRAME_X_COLORMAP (f
), colors
,
125 fg
->color
.alpha
= 0xFFFF;
126 fg
->color
.red
= colors
[0].red
;
127 fg
->color
.green
= colors
[0].green
;
128 fg
->color
.blue
= colors
[0].blue
;
131 bg
->color
.alpha
= 0xFFFF;
132 bg
->color
.red
= colors
[1].red
;
133 bg
->color
.green
= colors
[1].green
;
134 bg
->color
.blue
= colors
[1].blue
;
142 static Lisp_Object xftfont_list
P_ ((Lisp_Object
, Lisp_Object
));
143 static Lisp_Object xftfont_match
P_ ((Lisp_Object
, Lisp_Object
));
144 static Lisp_Object xftfont_open
P_ ((FRAME_PTR
, Lisp_Object
, int));
145 static void xftfont_close
P_ ((FRAME_PTR
, struct font
*));
146 static int xftfont_prepare_face
P_ ((FRAME_PTR
, struct face
*));
147 static void xftfont_done_face
P_ ((FRAME_PTR
, struct face
*));
148 static int xftfont_has_char
P_ ((Lisp_Object
, int));
149 static unsigned xftfont_encode_char
P_ ((struct font
*, int));
150 static int xftfont_text_extents
P_ ((struct font
*, unsigned *, int,
151 struct font_metrics
*));
152 static int xftfont_draw
P_ ((struct glyph_string
*, int, int, int, int, int));
153 static int xftfont_end_for_frame
P_ ((FRAME_PTR f
));
155 struct font_driver xftfont_driver
;
158 xftfont_list (frame
, spec
)
162 Lisp_Object list
= ftfont_driver
.list (frame
, spec
), tail
;
164 for (tail
= list
; CONSP (tail
); tail
= XCDR (tail
))
165 ASET (XCAR (tail
), FONT_TYPE_INDEX
, Qxft
);
170 xftfont_match (frame
, spec
)
174 Lisp_Object entity
= ftfont_driver
.match (frame
, spec
);
177 ASET (entity
, FONT_TYPE_INDEX
, Qxft
);
181 extern Lisp_Object ftfont_font_format
P_ ((FcPattern
*, Lisp_Object
));
182 extern FcCharSet
*ftfont_get_fc_charset
P_ ((Lisp_Object
));
183 extern Lisp_Object QCantialias
;
185 static FcChar8 ascii_printable
[95];
188 xftfont_fix_match (pat
, match
)
189 FcPattern
*pat
, *match
;
191 /* These values are not used for matching (except antialias), but for
192 rendering, so make sure they are carried over to the match.
193 We also put antialias here because most fonts are antialiased, so
194 the match will have antialias true. */
200 FcPatternGetBool (pat
, FC_ANTIALIAS
, 0, &b
);
203 FcPatternDel (match
, FC_ANTIALIAS
);
204 FcPatternAddBool (match
, FC_ANTIALIAS
, FcFalse
);
206 FcPatternGetBool (pat
, FC_HINTING
, 0, &b
);
209 FcPatternDel (match
, FC_HINTING
);
210 FcPatternAddBool (match
, FC_HINTING
, FcFalse
);
212 if (FcResultMatch
== FcPatternGetInteger (pat
, FC_HINT_STYLE
, 0, &i
))
214 FcPatternDel (match
, FC_HINT_STYLE
);
215 FcPatternAddInteger (match
, FC_HINT_STYLE
, i
);
217 if (FcResultMatch
== FcPatternGetInteger (pat
, FC_LCD_FILTER
, 0, &i
))
219 FcPatternDel (match
, FC_LCD_FILTER
);
220 FcPatternAddInteger (match
, FC_LCD_FILTER
, i
);
222 if (FcResultMatch
== FcPatternGetInteger (pat
, FC_RGBA
, 0, &i
))
224 FcPatternDel (match
, FC_RGBA
);
225 FcPatternAddInteger (match
, FC_RGBA
, i
);
227 if (FcResultMatch
== FcPatternGetDouble (pat
, FC_DPI
, 0, &dpi
))
229 FcPatternDel (match
, FC_DPI
);
230 FcPatternAddDouble (match
, FC_DPI
, dpi
);
235 xftfont_open (f
, entity
, pixel_size
)
241 Display
*display
= FRAME_X_DISPLAY (f
);
242 Lisp_Object val
, filename
, index
, tail
, font_object
;
243 FcPattern
*pat
= NULL
, *match
;
244 struct xftfont_info
*xftfont_info
= NULL
;
247 XftFont
*xftfont
= NULL
;
254 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
258 filename
= XCAR (val
);
260 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
263 pat
= FcPatternCreate ();
264 FcPatternAddInteger (pat
, FC_WEIGHT
, FONT_WEIGHT_NUMERIC (entity
));
265 i
= FONT_SLANT_NUMERIC (entity
) - 100;
267 FcPatternAddInteger (pat
, FC_SLANT
, i
);
268 FcPatternAddInteger (pat
, FC_WIDTH
, FONT_WIDTH_NUMERIC (entity
));
269 FcPatternAddDouble (pat
, FC_PIXEL_SIZE
, pixel_size
);
270 val
= AREF (entity
, FONT_FAMILY_INDEX
);
272 FcPatternAddString (pat
, FC_FAMILY
, (FcChar8
*) SDATA (SYMBOL_NAME (val
)));
273 val
= AREF (entity
, FONT_FOUNDRY_INDEX
);
275 FcPatternAddString (pat
, FC_FOUNDRY
, (FcChar8
*) SDATA (SYMBOL_NAME (val
)));
276 val
= AREF (entity
, FONT_SPACING_INDEX
);
278 FcPatternAddInteger (pat
, FC_SPACING
, XINT (val
));
279 val
= AREF (entity
, FONT_DPI_INDEX
);
282 double dbl
= XINT (val
);
284 FcPatternAddDouble (pat
, FC_DPI
, dbl
);
286 val
= AREF (entity
, FONT_AVGWIDTH_INDEX
);
287 if (INTEGERP (val
) && XINT (val
) == 0)
288 FcPatternAddBool (pat
, FC_SCALABLE
, FcTrue
);
289 /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
290 over 10x20-ISO8859-1.pcf.gz). */
291 FcPatternAddCharSet (pat
, FC_CHARSET
, ftfont_get_fc_charset (entity
));
293 for (tail
= AREF (entity
, FONT_EXTRA_INDEX
); CONSP (tail
); tail
= XCDR (tail
))
295 Lisp_Object key
, val
;
297 key
= XCAR (XCAR (tail
)), val
= XCDR (XCAR (tail
));
298 if (EQ (key
, QCantialias
))
299 FcPatternAddBool (pat
, FC_ANTIALIAS
, NILP (val
) ? FcFalse
: FcTrue
);
300 else if (EQ (key
, QChinting
))
301 FcPatternAddBool (pat
, FC_HINTING
, NILP (val
) ? FcFalse
: FcTrue
);
302 else if (EQ (key
, QCautohint
))
303 FcPatternAddBool (pat
, FC_AUTOHINT
, NILP (val
) ? FcFalse
: FcTrue
);
304 else if (EQ (key
, QChintstyle
))
307 FcPatternAddInteger (pat
, FC_HINT_STYLE
, XINT (val
));
309 else if (EQ (key
, QCrgba
))
312 FcPatternAddInteger (pat
, FC_RGBA
, XINT (val
));
315 else if (EQ (key
, QCembolden
))
316 FcPatternAddBool (pat
, FC_EMBOLDEN
, NILP (val
) ? FcFalse
: FcTrue
);
320 FcPatternAddString (pat
, FC_FILE
, (FcChar8
*) SDATA (filename
));
321 FcPatternAddInteger (pat
, FC_INDEX
, XINT (index
));
325 /* Make sure that the Xrender extension is added before the Xft one.
326 Otherwise, the close-display hook set by Xft is called after the
327 one for Xrender, and the former tries to re-add the latter. This
328 results in inconsistency of internal states and leads to X
329 protocol error when one reconnects to the same X server.
332 int event_base
, error_base
;
333 XRenderQueryExtension (display
, &event_base
, &error_base
);
336 /* Substitute in values from X resources and XftDefaultSet. */
337 XftDefaultSubstitute (display
, FRAME_X_SCREEN_NUMBER (f
), pat
);
338 match
= XftFontMatch (display
, FRAME_X_SCREEN_NUMBER (f
), pat
, &result
);
339 xftfont_fix_match (pat
, match
);
341 FcPatternDestroy (pat
);
342 xftfont
= XftFontOpenPattern (display
, match
);
346 XftPatternDestroy (match
);
349 ft_face
= XftLockFace (xftfont
);
352 /* We should not destroy PAT here because it is kept in XFTFONT and
353 destroyed automatically when XFTFONT is closed. */
354 font_object
= font_make_object (VECSIZE (struct xftfont_info
), entity
, size
);
355 ASET (font_object
, FONT_TYPE_INDEX
, Qxft
);
356 len
= font_unparse_xlfd (entity
, size
, name
, 256);
358 ASET (font_object
, FONT_NAME_INDEX
, make_string (name
, len
));
359 len
= font_unparse_fcname (entity
, size
, name
, 256);
361 ASET (font_object
, FONT_FULLNAME_INDEX
, make_string (name
, len
));
363 ASET (font_object
, FONT_FULLNAME_INDEX
,
364 AREF (font_object
, FONT_NAME_INDEX
));
365 ASET (font_object
, FONT_FILE_INDEX
, filename
);
366 ASET (font_object
, FONT_FORMAT_INDEX
,
367 ftfont_font_format (xftfont
->pattern
, filename
));
368 font
= XFONT_OBJECT (font_object
);
369 font
->pixel_size
= pixel_size
;
370 font
->driver
= &xftfont_driver
;
371 font
->encoding_charset
= font
->repertory_charset
= -1;
373 xftfont_info
= (struct xftfont_info
*) font
;
374 xftfont_info
->display
= display
;
375 xftfont_info
->screen
= FRAME_X_SCREEN_NUMBER (f
);
376 xftfont_info
->xftfont
= xftfont
;
377 font
->pixel_size
= size
;
378 font
->driver
= &xftfont_driver
;
379 if (INTEGERP (AREF (entity
, FONT_SPACING_INDEX
)))
380 spacing
= XINT (AREF (entity
, FONT_SPACING_INDEX
));
382 spacing
= FC_PROPORTIONAL
;
383 if (! ascii_printable
[0])
386 for (i
= 0; i
< 95; i
++)
387 ascii_printable
[i
] = ' ' + i
;
390 if (spacing
!= FC_PROPORTIONAL
)
392 font
->min_width
= font
->average_width
= font
->space_width
393 = xftfont
->max_advance_width
;
394 XftTextExtents8 (display
, xftfont
, ascii_printable
+ 1, 94, &extents
);
398 XftTextExtents8 (display
, xftfont
, ascii_printable
, 1, &extents
);
399 font
->space_width
= extents
.xOff
;
400 if (font
->space_width
<= 0)
401 /* dirty workaround */
402 font
->space_width
= pixel_size
;
403 XftTextExtents8 (display
, xftfont
, ascii_printable
+ 1, 94, &extents
);
404 font
->average_width
= (font
->space_width
+ extents
.xOff
) / 95;
408 font
->ascent
= xftfont
->ascent
;
409 font
->descent
= xftfont
->descent
;
412 /* The above condition is a dirty workaround because
413 XftTextExtents8 behaves strangely for some fonts
414 (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */
415 if (font
->ascent
< extents
.y
)
416 font
->ascent
= extents
.y
;
417 if (font
->descent
< extents
.height
- extents
.y
)
418 font
->descent
= extents
.height
- extents
.y
;
420 font
->height
= font
->ascent
+ font
->descent
;
422 if (XINT (AREF (entity
, FONT_SIZE_INDEX
)) == 0)
424 int upEM
= ft_face
->units_per_EM
;
426 font
->underline_position
= -ft_face
->underline_position
* size
/ upEM
;
427 font
->underline_thickness
= ft_face
->underline_thickness
* size
/ upEM
;
428 if (font
->underline_thickness
> 2)
429 font
->underline_position
-= font
->underline_thickness
/ 2;
433 font
->underline_position
= -1;
434 font
->underline_thickness
= 0;
437 xftfont_info
->maybe_otf
= ft_face
->face_flags
& FT_FACE_FLAG_SFNT
;
438 xftfont_info
->otf
= NULL
;
439 #endif /* HAVE_LIBOTF */
440 xftfont_info
->ft_size
= ft_face
->size
;
442 /* Unfortunately Xft doesn't provide a way to get minimum char
443 width. So, we use space_width instead. */
444 font
->min_width
= font
->space_width
;
446 font
->baseline_offset
= 0;
447 font
->relative_compose
= 0;
448 font
->default_ascent
= 0;
449 font
->vertical_centering
= 0;
451 if (! (ft_face
->face_flags
& FT_FACE_FLAG_SFNT
))
455 if (FT_Get_BDF_Property (ft_face
, "_MULE_BASELINE_OFFSET", &rec
) == 0
456 && rec
.type
== BDF_PROPERTY_TYPE_INTEGER
)
457 font
->baseline_offset
= rec
.u
.integer
;
458 if (FT_Get_BDF_Property (ft_face
, "_MULE_RELATIVE_COMPOSE", &rec
) == 0
459 && rec
.type
== BDF_PROPERTY_TYPE_INTEGER
)
460 font
->relative_compose
= rec
.u
.integer
;
461 if (FT_Get_BDF_Property (ft_face
, "_MULE_DEFAULT_ASCENT", &rec
) == 0
462 && rec
.type
== BDF_PROPERTY_TYPE_INTEGER
)
463 font
->default_ascent
= rec
.u
.integer
;
471 xftfont_close (f
, font
)
475 struct xftfont_info
*xftfont_info
= (struct xftfont_info
*) font
;
478 if (xftfont_info
->otf
)
479 OTF_close (xftfont_info
->otf
);
482 XftUnlockFace (xftfont_info
->xftfont
);
483 XftFontClose (xftfont_info
->display
, xftfont_info
->xftfont
);
488 xftfont_prepare_face (f
, face
)
492 struct xftface_info
*xftface_info
;
495 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
496 if (face
!= face
->ascii_face
)
498 face
->extra
= face
->ascii_face
->extra
;
503 xftface_info
= malloc (sizeof (struct xftface_info
));
506 xftfont_get_colors (f
, face
, face
->gc
, NULL
,
507 &xftface_info
->xft_fg
, &xftface_info
->xft_bg
);
508 face
->extra
= xftface_info
;
513 xftfont_done_face (f
, face
)
517 struct xftface_info
*xftface_info
;
520 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
521 if (face
!= face
->ascii_face
526 xftface_info
= (struct xftface_info
*) face
->extra
;
534 extern Lisp_Object Qja
, Qko
;
537 xftfont_has_char (font
, c
)
541 struct xftfont_info
*xftfont_info
;
542 struct charset
*cs
= NULL
;
544 if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qja
)
545 && charset_jisx0208
>= 0)
546 cs
= CHARSET_FROM_ID (charset_jisx0208
);
547 else if (EQ (AREF (font
, FONT_ADSTYLE_INDEX
), Qko
)
548 && charset_ksc5601
>= 0)
549 cs
= CHARSET_FROM_ID (charset_ksc5601
);
551 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
553 if (FONT_ENTITY_P (font
))
554 return ftfont_driver
.has_char (font
, c
);
555 xftfont_info
= (struct xftfont_info
*) XFONT_OBJECT (font
);
556 return (XftCharExists (xftfont_info
->display
, xftfont_info
->xftfont
,
557 (FcChar32
) c
) == FcTrue
);
561 xftfont_encode_char (font
, c
)
565 struct xftfont_info
*xftfont_info
= (struct xftfont_info
*) font
;
566 unsigned code
= XftCharIndex (xftfont_info
->display
, xftfont_info
->xftfont
,
569 return (code
? code
: FONT_INVALID_CODE
);
573 xftfont_text_extents (font
, code
, nglyphs
, metrics
)
577 struct font_metrics
*metrics
;
579 struct xftfont_info
*xftfont_info
= (struct xftfont_info
*) font
;
583 XftGlyphExtents (xftfont_info
->display
, xftfont_info
->xftfont
, code
, nglyphs
,
588 metrics
->lbearing
= - extents
.x
;
589 metrics
->rbearing
= - extents
.x
+ extents
.width
;
590 metrics
->width
= extents
.xOff
;
591 metrics
->ascent
= extents
.y
;
592 metrics
->descent
= extents
.height
- extents
.y
;
598 xftfont_get_xft_draw (f
)
601 XftDraw
*xft_draw
= font_get_frame_data (f
, &xftfont_driver
);
606 xft_draw
= XftDrawCreate (FRAME_X_DISPLAY (f
),
609 FRAME_X_COLORMAP (f
));
613 font_put_frame_data (f
, &xftfont_driver
, xft_draw
);
619 xftfont_draw (s
, from
, to
, x
, y
, with_background
)
620 struct glyph_string
*s
;
621 int from
, to
, x
, y
, with_background
;
624 struct face
*face
= s
->face
;
625 struct xftfont_info
*xftfont_info
= (struct xftfont_info
*) s
->font
;
626 struct xftface_info
*xftface_info
= NULL
;
627 XftDraw
*xft_draw
= xftfont_get_xft_draw (f
);
633 if (s
->font
== face
->font
)
634 xftface_info
= (struct xftface_info
*) face
->extra
;
635 xftfont_get_colors (f
, face
, s
->gc
, xftface_info
,
636 &fg
, with_background
? &bg
: NULL
);
638 if (s
->num_clips
> 0)
639 XftDrawSetClipRectangles (xft_draw
, 0, 0, s
->clip
, s
->num_clips
);
641 XftDrawSetClip (xft_draw
, NULL
);
644 XftDrawRect (xft_draw
, &bg
,
645 x
, y
- face
->font
->ascent
, s
->width
, face
->font
->height
);
646 code
= alloca (sizeof (FT_UInt
) * len
);
647 for (i
= 0; i
< len
; i
++)
648 code
[i
] = ((XCHAR2B_BYTE1 (s
->char2b
+ from
+ i
) << 8)
649 | XCHAR2B_BYTE2 (s
->char2b
+ from
+ i
));
652 for (i
= 0; i
< len
; i
++)
653 XftDrawGlyphs (xft_draw
, &fg
, xftfont_info
->xftfont
,
654 x
+ i
, y
, code
+ i
, 1);
656 XftDrawGlyphs (xft_draw
, &fg
, xftfont_info
->xftfont
,
664 xftfont_end_for_frame (f
)
667 XftDraw
*xft_draw
= font_get_frame_data (f
, &xftfont_driver
);
672 XftDrawDestroy (xft_draw
);
674 font_put_frame_data (f
, &xftfont_driver
, NULL
);
682 DEFSYM (Qxft
, "xft");
683 DEFSYM (QChinting
, ":hinting");
684 DEFSYM (QCautohint
, ":autohint");
685 DEFSYM (QChintstyle
, ":hintstyle");
686 DEFSYM (QCrgba
, ":rgba");
687 DEFSYM (QCembolden
, ":embolden");
689 xftfont_driver
= ftfont_driver
;
690 xftfont_driver
.type
= Qxft
;
691 xftfont_driver
.get_cache
= xfont_driver
.get_cache
;
692 xftfont_driver
.list
= xftfont_list
;
693 xftfont_driver
.match
= xftfont_match
;
694 xftfont_driver
.open
= xftfont_open
;
695 xftfont_driver
.close
= xftfont_close
;
696 xftfont_driver
.prepare_face
= xftfont_prepare_face
;
697 xftfont_driver
.done_face
= xftfont_done_face
;
698 xftfont_driver
.has_char
= xftfont_has_char
;
699 xftfont_driver
.encode_char
= xftfont_encode_char
;
700 xftfont_driver
.text_extents
= xftfont_text_extents
;
701 xftfont_driver
.draw
= xftfont_draw
;
702 xftfont_driver
.end_for_frame
= xftfont_end_for_frame
;
704 register_font_driver (&xftfont_driver
, NULL
);
707 /* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
708 (do not change this comment) */