xfont.c 30.5 KB
Newer Older
Kenichi Handa's avatar
Kenichi Handa committed
1
/* xfont.c -- X core font driver.
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

#include <config.h>
#include <stdio.h>
Paul Eggert's avatar
Paul Eggert committed
24
#include <stdlib.h>
Kenichi Handa's avatar
Kenichi Handa committed
25 26 27 28 29 30 31 32 33 34 35 36 37
#include <X11/Xlib.h>

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


/* X core font driver.  */

38 39 40 41 42
struct xfont_info
{
  struct font font;
  Display *display;
  XFontStruct *xfont;
43
  unsigned x_display_id;
44 45
};

Kenichi Handa's avatar
Kenichi Handa committed
46 47
/* Prototypes of support functions.  */

48
static XCharStruct *xfont_get_pcm (XFontStruct *, XChar2b *);
Kenichi Handa's avatar
Kenichi Handa committed
49 50 51 52 53

/* Get metrics of character CHAR2B in XFONT.  Value is null if CHAR2B
   is not contained in the font.  */

static XCharStruct *
54
xfont_get_pcm (XFontStruct *xfont, XChar2b *char2b)
Kenichi Handa's avatar
Kenichi Handa committed
55 56 57 58
{
  /* The result metric information.  */
  XCharStruct *pcm = NULL;

59
  eassert (xfont && char2b);
Kenichi Handa's avatar
Kenichi Handa committed
60 61 62 63 64 65 66 67 68 69 70 71 72 73 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

  if (xfont->per_char != NULL)
    {
      if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
	{
	  /* min_char_or_byte2 specifies the linear character index
	     corresponding to the first element of the per_char array,
	     max_char_or_byte2 is the index of the last character.  A
	     character with non-zero CHAR2B->byte1 is not in the font.
	     A character with byte2 less than min_char_or_byte2 or
	     greater max_char_or_byte2 is not in the font.  */
	  if (char2b->byte1 == 0
	      && char2b->byte2 >= xfont->min_char_or_byte2
	      && char2b->byte2 <= xfont->max_char_or_byte2)
	    pcm = xfont->per_char + char2b->byte2 - xfont->min_char_or_byte2;
	}
      else
	{
	  /* If either min_byte1 or max_byte1 are nonzero, both
	     min_char_or_byte2 and max_char_or_byte2 are less than
	     256, and the 2-byte character index values corresponding
	     to the per_char array element N (counting from 0) are:

	     byte1 = N/D + min_byte1
	     byte2 = N\D + min_char_or_byte2

	     where:

	     D = max_char_or_byte2 - min_char_or_byte2 + 1
	     / = integer division
	     \ = integer modulus  */
	  if (char2b->byte1 >= xfont->min_byte1
	      && char2b->byte1 <= xfont->max_byte1
	      && char2b->byte2 >= xfont->min_char_or_byte2
	      && char2b->byte2 <= xfont->max_char_or_byte2)
	    pcm = (xfont->per_char
		   + ((xfont->max_char_or_byte2 - xfont->min_char_or_byte2 + 1)
		      * (char2b->byte1 - xfont->min_byte1))
		   + (char2b->byte2 - xfont->min_char_or_byte2));
	}
    }
  else
    {
      /* If the per_char pointer is null, all glyphs between the first
	 and last character indexes inclusive have the same
	 information, as given by both min_bounds and max_bounds.  */
      if (char2b->byte2 >= xfont->min_char_or_byte2
	  && char2b->byte2 <= xfont->max_char_or_byte2)
	pcm = &xfont->max_bounds;
    }

  return ((pcm == NULL
	   || (pcm->width == 0 && (pcm->rbearing - pcm->lbearing) == 0))
	  ? NULL : pcm);
}

116
Lisp_Object
Dmitry Antipov's avatar
Dmitry Antipov committed
117
xfont_get_cache (struct frame *f)
Kenichi Handa's avatar
Kenichi Handa committed
118
{
119
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
Kenichi Handa's avatar
Kenichi Handa committed
120 121 122 123

  return (dpyinfo->name_list_element);
}

124 125 126
static int
compare_font_names (const void *name1, const void *name2)
{
127 128 129
  char *const *n1 = name1;
  char *const *n2 = name2;
  return xstrcasecmp (*n1, *n2);
130 131
}

132 133 134 135 136
/* Decode XLFD as iso-8859-1 into OUTPUT, and return the byte length
   of the decoding result.  LEN is the byte length of XLFD, or -1 if
   XLFD is NULL terminated.  The caller must assure that OUTPUT is at
   least twice (plus 1) as large as XLFD.  */

137
static ptrdiff_t
138 139 140 141
xfont_decode_coding_xlfd (char *xlfd, int len, char *output)
{
  char *p0 = xlfd, *p1 = output;
  int c;
142

143 144 145
  while (*p0)
    {
      c = *(unsigned char *) p0++;
146
      p1 += CHAR_STRING (c, (unsigned char *) p1);
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
      if (--len == 0)
	break;
    }
  *p1 = 0;
  return (p1 - output);
}

/* Encode XLFD from UTF-8 to iso-8859-1 destructively, and return the
   resulting byte length.  If XLFD contains unencodable character,
   return -1.  */

static int
xfont_encode_coding_xlfd (char *xlfd)
{
  const unsigned char *p0 = (unsigned char *) xlfd;
  unsigned char *p1 = (unsigned char *) xlfd;
  int len = 0;
164

165 166 167 168 169 170 171 172 173 174 175 176 177
  while (*p0)
    {
      int c = STRING_CHAR_ADVANCE (p0);

      if (c >= 0x100)
	return -1;
      *p1++ = c;
      len++;
    }
  *p1 = 0;
  return len;
}

