1 /* xftfont.c -- XFT font driver.
  2    Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
  3    Copyright (C) 2006, 2007, 2008, 2009, 2010
  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 3 of the License, or
 12 (at your option) 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.  If not, see <http://www.gnu.org/licenses/>.  */
 21 
 22 #include <config.h>
 23 #include <stdio.h>
 24 #include <setjmp.h>
 25 #include <X11/Xlib.h>
 26 #include <X11/Xft/Xft.h>
 27 
 28 #include "lisp.h"
 29 #include "dispextern.h"
 30 #include "xterm.h"
 31 #include "frame.h"
 32 #include "blockinput.h"
 33 #include "character.h"
 34 #include "charset.h"
 35 #include "fontset.h"
 36 #include "font.h"
 37 #include "ftfont.h"
 38 
 39 /* Xft font driver.  */
 40 
 41 static Lisp_Object Qxft;
 42 static Lisp_Object QChinting, QCautohint, QChintstyle, QCrgba, QCembolden,
 43   QClcdfilter;
 44 
 45 /* The actual structure for Xft font that can be casted to struct
 46    font.  */
 47 
 48 struct xftfont_info
 49 {
 50   struct font font;
 51   /* The following five members must be here in this order to be
 52      compatible with struct ftfont_info (in ftfont.c).  */
 53 #ifdef HAVE_LIBOTF
 54   int maybe_otf;          /* Flag to tell if this may be OTF or not.  */
 55   OTF *otf;
 56 #endif  /* HAVE_LIBOTF */
 57   FT_Size ft_size;
 58   int index;
 59   FT_Matrix matrix;
 60   Display *display;
 61   int screen;
 62   XftFont *xftfont;
 63 };
 64 
 65 /* Structure pointed by (struct face *)->extra  */
 66 
 67 struct xftface_info
 68 {
 69   XftColor xft_fg;              /* color for face->foreground */
 70   XftColor xft_bg;              /* color for face->background */
 71 };
 72 
 73 static void xftfont_get_colors P_ ((FRAME_PTR, struct face *, GC gc,
 74                                     struct xftface_info *,
 75                                     XftColor *fg, XftColor *bg));
 76 
 77 
 78 /* Setup foreground and background colors of GC into FG and BG.  If
 79    XFTFACE_INFO is not NULL, reuse the colors in it if possible.  BG
 80    may be NULL.  */
 81 
 82 static void
 83 xftfont_get_colors (f, face, gc, xftface_info, fg, bg)
 84      FRAME_PTR f;
 85      struct face *face;
 86      GC gc;
 87      struct xftface_info *xftface_info;
 88      XftColor *fg, *bg;
 89 {
 90   if (xftface_info && face->gc == gc)
 91     {
 92       *fg = xftface_info->xft_fg;
 93       if (bg)
 94         *bg = xftface_info->xft_bg;
 95     }
 96   else
 97     {
 98       XGCValues xgcv;
 99       int fg_done = 0, bg_done = 0;
100 
101       BLOCK_INPUT;
102       XGetGCValues (FRAME_X_DISPLAY (f), gc,
103                     GCForeground | GCBackground, &xgcv);
104       if (xftface_info)
105         {
106           if (xgcv.foreground == face->foreground)
107             *fg = xftface_info->xft_fg, fg_done = 1;
108           else if (xgcv.foreground == face->background)
109             *fg = xftface_info->xft_bg, fg_done = 1;
110           if (! bg)
111             bg_done = 1;
112           else if (xgcv.background == face->background)
113             *bg = xftface_info->xft_bg, bg_done = 1;
114           else if (xgcv.background == face->foreground)
115             *bg = xftface_info->xft_fg, bg_done = 1;
116         }
117 
118       if (fg_done + bg_done < 2)
119         {
120           XColor colors[2];
121 
122           colors[0].pixel = fg->pixel = xgcv.foreground;
123           if (bg)
124             colors[1].pixel = bg->pixel = xgcv.background;
125           XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors,
126                         bg ? 2 : 1);
127           fg->color.alpha = 0xFFFF;
128           fg->color.red = colors[0].red;
129           fg->color.green = colors[0].green;
130           fg->color.blue = colors[0].blue;
131           if (bg)
132             {
133               bg->color.alpha = 0xFFFF;
134               bg->color.red = colors[1].red;
135               bg->color.green = colors[1].green;
136               bg->color.blue = colors[1].blue;
137             }
138         }
139       UNBLOCK_INPUT;
140     }
141 }
142 
143 
144 static Lisp_Object xftfont_list P_ ((Lisp_Object, Lisp_Object));
145 static Lisp_Object xftfont_match P_ ((Lisp_Object, Lisp_Object));
146 static Lisp_Object xftfont_open P_ ((FRAME_PTR, Lisp_Object, int));
147 static void xftfont_close P_ ((FRAME_PTR, struct font *));
148 static int xftfont_prepare_face P_ ((FRAME_PTR, struct face *));
149 static void xftfont_done_face P_ ((FRAME_PTR, struct face *));
150 static int xftfont_has_char P_ ((Lisp_Object, int));
151 static unsigned xftfont_encode_char P_ ((struct font *, int));
152 static int xftfont_text_extents P_ ((struct font *, unsigned *, int,
153                                      struct font_metrics *));
154 static int xftfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
155 static int xftfont_end_for_frame P_ ((FRAME_PTR f));
156 
157 struct font_driver xftfont_driver;
158 
159 static Lisp_Object
160 xftfont_list (frame, spec)
161      Lisp_Object frame;
162      Lisp_Object spec;
163 {
164   Lisp_Object list = ftfont_driver.list (frame, spec), tail;
165 
166   for (tail = list; CONSP (tail); tail = XCDR (tail))
167     ASET (XCAR (tail), FONT_TYPE_INDEX, Qxft);
168   return list;
169 }
170 
171 static Lisp_Object
172 xftfont_match (frame, spec)
173      Lisp_Object frame;
174      Lisp_Object spec;
175 {
176   Lisp_Object entity = ftfont_driver.match (frame, spec);
177 
178   if (! NILP (entity))
179     ASET (entity, FONT_TYPE_INDEX, Qxft);
180   return entity;
181 }
182 
183 extern Lisp_Object ftfont_font_format P_ ((FcPattern *, Lisp_Object));
184 extern FcCharSet *ftfont_get_fc_charset P_ ((Lisp_Object));
185 extern Lisp_Object QCantialias;
186 
187 static FcChar8 ascii_printable[95];
188 
189 static void
190 xftfont_fix_match (pat, match)
191      FcPattern *pat, *match;
192 {
193   /*  These values are not used for matching (except antialias), but for
194       rendering, so make sure they are carried over to the match.
195       We also put antialias here because most fonts are antialiased, so
196       the match will have antialias true.  */
197 
198   FcBool b = FcTrue;
199   int i;
200   double dpi;
201 
202   FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b);
203   if (! b) 
204     {
205       FcPatternDel (match, FC_ANTIALIAS);
206       FcPatternAddBool (match, FC_ANTIALIAS, FcFalse);
207     }
208   FcPatternGetBool (pat, FC_HINTING, 0, &b);
209   if (! b) 
210     {
211       FcPatternDel (match, FC_HINTING);
212       FcPatternAddBool (match, FC_HINTING, FcFalse);
213     }
214   if (FcResultMatch == FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i))
215     {
216       FcPatternDel (match, FC_HINT_STYLE);
217       FcPatternAddInteger (match, FC_HINT_STYLE, i);
218     }
219 #ifndef FC_LCD_FILTER
220   /* Older fontconfig versions don't have FC_LCD_FILTER. */
221 #define FC_LCD_FILTER "lcdfilter"
222 #endif
223   if (FcResultMatch == FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i))
224     {
225       FcPatternDel (match, FC_LCD_FILTER);
226       FcPatternAddInteger (match, FC_LCD_FILTER, i);
227     }
228   if (FcResultMatch == FcPatternGetInteger (pat, FC_RGBA, 0, &i))
229     {
230       FcPatternDel (match, FC_RGBA);
231       FcPatternAddInteger (match, FC_RGBA, i);
232     }
233   if (FcResultMatch == FcPatternGetDouble (pat, FC_DPI, 0, &dpi))
234     {
235       FcPatternDel (match, FC_DPI);
236       FcPatternAddDouble (match, FC_DPI, dpi);
237     }
238 }
239 
240 static void
241 xftfont_add_rendering_parameters (pat, entity)
242      FcPattern *pat;
243      Lisp_Object entity;
244 {
245   Lisp_Object tail;
246   int ival;
247 
248   for (tail = AREF (entity, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
249     {
250       Lisp_Object key = XCAR (XCAR (tail));
251       Lisp_Object val = XCDR (XCAR (tail));
252 
253       if (EQ (key, QCantialias))
254           FcPatternAddBool (pat, FC_ANTIALIAS, NILP (val) ? FcFalse : FcTrue);
255       else if (EQ (key, QChinting))
256         FcPatternAddBool (pat, FC_HINTING, NILP (val) ? FcFalse : FcTrue);
257       else if (EQ (key, QCautohint))
258         FcPatternAddBool (pat, FC_AUTOHINT, NILP (val) ? FcFalse : FcTrue);
259       else if (EQ (key, QChintstyle))
260         {
261           if (INTEGERP (val))
262             FcPatternAddInteger (pat, FC_HINT_STYLE, XINT (val));
263           else if (SYMBOLP (val)
264                    && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
265             FcPatternAddInteger (pat, FC_HINT_STYLE, ival);
266         }
267       else if (EQ (key, QCrgba))
268         {
269           if (INTEGERP (val))
270             FcPatternAddInteger (pat, FC_RGBA, XINT (val));
271           else if (SYMBOLP (val)
272                    && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
273             FcPatternAddInteger (pat, FC_RGBA, ival);
274         }
275       else if (EQ (key, QClcdfilter))
276         {
277           if (INTEGERP (val))
278             FcPatternAddInteger (pat, FC_LCD_FILTER, ival = XINT (val));
279           else if (SYMBOLP (val)
280                    && FcNameConstant (SDATA (SYMBOL_NAME (val)), &ival))
281             FcPatternAddInteger (pat, FC_LCD_FILTER, ival);
282         }
283 #ifdef FC_EMBOLDEN
284       else if (EQ (key, QCembolden))
285         FcPatternAddBool (pat, FC_EMBOLDEN, NILP (val) ? FcFalse : FcTrue);
286 #endif
287     }
288 }
289 
290 static Lisp_Object
291 xftfont_open (f, entity, pixel_size)
292      FRAME_PTR f;
293      Lisp_Object entity;
294      int pixel_size;
295 {
296   FcResult result;
297   Display *display = FRAME_X_DISPLAY (f);
298   Lisp_Object val, filename, index, font_object;
299   FcPattern *pat = NULL, *match;
300   struct xftfont_info *xftfont_info = NULL;
301   struct font *font;
302   double size = 0;
303   XftFont *xftfont = NULL;
304   int spacing;
305   char name[256];
306   int len, i;
307   XGlyphInfo extents;
308   FT_Face ft_face;
309   FcMatrix *matrix;
310 
311   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
312   if (! CONSP (val))
313     return Qnil;
314   val = XCDR (val);
315   filename = XCAR (val);
316   index = XCDR (val);
317   size = XINT (AREF (entity, FONT_SIZE_INDEX));
318   if (size == 0)
319     size = pixel_size;
320   pat = FcPatternCreate ();
321   FcPatternAddInteger (pat, FC_WEIGHT, FONT_WEIGHT_NUMERIC (entity));
322   i = FONT_SLANT_NUMERIC (entity) - 100;
323   if (i < 0) i = 0;
324   FcPatternAddInteger (pat, FC_SLANT, i);
325   FcPatternAddInteger (pat, FC_WIDTH, FONT_WIDTH_NUMERIC (entity));
326   FcPatternAddDouble (pat, FC_PIXEL_SIZE, pixel_size);
327   val = AREF (entity, FONT_FAMILY_INDEX);
328   if (! NILP (val))
329     FcPatternAddString (pat, FC_FAMILY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
330   val = AREF (entity, FONT_FOUNDRY_INDEX);
331   if (! NILP (val))
332     FcPatternAddString (pat, FC_FOUNDRY, (FcChar8 *) SDATA (SYMBOL_NAME (val)));
333   val = AREF (entity, FONT_SPACING_INDEX);
334   if (! NILP (val))
335     FcPatternAddInteger (pat, FC_SPACING, XINT (val));
336   val = AREF (entity, FONT_DPI_INDEX);
337   if (! NILP (val))
338     {
339       double dbl = XINT (val);
340 
341       FcPatternAddDouble (pat, FC_DPI, dbl);
342     }
343   val = AREF (entity, FONT_AVGWIDTH_INDEX);
344   if (INTEGERP (val) && XINT (val) == 0)
345     FcPatternAddBool (pat, FC_SCALABLE, FcTrue);
346   /* This is necessary to identify the exact font (e.g. 10x20.pcf.gz
347      over 10x20-ISO8859-1.pcf.gz).  */
348   FcPatternAddCharSet (pat, FC_CHARSET, ftfont_get_fc_charset (entity));
349 
350   xftfont_add_rendering_parameters (pat, entity);
351 
352   FcPatternAddString (pat, FC_FILE, (FcChar8 *) SDATA (filename));
353   FcPatternAddInteger (pat, FC_INDEX, XINT (index));
354 
355 
356   BLOCK_INPUT;
357   /* Make sure that the Xrender extension is added before the Xft one.
358      Otherwise, the close-display hook set by Xft is called after the
359      one for Xrender, and the former tries to re-add the latter.  This
360      results in inconsistency of internal states and leads to X
361      protocol error when one reconnects to the same X server.
362      (Bug#1696)  */
363   {
364     int event_base, error_base;
365     XRenderQueryExtension (display, &event_base, &error_base);
366   }
367 
368   /* Substitute in values from X resources and XftDefaultSet.  */
369   XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
370   match = XftFontMatch (display, FRAME_X_SCREEN_NUMBER (f), pat, &result);
371   xftfont_fix_match (pat, match);
372 
373   FcPatternDestroy (pat);
374   xftfont = XftFontOpenPattern (display, match);
375   if (!xftfont)
376     {
377       UNBLOCK_INPUT;
378       XftPatternDestroy (match);
379       return Qnil;
380     }
381   ft_face = XftLockFace (xftfont);
382   UNBLOCK_INPUT;
383 
384   /* We should not destroy PAT here because it is kept in XFTFONT and
385      destroyed automatically when XFTFONT is closed.  */
386   font_object = font_make_object (VECSIZE (struct xftfont_info), entity, size);
387   ASET (font_object, FONT_TYPE_INDEX, Qxft);
388   len = font_unparse_xlfd (entity, size, name, 256);
389   if (len > 0)
390     ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
391   len = font_unparse_fcname (entity, size, name, 256);
392   if (len > 0)
393     ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
394   else
395     ASET (font_object, FONT_FULLNAME_INDEX,
396           AREF (font_object, FONT_NAME_INDEX));
397   ASET (font_object, FONT_FILE_INDEX, filename);
398   ASET (font_object, FONT_FORMAT_INDEX,
399         ftfont_font_format (xftfont->pattern, filename));
400   font = XFONT_OBJECT (font_object);
401   font->pixel_size = pixel_size;
402   font->driver = &xftfont_driver;
403   font->encoding_charset = font->repertory_charset = -1;
404 
405   xftfont_info = (struct xftfont_info *) font;
406   xftfont_info->display = display;
407   xftfont_info->screen = FRAME_X_SCREEN_NUMBER (f);
408   xftfont_info->xftfont = xftfont;
409   /* This means that there's no need of transformation.  */
410   xftfont_info->matrix.xx = 0;
411   if (FcPatternGetMatrix (xftfont->pattern, FC_MATRIX, 0, &matrix)
412       == FcResultMatch)
413     {
414       xftfont_info->matrix.xx = 0x10000L * matrix->xx;
415       xftfont_info->matrix.yy = 0x10000L * matrix->yy;
416       xftfont_info->matrix.xy = 0x10000L * matrix->xy;
417       xftfont_info->matrix.yx = 0x10000L * matrix->yx;
418     }
419   font->pixel_size = size;
420   font->driver = &xftfont_driver;
421   if (INTEGERP (AREF (entity, FONT_SPACING_INDEX)))
422     spacing = XINT (AREF (entity, FONT_SPACING_INDEX));
423   else
424     spacing = FC_PROPORTIONAL;
425   if (! ascii_printable[0])
426     {
427       int i;
428       for (i = 0; i < 95; i++)
429         ascii_printable[i] = ' ' + i;
430     }
431   BLOCK_INPUT;
432   if (spacing != FC_PROPORTIONAL)
433     {
434       font->min_width = font->average_width = font->space_width
435         = xftfont->max_advance_width;
436       XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
437     }
438   else
439     {
440       XftTextExtents8 (display, xftfont, ascii_printable, 1, &extents);
441       font->space_width = extents.xOff;
442       if (font->space_width <= 0)
443         /* dirty workaround */
444         font->space_width = pixel_size;
445       XftTextExtents8 (display, xftfont, ascii_printable + 1, 94, &extents);
446       font->average_width = (font->space_width + extents.xOff) / 95;
447     }
448   UNBLOCK_INPUT;
449 
450   font->ascent = xftfont->ascent;
451   font->descent = xftfont->descent;
452   if (pixel_size >= 5)
453     {
454       /* The above condition is a dirty workaround because
455          XftTextExtents8 behaves strangely for some fonts
456          (e.g. "Dejavu Sans Mono") when pixel_size is less than 5. */
457       if (font->ascent < extents.y)
458         font->ascent = extents.y;
459       if (font->descent < extents.height - extents.y)
460         font->descent = extents.height - extents.y;
461     }
462   font->height = font->ascent + font->descent;
463 
464   if (XINT (AREF (entity, FONT_SIZE_INDEX)) == 0)
465     {
466       int upEM = ft_face->units_per_EM;
467 
468       font->underline_position = -ft_face->underline_position * size / upEM;
469       font->underline_thickness = ft_face->underline_thickness * size / upEM;
470       if (font->underline_thickness > 2)
471         font->underline_position -= font->underline_thickness / 2;
472     }
473   else
474     {
475       font->underline_position = -1;
476       font->underline_thickness = 0;
477     }
478 #ifdef HAVE_LIBOTF
479   xftfont_info->maybe_otf = ft_face->face_flags & FT_FACE_FLAG_SFNT;
480   xftfont_info->otf = NULL;
481 #endif  /* HAVE_LIBOTF */
482   xftfont_info->ft_size = ft_face->size;
483 
484   /* Unfortunately Xft doesn't provide a way to get minimum char
485      width.  So, we use space_width instead.  */
486   font->min_width = font->space_width;
487 
488   font->baseline_offset = 0;
489   font->relative_compose = 0;
490   font->default_ascent = 0;
491   font->vertical_centering = 0;
492 #ifdef FT_BDF_H
493   if (! (ft_face->face_flags & FT_FACE_FLAG_SFNT))
494     {
495       BDF_PropertyRec rec;
496 
497       if (FT_Get_BDF_Property (ft_face, "_MULE_BASELINE_OFFSET", &rec) == 0
498           && rec.type == BDF_PROPERTY_TYPE_INTEGER)
499         font->baseline_offset = rec.u.integer;
500       if (FT_Get_BDF_Property (ft_face, "_MULE_RELATIVE_COMPOSE", &rec) == 0
501           && rec.type == BDF_PROPERTY_TYPE_INTEGER)
502         font->relative_compose = rec.u.integer;
503       if (FT_Get_BDF_Property (ft_face, "_MULE_DEFAULT_ASCENT", &rec) == 0
504           && rec.type == BDF_PROPERTY_TYPE_INTEGER)
505         font->default_ascent = rec.u.integer;
506     }
507 #endif
508 
509   return font_object;
510 }
511 
512 static void
513 xftfont_close (f, font)
514      FRAME_PTR f;
515      struct font *font;
516 {
517   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
518 
519 #ifdef HAVE_LIBOTF
520   if (xftfont_info->otf)
521     OTF_close (xftfont_info->otf);
522 #endif
523   BLOCK_INPUT;
524   XftUnlockFace (xftfont_info->xftfont);
525   XftFontClose (xftfont_info->display, xftfont_info->xftfont);
526   UNBLOCK_INPUT;
527 }
528 
529 static int
530 xftfont_prepare_face (f, face)
531      FRAME_PTR f;
532      struct face *face;
533 {
534   struct xftface_info *xftface_info;
535 
536 #if 0
537   /* This doesn't work if face->ascii_face doesn't use an Xft font. */
538   if (face != face->ascii_face)
539     {
540       face->extra = face->ascii_face->extra;
541       return 0;
542     }
543 #endif
544 
545   xftface_info = malloc (sizeof (struct xftface_info));
546   if (! xftface_info)
547     return -1;
548   xftfont_get_colors (f, face, face->gc, NULL,
549                       &xftface_info->xft_fg, &xftface_info->xft_bg);
550   face->extra = xftface_info;
551   return 0;
552 }
553 
554 static void
555 xftfont_done_face (f, face)
556      FRAME_PTR f;
557      struct face *face;
558 {
559   struct xftface_info *xftface_info;
560 
561 #if 0
562   /* This doesn't work if face->ascii_face doesn't use an Xft font. */
563   if (face != face->ascii_face
564       || ! face->extra)
565     return;
566 #endif
567 
568   xftface_info = (struct xftface_info *) face->extra;
569   if (xftface_info)
570     {
571       free (xftface_info);
572       face->extra = NULL;
573     }
574 }
575 
576 extern Lisp_Object Qja, Qko;
577 
578 static int
579 xftfont_has_char (font, c)
580      Lisp_Object font;
581      int c;
582 {
583   struct xftfont_info *xftfont_info;
584   struct charset *cs = NULL;
585 
586   if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
587       && charset_jisx0208 >= 0)
588     cs = CHARSET_FROM_ID (charset_jisx0208);
589   else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
590       && charset_ksc5601 >= 0)
591     cs = CHARSET_FROM_ID (charset_ksc5601);
592   if (cs)
593     return (ENCODE_CHAR (cs, c) != CHARSET_INVALID_CODE (cs));
594 
595   if (FONT_ENTITY_P (font))
596     return ftfont_driver.has_char (font, c);
597   xftfont_info = (struct xftfont_info *) XFONT_OBJECT (font);
598   return (XftCharExists (xftfont_info->display, xftfont_info->xftfont,
599                          (FcChar32) c) == FcTrue);
600 }
601 
602 static unsigned
603 xftfont_encode_char (font, c)
604      struct font *font;
605      int c;
606 {
607   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
608   unsigned code = XftCharIndex (xftfont_info->display, xftfont_info->xftfont,
609                                 (FcChar32) c);
610 
611   return (code ? code : FONT_INVALID_CODE);
612 }
613 
614 static int
615 xftfont_text_extents (font, code, nglyphs, metrics)
616      struct font *font;
617      unsigned *code;
618      int nglyphs;
619      struct font_metrics *metrics;
620 {
621   struct xftfont_info *xftfont_info = (struct xftfont_info *) font;
622   XGlyphInfo extents;
623 
624   BLOCK_INPUT;
625   XftGlyphExtents (xftfont_info->display, xftfont_info->xftfont, code, nglyphs,
626                    &extents);
627   UNBLOCK_INPUT;
628   if (metrics)
629     {
630       metrics->lbearing = - extents.x;
631       metrics->rbearing = - extents.x + extents.width;
632       metrics->width = extents.xOff;
633       metrics->ascent = extents.y;
634       metrics->descent = extents.height - extents.y;
635     }
636   return extents.xOff;
637 }
638 
639 static XftDraw *
640 xftfont_get_xft_draw (f)
641      FRAME_PTR f;
642 {
643   XftDraw *xft_draw = font_get_frame_data (f, &xftfont_driver);
644 
645   if (! xft_draw)
646     {
647       BLOCK_INPUT;
648       xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
649                                FRAME_X_WINDOW (f),
650                                FRAME_X_VISUAL (f),
651                                FRAME_X_COLORMAP (f));
652       UNBLOCK_INPUT;
653       if (! xft_draw)
654         abort ();
655       font_put_frame_data (f, &xftfont_driver, xft_draw);
656     }
657   return xft_draw;
658 }
659 
660 static int
661 xftfont_draw (s, from, to, x, y, with_background)
662      struct glyph_string *s;
663      int from, to, x, y, with_background;
664 {
665   FRAME_PTR f = s->f;
666   struct face *face = s->face;
667   struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font;
668   struct xftface_info *xftface_info = NULL;
669   XftDraw *xft_draw = xftfont_get_xft_draw (f);
670   FT_UInt *code;
671   XftColor fg, bg;
672   int len = to - from;
673   int i;
674 
675   if (s->font == face->font)
676     xftface_info = (struct xftface_info *) face->extra;
677   xftfont_get_colors (f, face, s->gc, xftface_info,
678                       &fg, with_background ? &bg : NULL);
679   BLOCK_INPUT;
680   if (s->num_clips > 0)
681     XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips);
682   else
683     XftDrawSetClip (xft_draw, NULL);
684 
685   if (with_background)
686     XftDrawRect (xft_draw, &bg,
687                  x, y - face->font->ascent, s->width, face->font->height);
688   code = alloca (sizeof (FT_UInt) * len);
689   for (i = 0; i < len; i++)
690     code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
691                | XCHAR2B_BYTE2 (s->char2b + from + i));
692 
693   if (s->padding_p)
694     for (i = 0; i < len; i++)
695       XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
696                      x + i, y, code + i, 1);
697   else
698     XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont,
699                    x, y, code, len);
700   UNBLOCK_INPUT;
701 
702   return len;
703 }
704 
705 static int
706 xftfont_end_for_frame (f)
707      FRAME_PTR f;
708 {
709   XftDraw *xft_draw;
710 
711   /* Don't do anything if display is dead */
712   if (FRAME_X_DISPLAY (f) == NULL) return 0;
713 
714   xft_draw = font_get_frame_data (f, &xftfont_driver);
715 
716   if (xft_draw)
717     {
718       BLOCK_INPUT;
719       XftDrawDestroy (xft_draw);
720       UNBLOCK_INPUT;
721       font_put_frame_data (f, &xftfont_driver, NULL);
722     }
723   return 0;
724 }
725 
726 static int
727 xftfont_cached_font_ok (f, font_object, entity)
728      struct frame *f;
729      Lisp_Object font_object;
730      Lisp_Object entity;
731 
732 {
733   struct xftfont_info *info = (struct xftfont_info *) XFONT_OBJECT (font_object);
734   FcPattern *oldpat = info->xftfont->pattern;
735   Display *display = FRAME_X_DISPLAY (f);
736   FcPattern *pat = FcPatternCreate ();
737   FcBool b1, b2;
738   int ok = 0, i1, i2, r1, r2;
739 
740   xftfont_add_rendering_parameters (pat, entity);
741   XftDefaultSubstitute (display, FRAME_X_SCREEN_NUMBER (f), pat);
742 
743   r1 = FcPatternGetBool (pat, FC_ANTIALIAS, 0, &b1);
744   r2 = FcPatternGetBool (oldpat, FC_ANTIALIAS, 0, &b2);
745   if (r1 != r2 || b1 != b2) goto out;
746   r1 = FcPatternGetBool (pat, FC_HINTING, 0, &b1);
747   r2 = FcPatternGetBool (oldpat, FC_HINTING, 0, &b2);
748   if (r1 != r2 || b1 != b2) goto out;
749   r1 = FcPatternGetBool (pat, FC_AUTOHINT, 0, &b1);
750   r2 = FcPatternGetBool (oldpat, FC_AUTOHINT, 0, &b2);
751   if (r1 != r2 || b1 != b2) goto out;
752 #ifdef FC_EMBOLDEN
753   r1 = FcPatternGetBool (pat, FC_EMBOLDEN, 0, &b1);
754   r2 = FcPatternGetBool (oldpat, FC_EMBOLDEN, 0, &b2);
755   if (r1 != r2 || b1 != b2) goto out;
756 #endif
757   r1 = FcPatternGetInteger (pat, FC_HINT_STYLE, 0, &i1);
758   r2 = FcPatternGetInteger (oldpat, FC_HINT_STYLE, 0, &i2);
759   if (r1 != r2 || i1 != i2) goto out;
760   r1 = FcPatternGetInteger (pat, FC_LCD_FILTER, 0, &i1);
761   r2 = FcPatternGetInteger (oldpat, FC_LCD_FILTER, 0, &i2);
762   if (r1 != r2 || i1 != i2) goto out;
763   r1 = FcPatternGetInteger (pat, FC_RGBA, 0, &i1);
764   r2 = FcPatternGetInteger (oldpat, FC_RGBA, 0, &i2);
765   if (r1 != r2 || i1 != i2) goto out;
766 
767   ok = 1;
768  out:
769   FcPatternDestroy (pat);
770   return ok;
771 }
772 
773 void
774 syms_of_xftfont ()
775 {
776   DEFSYM (Qxft, "xft");
777   DEFSYM (QChinting, ":hinting");
778   DEFSYM (QCautohint, ":autohint");
779   DEFSYM (QChintstyle, ":hintstyle");
780   DEFSYM (QCrgba, ":rgba");
781   DEFSYM (QCembolden, ":embolden");
782   DEFSYM (QClcdfilter, ":lcdfilter");
783 
784   xftfont_driver = ftfont_driver;
785   xftfont_driver.type = Qxft;
786   xftfont_driver.get_cache = xfont_driver.get_cache;
787   xftfont_driver.list = xftfont_list;
788   xftfont_driver.match = xftfont_match;
789   xftfont_driver.open = xftfont_open;
790   xftfont_driver.close = xftfont_close;
791   xftfont_driver.prepare_face = xftfont_prepare_face;
792   xftfont_driver.done_face = xftfont_done_face;
793   xftfont_driver.has_char = xftfont_has_char;
794   xftfont_driver.encode_char = xftfont_encode_char;
795   xftfont_driver.text_extents = xftfont_text_extents;
796   xftfont_driver.draw = xftfont_draw;
797   xftfont_driver.end_for_frame = xftfont_end_for_frame;
798   xftfont_driver.cached_font_ok = xftfont_cached_font_ok;
799 
800   register_font_driver (&xftfont_driver, NULL);
801 }
802 
803 /* arch-tag: 64ec61bf-7c8e-4fe6-b953-c6a85d5e1605
804    (do not change this comment) */