(font_select_entity): New function.
[bpt/emacs.git] / src / font.c
index 0c9a625..9a656b1 100644 (file)
@@ -1,6 +1,6 @@
 /* font.c -- "Font" primitives.
-   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
-   Copyright (C) 2006, 2007, 2008
+   Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2008, 2009
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H13PRO009
 
@@ -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
     {
@@ -1066,11 +1064,11 @@ font_parse_xlfd (name, font)
   Lisp_Object val;
   char *p;
 
-  if (len > 255)
+  if (len > 255 || !len)
     /* Maximum XLFD name length is 255. */
     return -1;
   /* Accept "*-.." as a fully specified XLFD. */
-  if (name[0] == '*' && name[1] == '-')
+  if (name[0] == '*' && (len == 1 || name[1] == '-'))
     i = 1, f[XLFD_FOUNDRY_INDEX] = name;
   else
     i = 0;
@@ -1814,7 +1812,7 @@ font_parse_name (name, font)
      char *name;
      Lisp_Object font;
 {
-  if (name[0] == '-' || index (name, '*'))
+  if (name[0] == '-' || index (name, '*') || index (name, '?'))
     return font_parse_xlfd (name, font);
   return font_parse_fcname (name, font);
 }
@@ -2424,7 +2422,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;
     }
@@ -3051,15 +3052,21 @@ font_get_spec (font_object)
   return spec;
 }
 
+
+/* Create a new font spec from FONT_NAME, and return it.  If FONT_NAME
+   could not be parsed by font_parse_name, return Qnil.  */
+
 Lisp_Object
 font_spec_from_name (font_name)
      Lisp_Object font_name;
 {
-  Lisp_Object args[2];
+  Lisp_Object spec = Ffont_spec (0, NULL);
 
-  args[0] = QCname;
-  args[1] = font_name;
-  return Ffont_spec (2, args);
+  CHECK_STRING (font_name);
+  if (font_parse_name ((char *) SDATA (font_name), spec) == -1)
+    return Qnil;
+  font_put_extra (spec, QCname, font_name);
+  return spec;
 }
 
 
@@ -3083,7 +3090,13 @@ font_clear_prop (attrs, prop)
   if (prop == FONT_FAMILY_INDEX || prop == FONT_FOUNDRY_INDEX)
     {
       if (prop == FONT_FAMILY_INDEX)
-       ASET (font, FONT_FOUNDRY_INDEX, Qnil);
+       {
+         ASET (font, FONT_FOUNDRY_INDEX, Qnil);
+         /* If we are setting the font family, we must also clear
+            FONT_WIDTH_INDEX to avoid rejecting families that lack
+            support for some widths.  */
+         ASET (font, FONT_WIDTH_INDEX, Qnil);
+       }
       ASET (font, FONT_ADSTYLE_INDEX, Qnil);
       ASET (font, FONT_REGISTRY_INDEX, Qnil);
       ASET (font, FONT_SIZE_INDEX, Qnil);
@@ -3120,7 +3133,7 @@ font_update_lface (f, attrs)
   if (! NILP (AREF (spec, FONT_WEIGHT_INDEX)))
     attrs[LFACE_WEIGHT_INDEX] = FONT_WEIGHT_FOR_FACE (spec);
   if (! NILP (AREF (spec, FONT_SLANT_INDEX)))
-    attrs[LFACE_SLANT_INDEX] = FONT_SLANT_FOR_FACE (spec);;
+    attrs[LFACE_SLANT_INDEX] = FONT_SLANT_FOR_FACE (spec);
   if (! NILP (AREF (spec, FONT_WIDTH_INDEX)))
     attrs[LFACE_SWIDTH_INDEX] = FONT_WIDTH_FOR_FACE (spec);
   if (! NILP (AREF (spec, FONT_SIZE_INDEX)))
@@ -3148,6 +3161,75 @@ 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));
+  entities = font_sort_entites (entities, prefer, frame, c < 0);
+
+  if (c < 0)
+    return entities;
+
+  for (i = 0; i < ASIZE (entities); i++)
+    {
+      int j;
+
+      font_entity = AREF (entities, i);
+      if (i > 0)
+       {
+         for (j = FONT_FOUNDRY_INDEX; j <= FONT_REGISTRY_INDEX; j++)
+           if (! EQ (AREF (font_entity, j), props[j]))
+             break;
+         if (j > FONT_REGISTRY_INDEX)
+           continue;
+       }
+      for (j = FONT_FOUNDRY_INDEX; j <= FONT_REGISTRY_INDEX; j++)
+       props[j] = AREF (font_entity, j);
+      result = font_has_char (f, font_entity, c);
+      if (result > 0)
+       return font_entity;
+    }
+  return Qnil;
+}
+
 /* 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.  */
@@ -3295,74 +3377,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;
 }
 
 
