xftfont.c 15 KB
Newer Older
Kenichi Handa's avatar
Kenichi Handa committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
/* xftfont.c -- XFT font driver.
   Copyright (C) 2006 Free Software Foundation, Inc.
   Copyright (C) 2006
     National Institute of Advanced Industrial Science and Technology (AIST)
     Registration Number H13PRO009

This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.  */

#include <config.h>
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>

#include "lisp.h"
#include "dispextern.h"
#include "xterm.h"
#include "frame.h"
#include "blockinput.h"
#include "character.h"
#include "charset.h"
#include "fontset.h"
#include "font.h"

/* Xft font driver.  */

static Lisp_Object Qxft;

/* The actual structure for Xft font that can be casted to struct
   font.  */

struct xftfont_info
{
  struct font font;
  Display *display;
  int screen;
  XftFont *xftfont;
Kenichi Handa's avatar
Kenichi Handa committed
52
  FT_Face ft_face;		/* set to XftLockFace (xftfont) */
Kenichi Handa's avatar
Kenichi Handa committed
53 54 55
};

/* Structure pointed by (struct face *)->extra  */
Kenichi Handa's avatar
Kenichi Handa committed
56

Kenichi Handa's avatar
Kenichi Handa committed
57 58
struct xftface_info
{
Kenichi Handa's avatar
Kenichi Handa committed
59 60
  XftColor xft_fg;		/* color for face->foreground */
  XftColor xft_bg;		/* color for face->background */
Kenichi Handa's avatar
Kenichi Handa committed
61 62 63 64 65 66 67 68 69
  XftDraw *xft_draw;
};

static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc,
				    struct xftface_info *,
				    XftColor *fg, XftColor *bg));
static Font xftfont_default_fid P_ ((FRAME_PTR));


Kenichi Handa's avatar
Kenichi Handa committed
70 71 72 73
/* Setup foreground and background colors of GC into FG and BG.  If
   XFTFACE_INFO is not NULL, reuse the colors in it if possible.  BG
   may be NULL.  */

Kenichi Handa's avatar
Kenichi Handa committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
static void
xftfont_get_colors (f, face, gc, xftface_info, fg, bg)
     FRAME_PTR f;
     struct face *face;
     GC gc;
     struct xftface_info *xftface_info;
     XftColor *fg, *bg;
{
  if (xftface_info && face->gc == gc)
    {
      *fg = xftface_info->xft_fg;
      if (bg)
	*bg = xftface_info->xft_bg;
    }
  else
    {
      XGCValues xgcv;
      int fg_done = 0, bg_done = 0;

      BLOCK_INPUT;
      XGetGCValues (FRAME_X_DISPLAY (f), gc,
		    GCForeground | GCBackground, &xgcv);
      if (xftface_info)
	{
	  if (xgcv.foreground == face->foreground)
	    *fg = xftface_info->xft_fg, fg_done = 1;
	  else if (xgcv.foreground == face->background)
	    *fg = xftface_info->xft_bg, fg_done = 1;
	  if (! bg)
	    bg_done = 1;
	  else if (xgcv.background == face->background)
	    *bg = xftface_info->xft_bg, bg_done = 1;
	  else if (xgcv.background == face->foreground)
	    *bg = xftface_info->xft_fg, bg_done = 1;
	}

      if (fg_done + bg_done < 2)
	{
	  XColor colors[2];

	  colors[0].pixel = fg->pixel = xgcv.foreground;
	  if (bg)
	    colors[1].pixel = bg->pixel = xgcv.background;
	  XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors,
			bg ? 2 : 1);
	  fg->color.alpha = 0xFFFF;
	  fg->color.red = colors[0].red;
	  fg->color.green = colors[0].green;
	  fg->color.blue = colors[0].blue;
	  if (bg)
	    {
	      bg->color.alpha = 0xFFFF;
	      bg->color.red = colors[1].red;
	      bg->color.green = colors[1].green;
	      bg->color.blue = colors[1].blue;
	    }
	}
      UNBLOCK_INPUT;
    }
}

Kenichi Handa's avatar
Kenichi Handa committed
135 136 137
/* Return the default Font ID on frame F.  The Returned Font ID is
   stored in the GC of the frame F, but the font is never used.  So,
   any ID is ok as long as it is valid.  */
Kenichi Handa's avatar
Kenichi Handa committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

static Font
xftfont_default_fid (f)
     FRAME_PTR f;
{
  static int fid_known;
  static Font fid;

  if (! fid_known)
    {
      fid = XLoadFont (FRAME_X_DISPLAY (f), "fixed");
      if (! fid)
	{
	  fid = XLoadFont (FRAME_X_DISPLAY (f), "*");
	  if (! fid)
	    abort ();
	}
155
      fid_known = 1;
Kenichi Handa's avatar
Kenichi Handa committed
156 157 158 159 160 161
    }
  return fid;
}


