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

Paul Eggert's avatar
Paul Eggert committed
3
Copyright (C) 2001-2019 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 <https://www.gnu.org/licenses/>.  */
Karl Heuer's avatar
Karl Heuer committed
26 27

#include <config.h>
28
#include <stdio.h>
Paul Eggert's avatar
Paul Eggert committed
29
#include <stdlib.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"
Karl Heuer's avatar
Karl Heuer committed
34 35
#include "charset.h"
#include "frame.h"
36
#include "dispextern.h"
37
#include "fontset.h"
38 39 40
#ifdef HAVE_WINDOW_SYSTEM
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
Kenichi Handa's avatar
Kenichi Handa committed
41
#include "font.h"
Daniel Colascione's avatar
Daniel Colascione committed
42
#include "pdumper.h"
Kenichi Handa's avatar
Kenichi Handa committed
43

44 45 46
/* FONTSET

   A fontset is a collection of font related information to give
47 48 49 50 51 52 53 54 55 56 57 58 59 60
   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
61

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

65 66
   An element of a base fontset is a vector of FONT-DEFs which themselves
   are vectors of the form [ FONT-SPEC ENCODING REPERTORY ].
67

K. Handa's avatar
K. Handa committed
68 69
   An element of a realized fontset is nil, t, 0, or a cons that has
   this from:
70

K. Handa's avatar
K. Handa committed
71 72 73 74 75 76 77
	(CHARSET-ORDERED-LIST-TICK . FONT-GROUP)

   CHARSET_ORDERED_LIST_TICK is the same as charset_ordered_list_tick or -1.

   FONT-GROUP is a vector of elements that have this form:

	[ RFONT-DEF0 RFONT-DEF1 ... ]
78

79
   Each RFONT-DEFn (i.e. Realized FONT-DEF) has this form:
80

81
	[ FACE-ID FONT-DEF FONT-OBJECT SORTING-SCORE ]
82

K. Handa's avatar
K. Handa committed
83 84 85 86 87
   RFONT-DEFn are automatically reordered considering the current
   charset priority list, the current language environment, and
   priorities determined by font-backends.

   RFONT-DEFn may not be a vector in the following cases.
88

89 90
   The value nil means that we have not yet generated the above vector
   from the base of the fontset.
91

92 93
   The value t means that no font is available for the corresponding
   range of characters.
94

95 96
   The value 0 means that no font is available for the corresponding
   range of characters in this fontset, but may be available in the
K. Handa's avatar
K. Handa committed
97
   fallback font-group or in the default fontset.
98

99
   A fontset has 8 extra slots.
100

101 102 103
   The 1st slot:
	base: the ID number of the fontset
	realized: Likewise
104

105 106 107
   The 2nd slot:
	base: the name of the fontset
	realized: nil
108

109
   The 3rd slot:
110 111
	base: the font name for ASCII characters
	realized: nil
Kenichi Handa's avatar
Kenichi Handa committed
112

113 114
   The 4th slot:
	base: nil
115
	realized: the base fontset
116

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

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

126
   The 7th slot:
127 128
	base: nil
	realized: If the base is not the default fontset, a fontset
129
		  realized from the default fontset, else nil.
130

131
   The 8th slot:
132 133
	base: Same as element value (but for fallback fonts).
	realized: Likewise.
Kenichi Handa's avatar
Kenichi Handa committed
134

135
   All fontsets are recorded in the vector Vfontset_table.
136 137 138 139


   DEFAULT FONTSET

140 141 142 143
   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.
144

145 146
   The parent of a realized fontset created for such a face that has
   no fontset is the default fontset.
147 148 149 150


   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
151
   usually use the variable name `fontset' for IDs.  But, in this
Paul Eggert's avatar
Paul Eggert committed
152
   file, we always use variable name `id' for IDs, and name `fontset'
153
   for an actual fontset object, i.e., char-table.
154 155 156 157 158 159 160 161

*/

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

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

