Add bug reference.
[bpt/emacs.git] / src / font.c
index 0bd18d4..b5496e8 100644 (file)
@@ -47,8 +47,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "nsterm.h"
 #endif /* HAVE_NS */
 
-Lisp_Object Qfont_spec, Qfont_entity, Qfont_object;
-
 #ifdef HAVE_NS
 extern Lisp_Object Qfontsize;
 #endif
@@ -98,7 +96,7 @@ static struct table_entry weight_table[] =
   { 40, { "extra-light", "extralight" }},
   { 50, { "light" }},
   { 75, { "semi-light", "semilight", "demilight", "book" }},
-  { 100, { "normal", "medium", "regular" }},
+  { 100, { "normal", "medium", "regular", "unspecified" }},
   { 180, { "semi-bold", "semibold", "demibold", "demi" }},
   { 200, { "bold" }},
   { 205, { "extra-bold", "extrabold" }},
@@ -112,7 +110,7 @@ static struct table_entry slant_table[] =
 {
   { 0, { "reverse-oblique", "ro" }},
   { 10, { "reverse-italic", "ri" }},
-  { 100, { "normal", "r" }},
+  { 100, { "normal", "r", "unspecified" }},
   { 200, { "italic" ,"i", "ot" }},
   { 210, { "oblique", "o" }}
 };
@@ -126,7 +124,7 @@ static struct table_entry width_table[] =
   { 63, { "extra-condensed", "extracondensed" }},
   { 75, { "condensed", "compressed", "narrow" }},
   { 87, { "semi-condensed", "semicondensed", "demicondensed" }},
-  { 100, { "normal", "medium", "regular" }},
+  { 100, { "normal", "medium", "regular", "unspecified" }},
   { 113, { "semi-expanded", "semiexpanded", "demiexpanded" }},
   { 125, { "expanded" }},
   { 150, { "extra-expanded", "extraexpanded" }},
@@ -362,12 +360,12 @@ font_style_to_value (prop, val, noerror)
        return -1;
       if (len == 255)
        abort ();
-      elt = Fmake_vector (make_number (2), make_number (255));
+      elt = Fmake_vector (make_number (2), make_number (100));
       ASET (elt, 1, val);
       args[0] = table;
       args[1] = Fmake_vector (make_number (1), elt);
       ASET (font_style_table, prop - FONT_WEIGHT_INDEX, Fvconcat (2, args));
-      return (255 << 8) | (i << 4);
+      return (100 << 8) | (i << 4);
     }
   else
     {
@@ -441,8 +439,7 @@ find_font_encoding (fontname)
              : CONSP (XCDR (elt)) && CHARSETP (XCAR (XCDR (elt)))))
        return (XCDR (elt));
     }
-  /* We don't know the encoding of this font.  Let's assume `ascii'.  */
-  return Qascii;
+  return Qnil;
 }
 
 /* Return encoding charset and repertory charset for REGISTRY in
@@ -722,6 +719,8 @@ font_put_extra (font, prop, val)
     {
       Lisp_Object prev = Qnil;
 
+      if (NILP (val))
+       return val;
       while (CONSP (extra)
             && NILP (Fstring_lessp (prop, XCAR (XCAR (extra)))))
        prev = extra, extra = XCDR (extra);
@@ -732,6 +731,8 @@ font_put_extra (font, prop, val)
       return val;
     }
   XSETCDR (slot, val);
+  if (NILP (val))
+    ASET (font, FONT_EXTRA_INDEX, Fdelq (slot, extra));
   return val;
 }
 
@@ -2296,8 +2297,12 @@ struct font_sort_data
    pixel-size from QCdpi property of PREFER or from the Y-resolution
    of FRAME before sorting.
 
-   If BEST-ONLY is nonzero, return the best matching entity.  Otherwise,
-   return the sorted VEC.  */
+   If BEST-ONLY is nonzero, return the best matching entity (that
+   supports the character BEST-ONLY if BEST-ONLY is positive, or any
+   if BEST-ONLY is negative).  Otherwise, return the sorted VEC.
+
+   This function does no optimization for the case that the length of
+   VEC is 1.  The caller should avoid calling this in such a case.  */
 
 static Lisp_Object
 font_sort_entites (vec, prefer, frame, best_only)
@@ -2315,9 +2320,6 @@ font_sort_entites (vec, prefer, frame, best_only)
   USE_SAFE_ALLOCA;
 
   len = ASIZE (vec);
-  if (len <= 1)
-    return best_only ? AREF (vec, 0) : vec;
-
   for (i = FONT_WEIGHT_INDEX; i <= FONT_DPI_INDEX; i++)
     prefer_prop[i] = AREF (prefer, i);
   if (FLOATP (prefer_prop[FONT_SIZE_INDEX]))
