fontset.c 64.1 KB
Newer Older
Karl Heuer's avatar
Karl Heuer committed
1
/* Fontset handler.
2

3
Copyright (C) 2001-2012  Free Software Foundation, Inc.
4 5 6 7 8 9 10
Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
  2005, 2006, 2007, 2008, 2009, 2010, 2011
  National Institute of Advanced Industrial Science and Technology (AIST)
  Registration Number H14PRO021
Copyright (C) 2003, 2006
  National Institute of Advanced Industrial Science and Technology (AIST)
  Registration Number H13PRO009
Juanma Barranquero's avatar
Juanma Barranquero committed
11

Karl Heuer's avatar
Karl Heuer committed
12 13
This file is part of GNU Emacs.

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

Karl Heuer's avatar
Karl Heuer committed
19 20 21 22
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.
Karl Heuer's avatar
Karl Heuer committed
23

Karl Heuer's avatar
Karl Heuer committed
24
You should have received a copy of the GNU General Public License
25
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Karl Heuer's avatar
Karl Heuer committed
26 27

#include <config.h>
28
#include <stdio.h>
29
#include <setjmp.h>
30

Karl Heuer's avatar
Karl Heuer committed
31
#include "lisp.h"
Kenichi Handa's avatar
Kenichi Handa committed
32 33
#include "blockinput.h"
#include "character.h"
34
#include "buffer.h"
Karl Heuer's avatar
Karl Heuer committed
35 36
#include "charset.h"
#include "ccl.h"
37
#include "keyboard.h"
Karl Heuer's avatar
Karl Heuer committed
38
#include "frame.h"
39
#include "dispextern.h"
Kenichi Handa's avatar
Kenichi Handa committed
40
#include "intervals.h"
41
#include "fontset.h"
42
#include "window.h"
Kenichi Handa's avatar
Kenichi Handa committed
43 44 45 46 47 48
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#endif
#ifdef WINDOWSNT
#include "w32term.h"
#endif
49 50 51
#ifdef HAVE_NS
#include "nsterm.h"
#endif
52
#include "termhooks.h"
53

Kenichi Handa's avatar
Kenichi Handa committed
54 55
#include "font.h"

56 57 58
/* FONTSET

   A fontset is a collection of font related information to give
59 60 61 62 63 64 65 66 67 68 69 70 71 72
   similar appearance (style, etc) of characters.  A fontset has two
   roles.  One is to use for the frame parameter `font' as if it is an
   ASCII font.  In that case, Emacs uses the font specified for
   `ascii' script for the frame's default font.

   Another role, the more important one, is to provide information
   about which font to use for each non-ASCII character.

   There are two kinds of fontsets; base and realized.  A base fontset
   is created by `new-fontset' from Emacs Lisp explicitly.  A realized
   fontset is created implicitly when a face is realized for ASCII
   characters.  A face is also realized for non-ASCII characters based
   on an ASCII face.  All of non-ASCII faces based on the same ASCII
   face share the same realized fontset.
Kenichi Handa's avatar
Kenichi Handa committed
73

Kenichi Handa's avatar
Kenichi Handa committed
74 75
   A fontset object is implemented by a char-table whose default value
   and parent are always nil.
76

77 78 79
   An element of a base fontset is a vector of FONT-DEFs which itself
   is a vector [ FONT-SPEC ENCODING REPERTORY ].

80 81
   An element of a realized fontset is nil, t, 0, or a vector of this
   form:
82

83 84
	[ CHARSET-ORDERED-LIST-TICK PREFERRED-RFONT-DEF
	  RFONT-DEF0 RFONT-DEF1 ... ]
85

86
   RFONT-DEFn (i.e. Realized FONT-DEF) has this form:
87

88
	[ FACE-ID FONT-DEF FONT-OBJECT SORTING-SCORE ]
89

90
   RFONT-DEFn are automatically reordered by the current charset
91
   priority list.
92

93 94
   The value nil means that we have not yet generated the above vector
   from the base of the fontset.
95

96 97
   The value t means that no font is available for the corresponding
   range of characters.
98

99 100 101 102
   The value 0 means that no font is available for the corresponding
   range of characters in this fontset, but may be available in the
   default fontset.

103

Kenichi Handa's avatar
Kenichi Handa committed
104
   A fontset has 9 extra slots.
105

106
   The 1st slot: the ID number of the fontset
107

108 109 110
   The 2nd slot:
	base: the name of the fontset
	realized: nil
111

112
   The 3rd slot:
113
	base: nil
114
	realized: the base fontset
Kenichi Handa's avatar
Kenichi Handa committed
115

116 117 118
   The 4th slot:
	base: nil
	realized: the frame that the fontset belongs to
119

120 121 122
   The 5th slot:
	base: the font name for ASCII characters
	realized: nil
123

124 125 126 127
   The 6th slot:
	base: nil
	realized: the ID number of a face to use for characters that
		  has no font in a realized fontset.
128

129 130 131 132
   The 7th slot:
	base: nil
	realized: Alist of font index vs the corresponding repertory
	char-table.
Juanma Barranquero's avatar
Juanma Barranquero committed
133

134 135 136 137
   The 8th slot:
	base: nil
	realized: If the base is not the default fontset, a fontset
	realized from the default fontset, else nil.
138

Kenichi Handa's avatar
Kenichi Handa committed
139
   The 9th slot:
140 141
	base: Same as element value (but for fallback fonts).
	realized: Likewise.
Kenichi Handa's avatar
Kenichi Handa committed
142

143
   All fontsets are recorded in the vector Vfontset_table.
144 145 146 147


   DEFAULT FONTSET

148 149 150 151
   There's a special base fontset named `default fontset' which
   defines the default font specifications.  When a base fontset
   doesn't specify a font for a specific character, the corresponding
   value in the default fontset is used.
152

153 154
   The parent of a realized fontset created for such a face that has
   no fontset is the default fontset.
155 156 157 158


   These structures are hidden from the other codes than this file.
   The other codes handle fontsets only by their ID numbers.  They
Kenichi Handa's avatar
Kenichi Handa committed
159
   usually use the variable name `fontset' for IDs.  But, in this
Paul Eggert's avatar
Paul Eggert committed
160
   file, we always use variable name `id' for IDs, and name `fontset'
161
   for an actual fontset object, i.e., char-table.
162 163 164 165 166

*/

