emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to src/xftfont.c


From: Miles Bader
Subject: [Emacs-diffs] Changes to src/xftfont.c
Date: Fri, 01 Feb 2008 16:04:20 +0000

CVSROOT:        /cvsroot/emacs
Module name:    emacs
Changes by:     Miles Bader <miles>     08/02/01 16:01:31

Index: src/xftfont.c
===================================================================
RCS file: src/xftfont.c
diff -N src/xftfont.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ src/xftfont.c       1 Feb 2008 16:00:44 -0000       1.2
@@ -0,0 +1,667 @@
+/* xftfont.c -- XFT font driver.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007
+     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"
+#include "ftfont.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;
+#ifdef HAVE_LIBOTF
+  int maybe_otf;         /* Flag to tell if this may be OTF or not.  */
+  OTF *otf;
+#endif /* HAVE_LIBOTF */
+};
+
+/* Structure pointed by (struct face *)->extra  */
+
+struct xftface_info
+{
+  XftColor xft_fg;             /* color for face->foreground */
+  XftColor xft_bg;             /* color for face->background */
+};
+
+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));
+
+
+/* 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.  */
+
+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;
+    }
+}
+
+/* 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.  */
+
+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 ();
+       }
+      fid_known = 1;
+    }
+  return fid;
+}
+
+
+static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
+static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
+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 *));
+static int xftfont_end_for_frame P_ ((FRAME_PTR f));
+
+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);
+  int i;
+  
+  if (! NILP (val))
+    for (i = 0; i < ASIZE (val); i++)
+      ASET (AREF (val, i), FONT_TYPE_INDEX, Qxft);
+  return val;
+}
+
+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;
+}
+
+extern Lisp_Object ftfont_font_format P_ ((FcPattern *));
+
+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;
+  FcPattern *pattern, *pat = NULL;
+  FcChar8 *file;
+  struct xftfont_info *xftfont_info = NULL;
+  XFontStruct *xfont = NULL;
+  struct font *font;
+  double size = 0;
+  XftFont *xftfont = NULL;
+  int spacing;
+  char *name;
+  int len;
+  XGlyphInfo extents;
+  FT_Face ft_face;
+
+  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;
+
+  pat = FcPatternCreate ();
+  FcPatternAddString (pat, FC_FILE, file);
+  FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
+  /*FcPatternAddBool (pat, FC_ANTIALIAS, FcTrue);*/
+  val = AREF (entity, FONT_FAMILY_INDEX);
+  if (! NILP (val))
+    FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
+  FcConfigSubstitute (NULL, pat, FcMatchPattern);
+
+  BLOCK_INPUT;
+  XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
+  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)
+    goto err;
+
+  xftfont_info = malloc (sizeof (struct xftfont_info));
+  if (! xftfont_info)
+    goto err;
+  xfont = malloc (sizeof (XFontStruct));
+  if (! xfont)
+    goto err;
+  xftfont_info->display = display;
+  xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
+  xftfont_info->xftfont = xftfont;
+#ifdef HAVE_LIBOTF
+  ft_face = XftLockFace (xftfont);
+  xftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
+  XftUnlockFace (xftfont);
+  xftfont_info->otf = NULL;
+#endif /* HAVE_LIBOTF */
+
+  font = (struct font *) xftfont_info;
+  font->format = ftfont_font_format (xftfont->pattern);
+  font->entity = entity;
+  font->pixel_size = size;
+  font->driver = &xftfont_driver;
+  len = 96;
+  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;
+  font->file_name = (char *) file;
+  font->font.size = xftfont->max_advance_width;
+  font->font.charset = font->encoding_charset = font->repertory_charset = -1;
+
+  if (FcPatternGetInteger (xftfont->pattern, FC_SPACING, 0, &spacing)
+      != FcResultMatch)
+    spacing = FC_PROPORTIONAL;
+  if (! ascii_printable[0])
+    {
+      int i;
+      for (i = 0; i < 95; i++)
+       ascii_printable[i] = ' ' + i;
+    }
+  if (spacing != FC_PROPORTIONAL)
+    {
+      font->font.average_width = font->font.space_width
+       = xftfont->max_advance_width;
+      XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
+    }
+  else
+    {
+      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;
+    }
+  UNBLOCK_INPUT;
+
+  font->ascent = xftfont->ascent;
+  if (font->ascent < extents.y)
+    font->ascent = extents.y;
+  font->descent = xftfont->descent;
+  if (font->descent < extents.height - extents.y)
+    font->descent = extents.height - extents.y;
+  font->font.height = font->ascent + font->descent;
+
+  /* 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 = font->ascent;
+  xfont->descent = font->descent;
+  xfont->max_bounds.descent = font->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;
+
+ err:
+  if (xftfont) XftFontClose (display, xftfont);
+  UNBLOCK_INPUT;
+  if (xftfont_info) free (xftfont_info);
+  if (xfont) free (xfont);
+  return NULL;
+}
+
+static void
+xftfont_close (f, font)
+     FRAME_PTR f;
+     struct font *font;
+{
+  struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
+
+#ifdef HAVE_LIBOTF
+  if (xftfont_info->otf)
+    OTF_close (xftfont_info->otf);
+#endif
+  XftFontClose (xftfont_info->display, xftfont_info->xftfont);
+  if (font->font.name)
+    free (font->font.name);
+  free (font);
+  FRAME_X_DISPLAY_INFO (f)->n_fonts--;
+}
+
+static int
+xftfont_prepare_face (f, face)
+     FRAME_PTR f;
+     struct face *face;
+{
+  struct xftface_info *xftface_info;
+
+#if 0
+  /* This doesn't work if face->ascii_face doesn't use an Xft font. */
+  if (face != face->ascii_face)
+    {
+      face->extra = face->ascii_face->extra;
+      return 0;
+    }
+#endif
+
+  xftface_info = malloc (sizeof (struct xftface_info));
+  if (! xftface_info)
+    return -1;
+
+  BLOCK_INPUT;
+  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;
+{
+  struct xftface_info *xftface_info;
+  
+#if 0
+  /* This doesn't work if face->ascii_face doesn't use an Xft font. */
+  if (face != face->ascii_face
+      || ! face->extra)
+    return;
+#endif
+
+  xftface_info = (struct xftface_info *) face->extra;
+  if (xftface_info)
+    {
+      free (xftface_info);
+      face->extra = NULL;
+    }
+}
+
+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 : FONT_INVALID_CODE);
+}
+
+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;
+      metrics->descent = extents.height - extents.y;
+    }
+  return extents.xOff;
+}
+
+static XftDraw *
+xftfont_get_xft_draw (f)
+     FRAME_PTR f;
+{
+  XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);;
+
+  if (! xft_draw)
+    {
+      BLOCK_INPUT;
+      xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
+                              FRAME_X_WINDOW (f),
+                              FRAME_X_VISUAL (f),
+                              FRAME_X_COLORMAP (f));
+      UNBLOCK_INPUT;
+      if (! xft_draw)
+       abort ();
+      font_put_frame_data (f, &xftfont_driver, xft_draw);
+    }
+  return xft_draw;
+}
+
+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 *) s->font_info;
+  struct xftface_info *xftface_info = NULL;
+  XftDraw *xft_draw = xftfont_get_xft_draw (f);
+  FT_UInt *code;
+  XftColor fg, bg;
+  XRectangle r;
+  int len = to - from;
+  int i;
+
+  if (s->font_info == face->font_info)
+    xftface_info = (struct xftface_info *) face->extra;
+  xftfont_get_colors (f, face, s->gc, xftface_info,
+                     &fg, with_background ? &bg : NULL);
+  BLOCK_INPUT;
+  if (s->num_clips > 0)
+    XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips);
+  else
+    XftDrawSetClip (xft_draw, NULL);
+
+  if (with_background)
+    {
+      struct font *font = (struct font *) face->font_info;
+
+      XftDrawRect (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 (xft_draw, &fg, xftfont_info->xftfont,
+                x, y, code, len);
+  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 = XftLockFace (xftfont_info->xftfont);
+  int result;
+
+  if (FT_Load_Glyph (ft_face, code, FT_LOAD_DEFAULT) != 0)
+    result = -1;
+  else if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+    result = -1;
+  else if (index >= ft_face->glyph->outline.n_points)
+    result = -1;
+  else
+    {
+      *x = ft_face->glyph->outline.points[index].x;
+      *y = ft_face->glyph->outline.points[index].y;
+    }
+  XftUnlockFace (xftfont_info->xftfont);
+  return result;
+}
+
+static int
+xftfont_end_for_frame (f)
+     FRAME_PTR f;
+{
+  XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
+
+  if (xft_draw)
+    {
+      BLOCK_INPUT;
+      XftDrawDestroy (xft_draw);
+      UNBLOCK_INPUT;
+      font_put_frame_data (f, &xftfont_driver, NULL);
+    }
+  return 0;
+}
+
+#ifdef HAVE_LIBOTF
+#ifdef HAVE_M17N_FLT
+static Lisp_Object
+xftfont_shape (lgstring)
+     Lisp_Object lgstring;
+{
+  struct font *font;
+  struct xftfont_info *xftfont_info;
+  int result;
+  FT_Face ft_face;
+
+  CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
+  xftfont_info = (struct xftfont_info *) font;
+  if (! xftfont_info->maybe_otf)
+    return Qnil;
+  ft_face = XftLockFace (xftfont_info->xftfont);
+  if (! xftfont_info->otf)
+    {
+      OTF *otf = OTF_open_ft_face (ft_face);
+
+      if (! otf || OTF_get_table (otf, "head") < 0)
+       {
+         if (otf)
+           OTF_close (otf);
+         xftfont_info->maybe_otf = 0;
+         XftUnlockFace (xftfont_info->xftfont);
+         return 0;
+       }
+      xftfont_info->otf = otf;
+    }
+
+  result = ftfont_shape_by_flt (lgstring, font, ft_face, xftfont_info->otf);
+  XftUnlockFace (xftfont_info->xftfont);
+  return result;
+}
+#endif /* HAVE_M17N_FLT */
+#endif /* HAVE_LIBOTF */
+
+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;
+  xftfont_driver.match = xftfont_match;
+  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;
+  xftfont_driver.end_for_frame = xftfont_end_for_frame;
+#ifdef HAVE_LIBOTF
+#ifdef HAVE_M17N_FLT
+  xftfont_driver.shape = xftfont_shape;
+#endif /* HAVE_M17N_FLT */
+#endif /* HAVE_LIBOTF */
+
+  register_font_driver (&xftfont_driver, NULL);
+}
+
+/* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
+   (do not change this comment) */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]