178 179 180
/* Check if CHARS (cons or vector) is supported by XFONT whose
   encoding charset is ENCODING (XFONT is NULL) or by a font whose
   registry corresponds to ENCODING and REPERTORY.
181
   Return true if supported.  */
182

183
static bool
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
xfont_chars_supported (Lisp_Object chars, XFontStruct *xfont,
		       struct charset *encoding, struct charset *repertory)
{
  struct charset *charset = repertory ? repertory : encoding;

  if (CONSP (chars))
    {
      for (; CONSP (chars); chars = XCDR (chars))
	{
	  int c = XINT (XCAR (chars));
	  unsigned code = ENCODE_CHAR (charset, c);
	  XChar2b char2b;

	  if (code == CHARSET_INVALID_CODE (charset))
	    break;
	  if (! xfont)
	    continue;
	  if (code >= 0x10000)
	    break;
	  char2b.byte1 = code >> 8;
	  char2b.byte2 = code & 0xFF;
	  if (! xfont_get_pcm (xfont, &char2b))
	    break;
	}
      return (NILP (chars));
    }
  else if (VECTORP (chars))
    {
212
      ptrdiff_t i;
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232

      for (i = ASIZE (chars) - 1; i >= 0; i--)
	{
	  int c = XINT (AREF (chars, i));
	  unsigned code = ENCODE_CHAR (charset, c);
	  XChar2b char2b;

	  if (code == CHARSET_INVALID_CODE (charset))
	    continue;
	  if (! xfont)
	    break;
	  if (code >= 0x10000)
	    continue;
	  char2b.byte1 = code >> 8;
	  char2b.byte2 = code & 0xFF;
	  if (xfont_get_pcm (xfont, &char2b))
	    break;
	}
      return (i >= 0);
    }
233
  return false;
234 235
}

Juanma Barranquero's avatar
Juanma Barranquero committed
236 237
/* A hash table recoding which font supports which scripts.  Each key
   is a vector of characteristic font properties FOUNDRY to WIDTH and
238 239 240 241 242 243 244
   ADDSTYLE, and each value is a list of script symbols.

   We assume that fonts that have the same value in the above
   properties supports the same set of characters on all displays.  */

static Lisp_Object xfont_scripts_cache;

Juanma Barranquero's avatar
Juanma Barranquero committed
245
/* Re-usable vector to store characteristic font properties.   */
246 247 248 249 250
static Lisp_Object xfont_scratch_props;

/* Return a list of scripts supported by the font of FONTNAME whose
   characteristic properties are in PROPS and whose encoding charset
   is ENCODING.  A caller must call BLOCK_INPUT in advance.  */
Kenichi Handa's avatar
Kenichi Handa committed
251 252

static Lisp_Object
253 254 255 256 257 258 259
xfont_supported_scripts (Display *display, char *fontname, Lisp_Object props,
			 struct charset *encoding)
{
  Lisp_Object scripts;

  /* Two special cases to avoid opening rather big fonts.  */
  if (EQ (AREF (props, 2), Qja))
260
    return list2 (intern ("kana"), intern ("han"));
261
  if (EQ (AREF (props, 2), Qko))
262
    return list1 (intern ("hangul"));
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
  scripts = Fgethash (props, xfont_scripts_cache, Qt);
  if (EQ (scripts, Qt))
    {
      XFontStruct *xfont;
      Lisp_Object val;

      scripts = Qnil;
      xfont = XLoadQueryFont (display, fontname);
      if (xfont)
	{
	  if (xfont->per_char)
	    {
	      for (val = Vscript_representative_chars; CONSP (val);
		   val = XCDR (val))
		if (CONSP (XCAR (val)) && SYMBOLP (XCAR (XCAR (val))))
		  {
		    Lisp_Object script = XCAR (XCAR (val));
		    Lisp_Object chars = XCDR (XCAR (val));

		    if (xfont_chars_supported (chars, xfont, encoding, NULL))
		      scripts = Fcons (script, scripts);
		  }
	    }
	  XFreeFont (display, xfont);
	}
      if (EQ (AREF (props, 3), Qiso10646_1)
	  && NILP (Fmemq (Qlatin, scripts)))
	scripts = Fcons (Qlatin, scripts);
      Fputhash (Fcopy_sequence (props), scripts, xfont_scripts_cache);
    }
  return scripts;
}

static Lisp_Object
297
xfont_list_pattern (Display *display, const char *pattern,
298
		    Lisp_Object registry, Lisp_Object script)