static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
162
static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
static struct font *xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
static void xftfont_close P_ ((FRAME_PTR, struct font *));
static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
static unsigned xftfont_encode_char P_ ((struct font *, int));
static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
				     struct font_metrics *));
static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));

static int xftfont_anchor_point P_ ((struct font *, unsigned, int,
				     int *, int *));

struct font_driver xftfont_driver;

static Lisp_Object
xftfont_list (frame, spec)
     Lisp_Object frame;
     Lisp_Object spec;
{
  Lisp_Object val = ftfont_driver.list (frame, spec);
Kenichi Handa's avatar
Kenichi Handa committed
183
  int i;
Kenichi Handa's avatar
Kenichi Handa committed
184 185
  
  if (! NILP (val))
Kenichi Handa's avatar
Kenichi Handa committed
186 187
    for (i = 0; i < ASIZE (val); i++)
      ASET (AREF (val, i), FONT_TYPE_INDEX, Qxft);
Kenichi Handa's avatar
Kenichi Handa committed
188 189 190
  return val;
}

Kenichi Handa's avatar
Kenichi Handa committed
191 192 193 194 195 196 197 198 199 200 201 202
static Lisp_Object
xftfont_match (frame, spec)
     Lisp_Object frame;
     Lisp_Object spec;
{
  Lisp_Object entity = ftfont_driver.match (frame, spec);

  if (VECTORP (entity))
    ASET (entity, FONT_TYPE_INDEX, Qxft);
  return entity;
}

Kenichi Handa's avatar
Kenichi Handa committed
203 204 205 206 207 208 209 210 211 212 213
static FcChar8 ascii_printable[95];

static struct font *
xftfont_open (f, entity, pixel_size)
     FRAME_PTR f;
     Lisp_Object entity;
     int pixel_size;
{
  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
  Display *display = FRAME_X_DISPLAY (f);
  Lisp_Object val;
214 215 216 217
  FcPattern *pattern, *pat = NULL;
  FcChar8 *file;
  struct xftfont_info *xftfont_info = NULL;
  XFontStruct *xfont = NULL;
Kenichi Handa's avatar
Kenichi Handa committed
218 219
  struct font *font;
  double size = 0;
220
  XftFont *xftfont = NULL;
Kenichi Handa's avatar
Kenichi Handa committed
221
  int spacing;
222
  char *name;
223
  int len;
Kenichi Handa's avatar
Kenichi Handa committed
224 225 226 227 228 229 230 231 232 233 234 235

  val = AREF (entity, FONT_EXTRA_INDEX);
  if (XTYPE (val) != Lisp_Misc
      || XMISCTYPE (val) != Lisp_Misc_Save_Value)
    return NULL;
  pattern = XSAVE_VALUE (val)->pointer;
  if (FcPatternGetString (pattern, FC_FILE, 0, &file) != FcResultMatch)
    return NULL;

  size = XINT (AREF (entity, FONT_SIZE_INDEX));
  if (size == 0)
    size = pixel_size;
236

Kenichi Handa's avatar
Kenichi Handa committed
237 238 239 240
  pat = FcPatternCreate ();
  FcPatternAddString (pat, FC_FILE, file);
  FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
  FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);
241 242

  BLOCK_INPUT;
243
  XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
Kenichi Handa's avatar
Kenichi Handa committed
244 245 246 247
  xftfont = XftFontOpenPattern (display, pat);
  /* We should not destroy PAT here because it is kept in XFTFONT and
     destroyed automatically when XFTFONT is closed.  */
  if (! xftfont)
248
    goto err;
Kenichi Handa's avatar
Kenichi Handa committed
249 250 251

  xftfont_info = malloc (sizeof (struct xftfont_info));
  if (! xftfont_info)
252
    goto err;
Kenichi Handa's avatar
Kenichi Handa committed
253
  xfont = malloc (sizeof (XFontStruct));
254 255
  if (! xfont)
    goto err;
Kenichi Handa's avatar
Kenichi Handa committed
256 257 258 259 260 261 262 263 264
  xftfont_info->display = display;
  xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
  xftfont_info->xftfont = xftfont;
  xftfont_info->ft_face = XftLockFace (xftfont);

  font = (struct font *) xftfont_info;
  font->entity = entity;
  font->pixel_size = size;
  font->driver = &xftfont_driver;
265
  len = 96;
266 267 268 269 270 271 272 273 274 275 276 277
  name = malloc (len);
  while (name && font_unparse_fcname (entity, pixel_size, name, len) < 0)
    {
      char *new = realloc (name, len += 32);

      if (! new)
	free (name);
      name = new;
    }
  if (! name)
    goto err;
  font->font.full_name = font->font.name = name;