162
/* Next possibly free fontset ID.  Usually this keeps the minimum
163 164 165 166
   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
167
   font for each character.  */
168
static Lisp_Object Vdefault_fontset;
Karl Heuer's avatar
Karl Heuer committed
169

170
/* Prototype declarations for static functions.  */
171
static Lisp_Object make_fontset (Lisp_Object, Lisp_Object, Lisp_Object);
172

173
/* Return true if ID is a valid fontset id.
174
   Optimized away if ENABLE_CHECKING is not defined.  */
175

176
static bool
177
fontset_id_valid_p (int id)
178 179 180 181
{
  return (id >= 0 && id < ASIZE (Vfontset_table) - 1);
}

182 183 184 185 186 187 188


/********** 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)

189
/* Access special values of FONTSET.  */
Dmitry Antipov's avatar
Dmitry Antipov committed
190 191

#define FONTSET_ID(fontset) XCHAR_TABLE (fontset)->extras[0]
192 193 194 195 196
static void
set_fontset_id (Lisp_Object fontset, Lisp_Object id)
{
  set_char_table_extras (fontset, 0, id);
}
Kenichi Handa's avatar
Kenichi Handa committed
197

198
/* Access special values of (base) FONTSET.  */
Dmitry Antipov's avatar
Dmitry Antipov committed
199 200

#define FONTSET_NAME(fontset) XCHAR_TABLE (fontset)->extras[1]
201 202 203 204 205
static void
set_fontset_name (Lisp_Object fontset, Lisp_Object name)
{
  set_char_table_extras (fontset, 1, name);
}
Dmitry Antipov's avatar
Dmitry Antipov committed
206

Dmitry Antipov's avatar
Dmitry Antipov committed
207
#define FONTSET_ASCII(fontset) XCHAR_TABLE (fontset)->extras[2]
208 209 210
static void
set_fontset_ascii (Lisp_Object fontset, Lisp_Object ascii)
{
Dmitry Antipov's avatar
Dmitry Antipov committed
211
  set_char_table_extras (fontset, 2, ascii);
212
}
Kenichi Handa's avatar
Kenichi Handa committed
213

214
/* Access special values of (realized) FONTSET.  */
Dmitry Antipov's avatar
Dmitry Antipov committed
215

Dmitry Antipov's avatar
Dmitry Antipov committed
216
#define FONTSET_BASE(fontset) XCHAR_TABLE (fontset)->extras[3]
217 218 219
static void
set_fontset_base (Lisp_Object fontset, Lisp_Object base)
{
Dmitry Antipov's avatar
Dmitry Antipov committed
220
  set_char_table_extras (fontset, 3, base);
221
}
Dmitry Antipov's avatar
Dmitry Antipov committed
222

Dmitry Antipov's avatar
Dmitry Antipov committed
223
#define FONTSET_FRAME(fontset) XCHAR_TABLE (fontset)->extras[4]
224 225 226
static void
set_fontset_frame (Lisp_Object fontset, Lisp_Object frame)
{
Dmitry Antipov's avatar
Dmitry Antipov committed
227
  set_char_table_extras (fontset, 4, frame);
228
}
Dmitry Antipov's avatar
Dmitry Antipov committed
229 230

#define FONTSET_NOFONT_FACE(fontset) XCHAR_TABLE (fontset)->extras[5]
231 232 233 234 235
static void
set_fontset_nofont_face (Lisp_Object fontset, Lisp_Object face)
{
  set_char_table_extras (fontset, 5, face);
}
Dmitry Antipov's avatar
Dmitry Antipov committed
236

Dmitry Antipov's avatar
Dmitry Antipov committed
237
#define FONTSET_DEFAULT(fontset) XCHAR_TABLE (fontset)->extras[6]
238 239 240
static void
set_fontset_default (Lisp_Object fontset, Lisp_Object def)
{
Dmitry Antipov's avatar
Dmitry Antipov committed
241
  set_char_table_extras (fontset, 6, def);
242
}
Kenichi Handa's avatar
Kenichi Handa committed
243