Kenichi Handa's avatar
Kenichi Handa committed
299
{
300
  Lisp_Object list = Qnil;
301 302
  Lisp_Object chars = Qnil;
  struct charset *encoding, *repertory = NULL;
303 304
  int i, limit, num_fonts;
  char **names;
305 306
  /* Large enough to decode the longest XLFD (255 bytes). */
  char buf[512];
Kenichi Handa's avatar
Kenichi Handa committed
307

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
  if (! NILP (registry)
      && font_registry_charsets (registry, &encoding, &repertory) < 0)
    /* Unknown REGISTRY, not supported.  */
    return Qnil;
  if (! NILP (script))
    {
      chars = assq_no_quit (script, Vscript_representative_chars);
      if (NILP (chars))
	/* We can't tell whether or not a font supports SCRIPT.  */
	return Qnil;
      chars = XCDR (chars);
      if (repertory)
	{
	  if (! xfont_chars_supported (chars, NULL, encoding, repertory))
	    return Qnil;
	  script = Qnil;
	}
    }
326

327
  block_input ();
328
  x_catch_errors (display);
Kenichi Handa's avatar
Kenichi Handa committed
329

330
  for (limit = 512; ; limit *= 2)
Kenichi Handa's avatar
Kenichi Handa committed
331
    {
332 333
      names = XListFonts (display, pattern, limit, &num_fonts);
      if (x_had_errors_p (display))
Kenichi Handa's avatar
Kenichi Handa committed
334 335 336
	{
	  /* This error is perhaps due to insufficient memory on X
	     server.  Let's just ignore it.  */
337 338 339
	  x_clear_errors (display);
	  num_fonts = 0;
	  break;
Kenichi Handa's avatar
Kenichi Handa committed
340
	}
341 342 343 344 345
      if (num_fonts < limit)
	break;
      XFreeFontNames (names);
    }

346
  if (num_fonts > 0)
347
    {
348
      char **indices = alloca (sizeof (char *) * num_fonts);
349
      Lisp_Object *props = XVECTOR (xfont_scratch_props)->contents;
350
      Lisp_Object scripts = Qnil, entity = Qnil;
351

352
      for (i = 0; i < ASIZE (xfont_scratch_props); i++)
353
	ASET (xfont_scratch_props, i, Qnil);
354 355 356
      for (i = 0; i < num_fonts; i++)
	indices[i] = names[i];
      qsort (indices, num_fonts, sizeof (char *), compare_font_names);
357

Paul Eggert's avatar
Paul Eggert committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
      /* Take one or two passes over the font list.  Do the second
	 pass only if we really need it, i.e., only if the first pass
	 found no fonts and skipped some scalable fonts.  */
      bool skipped_some_scalable_fonts = false;
      for (int i_pass = 0;
	   (i_pass == 0
	    || (i_pass == 1 && NILP (list) && skipped_some_scalable_fonts));
	   i_pass++)
	for (i = 0; i < num_fonts; i++)
	  {
	    ptrdiff_t len;

	    if (i > 0 && xstrcasecmp (indices[i - 1], indices[i]) == 0)
	      continue;
	    if (NILP (entity))
	      entity = font_make_entity ();
	    len = xfont_decode_coding_xlfd (indices[i], -1, buf);
	    if (font_parse_xlfd (buf, len, entity) < 0)
	      continue;
	    ASET (entity, FONT_TYPE_INDEX, Qx);
	    /* Avoid auto-scaled fonts.  */
	    if (INTEGERP (AREF (entity, FONT_DPI_INDEX))
		&& INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
		&& XINT (AREF (entity, FONT_DPI_INDEX)) != 0
		&& XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0)
	      continue;
	    /* Avoid not-allowed scalable fonts.  */
	    if (NILP (Vscalable_fonts_allowed))
	      {
		int size = 0;

		if (INTEGERP (AREF (entity, FONT_SIZE_INDEX)))
		  size = XINT (AREF (entity, FONT_SIZE_INDEX));
		else if (FLOATP (AREF (entity, FONT_SIZE_INDEX)))
		  size = XFLOAT_DATA (AREF (entity, FONT_SIZE_INDEX));
		if (size == 0 && i_pass == 0)
		  {
		    skipped_some_scalable_fonts = true;
		    continue;
		  }
	      }
	    else if (CONSP (Vscalable_fonts_allowed))
	      {
		Lisp_Object tail;

		for (tail = Vscalable_fonts_allowed; CONSP (tail);
		     tail = XCDR (tail))
		  {
		    Lisp_Object elt = XCAR (tail);
		    if (STRINGP (elt)
			&& (fast_c_string_match_ignore_case (elt, indices[i],
							     len)
			    >= 0))
		      break;
		  }
		if (! CONSP (tail))
		  continue;
	      }

	    /* Avoid fonts of invalid registry.  */
	    if (NILP (AREF (entity, FONT_REGISTRY_INDEX)))
	      continue;

	    /* Update encoding and repertory if necessary.  */
	    if (! EQ (registry, AREF (entity, FONT_REGISTRY_INDEX)))
	      {
		registry = AREF (entity, FONT_REGISTRY_INDEX);
		if (font_registry_charsets (registry, &encoding, &repertory) < 0)
		  encoding = NULL;
	      }
	    if (! encoding)
	      /* Unknown REGISTRY, not supported.  */
	      continue;
	    if (repertory)
	      {
		if (NILP (script)
		    || xfont_chars_supported (chars, NULL, encoding, repertory))
		  list = Fcons (entity, list), entity = Qnil;
		continue;
	      }
	    if (memcmp (props, aref_addr (entity, FONT_FOUNDRY_INDEX),
			word_size * 7)
		|| ! EQ (AREF (entity, FONT_SPACING_INDEX), props[7]))
	      {
		vcopy (xfont_scratch_props, 0,
		       aref_addr (entity, FONT_FOUNDRY_INDEX), 7);
		ASET (xfont_scratch_props, 7, AREF (entity, FONT_SPACING_INDEX));
		scripts = xfont_supported_scripts (display, indices[i],
						   xfont_scratch_props,
						   encoding);
	      }
	    if (NILP (script)
		|| ! NILP (Fmemq (script, scripts)))
	      list = Fcons (entity, list), entity = Qnil;
	  }
453
      XFreeFontNames (names);
Kenichi Handa's avatar
Kenichi Handa committed
454 455 456
    }

  x_uncatch_errors ();
457
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
458

459
  FONT_ADD_LOG ("xfont-list", build_string (pattern), list);
460 461
  return list;
}
Kenichi Handa's avatar
Kenichi Handa committed
462

