ftxfont.c 10.1 KB
Newer Older
Kenichi Handa's avatar
Kenichi Handa committed
1
/* ftxfont.c -- FreeType font driver on X (without using XFT).
2
   Copyright (C) 2006-2011 Free Software Foundation, Inc.
3
   Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
Kenichi Handa's avatar
Kenichi Handa committed
4 5 6 7 8
     National Institute of Advanced Industrial Science and Technology (AIST)
     Registration Number H13PRO009

This file is part of GNU Emacs.

9
GNU Emacs is free software: you can redistribute it and/or modify
Kenichi Handa's avatar
Kenichi Handa committed
10
it under the terms of the GNU General Public License as published by
11 12
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Kenichi Handa's avatar
Kenichi Handa committed
13 14 15 16 17 18 19

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
20
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Kenichi Handa's avatar
Kenichi Handa committed
21 22 23

#include <config.h>
#include <stdio.h>
24
#include <setjmp.h>
Kenichi Handa's avatar
Kenichi Handa committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
#include <X11/Xlib.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"

/* FTX font driver.  */

static Lisp_Object Qftx;

41 42 43 44 45
#if defined HAVE_XFT || !defined HAVE_FREETYPE
static
#endif
struct font_driver ftxfont_driver;

Kenichi Handa's avatar
Kenichi Handa committed
46
/* Prototypes for helper function.  */
47 48 49 50 51 52
static GC *ftxfont_get_gcs (FRAME_PTR, unsigned long, unsigned long);
static int ftxfont_draw_bitmap (FRAME_PTR, GC, GC *, struct font *,
                                unsigned, int, int, XPoint *, int, int *,
                                int);
static void ftxfont_draw_backgrond (FRAME_PTR, struct font *, GC,
                                    int, int, int);
53

54 55 56 57 58 59 60 61 62 63
struct ftxfont_frame_data
{
  /* Background and foreground colors.  */
  XColor colors[2];
  /* GCs interporationg the above colors.  gcs[0] is for a color
   closest to BACKGROUND, and gcs[5] is for a color closest to
   FOREGROUND.  */
  GC gcs[6];
  struct ftxfont_frame_data *next;
};
64

65 66 67 68

/* Return an array of 6 GCs for antialiasing.  */

static GC *
69
ftxfont_get_gcs (FRAME_PTR f, long unsigned int foreground, long unsigned int background)
70
{
71
  XColor color;
72 73
  XGCValues xgcv;
  int i;
74 75
  struct ftxfont_frame_data *data = font_get_frame_data (f, &ftxfont_driver);
  struct ftxfont_frame_data *prev = NULL, *this = NULL, *new;
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
  if (data)
    {
      for (this = data; this; prev = this, this = this->next)
	{
	  if (this->colors[0].pixel < background)
	    continue;
	  if (this->colors[0].pixel > background)
	    break;
	  if (this->colors[1].pixel < foreground)
	    continue;
	  if (this->colors[1].pixel > foreground)
	    break;
	  return this->gcs;
	}
    }

  new = malloc (sizeof (struct ftxfont_frame_data));
  if (! new)
    return NULL;
  new->next = this;
  if (prev)
    {
      prev->next = new;
    }
  else if (font_put_frame_data (f, &ftxfont_driver, new) < 0)
    {
      free (new);
      return NULL;
    }

  new->colors[0].pixel = background;
  new->colors[1].pixel = foreground;
109 110

  BLOCK_INPUT;
111
  XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), new->colors, 2);
112 113
  for (i = 1; i < 7; i++)
    {
114 115 116 117 118 119 120 121
      /* Interpolate colors linearly.  Any better algorithm?  */
      color.red
	= (new->colors[1].red * i + new->colors[0].red * (8 - i)) / 8;
      color.green
	= (new->colors[1].green * i + new->colors[0].green * (8 - i)) / 8;
      color.blue
	= (new->colors[1].blue * i + new->colors[0].blue * (8 - i)) / 8;
      if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &color))