244
/* For both base and realized fontset.  */
245

Dmitry Antipov's avatar
Dmitry Antipov committed
246
#define FONTSET_FALLBACK(fontset) XCHAR_TABLE (fontset)->extras[7]
247 248 249
static void
set_fontset_fallback (Lisp_Object fontset, Lisp_Object fallback)
{
Dmitry Antipov's avatar
Dmitry Antipov committed
250
  set_char_table_extras (fontset, 7, fallback);
251
}
252

Dmitry Antipov's avatar
Dmitry Antipov committed
253
#define BASE_FONTSET_P(fontset) (NILP (FONTSET_BASE (fontset)))
254

255 256 257
/* Macros for FONT-DEF and RFONT-DEF of fontset.  */
#define FONT_DEF_NEW(font_def, font_spec, encoding, repertory)	\
  do {								\
258 259
    (font_def) = make_uninit_vector (3);			\
    ASET ((font_def), 0, font_spec);				\
260 261 262 263 264 265 266 267 268 269
    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)	\
270
  ASET ((rfont_def), 0, make_fixnum (face_id))
271 272 273 274 275
#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))
276 277 278 279
/* 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.  */
Tom Tromey's avatar
Tom Tromey committed
280
#define RFONT_DEF_SCORE(rfont_def) XFIXNUM (AREF (rfont_def, 3))
281
#define RFONT_DEF_SET_SCORE(rfont_def, score) \
282
  ASET ((rfont_def), 3, make_fixnum (score))
283 284
#define RFONT_DEF_NEW(rfont_def, font_def)		\
  do {							\
285 286 287 288
    (rfont_def) = make_nil_vector (4);			\
    ASET (rfont_def, 1, font_def);			\
    RFONT_DEF_SET_SCORE (rfont_def, 0);			\
  } while (false)
289 290


291 292 293 294
/* 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.  */
295

296 297 298 299
#define FONTSET_REF(fontset, c)		\
  (EQ (fontset, Vdefault_fontset)	\
   ? CHAR_TABLE_REF (fontset, c)	\
   : fontset_ref ((fontset), (c)))
300

301
static Lisp_Object
302
fontset_ref (Lisp_Object fontset, int c)
303
{
Kenichi Handa's avatar
Kenichi Handa committed
304 305
  Lisp_Object elt;

306 307 308 309 310
  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);
311 312 313
  return elt;
}

314 315 316 317 318 319 320
/* 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))

321

322
/* Modify the elements of FONTSET for characters in RANGE by replacing
323
   with ELT or adding ELT.  RANGE is a cons (FROM . TO), where FROM
324 325 326 327
   and TO are character codes specifying a range.  If ADD is nil,
   replace with ELT, if ADD is `prepend', prepend ELT, otherwise,
   append ELT.  */

Dmitry Antipov's avatar
Dmitry Antipov committed
328 329 330
#define FONTSET_ADD(fontset, range, elt, add)				\
  (NILP (add)								\
   ? (NILP (range)							\
331 332
      ? set_fontset_fallback (fontset, make_vector (1, elt))		\
      : (void) Fset_char_table_range (fontset, range, make_vector (1, elt))) \
333
   : fontset_add ((fontset), (range), (elt), (add)))
334