463
static Lisp_Object
464
xfont_list (struct frame *f, Lisp_Object spec)
465
{
466
  Display *display = FRAME_DISPLAY_INFO (f)->display;
467
  Lisp_Object registry, list, val, extra, script;
468
  int len;
469 470
  /* Large enough to contain the longest XLFD (255 bytes) in UTF-8.  */
  char name[512];
471

472 473
  extra = AREF (spec, FONT_EXTRA_INDEX);
  if (CONSP (extra))
Kenichi Handa's avatar
Kenichi Handa committed
474
    {
475 476
      val = assq_no_quit (QCotf, extra);
      if (! NILP (val))
477 478
	return Qnil;
      val = assq_no_quit (QClang, extra);
479
      if (! NILP (val))
480
	return Qnil;
Kenichi Handa's avatar
Kenichi Handa committed
481
    }
Kenichi Handa's avatar
Kenichi Handa committed
482

483
  registry = AREF (spec, FONT_REGISTRY_INDEX);
484 485
  len = font_unparse_xlfd (spec, 0, name, 512);
  if (len < 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
486
    return Qnil;
487 488 489 490

  val = assq_no_quit (QCscript, extra);
  script = CDR (val);
  list = xfont_list_pattern (display, name, registry, script);
491
  if (NILP (list) && NILP (registry))
Kenichi Handa's avatar
Kenichi Handa committed
492
    {
493 494 495 496
      /* Try iso10646-1 */
      char *r = name + len - 9;	/* 9 == strlen (iso8859-1) */

      if (r - name + 10 < 256)	/* 10 == strlen (iso10646-1) */
497
	{
498
	  strcpy (r, "iso10646-1");
499
	  list = xfont_list_pattern (display, name, Qiso10646_1, script);
500 501 502 503
	}
    }
  if (NILP (list) && ! NILP (registry))
    {
Kenichi Handa's avatar
Kenichi Handa committed
504
      /* Try alternate registries.  */
505
      Lisp_Object alter;
506

507
      if ((alter = Fassoc (SYMBOL_NAME (registry),
508 509
			   Vface_alternative_font_registry_alist,
			   Qnil),
510 511 512 513 514 515 516 517 518
	   CONSP (alter)))
	{
	  /* Pointer to REGISTRY-ENCODING field.  */
	  char *r = name + len - SBYTES (SYMBOL_NAME (registry));

	  for (alter = XCDR (alter); CONSP (alter); alter = XCDR (alter))
	    if (STRINGP (XCAR (alter))
		&& ((r - name) + SBYTES (XCAR (alter))) < 256)
	      {
519
		lispstpcpy (r, XCAR (alter));
520
		list = xfont_list_pattern (display, name, registry, script);
521 522 523
		if (! NILP (list))
		  break;
	      }
524
	}
Kenichi Handa's avatar
Kenichi Handa committed
525
    }
Kenichi Handa's avatar
Kenichi Handa committed
526 527 528 529
  if (NILP (list))
    {
      /* Try alias.  */
      val = assq_no_quit (QCname, AREF (spec, FONT_EXTRA_INDEX));
530 531
      if (CONSP (val) && STRINGP (XCDR (val)) && SBYTES (XCDR (val)) < 512)
	{
532
	  memcpy (name, SDATA (XCDR (val)), SBYTES (XCDR (val)) + 1);
533 534
	  if (xfont_encode_coding_xlfd (name) < 0)
	    return Qnil;
535
	  list = xfont_list_pattern (display, name, registry, script);
536
	}
Kenichi Handa's avatar
Kenichi Handa committed
537
    }
Kenichi Handa's avatar
Kenichi Handa committed
538

539
  return list;
Kenichi Handa's avatar
Kenichi Handa committed
540 541
}

Kenichi Handa's avatar
Kenichi Handa committed
542
static Lisp_Object
543
xfont_match (struct frame *f, Lisp_Object spec)
Kenichi Handa's avatar
Kenichi Handa committed
544
{
545
  Display *display = FRAME_DISPLAY_INFO (f)->display;
Kenichi Handa's avatar
Kenichi Handa committed
546
  Lisp_Object extra, val, entity;
547
  char name[512];
Kenichi Handa's avatar
Kenichi Handa committed
548 549 550 551 552 553
  XFontStruct *xfont;
  unsigned long value;

  extra = AREF (spec, FONT_EXTRA_INDEX);
  val = assq_no_quit (QCname, extra);
  if (! CONSP (val) || ! STRINGP (XCDR (val)))
554
    {
555
      if (font_unparse_xlfd (spec, 0, name, 512) < 0)
556 557
	return Qnil;
    }
558
  else if (SBYTES (XCDR (val)) < 512)
559
    memcpy (name, SDATA (XCDR (val)), SBYTES (XCDR (val)) + 1);
560
  else
561 562 563
    return Qnil;
  if (xfont_encode_coding_xlfd (name) < 0)
    return Qnil;
Kenichi Handa's avatar
Kenichi Handa committed
564

565
  block_input ();
Kenichi Handa's avatar
Kenichi Handa committed
566 567 568 569 570 571
  entity = Qnil;
  xfont = XLoadQueryFont (display, name);
  if (xfont)
    {
      if (XGetFontProperty (xfont, XA_FONT, &value))
	{
Paul Eggert's avatar
Paul Eggert committed
572
	  char *s = XGetAtomName (display, (Atom) value);
Kenichi Handa's avatar
Kenichi Handa committed
573 574 575 576

	  /* If DXPC (a Differential X Protocol Compressor)
	     Ver.3.7 is running, XGetAtomName will return null
	     string.  We must avoid such a name.  */
577
	  if (*s)
Kenichi Handa's avatar
Kenichi Handa committed
578
	    {
579
	      ptrdiff_t len;
580
	      entity = font_make_entity ();
Kenichi Handa's avatar
Kenichi Handa committed
581
	      ASET (entity, FONT_TYPE_INDEX, Qx);
582 583
	      len = xfont_decode_coding_xlfd (s, -1, name);
	      if (font_parse_xlfd (name, len, entity) < 0)
Kenichi Handa's avatar
Kenichi Handa committed
584 585
		entity = Qnil;
	    }
586
	  XFree (s);
Kenichi Handa's avatar
Kenichi Handa committed
587 588 589
	}
      XFreeFont (display, xfont);
    }
590
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
591

592
  FONT_ADD_LOG ("xfont-match", spec, entity);
Kenichi Handa's avatar
Kenichi Handa committed
593 594 595
  return entity;
}

Kenichi Handa's avatar
Kenichi Handa committed
596
static Lisp_Object
597
xfont_list_family (struct frame *f)
Kenichi Handa's avatar
Kenichi Handa committed
598
{
599
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
Kenichi Handa's avatar
Kenichi Handa committed
600 601 602
  char **names;
  int num_fonts, i;
  Lisp_Object list;
603
  char *last_family UNINIT;
Kenichi Handa's avatar
Kenichi Handa committed
604 605
  int last_len;

606
  block_input ();
Kenichi Handa's avatar
Kenichi Handa committed
607 608 609 610 611 612 613 614 615 616 617 618 619 620
  x_catch_errors (dpyinfo->display);
  names = XListFonts (dpyinfo->display, "-*-*-*-*-*-*-*-*-*-*-*-*-*-*",
		      0x8000, &num_fonts);
  if (x_had_errors_p (dpyinfo->display))
    {
      /* This error is perhaps due to insufficient memory on X server.
	 Let's just ignore it.  */
      x_clear_errors (dpyinfo->display);
      num_fonts = 0;
    }

  list = Qnil;
  for (i = 0, last_len = 0; i < num_fonts; i++)
    {
621
      char *p0 = names[i], *p1, buf[512];
Kenichi Handa's avatar
Kenichi Handa committed
622
      Lisp_Object family;
623
      int decoded_len;
Kenichi Handa's avatar
Kenichi Handa committed
624 625 626 627 628 629 630 631 632 633

      p0++;			/* skip the leading '-' */
      while (*p0 && *p0 != '-') p0++; /* skip foundry */
      if (! *p0)
	continue;
      p1 = ++p0;
      while (*p1 && *p1 != '-') p1++; /* find the end of family */
      if (! *p1 || p1 == p0)
	continue;
      if (last_len == p1 - p0
634
	  && memcmp (last_family, p0, last_len) == 0)
Kenichi Handa's avatar
Kenichi Handa committed
635 636 637
	continue;
      last_len = p1 - p0;
      last_family = p0;
638 639 640

      decoded_len = xfont_decode_coding_xlfd (p0, last_len, buf);
      family = font_intern_prop (p0, decoded_len, 1);
641
      if (NILP (assq_no_quit (family, list)))
Kenichi Handa's avatar
Kenichi Handa committed
642 643 644 645 646
	list = Fcons (family, list);
    }

  XFreeFontNames (names);
  x_uncatch_errors ();
647
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
648 649 650 651

  return list;
}

652
static Lisp_Object
Dmitry Antipov's avatar
Dmitry Antipov committed
653
xfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
Kenichi Handa's avatar
Kenichi Handa committed
654
{
655
  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
Kenichi Handa's avatar
Kenichi Handa committed
656
  Display *display = dpyinfo->display;
657
  char name[512];
Kenichi Handa's avatar
Kenichi Handa committed
658 659 660 661
  int len;
  unsigned long value;
  Lisp_Object registry;
  struct charset *encoding, *repertory;
662
  Lisp_Object font_object, fullname;
Kenichi Handa's avatar
Kenichi Handa committed
663 664 665 666 667 668
  struct font *font;
  XFontStruct *xfont;

  /* At first, check if we know how to encode characters for this
     font.  */
  registry = AREF (entity, FONT_REGISTRY_INDEX);
669
  if (font_registry_charsets (registry, &encoding, &repertory) < 0)
670
    {
671
      FONT_ADD_LOG ("  x:unknown registry", registry, Qnil);
672 673
      return Qnil;
    }
Kenichi Handa's avatar
Kenichi Handa committed
674 675 676

  if (XINT (AREF (entity, FONT_SIZE_INDEX)) != 0)
    pixel_size = XINT (AREF (entity, FONT_SIZE_INDEX));
677 678 679 680 681 682 683
  else if (pixel_size == 0)
    {
      if (FRAME_FONT (f))
	pixel_size = FRAME_FONT (f)->pixel_size;
      else
	pixel_size = 14;
    }
684 685
  len = font_unparse_xlfd (entity, pixel_size, name, 512);
  if (len <= 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
686
    {
687
      FONT_ADD_LOG ("  x:unparse failed", entity, Qnil);
688 689
      return Qnil;
    }
Kenichi Handa's avatar
Kenichi Handa committed
690

691
  block_input ();
Kenichi Handa's avatar
Kenichi Handa committed
692 693 694 695 696 697 698 699 700
  x_catch_errors (display);
  xfont = XLoadQueryFont (display, name);
  if (x_had_errors_p (display))
    {
      /* This error is perhaps due to insufficient memory on X server.
	 Let's just ignore it.  */
      x_clear_errors (display);
      xfont = NULL;
    }
701 702 703 704 705 706 707 708 709 710 711 712
  else if (! xfont)
    {
      /* Some version of X lists:
	   -misc-fixed-medium-r-normal--20-*-75-75-c-100-iso8859-1
	   -misc-fixed-medium-r-normal--20-*-100-100-c-100-iso8859-1
	 but can open only:
	   -misc-fixed-medium-r-normal--20-*-100-100-c-100-iso8859-1
	 and
	   -misc-fixed-medium-r-normal--20-*-*-*-c-100-iso8859-1
	 So, we try again with wildcards in RESX and RESY.  */
      Lisp_Object temp;

713
      temp = copy_font_spec (entity);
714
      ASET (temp, FONT_DPI_INDEX, Qnil);
715 716
      len = font_unparse_xlfd (temp, pixel_size, name, 512);
      if (len <= 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
717
	{
718
	  FONT_ADD_LOG ("  x:unparse failed", temp, Qnil);
719 720 721 722 723 724 725 726 727 728 729
	  return Qnil;
	}
      xfont = XLoadQueryFont (display, name);
      if (x_had_errors_p (display))
	{
	  /* This error is perhaps due to insufficient memory on X server.
	     Let's just ignore it.  */
	  x_clear_errors (display);
	  xfont = NULL;
	}
    }
730 731 732 733 734 735 736
  fullname = Qnil;
  /* Try to get the full name of FONT.  */
  if (xfont && XGetFontProperty (xfont, XA_FONT, &value))
    {
      char *p0, *p;
      int dashes = 0;

Paul Eggert's avatar
Paul Eggert committed
737
      p0 = p = XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
738 739 740 741 742 743 744 745 746 747 748 749 750
      /* Count the number of dashes in the "full name".
	 If it is too few, this isn't really the font's full name,
	 so don't use it.
	 In X11R4, the fonts did not come with their canonical names
	 stored in them.  */
      while (*p)
	{
	  if (*p == '-')
	    dashes++;
	  p++;
	}

      if (dashes >= 13)
751 752
	{
	  len = xfont_decode_coding_xlfd (p0, -1, name);
753
	  fullname = Fdowncase (make_string (name, len));
754
	}
755 756
      XFree (p0);
    }
Kenichi Handa's avatar
Kenichi Handa committed
757
  x_uncatch_errors ();
758
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
759 760

  if (! xfont)
761
    {
762
      FONT_ADD_LOG ("  x:open failed", build_string (name), Qnil);
763 764
      return Qnil;
    }
765

766 767
  font_object = font_make_object (VECSIZE (struct xfont_info),
				  entity, pixel_size);
768 769
  ASET (font_object, FONT_TYPE_INDEX, Qx);
  if (STRINGP (fullname))
770
    {
771
      font_parse_xlfd (SSDATA (fullname), SBYTES (fullname), font_object);
772 773
      ASET (font_object, FONT_NAME_INDEX, fullname);
    }
774
  else
775 776 777 778 779 780
    {
      char buf[512];

      len = xfont_decode_coding_xlfd (name, -1, buf);
      ASET (font_object, FONT_NAME_INDEX, make_string (buf, len));
    }
781 782 783 784
  ASET (font_object, FONT_FULLNAME_INDEX, fullname);
  font = XFONT_OBJECT (font_object);
  ((struct xfont_info *) font)->xfont = xfont;
  ((struct xfont_info *) font)->display = FRAME_X_DISPLAY (f);
785
  ((struct xfont_info *) font)->x_display_id = FRAME_DISPLAY_INFO (f)->x_id;
Kenichi Handa's avatar
Kenichi Handa committed
786 787 788
  font->pixel_size = pixel_size;
  font->driver = &xfont_driver;
  font->encoding_charset = encoding->id;
789
  font->repertory_charset = repertory ? repertory->id : -1;
Kenichi Handa's avatar
Kenichi Handa committed
790 791
  font->ascent = xfont->ascent;
  font->descent = xfont->descent;
792 793
  font->height = font->ascent + font->descent;
  font->min_width = xfont->min_bounds.width;
794
  font->max_width = xfont->max_bounds.width;
Kenichi Handa's avatar
Kenichi Handa committed
795 796 797
  if (xfont->min_bounds.width == xfont->max_bounds.width)
    {
      /* Fixed width font.  */
798
      font->average_width = font->space_width = xfont->min_bounds.width;
Kenichi Handa's avatar
Kenichi Handa committed
799 800 801 802
    }
  else
    {
      XCharStruct *pcm;
803 804
      XChar2b char2b;
      Lisp_Object val;
Kenichi Handa's avatar
Kenichi Handa committed
805 806 807 808

      char2b.byte1 = 0x00, char2b.byte2 = 0x20;
      pcm = xfont_get_pcm (xfont, &char2b);
      if (pcm)
809
	font->space_width = pcm->width;
Kenichi Handa's avatar
Kenichi Handa committed
810
      else
811 812 813 814
	font->space_width = 0;

      val = Ffont_get (font_object, QCavgwidth);
      if (INTEGERP (val))
815
	font->average_width = XINT (val) / 10;
816 817
      if (font->average_width < 0)
	font->average_width = - font->average_width;
818
      else
Kenichi Handa's avatar
Kenichi Handa committed
819
	{
820 821 822 823
	  if (font->average_width == 0
	      && encoding->ascii_compatible_p)
	    {
	      int width = font->space_width, n = pcm != NULL;
Kenichi Handa's avatar
Kenichi Handa committed
824

825 826 827 828 829 830 831 832 833 834 835
	      for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
		if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
		  width += pcm->width, n++;
	      if (n > 0)
		font->average_width = width / n;
	    }
	  if (font->average_width == 0)
	    /* No easy way other than this to get a reasonable
	       average_width.  */
	    font->average_width
	      = (xfont->min_bounds.width + xfont->max_bounds.width) / 2;
Kenichi Handa's avatar
Kenichi Handa committed
836 837 838
	}
    }

839
  block_input ();
840 841 842 843 844 845 846
  font->underline_thickness
    = (XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &value)
       ? (long) value : 0);
  font->underline_position
    = (XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &value)
       ? (long) value : -1);
  font->baseline_offset
Kenichi Handa's avatar
Kenichi Handa committed
847 848
    = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
       ? (long) value : 0);
849
  font->relative_compose
Kenichi Handa's avatar
Kenichi Handa committed
850 851
    = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
       ? (long) value : 0);