@@ -2326,16 +2328,14 @@ font_sort_entites (vec, prefer, frame, best_only)
 
   /* Scoring and sorting.  */
   SAFE_ALLOCA (data, struct font_sort_data *, (sizeof *data) * len);
-  best_score = 0xFFFFFFFF;
   /* We are sure that the length of VEC > 1.  */
   driver_type = AREF (AREF (vec, 0), FONT_TYPE_INDEX);
   for (driver_order = 0, list = f->font_driver_list; list;
        driver_order++, list = list->next)
     if (EQ (driver_type, list->driver->type))
       break;
-  best_entity = data[0].entity = AREF (vec, 0);
-  best_score = data[0].score
-    = font_score (data[0].entity, prefer_prop) | driver_order;
+  best_score = 0xFFFFFFFF;
+  best_entity = Qnil;
   for (i = 0; i < len; i++)
     {
       if (!EQ (driver_type, AREF (AREF (vec, i), FONT_TYPE_INDEX)))
@@ -2344,7 +2344,10 @@ font_sort_entites (vec, prefer, frame, best_only)
          if (EQ (driver_type, list->driver->type))
            break;
       data[i].entity = AREF (vec, i);
-      data[i].score = font_score (data[i].entity, prefer_prop) | driver_order;
+      data[i].score
+       = (best_only <= 0 || font_has_char (f, data[i].entity, best_only) > 0
+          ? font_score (data[i].entity, prefer_prop) | driver_order
+          : 0xFFFFFFFF);
       if (best_only && best_score > data[i].score)
        {
          best_score = data[i].score;
@@ -2424,7 +2427,10 @@ font_check_otf_features (script, langsys, features, table)
   for (negative = 0; CONSP (features); features = XCDR (features))
     {
       if (NILP (XCAR (features)))
-       negative = 1;
+       {
+         negative = 1;
+         continue;
+       }
       if (NILP (Fmemq (XCAR (features), table)) != negative)
        return 0;
     }
@@ -2748,7 +2754,7 @@ font_delete_unmatched (list, spec, size)
       if (prop < FONT_SPEC_MAX)
        val = Fcons (entity, val);
     }
-  return val;
+  return Fnreverse (val);
 }
 
 
@@ -3078,13 +3084,20 @@ font_clear_prop (attrs, prop)
 
   if (! FONTP (font))
     return;
+  if (! NILP (Ffont_get (font, QCname)))
+    {
+      font = Fcopy_font_spec (font);
+      font_put_extra (font, QCname, Qnil);
+    }
+
   if (NILP (AREF (font, prop))
       && prop != FONT_FAMILY_INDEX
       && prop != FONT_FOUNDRY_INDEX
       && prop != FONT_WIDTH_INDEX
       && prop != FONT_SIZE_INDEX)
     return;
-  font = Fcopy_font_spec (font);
+  if (EQ (font, attrs[LFACE_FONT_INDEX]))
+    font = Fcopy_font_spec (font);
   ASET (font, prop, Qnil);
   if (prop == FONT_FAMILY_INDEX || prop == FONT_FOUNDRY_INDEX)
     {
@@ -3160,6 +3173,52 @@ font_update_lface (f, attrs)
 }
 
 
+/* Selecte a font from ENTITIES that supports C and matches best with
+   ATTRS and PIXEL_SIZE.  */
+
+static Lisp_Object
+font_select_entity (frame, entities, attrs, pixel_size, c)
+     Lisp_Object frame, entities, *attrs;
+     int pixel_size, c;
+{
+  Lisp_Object font_entity;
+  Lisp_Object prefer;
+  Lisp_Object props[FONT_REGISTRY_INDEX + 1] ;
+  int result, i;
+  FRAME_PTR f = XFRAME (frame);
+
+  if (ASIZE (entities) == 1)
+    {
+      font_entity = AREF (entities, 0);
+      if (c < 0
+         || (result = font_has_char (f, font_entity, c)) > 0)
+       return font_entity;
+      return Qnil;
+    }
+
+  /* Sort fonts by properties specified in ATTRS.  */
+  prefer = scratch_font_prefer;
+
+  for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
+    ASET (prefer, i, Qnil);
+  if (FONTP (attrs[LFACE_FONT_INDEX]))
+    {
+      Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
+
+      for (i = FONT_WEIGHT_INDEX; i <= FONT_SIZE_INDEX; i++)
+       ASET (prefer, i, AREF (face_font, i));
+    }
+  if (NILP (AREF (prefer, FONT_WEIGHT_INDEX)))
+    FONT_SET_STYLE (prefer, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
+  if (NILP (AREF (prefer, FONT_SLANT_INDEX)))
+    FONT_SET_STYLE (prefer, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
+  if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
+    FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
+  ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
+
+  return font_sort_entites (entities, prefer, frame, c);
+}
+
 /* Return a font-entity satisfying SPEC and best matching with face's
    font related attributes in ATTRS.  C, if not negative, is a
    character that the entity must support.  */
@@ -3307,74 +3366,17 @@ font_find_for_lface (f, attrs, spec, c)
                  ASET (work, FONT_ADSTYLE_INDEX, adstyle[l]);
                  entities = font_list_entities (frame, work);
                  if (ASIZE (entities) > 0)
-                   goto found;
+                   {
+                     val = font_select_entity (frame, entities,
+                                               attrs, pixel_size, c);
+                     if (! NILP (val))
+                       return val;
+                   }
                }
            }
        }
     }
   return Qnil;
