(describe-char): Fix for the case that a component character is TAB.
[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
98d12656
KH
203extern Lisp_Object ftfont_font_format P_ ((FcPattern *));
204
c2f5bfd6
KH
205static FcChar8 ascii_printable[95];
206
207static struct font *
208xftfont_open (f, entity, pixel_size)
209 FRAME_PTR f;
210 Lisp_Object entity;
211 int pixel_size;
212{
213 Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
214 Display *display = FRAME_X_DISPLAY (f);
215 Lisp_Object val;
2d93c6bd
KH
216 FcPattern *pattern, *pat = NULL;
217 FcChar8 *file;
218 struct xftfont_info *xftfont_info = NULL;
219 XFontStruct *xfont = NULL;
c2f5bfd6
KH
220 struct font *font;
221 double size = 0;
2d93c6bd 222 XftFont *xftfont = NULL;
c2f5bfd6 223 int spacing;
2d93c6bd 224 char *name;
dcce3c58 225 int len;
c2f5bfd6
KH
226
227 val = AREF (entity, FONT_EXTRA_INDEX);
228 if (XTYPE (val) != Lisp_Misc
229 || XMISCTYPE (val) != Lisp_Misc_Save_Value)
230 return NULL;
231 pattern = XSAVE_VALUE (val)->pointer;
232 if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
233 return NULL;
234
235 size = XINT (AREF (entity, FONT_SIZE_INDEX));
236 if (size == 0)
237 size = pixel_size;
dcce3c58 238
c2f5bfd6
KH
239 pat = FcPatternCreate ();
240 FcPatternAddString (pat, FC_FILE, file);
241 FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
fa762662 242 /*FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);*/
3cc2aca0
KH
243 val = AREF (entity, FONT_FAMILY_INDEX);
244 if (! NILP (val))
245 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
246 FcConfigSubstitute (NULL, pat, FcMatchPattern);
dcce3c58
KH
247
248 BLOCK_INPUT;
4f4426f9 249 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
c2f5bfd6
KH
250 xftfont = XftFontOpenPattern (display, pat);
251 /* We should not destroy PAT here because it is kept in XFTFONT and
252 destroyed automatically when XFTFONT is closed. */
253 if (! xftfont)
2d93c6bd 254 goto err;
c2f5bfd6
KH
255
256 xftfont_info = malloc (sizeof (struct xftfont_info));
257 if (! xftfont_info)
2d93c6bd 258 goto err;
c2f5bfd6 259 xfont = malloc (sizeof (XFontStruct));
2d93c6bd
KH
260 if (! xfont)
261 goto err;
c2f5bfd6
KH
262 xftfont_info->display = display;
263 xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
264 xftfont_info->xftfont = xftfont;
265 xftfont_info->ft_face = XftLockFace (xftfont);
266
267 font = (struct font *) xftfont_info;
b2e0f618 268 font->format = ftfont_font_format (xftfont->pattern);
c2f5bfd6
KH
269 font->entity = entity;
270 font->pixel_size = size;
271 font->driver = &xftfont_driver;
560fd3fa 272 len = 96;
2d93c6bd
KH
273 name = malloc (len);
274 while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
275 {
276 char *new = realloc (name, len += 32);
277
278 if (! new)
279 free (name);
280 name = new;
281 }
282 if (! name)
283 goto err;
284 font->font.full_name = font->font.name = name;
c2f5bfd6
KH
285 font->file_name = (char *) file;
286 font->font.size = xftfont->max_advance_width;
8bf90572 287 font->font.charset = font->encoding_charset = font->repertory_charset = -1;
c2f5bfd6
KH
288 font->ascent = xftfont->ascent;
289 font->descent = xftfont->descent;
290 font->font.height = xftfont->ascent + xftfont->descent;
291
292 if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing)
293 != FcResultMatch)
294 spacing = FC_PROPORTIONAL;
295 if (spacing != FC_PROPORTIONAL)
296 font->font.average_width = font->font.space_width
297 = xftfont->max_advance_width;
298 else
299 {
300 XGlyphInfo extents;
301
302 if (! ascii_printable[0])
303 {
304 int i;
305 for (i = 0; i < 95; i++)
306 ascii_printable[i] = ' ' + i;
307 }
308 XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
309 font->font.space_width = extents.xOff;
310 if (font->font.space_width <= 0)
311 /* dirty workaround */
312 font->font.space_width = pixel_size;
313 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
314 font->font.average_width = (font->font.space_width + extents.xOff) / 95;
315 }
dcce3c58 316 UNBLOCK_INPUT;
c2f5bfd6
KH
317
318 /* Unfortunately Xft doesn't provide a way to get minimum char
319 width. So, we use space_width instead. */
320 font->min_width = font->font.space_width;
321
322 font->font.baseline_offset = 0;
323 font->font.relative_compose = 0;
324 font->font.default_ascent = 0;
325 font->font.vertical_centering = 0;
326
327 /* Setup pseudo XFontStruct */
328 xfont->fid = xftfont_default_fid (f);
329 xfont->ascent = xftfont->ascent;
330 xfont->descent = xftfont->descent;
331 xfont->max_bounds.descent = xftfont->descent;
332 xfont->max_bounds.width = xftfont->max_advance_width;
333 xfont->min_bounds.width = font->font.space_width;
334 font->font.font = xfont;
335
336 dpyinfo->n_fonts++;
337
338 /* Set global flag fonts_changed_p to non-zero if the font loaded
339 has a character with a smaller width than any other character
340 before, or if the font loaded has a smaller height than any other
341 font loaded before. If this happens, it will make a glyph matrix
342 reallocation necessary. */
343 if (dpyinfo->n_fonts == 1)
344 {
345 dpyinfo->smallest_font_height = font->font.height;
346 dpyinfo->smallest_char_width = font->min_width;
347 fonts_changed_p = 1;
348 }
349 else
350 {
351 if (dpyinfo->smallest_font_height > font->font.height)
352 dpyinfo->smallest_font_height = font->font.height,
353 fonts_changed_p |= 1;
354 if (dpyinfo->smallest_char_width > font->min_width)
355 dpyinfo->smallest_char_width = font->min_width,
356 fonts_changed_p |= 1;
357 }
358
359 return font;
2d93c6bd
KH
360
361 err:
362 if (xftfont) XftFontClose (display, xftfont);
363 UNBLOCK_INPUT;
364 if (xftfont_info) free (xftfont_info);
365 if (xfont) free (xfont);
366 return NULL;
c2f5bfd6
KH
367}
368
369static void
370xftfont_close (f, font)
371 FRAME_PTR f;
372 struct font *font;
373{
374 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
375
376 XftUnlockFace (xftfont_info->xftfont);
377 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
dcce3c58
KH
378 if (font->font.name)
379 free (font->font.name);
c2f5bfd6
KH
380 free (font);
381 FRAME_X_DISPLAY_INFO (f)->n_fonts--;
382}
383
c2f5bfd6
KH
384static int
385xftfont_prepare_face (f, face)
386 FRAME_PTR f;
387 struct face *face;
388{
e2d0c925 389 struct xftface_info *xftface_info;
c2f5bfd6 390
a703d27d
KH
391#if 0
392 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
393 if (face != face->ascii_face)
394 {
395 face->extra = face->ascii_face->extra;
396 return 0;
397 }
a703d27d 398#endif
e2d0c925
KH
399
400 xftface_info = malloc (sizeof (struct xftface_info));
c2f5bfd6
KH
401 if (! xftface_info)
402 return -1;
403
404 BLOCK_INPUT;
405 xftface_info->xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
406 FRAME_X_WINDOW (f),
407 FRAME_X_VISUAL (f),
408 FRAME_X_COLORMAP (f));
c2f5bfd6
KH
409 xftfont_get_colors (f, face, face->gc, NULL,
410 &xftface_info->xft_fg, &xftface_info->xft_bg);
411 UNBLOCK_INPUT;
412
413 face->extra = xftface_info;
414 return 0;
415}
416
417static void
418xftfont_done_face (f, face)
419 FRAME_PTR f;
420 struct face *face;
421{
e2d0c925
KH
422 struct xftface_info *xftface_info;
423
a703d27d
KH
424#if 0
425 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
e2d0c925
KH
426 if (face != face->ascii_face
427 || ! face->extra)
428 return;
a703d27d 429#endif
c2f5bfd6 430
e2d0c925 431 xftface_info = (struct xftface_info *) face->extra;
773039e8
JD
432 if (xftface_info)
433 {
434 BLOCK_INPUT;
435 XftDrawDestroy (xftface_info->xft_draw);
436 UNBLOCK_INPUT;
437 free (xftface_info);
438 }
e2d0c925 439 face->extra = NULL;
c2f5bfd6
KH
440}
441
442static unsigned
443xftfont_encode_char (font, c)
444 struct font *font;
445 int c;
446{
447 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
448 unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
449 (FcChar32) c);
450
451 return (code ? code : 0xFFFFFFFF);
452}
453
454static int
455xftfont_text_extents (font, code, nglyphs, metrics)
456 struct font *font;
457 unsigned *code;
458 int nglyphs;
459 struct font_metrics *metrics;
460{
461 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
462 XGlyphInfo extents;
463
464 BLOCK_INPUT;
465 XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
466 &extents);
467 UNBLOCK_INPUT;
468 if (metrics)
469 {
470 metrics->lbearing = - extents.x;
471 metrics->rbearing = - extents.x + extents.width;
472 metrics->width = extents.xOff;
473 metrics->ascent = extents.y;
4b848612 474 metrics->descent = extents.height - extents.y;
c2f5bfd6
KH
475 }
476 return extents.xOff;
477}
478
479static int
480xftfont_draw (s, from, to, x, y, with_background)
481 struct glyph_string *s;
482 int from, to, x, y, with_background;
483{
484 FRAME_PTR f = s->f;
485 struct face *face = s->face;
486 struct xftfont_info *xftfont_info = (struct xftfont_info *) face->font_info;
487 struct xftface_info *xftface_info = (struct xftface_info *) face->extra;
488 FT_UInt *code;
489 XftColor fg, bg;
490 XRectangle r;
491 int len = to - from;
492 int i;
493
494 xftfont_get_colors (f, face, s->gc, xftface_info,
322f8671 495 &fg, with_background ? &bg : NULL);
c2f5bfd6
KH
496 BLOCK_INPUT;
497 if (s->clip_width)
498 {
499 r.x = s->clip_x, r.width = s->clip_width;
500 r.y = s->clip_y, r.height = s->clip_height;
501 XftDrawSetClipRectangles (xftface_info->xft_draw, 0, 0, &r, 1);
502 }
503 if (with_background)
504 {
505 struct font *font = (struct font *) face->font_info;
506
507 XftDrawRect (xftface_info->xft_draw, &bg,
508 x, y - face->font->ascent, s->width, font->font.height);
509 }
510 code = alloca (sizeof (FT_UInt) * len);
511 for (i = 0; i < len; i++)
512 code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
513 | XCHAR2B_BYTE2 (s->char2b + from + i));
514
515 XftDrawGlyphs (xftface_info->xft_draw, &fg, xftfont_info->xftfont,
516 x, y, code, len);
517 if (s->clip_width)
518 XftDrawSetClip (xftface_info->xft_draw, NULL);
519 UNBLOCK_INPUT;
520
521 return len;
522}
523
524static int
525xftfont_anchor_point (font, code, index, x, y)
526 struct font *font;
527 unsigned code;
528 int index;
529 int *x, *y;
530{
531 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
532 FT_Face ft_face = xftfont_info->ft_face;
533
534 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
535 return -1;
536 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
537 return -1;
538 if (index >= ft_face->glyph->outline.n_points)
539 return -1;
540 *x = ft_face->glyph->outline.points[index].x;
541 *y = ft_face->glyph->outline.points[index].y;
542 return 0;
543}
544
545
546void
547syms_of_xftfont ()
548{
549 DEFSYM (Qxft, "xft");
550
551 xftfont_driver = ftfont_driver;
552 xftfont_driver.type = Qxft;
553 xftfont_driver.get_cache = xfont_driver.get_cache;
554 xftfont_driver.list = xftfont_list;
10aca0f7 555 xftfont_driver.match = xftfont_match;
c2f5bfd6
KH
556 xftfont_driver.open = xftfont_open;
557 xftfont_driver.close = xftfont_close;
558 xftfont_driver.prepare_face = xftfont_prepare_face;
559 xftfont_driver.done_face = xftfont_done_face;
560 xftfont_driver.encode_char = xftfont_encode_char;
561 xftfont_driver.text_extents = xftfont_text_extents;
562 xftfont_driver.draw = xftfont_draw;
563 xftfont_driver.anchor_point = xftfont_anchor_point;
564
565 register_font_driver (&xftfont_driver, NULL);
566}
885b7d09
MB
567
568/* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
569 (do not change this comment) */