852
  font->default_ascent
Kenichi Handa's avatar
Kenichi Handa committed
853 854
    = (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
       ? (long) value : 0);
855
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
856

857 858
  if (NILP (fullname))
    fullname = AREF (font_object, FONT_NAME_INDEX);
859 860 861 862
  font->vertical_centering
    = (STRINGP (Vvertical_centering_font_regexp)
       && (fast_string_match_ignore_case
	   (Vvertical_centering_font_regexp, fullname) >= 0));
Kenichi Handa's avatar
Kenichi Handa committed
863

864
  return font_object;
Kenichi Handa's avatar
Kenichi Handa committed
865 866 867
}

static void
868
xfont_close (struct font *font)
Kenichi Handa's avatar
Kenichi Handa committed
869
{
870
  struct x_display_info *xdi;
871 872
  struct xfont_info *xfi = (struct xfont_info *) font;

873
  /* This function may be called from GC when X connection is gone
Paul Eggert's avatar
Paul Eggert committed
874
     (Bug#16093), and an attempt to free font resources on invalid
875 876 877 878 879
     display may lead to X protocol errors or segfaults.  Moreover,
     the memory referenced by 'Display *' pointer may be reused for
     the logically different X connection after the previous display
     connection was closed.  That's why we also check whether font's
     ID matches the one recorded in x_display_info for this display.
880
     See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=16069.  */
881 882 883
  if (xfi->xfont
      && ((xdi = x_display_info_for_display (xfi->display))
	  && xfi->x_display_id == xdi->x_id))
884 885 886 887 888 889
    {
      block_input ();
      XFreeFont (xfi->display, xfi->xfont);
      unblock_input ();
      xfi->xfont = NULL;
    }
Kenichi Handa's avatar
Kenichi Handa committed
890 891
}