335
static void
336
fontset_add (Lisp_Object fontset, Lisp_Object range, Lisp_Object elt, Lisp_Object add)
Kenichi Handa's avatar
Kenichi Handa committed
337
{
Kenichi Handa's avatar
Kenichi Handa committed
338 339 340
  Lisp_Object args[2];
  int idx = (EQ (add, Qappend) ? 0 : 1);

341
  args[1 - idx] = make_vector (1, elt);
Kenichi Handa's avatar
Kenichi Handa committed
342 343 344

  if (CONSP (range))
    {
Tom Tromey's avatar
Tom Tromey committed
345 346
      int from = XFIXNUM (XCAR (range));
      int to = XFIXNUM (XCDR (range));
Kenichi Handa's avatar
Kenichi Handa committed
347 348 349
      int from1, to1;

      do {
350
	from1 = from, to1 = to;
Kenichi Handa's avatar
Kenichi Handa committed
351 352
	args[idx] = char_table_ref_and_range (fontset, from, &from1, &to1);
	char_table_set_range (fontset, from, to1,
353 354
			      (NILP (args[idx]) ? args[1 - idx]
			       : CALLMANY (Fvconcat, args)));
Kenichi Handa's avatar
Kenichi Handa committed
355 356 357 358 359 360
	from = to1 + 1;
      } while (from < to);
    }
  else
    {
      args[idx] = FONTSET_FALLBACK (fontset);
361 362 363
      set_fontset_fallback (fontset,
			    (NILP (args[idx]) ? args[1 - idx]
			     : CALLMANY (Fvconcat, args)));
Kenichi Handa's avatar
Kenichi Handa committed
364
    }
365 366
}

367
static int
368
fontset_compare_rfontdef (const void *val1, const void *val2)
369
{
370 371
  return (RFONT_DEF_SCORE (*(Lisp_Object *) val1)
	  - RFONT_DEF_SCORE (*(Lisp_Object *) val2));
372
}
373

374 375 376 377
/* Update a cons cell which has this form:
	(CHARSET-ORDERED-LIST-TICK . FONT-GROUP)
   where FONT-GROUP is of the form
	[ PREFERRED-RFONT-DEF RFONT-DEF0 RFONT-DEF1 ... ]
Juanma Barranquero's avatar
Juanma Barranquero committed
378
   Reorder RFONT-DEFs according to the current language, and update
379
   CHARSET-ORDERED-LIST-TICK.  */
380

381
static void
382
reorder_font_vector (Lisp_Object font_group, struct font *font)
383
{
384
  Lisp_Object vec, font_object;
385
  int size;
386
  int i;
387
  bool score_changed = false;
388

389 390 391 392 393 394 395 396 397 398
  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--;
399 400

  for (i = 0; i < size; i++)
401
    {
402
      Lisp_Object rfont_def = AREF (vec, i);
403 404
      Lisp_Object font_def = RFONT_DEF_FONT_DEF (rfont_def);
      Lisp_Object font_spec = FONT_DEF_SPEC (font_def);
405
      int score = RFONT_DEF_SCORE (rfont_def) & 0xFF;
406
      Lisp_Object otf_spec = Ffont_get (font_spec, QCotf);
407

408 409 410 411 412
      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
413
	{
414
	  Lisp_Object encoding = FONT_DEF_ENCODING (font_def);
415

416
	  if (! NILP (encoding))
417
	    {
K. Handa's avatar
K. Handa committed
418 419 420
	      /* This spec specifies an encoding by a charset set
		 name.  Reflect the preference order of that charset
		 in the upper bits of SCORE.  */
421
	      Lisp_Object tail;
422

423 424
	      for (tail = Vcharset_ordered_list;
		   ! EQ (tail, Vcharset_non_preferred_head) && CONSP (tail);
425
		   tail = XCDR (tail))
426
		if (EQ (encoding, XCAR (tail)))
427
		  break;
428
		else if (score <= min (INT_MAX, MOST_POSITIVE_FIXNUM) - 0x100)
429
		  score += 0x100;
430 431 432
	    }
	  else
	    {
K. Handa's avatar
K. Handa committed
433 434 435 436
	      /* This spec does not specify an encoding.  If the spec
		 specifies a language, and the language is not for the
		 current language environment, make the score
		 larger.  */
437 438 439 440 441 442 443 444
	      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;
	    }
445
	}
446
      if (RFONT_DEF_SCORE (rfont_def) != score)
447
	{
448
	  RFONT_DEF_SET_SCORE (rfont_def, score);
449
	  score_changed = true;
450
	}
451
    }
452

453
  if (score_changed)
Paul Eggert's avatar
Paul Eggert committed
454
    qsort (XVECTOR (vec)->contents, size, word_size,
455
	   fontset_compare_rfontdef);
456
  EMACS_INT low_tick_bits = charset_ordered_list_tick & MOST_POSITIVE_FIXNUM;
457
  XSETCAR (font_group, make_fixnum (low_tick_bits));
458 459
}