/********** VARIABLES and FUNCTION PROTOTYPES **********/

167 168
static Lisp_Object Qfontset;
static Lisp_Object Qfontset_info;
169
static Lisp_Object Qprepend, Qappend;
170
Lisp_Object Qlatin;
171 172 173 174

/* Vector containing all fontsets.  */
static Lisp_Object Vfontset_table;

175
/* Next possibly free fontset ID.  Usually this keeps the minimum
176 177 178 179
   fontset ID not yet used.  */
static int next_fontset_id;

/* The default fontset.  This gives default FAMILY and REGISTRY of
Kenichi Handa's avatar
Kenichi Handa committed
180
   font for each character.  */
181
static Lisp_Object Vdefault_fontset;
Karl Heuer's avatar
Karl Heuer committed
182 183

/* Check if any window system is used now.  */
184
void (*check_window_system_func) (void);
Karl Heuer's avatar
Karl Heuer committed
185

186 187

/* Prototype declarations for static functions.  */
188 189 190 191 192 193 194 195 196 197 198
static Lisp_Object fontset_add (Lisp_Object, Lisp_Object, Lisp_Object,
                                Lisp_Object);
static Lisp_Object fontset_find_font (Lisp_Object, int, struct face *,
                                      int, int);
static void reorder_font_vector (Lisp_Object, struct font *);
static Lisp_Object fontset_font (Lisp_Object, int, struct face *, int);
static Lisp_Object make_fontset (Lisp_Object, Lisp_Object, Lisp_Object);
static Lisp_Object fontset_pattern_regexp (Lisp_Object);
static void accumulate_script_ranges (Lisp_Object, Lisp_Object,
                                      Lisp_Object);
static void set_fontset_font (Lisp_Object, Lisp_Object);
199

200 201
/* Return 1 if ID is a valid fontset id, else return 0.
   Optimized away if ENABLE_CHECKING is not defined.  */
202 203

static int
204
fontset_id_valid_p (int id)
205 206 207 208
{
  return (id >= 0 && id < ASIZE (Vfontset_table) - 1);
}

209 210 211 212 213 214 215


/********** MACROS AND FUNCTIONS TO HANDLE FONTSET **********/

/* Return the fontset with ID.  No check of ID's validness.  */
#define FONTSET_FROM_ID(id) AREF (Vfontset_table, id)

216
/* Macros to access special values of FONTSET.  */
217
#define FONTSET_ID(fontset)		XCHAR_TABLE (fontset)->extras[0]
Kenichi Handa's avatar
Kenichi Handa committed
218 219

/* Macros to access special values of (base) FONTSET.  */
220
#define FONTSET_NAME(fontset)		XCHAR_TABLE (fontset)->extras[1]
Kenichi Handa's avatar
Kenichi Handa committed
221
#define FONTSET_ASCII(fontset)		XCHAR_TABLE (fontset)->extras[4]
222
/* #define FONTSET_SPEC(fontset)	XCHAR_TABLE (fontset)->extras[5] */
Kenichi Handa's avatar
Kenichi Handa committed
223 224 225 226

/* Macros to access special values of (realized) FONTSET.  */
#define FONTSET_BASE(fontset)		XCHAR_TABLE (fontset)->extras[2]
#define FONTSET_FRAME(fontset)		XCHAR_TABLE (fontset)->extras[3]
227
/* #define FONTSET_OBJLIST(fontset)	XCHAR_TABLE (fontset)->extras[4] */
228
#define FONTSET_NOFONT_FACE(fontset)	XCHAR_TABLE (fontset)->extras[5]
229
/* #define FONTSET_REPERTORY(fontset)	XCHAR_TABLE (fontset)->extras[6] */
Kenichi Handa's avatar
Kenichi Handa committed
230 231
#define FONTSET_DEFAULT(fontset)	XCHAR_TABLE (fontset)->extras[7]