892
static void
Dmitry Antipov's avatar
Dmitry Antipov committed
893
xfont_prepare_face (struct frame *f, struct face *face)
Kenichi Handa's avatar
Kenichi Handa committed
894
{
895
  block_input ();
896 897
  XSetFont (FRAME_X_DISPLAY (f), face->gc,
	    ((struct xfont_info *) face->font)->xfont->fid);
898
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
899 900 901
}

static int
902
xfont_has_char (Lisp_Object font, int c)
Kenichi Handa's avatar
Kenichi Handa committed
903
{
904
  Lisp_Object registry = AREF (font, FONT_REGISTRY_INDEX);
905
  struct charset *encoding;
906
  struct charset *repertory = NULL;
Kenichi Handa's avatar
Kenichi Handa committed
907

908 909
  if (EQ (registry, Qiso10646_1))
    {
910
      encoding = CHARSET_FROM_ID (charset_unicode);
911 912 913 914
      /* We use a font of `ja' and `ko' adstyle only for a character
	 in JISX0208 and KSC5601 charsets respectively.  */
      if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
	  && charset_jisx0208 >= 0)
915
	repertory = CHARSET_FROM_ID (charset_jisx0208);
916 917
      else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
	       && charset_ksc5601 >= 0)
918
	repertory = CHARSET_FROM_ID (charset_ksc5601);