K. Handa's avatar
K. Handa committed
460 461 462 463 464
/* Return a font-group (actually a cons (CHARSET_ORDERED_LIST_TICK
   . FONT-GROUP)) for character C or a fallback font-group in the
   realized fontset FONTSET.  The elements of FONT-GROUP are
   RFONT-DEFs.  The value may not be a cons.  See the comment at the
   head of this file for the detail of the return value.  */
465

466
static Lisp_Object
467
fontset_get_font_group (Lisp_Object fontset, int c)
468 469 470
{
  Lisp_Object font_group;
  Lisp_Object base_fontset;
471
  int from = 0, to = MAX_CHAR, i;
472

473
  eassert (! BASE_FONTSET_P (fontset));
474 475 476 477 478
  if (c >= 0)
    font_group = CHAR_TABLE_REF (fontset, c);
  else
    font_group = FONTSET_FALLBACK (fontset);
  if (! NILP (font_group))
K. Handa's avatar
K. Handa committed
479 480 481
    /* We have already realized FONT-DEFs of this font group for C or
       for fallback (FONT_GROUP is a cons), or we have already found
       that no appropriate font was found (FONT_GROUP is t or 0).  */
482 483
    return font_group;
  base_fontset = FONTSET_BASE (fontset);
484
  if (NILP (base_fontset))
K. Handa's avatar
K. Handa committed
485 486
    /* Actually we never come here because FONTSET is a realized one,
       and thus it should have a base.  */
487 488
    font_group = Qnil;
  else if (c >= 0)
489 490 491
    font_group = char_table_ref_and_range (base_fontset, c, &from, &to);
  else
    font_group = FONTSET_FALLBACK (base_fontset);
K. Handa's avatar
K. Handa committed
492 493 494

  /* FONT_GROUP not being a vector means that no fonts are specified
     for C, or the fontset does not have fallback fonts.  */
495
  if (NILP (font_group))
496
    {
497
      font_group = make_fixnum (0);
498
      if (c >= 0)
K. Handa's avatar
K. Handa committed
499
	/* Record that FONTSET does not specify fonts for C.  As
Paul Eggert's avatar
Paul Eggert committed
500
	   there's a possibility that a font is found in a fallback
K. Handa's avatar
K. Handa committed
501
	   font group, we set 0 at the moment.  */
502 503
	char_table_set_range (fontset, from, to, font_group);
      return font_group;
504
    }
505 506
  if (!VECTORP (font_group))
    return font_group;
K. Handa's avatar
K. Handa committed
507 508 509

  /* Now realize FONT-DEFs of this font group, and update the realized
     fontset FONTSET. */
510 511 512 513 514 515 516 517 518 519 520
  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);
      }
521
  font_group = Fcons (make_fixnum (-1), font_group);
522 523 524
  if (c >= 0)
    char_table_set_range (fontset, from, to, font_group);
  else
525
    set_fontset_fallback (fontset, font_group);
526
  return font_group;
527 528
}

529
/* Return RFONT-DEF (vector) in the realized fontset FONTSET for the
K. Handa's avatar
K. Handa committed
530
   character C.  If no font is found, return Qnil or 0 if there's a
531 532 533 534 535 536
   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).

K. Handa's avatar
K. Handa committed
537
   CHARSET_ID is a charset-id that must be preferred, or -1 meaning no
538
   preference.
539

540
   If FALLBACK, search only fallback fonts.  */
541

542
static Lisp_Object
Paul Eggert's avatar
Paul Eggert committed
543
fontset_find_font (Lisp_Object fontset, int c, struct face *face,
K. Handa's avatar
K. Handa committed
544
		   int charset_id, bool fallback)