232
/* For both base and realized fontset.  */
Kenichi Handa's avatar
Kenichi Handa committed
233
#define FONTSET_FALLBACK(fontset)	XCHAR_TABLE (fontset)->extras[8]
234

235
#define BASE_FONTSET_P(fontset)		(NILP (FONTSET_BASE (fontset)))
236 237


238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/* Macros for FONT-DEF and RFONT-DEF of fontset.  */
#define FONT_DEF_NEW(font_def, font_spec, encoding, repertory)	\
  do {								\
    (font_def) = Fmake_vector (make_number (3), (font_spec));	\
    ASET ((font_def), 1, encoding);				\
    ASET ((font_def), 2, repertory);				\
  } while (0)

#define FONT_DEF_SPEC(font_def) AREF (font_def, 0)
#define FONT_DEF_ENCODING(font_def) AREF (font_def, 1)
#define FONT_DEF_REPERTORY(font_def) AREF (font_def, 2)

#define RFONT_DEF_FACE(rfont_def) AREF (rfont_def, 0)
#define RFONT_DEF_SET_FACE(rfont_def, face_id)	\
  ASET ((rfont_def), 0, make_number (face_id))
#define RFONT_DEF_FONT_DEF(rfont_def) AREF (rfont_def, 1)
#define RFONT_DEF_SPEC(rfont_def) FONT_DEF_SPEC (AREF (rfont_def, 1))
#define RFONT_DEF_OBJECT(rfont_def) AREF (rfont_def, 2)
#define RFONT_DEF_SET_OBJECT(rfont_def, object)	\
  ASET ((rfont_def), 2, (object))
258 259 260 261
/* Score of RFONT_DEF is an integer value; the lowest 8 bits represent
   the order of listing by font backends, the higher bits represents
   the order given by charset priority list.  The smaller value is
   preferable.  */
262 263 264 265 266 267 268 269 270 271 272
#define RFONT_DEF_SCORE(rfont_def) XINT (AREF (rfont_def, 3))
#define RFONT_DEF_SET_SCORE(rfont_def, score) \
  ASET ((rfont_def), 3, make_number (score))
#define RFONT_DEF_NEW(rfont_def, font_def)		\
  do {							\
    (rfont_def) = Fmake_vector (make_number (4), Qnil);	\
    ASET ((rfont_def), 1, (font_def));		\
    RFONT_DEF_SET_SCORE ((rfont_def), 0);		\
  } while (0)


273 274 275 276
/* Return the element of FONTSET for the character C.  If FONTSET is a
   base fontset other then the default fontset and FONTSET doesn't
   contain information for C, return the information in the default
   fontset.  */
277

278 279 280 281
#define FONTSET_REF(fontset, c)		\
  (EQ (fontset, Vdefault_fontset)	\
   ? CHAR_TABLE_REF (fontset, c)	\
   : fontset_ref ((fontset), (c)))
282

283
static Lisp_Object
284
fontset_ref (Lisp_Object fontset, int c)
285
{
Kenichi Handa's avatar
Kenichi Handa committed
286 287
  Lisp_Object elt;

288 289 290 291 292
  elt = CHAR_TABLE_REF (fontset, c);
  if (NILP (elt) && ! EQ (fontset, Vdefault_fontset)
      /* Don't check Vdefault_fontset for a realized fontset.  */
      && NILP (FONTSET_BASE (fontset)))
    elt = CHAR_TABLE_REF (Vdefault_fontset, c);
293 294 295
  return elt;
}

296 297 298 299 300 301 302
/* Set elements of FONTSET for characters in RANGE to the value ELT.
   RANGE is a cons (FROM . TO), where FROM and TO are character codes
   specifying a range.  */

#define FONTSET_SET(fontset, range, elt)	\
  Fset_char_table_range ((fontset), (range), (elt))

303

304
/* Modify the elements of FONTSET for characters in RANGE by replacing
305
   with ELT or adding ELT.  RANGE is a cons (FROM . TO), where FROM
306 307 308 309
   and TO are character codes specifying a range.  If ADD is nil,
   replace with ELT, if ADD is `prepend', prepend ELT, otherwise,
   append ELT.  */

310 311 312 313 314 315
#define FONTSET_ADD(fontset, range, elt, add)				     \
  (NILP (add)								     \
   ? (NILP (range)							     \
      ? (FONTSET_FALLBACK (fontset) = Fmake_vector (make_number (1), (elt))) \
      : Fset_char_table_range ((fontset), (range),			     \
			       Fmake_vector (make_number (1), (elt))))	     \
316
   : fontset_add ((fontset), (range), (elt), (add)))
317

