Fix maintainer email
[bpt/emacs.git] / src / xftfont.c
CommitLineData
c2f5bfd6
KH
1/* xftfont.c -- XFT font driver.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3 Copyright (C) 2006
4 National Institute of Advanced Industrial Science and Technology (AIST)
5 Registration Number H13PRO009
6
7This file is part of GNU Emacs.
8
9GNU Emacs is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
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
20along with GNU Emacs; see the file COPYING. If not, write to
21the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22Boston, MA 02110-1301, USA. */
23
24#include <config.h>
25#include <stdio.h>
26#include <X11/Xlib.h>
27#include <X11/Xft/Xft.h>
28
29#include "lisp.h"
30#include "dispextern.h"
31#include "xterm.h"
32#include "frame.h"
33#include "blockinput.h"
34#include "character.h"
35#include "charset.h"
36#include "fontset.h"
37#include "font.h"
38
39/* Xft font driver. */
40
41static Lisp_Object Qxft;
42
43/* The actual structure for Xft font that can be casted to struct
44 font. */
45
46struct xftfont_info
47{
48 struct font font;
49 Display *display;
50 int screen;
51 XftFont *xftfont;
10aca0f7 52 FT_Face ft_face; /* set to XftLockFace (xftfont) */
c2f5bfd6
KH
53};
54
55/* Structure pointed by (struct face *)->extra */
10aca0f7 56
c2f5bfd6
KH
57struct xftface_info
58{
10aca0f7
KH
59 XftColor xft_fg; /* color for face->foreground */
60 XftColor xft_bg; /* color for face->background */
c2f5bfd6
KH
61 XftDraw *xft_draw;
62};
63
64static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc,
65 struct xftface_info *,
66 XftColor *fg, XftColor *bg));
67static Font xftfont_default_fid P_ ((FRAME_PTR));
68
69
10aca0f7
KH
70/* Setup foreground and background colors of GC into FG and BG. If
71 XFTFACE_INFO is not NULL, reuse the colors in it if possible. BG
72 may be NULL. */
73
c2f5bfd6
KH
74static void
75xftfont_get_colors (f, face, gc, xftface_info, fg, bg)
76 FRAME_PTR f;
77 struct face *face;
78 GC gc;
79 struct xftface_info *xftface_info;
80 XftColor *fg, *bg;
81{
82 if (xftface_info && face->gc == gc)
83 {
84 *fg = xftface_info->xft_fg;
85 if (bg)
86 *bg = xftface_info->xft_bg;
87 }
88 else
89 {
90 XGCValues xgcv;
91 int fg_done = 0, bg_done = 0;
92
93 BLOCK_INPUT;
94 XGetGCValues (FRAME_X_DISPLAY (f), gc,
95 GCForeground | GCBackground, &xgcv);
96 if (xftface_info)
97 {
98 if (xgcv.foreground == face->foreground)
99 *fg = xftface_info->xft_fg, fg_done = 1;
100 else if (xgcv.foreground == face->background)
101 *fg = xftface_info->xft_bg, fg_done = 1;
102 if (! bg)
103 bg_done = 1;
104 else if (xgcv.background == face->background)
105 *bg = xftface_info->xft_bg, bg_done = 1;
106 else if (xgcv.background == face->foreground)
107 *bg = xftface_info->xft_fg, bg_done = 1;
108 }
109
110 if (fg_done + bg_done < 2)
111 {
112 XColor colors[2];
113
114 colors[0].pixel = fg->pixel = xgcv.foreground;
115 if (bg)
116 colors[1].pixel = bg->pixel = xgcv.background;
117 XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors,
118 bg ? 2 : 1);
119 fg->color.alpha = 0xFFFF;
120 fg->color.red = colors[0].red;
121 fg->color.green = colors[0].green;
122 fg->color.blue = colors[0].blue;
123 if (bg)
124 {
125 bg->color.alpha = 0xFFFF;
126 bg->color.red = colors[1].red;
127 bg->color.green = colors[1].green;
128 bg->color.blue = colors[1].blue;
129 }
130 }
131 UNBLOCK_INPUT;
132 }
133}
134
10aca0f7
KH
135/* Return the default Font ID on frame F. The Returned Font ID is
136 stored in the GC of the frame F, but the font is never used. So,
137 any ID is ok as long as it is valid. */
c2f5bfd6
KH
138
139static Font
140xftfont_default_fid (f)
141 FRAME_PTR f;
142{
143 static int fid_known;
144 static Font fid;
145
146 if (! fid_known)
147 {
148 fid = XLoadFont (FRAME_X_DISPLAY (f), "fixed");
149 if (! fid)
150 {
151 fid = XLoadFont (FRAME_X_DISPLAY (f), "*");
152 if (! fid)
153 abort ();
154 }
322f8671 155 fid_known = 1;
c2f5bfd6
KH
156 }
157 return fid;
158}
159
160
161static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
10aca0f7 162static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
c2f5bfd6
KH
163static struct font *xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
164static void xftfont_close P_ ((FRAME_PTR, struct font *));
165static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
166static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
167static unsigned xftfont_encode_char P_ ((struct font *, int));
168static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
169 struct font_metrics *));
170static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
171
172static int xftfont_anchor_point P_ ((struct font *, unsigned, int,
173 int *, int *));
174
175struct font_driver xftfont_driver;
176
177static Lisp_Object
178xftfont_list (frame, spec)
179 Lisp_Object frame;
180 Lisp_Object spec;
181{
182 Lisp_Object val = ftfont_driver.list (frame, spec);
10aca0f7 183 int i;
c2f5bfd6
KH
184
185 if (! NILP (val))
10aca0f7
KH
186 for (i = 0; i < ASIZE (val); i++)
187 ASET (AREF (val, i), FONT_TYPE_INDEX, Qxft);
c2f5bfd6
KH
188 return val;
189}
190
10aca0f7
KH
191static Lisp_Object
192xftfont_match (frame, spec)
193 Lisp_Object frame;
194 Lisp_Object spec;
195{
196 Lisp_Object entity = ftfont_driver.match (frame, spec);
197
198 if (VECTORP (entity))
199 ASET (entity, FONT_TYPE_INDEX, Qxft);
200 return entity;
201}
202
c2f5bfd6
KH
203static FcChar8 ascii_printable[95];
204
205static struct font *
206xftfont_open (f, entity, pixel_size)
207 FRAME_PTR f;
208 Lisp_Object entity;
209 int pixel_size;
210{
211 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
212 Display *display = FRAME_X_DISPLAY (f);
213 Lisp_Object val;
2d93c6bd
KH
214 FcPattern *pattern, *pat = NULL;
215 FcChar8 *file;
216 struct xftfont_info *xftfont_info = NULL;
217 XFontStruct *xfont = NULL;
c2f5bfd6
KH
218 struct font *font;
219 double size = 0;
2d93c6bd 220 XftFont *xftfont = NULL;
c2f5bfd6 221 int spacing;
2d93c6bd 222 char *name;
dcce3c58 223 int len;
c2f5bfd6
KH
224
225 val = AREF (entity, FONT_EXTRA_INDEX);
226 if (XTYPE (val) != Lisp_Misc
227 || XMISCTYPE (val) != Lisp_Misc_Save_Value)
228 return NULL;
229 pattern = XSAVE_VALUE (val)->pointer;
230 if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
231 return NULL;
232
233 size = XINT (AREF (entity, FONT_SIZE_INDEX));
234 if (size == 0)
235 size = pixel_size;
dcce3c58 236
c2f5bfd6
KH
237 pat = FcPatternCreate ();
238 FcPatternAddString (pat, FC_FILE, file);
239 FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
240 FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);
dcce3c58
KH
241
242 BLOCK_INPUT;
4f4426f9 243 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
c2f5bfd6
KH
244 xftfont = XftFontOpenPattern (display, pat);
245 /* We should not destroy PAT here because it is kept in XFTFONT and
246 destroyed automatically when XFTFONT is closed. */
247 if (! xftfont)
2d93c6bd 248 goto err;
c2f5bfd6
KH
249
250 xftfont_info = malloc (sizeof (struct xftfont_info));
251 if (! xftfont_info)
2d93c6bd 252 goto err;
c2f5bfd6 253 xfont = malloc (sizeof (XFontStruct));
2d93c6bd
KH
254 if (! xfont)
255 goto err;
c2f5bfd6
KH
256 xftfont_info->display = display;
257 xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
258 xftfont_info->xftfont = xftfont;
259 xftfont_info->ft_face = XftLockFace (xftfont);
260
261 font = (struct font *) xftfont_info;
262 font->entity = entity;
263 font->pixel_size = size;
264 font->driver = &xftfont_driver;
560fd3fa 265 len = 96;
2d93c6bd
KH
266 name = malloc (len);
267 while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
268 {
269 char *new = realloc (name, len += 32);
270
271 if (! new)
272 free (name);
273 name = new;
274 }
275 if (! name)
276 goto err;
277 font->font.full_name = font->font.name = name;
c2f5bfd6
KH
278 font->file_name = (char *) file;
279 font->font.size = xftfont->max_advance_width;
8bf90572 280 font->font.charset = font->encoding_charset = font->repertory_charset = -1;
c2f5bfd6
KH
281 font->ascent = xftfont->ascent;
282 font->descent = xftfont->descent;
283 font->font.height = xftfont->ascent + xftfont->descent;
284
285 if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing)
286 != FcResultMatch)
287 spacing = FC_PROPORTIONAL;
288 if (spacing != FC_PROPORTIONAL)
289 font->font.average_width = font->font.space_width
290 = xftfont->max_advance_width;
291 else
292 {
293 XGlyphInfo extents;
294
295 if (! ascii_printable[0])
296 {
297 int i;
298 for (i = 0; i < 95; i++)
299 ascii_printable[i] = ' ' + i;
300 }
301 XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
302 font->font.space_width = extents.xOff;
303 if (font->font.space_width <= 0)
304 /* dirty workaround */
305 font->font.space_width = pixel_size;
306 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
307 font->font.average_width = (font->font.space_width + extents.xOff) / 95;
308 }
dcce3c58 309 UNBLOCK_INPUT;
c2f5bfd6
KH
310
311 /* Unfortunately Xft doesn't provide a way to get minimum char
312 width. So, we use space_width instead. */
313 font->min_width = font->font.space_width;
314
315 font->font.baseline_offset = 0;
316 font->font.relative_compose = 0;
317 font->font.default_ascent = 0;
318 font->font.vertical_centering = 0;
319
320 /* Setup pseudo XFontStruct */
321 xfont->fid = xftfont_default_fid (f);
322 xfont->ascent = xftfont->ascent;
323 xfont->descent = xftfont->descent;
324 xfont->max_bounds.descent = xftfont->descent;
325 xfont->max_bounds.width = xftfont->max_advance_width;
326 xfont->min_bounds.width = font->font.space_width;
327 font->font.font = xfont;
328
329 dpyinfo->n_fonts++;
330
331 /* Set global flag fonts_changed_p to non-zero if the font loaded
332 has a character with a smaller width than any other character
333 before, or if the font loaded has a smaller height than any other
334 font loaded before. If this happens, it will make a glyph matrix
335 reallocation necessary. */
336 if (dpyinfo->n_fonts == 1)
337 {
338 dpyinfo->smallest_font_height = font->font.height;
339 dpyinfo->smallest_char_width = font->min_width;
340 fonts_changed_p = 1;
341 }
342 else
343 {
344 if (dpyinfo->smallest_font_height > font->font.height)
345 dpyinfo->smallest_font_height = font->font.height,
346 fonts_changed_p |= 1;
347 if (dpyinfo->smallest_char_width > font->min_width)
348 dpyinfo->smallest_char_width = font->min_width,
349 fonts_changed_p |= 1;
350 }
351
352 return font;
2d93c6bd
KH
353
354 err:
355 if (xftfont) XftFontClose (display, xftfont);
356 UNBLOCK_INPUT;
357 if (xftfont_info) free (xftfont_info);
358 if (xfont) free (xfont);
359 return NULL;
c2f5bfd6
KH
360}
361
362static void
363xftfont_close (f, font)
364 FRAME_PTR f;
365 struct font *font;
366{
367 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
368
369 XftUnlockFace (xftfont_info->xftfont);
370 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
dcce3c58
KH
371 if (font->font.name)
372 free (font->font.name);
c2f5bfd6
KH
373 free (font);
374 FRAME_X_DISPLAY_INFO (f)->n_fonts--;
375}
376
c2f5bfd6
KH
377static int
378xftfont_prepare_face (f, face)
379 FRAME_PTR f;
380 struct face *face;
381{
e2d0c925 382 struct xftface_info *xftface_info;
c2f5bfd6 383
a703d27d
KH
384#if 0
385 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
386 if (face != face->ascii_face)
387 {
388 face->extra = face->ascii_face->extra;
389 return 0;
390 }
a703d27d 391#endif
e2d0c925
KH
392
393 xftface_info = malloc (sizeof (struct xftface_info));
c2f5bfd6
KH
394 if (! xftface_info)
395 return -1;
396
397 BLOCK_INPUT;
398 xftface_info->xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
399 FRAME_X_WINDOW (f),
400 FRAME_X_VISUAL (f),
401 FRAME_X_COLORMAP (f));
c2f5bfd6
KH
402 xftfont_get_colors (f, face, face->gc, NULL,
403 &xftface_info->xft_fg, &xftface_info->xft_bg);
404 UNBLOCK_INPUT;
405
406 face->extra = xftface_info;
407 return 0;
408}
409
410static void
411xftfont_done_face (f, face)
412 FRAME_PTR f;
413 struct face *face;
414{
e2d0c925
KH
415 struct xftface_info *xftface_info;
416
a703d27d
KH
417#if 0
418 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
419 if (face != face->ascii_face
420 || ! face->extra)
421 return;
a703d27d 422#endif
c2f5bfd6 423
e2d0c925 424 xftface_info = (struct xftface_info *) face->extra;
773039e8
JD
425 if (xftface_info)
426 {
427 BLOCK_INPUT;
428 XftDrawDestroy (xftface_info->xft_draw);
429 UNBLOCK_INPUT;
430 free (xftface_info);
431 }
e2d0c925 432 face->extra = NULL;
c2f5bfd6
KH
433}
434
435static unsigned
436xftfont_encode_char (font, c)
437 struct font *font;
438 int c;
439{
440 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
441 unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
442 (FcChar32) c);
443
444 return (code ? code : 0xFFFFFFFF);
445}
446
447static int
448xftfont_text_extents (font, code, nglyphs, metrics)
449 struct font *font;
450 unsigned *code;
451 int nglyphs;
452 struct font_metrics *metrics;
453{
454 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
455 XGlyphInfo extents;
456
457 BLOCK_INPUT;
458 XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
459 &extents);
460 UNBLOCK_INPUT;
461 if (metrics)
462 {
463 metrics->lbearing = - extents.x;
464 metrics->rbearing = - extents.x + extents.width;
465 metrics->width = extents.xOff;
466 metrics->ascent = extents.y;
4b848612 467 metrics->descent = extents.height - extents.y;
c2f5bfd6
KH
468 }
469 return extents.xOff;
470}
471
472static int
473xftfont_draw (s, from, to, x, y, with_background)
474 struct glyph_string *s;
475 int from, to, x, y, with_background;
476{
477 FRAME_PTR f = s->f;
478 struct face *face = s->face;
479 struct xftfont_info *xftfont_info = (struct xftfont_info *) face->font_info;
480 struct xftface_info *xftface_info = (struct xftface_info *) face->extra;
481 FT_UInt *code;
482 XftColor fg, bg;
483 XRectangle r;
484 int len = to - from;
485 int i;
486
487 xftfont_get_colors (f, face, s->gc, xftface_info,
322f8671 488 &fg, with_background ? &bg : NULL);
c2f5bfd6
KH
489 BLOCK_INPUT;
490 if (s->clip_width)
491 {
492 r.x = s->clip_x, r.width = s->clip_width;
493 r.y = s->clip_y, r.height = s->clip_height;
494 XftDrawSetClipRectangles (xftface_info->xft_draw, 0, 0, &r, 1);
495 }
496 if (with_background)
497 {
498 struct font *font = (struct font *) face->font_info;
499
500 XftDrawRect (xftface_info->xft_draw, &bg,
501 x, y - face->font->ascent, s->width, font->font.height);
502 }
503 code = alloca (sizeof (FT_UInt) * len);
504 for (i = 0; i < len; i++)
505 code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
506 | XCHAR2B_BYTE2 (s->char2b + from + i));
507
508 XftDrawGlyphs (xftface_info->xft_draw, &fg, xftfont_info->xftfont,
509 x, y, code, len);
510 if (s->clip_width)
511 XftDrawSetClip (xftface_info->xft_draw, NULL);
512 UNBLOCK_INPUT;
513
514 return len;
515}
516
517static int
518xftfont_anchor_point (font, code, index, x, y)
519 struct font *font;
520 unsigned code;
521 int index;
522 int *x, *y;
523{
524 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
525 FT_Face ft_face = xftfont_info->ft_face;
526
527 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
528 return -1;
529 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
530 return -1;
531 if (index >= ft_face->glyph->outline.n_points)
532 return -1;
533 *x = ft_face->glyph->outline.points[index].x;
534 *y = ft_face->glyph->outline.points[index].y;
535 return 0;
536}
537
538
539void
540syms_of_xftfont ()
541{
542 DEFSYM (Qxft, "xft");
543
544 xftfont_driver = ftfont_driver;
545 xftfont_driver.type = Qxft;
546 xftfont_driver.get_cache = xfont_driver.get_cache;
547 xftfont_driver.list = xftfont_list;
10aca0f7 548 xftfont_driver.match = xftfont_match;
c2f5bfd6
KH
549 xftfont_driver.open = xftfont_open;
550 xftfont_driver.close = xftfont_close;
551 xftfont_driver.prepare_face = xftfont_prepare_face;
552 xftfont_driver.done_face = xftfont_done_face;
553 xftfont_driver.encode_char = xftfont_encode_char;
554 xftfont_driver.text_extents = xftfont_text_extents;
555 xftfont_driver.draw = xftfont_draw;
556 xftfont_driver.anchor_point = xftfont_anchor_point;
557
558 register_font_driver (&xftfont_driver, NULL);
559}
885b7d09
MB
560
561/* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
562 (do not change this comment) */