122
	break;
123 124 125
      xgcv.foreground = color.pixel;
      new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
				   GCForeground, &xgcv);
126 127 128 129 130 131 132
    }
  UNBLOCK_INPUT;

  if (i < 7)
    {
      BLOCK_INPUT;
      for (i--; i >= 0; i--)
133
	XFreeGC (FRAME_X_DISPLAY (f), new->gcs[i]);
134
      UNBLOCK_INPUT;
135 136 137 138 139 140
      if (prev)
	prev->next = new->next;
      else if (data)
	font_put_frame_data (f, &ftxfont_driver, new->next);
      free (new);
      return NULL;
141
    }
142
  return new->gcs;
143
}
Kenichi Handa's avatar
Kenichi Handa committed
144 145

static int
146
ftxfont_draw_bitmap (FRAME_PTR f, GC gc_fore, GC *gcs, struct font *font, unsigned int code, int x, int y, XPoint *p, int size, int *n, int flush)
Kenichi Handa's avatar
Kenichi Handa committed
147 148 149 150 151
{
  struct font_bitmap bitmap;
  unsigned char *b;
  int i, j;

152
  if (ftfont_driver.get_bitmap (font, code, &bitmap, size > 0x100 ? 1 : 8) < 0)
Kenichi Handa's avatar
Kenichi Handa committed
153
    return 0;
154
  if (size > 0x100)
Kenichi Handa's avatar
Kenichi Handa committed
155
    {
156 157
      for (i = 0, b = bitmap.buffer; i < bitmap.rows;
	   i++, b += bitmap.pitch)
Kenichi Handa's avatar
Kenichi Handa committed
158 159 160 161 162 163
	{
	  for (j = 0; j < bitmap.width; j++)
	    if (b[j / 8] & (1 << (7 - (j % 8))))
	      {
		p[n[0]].x = x + bitmap.left + j;
		p[n[0]].y = y - bitmap.top + i;
164
		if (++n[0] == size)
Kenichi Handa's avatar
Kenichi Handa committed
165 166
		  {
		    XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
167
				 gc_fore, p, size, CoordModeOrigin);
Kenichi Handa's avatar
Kenichi Handa committed
168 169 170 171
		    n[0] = 0;
		  }
	      }
	}
172 173 174 175 176 177 178 179
      if (flush && n[0] > 0)
	XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
		     gc_fore, p, n[0], CoordModeOrigin);
    }
  else
    {
      for (i = 0, b = bitmap.buffer; i < bitmap.rows;
	   i++, b += bitmap.pitch)
Kenichi Handa's avatar
Kenichi Handa committed
180 181 182
	{
	  for (j = 0; j < bitmap.width; j++)
	    {
183 184 185
	      int idx = (bitmap.bits_per_pixel == 1
			 ? ((b[j / 8] & (1 << (7 - (j % 8)))) ? 6 : -1)
			 : (b[j] >> 5) - 1);
Kenichi Handa's avatar
Kenichi Handa committed
186 187 188 189 190 191 192

	      if (idx >= 0)
		{
		  XPoint *pp = p + size * idx;

		  pp[n[idx]].x = x + bitmap.left + j;
		  pp[n[idx]].y = y - bitmap.top + i;
193
		  if (++(n[idx]) == size)
Kenichi Handa's avatar
Kenichi Handa committed
194 195
		    {
		      XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
196 197
				   idx == 6 ? gc_fore : gcs[idx], pp, size,
				   CoordModeOrigin);
Kenichi Handa's avatar
Kenichi Handa committed
198 199 200 201 202
		      n[idx] = 0;
		    }
		}
	    }
	}
203 204 205 206 207 208 209 210 211 212
      if (flush)
	{
	  for (i = 0; i < 6; i++)
	    if (n[i] > 0)
	      XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
			   gcs[i], p + 0x100 * i, n[i], CoordModeOrigin);
	  if (n[6] > 0)
	    XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
			 gc_fore, p + 0x600, n[6], CoordModeOrigin);
	}
