ftxfont.c 9.42 KB
Newer Older
Kenichi Handa's avatar
Kenichi Handa committed
1
/* ftxfont.c -- FreeType font driver on X (without using XFT).
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 2006-2019 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 <https://www.gnu.org/licenses/>.  */
Kenichi Handa's avatar
Kenichi Handa committed
21 22 23 24 25 26 27 28 29 30

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

#include "lisp.h"
#include "xterm.h"
#include "frame.h"
#include "blockinput.h"
#include "font.h"
Daniel Colascione's avatar
Daniel Colascione committed
31
#include "pdumper.h"
Kenichi Handa's avatar
Kenichi Handa committed
32 33 34

/* FTX font driver.  */

35 36 37 38
struct ftxfont_frame_data
{
  /* Background and foreground colors.  */
  XColor colors[2];
Paul Eggert's avatar
Paul Eggert committed
39
  /* GCs interpolating the above colors.  gcs[0] is for a color
40 41 42 43 44
   closest to BACKGROUND, and gcs[5] is for a color closest to
   FOREGROUND.  */
  GC gcs[6];
  struct ftxfont_frame_data *next;
};
45

46 47 48 49

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

static GC *
50
ftxfont_get_gcs (struct frame *f, unsigned long foreground, unsigned long background)
51
{
52
  XColor color;
53 54
  XGCValues xgcv;
  int i;
55
  struct ftxfont_frame_data *data = font_get_frame_data (f, Qftx);
56
  struct ftxfont_frame_data *prev = NULL, *this = NULL, *new;
57

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
  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;
	}
    }

74
  new = xmalloc (sizeof *new);
75 76 77
  new->next = this;
  if (prev)
      prev->next = new;
78
  font_put_frame_data (f, Qftx, new);
79 80 81

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

83
  block_input ();
84
  XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), new->colors, 2);
85 86
  for (i = 1; i < 7; i++)
    {
87 88 89 90 91 92 93 94
      /* 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))
95
	break;
96
      xgcv.foreground = color.pixel;
97
      new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
98
				   GCForeground, &xgcv);
99
    }
100
  unblock_input ();
101 102 103

  if (i < 7)
    {
104
      block_input ();
105
      for (i--; i >= 0; i--)
106
	XFreeGC (FRAME_X_DISPLAY (f), new->gcs[i]);
107
      unblock_input ();
108 109 110
      if (prev)
	prev->next = new->next;
      else if (data)
111 112
	font_put_frame_data (f, Qftx, new->next);
      xfree (new);
113
      return NULL;
114
    }
115
  return new->gcs;
116
}
Kenichi Handa's avatar
Kenichi Handa committed
117 118

static int
Dmitry Antipov's avatar
Dmitry Antipov committed
119
ftxfont_draw_bitmap (struct frame *f, GC gc_fore, GC *gcs, struct font *font,
120 121
                     unsigned int code, int x, int y, XPoint *p, int size,
                     int *n, bool flush)
Kenichi Handa's avatar
Kenichi Handa committed
122 123 124 125 126
{
  struct font_bitmap bitmap;
  unsigned char *b;
  int i, j;

127
  if (ftfont_get_bitmap (font, code, &bitmap, size > 0x100 ? 1 : 8) < 0)
Kenichi Handa's avatar
Kenichi Handa committed
128
    return 0;
129
  if (size > 0x100)
Kenichi Handa's avatar
Kenichi Handa committed
130
    {
131 132
      for (i = 0, b = bitmap.buffer; i < bitmap.rows;
	   i++, b += bitmap.pitch)
Kenichi Handa's avatar
Kenichi Handa committed
133 134 135 136 137 138
	{
	  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;
139
		if (++n[0] == size)
Kenichi Handa's avatar
Kenichi Handa committed
140
		  {
141
                    XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
142
				 gc_fore, p, size, CoordModeOrigin);
Kenichi Handa's avatar
Kenichi Handa committed
143 144 145 146
		    n[0] = 0;
		  }
	      }
	}
147
      if (flush && n[0] > 0)
148
        XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
149 150 151 152 153 154
		     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
155 156 157
	{
	  for (j = 0; j < bitmap.width; j++)
	    {
158 159 160
	      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
161 162 163 164 165 166 167

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

		  pp[n[idx]].x = x + bitmap.left + j;
		  pp[n[idx]].y = y - bitmap.top + i;
168
		  if (++(n[idx]) == size)
Kenichi Handa's avatar
Kenichi Handa committed
169
		    {
170
                      XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
171 172
				   idx == 6 ? gc_fore : gcs[idx], pp, size,
				   CoordModeOrigin);
Kenichi Handa's avatar
Kenichi Handa committed
173 174 175 176 177
		      n[idx] = 0;
		    }
		}
	    }
	}
178 179 180 181
      if (flush)
	{
	  for (i = 0; i < 6; i++)
	    if (n[i] > 0)
182
              XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
183 184
			   gcs[i], p + 0x100 * i, n[i], CoordModeOrigin);
	  if (n[6] > 0)
185
            XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
186 187
			 gc_fore, p + 0x600, n[6], CoordModeOrigin);
	}
Kenichi Handa's avatar
Kenichi Handa committed
188 189
    }

190
  /* There is no ftfont_free_bitmap, so do not try to free BITMAP.  */
Kenichi Handa's avatar
Kenichi Handa committed
191 192 193 194 195

  return bitmap.advance;
}