- found:
-  if (ASIZE (entities) == 1)
-    {
-      if (c < 0)
-       return AREF (entities, 0);
-    }
-  else
-    {
-      /* Sort fonts by properties specified in LFACE.  */
-      Lisp_Object prefer = scratch_font_prefer;
-
-      for (i = 0; i < FONT_EXTRA_INDEX; i++)
-       ASET (prefer, i, AREF (work, i));
-      if (FONTP (attrs[LFACE_FONT_INDEX]))
-       {
-         Lisp_Object face_font = attrs[LFACE_FONT_INDEX];
-
-         for (i = 0; i < FONT_EXTRA_INDEX; i++)
-           if (NILP (AREF (prefer, i)))
-             ASET (prefer, i, AREF (face_font, i));
-       }
-      if (NILP (AREF (prefer, FONT_WEIGHT_INDEX)))
-       FONT_SET_STYLE (prefer, FONT_WEIGHT_INDEX, attrs[LFACE_WEIGHT_INDEX]);
-      if (NILP (AREF (prefer, FONT_SLANT_INDEX)))
-       FONT_SET_STYLE (prefer, FONT_SLANT_INDEX, attrs[LFACE_SLANT_INDEX]);
-      if (NILP (AREF (prefer, FONT_WIDTH_INDEX)))
-       FONT_SET_STYLE (prefer, FONT_WIDTH_INDEX, attrs[LFACE_SWIDTH_INDEX]);
-      ASET (prefer, FONT_SIZE_INDEX, make_number (pixel_size));
-      entities = font_sort_entites (entities, prefer, frame, c < 0);
-    }
-  if (c < 0)
-    return entities;
-
-  for (i = 0; i < ASIZE (entities); i++)
-    {
-      int j;
-
-      val = AREF (entities, i);
-      if (i > 0)
-       {
-         for (j = FONT_FOUNDRY_INDEX; j <= FONT_REGISTRY_INDEX; j++)
-           if (! EQ (AREF (val, j), props[j]))
-             break;
-         if (j > FONT_REGISTRY_INDEX)
-           continue;
-       }
-      for (j = FONT_FOUNDRY_INDEX; j <= FONT_REGISTRY_INDEX; j++)
-       props[j] = AREF (val, j);
-      result = font_has_char (f, val, c);
-      if (result > 0)
-       return val;
-      if (result == 0)
-       return Qnil;
-      val = font_open_for_lface (f, val, attrs, spec);
-      if (NILP (val))
-       continue;
-      result = font_has_char (f, val, c);
-      font_close_object (f, val);
-      if (result > 0)
-       return AREF (entities, i);
-    }
-  return Qnil;
 }
 
 