Dave Love's avatar
Dave Love committed
318
static Lisp_Object
319
fontset_add (Lisp_Object fontset, Lisp_Object range, Lisp_Object elt, Lisp_Object add)
Kenichi Handa's avatar
Kenichi Handa committed
320
{
Kenichi Handa's avatar
Kenichi Handa committed
321 322 323 324 325 326 327 328 329 330 331 332
  Lisp_Object args[2];
  int idx = (EQ (add, Qappend) ? 0 : 1);

  args[1 - idx] = Fmake_vector (make_number (1), elt);

  if (CONSP (range))
    {
      int from = XINT (XCAR (range));
      int to = XINT (XCDR (range));
      int from1, to1;

      do {
333
	from1 = from, to1 = to;
Kenichi Handa's avatar
Kenichi Handa committed
334 335 336 337 338 339 340 341 342 343 344 345 346
	args[idx] = char_table_ref_and_range (fontset, from, &from1, &to1);
	char_table_set_range (fontset, from, to1,
			      NILP (args[idx]) ? args[1 - idx]
			      : Fvconcat (2, args));
	from = to1 + 1;
      } while (from < to);
    }
  else
    {
      args[idx] = FONTSET_FALLBACK (fontset);
      FONTSET_FALLBACK (fontset)
	= NILP (args[idx]) ? args[1 - idx] : Fvconcat (2, args);
    }
Dave Love's avatar
Dave Love committed
347
  return Qnil;
348 349
}

350
static int
351
fontset_compare_rfontdef (const void *val1, const void *val2)
352
{
353 354
  return (RFONT_DEF_SCORE (*(Lisp_Object *) val1)
	  - RFONT_DEF_SCORE (*(Lisp_Object *) val2));
355
}
356

357
/* Update FONT-GROUP which has this form:
358 359
	[ CHARSET-ORDERED-LIST-TICK PREFERRED-RFONT-DEF
	  RFONT-DEF0 RFONT-DEF1 ... ]
Juanma Barranquero's avatar
Juanma Barranquero committed
360
   Reorder RFONT-DEFs according to the current language, and update
361 362 363 364 365
   CHARSET-ORDERED-LIST-TICK.

   If PREFERRED_FAMILY is not nil, that family has the higher priority
   if the encoding charsets or languages in font-specs are the same.  */

366
static void
367
reorder_font_vector (Lisp_Object font_group, struct font *font)
368
{
369
  Lisp_Object vec, font_object;
370
  int size;
371 372
  int i;
  int score_changed = 0;
373

374 375 376 377 378 379 380 381 382 383
  if (font)
    XSETFONT (font_object, font);
  else
    font_object = Qnil;

  vec = XCDR (font_group);
  size = ASIZE (vec);
  /* Exclude the tailing nil element from the reordering.  */
  if (NILP (AREF (vec, size - 1)))
    size--;
384 385

  for (i = 0; i < size; i++)
386
    {
387
      Lisp_Object rfont_def = AREF (vec, i);
388 389
      Lisp_Object font_def = RFONT_DEF_FONT_DEF (rfont_def);
      Lisp_Object font_spec = FONT_DEF_SPEC (font_def);
390
      int score = RFONT_DEF_SCORE (rfont_def) & 0xFF;
391
      Lisp_Object otf_spec = Ffont_get (font_spec, QCotf);
392

393 394 395 396 397
      if (! NILP (otf_spec))
	/* A font-spec with :otf is preferable regardless of encoding
	   and language..  */
	;
      else if (! font_match_p (font_spec, font_object))
Juanma Barranquero's avatar
Juanma Barranquero committed
398
	{
399
	  Lisp_Object encoding = FONT_DEF_ENCODING (font_def);
400

401
	  if (! NILP (encoding))
402 403
	    {
	      Lisp_Object tail;
404

405 406
	      for (tail = Vcharset_ordered_list;
		   ! EQ (tail, Vcharset_non_preferred_head) && CONSP (tail);
407
		   tail = XCDR (tail))
408
		if (EQ (encoding, XCAR (tail)))
409
		  break;
410
		else if (score <= min (INT_MAX, MOST_POSITIVE_FIXNUM) - 0x100)
411
		  score += 0x100;
412 413 414 415 416 417 418 419 420 421 422
	    }
	  else
	    {
	      Lisp_Object lang = Ffont_get (font_spec, QClang);

	      if (! NILP (lang)
		  && ! EQ (lang, Vcurrent_iso639_language)
		  && (! CONSP (Vcurrent_iso639_language)
		      || NILP (Fmemq (lang, Vcurrent_iso639_language))))
		score |= 0x100;
	    }
423
	}
424
      if (RFONT_DEF_SCORE (rfont_def) != score)
425
	{
426 427
	  RFONT_DEF_SET_SCORE (rfont_def, score);
	  score_changed = 1;
428
	}
429
    }
430

431
  if (score_changed)
432
    qsort (XVECTOR (vec)->contents, size, sizeof (Lisp_Object),
433
	   fontset_compare_rfontdef);
434 435 436
  XSETCAR (font_group, make_number (charset_ordered_list_tick));
}