@@ -3382,7 +3407,18 @@ font_open_for_lface (f, entity, attrs, spec)
     size = font_pixel_size (f, spec);
   else
     {
-      double pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
+      double pt;
+      if (INTEGERP (attrs[LFACE_HEIGHT_INDEX]))
+       pt = XINT (attrs[LFACE_HEIGHT_INDEX]);
+      else
+       {
+         struct face *def = FACE_FROM_ID (f, DEFAULT_FACE_ID);
+         Lisp_Object height = def->lface[LFACE_HEIGHT_INDEX];
+         if (INTEGERP (height))
+           pt = XINT (height);
+         else
+           abort(); /* We should never end up here.  */
+       }
 
       pt /= 10;
       size = POINT_TO_PIXEL (pt, f->resy);
@@ -3811,6 +3847,7 @@ font_range (pos, limit, w, face, string)
 
       category = CHAR_TABLE_REF (Vunicode_category_table, c);
       if (! EQ (category, QCf)
+         && ! CHAR_VARIATION_SELECTOR_P (c)
          && font_encode_char (font_object, c) == FONT_INVALID_CODE)
        {
          Lisp_Object f = font_for_char (face, c, pos - 1, string);
@@ -3832,6 +3869,7 @@ font_range (pos, limit, w, face, string)
                FETCH_STRING_CHAR_ADVANCE_NO_CHECK (c, string, i, i_byte);
              category = CHAR_TABLE_REF (Vunicode_category_table, c);
              if (! EQ (category, QCf)
+                 && ! CHAR_VARIATION_SELECTOR_P (c)
                  && font_encode_char (f, c) == FONT_INVALID_CODE)
                {
                  *limit = pos - 1;
@@ -3896,8 +3934,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'
 
@@ -3906,7 +3944,32 @@ VALUE must be a string of XLFD-style or fontconfig-style font name.
 `:script'
 
 VALUE must be a symbol representing a script that the font must
-support.
+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;
@@ -4200,17 +4263,12 @@ Optional argument FRAME, if non-nil, specifies the target frame.  */)
     if (driver_list->driver->list_family)
       {
        Lisp_Object val = driver_list->driver->list_family (frame);
+       Lisp_Object tail = list;
 
-       if (NILP (list))
-         list = val;
-       else
-         {
-           Lisp_Object tail = list;
-
-           for (; CONSP (val); val = XCDR (val))
-             if (NILP (Fmemq (XCAR (val), tail)))
-               list = Fcons (XCAR (val), list);
-         }
+       for (; CONSP (val); val = XCDR (val))
+         if (NILP (Fmemq (XCAR (val), tail))
+             && SYMBOLP (XCAR (val)))
+           list = Fcons (SYMBOL_NAME (XCAR (val)), list);
       }
   return list;
 }
@@ -4407,6 +4465,49 @@ created glyph-string.  Otherwise, the value is nil.  */)
   return composition_gstring_put_cache (gstring, XINT (n));
 }
 
+DEFUN ("font-variation-glyphs", Ffont_variation_glyphs, Sfont_variation_glyphs,
+       2, 2, 0,
+       doc: /* Return a list of variation glyphs for CHAR in FONT-OBJECT.
+Each element of the value is a cons (VARIATION-SELECTOR . GLYPH-ID),
+where
+  VARIATION-SELECTOR is a chracter code of variation selection
+    (#xFE00..#xFE0F or #xE0100..#xE01EF)
+  GLYPH-ID is a glyph code of the corresponding variation glyph.  */)
+     (font_object, character)
+     Lisp_Object font_object, character;
+{
+  unsigned variations[256];
+  struct font *font;
+  int i, n;
+  Lisp_Object val;
+
+  CHECK_FONT_OBJECT (font_object);
+  CHECK_CHARACTER (character);
+  font = XFONT_OBJECT (font_object);
+  if (! font->driver->get_variation_glyphs)
+    return Qnil;
+  n = font->driver->get_variation_glyphs (font, XINT (character), variations);
+  if (! n)
+    return Qnil;
+  val = Qnil;
+  for (i = 0; i < 255; i++)
+    if (variations[i])
+      {
+       Lisp_Object code;
+       int vs = (i < 16 ? 0xFE00 + i : 0xE0100 + (i - 16));
+       /* Stops GCC whining about limited range of data type.  */
+       EMACS_INT var = variations[i];
+
+       if (var > MOST_POSITIVE_FIXNUM)
+         code = Fcons (make_number ((variations[i]) >> 16),
+                       make_number ((variations[i]) & 0xFFFF));
+       else
+         code = make_number (variations[i]);
+       val = Fcons (Fcons (make_number (vs), code), val);
+      }
+  return val;
+}
+
 #if 0
 
 DEFUN ("font-drive-otf", Ffont_drive_otf, Sfont_drive_otf, 6, 6, 0,
@@ -5000,10 +5101,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");
@@ -5065,6 +5162,7 @@ syms_of_font ()
   defsubr (&Sfont_xlfd_name);
   defsubr (&Sclear_font_cache);
   defsubr (&Sfont_shape_gstring);
+  defsubr (&Sfont_variation_glyphs);
 #if 0
   defsubr (&Sfont_drive_otf);
   defsubr (&Sfont_otf_alternates);