@@ -3432,7 +3434,8 @@ font_load_for_lface (f, attrs, spec)
 {
   Lisp_Object entity;
 
-  entity = font_find_for_lface (f, attrs, spec, -1);
+  /* We assume that a font that supports 'A' supports ASCII chars.  */
+  entity = font_find_for_lface (f, attrs, spec, 'A');
   if (NILP (entity))
     {
       /* No font is listed for SPEC, but each font-backend may have
@@ -3471,20 +3474,16 @@ font_done_for_face (f, face)
 }
 
 
-/* Open a font best matching with NAME on frame F.  If no proper font
-   is found, return Qnil.  */
+/* Open a font matching with font-spec SPEC on frame F.  If no proper
+   font is found, return Qnil.  */
 
 Lisp_Object
-font_open_by_name (f, name)
+font_open_by_spec (f, spec)
      FRAME_PTR f;
-     char *name;
+     Lisp_Object spec;
 {
-  Lisp_Object args[2];
-  Lisp_Object spec, attrs[LFACE_VECTOR_SIZE];
+  Lisp_Object attrs[LFACE_VECTOR_SIZE];
 
-  args[0] = QCname;
-  args[1] = make_unibyte_string (name, strlen (name));
-  spec = Ffont_spec (2, args);
   /* We set up the default font-related attributes of a face to prefer
      a moderate font.  */
   attrs[LFACE_FAMILY_INDEX] = attrs[LFACE_FOUNDRY_INDEX] = Qnil;
@@ -3501,6 +3500,24 @@ font_open_by_name (f, name)
 }
 
 
+/* Open a font matching with NAME on frame F.  If no proper font is
+   found, return Qnil.  */
+
+Lisp_Object
+font_open_by_name (f, name)
+     FRAME_PTR f;
+     char *name;
+{
+  Lisp_Object args[2];
+  Lisp_Object spec;
+
+  args[0] = QCname;
+  args[1] = make_unibyte_string (name, strlen (name));
+  spec = Ffont_spec (2, args);
+  return font_open_by_spec (f, spec);
+}
+
+
 /* Register font-driver DRIVER.  This function is used in two ways.
 
    The first is with frame F non-NULL.  In this case, make DRIVER
@@ -3921,8 +3938,8 @@ encoding of a font, e.g. ``iso8859-1''.
 `:size'
 
 VALUE must be a non-negative integer or a floating point number
-specifying the font size.  It specifies the font size in pixels
-(if VALUE is an integer), or in points (if VALUE is a float).
+specifying the font size.  It specifies the font size in pixels (if
+VALUE is an integer), or in points (if VALUE is a float).
 
 `:name'
 
@@ -3933,6 +3950,30 @@ VALUE must be a string of XLFD-style or fontconfig-style font name.
 VALUE must be a symbol representing a script that the font must
 support.  It may be a symbol representing a subgroup of a script
 listed in the variable `script-representative-chars'.
+
+`:lang'
+
+VALUE must be a symbol of two-letter ISO-639 language names,
+e.g. `ja'.
+
+`:otf'
+
+VALUE must be a list (SCRIPT-TAG LANGSYS-TAG GSUB [ GPOS ]) to specify
+required OpenType features.
+
+  SCRIPT-TAG: OpenType script tag symbol (e.g. `deva').
+  LANGSYS-TAG: OpenType language system tag symbol,
+     or nil for the default language system.
+  GSUB: List of OpenType GSUB feature tag symbols, or nil if none required.
+  GPOS: List of OpenType GPOS feature tag symbols, or nil if none required.
+
+GSUB and GPOS may contain `nil' element.  In such a case, the font
+must not have any of the remaining elements.
+
+For instance, if the VALUE is `(thai nil nil (mark))', the font must
+be an OpenType font, and whose GPOS table of `thai' script's default
+language system must contain `mark' feature.
+
 usage: (font-spec ARGS...)  */)
      (nargs, args)
      int nargs;
@@ -4838,13 +4879,13 @@ Type C-l to recover what previously shown.  */)
 DEFUN ("font-info", Ffont_info, Sfont_info, 1, 2, 0,
        doc: /* Return information about a font named NAME on frame FRAME.
 If FRAME is omitted or nil, use the selected frame.
-The returned value is a vector of OPENED-NAME, FULL-NAME, CHARSET, SIZE,
+The returned value is a vector of OPENED-NAME, FULL-NAME, SIZE,
   HEIGHT, BASELINE-OFFSET, RELATIVE-COMPOSE, and DEFAULT-ASCENT,
 where
   OPENED-NAME is the name used for opening the font,
   FULL-NAME is the full name of the font,
-  SIZE is the maximum bound width of the font,
-  HEIGHT is the height of the font,
+  SIZE is the pixelsize of the font,
+  HEIGHT is the pixel-height of the font (i.e ascent + descent),
   BASELINE-OFFSET is the upward offset pixels from ASCII baseline,
   RELATIVE-COMPOSE and DEFAULT-ASCENT are the numbers controlling
     how to compose characters.
@@ -4891,7 +4932,7 @@ If the named font is not yet loaded, return nil.  */)
 
   info = Fmake_vector (make_number (7), Qnil);
   XVECTOR (info)->contents[0] = AREF (font_object, FONT_NAME_INDEX);
-  XVECTOR (info)->contents[1] = AREF (font_object, FONT_NAME_INDEX);
+  XVECTOR (info)->contents[1] = AREF (font_object, FONT_FULLNAME_INDEX);
   XVECTOR (info)->contents[2] = make_number (font->pixel_size);
   XVECTOR (info)->contents[3] = make_number (font->height);
   XVECTOR (info)->contents[4] = make_number (font->baseline_offset);
@@ -5064,10 +5105,6 @@ syms_of_font ()
   staticpro (&font_charset_alist);
   font_charset_alist = Qnil;
 
-  DEFSYM (Qfont_spec, "font-spec");
-  DEFSYM (Qfont_entity, "font-entity");
-  DEFSYM (Qfont_object, "font-object");
-
   DEFSYM (Qopentype, "opentype");
 
   DEFSYM (Qascii_0, "ascii-0");