static void
Dmitry Antipov's avatar
Dmitry Antipov committed
196
ftxfont_draw_background (struct frame *f, struct font *font, GC gc, int x, int y,
Paul Eggert's avatar
Paul Eggert committed
197
			 int width)
Kenichi Handa's avatar
Kenichi Handa committed
198 199 200 201 202 203
{
  XGCValues xgcv;

  XGetGCValues (FRAME_X_DISPLAY (f), gc,
		GCForeground | GCBackground, &xgcv);
  XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background);
204
  XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), gc,
205
		  x, y - FONT_BASE (font), width, FONT_HEIGHT (font));
Kenichi Handa's avatar
Kenichi Handa committed
206 207 208 209
  XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground);
}

static Lisp_Object
210
ftxfont_list (struct frame *f, Lisp_Object spec)
Kenichi Handa's avatar
Kenichi Handa committed
211
{
212
  return ftfont_list2 (f, spec, Qftx);
Kenichi Handa's avatar
Kenichi Handa committed
213 214
}

Kenichi Handa's avatar
Kenichi Handa committed
215
static Lisp_Object
216
ftxfont_match (struct frame *f, Lisp_Object spec)
Kenichi Handa's avatar
Kenichi Handa committed
217
{
218
  return ftfont_match2 (f, spec, Qftx);
Kenichi Handa's avatar
Kenichi Handa committed
219 220
}

221
static Lisp_Object
Dmitry Antipov's avatar
Dmitry Antipov committed
222
ftxfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
Kenichi Handa's avatar
Kenichi Handa committed
223
{
224
  Lisp_Object font_object = ftfont_open (f, entity, pixel_size);
225 226
  if (NILP (font_object))
    return Qnil;
227
  struct font *font = XFONT_OBJECT (font_object);
228 229
  font->driver = &ftxfont_driver;
  return font_object;
Kenichi Handa's avatar
Kenichi Handa committed
230 231 232
}

static void
233
ftxfont_close (struct font *font)
Kenichi Handa's avatar
Kenichi Handa committed
234
{
235
  ftfont_close (font);
Kenichi Handa's avatar
Kenichi Handa committed
236 237 238
}

static int
239 240
ftxfont_draw (struct glyph_string *s, int from, int to, int x, int y,
              bool with_background)