437 438 439
/* Return a font-group (actually a cons (-1 . FONT-GROUP-VECTOR)) for
   character C in FONTSET.  If C is -1, return a fallback font-group.
   If C is not -1, the value may be Qt (FONTSET doesn't have a font
440
   for C even in the fallback group), or 0 (a font for C may be found
441 442
   only in the fallback group).  */

443
static Lisp_Object
444
fontset_get_font_group (Lisp_Object fontset, int c)
445 446 447
{
  Lisp_Object font_group;
  Lisp_Object base_fontset;
448
  int from = 0, to = MAX_CHAR, i;
449

450
  eassert (! BASE_FONTSET_P (fontset));
451 452 453 454 455 456 457
  if (c >= 0)
    font_group = CHAR_TABLE_REF (fontset, c);
  else
    font_group = FONTSET_FALLBACK (fontset);
  if (! NILP (font_group))
    return font_group;
  base_fontset = FONTSET_BASE (fontset);
458 459 460
  if (NILP (base_fontset))
    font_group = Qnil;
  else if (c >= 0)
461 462 463 464
    font_group = char_table_ref_and_range (base_fontset, c, &from, &to);
  else
    font_group = FONTSET_FALLBACK (base_fontset);
  if (NILP (font_group))
465
    {
466
      font_group = make_number (0);
467
      if (c >= 0)
468 469
	char_table_set_range (fontset, from, to, font_group);
      return font_group;
470
    }
471 472
  if (!VECTORP (font_group))
    return font_group;
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
  font_group = Fcopy_sequence (font_group);
  for (i = 0; i < ASIZE (font_group); i++)
    if (! NILP (AREF (font_group, i)))
      {
	Lisp_Object rfont_def;

	RFONT_DEF_NEW (rfont_def, AREF (font_group, i));
	/* Remember the original order.  */
	RFONT_DEF_SET_SCORE (rfont_def, i);
	ASET (font_group, i, rfont_def);
      }
  font_group = Fcons (make_number (-1), font_group);
  if (c >= 0)
    char_table_set_range (fontset, from, to, font_group);
  else
    FONTSET_FALLBACK (fontset) = font_group;
  return font_group;
490 491
}

492
/* Return RFONT-DEF (vector) in the realized fontset FONTSET for the
493 494 495 496 497 498 499
   character C.  If no font is found, return Qnil if there's a
   possibility that the default fontset or the fallback font groups
   have a proper font, and return Qt if not.

   If a font is found but is not yet opened, open it (if FACE is not
   NULL) or return Qnil (if FACE is NULL).

500 501
   ID is a charset-id that must be preferred, or -1 meaning no
   preference.
502

503
   If FALLBACK is nonzero, search only fallback fonts.  */
504