Kenichi Handa's avatar
Kenichi Handa committed
278 279
  font->file_name = (char *) file;
  font->font.size = xftfont->max_advance_width;
280
  font->font.charset = font->encoding_charset = font->repertory_charset = -1;
Kenichi Handa's avatar
Kenichi Handa committed
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
  font->ascent = xftfont->ascent;
  font->descent = xftfont->descent;
  font->font.height = xftfont->ascent + xftfont->descent;

  if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing)
      != FcResultMatch)
    spacing = FC_PROPORTIONAL;
  if (spacing != FC_PROPORTIONAL)
    font->font.average_width = font->font.space_width
      = xftfont->max_advance_width;
  else
    {
      XGlyphInfo extents;

      if (! ascii_printable[0])
	{
	  int i;
	  for (i = 0; i < 95; i++)
	    ascii_printable[i] = ' ' + i;
	}
      XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
      font->font.space_width = extents.xOff;
      if (font->font.space_width <= 0)
	/* dirty workaround */
	font->font.space_width = pixel_size;	
      XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
      font->font.average_width = (font->font.space_width + extents.xOff) / 95;
    }
309
  UNBLOCK_INPUT;
Kenichi Handa's avatar
Kenichi Handa committed
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352

  /* Unfortunately Xft doesn't provide a way to get minimum char
     width.  So, we use space_width instead.  */
  font->min_width = font->font.space_width;

  font->font.baseline_offset = 0;
  font->font.relative_compose = 0;
  font->font.default_ascent = 0;
  font->font.vertical_centering = 0;

  /* Setup pseudo XFontStruct */
  xfont->fid = xftfont_default_fid (f);
  xfont->ascent = xftfont->ascent;
  xfont->descent = xftfont->descent;
  xfont->max_bounds.descent = xftfont->descent;
  xfont->max_bounds.width = xftfont->max_advance_width;
  xfont->min_bounds.width = font->font.space_width;
  font->font.font = xfont;

  dpyinfo->n_fonts++;

  /* Set global flag fonts_changed_p to non-zero if the font loaded
     has a character with a smaller width than any other character
     before, or if the font loaded has a smaller height than any other
     font loaded before.  If this happens, it will make a glyph matrix
     reallocation necessary.  */
  if (dpyinfo->n_fonts == 1)
    {
      dpyinfo->smallest_font_height = font->font.height;
      dpyinfo->smallest_char_width = font->min_width;
      fonts_changed_p = 1;
    }
  else
    {
      if (dpyinfo->smallest_font_height > font->font.height)
	dpyinfo->smallest_font_height = font->font.height,
	  fonts_changed_p |= 1;
      if (dpyinfo->smallest_char_width > font->min_width)
	dpyinfo->smallest_char_width = font->min_width,
	  fonts_changed_p |= 1;
    }

  return font;
353 354 355 356 357 358 359

 err:
  if (xftfont) XftFontClose (display, xftfont);
  UNBLOCK_INPUT;
  if (xftfont_info) free (xftfont_info);
  if (xfont) free (xfont);
  return NULL;
Kenichi Handa's avatar
Kenichi Handa committed
360 361 362 363 364 365 366 367 368 369 370
}

static void
xftfont_close (f, font)
     FRAME_PTR f;
     struct font *font;
{
  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;

  XftUnlockFace (xftfont_info->xftfont);
  XftFontClose (xftfont_info->display, xftfont_info->xftfont);
371 372
  if (font->font.name)
    free (font->font.name);
Kenichi Handa's avatar
Kenichi Handa committed
373 374 375 376 377 378 379 380 381
  free (font);
  FRAME_X_DISPLAY_INFO (f)->n_fonts--;
}

static int
xftfont_prepare_face (f, face)
     FRAME_PTR f;
     struct face *face;
{
382
  struct xftface_info *xftface_info;
Kenichi Handa's avatar
Kenichi Handa committed
383

384 385
#if 0
  /* This doesn't work if face->ascii_face doesn't use an Xft font. */
386 387 388 389 390
  if (face != face->ascii_face)
    {
      face->extra = face->ascii_face->extra;
      return 0;
    }
391
#endif
392 393

  xftface_info = malloc (sizeof (struct xftface_info));
Kenichi Handa's avatar
Kenichi Handa committed
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
  if (! xftface_info)
    return -1;

  BLOCK_INPUT;
  xftface_info->xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
					  FRAME_X_WINDOW (f),
					  FRAME_X_VISUAL (f),
					  FRAME_X_COLORMAP (f));
  xftfont_get_colors (f, face, face->gc, NULL,
		      &xftface_info->xft_fg, &xftface_info->xft_bg);
  UNBLOCK_INPUT;

  face->extra = xftface_info;
  return 0;
}

