Fix use of pointers to image library functions
[bpt/emacs.git] / src / xftfont.c
CommitLineData
c2f5bfd6 1/* xftfont.c -- XFT font driver.
5df4f04c
GM
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
3 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
c2f5bfd6
KH
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7This file is part of GNU Emacs.
8
9ec0b715 9GNU Emacs is free software: you can redistribute it and/or modify
c2f5bfd6 10it under the terms of the GNU General Public License as published by
9ec0b715
GM
11the Free Software Foundation, either version 3 of the License, or
12(at your option) any later version.
c2f5bfd6
KH
13
14GNU Emacs is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
9ec0b715 20along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
c2f5bfd6
KH
21
22#include <config.h>
23#include <stdio.h>
d7306fe6 24#include <setjmp.h>
c2f5bfd6
KH
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"
31daa5e1 35#include "composite.h"
c2f5bfd6
KH
36#include "fontset.h"
37#include "font.h"
4613015e 38#include "ftfont.h"
c2f5bfd6
KH
39
40/* Xft font driver. */
41
42static Lisp_Object Qxft;
223e5fc6
JD
43static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden,
44 QClcdfilter;
c2f5bfd6
KH
45
46/* The actual structure for Xft font that can be casted to struct
47 font. */
48
49struct xftfont_info
50{
51 struct font font;
91ce2415 52 /* The following five members must be here in this order to be
0fce2b40 53 compatible with struct ftfont_info (in ftfont.c). */
4613015e
KH
54#ifdef HAVE_LIBOTF
55 int maybe_otf; /* Flag to tell if this may be OTF or not. */
56 OTF *otf;
794eba0f 57#endif /* HAVE_LIBOTF */
0fce2b40 58 FT_Size ft_size;
b0c25608 59 int index;
91ce2415 60 FT_Matrix matrix;
0fce2b40
KH
61 Display *display;
62 int screen;
63 XftFont *xftfont;
c2f5bfd6
KH
64};
65
66/* Structure pointed by (struct face *)->extra */
10aca0f7 67
c2f5bfd6
KH
68struct xftface_info
69{
10aca0f7
KH
70 XftColor xft_fg; /* color for face->foreground */
71 XftColor xft_bg; /* color for face->background */
c2f5bfd6
KH
72};
73
74static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc,
75 struct xftface_info *,
76 XftColor *fg, XftColor *bg));
c2f5bfd6
KH
77
78
10aca0f7
KH
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
c2f5bfd6
KH
83static void
84xftfont_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
c2f5bfd6
KH
144
145static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
10aca0f7 146static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
3528e709 147static Lisp_Object xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
c2f5bfd6
KH
148static void xftfont_close P_ ((FRAME_PTR, struct font *));
149static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
150static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
6570a1c4 151static int xftfont_has_char P_ ((Lisp_Object, int));
c2f5bfd6
KH
152static unsigned xftfont_encode_char P_ ((struct font *, int));
153static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
154 struct font_metrics *));
155static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
a92ee6bf 156static int xftfont_end_for_frame P_ ((FRAME_PTR f));
c2f5bfd6
KH
157
158struct font_driver xftfont_driver;
159
160static Lisp_Object
161xftfont_list (frame, spec)
162 Lisp_Object frame;
163 Lisp_Object spec;
164{
3528e709 165 Lisp_Object list = ftfont_driver.list (frame, spec), tail;
8510724d 166
3528e709
KH
167 for (tail = list; CONSP (tail); tail = XCDR (tail))
168 ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
169 return list;
c2f5bfd6
KH
170}
171
10aca0f7
KH
172static Lisp_Object
173xftfont_match (frame, spec)
174 Lisp_Object frame;
175 Lisp_Object spec;
176{
177 Lisp_Object entity = ftfont_driver.match (frame, spec);
178
3528e709 179 if (! NILP (entity))
10aca0f7
KH
180 ASET (entity, FONT_TYPE_INDEX, Qxft);
181 return entity;
182}
183
1cf6763f 184extern Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object));
0fce2b40 185extern FcCharSet *ftfont_get_fc_charset P_ ((Lisp_Object));
81094fab 186extern Lisp_Object QCantialias;
98d12656 187
c2f5bfd6
KH
188static FcChar8 ascii_printable[95];
189
637fa988
JD
190static void
191xftfont_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 }
21050de1 220#ifndef FC_LCD_FILTER
a6eb20d8 221 /* Older fontconfig versions don't have FC_LCD_FILTER. */
21050de1
JD
222#define FC_LCD_FILTER "lcdfilter"
223#endif
637fa988
JD
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
d0cf45b7
JD
241static void
242xftfont_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
3528e709 291static Lisp_Object
c2f5bfd6
KH
292xftfont_open (f, entity, pixel_size)
293 FRAME_PTR f;
294 Lisp_Object entity;
295 int pixel_size;
296{
81094fab 297 FcResult result;
c2f5bfd6 298 Display *display = FRAME_X_DISPLAY (f);
d0cf45b7 299 Lisp_Object val, filename, index, font_object;
81094fab 300 FcPattern *pat = NULL, *match;
2d93c6bd 301 struct xftfont_info *xftfont_info = NULL;
c2f5bfd6
KH
302 struct font *font;
303 double size = 0;
2d93c6bd 304 XftFont *xftfont = NULL;
c2f5bfd6 305 int spacing;
3528e709 306 char name[256];
d0cf45b7 307 int len, i;
91c5bb27 308 XGlyphInfo extents;
365131ac 309 FT_Face ft_face;
91ce2415 310 FcMatrix *matrix;
c2f5bfd6 311
3528e709 312 val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
686ee703 313 if (! CONSP (val))
3528e709 314 return Qnil;
686ee703
KH
315 val = XCDR (val);
316 filename = XCAR (val);
0fce2b40 317 index = XCDR (val);
c2f5bfd6
KH
318 size = XINT (AREF (entity, FONT_SIZE_INDEX));
319 if (size == 0)
320 size = pixel_size;
321 pat = FcPatternCreate ();
81094fab
KH
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));
c2f5bfd6 327 FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
3cc2aca0
KH
328 val = AREF (entity, FONT_FAMILY_INDEX);
329 if (! NILP (val))
330 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
dc2226d0
KH
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);
0fce2b40
KH
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));
dc2226d0 350
d0cf45b7 351 xftfont_add_rendering_parameters (pat, entity);
dcce3c58 352
0fce2b40
KH
353 FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
354 FcPatternAddInteger (pat, FC_INDEX, XINT (index));
8510724d 355
0fce2b40 356
dcce3c58 357 BLOCK_INPUT;
9cb363db
YM
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 }
637fa988
JD
368
369 /* Substitute in values from X resources and XftDefaultSet. */
370 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
81094fab 371 match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
637fa988 372 xftfont_fix_match (pat, match);
223e5fc6 373
81094fab
KH
374 FcPatternDestroy (pat);
375 xftfont = XftFontOpenPattern (display, match);
99061dfc 376 if (!xftfont)
5c629bf6 377 {
99061dfc 378 UNBLOCK_INPUT;
5c629bf6
CY
379 XftPatternDestroy (match);
380 return Qnil;
381 }
99061dfc
CY
382 ft_face = XftLockFace (xftfont);
383 UNBLOCK_INPUT;
384
c2f5bfd6
KH
385 /* We should not destroy PAT here because it is kept in XFTFONT and
386 destroyed automatically when XFTFONT is closed. */
0fce2b40 387 font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
3528e709 388 ASET (font_object, FONT_TYPE_INDEX, Qxft);
3528e709
KH
389 len = font_unparse_xlfd (entity, size, name, 256);
390 if (len > 0)
2781b4e0 391 ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
3528e709
KH
392 len = font_unparse_fcname (entity, size, name, 256);
393 if (len > 0)
2781b4e0 394 ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
3528e709
KH
395 else
396 ASET (font_object, FONT_FULLNAME_INDEX,
397 AREF (font_object, FONT_NAME_INDEX));
686ee703
KH
398 ASET (font_object, FONT_FILE_INDEX, filename);
399 ASET (font_object, FONT_FORMAT_INDEX,
1cf6763f 400 ftfont_font_format (xftfont->pattern, filename));
3528e709
KH
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;
c2f5bfd6
KH
407 xftfont_info->display = display;
408 xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
409 xftfont_info->xftfont = xftfont;
91ce2415
KH
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 }
c2f5bfd6
KH
420 font->pixel_size = size;
421 font->driver = &xftfont_driver;
686ee703
KH
422 if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
423 spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
424 else
c2f5bfd6 425 spacing = FC_PROPORTIONAL;
91c5bb27
KH
426 if (! ascii_printable[0])
427 {
428 int i;
429 for (i = 0; i < 95; i++)
430 ascii_printable[i] = ' ' + i;
431 }
3528e709 432 BLOCK_INPUT;
3d8416fc 433 if (spacing != FC_PROPORTIONAL && spacing != FC_DUAL)
91c5bb27 434 {
3528e709 435 font->min_width = font->average_width = font->space_width
91c5bb27
KH
436 = xftfont->max_advance_width;
437 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
438 }
c2f5bfd6
KH
439 else
440 {
c2f5bfd6 441 XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
3528e709
KH
442 font->space_width = extents.xOff;
443 if (font->space_width <= 0)
c2f5bfd6 444 /* dirty workaround */
8510724d 445 font->space_width = pixel_size;
c2f5bfd6 446 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
3528e709 447 font->average_width = (font->space_width + extents.xOff) / 95;
c2f5bfd6 448 }
dcce3c58 449 UNBLOCK_INPUT;
c2f5bfd6 450
91c5bb27 451 font->ascent = xftfont->ascent;
91c5bb27 452 font->descent = xftfont->descent;
81094fab
KH
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 }
3528e709 463 font->height = font->ascent + font->descent;
91c5bb27 464
3528e709 465 if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
c2f5bfd6 466 {
3528e709
KH
467 int upEM = ft_face->units_per_EM;
468
469 font->underline_position = -ft_face->underline_position * size / upEM;
bc981e4e 470 font->underline_thickness = ft_face->underline_thickness * size / upEM;
951b8112
KH
471 if (font->underline_thickness > 2)
472 font->underline_position -= font->underline_thickness / 2;
c2f5bfd6
KH
473 }
474 else
475 {
3528e709
KH
476 font->underline_position = -1;
477 font->underline_thickness = 0;
c2f5bfd6 478 }
3528e709
KH
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 */
0fce2b40 483 xftfont_info->ft_size = ft_face->size;
c2f5bfd6 484
3528e709
KH
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;
2d93c6bd 488
3528e709
KH
489 font->baseline_offset = 0;
490 font->relative_compose = 0;
491 font->default_ascent = 0;
492 font->vertical_centering = 0;
0fce2b40
KH
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
3528e709
KH
509
510 return font_object;
c2f5bfd6
KH
511}
512
513static void
514xftfont_close (f, font)
515 FRAME_PTR f;
516 struct font *font;
517{
518 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
519
4613015e
KH
520#ifdef HAVE_LIBOTF
521 if (xftfont_info->otf)
522 OTF_close (xftfont_info->otf);
523#endif
3528e709 524 BLOCK_INPUT;
0fce2b40 525 XftUnlockFace (xftfont_info->xftfont);
c2f5bfd6 526 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
3528e709 527 UNBLOCK_INPUT;
c2f5bfd6
KH
528}
529
c2f5bfd6
KH
530static int
531xftfont_prepare_face (f, face)
532 FRAME_PTR f;
533 struct face *face;
534{
e2d0c925 535 struct xftface_info *xftface_info;
c2f5bfd6 536
a703d27d
KH
537#if 0
538 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
539 if (face != face->ascii_face)
540 {
541 face->extra = face->ascii_face->extra;
542 return 0;
543 }
a703d27d 544#endif
e2d0c925
KH
545
546 xftface_info = malloc (sizeof (struct xftface_info));
c2f5bfd6
KH
547 if (! xftface_info)
548 return -1;
c2f5bfd6
KH
549 xftfont_get_colors (f, face, face->gc, NULL,
550 &xftface_info->xft_fg, &xftface_info->xft_bg);
c2f5bfd6
KH
551 face->extra = xftface_info;
552 return 0;
553}
554
555static void
556xftfont_done_face (f, face)
557 FRAME_PTR f;
558 struct face *face;
559{
e2d0c925 560 struct xftface_info *xftface_info;
8510724d 561
a703d27d
KH
562#if 0
563 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
564 if (face != face->ascii_face
565 || ! face->extra)
566 return;
a703d27d 567#endif
c2f5bfd6 568
e2d0c925 569 xftface_info = (struct xftface_info *) face->extra;
773039e8
JD
570 if (xftface_info)
571 {
773039e8 572 free (xftface_info);
a92ee6bf 573 face->extra = NULL;
773039e8 574 }
c2f5bfd6
KH
575}
576
b840b299
KH
577extern Lisp_Object Qja, Qko;
578
6570a1c4
KH
579static int
580xftfont_has_char (font, c)
581 Lisp_Object font;
582 int c;
583{
584 struct xftfont_info *xftfont_info;
b840b299 585 struct charset *cs = NULL;
6570a1c4 586
b840b299
KH
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
ea12eb81
KH
596 if (FONT_ENTITY_P (font))
597 return ftfont_driver.has_char (font, c);
6570a1c4
KH
598 xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font);
599 return (XftCharExists (xftfont_info->display, xftfont_info->xftfont,
600 (FcChar32) c) == FcTrue);
601}
602
c2f5bfd6
KH
603static unsigned
604xftfont_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);
8510724d 611
b5b2545a 612 return (code ? code : FONT_INVALID_CODE);
c2f5bfd6
KH
613}
614
615static int
616xftfont_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;
4b848612 635 metrics->descent = extents.height - extents.y;
c2f5bfd6
KH
636 }
637 return extents.xOff;
638}
639
a92ee6bf
KH
640static XftDraw *
641xftfont_get_xft_draw (f)
642 FRAME_PTR f;
643{
8510724d 644 XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
a92ee6bf
KH
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
c2f5bfd6
KH
661static int
662xftfont_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;
3528e709 668 struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font;
c78c1659 669 struct xftface_info *xftface_info = NULL;
a92ee6bf 670 XftDraw *xft_draw = xftfont_get_xft_draw (f);
c2f5bfd6
KH
671 FT_UInt *code;
672 XftColor fg, bg;
c2f5bfd6
KH
673 int len = to - from;
674 int i;
675
3528e709 676 if (s->font == face->font)
a92ee6bf 677 xftface_info = (struct xftface_info *) face->extra;
c2f5bfd6 678 xftfont_get_colors (f, face, s->gc, xftface_info,
322f8671 679 &fg, with_background ? &bg : NULL);
c2f5bfd6 680 BLOCK_INPUT;
03d198e8
KH
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
c2f5bfd6 686 if (with_background)
3528e709
KH
687 XftDrawRect (xft_draw, &bg,
688 x, y - face->font->ascent, s->width, face->font->height);
c2f5bfd6
KH
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
785543da
KH
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);
c2f5bfd6
KH
701 UNBLOCK_INPUT;
702
703 return len;
704}
705
31daa5e1
KH
706Lisp_Object
707xftfont_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
a92ee6bf
KH
723static int
724xftfont_end_for_frame (f)
725 FRAME_PTR f;
726{
ece2d4ed
JD
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);
a92ee6bf
KH
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}
c2f5bfd6 743
d0cf45b7
JD
744static int
745xftfont_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
c2f5bfd6
KH
791void
792syms_of_xftfont ()
793{
794 DEFSYM (Qxft, "xft");
81094fab 795 DEFSYM (QChinting, ":hinting");
9743ac48 796 DEFSYM (QCautohint, ":autohint");
81094fab
KH
797 DEFSYM (QChintstyle, ":hintstyle");
798 DEFSYM (QCrgba, ":rgba");
799 DEFSYM (QCembolden, ":embolden");
223e5fc6 800 DEFSYM (QClcdfilter, ":lcdfilter");
c2f5bfd6
KH
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;
10aca0f7 806 xftfont_driver.match = xftfont_match;
c2f5bfd6
KH
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;
6570a1c4 811 xftfont_driver.has_char = xftfont_has_char;
c2f5bfd6
KH
812 xftfont_driver.encode_char = xftfont_encode_char;
813 xftfont_driver.text_extents = xftfont_text_extents;
814 xftfont_driver.draw = xftfont_draw;
a92ee6bf 815 xftfont_driver.end_for_frame = xftfont_end_for_frame;
d0cf45b7 816 xftfont_driver.cached_font_ok = xftfont_cached_font_ok;
31daa5e1
KH
817#if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
818 xftfont_driver.shape = xftfont_shape;
819#endif
c2f5bfd6
KH
820
821 register_font_driver (&xftfont_driver, NULL);
822}
885b7d09
MB
823
824/* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
825 (do not change this comment) */