]> code.delx.au - gnu-emacs/blobdiff - src/xfont.c
Fix for Bug#5984.
[gnu-emacs] / src / xfont.c
index 3a49d7246d3441a89ab29d82c03dcc7f998cca98..d8fe40eaa93996715460cfdfa8409fa910066f4d 100644 (file)
@@ -1,6 +1,6 @@
 /* xfont.c -- X core font driver.
 /* xfont.c -- X core font driver.
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
-   Copyright (C) 2006, 2007, 2008
+   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
 
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H13PRO009
 
@@ -22,6 +22,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <setjmp.h>
 #include <X11/Xlib.h>
 
 #include "lisp.h"
 #include <X11/Xlib.h>
 
 #include "lisp.h"
@@ -49,10 +50,6 @@ struct xfont_info
 extern void x_clear_errors P_ ((Display *));
 
 static XCharStruct *xfont_get_pcm P_ ((XFontStruct *, XChar2b *));
 extern void x_clear_errors P_ ((Display *));
 
 static XCharStruct *xfont_get_pcm P_ ((XFontStruct *, XChar2b *));
-static void xfont_find_ccl_program P_ ((struct font *));
-static int xfont_registry_charsets P_ ((Lisp_Object, struct charset **,
-                                       struct charset **));
-
 
 /* Get metrics of character CHAR2B in XFONT.  Value is null if CHAR2B
    is not contained in the font.  */
 
 /* Get metrics of character CHAR2B in XFONT.  Value is null if CHAR2B
    is not contained in the font.  */
@@ -65,7 +62,7 @@ xfont_get_pcm (xfont, char2b)
   /* The result metric information.  */
   XCharStruct *pcm = NULL;
 
   /* The result metric information.  */
   XCharStruct *pcm = NULL;
 
-  xassert (xfont && char2b);
+  font_assert (xfont && char2b);
 
   if (xfont->per_char != NULL)
     {
 
   if (xfont->per_char != NULL)
     {
@@ -122,42 +119,6 @@ xfont_get_pcm (xfont, char2b)
          ? NULL : pcm);
 }
 
          ? NULL : pcm);
 }
 
-/* Find a CCL program for a font specified by FONTP, and set the member
- `encoder' of the structure.  */
-
-static void
-xfont_find_ccl_program (font)
-     struct font *font;
-{
-  Lisp_Object list, elt;
-
-  elt = Qnil;
-  for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
-    {
-      elt = XCAR (list);
-      if (CONSP (elt)
-         && STRINGP (XCAR (elt))
-         && ((fast_string_match_ignore_case (XCAR (elt),
-                                             font->props[FONT_NAME_INDEX])
-              >= 0)
-             || (fast_string_match_ignore_case (XCAR (elt),
-                                                font->props[FONT_FULLNAME_INDEX])
-                 >= 0)))
-       break;
-    }
-
-  if (! NILP (list))
-    {
-      struct ccl_program *ccl
-       = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
-
-      if (setup_ccl_program (ccl, XCDR (elt)) < 0)
-       xfree (ccl);
-      else
-       font->font_encoder = ccl;
-    }
-}
-
 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_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));
@@ -190,7 +151,9 @@ struct font_driver xfont_driver =
     xfont_text_extents,
     xfont_draw,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     xfont_text_extents,
     xfont_draw,
     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-    xfont_check
+    xfont_check,
+    NULL, /* get_variation_glyphs */
+    NULL, /* filter_properties */
   };
 
 extern Lisp_Object QCname;
   };
 
 extern Lisp_Object QCname;