919 920 921 922
    }
  else if (font_registry_charsets (registry, &encoding, &repertory) < 0)
    /* Unknown REGISTRY, not usable.  */
    return 0;
923 924
  if (ASCII_CHAR_P (c) && encoding->ascii_compatible_p)
    return 1;
Kenichi Handa's avatar
Kenichi Handa committed
925 926 927 928 929 930
  if (! repertory)
    return -1;
  return (ENCODE_CHAR (repertory, c) != CHARSET_INVALID_CODE (repertory));
}

static unsigned
931
xfont_encode_char (struct font *font, int c)
Kenichi Handa's avatar
Kenichi Handa committed
932
{
933
  XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
Kenichi Handa's avatar
Kenichi Handa committed
934 935 936 937 938 939 940
  struct charset *charset;
  unsigned code;
  XChar2b char2b;

  charset = CHARSET_FROM_ID (font->encoding_charset);
  code = ENCODE_CHAR (charset, c);
  if (code == CHARSET_INVALID_CODE (charset))
941
    return FONT_INVALID_CODE;
942
  if (font->repertory_charset >= 0)
Kenichi Handa's avatar
Kenichi Handa committed
943
    {
944
      charset = CHARSET_FROM_ID (font->repertory_charset);
Kenichi Handa's avatar
Kenichi Handa committed
945
      return (ENCODE_CHAR (charset, c) != CHARSET_INVALID_CODE (charset)
946
	      ? code : FONT_INVALID_CODE);
Kenichi Handa's avatar
Kenichi Handa committed
947
    }
948 949
  char2b.byte1 = code >> 8;
  char2b.byte2 = code & 0xFF;
950
  return (xfont_get_pcm (xfont, &char2b) ? code : FONT_INVALID_CODE);
Kenichi Handa's avatar
Kenichi Handa committed
951 952
}

953 954 955
static void
xfont_text_extents (struct font *font, unsigned int *code,
		    int nglyphs, struct font_metrics *metrics)
