/* xfont.c -- X core font driver.
- Copyright (C) 2006 Free Software Foundation, Inc.
- Copyright (C) 2006
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2009, 2010
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H13PRO009
This file is part of GNU Emacs.
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA. */
+along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
#include <X11/Xlib.h>
#include "lisp.h"
#include "charset.h"
#include "fontset.h"
#include "font.h"
+#include "ccl.h"
\f
/* X core font driver. */
-/* Prototypes of support functions. */
-extern void x_clear_errors P_ ((Display *));
-
-static char *xfont_query_font P_ ((Display *, char *, Lisp_Object));
-static XCharStruct *xfont_get_pcm P_ ((XFontStruct *, XChar2b *));
-static int xfont_registry_charsets P_ ((Lisp_Object, struct charset **,
- struct charset **));
-
-static char *
-xfont_query_font (display, name, spec)
- Display *display;
- char *name;
- Lisp_Object spec;
+struct xfont_info
{
- XFontStruct *font;
-
- BLOCK_INPUT;
- x_catch_errors (display);
- font = XLoadQueryFont (display, name);
- name = NULL;
- if (x_had_errors_p (display))
- {
- /* This error is perhaps due to insufficient memory on X
- server. Let's just ignore it. */
- x_clear_errors (display);
- }
- else if (font)
- {
- unsigned long value;
-
- if (XGetFontProperty (font, XA_FONT, &value))
- {
- char *n = (char *) XGetAtomName (display, (Atom) value);
-
- if (font_parse_xlfd (n, spec) >= 0)
- name = n;
- else
- XFree (n);
- }
- XFreeFont (display, font);
- }
- x_uncatch_errors ();
- UNBLOCK_INPUT;
+ struct font font;
+ Display *display;
+ XFontStruct *xfont;
+};
- return name;
-}
+/* Prototypes of support functions. */
+extern void x_clear_errors (Display *);
+static XCharStruct *xfont_get_pcm (XFontStruct *, XChar2b *);
/* Get metrics of character CHAR2B in XFONT. Value is null if CHAR2B
is not contained in the font. */
/* The result metric information. */
XCharStruct *pcm = NULL;
- xassert (xfont && char2b);
+ font_assert (xfont && char2b);
if (xfont->per_char != NULL)
{
? NULL : pcm);
}
-static Lisp_Object xfont_get_cache P_ ((FRAME_PTR));
-static Lisp_Object xfont_list P_ ((Lisp_Object, Lisp_Object));
-static Lisp_Object xfont_match P_ ((Lisp_Object, Lisp_Object));
-static Lisp_Object xfont_list_family P_ ((Lisp_Object));
-static struct font *xfont_open P_ ((FRAME_PTR, Lisp_Object, int));
-static void xfont_close P_ ((FRAME_PTR, struct font *));
-static int xfont_prepare_face P_ ((FRAME_PTR, struct face *));
-#if 0
-static void xfont_done_face P_ ((FRAME_PTR, struct face *));
-#endif
-static int xfont_has_char P_ ((Lisp_Object, int));
-static unsigned xfont_encode_char P_ ((struct font *, int));
-static int xfont_text_extents P_ ((struct font *, unsigned *, int,
- struct font_metrics *));
-static int xfont_draw P_ ((struct glyph_string *, int, int, int, int, int));
+static Lisp_Object xfont_get_cache (FRAME_PTR);
+static Lisp_Object xfont_list (Lisp_Object, Lisp_Object);
+static Lisp_Object xfont_match (Lisp_Object, Lisp_Object);
+static Lisp_Object xfont_list_family (Lisp_Object);
+static Lisp_Object xfont_open (FRAME_PTR, Lisp_Object, int);
+static void xfont_close (FRAME_PTR, struct font *);
+static int xfont_prepare_face (FRAME_PTR, struct face *);
+static int xfont_has_char (Lisp_Object, int);
+static unsigned xfont_encode_char (struct font *, int);
+static int xfont_text_extents (struct font *, unsigned *, int,
+ struct font_metrics *);
+static int xfont_draw (struct glyph_string *, int, int, int, int, int);
+static int xfont_check (FRAME_PTR, struct font *);
struct font_driver xfont_driver =
{
0, /* Qx */
+ 0, /* case insensitive */
xfont_get_cache,
xfont_list,
xfont_match,
xfont_open,
xfont_close,
xfont_prepare_face,
- NULL /*xfont_done_face*/,
+ NULL,
xfont_has_char,
xfont_encode_char,
xfont_text_extents,
- xfont_draw
+ xfont_draw,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ xfont_check,
+ NULL, /* get_variation_glyphs */
+ NULL, /* filter_properties */
};
extern Lisp_Object QCname;
extern Lisp_Object Vface_alternative_font_registry_alist;
+static int
+compare_font_names (const void *name1, const void *name2)
+{
+ return xstrcasecmp (*(const unsigned char **) name1,
+ *(const unsigned char **) name2);
+}
+
+/* Decode XLFD as iso-8859-1 into OUTPUT, and return the byte length
+ of the decoding result. LEN is the byte length of XLFD, or -1 if
+ XLFD is NULL terminated. The caller must assure that OUTPUT is at
+ least twice (plus 1) as large as XLFD. */
+
+static int
+xfont_decode_coding_xlfd (char *xlfd, int len, char *output)
+{
+ char *p0 = xlfd, *p1 = output;
+ int c;
+
+ while (*p0)
+ {
+ c = *(unsigned char *) p0++;
+ p1 += CHAR_STRING (c, p1);
+ if (--len == 0)
+ break;
+ }
+ *p1 = 0;
+ return (p1 - output);
+}
+
+/* Encode XLFD from UTF-8 to iso-8859-1 destructively, and return the
+ resulting byte length. If XLFD contains unencodable character,
+ return -1. */
+
+static int
+xfont_encode_coding_xlfd (char *xlfd)
+{
+ const unsigned char *p0 = (unsigned char *) xlfd;
+ unsigned char *p1 = (unsigned char *) xlfd;
+ int len = 0;
+
+ while (*p0)
+ {
+ int c = STRING_CHAR_ADVANCE (p0);
+
+ if (c >= 0x100)
+ return -1;
+ *p1++ = c;
+ len++;
+ }
+ *p1 = 0;
+ return len;
+}
+
+/* Check if CHARS (cons or vector) is supported by XFONT whose
+ encoding charset is ENCODING (XFONT is NULL) or by a font whose
+ registry corresponds to ENCODING and REPERTORY.
+ Return 1 if supported, return 0 otherwise. */
+
+static int
+xfont_chars_supported (Lisp_Object chars, XFontStruct *xfont,
+ struct charset *encoding, struct charset *repertory)
+{
+ struct charset *charset = repertory ? repertory : encoding;
+
+ if (CONSP (chars))
+ {
+ for (; CONSP (chars); chars = XCDR (chars))
+ {
+ int c = XINT (XCAR (chars));
+ unsigned code = ENCODE_CHAR (charset, c);
+ XChar2b char2b;
+
+ if (code == CHARSET_INVALID_CODE (charset))
+ break;
+ if (! xfont)
+ continue;
+ if (code >= 0x10000)
+ break;
+ char2b.byte1 = code >> 8;
+ char2b.byte2 = code & 0xFF;
+ if (! xfont_get_pcm (xfont, &char2b))
+ break;
+ }
+ return (NILP (chars));
+ }
+ else if (VECTORP (chars))
+ {
+ int i;
+
+ for (i = ASIZE (chars) - 1; i >= 0; i--)
+ {
+ int c = XINT (AREF (chars, i));
+ unsigned code = ENCODE_CHAR (charset, c);
+ XChar2b char2b;
+
+ if (code == CHARSET_INVALID_CODE (charset))
+ continue;
+ if (! xfont)
+ break;
+ if (code >= 0x10000)
+ continue;
+ char2b.byte1 = code >> 8;
+ char2b.byte2 = code & 0xFF;
+ if (xfont_get_pcm (xfont, &char2b))
+ break;
+ }
+ return (i >= 0);
+ }
+ return 0;
+}
+
+/* A hash table recoding which font supports which scritps. Each key
+ is a vector of characteristic font propertis FOUNDRY to WIDTH and
+ ADDSTYLE, and each value is a list of script symbols.
+
+ We assume that fonts that have the same value in the above
+ properties supports the same set of characters on all displays. */
+
+static Lisp_Object xfont_scripts_cache;
+
+/* Re-usable vector to store characteristic font properites. */
+static Lisp_Object xfont_scratch_props;
+
+extern Lisp_Object Qlatin;
+
+/* Return a list of scripts supported by the font of FONTNAME whose
+ characteristic properties are in PROPS and whose encoding charset
+ is ENCODING. A caller must call BLOCK_INPUT in advance. */
+
static Lisp_Object
-xfont_list_pattern (frame, display, pattern)
- Lisp_Object frame;
- Display *display;
- char *pattern;
+xfont_supported_scripts (Display *display, char *fontname, Lisp_Object props,
+ struct charset *encoding)
+{
+ Lisp_Object scripts;
+
+ /* Two special cases to avoid opening rather big fonts. */
+ if (EQ (AREF (props, 2), Qja))
+ return Fcons (intern ("kana"), Fcons (intern ("han"), Qnil));
+ if (EQ (AREF (props, 2), Qko))
+ return Fcons (intern ("hangul"), Qnil);
+ scripts = Fgethash (props, xfont_scripts_cache, Qt);
+ if (EQ (scripts, Qt))
+ {
+ XFontStruct *xfont;
+ Lisp_Object val;
+
+ scripts = Qnil;
+ xfont = XLoadQueryFont (display, fontname);
+ if (xfont)
+ {
+ if (xfont->per_char)
+ {
+ for (val = Vscript_representative_chars; CONSP (val);
+ val = XCDR (val))
+ if (CONSP (XCAR (val)) && SYMBOLP (XCAR (XCAR (val))))
+ {
+ Lisp_Object script = XCAR (XCAR (val));
+ Lisp_Object chars = XCDR (XCAR (val));
+
+ if (xfont_chars_supported (chars, xfont, encoding, NULL))
+ scripts = Fcons (script, scripts);
+ }
+ }
+ XFreeFont (display, xfont);
+ }
+ if (EQ (AREF (props, 3), Qiso10646_1)
+ && NILP (Fmemq (Qlatin, scripts)))
+ scripts = Fcons (Qlatin, scripts);
+ Fputhash (Fcopy_sequence (props), scripts, xfont_scripts_cache);
+ }
+ return scripts;
+}
+
+extern Lisp_Object Vscalable_fonts_allowed;
+
+static Lisp_Object
+xfont_list_pattern (Display *display, char *pattern,
+ Lisp_Object registry, Lisp_Object script)
{
Lisp_Object list = Qnil;
+ Lisp_Object chars = Qnil;
+ struct charset *encoding, *repertory = NULL;
int i, limit, num_fonts;
char **names;
+ /* Large enough to decode the longest XLFD (255 bytes). */
+ char buf[512];
+ if (! NILP (registry)
+ && font_registry_charsets (registry, &encoding, &repertory) < 0)
+ /* Unknown REGISTRY, not supported. */
+ return Qnil;
+ if (! NILP (script))
+ {
+ chars = assq_no_quit (script, Vscript_representative_chars);
+ if (NILP (chars))
+ /* We can't tell whether or not a font supports SCRIPT. */
+ return Qnil;
+ chars = XCDR (chars);
+ if (repertory)
+ {
+ if (! xfont_chars_supported (chars, NULL, encoding, repertory))
+ return Qnil;
+ script = Qnil;
+ }
+ }
+
BLOCK_INPUT;
x_catch_errors (display);
XFreeFontNames (names);
}
- for (i = 0; i < num_fonts; i++)
+ if (num_fonts > 0)
{
- Lisp_Object entity = Fmake_vector (make_number (FONT_ENTITY_MAX), Qnil);
- int result;
+ char **indices = alloca (sizeof (char *) * num_fonts);
+ Lisp_Object *props = XVECTOR (xfont_scratch_props)->contents;
+ Lisp_Object scripts = Qnil;
- ASET (entity, FONT_TYPE_INDEX, Qx);
- ASET (entity, FONT_FRAME_INDEX, frame);
+ for (i = 0; i < ASIZE (xfont_scratch_props); i++)
+ props[i] = Qnil;
+ for (i = 0; i < num_fonts; i++)
+ indices[i] = names[i];
+ qsort (indices, num_fonts, sizeof (char *), compare_font_names);
- result = font_parse_xlfd (names[i], entity);
- if (result < 0)
+ for (i = 0; i < num_fonts; i++)
{
- /* This may be an alias name. Try to get the full XLFD name
- from XA_FONT property of the font. */
- XFontStruct *font = XLoadQueryFont (display, names[i]);
- unsigned long value;
+ Lisp_Object entity;
- if (! font)
+ if (i > 0 && xstrcasecmp (indices[i - 1], indices[i]) == 0)
+ continue;
+ entity = font_make_entity ();
+ xfont_decode_coding_xlfd (indices[i], -1, buf);
+ if (font_parse_xlfd (buf, entity) < 0)
continue;
- if (XGetFontProperty (font, XA_FONT, &value))
+ ASET (entity, FONT_TYPE_INDEX, Qx);
+ /* Avoid auto-scaled fonts. */
+ if (INTEGERP (AREF (entity, FONT_DPI_INDEX))
+ && INTEGERP (AREF (entity, FONT_AVGWIDTH_INDEX))
+ && XINT (AREF (entity, FONT_DPI_INDEX)) != 0
+ && XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) == 0)
+ continue;
+ /* Avoid not-allowed scalable fonts. */
+ if (NILP (Vscalable_fonts_allowed))
{
- char *name = (char *) XGetAtomName (display, (Atom) value);
- int len = strlen (name);
-
- /* If DXPC (a Differential X Protocol Compressor)
- Ver.3.7 is running, XGetAtomName will return null
- string. We must avoid such a name. */
- if (len > 0)
- result = font_parse_xlfd (name, entity);
- XFree (name);
+ int size = 0;
+
+ if (INTEGERP (AREF (entity, FONT_SIZE_INDEX)))
+ size = XINT (AREF (entity, FONT_SIZE_INDEX));
+ else if (FLOATP (AREF (entity, FONT_SIZE_INDEX)))
+ size = XFLOAT_DATA (AREF (entity, FONT_SIZE_INDEX));
+ if (size == 0)
+ continue;
+ }
+ else if (CONSP (Vscalable_fonts_allowed))
+ {
+ Lisp_Object tail, elt;
+
+ for (tail = Vscalable_fonts_allowed; CONSP (tail);
+ tail = XCDR (tail))
+ {
+ elt = XCAR (tail);
+ if (STRINGP (elt)
+ && fast_c_string_match_ignore_case (elt, indices[i]) >= 0)
+ break;
+ }
+ if (! CONSP (tail))
+ continue;
}
- XFreeFont (display, font);
- }
- if (result == 0)
- {
- Lisp_Object val = AREF (entity, FONT_EXTRA_INDEX);
- char *p = (char *) SDATA (SYMBOL_NAME (val));
+ /* Avoid fonts of invalid registry. */
+ if (NILP (AREF (entity, FONT_REGISTRY_INDEX)))
+ continue;
- /* P == "RESX-RESY-SPACING-AVGWIDTH. We rejust this font if
- it's an autoscaled one (i.e. RESX > 0 && AVGWIDTH == 0). */
- if (atoi (p) > 0)
+ /* Update encoding and repertory if necessary. */
+ if (! EQ (registry, AREF (entity, FONT_REGISTRY_INDEX)))
{
- p += SBYTES (SYMBOL_NAME (val));
- while (p[-1] != '-') p--;
- if (atoi (p) == 0)
- continue;
+ registry = AREF (entity, FONT_REGISTRY_INDEX);
+ if (font_registry_charsets (registry, &encoding, &repertory) < 0)
+ encoding = NULL;
+ }
+ if (! encoding)
+ /* Unknown REGISTRY, not supported. */
+ continue;
+ if (repertory)
+ {
+ if (NILP (script)
+ || xfont_chars_supported (chars, NULL, encoding, repertory))
+ list = Fcons (entity, list);
+ continue;
+ }
+ if (memcmp (props, &(AREF (entity, FONT_FOUNDRY_INDEX)),
+ sizeof (Lisp_Object) * 7)
+ || ! EQ (AREF (entity, FONT_SPACING_INDEX), props[7]))
+ {
+ memcpy (props, &(AREF (entity, FONT_FOUNDRY_INDEX)),
+ sizeof (Lisp_Object) * 7);
+ props[7] = AREF (entity, FONT_SPACING_INDEX);
+ scripts = xfont_supported_scripts (display, indices[i],
+ xfont_scratch_props, encoding);
}
- list = Fcons (entity, list);
+ if (NILP (script)
+ || ! NILP (Fmemq (script, scripts)))
+ list = Fcons (entity, list);
}
+ XFreeFontNames (names);
}
x_uncatch_errors ();
UNBLOCK_INPUT;
+ FONT_ADD_LOG ("xfont-list", build_string (pattern), list);
return list;
}
{
FRAME_PTR f = XFRAME (frame);
Display *display = FRAME_X_DISPLAY_INFO (f)->display;
- Lisp_Object list, val, extra, font_name;
+ Lisp_Object registry, list, val, extra, script;
int len;
- char name[256];
-
+ /* Large enough to contain the longest XLFD (255 bytes) in UTF-8. */
+ char name[512];
+
extra = AREF (spec, FONT_EXTRA_INDEX);
- font_name = Qnil;
if (CONSP (extra))
{
val = assq_no_quit (QCotf, extra);
if (! NILP (val))
- return null_vector;
- val = assq_no_quit (QCscript, extra);
+ return Qnil;
+ val = assq_no_quit (QClang, extra);
if (! NILP (val))
- return null_vector;
- val = assq_no_quit (QClanguage, extra);
- if (! NILP (val))
- return null_vector;
- val = assq_no_quit (QCname, extra);
- if (CONSP (val))
- font_name = XCDR (val);
+ return Qnil;
}
- if (STRINGP (font_name)
- && ! strchr ((char *) SDATA (font_name), ':'))
- list = xfont_list_pattern (frame, display, (char *) SDATA (font_name));
- else if ((len = font_unparse_xlfd (spec, 0, name, 256)) < 0)
- return null_vector;
- else
+ registry = AREF (spec, FONT_REGISTRY_INDEX);
+ len = font_unparse_xlfd (spec, 0, name, 512);
+ if (len < 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
+ return Qnil;
+
+ val = assq_no_quit (QCscript, extra);
+ script = CDR (val);
+ list = xfont_list_pattern (display, name, registry, script);
+ if (NILP (list) && NILP (registry))
{
- list = xfont_list_pattern (frame, display, name);
- if (NILP (list))
- {
- Lisp_Object registry = AREF (spec, FONT_REGISTRY_INDEX);
- Lisp_Object alter;
+ /* Try iso10646-1 */
+ char *r = name + len - 9; /* 9 == strlen (iso8859-1) */
- if (! NILP (registry)
- && (alter = Fassoc (SYMBOL_NAME (registry),
- Vface_alternative_font_registry_alist),
- CONSP (alter)))
- {
- /* Pointer to REGISTRY-ENCODING field. */
- char *r = name + len - SBYTES (SYMBOL_NAME (registry));
+ if (r - name + 10 < 256) /* 10 == strlen (iso10646-1) */
+ {
+ strcpy (r, "iso10646-1");
+ list = xfont_list_pattern (display, name, Qiso10646_1, script);
+ }
+ }
+ if (NILP (list) && ! NILP (registry))
+ {
+ /* Try alternate registries. */
+ Lisp_Object alter;
- for (alter = XCDR (alter); CONSP (alter); alter = XCDR (alter))
- if (STRINGP (XCAR (alter))
- && ((r - name) + SBYTES (XCAR (alter))) < 255)
- {
- strcpy (r, (char *) SDATA (XCAR (alter)));
- list = xfont_list_pattern (frame, display, name);
- if (! NILP (list))
- break;
- }
- }
+ if ((alter = Fassoc (SYMBOL_NAME (registry),
+ Vface_alternative_font_registry_alist),
+ CONSP (alter)))
+ {
+ /* Pointer to REGISTRY-ENCODING field. */
+ char *r = name + len - SBYTES (SYMBOL_NAME (registry));
+
+ for (alter = XCDR (alter); CONSP (alter); alter = XCDR (alter))
+ if (STRINGP (XCAR (alter))
+ && ((r - name) + SBYTES (XCAR (alter))) < 256)
+ {
+ strcpy (r, (char *) SDATA (XCAR (alter)));
+ list = xfont_list_pattern (display, name, registry, script);
+ if (! NILP (list))
+ break;
+ }
+ }
+ }
+ if (NILP (list))
+ {
+ /* Try alias. */
+ val = assq_no_quit (QCname, AREF (spec, FONT_EXTRA_INDEX));
+ if (CONSP (val) && STRINGP (XCDR (val)) && SBYTES (XCDR (val)) < 512)
+ {
+ bcopy (SDATA (XCDR (val)), name, SBYTES (XCDR (val)) + 1);
+ if (xfont_encode_coding_xlfd (name) < 0)
+ return Qnil;
+ list = xfont_list_pattern (display, name, registry, script);
}
}
- return (NILP (list) ? null_vector : Fvconcat (1, &list));
+ return list;
}
static Lisp_Object
FRAME_PTR f = XFRAME (frame);
Display *display = FRAME_X_DISPLAY_INFO (f)->display;
Lisp_Object extra, val, entity;
- char *name;
+ char name[512];
XFontStruct *xfont;
unsigned long value;
extra = AREF (spec, FONT_EXTRA_INDEX);
val = assq_no_quit (QCname, extra);
if (! CONSP (val) || ! STRINGP (XCDR (val)))
+ {
+ if (font_unparse_xlfd (spec, 0, name, 512) < 0)
+ return Qnil;
+ }
+ else if (SBYTES (XCDR (val)) < 512)
+ bcopy (SDATA (XCDR (val)), name, SBYTES (XCDR (val)) + 1);
+ else
+ return Qnil;
+ if (xfont_encode_coding_xlfd (name) < 0)
return Qnil;
BLOCK_INPUT;
entity = Qnil;
- name = (char *) SDATA (XCDR (val));
xfont = XLoadQueryFont (display, name);
if (xfont)
{
if (XGetFontProperty (xfont, XA_FONT, &value))
{
int len;
+ char *s;
- name = (char *) XGetAtomName (display, (Atom) value);
- len = strlen (name);
+ s = (char *) XGetAtomName (display, (Atom) value);
+ len = strlen (s);
/* If DXPC (a Differential X Protocol Compressor)
Ver.3.7 is running, XGetAtomName will return null
string. We must avoid such a name. */
if (len > 0)
{
- entity = Fmake_vector (make_number (FONT_ENTITY_MAX), Qnil);
+ entity = font_make_entity ();
ASET (entity, FONT_TYPE_INDEX, Qx);
- ASET (entity, FONT_FRAME_INDEX, frame);
+ xfont_decode_coding_xlfd (s, -1, name);
if (font_parse_xlfd (name, entity) < 0)
entity = Qnil;
}
- XFree (name);
+ XFree (s);
}
XFreeFont (display, xfont);
}
UNBLOCK_INPUT;
+ FONT_ADD_LOG ("xfont-match", spec, entity);
return entity;
}
-static int
-memq_no_quit (elt, list)
- Lisp_Object elt, list;
-{
- while (CONSP (list) && ! EQ (XCAR (list), elt))
- list = XCDR (list);
- return (CONSP (list));
-}
-
static Lisp_Object
xfont_list_family (frame)
Lisp_Object frame;
list = Qnil;
for (i = 0, last_len = 0; i < num_fonts; i++)
{
- char *p0 = names[i], *p1;
+ char *p0 = names[i], *p1, buf[512];
Lisp_Object family;
+ int decoded_len;
p0++; /* skip the leading '-' */
while (*p0 && *p0 != '-') p0++; /* skip foundry */
continue;
last_len = p1 - p0;
last_family = p0;
- family = intern_downcase (p0, last_len);
- if (! memq_no_quit (family, list))
+
+ decoded_len = xfont_decode_coding_xlfd (p0, last_len, buf);
+ family = font_intern_prop (p0, decoded_len, 1);
+ if (NILP (assq_no_quit (family, list)))
list = Fcons (family, list);
}
return list;
}
-static struct font *
+extern Lisp_Object QCavgwidth;
+
+static Lisp_Object
xfont_open (f, entity, pixel_size)
FRAME_PTR f;
Lisp_Object entity;
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
Display *display = dpyinfo->display;
- char name[256];
+ char name[512];
int len;
unsigned long value;
Lisp_Object registry;
struct charset *encoding, *repertory;
+ Lisp_Object font_object, fullname;
struct font *font;
XFontStruct *xfont;
font. */
registry = AREF (entity, FONT_REGISTRY_INDEX);
if (font_registry_charsets (registry, &encoding, &repertory) < 0)
- return NULL;
+ {
+ FONT_ADD_LOG (" x:unknown registry", registry, Qnil);
+ return Qnil;
+ }
if (XINT (AREF (entity, FONT_SIZE_INDEX)) != 0)
pixel_size = XINT (AREF (entity, FONT_SIZE_INDEX));
- len = font_unparse_xlfd (entity, pixel_size, name, 256);
- if (len <= 0)
- return NULL;
+ else if (pixel_size == 0)
+ {
+ if (FRAME_FONT (f))
+ pixel_size = FRAME_FONT (f)->pixel_size;
+ else
+ pixel_size = 14;
+ }
+ len = font_unparse_xlfd (entity, pixel_size, name, 512);
+ if (len <= 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
+ {
+ FONT_ADD_LOG (" x:unparse failed", entity, Qnil);
+ return Qnil;
+ }
BLOCK_INPUT;
x_catch_errors (display);
x_clear_errors (display);
xfont = NULL;
}
- x_uncatch_errors ();
- UNBLOCK_INPUT;
-
- if (! xfont)
- return NULL;
- font = malloc (sizeof (struct font));
- font->format = Qx;
- font->font.font = xfont;
- font->entity = entity;
- font->pixel_size = pixel_size;
- font->driver = &xfont_driver;
- font->font.name = malloc (len + 1);
- if (! font->font.name)
- {
- XFreeFont (display, xfont);
- free (font);
- return NULL;
- }
- bcopy (name, font->font.name, len + 1);
- font->font.charset = encoding->id;
- font->encoding_charset = encoding->id;
- font->repertory_charset = repertory ? repertory->id : -1;
- font->ascent = xfont->ascent;
- font->descent = xfont->descent;
-
- if (xfont->min_bounds.width == xfont->max_bounds.width)
- {
- /* Fixed width font. */
- font->font.average_width = font->font.space_width
- = xfont->min_bounds.width;
- }
- else
+ else if (! xfont)
{
- XChar2b char2b;
- XCharStruct *pcm;
-
- char2b.byte1 = 0x00, char2b.byte2 = 0x20;
- pcm = xfont_get_pcm (xfont, &char2b);
- if (pcm)
- font->font.space_width = pcm->width;
- else
- font->font.space_width = xfont->max_bounds.width;
-
- font->font.average_width
- = (XGetFontProperty (xfont, dpyinfo->Xatom_AVERAGE_WIDTH, &value)
- ? (long) value / 10 : 0);
- if (font->font.average_width < 0)
- font->font.average_width = - font->font.average_width;
- if (font->font.average_width == 0)
+ /* Some version of X lists:
+ -misc-fixed-medium-r-normal--20-*-75-75-c-100-iso8859-1
+ -misc-fixed-medium-r-normal--20-*-100-100-c-100-iso8859-1
+ but can open only:
+ -misc-fixed-medium-r-normal--20-*-100-100-c-100-iso8859-1
+ and
+ -misc-fixed-medium-r-normal--20-*-*-*-c-100-iso8859-1
+ So, we try again with wildcards in RESX and RESY. */
+ Lisp_Object temp;
+
+ temp = Fcopy_font_spec (entity);
+ ASET (temp, FONT_DPI_INDEX, Qnil);
+ len = font_unparse_xlfd (temp, pixel_size, name, 512);
+ if (len <= 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
{
- if (pcm)
- {
- int width = pcm->width;
- for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
- if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
- width += pcm->width;
- font->font.average_width = width / 95;
- }
- else
- font->font.average_width = xfont->max_bounds.width;
+ FONT_ADD_LOG (" x:unparse failed", temp, Qnil);
+ return Qnil;
+ }
+ xfont = XLoadQueryFont (display, name);
+ if (x_had_errors_p (display))
+ {
+ /* This error is perhaps due to insufficient memory on X server.
+ Let's just ignore it. */
+ x_clear_errors (display);
+ xfont = NULL;
}
}
- font->min_width = xfont->min_bounds.width;
- if (font->min_width <= 0)
- font->min_width = font->font.space_width;
-
- BLOCK_INPUT;
- /* Try to get the full name of FONT. Put it in FULL_NAME. */
- if (XGetFontProperty (xfont, XA_FONT, &value))
+ fullname = Qnil;
+ /* Try to get the full name of FONT. */
+ if (xfont && XGetFontProperty (xfont, XA_FONT, &value))
{
- char *full_name = NULL, *p0, *p;
+ char *p0, *p;
int dashes = 0;
- p0 = p = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);;
+ p0 = p = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
/* Count the number of dashes in the "full name".
If it is too few, this isn't really the font's full name,
so don't use it.
if (dashes >= 13)
{
- full_name = (char *) malloc (p - p0 + 1);
- if (full_name)
- bcopy (p0, full_name, p - p0 + 1);
+ len = xfont_decode_coding_xlfd (p0, -1, name);
+ fullname = Fdowncase (make_string (name, len));
}
XFree (p0);
+ }
+ x_uncatch_errors ();
+ UNBLOCK_INPUT;
+
+ if (! xfont)
+ {
+ FONT_ADD_LOG (" x:open failed", build_string (name), Qnil);
+ return Qnil;
+ }
- if (full_name)
- font->font.full_name = full_name;
+ font_object = font_make_object (VECSIZE (struct xfont_info),
+ entity, pixel_size);
+ ASET (font_object, FONT_TYPE_INDEX, Qx);
+ if (STRINGP (fullname))
+ {
+ font_parse_xlfd ((char *) SDATA (fullname), font_object);
+ ASET (font_object, FONT_NAME_INDEX, fullname);
+ }
+ else
+ {
+ char buf[512];
+
+ len = xfont_decode_coding_xlfd (name, -1, buf);
+ ASET (font_object, FONT_NAME_INDEX, make_string (buf, len));
+ }
+ ASET (font_object, FONT_FULLNAME_INDEX, fullname);
+ ASET (font_object, FONT_FILE_INDEX, Qnil);
+ ASET (font_object, FONT_FORMAT_INDEX, Qx);
+ font = XFONT_OBJECT (font_object);
+ ((struct xfont_info *) font)->xfont = xfont;
+ ((struct xfont_info *) font)->display = FRAME_X_DISPLAY (f);
+ font->pixel_size = pixel_size;
+ font->driver = &xfont_driver;
+ font->encoding_charset = encoding->id;
+ font->repertory_charset = repertory ? repertory->id : -1;
+ font->ascent = xfont->ascent;
+ font->descent = xfont->descent;
+ font->height = font->ascent + font->descent;
+ font->min_width = xfont->min_bounds.width;
+ if (xfont->min_bounds.width == xfont->max_bounds.width)
+ {
+ /* Fixed width font. */
+ font->average_width = font->space_width = xfont->min_bounds.width;
+ }
+ else
+ {
+ XCharStruct *pcm;
+ XChar2b char2b;
+ Lisp_Object val;
+
+ char2b.byte1 = 0x00, char2b.byte2 = 0x20;
+ pcm = xfont_get_pcm (xfont, &char2b);
+ if (pcm)
+ font->space_width = pcm->width;
else
- font->font.full_name = font->font.name;
+ font->space_width = 0;
+
+ val = Ffont_get (font_object, QCavgwidth);
+ if (INTEGERP (val))
+ font->average_width = XINT (val);
+ if (font->average_width < 0)
+ font->average_width = - font->average_width;
+ if (font->average_width == 0
+ && encoding->ascii_compatible_p)
+ {
+ int width = font->space_width, n = pcm != NULL;
+
+ for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
+ if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
+ width += pcm->width, n++;
+ if (n > 0)
+ font->average_width = width / n;
+ }
+ if (font->average_width == 0)
+ /* No easy way other than this to get a reasonable
+ average_width. */
+ font->average_width
+ = (xfont->min_bounds.width + xfont->max_bounds.width) / 2;
}
- font->file_name = NULL;
- font->font.size = xfont->max_bounds.width;
- font->font.height = xfont->ascent + xfont->descent;
- font->font.baseline_offset
+ BLOCK_INPUT;
+ font->underline_thickness
+ = (XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &value)
+ ? (long) value : 0);
+ font->underline_position
+ = (XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &value)
+ ? (long) value : -1);
+ font->baseline_offset
= (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_BASELINE_OFFSET, &value)
? (long) value : 0);
- font->font.relative_compose
+ font->relative_compose
= (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_RELATIVE_COMPOSE, &value)
? (long) value : 0);
- font->font.default_ascent
+ font->default_ascent
= (XGetFontProperty (xfont, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
? (long) value : 0);
- font->font.vertical_centering
- = (STRINGP (Vvertical_centering_font_regexp)
- && (fast_c_string_match_ignore_case
- (Vvertical_centering_font_regexp, font->font.full_name) >= 0));
-
UNBLOCK_INPUT;
- dpyinfo->n_fonts++;
-
- /* Set global flag fonts_changed_p to non-zero if the font loaded
- has a character with a smaller width than any other character
- before, or if the font loaded has a smaller height than any other
- font loaded before. If this happens, it will make a glyph matrix
- reallocation necessary. */
- if (dpyinfo->n_fonts == 1)
- {
- dpyinfo->smallest_font_height = font->font.height;
- dpyinfo->smallest_char_width = font->min_width;
- fonts_changed_p = 1;
- }
- else
- {
- if (dpyinfo->smallest_font_height > font->font.height)
- dpyinfo->smallest_font_height = font->font.height, fonts_changed_p |= 1;
- if (dpyinfo->smallest_char_width > font->min_width)
- dpyinfo->smallest_char_width = font->min_width, fonts_changed_p |= 1;
- }
+ if (NILP (fullname))
+ fullname = AREF (font_object, FONT_NAME_INDEX);
+ font->vertical_centering
+ = (STRINGP (Vvertical_centering_font_regexp)
+ && (fast_string_match_ignore_case
+ (Vvertical_centering_font_regexp, fullname) >= 0));
- return font;
+ return font_object;
}
static void
struct font *font;
{
BLOCK_INPUT;
- XFreeFont (FRAME_X_DISPLAY (f), font->font.font);
+ XFreeFont (FRAME_X_DISPLAY (f), ((struct xfont_info *) font)->xfont);
UNBLOCK_INPUT;
-
- if (font->font.name != font->font.full_name)
- free (font->font.full_name);
- free (font->font.name);
- free (font);
- FRAME_X_DISPLAY_INFO (f)->n_fonts--;
}
static int
struct face *face;
{
BLOCK_INPUT;
- XSetFont (FRAME_X_DISPLAY (f), face->gc, face->font->fid);
+ XSetFont (FRAME_X_DISPLAY (f), face->gc,
+ ((struct xfont_info *) face->font)->xfont->fid);
UNBLOCK_INPUT;
return 0;
}
-#if 0
-static void
-xfont_done_face (f, face)
- FRAME_PTR f;
- struct face *face;
-{
- if (face->extra)
- {
- BLOCK_INPUT;
- XFreeGC (FRAME_X_DISPLAY (f), (GC) face->extra);
- UNBLOCK_INPUT;
- face->extra = NULL;
- }
-}
-#endif /* 0 */
-
static int
-xfont_has_char (entity, c)
- Lisp_Object entity;
+xfont_has_char (font, c)
+ Lisp_Object font;
int c;
{
- Lisp_Object registry = AREF (entity, FONT_REGISTRY_INDEX);
- struct charset *repertory;
+ Lisp_Object registry = AREF (font, FONT_REGISTRY_INDEX);
+ struct charset *encoding;
+ struct charset *repertory = NULL;
- if (font_registry_charsets (registry, NULL, &repertory) < 0)
- return -1;
+ if (EQ (registry, Qiso10646_1))
+ {
+ encoding = CHARSET_FROM_ID (charset_unicode);
+ /* We use a font of `ja' and `ko' adstyle only for a character
+ in JISX0208 and KSC5601 charsets respectively. */
+ if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qja)
+ && charset_jisx0208 >= 0)
+ repertory = CHARSET_FROM_ID (charset_jisx0208);
+ else if (EQ (AREF (font, FONT_ADSTYLE_INDEX), Qko)
+ && charset_ksc5601 >= 0)
+ repertory = CHARSET_FROM_ID (charset_ksc5601);
+ }
+ else if (font_registry_charsets (registry, &encoding, &repertory) < 0)
+ /* Unknown REGISTRY, not usable. */
+ return 0;
+ if (ASCII_CHAR_P (c) && encoding->ascii_compatible_p)
+ return 1;
if (! repertory)
return -1;
return (ENCODE_CHAR (repertory, c) != CHARSET_INVALID_CODE (repertory));
struct font *font;
int c;
{
+ XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
struct charset *charset;
unsigned code;
XChar2b char2b;
}
char2b.byte1 = code >> 8;
char2b.byte2 = code & 0xFF;
- return (xfont_get_pcm (font->font.font, &char2b) ? code : FONT_INVALID_CODE);
+ return (xfont_get_pcm (xfont, &char2b) ? code : FONT_INVALID_CODE);
}
static int
int nglyphs;
struct font_metrics *metrics;
{
+ XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
int width = 0;
- int i, x;
+ int i, first, x;
if (metrics)
bzero (metrics, sizeof (struct font_metrics));
- for (i = 0, x = 0; i < nglyphs; i++)
+ for (i = 0, x = 0, first = 1; i < nglyphs; i++)
{
XChar2b char2b;
static XCharStruct *pcm;
if (code[i] >= 0x10000)
continue;
char2b.byte1 = code[i] >> 8, char2b.byte2 = code[i] & 0xFF;
- pcm = xfont_get_pcm (font->font.font, &char2b);
+ pcm = xfont_get_pcm (xfont, &char2b);
if (! pcm)
continue;
- if (metrics->lbearing > width + pcm->lbearing)
- metrics->lbearing = width + pcm->lbearing;
- if (metrics->rbearing < width + pcm->rbearing)
- metrics->rbearing = width + pcm->rbearing;
- if (metrics->ascent < pcm->ascent)
- metrics->ascent = pcm->ascent;
- if (metrics->descent < pcm->descent)
- metrics->descent = pcm->descent;
+ if (first)
+ {
+ if (metrics)
+ {
+ metrics->lbearing = pcm->lbearing;
+ metrics->rbearing = pcm->rbearing;
+ metrics->ascent = pcm->ascent;
+ metrics->descent = pcm->descent;
+ }
+ first = 0;
+ }
+ else
+ {
+ if (metrics)
+ {
+ if (metrics->lbearing > width + pcm->lbearing)
+ metrics->lbearing = width + pcm->lbearing;
+ if (metrics->rbearing < width + pcm->rbearing)
+ metrics->rbearing = width + pcm->rbearing;
+ if (metrics->ascent < pcm->ascent)
+ metrics->ascent = pcm->ascent;
+ if (metrics->descent < pcm->descent)
+ metrics->descent = pcm->descent;
+ }
+ }
width += pcm->width;
}
if (metrics)
struct glyph_string *s;
int from, to, x, y, with_background;
{
- XFontStruct *xfont = s->face->font;
+ XFontStruct *xfont = ((struct xfont_info *) s->font)->xfont;
int len = to - from;
GC gc = s->gc;
+ int i;
- if (gc != s->face->gc)
+ if (s->gc != s->face->gc)
{
- XGCValues xgcv;
- Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (s->f);
-
- XGetGCValues (s->display, gc, GCFont, &xgcv);
- if (xgcv.font != xfont->fid)
- XSetFont (s->display, gc, xfont->fid);
+ BLOCK_INPUT;
+ XSetFont (s->display, gc, xfont->fid);
+ UNBLOCK_INPUT;
}
if (xfont->min_byte1 == 0 && xfont->max_byte1 == 0)
{
char *str;
- int i;
USE_SAFE_ALLOCA;
SAFE_ALLOCA (str, char *, len);
for (i = 0; i < len ; i++)
str[i] = XCHAR2B_BYTE2 (s->char2b + from + i);
+ BLOCK_INPUT;
if (with_background > 0)
- XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
- gc, x, y, str, len);
+ {
+ if (s->padding_p)
+ for (i = 0; i < len; i++)
+ XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x + i, y, str + i, 1);
+ else
+ XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x, y, str, len);
+ }
else
- XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
- gc, x, y, str, len);
+ {
+ if (s->padding_p)
+ for (i = 0; i < len; i++)
+ XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x + i, y, str + i, 1);
+ else
+ XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x, y, str, len);
+ }
+ UNBLOCK_INPUT;
SAFE_FREE ();
return s->nchars;
}
+ BLOCK_INPUT;
if (with_background > 0)
- XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
- gc, x, y, s->char2b + from, len);
+ {
+ if (s->padding_p)
+ for (i = 0; i < len; i++)
+ XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x + i, y, s->char2b + from + i, 1);
+ else
+ XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x, y, s->char2b + from, len);
+ }
else
- XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
- gc, x, y, s->char2b + from, len);
+ {
+ if (s->padding_p)
+ for (i = 0; i < len; i++)
+ XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x + i, y, s->char2b + from + i, 1);
+ else
+ XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f),
+ gc, x, y, s->char2b + from, len);
+ }
+ UNBLOCK_INPUT;
return len;
}
+static int
+xfont_check (f, font)
+ FRAME_PTR f;
+ struct font *font;
+{
+ struct xfont_info *xfont = (struct xfont_info *) font;
+
+ return (FRAME_X_DISPLAY (f) == xfont->display ? 0 : -1);
+}
+
\f
void
syms_of_xfont ()
{
+ staticpro (&xfont_scripts_cache);
+ { /* Here we rely on the fact that syms_of_xfont (via syms_of_font)
+ is called fairly late, when QCtest and Qequal are known to be set. */
+ Lisp_Object args[2];
+ args[0] = QCtest;
+ args[1] = Qequal;
+ xfont_scripts_cache = Fmake_hash_table (2, args);
+ }
+ staticpro (&xfont_scratch_props);
+ xfont_scratch_props = Fmake_vector (make_number (8), Qnil);
xfont_driver.type = Qx;
register_font_driver (&xfont_driver, NULL);
}