@@ -209,21 +172,209 @@ extern Lisp_Object Vface_alternative_font_registry_alist;
 static int
 compare_font_names (const void *name1, const void *name2)
 {
 static int
 compare_font_names (const void *name1, const void *name2)
 {
-  return strcasecmp (*(const char **) name1, *(const char **) 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_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;
 }
 
 }
 
-static Lisp_Object xfont_list_pattern P_ ((Lisp_Object, Display *, char *));
+extern Lisp_Object Vscalable_fonts_allowed;
 
 static Lisp_Object
 
 static Lisp_Object
-xfont_list_pattern (frame, display, pattern)
-     Lisp_Object frame;
-     Display *display;
-     char *pattern;
+xfont_list_pattern (Display *display, char *pattern,
+                   Lisp_Object registry, Lisp_Object script)
 {
   Lisp_Object list = Qnil;
 {
   Lisp_Object list = Qnil;
+  Lisp_Object chars = Qnil;
+  struct charset *encoding, *repertory = NULL;
   int i, limit, num_fonts;
   char **names;
   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);
 
   BLOCK_INPUT;
   x_catch_errors (display);
 
@@ -246,7 +397,11 @@ xfont_list_pattern (frame, display, pattern)
   if (num_fonts > 0)
     {
       char **indices = alloca (sizeof (char *) * num_fonts);
   if (num_fonts > 0)
     {
       char **indices = alloca (sizeof (char *) * num_fonts);
+      Lisp_Object *props = XVECTOR (xfont_scratch_props)->contents;
+      Lisp_Object scripts = Qnil;
 
 
+      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);
       for (i = 0; i < num_fonts; i++)
        indices[i] = names[i];
       qsort (indices, num_fonts, sizeof (char *), compare_font_names);
@@ -254,50 +409,90 @@ xfont_list_pattern (frame, display, pattern)
       for (i = 0; i < num_fonts; i++)
        {
          Lisp_Object entity;
       for (i = 0; i < num_fonts; i++)
        {
          Lisp_Object entity;
-         int result;
 
 
-         if (i > 0 && strcasecmp (indices[i - 1], indices[i]) == 0)
+         if (i > 0 && xstrcasecmp (indices[i - 1], indices[i]) == 0)
            continue;
            continue;
-
          entity = font_make_entity ();
          entity = font_make_entity ();
+         xfont_decode_coding_xlfd (indices[i], -1, buf);
+         if (font_parse_xlfd (buf, entity) < 0)
+           continue;
          ASET (entity, FONT_TYPE_INDEX, Qx);
          ASET (entity, FONT_TYPE_INDEX, Qx);
-
-         result = font_parse_xlfd (indices[i], entity);
-         if (result < 0)
+         /* 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))
            {
            {
-             /* This may be an alias name.  Try to get the full XLFD name
-                from XA_FONT property of the font.  */
-             XFontStruct *font = XLoadQueryFont (display, indices[i]);
-             unsigned long value;
+             int size = 0;
 
 
-             if (! font)
+             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;
                continue;
-             if (XGetFontProperty (font, XA_FONT, &value))
+           }
+         else if (CONSP (Vscalable_fonts_allowed))
+           {
+             Lisp_Object tail, elt;
+
+             for (tail = Vscalable_fonts_allowed; CONSP (tail);
+                  tail = XCDR (tail))
                {
                {
-                 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);
+                 elt = XCAR (tail);
+                 if (STRINGP (elt)
+                     && fast_c_string_match_ignore_case (elt, indices[i]) >= 0)
+                   break;
                }
                }
-             XFreeFont (display, font);
+             if (! CONSP (tail))
+               continue;
            }
 
            }
 
-         if (result == 0
-             /* Avoid auto-scaled fonts.  */
-             && (XINT (AREF (entity, FONT_DPI_INDEX)) == 0
-                 || XINT (AREF (entity, FONT_AVGWIDTH_INDEX)) > 0))
+         /* Avoid fonts of invalid registry.  */
+         if (NILP (AREF (entity, FONT_REGISTRY_INDEX)))
+           continue;
+
+         /* Update encoding and repertory if necessary.  */
+         if (! EQ (registry, AREF (entity, FONT_REGISTRY_INDEX)))
+           {
+             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);
+           }
+         if (NILP (script)
+             || ! NILP (Fmemq (script, scripts)))
            list = Fcons (entity, list);
        }
            list = Fcons (entity, list);
        }
+      XFreeFontNames (names);
     }
 
   x_uncatch_errors ();
   UNBLOCK_INPUT;
 
     }
 
   x_uncatch_errors ();
   UNBLOCK_INPUT;
 
+  FONT_ADD_LOG ("xfont-list", build_string (pattern), list);
   return list;
 }
 
   return list;
 }
 