Kenichi Handa's avatar
Kenichi Handa committed
956
{
957
  XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
958 959
  int i, width = 0;
  bool first;
Kenichi Handa's avatar
Kenichi Handa committed
960

961
  for (i = 0, first = true; i < nglyphs; i++)
Kenichi Handa's avatar
Kenichi Handa committed
962 963 964 965 966 967 968
    {
      XChar2b char2b;
      static XCharStruct *pcm;

      if (code[i] >= 0x10000)
	continue;
      char2b.byte1 = code[i] >> 8, char2b.byte2 = code[i] & 0xFF;
969
      pcm = xfont_get_pcm (xfont, &char2b);
Kenichi Handa's avatar
Kenichi Handa committed
970 971
      if (! pcm)
	continue;
972 973
      if (first)
	{
974 975 976 977
	  metrics->lbearing = pcm->lbearing;
	  metrics->rbearing = pcm->rbearing;
	  metrics->ascent = pcm->ascent;
	  metrics->descent = pcm->descent;
978
	  first = false;
979 980 981
	}
      else
	{
982 983 984 985 986 987 988 989
	  if (metrics->lbearing > width + pcm->lbearing)
	    metrics->lbearing = width + pcm->lbearing;
	  if (metrics->rbearing < width + pcm->rbearing)
	    metrics->rbearing = width + pcm->rbearing;
	  if (metrics->ascent < pcm->ascent)
	    metrics->ascent = pcm->ascent;
	  if (metrics->descent < pcm->descent)
	    metrics->descent = pcm->descent;
990
	}
Kenichi Handa's avatar
Kenichi Handa committed
991 992
      width += pcm->width;
    }
993 994

  metrics->width = width;
Kenichi Handa's avatar
Kenichi Handa committed
995 996 997
}

static int
998 999
xfont_draw (struct glyph_string *s, int from, int to, int x, int y,
            bool with_background)
Kenichi Handa's avatar
Kenichi Handa committed
1000
{
1001
  XFontStruct *xfont = ((struct xfont_info *) s->font)->xfont;
Kenichi Handa's avatar
Kenichi Handa committed
1002
  int len = to - from;
Kenichi Handa's avatar
Kenichi Handa committed
1003
  GC gc = s->gc;
1004
  int i;
Kenichi Handa's avatar
Kenichi Handa committed
1005

1006
  if (s->gc != s->face->gc)
Kenichi Handa's avatar
Kenichi Handa committed
1007
    {
1008
      block_input ();
1009
      XSetFont (s->display, gc, xfont->fid);
1010
      unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
1011
    }
Kenichi Handa's avatar
Kenichi Handa committed
1012 1013 1014 1015

  if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
    {
      USE_SAFE_ALLOCA;
1016
      char *str = SAFE_ALLOCA (len);
Kenichi Handa's avatar
Kenichi Handa committed
1017 1018
      for (i = 0; i < len ; i++)
	str[i] = XCHAR2B_BYTE2 (s->char2b + from + i);
1019
      block_input ();
1020
      if (with_background)
1021 1022 1023
	{
	  if (s->padding_p)
	    for (i = 0; i < len; i++)
1024
              XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1025 1026
				gc, x + i, y, str + i, 1);
	  else
1027
            XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1028 1029
			      gc, x, y, str, len);
	}
Kenichi Handa's avatar
Kenichi Handa committed
1030
      else
1031 1032 1033
	{
	  if (s->padding_p)
	    for (i = 0; i < len; i++)
1034
              XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1035 1036
			   gc, x + i, y, str + i, 1);
	  else
1037
            XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1038 1039
			 gc, x, y, str, len);
	}
1040
      unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
1041 1042 1043 1044
      SAFE_FREE ();
      return s->nchars;
    }

1045
  block_input ();
1046
  if (with_background)
1047 1048 1049
    {
      if (s->padding_p)
	for (i = 0; i < len; i++)
1050
          XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1051 1052
			      gc, x + i, y, s->char2b + from + i, 1);
      else
1053
        XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1054 1055
			    gc, x, y, s->char2b + from, len);
    }
Kenichi Handa's avatar
Kenichi Handa committed
1056
  else
1057 1058 1059
    {
      if (s->padding_p)
	for (i = 0; i < len; i++)
1060
          XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1061 1062
			 gc, x + i, y, s->char2b + from + i, 1);
      else
1063
        XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f),
1064 1065
		       gc, x, y, s->char2b + from, len);
    }
1066
  unblock_input ();
Kenichi Handa's avatar
Kenichi Handa committed
1067 1068 1069 1070

  return len;
}

1071
static int
Dmitry Antipov's avatar
Dmitry Antipov committed
1072
xfont_check (struct frame *f, struct font *font)
1073 1074 1075 1076 1077 1078
{
  struct xfont_info *xfont = (struct xfont_info *) font;

  return (FRAME_X_DISPLAY (f) == xfont->display ? 0 : -1);
}

Kenichi Handa's avatar
Kenichi Handa committed
1079

1080 1081 1082

struct font_driver const xfont_driver =
  {
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
  .type = LISPSYM_INITIALLY (Qx),
  .get_cache = xfont_get_cache,
  .list = xfont_list,
  .match = xfont_match,
  .list_family = xfont_list_family,
  .open = xfont_open,
  .close = xfont_close,
  .prepare_face = xfont_prepare_face,
  .has_char = xfont_has_char,
  .encode_char = xfont_encode_char,
  .text_extents = xfont_text_extents,
  .draw = xfont_draw,
  .check = xfont_check,
1096 1097
  };

Kenichi Handa's avatar
Kenichi Handa committed
1098
void
1099
syms_of_xfont (void)
Kenichi Handa's avatar
Kenichi Handa committed
1100
{
1101
  staticpro (&xfont_scripts_cache);
1102
  xfont_scripts_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
1103
  staticpro (&xfont_scratch_props);
1104
  xfont_scratch_props = Fmake_vector (make_number (8), Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
1105 1106
  register_font_driver (&xfont_driver, NULL);
}