Kenichi Handa's avatar
Kenichi Handa committed
213 214 215 216 217 218 219 220 221
    }

  if (ftfont_driver.free_bitmap)
    ftfont_driver.free_bitmap (font, &bitmap);

  return bitmap.advance;
}

static void
222
ftxfont_draw_backgrond (FRAME_PTR f, struct font *font, GC gc, int x, int y, int width)
Kenichi Handa's avatar
Kenichi Handa committed
223 224 225 226 227 228 229
{
  XGCValues xgcv;

  XGetGCValues (FRAME_X_DISPLAY (f), gc,
		GCForeground | GCBackground, &xgcv);
  XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background);
  XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
230
		  x, y - FONT_BASE (font), width, FONT_HEIGHT (font));
Kenichi Handa's avatar
Kenichi Handa committed
231 232 233 234
  XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground);
}

/* Prototypes for font-driver methods.  */
235 236 237 238 239
static Lisp_Object ftxfont_list (Lisp_Object, Lisp_Object);
static Lisp_Object ftxfont_match (Lisp_Object, Lisp_Object);
static Lisp_Object ftxfont_open (FRAME_PTR, Lisp_Object, int);
static void ftxfont_close (FRAME_PTR, struct font *);
static int ftxfont_draw (struct glyph_string *, int, int, int, int, int);
Kenichi Handa's avatar
Kenichi Handa committed
240 241

static Lisp_Object
242
ftxfont_list (Lisp_Object frame, Lisp_Object spec)
Kenichi Handa's avatar
Kenichi Handa committed
243
{
244
  Lisp_Object list = ftfont_driver.list (frame, spec), tail;
245

246 247 248
  for (tail = list; CONSP (tail); tail = XCDR (tail))
    ASET (XCAR (tail), FONT_TYPE_INDEX, Qftx);
  return list;
Kenichi Handa's avatar
Kenichi Handa committed
249 250
}