@@ -307,18 +502,15 @@ xfont_list (frame, spec)
 {
   FRAME_PTR f = XFRAME (frame);
   Display *display = FRAME_X_DISPLAY_INFO (f)->display;
 {
   FRAME_PTR f = XFRAME (frame);
   Display *display = FRAME_X_DISPLAY_INFO (f)->display;
-  Lisp_Object registry, list, val, extra, font_name;
-  Lisp_Object dpi, avgwidth;
+  Lisp_Object registry, list, val, extra, script;
   int len;
   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);
   if (CONSP (extra))
     {
       val = assq_no_quit (QCotf, extra);
   extra = AREF (spec, FONT_EXTRA_INDEX);
   if (CONSP (extra))
     {
       val = assq_no_quit (QCotf, extra);
-      if (! NILP (val))
-       return Qnil;
-      val = assq_no_quit (QCscript, extra);
       if (! NILP (val))
        return Qnil;
       val = assq_no_quit (QClang, extra);
       if (! NILP (val))
        return Qnil;
       val = assq_no_quit (QClang, extra);
@@ -327,13 +519,13 @@ xfont_list (frame, spec)
     }
 
   registry = AREF (spec, FONT_REGISTRY_INDEX);
     }
 
   registry = AREF (spec, FONT_REGISTRY_INDEX);
-  if (NILP (registry))
-    ASET (spec, FONT_REGISTRY_INDEX, Qiso8859_1);
-  len = font_unparse_xlfd (spec, 0, name, 256);
-  ASET (spec, FONT_REGISTRY_INDEX, registry);
-  if (len < 0)
+  len = font_unparse_xlfd (spec, 0, name, 512);
+  if (len < 0 || (len = xfont_encode_coding_xlfd (name)) < 0)
     return Qnil;
     return Qnil;
-  list = xfont_list_pattern (frame, display, name);
+
+  val = assq_no_quit (QCscript, extra);
+  script = CDR (val);
+  list = xfont_list_pattern (display, name, registry, script);
   if (NILP (list) && NILP (registry))
     {
       /* Try iso10646-1 */
   if (NILP (list) && NILP (registry))
     {
       /* Try iso10646-1 */
@@ -342,11 +534,12 @@ xfont_list (frame, spec)
       if (r - name + 10 < 256) /* 10 == strlen (iso10646-1) */
        {
          strcpy (r, "iso10646-1");
       if (r - name + 10 < 256) /* 10 == strlen (iso10646-1) */
        {
          strcpy (r, "iso10646-1");
-         list = xfont_list_pattern (frame, display, name);
+         list = xfont_list_pattern (display, name, Qiso10646_1, script);
        }
     }
   if (NILP (list) && ! NILP (registry))
     {
        }
     }
   if (NILP (list) && ! NILP (registry))
     {
+      /* Try alternate registries.  */
       Lisp_Object alter;
 
       if ((alter = Fassoc (SYMBOL_NAME (registry),
       Lisp_Object alter;
 
       if ((alter = Fassoc (SYMBOL_NAME (registry),
@@ -361,12 +554,24 @@ xfont_list (frame, spec)
                && ((r - name) + SBYTES (XCAR (alter))) < 256)
              {
                strcpy (r, (char *) SDATA (XCAR (alter)));
                && ((r - name) + SBYTES (XCAR (alter))) < 256)
              {
                strcpy (r, (char *) SDATA (XCAR (alter)));
-               list = xfont_list_pattern (frame, display, name);
+               list = xfont_list_pattern (display, name, registry, script);
                if (! NILP (list))
                  break;
              }
        }
     }
                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 list;
 }
 
   return list;
 }
@@ -378,7 +583,7 @@ xfont_match (frame, spec)
   FRAME_PTR f = XFRAME (frame);
   Display *display = FRAME_X_DISPLAY_INFO (f)->display;
   Lisp_Object extra, val, entity;
   FRAME_PTR f = XFRAME (frame);
   Display *display = FRAME_X_DISPLAY_INFO (f)->display;
   Lisp_Object extra, val, entity;
-  char buf[256], *name;
+  char name[512];
   XFontStruct *xfont;
   unsigned long value;
 
   XFontStruct *xfont;
   unsigned long value;
 
@@ -386,12 +591,15 @@ xfont_match (frame, spec)
   val = assq_no_quit (QCname, extra);
   if (! CONSP (val) || ! STRINGP (XCDR (val)))
     {
   val = assq_no_quit (QCname, extra);
   if (! CONSP (val) || ! STRINGP (XCDR (val)))
     {
-      if (font_unparse_xlfd (spec, 0, buf, 256) < 0)
+      if (font_unparse_xlfd (spec, 0, name, 512) < 0)
        return Qnil;
        return Qnil;
-      name = buf;
     }
     }
+  else if (SBYTES (XCDR (val)) < 512)
+    bcopy (SDATA (XCDR (val)), name, SBYTES (XCDR (val)) + 1);
   else
   else
-    name = (char *) SDATA (XCDR (val));
+    return Qnil;
+  if (xfont_encode_coding_xlfd (name) < 0)
+    return Qnil;
 
   BLOCK_INPUT;
   entity = Qnil;
 
   BLOCK_INPUT;
   entity = Qnil;
@@ -401,9 +609,10 @@ xfont_match (frame, spec)
       if (XGetFontProperty (xfont, XA_FONT, &value))
        {
          int len;
       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
 
          /* If DXPC (a Differential X Protocol Compressor)
             Ver.3.7 is running, XGetAtomName will return null
@@ -412,27 +621,20 @@ xfont_match (frame, spec)
            {
              entity = font_make_entity ();
              ASET (entity, FONT_TYPE_INDEX, Qx);
            {
              entity = font_make_entity ();
              ASET (entity, FONT_TYPE_INDEX, Qx);
+             xfont_decode_coding_xlfd (s, -1, name);
              if (font_parse_xlfd (name, entity) < 0)
                entity = Qnil;
            }
              if (font_parse_xlfd (name, entity) < 0)
                entity = Qnil;
            }
-         XFree (name);
+         XFree (s);
        }
       XFreeFont (display, xfont);
     }
   UNBLOCK_INPUT;
 
        }
       XFreeFont (display, xfont);
     }
   UNBLOCK_INPUT;
 
+  FONT_ADD_LOG ("xfont-match", spec, entity);
   return 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;
 static Lisp_Object
 xfont_list_family (frame)
      Lisp_Object frame;
@@ -460,8 +662,9 @@ xfont_list_family (frame)
   list = Qnil;
   for (i = 0, last_len = 0; i < num_fonts; i++)
     {
   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;
       Lisp_Object family;
+      int decoded_len;
 
       p0++;                    /* skip the leading '-' */
       while (*p0 && *p0 != '-') p0++; /* skip foundry */
 
       p0++;                    /* skip the leading '-' */
       while (*p0 && *p0 != '-') p0++; /* skip foundry */
@@ -476,8 +679,10 @@ xfont_list_family (frame)
        continue;
       last_len = p1 - p0;
       last_family = p0;
        continue;
       last_len = p1 - p0;
       last_family = p0;
-      family = make_unibyte_string (p0, last_len);
-      if (NILP (Fassoc_string (family, list, Qt)))
+
+      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);
     }
 
        list = Fcons (family, list);
     }
 
@@ -498,7 +703,7 @@ xfont_open (f, entity, pixel_size)
 {
   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
   Display *display = dpyinfo->display;
 {
   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;
   int len;
   unsigned long value;
   Lisp_Object registry;
@@ -506,13 +711,15 @@ xfont_open (f, entity, pixel_size)
   Lisp_Object font_object, fullname;
   struct font *font;
   XFontStruct *xfont;
   Lisp_Object font_object, fullname;
   struct font *font;
   XFontStruct *xfont;
-  int i;
 
   /* At first, check if we know how to encode characters for this
      font.  */
   registry = AREF (entity, FONT_REGISTRY_INDEX);
   if (font_registry_charsets (registry, &encoding, &repertory) < 0)
 
   /* At first, check if we know how to encode characters for this
      font.  */
   registry = AREF (entity, FONT_REGISTRY_INDEX);
   if (font_registry_charsets (registry, &encoding, &repertory) < 0)
-    return Qnil;
+    {
+      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));
 
   if (XINT (AREF (entity, FONT_SIZE_INDEX)) != 0)
     pixel_size = XINT (AREF (entity, FONT_SIZE_INDEX));
@@ -523,9 +730,12 @@ xfont_open (f, entity, pixel_size)
       else
        pixel_size = 14;
     }
       else
        pixel_size = 14;
     }
-  len = font_unparse_xlfd (entity, pixel_size, name, 256);
-  if (len <= 0)
-    return Qnil;
+  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);
 
   BLOCK_INPUT;
   x_catch_errors (display);
