]> code.delx.au - gnu-emacs/blobdiff - src/xfont.c
On C-y, stop some text property entries being written into buffer-undo-list
[gnu-emacs] / src / xfont.c
index 9978aba76de52abbfcd4b66009fd9d7b6a0b021f..d5a7d64e6972ef7419bfbc5999bfa921863d7985 100644 (file)
@@ -1,5 +1,5 @@
 /* xfont.c -- X core font driver.
-   Copyright (C) 2006-2013 Free Software Foundation, Inc.
+   Copyright (C) 2006-2015 Free Software Foundation, Inc.
    Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H13PRO009
@@ -42,6 +42,7 @@ struct xfont_info
   struct font font;
   Display *display;
   XFontStruct *xfont;
+  unsigned x_display_id;
 };
 
 /* Prototypes of support functions.  */
@@ -114,24 +115,24 @@ xfont_get_pcm (XFontStruct *xfont, XChar2b *char2b)
          ? NULL : pcm);
 }
 
-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 Lisp_Object xfont_get_cache (struct frame *);
+static Lisp_Object xfont_list (struct frame *, Lisp_Object);
+static Lisp_Object xfont_match (struct frame *, Lisp_Object);
+static Lisp_Object xfont_list_family (struct frame *);
+static Lisp_Object xfont_open (struct frame *, Lisp_Object, int);
+static void xfont_close (struct font *);
+static void xfont_prepare_face (struct frame *, 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 void xfont_text_extents (struct font *, unsigned *, int,
+                               struct font_metrics *);
 static int xfont_draw (struct glyph_string *, int, int, int, int, bool);
-static int xfont_check (FRAME_PTR, struct font *);
+static int xfont_check (struct frame *, struct font *);
 
 struct font_driver xfont_driver =
   {
     LISP_INITIALLY_ZERO,       /* Qx */
-    0,                         /* case insensitive */
+    false,                     /* case insensitive */
     xfont_get_cache,
     xfont_list,
     xfont_match,
@@ -145,16 +146,16 @@ struct font_driver xfont_driver =
     xfont_encode_char,
     xfont_text_extents,
     xfont_draw,
-    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
     xfont_check,
     NULL, /* get_variation_glyphs */
     NULL, /* filter_properties */
   };
 
 static Lisp_Object
-xfont_get_cache (FRAME_PTR f)
+xfont_get_cache (struct frame *f)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
   return (dpyinfo->name_list_element);
 }
@@ -268,7 +269,7 @@ xfont_chars_supported (Lisp_Object chars, XFontStruct *xfont,
        }
       return (i >= 0);
     }
-  return 0;
+  return false;
 }
 
 /* A hash table recoding which font supports which scripts.  Each key
@@ -295,9 +296,9 @@ xfont_supported_scripts (Display *display, char *fontname, Lisp_Object props,
 
   /* Two special cases to avoid opening rather big fonts.  */
   if (EQ (AREF (props, 2), Qja))
-    return Fcons (intern ("kana"), Fcons (intern ("han"), Qnil));
+    return list2 (intern ("kana"), intern ("han"));
   if (EQ (AREF (props, 2), Qko))
-    return Fcons (intern ("hangul"), Qnil);
+    return list1 (intern ("hangul"));
   scripts = Fgethash (props, xfont_scripts_cache, Qt);
   if (EQ (scripts, Qt))
     {
@@ -385,7 +386,7 @@ xfont_list_pattern (Display *display, const char *pattern,
     {
       char **indices = alloca (sizeof (char *) * num_fonts);
       Lisp_Object *props = XVECTOR (xfont_scratch_props)->contents;
-      Lisp_Object scripts = Qnil;
+      Lisp_Object scripts = Qnil, entity = Qnil;
 
       for (i = 0; i < ASIZE (xfont_scratch_props); i++)
        ASET (xfont_scratch_props, i, Qnil);
@@ -393,88 +394,101 @@ xfont_list_pattern (Display *display, const char *pattern,
        indices[i] = names[i];
       qsort (indices, num_fonts, sizeof (char *), compare_font_names);
 
-      for (i = 0; i < num_fonts; i++)
-       {
-         ptrdiff_t len;
-         Lisp_Object entity;
+      /* Take one or two passes over the font list.  Do the second
+        pass only if we really need it, i.e., only if the first pass
+        found no fonts and skipped some scalable fonts.  */
+      bool skipped_some_scalable_fonts = false;
+      for (int i_pass = 0;
+          (i_pass == 0
+           || (i_pass == 1 && NILP (list) && skipped_some_scalable_fonts));
+          i_pass++)
+       for (i = 0; i < num_fonts; i++)
+         {
+           ptrdiff_t len;
+
+           if (i > 0 && xstrcasecmp (indices[i - 1], indices[i]) == 0)
+             continue;
+           if (NILP (entity))
+             entity = font_make_entity ();
+           len = xfont_decode_coding_xlfd (indices[i], -1, buf);
+           if (font_parse_xlfd (buf, len, entity) < 0)
+             continue;
+           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))
+             {
+               int size = 0;
 
-         if (i > 0 && xstrcasecmp (indices[i - 1], indices[i]) == 0)
-           continue;
-         entity = font_make_entity ();
-         len = xfont_decode_coding_xlfd (indices[i], -1, buf);
-         if (font_parse_xlfd (buf, len, entity) < 0)
-           continue;
-         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))
-           {
-             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 && i_pass == 0)
+                 {
+                   skipped_some_scalable_fonts = true;
+                   continue;
+                 }
+             }
+           else if (CONSP (Vscalable_fonts_allowed))
+             {
+               Lisp_Object tail;
 
-             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],
-                                                         len) >= 0)
-                   break;
-               }
-             if (! CONSP (tail))
-               continue;
-           }
+               for (tail = Vscalable_fonts_allowed; CONSP (tail);
+                    tail = XCDR (tail))
+                 {
+                   Lisp_Object elt = XCAR (tail);
+                   if (STRINGP (elt)
+                       && (fast_c_string_match_ignore_case (elt, indices[i],
+                                                            len)
+                           >= 0))
+                     break;
+                 }
+               if (! CONSP (tail))
+                 continue;
+             }
 