545
{
546
  Lisp_Object vec, font_group;
547
  int i, charset_matched = 0, found_index;
Dmitry Antipov's avatar
Dmitry Antipov committed
548 549 550
  struct frame *f = (FRAMEP (FONTSET_FRAME (fontset))
		     ? XFRAME (FONTSET_FRAME (fontset))
		     : XFRAME (selected_frame));
551
  Lisp_Object rfont_def;
552

553 554
  font_group = fontset_get_font_group (fontset, fallback ? -1 : c);
  if (! CONSP (font_group))
555
    return font_group;
556 557 558
  vec = XCDR (font_group);
  if (ASIZE (vec) == 0)
    return Qnil;
559

560
  if (ASIZE (vec) > 1)
561
    {
Tom Tromey's avatar
Tom Tromey committed
562
      if (XFIXNUM (XCAR (font_group)) != charset_ordered_list_tick)
563 564 565
	/* We have just created the font-group,
	   or the charset priorities were changed.  */
	reorder_font_vector (font_group, face->ascii_face->font);
K. Handa's avatar
K. Handa committed
566 567
      if (charset_id >= 0)
	/* Find a spec matching with CHARSET_ID to try it at
568 569 570
	   first.  */
	for (i = 0; i < ASIZE (vec); i++)
	  {
571 572
	    Lisp_Object repertory;

573
	    rfont_def = AREF (vec, i);
574 575 576
	    if (NILP (rfont_def))
	      break;
	    repertory = FONT_DEF_REPERTORY (RFONT_DEF_FONT_DEF (rfont_def));
577

Tom Tromey's avatar
Tom Tromey committed
578
	    if (XFIXNUM (repertory) == charset_id)
579
	      {
580
		charset_matched = i;
581
		break;
582 583
	      }
	  }
584
    }
585

K. Handa's avatar
K. Handa committed
586
  /* Find the first available font in the vector of RFONT-DEF.  If
Paul Eggert's avatar
Paul Eggert committed
587
     CHARSET_MATCHED > 0, try the corresponding RFONT-DEF first, then
K. Handa's avatar
K. Handa committed
588
     try the rest.  */
589
  for (i = 0; i < ASIZE (vec); i++)
590
    {
591
      Lisp_Object font_def;
592
      Lisp_Object font_entity, font_object;
593

594
      found_index = i;
595
      if (i == 0)
596
	{
597 598
	  if (charset_matched > 0)
	    {
K. Handa's avatar
K. Handa committed
599
	      /* Try the element matching with CHARSET_ID at first.  */
600 601 602
	      found_index = charset_matched;
	      /* Make this negative so that we don't come here in the
		 next loop.  */
603
	      charset_matched = - charset_matched;
604
	      /* We must try the first element in the next loop.  */
K. Handa's avatar
K. Handa committed
605
	      i = -1;
606
	    }
607
	}
608
      else if (i == - charset_matched)
609 610
	{
	  /* We have already tried this element and the followings
611 612
	     that have the same font specifications in the first
	     iteration.  So, skip them all.  */
613 614 615 616 617 618 619 620 621 622 623 624
	  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;
	}
625

626
      rfont_def = AREF (vec, found_index);
627
      if (NILP (rfont_def))
628
	{
629
	  if (i < 0)
630 631 632 633
	    continue;
	  /* This is a sign of not to try the other fonts.  */
	  return Qt;
	}
634
      if (FIXNUMP (RFONT_DEF_FACE (rfont_def))
Tom Tromey's avatar
Tom Tromey committed
635
	  && XFIXNUM (RFONT_DEF_FACE (rfont_def)) < 0)
636 637 638
	/* We couldn't open this font last time.  */
	continue;

639
      font_object = RFONT_DEF_OBJECT (rfont_def);
640
      if (NILP (font_object))
Kenichi Handa's avatar
Kenichi Handa committed
641
	{
642
	  font_def = RFONT_DEF_FONT_DEF (rfont_def);
643

644 645 646
	  if (! face)
	    /* We have not yet opened the font.  */
	    return Qnil;
647 648 649 650
	  /* 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.  */
651 652
	  font_entity = font_find_for_lface (f, face->lface,
					     FONT_DEF_SPEC (font_def), -1);
653
	  if (NILP (font_entity))
654
	    {
655
	      /* Record that no font matches the spec.  */
656
	      RFONT_DEF_SET_FACE (rfont_def, -1);
657
	      continue;
658
	    }
659 660
	  font_object = font_open_for_lface (f, font_entity, face->lface,
					     FONT_DEF_SPEC (font_def));
661
	  if (NILP (font_object))
662
	    {
663
	      /* Something strange happened, perhaps because of a
K. Handa's avatar
K. Handa committed
664
		 Font-backend problem.  To avoid crashing, record
Paul Eggert's avatar
Paul Eggert committed
665
		 that this spec is unusable.  It may be better to find
666
		 another font of the same spec, but currently we don't
K. Handa's avatar
K. Handa committed
667
		 have such an API in font-backend.  */
668
	      RFONT_DEF_SET_FACE (rfont_def, -1);
669
	      continue;
Kenichi Handa's avatar
Kenichi Handa committed
670
	    }
671
	  RFONT_DEF_SET_OBJECT (rfont_def, font_object);
Kenichi Handa's avatar
Kenichi Handa committed
672
	}
Juanma Barranquero's avatar
Juanma Barranquero committed
673

674
      if (font_has_char (f, font_object, c))
675
	goto found;
676

Paul Eggert's avatar
Paul Eggert committed
677
      /* Find a font already opened, matching with the current spec,
678 679
	 and supporting C. */
      font_def = RFONT_DEF_FONT_DEF (rfont_def);
680
      for (; found_index + 1 < ASIZE (vec); found_index++)
681
	{
682
	  rfont_def = AREF (vec, found_index + 1);
683
	  if (NILP (rfont_def))
684
	    break;
685
	  if (! EQ (RFONT_DEF_FONT_DEF (rfont_def), font_def))
686
	    break;
687
	  font_object = RFONT_DEF_OBJECT (rfont_def);
688
	  if (! NILP (font_object) && font_has_char (f, font_object, c))
689 690 691 692
	    {
	      found_index++;
	      goto found;
	    }
693
	}
694 695

      /* Find a font-entity with the current spec and supporting C.  */
696 697 698
      font_entity = font_find_for_lface (f, face->lface,
					 FONT_DEF_SPEC (font_def), c);
      if (! NILP (font_entity))
699
	{
700 701
	  /* We found a font.  Open it and insert a new element for
	     that font in VEC.  */
702
	  int j;
703

704 705
	  font_object = font_open_for_lface (f, font_entity, face->lface,
					     Qnil);
706 707
	  if (NILP (font_object))
	    continue;
708 709
	  RFONT_DEF_NEW (rfont_def, font_def);
	  RFONT_DEF_SET_OBJECT (rfont_def, font_object);
710
	  RFONT_DEF_SET_SCORE (rfont_def, RFONT_DEF_SCORE (rfont_def));
711
	  Lisp_Object new_vec = make_nil_vector (ASIZE (vec) + 1);
712 713
	  found_index++;
	  for (j = 0; j < found_index; j++)
714 715 716 717
	    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));
718
	  XSETCDR (font_group, new_vec);
719 720
	  vec = new_vec;
	  goto found;
721
	}
