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
,
45 /* The actual structure for Xft font that can be casted to struct
51 /* The following five members must be here in this order to be
52 compatible with struct ftfont_info (in ftfont.c). */
54 int maybe_otf
; /* Flag to tell if this may be OTF or not. */
56 #endif /* HAVE_LIBOTF */
65 /* Structure pointed by (struct face *)->extra */
69 XftColor xft_fg
; /* color for face->foreground */
70 XftColor xft_bg
; /* color for face->background */
73 static void xftfont_get_colors
P_ ((FRAME_PTR
, struct face
*, GC gc
,
74 struct xftface_info
*,
75 XftColor
*fg
, XftColor
*bg
));
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
83 xftfont_get_colors (f
, face
, gc
, xftface_info
, fg
, bg
)
87 struct xftface_info
*xftface_info
;
90 if (xftface_info
&& face
->gc
== gc
)
92 *fg
= xftface_info
->xft_fg
;
94 *bg
= xftface_info
->xft_bg
;
99 int fg_done
= 0, bg_done
= 0;
102 XGetGCValues (FRAME_X_DISPLAY (f
), gc
,
103 GCForeground
| GCBackground
, &xgcv
);
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;
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;
118 if (fg_done
+ bg_done
< 2)
122 colors
[0].pixel
= fg
->pixel
= xgcv
.foreground
;
124 colors
[1].pixel
= bg
->pixel
= xgcv
.background
;
125 XQueryColors (FRAME_X_DISPLAY (f
), FRAME_X_COLORMAP (f
), colors
,
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
;
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
;
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
));
157 struct font_driver xftfont_driver
;
160 xftfont_list (frame
, spec
)
164 Lisp_Object list
= ftfont_driver
.list (frame
, spec
), tail
;
166 for (tail
= list
; CONSP (tail
); tail
= XCDR (tail
))
167 ASET (XCAR (tail
), FONT_TYPE_INDEX
, Qxft
);
172 xftfont_match (frame
, spec
)
176 Lisp_Object entity
= ftfont_driver
.match (frame
, spec
);
179 ASET (entity
, FONT_TYPE_INDEX
, Qxft
);
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
;
187 static FcChar8 ascii_printable
[95];
190 xftfont_fix_match (pat
, match
)
191 FcPattern
*pat
, *match
;
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. */
202 FcPatternGetBool (pat
, FC_ANTIALIAS
, 0, &b
);
205 FcPatternDel (match
, FC_ANTIALIAS
);
206 FcPatternAddBool (match
, FC_ANTIALIAS
, FcFalse
);
208 FcPatternGetBool (pat
, FC_HINTING
, 0, &b
);
211 FcPatternDel (match
, FC_HINTING
);
212 FcPatternAddBool (match
, FC_HINTING
, FcFalse
);
214 if (FcResultMatch
== FcPatternGetInteger (pat
, FC_HINT_STYLE
, 0, &i
))
216 FcPatternDel (match
, FC_HINT_STYLE
);
217 FcPatternAddInteger (match
, FC_HINT_STYLE
, i
);
219 #ifndef FC_LCD_FILTER
220 /* Older fontconfig versions don't have FC_LCD_FILTER. */
221 #define FC_LCD_FILTER "lcdfilter"
223 if (FcResultMatch
== FcPatternGetInteger (pat
, FC_LCD_FILTER
, 0, &i
))
225 FcPatternDel (match
, FC_LCD_FILTER
);
226 FcPatternAddInteger (match
, FC_LCD_FILTER
, i
);
228 if (FcResultMatch
== FcPatternGetInteger (pat
, FC_RGBA
, 0, &i
))
230 FcPatternDel (match
, FC_RGBA
);
231 FcPatternAddInteger (match
, FC_RGBA
, i
);
233 if (FcResultMatch
== FcPatternGetDouble (pat
, FC_DPI
, 0, &dpi
))
235 FcPatternDel (match
, FC_DPI
);
236 FcPatternAddDouble (match
, FC_DPI
, dpi
);
241 xftfont_open (f
, entity
, pixel_size
)
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
;
253 XftFont
*xftfont
= NULL
;
261 val
= assq_no_quit (QCfont_entity
, AREF (entity
, FONT_EXTRA_INDEX
));
265 filename
= XCAR (val
);
267 size
= XINT (AREF (entity
, FONT_SIZE_INDEX
));
270 pat
= FcPatternCreate ();
271 FcPatternAddInteger (pat
, FC_WEIGHT
, FONT_WEIGHT_NUMERIC (entity
));
272 i
= FONT_SLANT_NUMERIC (entity
) - 100;
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
);
279 FcPatternAddString (pat
, FC_FAMILY
, (FcChar8
*) SDATA (SYMBOL_NAME (val
)));
280 val
= AREF (entity
, FONT_FOUNDRY_INDEX
);
282 FcPatternAddString (pat
, FC_FOUNDRY
, (FcChar8
*) SDATA (SYMBOL_NAME (val
)));
283 val
= AREF (entity
, FONT_SPACING_INDEX
);
285 FcPatternAddInteger (pat
, FC_SPACING
, XINT (val
));
286 val
= AREF (entity
, FONT_DPI_INDEX
);
289 double dbl
= XINT (val
);
291 FcPatternAddDouble (pat
, FC_DPI
, dbl
);
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
));
300 for (tail
= AREF (entity
, FONT_EXTRA_INDEX
); CONSP (tail
); tail
= XCDR (tail
))
302 Lisp_Object key
, val
;
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
))
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
);
319 else if (EQ (key
, QCrgba
))
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
);
327 else if (EQ (key
, QClcdfilter
))
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
);
336 else if (EQ (key
, QCembolden
))
337 FcPatternAddBool (pat
, FC_EMBOLDEN
, NILP (val
) ? FcFalse
: FcTrue
);
341 FcPatternAddString (pat
, FC_FILE
, (FcChar8
*) SDATA (filename
));
342 FcPatternAddInteger (pat
, FC_INDEX
, XINT (index
));
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.
353 int event_base
, error_base
;
354 XRenderQueryExtension (display
, &event_base
, &error_base
);
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
);
362 FcPatternDestroy (pat
);
363 xftfont
= XftFontOpenPattern (display
, match
);
367 XftPatternDestroy (match
);
370 ft_face
= XftLockFace (xftfont
);
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);
379 ASET (font_object
, FONT_NAME_INDEX
, make_string (name
, len
));
380 len
= font_unparse_fcname (entity
, size
, name
, 256);
382 ASET (font_object
, FONT_FULLNAME_INDEX
, make_string (name
, len
));
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;
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
)
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
;
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
));
413 spacing
= FC_PROPORTIONAL
;
414 if (! ascii_printable
[0])
417 for (i
= 0; i
< 95; i
++)
418 ascii_printable
[i
] = ' ' + i
;
421 if (spacing
!= FC_PROPORTIONAL
)
423 font
->min_width
= font
->average_width
= font
->space_width
424 = xftfont
->max_advance_width
;
425 XftTextExtents8 (display
, xftfont
, ascii_printable
+ 1, 94, &extents
);
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;
439 font
->ascent
= xftfont
->ascent
;
440 font
->descent
= xftfont
->descent
;
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
;
451 font
->height
= font
->ascent
+ font
->descent
;
453 if (XINT (AREF (entity
, FONT_SIZE_INDEX
)) == 0)
455 int upEM
= ft_face
->units_per_EM
;
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;
464 font
->underline_position
= -1;
465 font
->underline_thickness
= 0;
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
;
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
;
477 font
->baseline_offset
= 0;
478 font
->relative_compose
= 0;
479 font
->default_ascent
= 0;
480 font
->vertical_centering
= 0;
482 if (! (ft_face
->face_flags
& FT_FACE_FLAG_SFNT
))
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
;
502 xftfont_close (f
, font
)
506 struct xftfont_info
*xftfont_info
= (struct xftfont_info
*) font
;
509 if (xftfont_info
->otf
)
510 OTF_close (xftfont_info
->otf
);
513 XftUnlockFace (xftfont_info
->xftfont
);
514 XftFontClose (xftfont_info
->display
, xftfont_info
->xftfont
);
519 xftfont_prepare_face (f
, face
)
523 struct xftface_info
*xftface_info
;
526 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
527 if (face
!= face
->ascii_face
)
529 face
->extra
= face
->ascii_face
->extra
;
534 xftface_info
= malloc (sizeof (struct xftface_info
));
537 xftfont_get_colors (f
, face
, face
->gc
, NULL
,
538 &xftface_info
->xft_fg
, &xftface_info
->xft_bg
);
539 face
->extra
= xftface_info
;
544 xftfont_done_face (f
, face
)
548 struct xftface_info
*xftface_info
;
551 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
552 if (face
!= face
->ascii_face
557 xftface_info
= (struct xftface_info
*) face
->extra
;
565 extern Lisp_Object Qja
, Qko
;
568 xftfont_has_char (font
, c
)
572 struct xftfont_info
*xftfont_info
;
573 struct charset
*cs
= NULL
;
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
);
582 return (ENCODE_CHAR (cs
, c
) != CHARSET_INVALID_CODE (cs
));
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
);
592 xftfont_encode_char (font
, c
)
596 struct xftfont_info
*xftfont_info
= (struct xftfont_info
*) font
;
597 unsigned code
= XftCharIndex (xftfont_info
->display
, xftfont_info
->xftfont
,
600 return (code
? code
: FONT_INVALID_CODE
);
604 xftfont_text_extents (font
, code
, nglyphs
, metrics
)
608 struct font_metrics
*metrics
;
610 struct xftfont_info
*xftfont_info
= (struct xftfont_info
*) font
;
614 XftGlyphExtents (xftfont_info
->display
, xftfont_info
->xftfont
, code
, nglyphs
,
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
;
629 xftfont_get_xft_draw (f
)
632 XftDraw
*xft_draw
= font_get_frame_data (f
, &xftfont_driver
);
637 xft_draw
= XftDrawCreate (FRAME_X_DISPLAY (f
),
640 FRAME_X_COLORMAP (f
));
644 font_put_frame_data (f
, &xftfont_driver
, xft_draw
);
650 xftfont_draw (s
, from
, to
, x
, y
, with_background
)
651 struct glyph_string
*s
;
652 int from
, to
, x
, y
, with_background
;
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
);
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
);
669 if (s
->num_clips
> 0)
670 XftDrawSetClipRectangles (xft_draw
, 0, 0, s
->clip
, s
->num_clips
);
672 XftDrawSetClip (xft_draw
, NULL
);
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
));
683 for (i
= 0; i
< len
; i
++)
684 XftDrawGlyphs (xft_draw
, &fg
, xftfont_info
->xftfont
,
685 x
+ i
, y
, code
+ i
, 1);
687 XftDrawGlyphs (xft_draw
, &fg
, xftfont_info
->xftfont
,
695 xftfont_end_for_frame (f
)
700 /* Don't do anything if display is dead */
701 if (FRAME_X_DISPLAY (f
) == NULL
) return 0;
703 xft_draw
= font_get_frame_data (f
, &xftfont_driver
);
708 XftDrawDestroy (xft_draw
);
710 font_put_frame_data (f
, &xftfont_driver
, NULL
);
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");
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
;
741 register_font_driver (&xftfont_driver
, NULL
);
744 /* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
745 (do not change this comment) */