Kenichi Handa's avatar
Kenichi Handa committed
251
static Lisp_Object
252
ftxfont_match (Lisp_Object frame, Lisp_Object spec)
Kenichi Handa's avatar
Kenichi Handa committed
253 254 255 256 257 258 259 260
{
  Lisp_Object entity = ftfont_driver.match (frame, spec);

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

261
static Lisp_Object
262
ftxfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
Kenichi Handa's avatar
Kenichi Handa committed
263
{
264
  Lisp_Object font_object;
Kenichi Handa's avatar
Kenichi Handa committed
265 266
  struct font *font;

267 268 269 270 271 272
  font_object = ftfont_driver.open (f, entity, pixel_size);
  if (NILP (font_object))
    return Qnil;
  font = XFONT_OBJECT (font_object);
  font->driver = &ftxfont_driver;
  return font_object;
Kenichi Handa's avatar
Kenichi Handa committed
273 274 275
}

static void
276
ftxfont_close (FRAME_PTR f, struct font *font)
Kenichi Handa's avatar
Kenichi Handa committed
277 278 279 280 281
{
  ftfont_driver.close (f, font);
}

static int
282
ftxfont_draw (struct glyph_string *s, int from, int to, int x, int y, int with_background)
Kenichi Handa's avatar
Kenichi Handa committed
283 284 285
{
  FRAME_PTR f = s->f;
  struct face *face = s->face;
286
  struct font *font = s->font;
Kenichi Handa's avatar
Kenichi Handa committed
287 288 289 290 291
  XPoint p[0x700];
  int n[7];
  unsigned *code;
  int len = to - from;
  int i;
292
  GC *gcs;
293
  int xadvance;
Kenichi Handa's avatar
Kenichi Handa committed
294 295 296 297 298 299 300 301 302 303 304

  n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = 0;

  BLOCK_INPUT;
  if (with_background)
    ftxfont_draw_backgrond (f, font, s->gc, x, y, s->width);
  code = alloca (sizeof (unsigned) * len);
  for (i = 0; i < len; i++)
    code[i] = ((XCHAR2B_BYTE1 (s->char2b + from + i) << 8)
	       | XCHAR2B_BYTE2 (s->char2b + from + i));

305 306 307 308 309
  if (face->gc == s->gc)
    {
      gcs = ftxfont_get_gcs (f, face->foreground, face->background);
    }
  else
Kenichi Handa's avatar
Kenichi Handa committed
310
    {
311 312 313 314
      XGCValues xgcv;
      unsigned long mask = GCForeground | GCBackground;

      XGetGCValues (FRAME_X_DISPLAY (f), s->gc, mask, &xgcv);
315
      gcs = ftxfont_get_gcs (f, xgcv.foreground, xgcv.background);
316 317
    }

318
  if (gcs)
319
    {
320 321 322 323 324
      if (s->num_clips)
	for (i = 0; i < 6; i++)
	  XSetClipRectangles (FRAME_X_DISPLAY (f), gcs[i], 0, 0,
			      s->clip, s->num_clips, Unsorted);

Kenichi Handa's avatar
Kenichi Handa committed
325
      for (i = 0; i < len; i++)
326 327 328 329 330
	{
	  xadvance = ftxfont_draw_bitmap (f, s->gc, gcs, font, code[i], x, y,
					  p, 0x100, n, i + 1 == len);
	  x += (s->padding_p ? 1 : xadvance);
	}
331 332 333
      if (s->num_clips)
	for (i = 0; i < 6; i++)
	  XSetClipMask (FRAME_X_DISPLAY (f), gcs[i], None);
Kenichi Handa's avatar
Kenichi Handa committed
334 335 336
    }
  else
    {
337 338
      /* We can't draw with antialiasing.
	 s->gc should already have a proper clipping setting. */
Kenichi Handa's avatar
Kenichi Handa committed
339
      for (i = 0; i < len; i++)
340 341 342 343 344
	{
	  xadvance = ftxfont_draw_bitmap (f, s->gc, NULL, font, code[i], x, y,
					  p, 0x700, n, i + 1 == len);
	  x += (s->padding_p ? 1 : xadvance);
	}
Kenichi Handa's avatar
Kenichi Handa committed
345 346 347 348 349 350 351
    }

  UNBLOCK_INPUT;

  return len;
}

352
static int
353
ftxfont_end_for_frame (FRAME_PTR f)
354 355
{
  struct ftxfont_frame_data *data = font_get_frame_data (f, &ftxfont_driver);
356

357 358 359 360 361
  BLOCK_INPUT;
  while (data)
    {
      struct ftxfont_frame_data *next = data->next;
      int i;
362

363
      for (i = 0; i < 6; i++)
364 365 366 367 368
	XFreeGC (FRAME_X_DISPLAY (f), data->gcs[i]);
      free (data);
      data = next;
    }
  UNBLOCK_INPUT;
369
  font_put_frame_data (f, &ftxfont_driver, NULL);
370 371 372
  return 0;
}

Kenichi Handa's avatar
Kenichi Handa committed
373 374 375


void
376
syms_of_ftxfont (void)
Kenichi Handa's avatar
Kenichi Handa committed
377 378 379 380 381 382
{
  DEFSYM (Qftx, "ftx");

  ftxfont_driver = ftfont_driver;
  ftxfont_driver.type = Qftx;
  ftxfont_driver.list = ftxfont_list;
Kenichi Handa's avatar
Kenichi Handa committed
383
  ftxfont_driver.match = ftxfont_match;
Kenichi Handa's avatar
Kenichi Handa committed
384 385 386
  ftxfont_driver.open = ftxfont_open;
  ftxfont_driver.close = ftxfont_close;
  ftxfont_driver.draw = ftxfont_draw;
387
  ftxfont_driver.end_for_frame = ftxfont_end_for_frame;
Kenichi Handa's avatar
Kenichi Handa committed
388 389
  register_font_driver (&ftxfont_driver, NULL);
}