722 723
      if (i >= 0)
	i = found_index;
724
    }
725

K. Handa's avatar
K. Handa committed
726
  /* Record that no font in this font group supports C.  */
727
  FONTSET_SET (fontset, make_fixnum (c), make_fixnum (0));
728
  return Qnil;
729 730 731 732 733 734 735 736 737 738 739 740 741

 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;
742
}
743

744

K. Handa's avatar
K. Handa committed
745 746 747
/* Return RFONT-DEF (vector) corresponding to the font for character
   C.  The value is not a vector if no font is found for C.  */

748
static Lisp_Object
749
fontset_font (Lisp_Object fontset, int c, struct face *face, int id)
750
{
751 752
  Lisp_Object rfont_def;
  Lisp_Object default_rfont_def UNINIT;
753
  Lisp_Object base_fontset;
754

755
  /* Try a font-group of FONTSET. */
756
  FONT_DEFERRED_LOG ("current fontset: font for", make_fixnum (c), Qnil);
757
  rfont_def = fontset_find_font (fontset, c, face, id, 0);
758 759
  if (VECTORP (rfont_def))
    return rfont_def;
760
  if (NILP (rfont_def))
761
    FONTSET_SET (fontset, make_fixnum (c), make_fixnum (0));
762 763 764 765 766 767

  /* Try a font-group of the default fontset. */
  base_fontset = FONTSET_BASE (fontset);
  if (! EQ (base_fontset, Vdefault_fontset))
    {
      if (NILP (FONTSET_DEFAULT (fontset)))
768
	set_fontset_default
Dmitry Antipov's avatar
Dmitry Antipov committed
769 770
	  (fontset,
	   make_fontset (FONTSET_FRAME (fontset), Qnil, Vdefault_fontset));
771
      FONT_DEFERRED_LOG ("default fontset: font for", make_fixnum (c), Qnil);
772 773 774 775 776
      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))
