(xftfont_draw): If s->font_info != s->face->font_info,
[bpt/emacs.git] / src / xftfont.c
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
7 This file is part of GNU Emacs.
8
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 2, or (at your option)
12 any later version.
13
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.
18
19 You should have received a copy of the GNU General Public License
20 along with GNU Emacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, 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
41 static Lisp_Object Qxft;
42
43 /* The actual structure for Xft font that can be casted to struct
44 font. */
45
46 struct xftfont_info
47 {
48 struct font font;
49 Display *display;
50 int screen;
51 XftFont *xftfont;
52 FT_Face ft_face; /* set to XftLockFace (xftfont) */
53 };
54
55 /* Structure pointed by (struct face *)->extra */
56
57 struct xftface_info
58 {
59 XftColor xft_fg; /* color for face->foreground */
60 XftColor xft_bg; /* color for face->background */
61 XftDraw *xft_draw;
62 };
63
64 static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc,
65 struct xftface_info *,
66 XftColor *fg, XftColor *bg));
67 static Font xftfont_default_fid P_ ((FRAME_PTR));
68
69
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
74 static void
75 xftfont_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
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. */
138
139 static Font
140 xftfont_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 }
155 fid_known = 1;
156 }
157 return fid;
158 }
159
160
161 static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
162 static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
163 static struct font *xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
164 static void xftfont_close P_ ((FRAME_PTR, struct font *));
165 static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
166 static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
167 static unsigned xftfont_encode_char P_ ((struct font *, int));
168 static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
169 struct font_metrics *));
170 static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
171
172 static int xftfont_anchor_point P_ ((struct font *, unsigned, int,
173 int *, int *));
174
175 struct font_driver xftfont_driver;
176
177 static Lisp_Object
178 xftfont_list (frame, spec)
179 Lisp_Object frame;
180 Lisp_Object spec;
181 {
182 Lisp_Object val = ftfont_driver.list (frame, spec);
183 int i;
184
185 if (! NILP (val))
186 for (i = 0; i < ASIZE (val); i++)
187 ASET (AREF (val, i), FONT_TYPE_INDEX, Qxft);
188 return val;
189 }
190
191 static Lisp_Object
192 xftfont_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
203 extern Lisp_Object ftfont_font_format P_ ((FcPattern *));
204
205 static FcChar8 ascii_printable[95];
206
207 static struct font *
208 xftfont_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;
216 FcPattern *pattern, *pat = NULL;
217 FcChar8 *file;
218 struct xftfont_info *xftfont_info = NULL;
219 XFontStruct *xfont = NULL;
220 struct font *font;
221 double size = 0;
222 XftFont *xftfont = NULL;
223 int spacing;
224 char *name;
225 int len;
226 XGlyphInfo extents;
227
228 val = AREF (entity, FONT_EXTRA_INDEX);
229 if (XTYPE (val) != Lisp_Misc
230 || XMISCTYPE (val) != Lisp_Misc_Save_Value)
231 return NULL;
232 pattern = XSAVE_VALUE (val)->pointer;
233 if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
234 return NULL;
235
236 size = XINT (AREF (entity, FONT_SIZE_INDEX));
237 if (size == 0)
238 size = pixel_size;
239
240 pat = FcPatternCreate ();
241 FcPatternAddString (pat, FC_FILE, file);
242 FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
243 /*FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);*/
244 val = AREF (entity, FONT_FAMILY_INDEX);
245 if (! NILP (val))
246 FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
247 FcConfigSubstitute (NULL, pat, FcMatchPattern);
248
249 BLOCK_INPUT;
250 XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
251 xftfont = XftFontOpenPattern (display, pat);
252 /* We should not destroy PAT here because it is kept in XFTFONT and
253 destroyed automatically when XFTFONT is closed. */
254 if (! xftfont)
255 goto err;
256
257 xftfont_info = malloc (sizeof (struct xftfont_info));
258 if (! xftfont_info)
259 goto err;
260 xfont = malloc (sizeof (XFontStruct));
261 if (! xfont)
262 goto err;
263 xftfont_info->display = display;
264 xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
265 xftfont_info->xftfont = xftfont;
266 xftfont_info->ft_face = XftLockFace (xftfont);
267
268 font = (struct font *) xftfont_info;
269 font->format = ftfont_font_format (xftfont->pattern);
270 font->entity = entity;
271 font->pixel_size = size;
272 font->driver = &xftfont_driver;
273 len = 96;
274 name = malloc (len);
275 while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
276 {
277 char *new = realloc (name, len += 32);
278
279 if (! new)
280 free (name);
281 name = new;
282 }
283 if (! name)
284 goto err;
285 font->font.full_name = font->font.name = name;
286 font->file_name = (char *) file;
287 font->font.size = xftfont->max_advance_width;
288 font->font.charset = font->encoding_charset = font->repertory_charset = -1;
289
290 if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing)
291 != FcResultMatch)
292 spacing = FC_PROPORTIONAL;
293 if (! ascii_printable[0])
294 {
295 int i;
296 for (i = 0; i < 95; i++)
297 ascii_printable[i] = ' ' + i;
298 }
299 if (spacing != FC_PROPORTIONAL)
300 {
301 font->font.average_width = font->font.space_width
302 = xftfont->max_advance_width;
303 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
304 }
305 else
306 {
307 XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
308 font->font.space_width = extents.xOff;
309 if (font->font.space_width <= 0)
310 /* dirty workaround */
311 font->font.space_width = pixel_size;
312 XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
313 font->font.average_width = (font->font.space_width + extents.xOff) / 95;
314 }
315 UNBLOCK_INPUT;
316
317 font->ascent = xftfont->ascent;
318 if (font->ascent < extents.y)
319 font->ascent = extents.y;
320 font->descent = xftfont->descent;
321 if (font->descent < extents.height - extents.y)
322 font->descent = extents.height - extents.y;
323 font->font.height = font->ascent + font->descent;
324
325 /* Unfortunately Xft doesn't provide a way to get minimum char
326 width. So, we use space_width instead. */
327 font->min_width = font->font.space_width;
328
329 font->font.baseline_offset = 0;
330 font->font.relative_compose = 0;
331 font->font.default_ascent = 0;
332 font->font.vertical_centering = 0;
333
334 /* Setup pseudo XFontStruct */
335 xfont->fid = xftfont_default_fid (f);
336 xfont->ascent = font->ascent;
337 xfont->descent = font->descent;
338 xfont->max_bounds.descent = font->descent;
339 xfont->max_bounds.width = xftfont->max_advance_width;
340 xfont->min_bounds.width = font->font.space_width;
341 font->font.font = xfont;
342
343 dpyinfo->n_fonts++;
344
345 /* Set global flag fonts_changed_p to non-zero if the font loaded
346 has a character with a smaller width than any other character
347 before, or if the font loaded has a smaller height than any other
348 font loaded before. If this happens, it will make a glyph matrix
349 reallocation necessary. */
350 if (dpyinfo->n_fonts == 1)
351 {
352 dpyinfo->smallest_font_height = font->font.height;
353 dpyinfo->smallest_char_width = font->min_width;
354 fonts_changed_p = 1;
355 }
356 else
357 {
358 if (dpyinfo->smallest_font_height > font->font.height)
359 dpyinfo->smallest_font_height = font->font.height,
360 fonts_changed_p |= 1;
361 if (dpyinfo->smallest_char_width > font->min_width)
362 dpyinfo->smallest_char_width = font->min_width,
363 fonts_changed_p |= 1;
364 }
365
366 return font;
367
368 err:
369 if (xftfont) XftFontClose (display, xftfont);
370 UNBLOCK_INPUT;
371 if (xftfont_info) free (xftfont_info);
372 if (xfont) free (xfont);
373 return NULL;
374 }
375
376 static void
377 xftfont_close (f, font)
378 FRAME_PTR f;
379 struct font *font;
380 {
381 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
382
383 XftUnlockFace (xftfont_info->xftfont);
384 XftFontClose (xftfont_info->display, xftfont_info->xftfont);
385 if (font->font.name)
386 free (font->font.name);
387 free (font);
388 FRAME_X_DISPLAY_INFO (f)->n_fonts--;
389 }
390
391 static int
392 xftfont_prepare_face (f, face)
393 FRAME_PTR f;
394 struct face *face;
395 {
396 struct xftface_info *xftface_info;
397
398 #if 0
399 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
400 if (face != face->ascii_face)
401 {
402 face->extra = face->ascii_face->extra;
403 return 0;
404 }
405 #endif
406
407 xftface_info = malloc (sizeof (struct xftface_info));
408 if (! xftface_info)
409 return -1;
410
411 BLOCK_INPUT;
412 xftface_info->xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
413 FRAME_X_WINDOW (f),
414 FRAME_X_VISUAL (f),
415 FRAME_X_COLORMAP (f));
416 xftfont_get_colors (f, face, face->gc, NULL,
417 &xftface_info->xft_fg, &xftface_info->xft_bg);
418 UNBLOCK_INPUT;
419
420 face->extra = xftface_info;
421 return 0;
422 }
423
424 static void
425 xftfont_done_face (f, face)
426 FRAME_PTR f;
427 struct face *face;
428 {
429 struct xftface_info *xftface_info;
430
431 #if 0
432 /* This doesn't work if face->ascii_face doesn't use an Xft font. */
433 if (face != face->ascii_face
434 || ! face->extra)
435 return;
436 #endif
437
438 xftface_info = (struct xftface_info *) face->extra;
439 if (xftface_info)
440 {
441 BLOCK_INPUT;
442 XftDrawDestroy (xftface_info->xft_draw);
443 UNBLOCK_INPUT;
444 free (xftface_info);
445 }
446 face->extra = NULL;
447 }
448
449 static unsigned
450 xftfont_encode_char (font, c)
451 struct font *font;
452 int c;
453 {
454 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
455 unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
456 (FcChar32) c);
457
458 return (code ? code : 0xFFFFFFFF);
459 }
460
461 static int
462 xftfont_text_extents (font, code, nglyphs, metrics)
463 struct font *font;
464 unsigned *code;
465 int nglyphs;
466 struct font_metrics *metrics;
467 {
468 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
469 XGlyphInfo extents;
470
471 BLOCK_INPUT;
472 XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
473 &extents);
474 UNBLOCK_INPUT;
475 if (metrics)
476 {
477 metrics->lbearing = - extents.x;
478 metrics->rbearing = - extents.x + extents.width;
479 metrics->width = extents.xOff;
480 metrics->ascent = extents.y;
481 metrics->descent = extents.height - extents.y;
482 }
483 return extents.xOff;
484 }
485
486 static int
487 xftfont_draw (s, from, to, x, y, with_background)
488 struct glyph_string *s;
489 int from, to, x, y, with_background;
490 {
491 FRAME_PTR f = s->f;
492 struct face *face = s->face;
493 struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font_info;
494 struct xftface_info *xftface_info = NULL;
495 XftDraw *xft_draw = NULL;
496 FT_UInt *code;
497 XftColor fg, bg;
498 XRectangle r;
499 int len = to - from;
500 int i;
501
502 if (s->font_info == face->font_info)
503 {
504 xftface_info = (struct xftface_info *) face->extra;
505 xft_draw = xftface_info->xft_draw;
506 }
507 xftfont_get_colors (f, face, s->gc, xftface_info,
508 &fg, with_background ? &bg : NULL);
509 BLOCK_INPUT;
510 if (! xft_draw)
511 xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
512 FRAME_X_WINDOW (f),
513 FRAME_X_VISUAL (f),
514 FRAME_X_COLORMAP (f));
515 if (s->clip_width)
516 {
517 r.x = s->clip_x, r.width = s->clip_width;
518 r.y = s->clip_y, r.height = s->clip_height;
519 XftDrawSetClipRectangles (xft_draw, 0, 0, &r, 1);
520 }
521 if (with_background)
522 {
523 struct font *font = (struct font *) face->font_info;
524
525 XftDrawRect (xft_draw, &bg,
526 x, y - face->font->ascent, s->width, font->font.height);
527 }
528 code = alloca (sizeof (FT_UInt) * len);
529 for (i = 0; i < len; i++)
530 code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
531 | XCHAR2B_BYTE2 (s->char2b + from + i));
532
533 XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
534 x, y, code, len);
535 if (s->clip_width)
536 XftDrawSetClip (xft_draw, NULL);
537 if (s->font_info != face->font_info)
538 XftDrawDestroy (xft_draw);
539 UNBLOCK_INPUT;
540
541 return len;
542 }
543
544 static int
545 xftfont_anchor_point (font, code, index, x, y)
546 struct font *font;
547 unsigned code;
548 int index;
549 int *x, *y;
550 {
551 struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
552 FT_Face ft_face = xftfont_info->ft_face;
553
554 if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
555 return -1;
556 if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
557 return -1;
558 if (index >= ft_face->glyph->outline.n_points)
559 return -1;
560 *x = ft_face->glyph->outline.points[index].x;
561 *y = ft_face->glyph->outline.points[index].y;
562 return 0;
563 }
564
565
566 void
567 syms_of_xftfont ()
568 {
569 DEFSYM (Qxft, "xft");
570
571 xftfont_driver = ftfont_driver;
572 xftfont_driver.type = Qxft;
573 xftfont_driver.get_cache = xfont_driver.get_cache;
574 xftfont_driver.list = xftfont_list;
575 xftfont_driver.match = xftfont_match;
576 xftfont_driver.open = xftfont_open;
577 xftfont_driver.close = xftfont_close;
578 xftfont_driver.prepare_face = xftfont_prepare_face;
579 xftfont_driver.done_face = xftfont_done_face;
580 xftfont_driver.encode_char = xftfont_encode_char;
581 xftfont_driver.text_extents = xftfont_text_extents;
582 xftfont_driver.draw = xftfont_draw;
583 xftfont_driver.anchor_point = xftfont_anchor_point;
584
585 register_font_driver (&xftfont_driver, NULL);
586 }
587
588 /* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
589 (do not change this comment) */