static void
xftfont_done_face (f, face)
     FRAME_PTR f;
     struct face *face;
{
415 416
  struct xftface_info *xftface_info;
  
417 418
#if 0
  /* This doesn't work if face->ascii_face doesn't use an Xft font. */
419 420 421
  if (face != face->ascii_face
      || ! face->extra)
    return;
422
#endif
Kenichi Handa's avatar
Kenichi Handa committed
423

424
  xftface_info = (struct xftface_info *) face->extra;
425 426 427 428 429 430 431
  if (xftface_info)
    {
      BLOCK_INPUT;
      XftDrawDestroy (xftface_info->xft_draw);
      UNBLOCK_INPUT;
      free (xftface_info);
    }
432
  face->extra = NULL;
Kenichi Handa's avatar
Kenichi Handa committed
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
}

static unsigned
xftfont_encode_char (font, c)
     struct font *font;
     int c;
{
  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
  unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
				(FcChar32) c);
  
  return (code ? code : 0xFFFFFFFF);
}

static int
xftfont_text_extents (font, code, nglyphs, metrics)
     struct font *font;
     unsigned *code;
     int nglyphs;
     struct font_metrics *metrics;
{
  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
  XGlyphInfo extents;

  BLOCK_INPUT;
  XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
		   &extents);
  UNBLOCK_INPUT;
  if (metrics)
    {
      metrics->lbearing = - extents.x;
      metrics->rbearing = - extents.x + extents.width;
      metrics->width = extents.xOff;
      metrics->ascent = extents.y;
467
      metrics->descent = extents.height - extents.y;
Kenichi Handa's avatar
Kenichi Handa committed
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
    }
  return extents.xOff;
}

static int
xftfont_draw (s, from, to, x, y, with_background)
     struct glyph_string *s;
     int from, to, x, y, with_background;
{
  FRAME_PTR f = s->f;
  struct face *face = s->face;
  struct xftfont_info *xftfont_info = (struct xftfont_info *) face->font_info;
  struct xftface_info *xftface_info = (struct xftface_info *) face->extra;
  FT_UInt *code;
  XftColor fg, bg;
  XRectangle r;
  int len = to - from;
  int i;

  xftfont_get_colors (f, face, s->gc, xftface_info,
488
		      &fg, with_background ? &bg : NULL);
Kenichi Handa's avatar
Kenichi Handa committed
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
  BLOCK_INPUT;
  if (s->clip_width)
    {
      r.x = s->clip_x, r.width = s->clip_width;
      r.y = s->clip_y, r.height = s->clip_height;
      XftDrawSetClipRectangles (xftface_info->xft_draw, 0, 0, &r, 1);
    }
  if (with_background)
    {
      struct font *font = (struct font *) face->font_info;

      XftDrawRect (xftface_info->xft_draw, &bg,
		   x, y - face->font->ascent, s->width, font->font.height);
    }
  code = alloca (sizeof (FT_UInt) * len);
  for (i = 0; i < len; i++)
    code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
	       | XCHAR2B_BYTE2 (s->char2b + from + i));

  XftDrawGlyphs (xftface_info->xft_draw, &fg, xftfont_info->xftfont,
		 x, y, code, len);
  if (s->clip_width)
    XftDrawSetClip (xftface_info->xft_draw, NULL);
  UNBLOCK_INPUT;

  return len;
}

static int
xftfont_anchor_point (font, code, index, x, y)
     struct font *font;
     unsigned code;
     int index;
     int *x, *y;
{
  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
  FT_Face ft_face = xftfont_info->ft_face;

  if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
    return -1;
  if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
    return -1;
  if (index >= ft_face->glyph->outline.n_points)
    return -1;
  *x = ft_face->glyph->outline.points[index].x;
  *y = ft_face->glyph->outline.points[index].y;
  return 0;
}


void
syms_of_xftfont ()
{
  DEFSYM (Qxft, "xft");

  xftfont_driver = ftfont_driver;
  xftfont_driver.type = Qxft;
  xftfont_driver.get_cache = xfont_driver.get_cache;
  xftfont_driver.list = xftfont_list;
Kenichi Handa's avatar
Kenichi Handa committed
548
  xftfont_driver.match = xftfont_match;
Kenichi Handa's avatar
Kenichi Handa committed
549 550 551 552 553 554 555 556 557 558 559
  xftfont_driver.open = xftfont_open;
  xftfont_driver.close = xftfont_close;
  xftfont_driver.prepare_face = xftfont_prepare_face;
  xftfont_driver.done_face = xftfont_done_face;
  xftfont_driver.encode_char = xftfont_encode_char;
  xftfont_driver.text_extents = xftfont_text_extents;
  xftfont_driver.draw = xftfont_draw;
  xftfont_driver.anchor_point = xftfont_anchor_point;

  register_font_driver (&xftfont_driver, NULL);
}
Miles Bader's avatar
Miles Bader committed
560 561 562

/* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
   (do not change this comment) */