-         /* Avoid fonts of invalid registry.  */
-         if (NILP (AREF (entity, FONT_REGISTRY_INDEX)))
-           continue;
+           /* 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);
+           /* 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 (memcmp (props, aref_addr (entity, FONT_FOUNDRY_INDEX),
-                     word_size * 7)
-             || ! EQ (AREF (entity, FONT_SPACING_INDEX), props[7]))
-           {
-             vcopy (xfont_scratch_props, 0,
-                    aref_addr (entity, FONT_FOUNDRY_INDEX), 7);
-             ASET (xfont_scratch_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);
-       }
+           if (repertory)
+             {
+               if (NILP (script)
+                   || xfont_chars_supported (chars, NULL, encoding, repertory))
+                 list = Fcons (entity, list), entity = Qnil;
+               continue;
+             }
+           if (memcmp (props, aref_addr (entity, FONT_FOUNDRY_INDEX),
+                       word_size * 7)
+               || ! EQ (AREF (entity, FONT_SPACING_INDEX), props[7]))
+             {
+               vcopy (xfont_scratch_props, 0,
+                      aref_addr (entity, FONT_FOUNDRY_INDEX), 7);
+               ASET (xfont_scratch_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), entity = Qnil;
+         }
       XFreeFontNames (names);
     }
 
@@ -486,10 +500,9 @@ xfont_list_pattern (Display *display, const char *pattern,
 }
 
 static Lisp_Object
-xfont_list (Lisp_Object frame, Lisp_Object spec)
+xfont_list (struct frame *f, Lisp_Object spec)
 {
-  FRAME_PTR f = XFRAME (frame);
-  Display *display = FRAME_X_DISPLAY_INFO (f)->display;
+  Display *display = FRAME_DISPLAY_INFO (f)->display;
   Lisp_Object registry, list, val, extra, script;
   int len;
   /* Large enough to contain the longest XLFD (255 bytes) in UTF-8.  */
@@ -541,7 +554,7 @@ xfont_list (Lisp_Object frame, Lisp_Object spec)
            if (STRINGP (XCAR (alter))
                && ((r - name) + SBYTES (XCAR (alter))) < 256)
              {
-               strcpy (r, SSDATA (XCAR (alter)));
+               lispstpcpy (r, XCAR (alter));
                list = xfont_list_pattern (display, name, registry, script);
                if (! NILP (list))
                  break;
@@ -565,10 +578,9 @@ xfont_list (Lisp_Object frame, Lisp_Object spec)
 }
 
 static Lisp_Object