@@ -537,6 +747,35 @@ xfont_open (f, entity, pixel_size)
       x_clear_errors (display);
       xfont = NULL;
     }
       x_clear_errors (display);
       xfont = NULL;
     }
+  else if (! xfont)
+    {
+      /* 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)
+       {
+         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;
+       }
+    }
   fullname = Qnil;
   /* Try to get the full name of FONT.  */
   if (xfont && XGetFontProperty (xfont, XA_FONT, &value))
   fullname = Qnil;
   /* Try to get the full name of FONT.  */
   if (xfont && XGetFontProperty (xfont, XA_FONT, &value))
@@ -544,7 +783,7 @@ xfont_open (f, entity, pixel_size)
       char *p0, *p;
       int dashes = 0;
 
       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.
       /* 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.
@@ -558,26 +797,36 @@ xfont_open (f, entity, pixel_size)
        }
 
       if (dashes >= 13)
        }
 
       if (dashes >= 13)
-       fullname = Fdowncase (make_unibyte_string (p0, p - p0));
+       {
+         len = xfont_decode_coding_xlfd (p0, -1, name);
+         fullname = Fdowncase (make_string (name, len));
+       }
       XFree (p0);
     }
   x_uncatch_errors ();
   UNBLOCK_INPUT;
 
   if (! xfont)
       XFree (p0);
     }
   x_uncatch_errors ();
   UNBLOCK_INPUT;
 
   if (! xfont)
-    return Qnil;
+    {
+      FONT_ADD_LOG ("  x:open failed", build_string (name), Qnil);
+      return Qnil;
+    }
 
 
-  font_object = font_make_object (VECSIZE (struct xfont_info));
+  font_object = font_make_object (VECSIZE (struct xfont_info),
+                                 entity, pixel_size);
   ASET (font_object, FONT_TYPE_INDEX, Qx);
   if (STRINGP (fullname))
   ASET (font_object, FONT_TYPE_INDEX, Qx);
   if (STRINGP (fullname))
-    font_parse_xlfd (SDATA (fullname), font_object);
-  for (i = 1; i < FONT_ENTITY_MAX; i++)
-    ASET (font_object, i, AREF (entity, i));
-  ASET (font_object, FONT_SIZE_INDEX, make_number (pixel_size));
-  if (STRINGP (fullname))
-    ASET (font_object, FONT_NAME_INDEX, fullname);
+    {
+      font_parse_xlfd ((char *) SDATA (fullname), font_object);
+      ASET (font_object, FONT_NAME_INDEX, fullname);
+    }
   else
   else
-    ASET (font_object, FONT_NAME_INDEX, make_unibyte_string (name, len));
+    {
+      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);
   ASET (font_object, FONT_FULLNAME_INDEX, fullname);
   ASET (font_object, FONT_FILE_INDEX, Qnil);
   ASET (font_object, FONT_FORMAT_INDEX, Qx);
@@ -623,8 +872,14 @@ xfont_open (f, entity, pixel_size)
          for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
            if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
              width += pcm->width, n++;
          for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++)
            if ((pcm = xfont_get_pcm (xfont, &char2b)) != NULL)
              width += pcm->width, n++;
-         font->average_width = 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;
     }
 
   BLOCK_INPUT;
     }
 
   BLOCK_INPUT;
@@ -679,15 +934,31 @@ xfont_prepare_face (f, face)
 }
 
 static int
 }
 
 static int
-xfont_has_char (entity, c)
-     Lisp_Object entity;
+xfont_has_char (font, c)
+     Lisp_Object font;
      int c;
 {
      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));
   if (! repertory)
     return -1;
   return (ENCODE_CHAR (repertory, c) != CHARSET_INVALID_CODE (repertory));
@@ -727,11 +998,11 @@ xfont_text_extents (font, code, nglyphs, metrics)
 {
   XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
   int width = 0;
 {
   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));
 
   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;
     {
       XChar2b char2b;
       static XCharStruct *pcm;
@@ -742,14 +1013,31 @@ xfont_text_extents (font, code, nglyphs, metrics)
       pcm = xfont_get_pcm (xfont, &char2b);
       if (! pcm)
        continue;
       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)
       width += pcm->width;
     }
   if (metrics)
@@ -848,6 +1136,16 @@ xfont_check (f, font)
 void
 syms_of_xfont ()
 {
 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);
 }
   xfont_driver.type = Qx;
   register_font_driver (&xfont_driver, NULL);
 }