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-2020 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
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.
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

207
#define FONTSET_ASCII(fontset) XCHAR_TABLE (fontset)->extras[2]
208 209 210
static void
set_fontset_ascii (Lisp_Object fontset, Lisp_Object ascii)
{
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

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

223
#define FONTSET_FRAME(fontset) XCHAR_TABLE (fontset)->extras[4]
224 225 226
static void
set_fontset_frame (Lisp_Object fontset, Lisp_Object frame)
{
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

237
#define FONTSET_DEFAULT(fontset) XCHAR_TABLE (fontset)->extras[6]
238 239 240
static void
set_fontset_default (Lisp_Object fontset, Lisp_Object def)
{
241
  set_char_table_extras (fontset, 6, def);
242
}
243

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

246
#define FONTSET_FALLBACK(fontset) XCHAR_TABLE (fontset)->extras[7]
247 248 249
static void
set_fontset_fallback (Lisp_Object fontset, Lisp_Object fallback)
{
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
{
338 339 340
  Lisp_Object args[2];
  int idx = (EQ (add, Qappend) ? 0 : 1);

341
  args[1 - idx] = make_vector (1, elt);
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));
347 348 349
      int from1, to1;

      do {
350
	from1 = from, to1 = to;
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)));
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)));
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 ... ]
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))
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)
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
      if (charset_id >= 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
567 568 569 570 571 572 573 574 575
	{
	  Lisp_Object lcsetid = make_fixnum (charset_id);
	  /* Find a spec matching with CHARSET_ID to try it at first.  */
	  for (i = 0; i < ASIZE (vec); i++)
	    {
	      Lisp_Object repertory;

	      rfont_def = AREF (vec, i);
	      if (NILP (rfont_def))
576
		break;
Eli Zaretskii's avatar
Eli Zaretskii committed
577 578 579 580 581 582 583 584 585
	      repertory = FONT_DEF_REPERTORY (RFONT_DEF_FONT_DEF (rfont_def));

	      if (EQ (repertory, lcsetid))
		{
		  charset_matched = i;
		  break;
		}
	    }
	}
586
    }
587

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

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

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

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

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

676
      if (font_has_char (f, font_object, c))
677
	goto found;
678

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

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

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

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

 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;
744
}
745

746

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

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

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

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

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

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

  return Qnil;
807 808 809
}

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

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

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

830
  fontset = Fmake_char_table (Qfontset, Qnil);
831

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

Kenichi Handa's avatar
Kenichi Handa committed
842
  ASET (Vfontset_table, id, fontset);
843 844
  next_fontset_id = id + 1;
  return fontset;
Karl Heuer's avatar
Karl Heuer committed
845 846
}

847

848
/********** INTERFACES TO xfaces.c, xfns.c, and dispextern.h **********/
849

850
/* Return the name of the fontset who has ID.  */
851 852

Lisp_Object
853
fontset_name (int id)
854 855
{
  Lisp_Object fontset;
Kenichi Handa's avatar
Kenichi Handa committed
856

857 858 859 860 861
  fontset = FONTSET_FROM_ID (id);
  return FONTSET_NAME (fontset);
}


862
/* Return the ASCII font name of the fontset who has ID.  */
863 864

Lisp_Object
865
fontset_ascii (int id)
866 867
{
  Lisp_Object fontset, elt;
Kenichi Handa's avatar
Kenichi Handa committed
868

869 870
  fontset= FONTSET_FROM_ID (id);
  elt = FONTSET_ASCII (fontset);
Kenichi Handa's avatar
Kenichi Handa committed
871 872
  if (CONSP (elt))
    elt = XCAR (elt);
873
  return elt;
874 875
}

Kenichi Handa's avatar
Kenichi Handa committed
876 877
/* Free fontset of FACE defined on frame F.  Called from
   free_realized_face.  */
878

Karl Heuer's avatar
Karl Heuer committed
879
void
Dmitry Antipov's avatar
Dmitry Antipov committed
880
free_face_fontset (struct frame *f, struct face *face)
Karl Heuer's avatar
Karl Heuer committed
881
{
882 883
  Lisp_Object fontset;

884
  fontset = FONTSET_FROM_ID (face->fontset);
885 886
  if (NILP (fontset))
    return;
887 888
  eassert (! BASE_FONTSET_P (fontset));
  eassert (f == XFRAME (FONTSET_FRAME (fontset)));
889
  ASET (Vfontset_table, face->fontset, Qnil);
Kenichi Handa's avatar
Kenichi Handa committed
890 891
  if (face->fontset < next_fontset_id)
    next_fontset_id = face->fontset;
892
  if (! NILP (FONTSET_DEFAULT (fontset)))
893
    {
Tom Tromey's avatar
Tom Tromey committed
894
      int id = XFIXNUM (FONTSET_ID (FONTSET_DEFAULT (fontset)));
895

896
      fontset = AREF (Vfontset_table, id);
897 898
      eassert (!NILP (fontset) && ! BASE_FONTSET_P (fontset));
      eassert (f == XFRAME (FONTSET_FRAME (fontset)));
899 900 901 902
      ASET (Vfontset_table, id, Qnil);
      if (id < next_fontset_id)
	next_fontset_id = face->fontset;
    }
903
  face->fontset = -1;
904
}
905

906 907 908
/* Return ID of face suitable for displaying character C at buffer position
   POS on frame F.  FACE must be realized for ASCII characters in advance.
   Called from the macro FACE_FOR_CHAR.  */
909 910

int
911 912
face_for_char (struct frame *f, struct face *face, int c,
	       ptrdiff_t pos, Lisp_Object object)
913
{
914
  Lisp_Object fontset, rfont_def, charset;
915
  int face_id;
916
  int id;
917

918 919 920
  eassert (fontset_id_valid_p (face->fontset));

  if (ASCII_CHAR_P (c) || CHAR_BYTE8_P (c))
921
    return face->ascii_face->id;
922

923 924
  if (use_default_font_for_symbols  /* let the user disable this feature */
      && c > 0 && EQ (CHAR_TABLE_REF (Vchar_script_table, c), Qsymbol))
925
    {
926 927 928 929 930 931 932 933 934 935 936 937 938 939
      /* Fonts often have characters for punctuation and other
         symbols, even if they don't match the 'symbol' script.  So
         check if the character is present in the current ASCII face
         first, and if so, use the same font as used by that face.
         This avoids unnecessarily switching to another font when the
         frame's default font will do.  We only do this for symbols so
         that users could still setup fontsets to force Emacs to use
         specific fonts for characters from other scripts, because
         choice of fonts is frequently affected by cultural
         preferences and font features, not by font coverage.
         However, these considerations are unlikely to be relevant to
         punctuation and other symbols, since the latter generally
         aren't specific to any culture, and don't require
         sophisticated OTF features.  */
940
      Lisp_Object font_object;