-xfont_match (Lisp_Object frame, Lisp_Object spec)
+xfont_match (struct frame *f, Lisp_Object spec)
 {
-  FRAME_PTR f = XFRAME (frame);
-  Display *display = FRAME_X_DISPLAY_INFO (f)->display;
+  Display *display = FRAME_DISPLAY_INFO (f)->display;
   Lisp_Object extra, val, entity;
   char name[512];
   XFontStruct *xfont;
@@ -595,9 +607,7 @@ xfont_match (Lisp_Object frame, Lisp_Object spec)
     {
       if (XGetFontProperty (xfont, XA_FONT, &value))
        {
-         char *s;
-
-         s = (char *) XGetAtomName (display, (Atom) value);
+         char *s = XGetAtomName (display, (Atom) value);
 
          /* If DXPC (a Differential X Protocol Compressor)
             Ver.3.7 is running, XGetAtomName will return null
@@ -622,10 +632,9 @@ xfont_match (Lisp_Object frame, Lisp_Object spec)
 }
 
 static Lisp_Object
-xfont_list_family (Lisp_Object frame)
+xfont_list_family (struct frame *f)
 {
-  FRAME_PTR f = XFRAME (frame);
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
   char **names;
   int num_fonts, i;
   Lisp_Object list;
@@ -679,9 +688,9 @@ xfont_list_family (Lisp_Object frame)
 }
 
 static Lisp_Object
-xfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
+xfont_open (struct frame *f, Lisp_Object entity, int pixel_size)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
   Display *display = dpyinfo->display;
   char name[512];
   int len;
@@ -763,7 +772,7 @@ xfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
       char *p0, *p;
       int dashes = 0;
 
-      p0 = p = (char *) XGetAtomName (FRAME_X_DISPLAY (f), (Atom) value);
+      p0 = p = 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.
@@ -808,11 +817,10 @@ xfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
       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);
+  ((struct xfont_info *) font)->x_display_id = FRAME_DISPLAY_INFO (f)->x_id;
   font->pixel_size = pixel_size;
   font->driver = &xfont_driver;
   font->encoding_charset = encoding->id;
@@ -895,22 +903,37 @@ xfont_open (FRAME_PTR f, Lisp_Object entity, int pixel_size)
 }
 
 static void
-xfont_close (FRAME_PTR f, struct font *font)
+xfont_close (struct font *font)
 {
-  block_input ();
-  XFreeFont (FRAME_X_DISPLAY (f), ((struct xfont_info *) font)->xfont);
-  unblock_input ();
+  struct x_display_info *xdi;
+  struct xfont_info *xfi = (struct xfont_info *) font;
+
+  /* This function may be called from GC when X connection is gone
+     (Bug#16093), and an attempt to free font resources on invalid
+     display may lead to X protocol errors or segfaults.  Moreover,
+     the memory referenced by 'Display *' pointer may be reused for
+     the logically different X connection after the previous display
+     connection was closed.  That's why we also check whether font's
+     ID matches the one recorded in x_display_info for this display.
+     See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16069.  */
+  if (xfi->xfont
+      && ((xdi = x_display_info_for_display (xfi->display))
+         && xfi->x_display_id == xdi->x_id))
+    {
+      block_input ();
+      XFreeFont (xfi->display, xfi->xfont);
+      unblock_input ();
+      xfi->xfont = NULL;
+    }
 }
 
-static int
-xfont_prepare_face (FRAME_PTR f, struct face *face)
+static void
+xfont_prepare_face (struct frame *f, struct face *face)
 {
   block_input ();
   XSetFont (FRAME_X_DISPLAY (f), face->gc,
            ((struct xfont_info *) face->font)->xfont->fid);
   unblock_input ();
-
-  return 0;
 }
 
 static int
@@ -965,16 +988,15 @@ xfont_encode_char (struct font *font, int c)
   return (xfont_get_pcm (xfont, &char2b) ? code : FONT_INVALID_CODE);
 }
 
-static int
-xfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct font_metrics *metrics)
+static void
+xfont_text_extents (struct font *font, unsigned int *code,
+                   int nglyphs, struct font_metrics *metrics)
 {
   XFontStruct *xfont = ((struct xfont_info *) font)->xfont;
-  int width = 0;
-  int i, first;
+  int i, width = 0;
+  bool first;
 
-  if (metrics)
-    memset (metrics, 0, sizeof (struct font_metrics));
-  for (i = 0, first = 1; i < nglyphs; i++)
+  for (i = 0, first = true; i < nglyphs; i++)
     {
       XChar2b char2b;
       static XCharStruct *pcm;
@@ -987,34 +1009,27 @@ xfont_text_extents (struct font *font, unsigned int *code, int nglyphs, struct f
        continue;
       if (first)
        {
-         if (metrics)
-           {
-             metrics->lbearing = pcm->lbearing;
-             metrics->rbearing = pcm->rbearing;
-             metrics->ascent = pcm->ascent;
-             metrics->descent = pcm->descent;
-           }
-         first = 0;
+         metrics->lbearing = pcm->lbearing;
+         metrics->rbearing = pcm->rbearing;
+         metrics->ascent = pcm->ascent;
+         metrics->descent = pcm->descent;
+         first = false;
        }
       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;
-           }
+         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)
-    metrics->width = width;
-  return width;
+
+  metrics->width = width;
 }
 
 static int
@@ -1092,7 +1107,7 @@ xfont_draw (struct glyph_string *s, int from, int to, int x, int y,
 }
 
 static int
-xfont_check (FRAME_PTR f, struct font *font)
+xfont_check (struct frame *f, struct font *font)
 {
   struct xfont_info *xfont = (struct xfont_info *) font;
 
@@ -1104,13 +1119,7 @@ void
 syms_of_xfont (void)
 {
   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);
-  }
+  xfont_scripts_cache = CALLN (Fmake_hash_table, QCtest, Qequal);
   staticpro (&xfont_scratch_props);
   xfont_scratch_props = Fmake_vector (make_number (8), Qnil);
   xfont_driver.type = Qx;