777 778
	FONTSET_SET (FONTSET_DEFAULT (fontset), make_fixnum (c),
		     make_fixnum (0));
779 780 781
    }

  /* Try a fallback font-group of FONTSET. */
782 783
  if (! EQ (rfont_def, Qt))
    {
784
      FONT_DEFERRED_LOG ("current fallback: font for", make_fixnum (c), Qnil);
785 786 787 788
      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.  */
789
      FONTSET_SET (fontset, make_fixnum (c), Qt);
790
    }
791

792 793 794
  /* Try a fallback font-group of the default fontset. */
  if (! EQ (base_fontset, Vdefault_fontset)
      && ! EQ (default_rfont_def, Qt))
795
    {
796
      FONT_DEFERRED_LOG ("default fallback: font for", make_fixnum (c), Qnil);
797 798 799
      rfont_def = fontset_find_font (FONTSET_DEFAULT (fontset), c, face, id, 1);
      if (VECTORP (rfont_def))
	return rfont_def;
800
      /* Remember that the default fontset has no font for C.  */
801
      FONTSET_SET (FONTSET_DEFAULT (fontset), make_fixnum (c), Qt);
802 803 804
    }

  return Qnil;
805 806 807
}

/* Return a newly created fontset with NAME.  If BASE is nil, make a
Kenichi Handa's avatar
Kenichi Handa committed
808
   base fontset.  Otherwise make a realized fontset whose base is
809 810 811
   BASE.  */

static Lisp_Object
812
make_fontset (Lisp_Object frame, Lisp_Object name, Lisp_Object base)
Karl Heuer's avatar
Karl Heuer committed
813
{
814
  Lisp_Object fontset;
815 816 817 818 819 820
  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
821
     Vfontset_table is always nil, we don't have to check the range of
822 823 824 825
     id.  */
  while (!NILP (AREF (Vfontset_table, id))) id++;

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

828
  fontset = Fmake_char_table (Qfontset, Qnil);
829

830
  set_fontset_id (fontset, make_fixnum (id));
Kenichi Handa's avatar
Kenichi Handa committed
831
  if (NILP (base))
832
    set_fontset_name (fontset, name);
Kenichi Handa's avatar
Kenichi Handa committed
833 834
  else
    {
835 836 837
      set_fontset_name (fontset, Qnil);
      set_fontset_frame (fontset, frame);
      set_fontset_base (fontset, base);
Kenichi Handa's avatar
Kenichi Handa committed
838
    }