505
static Lisp_Object
506
fontset_find_font (Lisp_Object fontset, int c, struct face *face, int id, int fallback)
507
{
508
  Lisp_Object vec, font_group;
509
  int i, charset_matched = 0, found_index;
510 511
  FRAME_PTR f = (FRAMEP (FONTSET_FRAME (fontset))
		 ? XFRAME (FONTSET_FRAME (fontset)) : XFRAME (selected_frame));
512
  Lisp_Object rfont_def;
513

514 515
  font_group = fontset_get_font_group (fontset, fallback ? -1 : c);
  if (! CONSP (font_group))
516
    return font_group;
517 518 519
  vec = XCDR (font_group);
  if (ASIZE (vec) == 0)
    return Qnil;
520

521
  if (ASIZE (vec) > 1)
522
    {
523 524 525 526 527 528 529 530 531
      if (XINT (XCAR (font_group)) != charset_ordered_list_tick)
	/* We have just created the font-group,
	   or the charset priorities were changed.  */
	reorder_font_vector (font_group, face->ascii_face->font);
      if (id >= 0)
	/* Find a spec matching with the charset ID to try at
	   first.  */
	for (i = 0; i < ASIZE (vec); i++)
	  {
532 533
	    Lisp_Object repertory;

534
	    rfont_def = AREF (vec, i);
535 536 537
	    if (NILP (rfont_def))
	      break;
	    repertory = FONT_DEF_REPERTORY (RFONT_DEF_FONT_DEF (rfont_def));
538 539

	    if (XINT (repertory) == id)
540
	      {
541
		charset_matched = i;
542
		break;
543 544
	      }
	  }
545
    }
546

547
  /* Find the first available font in the vector of RFONT-DEF.  */
548
  for (i = 0; i < ASIZE (vec); i++)
549
    {
550
      Lisp_Object font_def;
551
      Lisp_Object font_entity, font_object;
552

553
      found_index = i;
554
      if (i == 0)
555
	{
556 557
	  if (charset_matched > 0)
	    {
558 559 560 561
	      /* Try the element matching with the charset ID at first.  */
	      found_index = charset_matched;
	      /* Make this negative so that we don't come here in the
		 next loop.  */
562
	      charset_matched = - charset_matched;
563
	      /* We must try the first element in the next loop.  */
564 565
	      i--;
	    }
566
	}
567
      else if (i == - charset_matched)
568 569
	{
	  /* We have already tried this element and the followings
570 571
	     that have the same font specifications in the first
	     iteration.  So, skip them all.  */
572 573 574 575 576 577 578 579 580 581 582 583
	  rfont_def = AREF (vec, i);
	  font_def = RFONT_DEF_FONT_DEF (rfont_def);
	  for (; i + 1 < ASIZE (vec); i++)
	    {
	      rfont_def = AREF (vec, i + 1);
	      if (NILP (rfont_def))
		break;
	      if (! EQ (RFONT_DEF_FONT_DEF (rfont_def), font_def))
		break;
	    }
	  continue;
	}
584

585
      rfont_def = AREF (vec, found_index);
586
      if (NILP (rfont_def))
587
	{
588
	  if (i < 0)
589 590 591 592
	    continue;
	  /* This is a sign of not to try the other fonts.  */
	  return Qt;
	}
593 594
      if (INTEGERP (RFONT_DEF_FACE (rfont_def))
	  && XINT (RFONT_DEF_FACE (rfont_def)) < 0)
595 596 597
	/* We couldn't open this font last time.  */
	continue;

598
      font_object = RFONT_DEF_OBJECT (rfont_def);
599
      if (NILP (font_object))
Kenichi Handa's avatar
Kenichi Handa committed
600
	{
601
	  font_def = RFONT_DEF_FONT_DEF (rfont_def);
602

603 604 605
	  if (! face)
	    /* We have not yet opened the font.  */
	    return Qnil;
606 607 608 609
	  /* Find a font best-matching with the spec without checking
	     the support of the character C.  That checking is costly,
	     and even without the checking, the found font supports C
	     in high possibility.  */
610 611
	  font_entity = font_find_for_lface (f, face->lface,
					     FONT_DEF_SPEC (font_def), -1);
612
	  if (NILP (font_entity))
613
	    {
614
	      /* Record that no font matches the spec.  */
615
	      RFONT_DEF_SET_FACE (rfont_def, -1);
616
	      continue;
617
	    }
618 619
	  font_object = font_open_for_lface (f, font_entity, face->lface,
					     FONT_DEF_SPEC (font_def));
620
	  if (NILP (font_object))
621
	    {
622 623
	      /* Something strange happened, perhaps because of a
		 Font-backend problem.  Too avoid crashing, record
Paul Eggert's avatar
Paul Eggert committed
624
		 that this spec is unusable.  It may be better to find
625 626 627
		 another font of the same spec, but currently we don't
		 have such an API.  */
	      RFONT_DEF_SET_FACE (rfont_def, -1);
628
	      continue;
Kenichi Handa's avatar
Kenichi Handa committed
629
	    }
630
	  RFONT_DEF_SET_OBJECT (rfont_def, font_object);
Kenichi Handa's avatar
Kenichi Handa committed
631
	}
Juanma Barranquero's avatar
Juanma Barranquero committed
632

633
      if (font_has_char (f, font_object, c))
634
	goto found;
635

Paul Eggert's avatar
Paul Eggert committed
636
      /* Find a font already opened, matching with the current spec,
637 638
	 and supporting C. */
      font_def = RFONT_DEF_FONT_DEF (rfont_def);
639
      for (; found_index + 1 < ASIZE (vec); found_index++)
640
	{
641
	  rfont_def = AREF (vec, found_index + 1);
642
	  if (NILP (rfont_def))
643
	    break;
644
	  if (! EQ (RFONT_DEF_FONT_DEF (rfont_def), font_def))
645
	    break;
646
	  font_object = RFONT_DEF_OBJECT (rfont_def);
647
	  if (! NILP (font_object) && font_has_char (f, font_object, c))
648 649 650 651
	    {
	      found_index++;
	      goto found;
	    }
652
	}
653 654

      /* Find a font-entity with the current spec and supporting C.  */
655 656 657
      font_entity = font_find_for_lface (f, face->lface,
					 FONT_DEF_SPEC (font_def), c);
      if (! NILP (font_entity))
658
	{
659 660 661
	  /* We found a font.  Open it and insert a new element for
	     that font in VEC.  */
	  Lisp_Object new_vec;
662
	  int j;
663

664 665
	  font_object = font_open_for_lface (f, font_entity, face->lface,
					     Qnil);
666 667
	  if (NILP (font_object))
	    continue;
668 669
	  RFONT_DEF_NEW (rfont_def, font_def);
	  RFONT_DEF_SET_OBJECT (rfont_def, font_object);
670
	  RFONT_DEF_SET_SCORE (rfont_def, RFONT_DEF_SCORE (rfont_def));
671
	  new_vec = Fmake_vector (make_number (ASIZE (vec) + 1), Qnil);
672 673
	  found_index++;
	  for (j = 0; j < found_index; j++)
674 675 676 677
	    ASET (new_vec, j, AREF (vec, j));
	  ASET (new_vec, j, rfont_def);
	  for (j++; j < ASIZE (new_vec); j++)
	    ASET (new_vec, j, AREF (vec, j - 1));
678
	  XSETCDR (font_group, new_vec);
679 680
	  vec = new_vec;
	  goto found;
681
	}
682 683
      if (i >= 0)
	i = found_index;
684
    }
685

686
  FONTSET_SET (fontset, make_number (c), make_number (0));
687
  return Qnil;
688 689 690 691 692 693 694 695 696 697 698 699 700

 found:
  if (fallback && found_index > 0)
    {
      /* The order of fonts in the fallback font-group is not that
	 important, and it is better to move the found font to the
	 first of the group so that the next try will find it
	 quickly. */
      for (i = found_index; i > 0; i--)
	ASET (vec, i, AREF (vec, i - 1));
      ASET (vec, 0, rfont_def);
    }
  return rfont_def;
701
}
702

