Commit 0d407d77 authored by Kenichi Handa's avatar Kenichi Handa

All codes rewritten or adjusted for the change of

fontset implementation.  Now fontset is represented by char table.
(Vglobal_fontset_alist, font_idx_temp, my_strcasetbl): Variables
(my_strcasecmp): Function removed.
(Vfontset_table, next_fontset_id, Vdefault_fontset): New
(AREF, ASIZE): New macros.
(fontset_ref, fontset_ref_via_base, fontset_set, make_fontset,
fontset_id_valid_p, font_family_registry, fontset_name,
fontset_ascii, free_face_fontset, face_suitable_for_char_p,
face_for_char, make_fontset_for_ascii_face, fontset_font_pattern):
New functions.
(fs_load_font): New arg FACE.  Caller changed.
(fs_query_fontset): Argument changed.  Caller changed.
(Fquery_fontset): call fs_query_fontset.
(fs_register_fontset, alloc_fontset_data, free_fontset_data):
Functions removed.
(clear_fontset_elements, check_registry_encoding,
check_fontset_name): New functions.
(syms_of_fontset): Set char-table-extra-slots property of fontset
to 3.  Staticpro and initialize Vfontset_table and
Vdefault_fontset.  Defsubr fontset_font and fontset_list.
parent 52ef6c89
/* Fontset handler.
Copyright (C) 1995, 1997 Electrotechnical Laboratory, JAPAN.
Copyright (C) 1995, 1997, 2000 Electrotechnical Laboratory, JAPAN.
Licensed to the Free Software Foundation.
This file is part of GNU Emacs.
......@@ -19,17 +19,121 @@ along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* #define FONTSET_DEBUG */
#include <config.h>
#include <alloca.h>
#endif /* HAVE_ALLOCA_H */
#include <stdio.h>
#include "lisp.h"
#include "charset.h"
#include "ccl.h"
#include "frame.h"
#include "dispextern.h"
#include "fontset.h"
#include "window.h"
#undef xassert
#define xassert(X) do {if (!(X)) abort ();} while (0)
#undef INLINE
#define INLINE
A fontset is a collection of font related information to give
similar appearance (style, size, etc) of characters. 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 multibyte characters based on an ASCII
face. All of the multibyte faces based on the same ASCII face
share the same realized fontset.
A fontset object is implemented by a char-table.
An element of a base fontset is:
FONTNAME is a font name pattern for the corresponding character.
FOUNDRY and REGISTRY are respectively foundy and regisry fields of
a font name for the corresponding character. INDEX specifies for
which character (or generic character) the element is defined. It
may be different from an index to access this element. For
instance, if a fontset defines some font for all characters of
charset `japanese-jisx0208', INDEX is the generic character of this
charset. REGISTRY is the
An element of a realized fontset is FACE-ID which is a face to use
for displaying the correspnding character.
All single byte charaters (ASCII and 8bit-unibyte) share the same
element in a fontset. The element is stored in `defalt' slot of
the fontset. And this slot is never used as a default value of
multibyte characters. That means that the first 256 elements of a
fontset set is always nil (as this is not efficient, we may
implement a fontset in a different way in the future).
To access or set each element, use macros FONTSET_REF and
FONTSET_SET respectively for efficiency.
A fontset has 3 extra slots.
The 1st slot is an ID number of the fontset.
The 2nd slot is a name of the fontset. This is nil for a realized
The 3rd slot is a frame that the fontset belongs to. This is nil
for a default face.
A parent of a base fontset is nil. A parent of a realized fontset
is a base fontset.
All fontsets (except for the default fontset described below) are
recorded in Vfontset_table.
There's a special fontset named `default fontset' which defines a
default fontname that contains only REGISTRY field for each
character. When a base fontset doesn't specify a font for a
specific character, the corresponding value in the default fontset
is used. The format is the same as a base fontset.
The parent of realized fontsets created for faces that have no
fontset is the default fontset.
These structures are hidden from the other codes than this file.
The other codes handle fontsets only by their ID numbers. They
usually use variable name `fontset' for IDs. But, in this file, we
always use varialbe name `id' for IDs, and name `fontset' for the
actual fontset objects.
/********** VARIABLES and FUNCTION PROTOTYPES **********/
extern Lisp_Object Qfont;
Lisp_Object Qfontset;
/* Vector containing all fontsets. */
static Lisp_Object Vfontset_table;
/* Next possibly free fontset ID. Usually this keeps the mininum
fontset ID not yet used. */
static int next_fontset_id;
/* The default fontset. This gives default FAMILY and REGISTRY of
font for each characters. */
static Lisp_Object Vdefault_fontset;
Lisp_Object Vglobal_fontset_alist;
Lisp_Object Vfont_encoding_alist;
Lisp_Object Vuse_default_ascent;
Lisp_Object Vignore_relative_composition;
......@@ -39,26 +143,9 @@ Lisp_Object Vhighlight_wrong_size_font;
Lisp_Object Vclip_large_size_font;
Lisp_Object Vvertical_centering_font_regexp;
/* Used as a temporary in macro FS_LOAD_FONT. */
int font_idx_temp;
/* We had better have our own strcasecmp function because some system
doesn't have it. */
static char my_strcasetbl[256];
/* Compare two strings S0 and S1 while ignoring differences in case.
Return 1 if they differ, else return 0. */
static int
my_strcasecmp (s0, s1)
unsigned char *s0, *s1;
while (*s0)
if (my_strcasetbl[*s0++] != my_strcasetbl[*s1++]) return 1;
return (int) *s1;
/* The following six are window system dependent functions. See
the comments in src/fontset.h for more detail. */
/* The following six are declarations of callback functions depending
on window system. See the comments in src/fontset.h for more
detail. */
/* Return a pointer to struct font_info of font FONT_IDX of frame F. */
struct font_info *(*get_font_info_func) P_ ((FRAME_PTR f, int font_idx));
......@@ -90,113 +177,462 @@ void (*find_ccl_program_func) P_ ((struct font_info *));
/* Check if any window system is used now. */
void (*check_window_system_func) P_ ((void));
struct fontset_data *
alloc_fontset_data ()
/* Prototype declarations for static functions. */
static Lisp_Object fontset_ref P_ ((Lisp_Object, int));
static void fontset_set P_ ((Lisp_Object, int, Lisp_Object));
static Lisp_Object make_fontset P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
static int fontset_id_valid_p P_ ((int));
static Lisp_Object fontset_pattern_regexp P_ ((Lisp_Object));
static Lisp_Object font_family_registry P_ ((Lisp_Object));
/* Macros for Lisp vector. */
#define AREF(V, IDX) XVECTOR (V)->contents[IDX]
#define ASIZE(V) XVECTOR (V)->size
/* Return the fontset with ID. No check of ID's validness. */
#define FONTSET_FROM_ID(id) AREF (Vfontset_table, id)
/* Macros to access extra, default, and parent slots, of fontset. */
#define FONTSET_ID(fontset) XCHAR_TABLE (fontset)->extras[0]
#define FONTSET_NAME(fontset) XCHAR_TABLE (fontset)->extras[1]
#define FONTSET_FRAME(fontset) XCHAR_TABLE (fontset)->extras[2]
#define FONTSET_ASCII(fontset) XCHAR_TABLE (fontset)->defalt
#define FONTSET_BASE(fontset) XCHAR_TABLE (fontset)->parent
#define BASE_FONTSET_P(fontset) NILP (FONTSET_BASE(fontset))
/* Return the element of FONTSET (char-table) at index C (character). */
#define FONTSET_REF(fontset, c) fontset_ref (fontset, c)
static INLINE Lisp_Object
fontset_ref (fontset, c)
Lisp_Object fontset;
int c;
int charset, c1, c2;
Lisp_Object elt, defalt;
int i;
return FONTSET_ASCII (fontset);
SPLIT_NON_ASCII_CHAR (c, charset, c1, c2);
elt = XCHAR_TABLE (fontset)->contents[charset + 128];
if (!SUB_CHAR_TABLE_P (elt))
return elt;
defalt = XCHAR_TABLE (elt)->defalt;
if (c1 < 32
|| (elt = XCHAR_TABLE (elt)->contents[c1],
NILP (elt)))
return defalt;
if (!SUB_CHAR_TABLE_P (elt))
return elt;
defalt = XCHAR_TABLE (elt)->defalt;
if (c2 < 32
|| (elt = XCHAR_TABLE (elt)->contents[c2],
NILP (elt)))
return defalt;
return elt;
#define FONTSET_REF_VIA_BASE(fontset, c) fontset_ref_via_base (fontset, &c)
static INLINE Lisp_Object
fontset_ref_via_base (fontset, c)
Lisp_Object fontset;
int *c;
int charset, c1, c2;
Lisp_Object elt;
int i;
return FONTSET_ASCII (fontset);
elt = FONTSET_REF (FONTSET_BASE (fontset), *c);
if (NILP (elt))
return Qnil;
*c = XINT (XCAR (elt));
SPLIT_NON_ASCII_CHAR (*c, charset, c1, c2);
elt = XCHAR_TABLE (fontset)->contents[charset + 128];
if (c1 < 32)
return (SUB_CHAR_TABLE_P (elt) ? XCHAR_TABLE (elt)->defalt : elt);
if (!SUB_CHAR_TABLE_P (elt))
return Qnil;
elt = XCHAR_TABLE (elt)->contents[c1];
if (c2 < 32)
return (SUB_CHAR_TABLE_P (elt) ? XCHAR_TABLE (elt)->defalt : elt);
if (!SUB_CHAR_TABLE_P (elt))
return Qnil;
elt = XCHAR_TABLE (elt)->contents[c2];
return elt;
/* Store into the element of FONTSET at index C the value NEWETL. */
#define FONTSET_SET(fontset, c, newelt) fontset_set(fontset, c, newelt)
static void
fontset_set (fontset, c, newelt)
Lisp_Object fontset;
int c;
Lisp_Object newelt;
int charset, code[3];
Lisp_Object *elt, tmp;
int i, j;
FONTSET_ASCII (fontset) = newelt;
SPLIT_NON_ASCII_CHAR (c, charset, code[0], code[1]);
code[2] = 0; /* anchor */
elt = &XCHAR_TABLE (fontset)->contents[charset + 128];
for (i = 0; code[i] > 0; i++)
if (!SUB_CHAR_TABLE_P (*elt))
*elt = make_sub_char_table (*elt);
elt = &XCHAR_TABLE (*elt)->contents[code[i]];
if (SUB_CHAR_TABLE_P (*elt))
XCHAR_TABLE (*elt)->defalt = newelt;
*elt = newelt;
/* Return a newly created fontset with NAME. If BASE is nil, make a
base fontset. Otherwise make a realized fontset whose parent is
BASE. */
static Lisp_Object
make_fontset (frame, name, base)
Lisp_Object frame, name, base;
struct fontset_data *fontset_data
= (struct fontset_data *) xmalloc (sizeof (struct fontset_data));
Lisp_Object fontset, elt, base_elt;
int size = ASIZE (Vfontset_table);
int id = next_fontset_id;
int i, j;
/* 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
Vfotnset_table is always nil, we don't have to check the range of
id. */
while (!NILP (AREF (Vfontset_table, id))) id++;
if (id + 1 == size)
Lisp_Object tem;
int i;
bzero (fontset_data, sizeof (struct fontset_data));
tem = Fmake_vector (make_number (size + 8), Qnil);
for (i = 0; i < size; i++)
AREF (tem, i) = AREF (Vfontset_table, i);
Vfontset_table = tem;
return fontset_data;
if (NILP (base))
fontset = Fcopy_sequence (Vdefault_fontset);
fontset = Fmake_char_table (Qfontset, Qnil);
FONTSET_ID (fontset) = make_number (id);
FONTSET_NAME (fontset) = name;
FONTSET_FRAME (fontset) = frame;
FONTSET_BASE (fontset) = base;
AREF (Vfontset_table, id) = fontset;
next_fontset_id = id + 1;
return fontset;
/* Return 1 if ID is a valid fontset id, else return 0. */
static INLINE int
fontset_id_valid_p (id)
int id;
return (id >= 0 && id < ASIZE (Vfontset_table) - 1);
/* Extract `family' and `registry' string from FONTNAME and set in
*FAMILY and *REGISTRY respectively. Actually, `family' may also
contain `foundry', `registry' may also contain `encoding' of
static Lisp_Object
font_family_registry (fontname)
Lisp_Object fontname;
Lisp_Object family, registry;
char *p = XSTRING (fontname)->data;
char *sep[15];
int i = 0;
while (*p && i < 15) if (*p++ == '-') sep[i++] = p;
if (i != 14)
return fontname;
family = make_unibyte_string (sep[0], sep[2] - 1 - sep[0]);
registry = make_unibyte_string (sep[12], p - sep[12]);
return Fcons (family, registry);
/********** INTERFACES TO xfaces.c and dispextern.h **********/
/* Return name of the fontset with ID. */
fontset_name (id)
int id;
Lisp_Object fontset;
fontset = FONTSET_FROM_ID (id);
return FONTSET_NAME (fontset);
/* Return ASCII font name of the fontset with ID. */
fontset_ascii (id)
int id;
Lisp_Object fontset, elt;
fontset= FONTSET_FROM_ID (id);
elt = FONTSET_ASCII (fontset);
return XCDR (elt);
/* Free fontset of FACE. Called from free_realized_face. */
free_fontset_data (fontset_data)
struct fontset_data *fontset_data;
free_face_fontset (f, face)
struct face *face;
if (fontset_data->fontset_table)
if (fontset_id_valid_p (face->fontset))
int i;
AREF (Vfontset_table, face->fontset) = Qnil;
if (face->fontset < next_fontset_id)
next_fontset_id = face->fontset;
for (i = 0; i < fontset_data->n_fontsets; i++)
int j;
xfree (fontset_data->fontset_table[i]->name);
for (j = 0; j <= MAX_CHARSET; j++)
if (fontset_data->fontset_table[i]->fontname[j])
xfree (fontset_data->fontset_table[i]->fontname[j]);
xfree (fontset_data->fontset_table[i]);
xfree (fontset_data->fontset_table);
/* Return 1 iff FACE is suitable for displaying character C.
Otherwise return 0. Called from the macro FACE_SUITABLE_FOR_CHAR_P
when C is not a single byte character.. */
face_suitable_for_char_p (face, c)
struct face *face;
int c;
Lisp_Object fontset, elt;
return (face == face->ascii_face);
xassert (fontset_id_valid_p (face->fontset));
fontset = FONTSET_FROM_ID (face->fontset);
xassert (!BASE_FONTSET_P (fontset));
elt = FONTSET_REF_VIA_BASE (fontset, c);
return (!NILP (elt) && face->id == XFASTINT (elt));
/* Return ID of face suitable for displaying character C on frame F.
The selection of face is done based on the fontset of FACE. FACE
should already have been realized for ASCII characters. Called
from the macro FACE_FOR_CHAR when C is not a single byte character. */
face_for_char (f, face, c)
struct face *face;
int c;
Lisp_Object fontset, elt;
int face_id;
xassert (fontset_id_valid_p (face->fontset));
fontset = FONTSET_FROM_ID (face->fontset);
xassert (!BASE_FONTSET_P (fontset));
elt = FONTSET_REF_VIA_BASE (fontset, c);
if (!NILP (elt))
return XINT (elt);
/* No face is recorded for C in the fontset of FACE. Make a new
realized face for C that has the same fontset. */
face_id = lookup_face (f, face->lface, c, face);
/* Record the face ID in FONTSET at the same index as the
information in the base fontset. */
FONTSET_SET (fontset, c, make_number (face_id));
return face_id;
/* Make a realized fontset for ASCII face FACE on frame F from the
base fontset BASE_FONTSET_ID. If BASE_FONTSET_ID is -1, use the
default fontset as the base. Value is the id of the new fontset.
Called from realize_x_face. */
make_fontset_for_ascii_face (f, base_fontset_id)
int base_fontset_id;
Lisp_Object base_fontset, fontset, name, frame;
XSETFRAME (frame, f);
if (base_fontset_id >= 0)
base_fontset = FONTSET_FROM_ID (base_fontset_id);
if (!BASE_FONTSET_P (base_fontset))
base_fontset = FONTSET_BASE (base_fontset);
xassert (BASE_FONTSET_P (base_fontset));
base_fontset = Vdefault_fontset;
fontset = make_fontset (frame, Qnil, base_fontset);
return FONTSET_ID (fontset);
/* Return the font name pattern for C that is recorded in the fontset
with ID. A font is opened by that pattern to get the fullname. If
the fullname conform to XLFD, extract foundry-family field and
registry-encoding field, and return the cons of them. Otherwise
return the fullname. If ID is -1, or the fontset doesn't contain
information about C, get the registry and encoding of C from the
default fontset. Called from choose_face_font. */
fontset_font_pattern (f, id, c)
int id, c;
Lisp_Object fontset, elt;
struct font_info *fontp;
Lisp_Object family_registry;
elt = Qnil;
if (fontset_id_valid_p (id))
fontset = FONTSET_FROM_ID (id);
xassert (!BASE_FONTSET_P (fontset));
fontset = FONTSET_BASE (fontset);
elt = FONTSET_REF (fontset, c);
elt = FONTSET_REF (Vdefault_fontset, c);
if (!CONSP (elt))
return Qnil;
if (CONSP (XCDR (elt)))
return XCDR (elt);
/* The fontset specifies only a font name pattern (not cons of
family and registry). Try to open a font by that pattern and get
a registry from the full name of the opened font. We ignore
family name here because it should be wild card in the fontset
specification. */
elt = XCDR (elt);
xassert (STRINGP (elt));
fontp = FS_LOAD_FONT (f, c, XSTRING (elt)->data, -1);
if (!fontp)
return Qnil;
xfree (fontset_data);
family_registry = font_family_registry (build_string (fontp->full_name));
if (!CONSP (family_registry))
return family_registry;
XCAR (family_registry) = Qnil;
return family_registry;
/* Load a font named FONTNAME for displaying CHARSET on frame F.
All fonts for frame F is stored in a table pointed by FONT_TABLE.
Return a pointer to the struct font_info of the loaded font.
If loading fails, return 0;
If FONTNAME is NULL, the name is taken from the information of FONTSET.
If FONTSET is given, try to load a font whose size matches that of
FONTSET, and, the font index is stored in the table for FONTSET.
If you give FONTSET argument, don't call this function directry,
instead call macro FS_LOAD_FONT with the same argument. */
/* Load a font named FONTNAME to display character C on frame F.
Return a pointer to the struct font_info of the loaded font. If
loading fails, return NULL. If FACE is non-zero and a fontset is
assigned to it, record FACE->id in the fontset for C. If FONTNAME
is NULL, the name is taken from the fontset of FACE or what
specified by ID. */
struct font_info *
fs_load_font (f, font_table, charset, fontname, fontset)
fs_load_font (f, c, fontname, id, face)
struct font_info *font_table;
int charset, fontset;
int c;
char *fontname;
int id;
struct face *face;
Lisp_Object font_list;
Lisp_Object fontset;
Lisp_Object list, elt;
int font_idx;
int size = 0;
struct fontset_info *fontsetp = 0;
struct font_info *fontp;
int charset = CHAR_CHARSET (c);
if (face)
id = face->fontset;
if (id < 0)
fontset = Qnil;
fontset = FONTSET_FROM_ID (id);
if (fontset >= 0 && fontset < FRAME_FONTSET_DATA (f)->n_fontsets)
if (!NILP (fontset)
&& !BASE_FONTSET_P (fontset))
fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
font_idx = fontsetp->font_indexes[charset];
if (font_idx >= 0)
/* We have already loaded a font. */
return font_table + font_idx;
else if (font_idx == FONT_NOT_FOUND)
/* We have already tried loading a font and failed. */
return 0;
if (!fontname)
fontname = fontsetp->fontname[charset];
elt = FONTSET_REF_VIA_BASE (fontset, c);
if (!NILP (elt))
/* A suitable face for C is already recorded, which means
that a proper font is already loaded. */
int face_id = XINT (elt);
if (!fontname)
/* No way to get fontname. */
return 0;
xassert (face_id == face->id);
face = FACE_FROM_ID (f, face_id);
return (*get_font_info_func) (f, face->font_info_id);
/* If CHARSET is not ASCII and FONTSET is specified, we must load a
font of appropriate size to be used with other fonts in this
fontset. */
if (charset != CHARSET_ASCII && fontsetp)
/* If we have not yet loaded ASCII font of FONTSET, we must load
it now to decided the size and height of this fontset. */
if (fontsetp->size == 0)