Kenichi Handa's avatar
Kenichi Handa committed
241
{
Dmitry Antipov's avatar
Dmitry Antipov committed
242
  struct frame *f = s->f;
Kenichi Handa's avatar
Kenichi Handa committed
243
  struct face *face = s->face;
244
  struct font *font = s->font;
Kenichi Handa's avatar
Kenichi Handa committed
245 246
  XPoint p[0x700];
  int n[7];
247
  unsigned *code = s->char2b + from;
Kenichi Handa's avatar
Kenichi Handa committed
248 249
  int len = to - from;
  int i;
250
  GC *gcs;
251
  int xadvance;
Kenichi Handa's avatar
Kenichi Handa committed
252 253 254

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

255
  block_input ();
Kenichi Handa's avatar
Kenichi Handa committed
256
  if (with_background)
Paul Eggert's avatar
Paul Eggert committed
257
    ftxfont_draw_background (f, font, s->gc, x, y, s->width);
Kenichi Handa's avatar
Kenichi Handa committed
258

259 260 261 262 263
  if (face->gc == s->gc)
    {
      gcs = ftxfont_get_gcs (f, face->foreground, face->background);
    }
  else
Kenichi Handa's avatar
Kenichi Handa committed
264
    {
265 266 267 268
      XGCValues xgcv;
      unsigned long mask = GCForeground | GCBackground;

      XGetGCValues (FRAME_X_DISPLAY (f), s->gc, mask, &xgcv);
269
      gcs = ftxfont_get_gcs (f, xgcv.foreground, xgcv.background);
270 271
    }

272
  if (gcs)
273
    {
274 275 276 277 278
      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
279
      for (i = 0; i < len; i++)
280 281 282 283 284
	{
	  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);
	}
285 286 287
      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
288 289 290
    }
  else
    {
291 292
      /* We can't draw with antialiasing.
	 s->gc should already have a proper clipping setting. */
Kenichi Handa's avatar
Kenichi Handa committed
293
      for (i = 0; i < len; i++)
294 295 296 297 298
	{
	  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
299 300
    }

301
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
302 303 304 305

  return len;
}

306
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
307
ftxfont_end_for_frame (struct frame *f)
308
{
309
  struct ftxfont_frame_data *data = font_get_frame_data (f, Qftx);
310

311
  block_input ();
312 313 314 315
  while (data)
    {
      struct ftxfont_frame_data *next = data->next;
      int i;
316

317
      for (i = 0; i < 6; i++)
318
	XFreeGC (FRAME_X_DISPLAY (f), data->gcs[i]);
319
      xfree (data);
320 321
      data = next;
    }
322
  unblock_input ();
323
  font_put_frame_data (f, Qftx, NULL);
324 325 326
  return 0;
}

Kenichi Handa's avatar
Kenichi Handa committed
327 328


Daniel Colascione's avatar
Daniel Colascione committed
329 330
static void syms_of_ftxfont_for_pdumper (void);

331 332 333
struct font_driver const ftxfont_driver =
  {
  /* We can't draw a text without device dependent functions.  */
Paul Eggert's avatar
Paul Eggert committed
334 335 336 337 338 339 340 341 342 343 344 345 346
  .type = LISPSYM_INITIALLY (Qftx),
  .get_cache = ftfont_get_cache,
  .list = ftxfont_list,
  .match = ftxfont_match,
  .list_family = ftfont_list_family,
  .open = ftxfont_open,
  .close = ftxfont_close,
  .has_char = ftfont_has_char,
  .encode_char = ftfont_encode_char,
  .text_extents = ftfont_text_extents,
  .draw = ftxfont_draw,
  .get_bitmap = ftfont_get_bitmap,
  .anchor_point = ftfont_anchor_point,
347
#ifdef HAVE_LIBOTF
Paul Eggert's avatar
Paul Eggert committed
348
  .otf_capability = ftfont_otf_capability,
349
#endif
Paul Eggert's avatar
Paul Eggert committed
350
  .end_for_frame = ftxfont_end_for_frame,
351
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
Paul Eggert's avatar
Paul Eggert committed
352
  .shape = ftfont_shape,
353
#endif
354
#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
Paul Eggert's avatar
Paul Eggert committed
355
  .get_variation_glyphs = ftfont_variation_glyphs,
356
#endif
Paul Eggert's avatar
Paul Eggert committed
357 358
  .filter_properties = ftfont_filter_properties,
  .combining_capability = ftfont_combining_capability,
359 360
  };

Kenichi Handa's avatar
Kenichi Handa committed
361
void
362
syms_of_ftxfont (void)
Kenichi Handa's avatar
Kenichi Handa committed
363 364
{
  DEFSYM (Qftx, "ftx");
Daniel Colascione's avatar
Daniel Colascione committed
365 366 367 368 369 370
  pdumper_do_now_and_after_load (syms_of_ftxfont_for_pdumper);
}

static void
syms_of_ftxfont_for_pdumper (void)
{
Kenichi Handa's avatar
Kenichi Handa committed
371 372
  register_font_driver (&ftxfont_driver, NULL);
}