703

704
static Lisp_Object
705
fontset_font (Lisp_Object fontset, int c, struct face *face, int id)
706
{
707
  Lisp_Object rfont_def, default_rfont_def IF_LINT (= Qnil);
708
  Lisp_Object base_fontset;
709

710
  /* Try a font-group of FONTSET. */
711
  FONT_DEFERRED_LOG ("current fontset: font for", make_number (c), Qnil);
712
  rfont_def = fontset_find_font (fontset, c, face, id, 0);
713 714
  if (VECTORP (rfont_def))
    return rfont_def;
715 716
  if (NILP (rfont_def))
    FONTSET_SET (fontset, make_number (c), make_number (0));
717 718 719 720 721 722 723 724

  /* Try a font-group of the default fontset. */
  base_fontset = FONTSET_BASE (fontset);
  if (! EQ (base_fontset, Vdefault_fontset))
    {
      if (NILP (FONTSET_DEFAULT (fontset)))
	FONTSET_DEFAULT (fontset)
	  = make_fontset (FONTSET_FRAME (fontset), Qnil, Vdefault_fontset);
725
      FONT_DEFERRED_LOG ("default fontset: font for", make_number (c), Qnil);
726 727 728 729 730 731 732
      default_rfont_def
	= fontset_find_font (FONTSET_DEFAULT (fontset), c, face, id, 0);
      if (VECTORP (default_rfont_def))
	return default_rfont_def;
      if (NILP (default_rfont_def))
	FONTSET_SET (FONTSET_DEFAULT (fontset), make_number (c),
		     make_number (0));
733 734 735
    }

  /* Try a fallback font-group of FONTSET. */
736 737 738 739 740 741 742 743 744
  if (! EQ (rfont_def, Qt))
    {
      FONT_DEFERRED_LOG ("current fallback: font for", make_number (c), Qnil);
      rfont_def = fontset_find_font (fontset, c, face, id, 1);
      if (VECTORP (rfont_def))
	return rfont_def;
      /* Remember that FONTSET has no font for C.  */
      FONTSET_SET (fontset, make_number (c), Qt);
    }
745

746 747 748
  /* Try a fallback font-group of the default fontset. */
  if (! EQ (base_fontset, Vdefault_fontset)
      && ! EQ (default_rfont_def, Qt))
749
    {
750
      FONT_DEFERRED_LOG ("default fallback: font for", make_number (c), Qnil);
751 752 753
      rfont_def = fontset_find_font (FONTSET_DEFAULT (fontset), c, face, id, 1);
      if (VECTORP (rfont_def))
	return rfont_def;
754 755
      /* Remember that the default fontset has no font for C.  */
      FONTSET_SET (FONTSET_DEFAULT (fontset), make_number (c), Qt);
756 757 758
    }

  return Qnil;
759 760 761
}

/* Return a newly created fontset with NAME.  If BASE is nil, make a
Kenichi Handa's avatar
Kenichi Handa committed
762
   base fontset.  Otherwise make a realized fontset whose base is
763 764 765
   BASE.  */

static Lisp_Object
766
make_fontset (Lisp_Object frame, Lisp_Object name, Lisp_Object base)
Karl Heuer's avatar
Karl Heuer committed
767
{
768
  Lisp_Object fontset;
769 770 771 772 773 774
  int size = ASIZE (Vfontset_table);
  int id = next_fontset_id;

  /* Find a free slot in Vfontset_table.  Usually, next_fontset_id is
     the next available fontset ID.  So it is expected that this loop
     terminates quickly.  In addition, as the last element of
775
     Vfontset_table is always nil, we don't have to check the range of
776 777 778 779
     id.  */
  while (!NILP (AREF (Vfontset_table, id))) id++;

  if (id + 1 == size)
780
    Vfontset_table = larger_vector (Vfontset_table, 1, -1);
Karl Heuer's avatar
Karl Heuer committed
781

782
  fontset = Fmake_char_table (Qfontset, Qnil);
783 784

  FONTSET_ID (fontset) = make_number (id);
Kenichi Handa's avatar
Kenichi Handa committed
785 786 787 788 789 790 791 792 793 794
  if (NILP (base))
    {
      FONTSET_NAME (fontset) = name;
    }
  else
    {
      FONTSET_NAME (fontset) = Qnil;
      FONTSET_FRAME (fontset) = frame;
      FONTSET_BASE (fontset) = base;
    }
795

Kenichi Handa's avatar
Kenichi Handa committed
796
  ASET (Vfontset_table, id, fontset);
797 798
  next_fontset_id = id + 1;
  return fontset;
Karl Heuer's avatar
Karl Heuer committed
799 800
}

801

802
/********** INTERFACES TO xfaces.c, xfns.c, and dispextern.h **********/
803

804
/* Return the name of the fontset who has ID.  */
805 806

Lisp_Object
807
fontset_name (int id)
808 809
{
  Lisp_Object fontset;
Kenichi Handa's avatar
Kenichi Handa committed
810

811 812 813 814 815
  fontset = FONTSET_FROM_ID (id);
  return FONTSET_NAME (fontset);
}


816
/* Return the ASCII font name of the fontset who has ID.  */
817 818

Lisp_Object
819
fontset_ascii (int id)
820 821
{
  Lisp_Object fontset, elt;
Kenichi Handa's avatar
Kenichi Handa committed
822

823 824
  fontset= FONTSET_FROM_ID (id);
  elt = FONTSET_ASCII (fontset);
Kenichi Handa's avatar
Kenichi Handa committed
825 826
  if (CONSP (elt))
    elt = XCAR (elt);
827
  return elt;
828 829
}

830
static void
831
free_realized_fontset (FRAME_PTR f, Lisp_Object fontset)
Kenichi Handa's avatar
Kenichi Handa committed
832
{
833
#if 0
Kenichi Handa's avatar
Kenichi Handa committed
834 835
  Lisp_Object tail;

836 837 838
  if (0)
    for (tail = FONTSET_OBJLIST (fontset); CONSP (tail); tail = XCDR (tail))
      {
839
	eassert (FONT_OBJECT_P (XCAR (tail)));
840 841
	font_close_object (f, XCAR (tail));
      }
842
#endif
Kenichi Handa's avatar
Kenichi Handa committed
843
}
844

Kenichi Handa's avatar
Kenichi Handa committed
845 846
/* Free fontset of FACE defined on frame F.  Called from
   free_realized_face.  */
847

Karl Heuer's avatar
Karl Heuer committed
848
void
849
free_face_fontset (FRAME_PTR f, struct face *face)
Karl Heuer's avatar
Karl Heuer committed
850
{
851 852
  Lisp_Object fontset;

853
  fontset = FONTSET_FROM_ID (face->fontset);
854 855
  if (NILP (fontset))
    return;
856 857
  eassert (! BASE_FONTSET_P (fontset));
  eassert (f == XFRAME (FONTSET_FRAME (fontset)));
Kenichi Handa's avatar
Kenichi Handa committed
858
  free_realized_fontset (f, fontset);
859
  ASET (Vfontset_table, face->fontset, Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
860 861
  if (face->fontset < next_fontset_id)
    next_fontset_id = face->fontset;
Kenichi Handa's avatar
Kenichi Handa committed
862
  if (! NILP (FONTSET_DEFAULT (fontset)))
863
    {
Kenichi Handa's avatar
Kenichi Handa committed
864
      int id = XINT (FONTSET_ID (FONTSET_DEFAULT (fontset)));
Juanma Barranquero's avatar
Juanma Barranquero committed
865

866
      fontset = AREF (Vfontset_table, id);
867 868
      eassert (!NILP (fontset) && ! BASE_FONTSET_P (fontset));
      eassert (f == XFRAME (FONTSET_FRAME (fontset)));
Kenichi Handa's avatar
Kenichi Handa committed
869
      free_realized_fontset (f, fontset);
870 871 872 873
      ASET (Vfontset_table, id, Qnil);
      if (id < next_fontset_id)
	next_fontset_id = face->fontset;
    }
874
  face->fontset = -1;
875
}
876

877

878
#if 0
Glenn Morris's avatar
Glenn Morris committed
879
/* Return 1 if FACE is suitable for displaying character C.
880
   Otherwise return 0.  Called from the macro FACE_SUITABLE_FOR_CHAR_P
Kenichi Handa's avatar
Kenichi Handa committed
881
   when C is not an ASCII character.  */
882 883

int
884
face_suitable_for_char_p (struct face *face, int c)
885
{
886
  Lisp_Object fontset, rfont_def;
887 888

  fontset = FONTSET_FROM_ID (face->fontset);
889 890
  rfont_def = fontset_font (fontset, c, NULL, -1);
  return (VECTORP (rfont_def)
891 892
	  && INTEGERP (RFONT_DEF_FACE (rfont_def))
	  && face->id == XINT (RFONT_DEF_FACE (rfont_def)));
893
}