Follow Glenn's lead and update format of Copyright.
[bpt/emacs.git] / src / ftfont.c
index 131e4b8..b28c4c3 100644 (file)
@@ -1,6 +1,6 @@
 /* ftfont.c -- FreeType font driver.
-   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
 
@@ -32,6 +32,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "character.h"
 #include "charset.h"
 #include "coding.h"
+#include "composite.h"
 #include "fontset.h"
 #include "font.h"
 #include "ftfont.h"
@@ -127,6 +128,7 @@ static struct
     { "windows-1251", { 0x0401, 0x0490 }, "ru"},
     { "koi8-r", { 0x0401, 0x2219 }, "ru"},
     { "mulelao-1", { 0x0E81 }, "lo"},
+    { "unicode-sip", { 0x20000 }},
     { NULL }
   };
 
@@ -207,6 +209,7 @@ ftfont_resolve_generic_family (family, pattern)
   Lisp_Object slot;
   FcPattern *match;
   FcResult result;
+  FcLangSet *langset;
 
   family = Fintern (Fdowncase (SYMBOL_NAME (family)), Qnil);
   if (EQ (family, Qmono))
@@ -224,6 +227,14 @@ ftfont_resolve_generic_family (family, pattern)
   FcPatternDel (pattern, FC_FOUNDRY);
   FcPatternDel (pattern, FC_FAMILY);
   FcPatternAddString (pattern, FC_FAMILY, SYMBOL_FcChar8 (family));
+  if (FcPatternGetLangSet (pattern, FC_LANG, 0, &langset) != FcResultMatch)
+    {
+      /* This is to avoid the effect of locale.  */
+      langset = FcLangSetCreate ();
+      FcLangSetAdd (langset, "en");
+      FcPatternAddLangSet (pattern, FC_LANG, langset);
+      FcLangSetDestroy (langset);
+    }
   FcConfigSubstitute (NULL, pattern, FcMatchPattern);
   FcDefaultSubstitute (pattern);
   match = FcFontMatch (NULL, pattern, &result);
@@ -237,8 +248,8 @@ ftfont_resolve_generic_family (family, pattern)
   else
     family = Qnil;
   XSETCDR (slot, family);
- err:
   if (match) FcPatternDestroy (match);
+ err:
   if (pattern) FcPatternDestroy (pattern);
   return family;
 }
@@ -299,9 +310,10 @@ ftfont_lookup_cache (key, for_face)
                                FC_INDEX, FcTypeInteger, index, NULL);
          objset = FcObjectSetBuild (FC_CHARSET, NULL);
          fontset = FcFontList (NULL, pat, objset);
-         xassert (fontset && fontset->nfont > 0);
-         if (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0, &charset)
-             == FcResultMatch)
+         if (fontset && fontset->nfont > 0
+             && (FcPatternGetCharSet (fontset->fonts[0], FC_CHARSET, 0,
+                                      &charset)
+                 == FcResultMatch))
            cache_data->fc_charset = FcCharSetCopy (charset);
          else
            cache_data->fc_charset = FcCharSetCreate ();
@@ -369,6 +381,8 @@ static int ftfont_anchor_point P_ ((struct font *, unsigned, int,
                                    int *, int *));
 static Lisp_Object ftfont_otf_capability P_ ((struct font *));
 static Lisp_Object ftfont_shape P_ ((Lisp_Object));
+static int ftfont_variation_glyphs P_ ((struct font *, int c,
+                                       unsigned variations[256]));
 
 struct font_driver ftfont_driver =
   {
@@ -378,35 +392,41 @@ struct font_driver ftfont_driver =
     ftfont_list,
     ftfont_match,
     ftfont_list_family,
-    NULL,
+    NULL,                      /* free_entity */
     ftfont_open,
     ftfont_close,
     /* We can't draw a text without device dependent functions.  */
-    NULL,
-    NULL,
+    NULL,                      /* prepare_face */
+    NULL,                      /* done_face */
     ftfont_has_char,
     ftfont_encode_char,
     ftfont_text_extents,
     /* We can't draw a text without device dependent functions.  */
-    NULL,
+    NULL,                      /* draw */
     ftfont_get_bitmap,
-    NULL,
-    NULL,
-    NULL,
+    NULL,                      /* get_bitmap */
+    NULL,                      /* free_bitmap */
+    NULL,                      /* get_outline */
     ftfont_anchor_point,
 #ifdef HAVE_LIBOTF
     ftfont_otf_capability,
 #else  /* not HAVE_LIBOTF */
     NULL,
 #endif /* not HAVE_LIBOTF */
-    NULL,
-    NULL,
-    NULL,
+    NULL,                      /* otf_drive */
+    NULL,                      /* start_for_frame */
+    NULL,                      /* end_for_frame */
 #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF)
-    ftfont_shape
+    ftfont_shape,
 #else  /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
-    NULL
+    NULL,
 #endif /* not (HAVE_M17N_FLT && HAVE_LIBOTF) */
+    NULL,                      /* check */
+#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
+    ftfont_variation_glyphs
+#else
+    NULL
+#endif
   };
 
 extern Lisp_Object QCname;
@@ -597,8 +617,7 @@ ftfont_spec_pattern (spec, otlayout, otspec)
   if (NILP (registry)
       || EQ (registry, Qascii_0)
       || EQ (registry, Qiso10646_1)
-      || EQ (registry, Qunicode_bmp)
-      || EQ (registry, Qunicode_sip))
+      || EQ (registry, Qunicode_bmp))
     fc_charset_idx = -1;
   else
     {
@@ -663,7 +682,7 @@ ftfont_spec_pattern (spec, otlayout, otspec)
     {
       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
 
-      if (CONSP (chars))
+      if (CONSP (chars) && CONSP (CDR (chars)))
        {
          charset = FcCharSetCreate ();
          if (! charset)
@@ -734,6 +753,9 @@ ftfont_list (frame, spec)
   FcPattern *pattern;
   FcFontSet *fontset = NULL;
   FcObjectSet *objset = NULL;
+  FcCharSet *charset;
+  Lisp_Object chars = Qnil;
+  FcResult result;
   char otlayout[15];           /* For "otlayout:XXXX" */
   struct OpenTypeSpec *otspec = NULL;
   int spacing = -1;
@@ -747,6 +769,17 @@ ftfont_list (frame, spec)
   pattern = ftfont_spec_pattern (spec, otlayout, &otspec);
   if (! pattern)
     return Qnil;
+  if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
+    {
+      val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
+      if (! NILP (val))
+       {
+         val = assq_no_quit (XCDR (val), Vscript_representative_chars);
+         if (CONSP (val) && VECTORP (XCDR (val)))
+           chars = XCDR (val);
+       }
+      val = Qnil;
+    }
   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
   family = AREF (spec, FONT_FAMILY_INDEX);
@@ -776,10 +809,12 @@ ftfont_list (frame, spec)
                             NULL);
   if (! objset)
     goto err;
+  if (! NILP (chars))
+    FcObjectSetAdd (objset, FC_CHARSET);
 
   fontset = FcFontList (NULL, pattern, objset);
-  if (! fontset)
-    goto err;
+  if (! fontset || fontset->nfont == 0)
+    goto finish;
 #if 0
   /* Need fix because this finds any fonts.  */
   if (fontset->nfont == 0 && ! NILP (family))
@@ -801,7 +836,7 @@ ftfont_list (frame, spec)
              FcPatternAddString (pattern, FC_FAMILY, fam);
              FcFontSetDestroy (fontset);
              fontset = FcFontList (NULL, pattern, objset);
-             if (fontset->nfont > 0)
+             if (fontset && fontset->nfont > 0)
                break;
            }
        }
@@ -826,8 +861,8 @@ ftfont_list (frame, spec)
        {
          FcChar8 *this;
 
-         if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0,
-                                 &this) != FcResultMatch
+         if (FcPatternGetString (fontset->fonts[i], FC_CAPABILITY, 0, &this)
+             != FcResultMatch
              || ! strstr ((char *) this, otlayout))
            continue;
        }
@@ -855,12 +890,26 @@ ftfont_list (frame, spec)
            continue;
        }
 #endif /* HAVE_LIBOTF */
+      if (VECTORP (chars))
+       {
+         int j;
+
+         if (FcPatternGetCharSet (fontset->fonts[i], FC_CHARSET, 0, &charset)
+             != FcResultMatch)
+           continue;
+         for (j = 0; j < ASIZE (chars); j++)
+           if (NATNUMP (AREF (chars, j))
+               && FcCharSetHasChar (charset, XFASTINT (AREF (chars, j))))
+             break;
+         if (j == ASIZE (chars))
+           continue;
+       }
       entity = ftfont_pattern_entity (fontset->fonts[i],
                                      AREF (spec, FONT_EXTRA_INDEX));
       if (! NILP (entity))
        val = Fcons (entity, val);
     }
-  font_add_log ("ftfont-list", spec, val);
+  val = Fnreverse (val);
   goto finish;
 
  err:
@@ -869,6 +918,7 @@ ftfont_list (frame, spec)
   val = Qnil;
 
  finish:
+  font_add_log ("ftfont-list", spec, val);
   if (objset) FcObjectSetDestroy (objset);
   if (fontset) FcFontSetDestroy (fontset);
   if (pattern) FcPatternDestroy (pattern);
@@ -879,7 +929,7 @@ static Lisp_Object
 ftfont_match (frame, spec)
      Lisp_Object frame, spec;
 {
-  Lisp_Object entity;
+  Lisp_Object entity = Qnil;
   FcPattern *pattern, *match = NULL;
   FcResult result;
   char otlayout[15];           /* For "otlayout:XXXX" */
@@ -929,7 +979,7 @@ static Lisp_Object
 ftfont_list_family (frame)
      Lisp_Object frame;
 {
-  Lisp_Object list;
+  Lisp_Object list = Qnil;
   FcPattern *pattern = NULL;
   FcFontSet *fontset = NULL;
   FcObjectSet *objset = NULL;
@@ -951,7 +1001,6 @@ ftfont_list_family (frame)
   if (! fontset)
     goto finish;
 
-  list = Qnil;
   for (i = 0; i < fontset->nfont; i++)
     {
       FcPattern *pat = fontset->fonts[i];
@@ -1027,10 +1076,10 @@ ftfont_open (f, entity, pixel_size)
   ASET (font_object, FONT_TYPE_INDEX, Qfreetype);
   len = font_unparse_xlfd (entity, size, name, 256);
   if (len > 0)
-    ASET (font_object, FONT_NAME_INDEX, make_unibyte_string (name, len));
+    ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
   len = font_unparse_fcname (entity, size, name, 256);
   if (len > 0)
-    ASET (font_object, FONT_FULLNAME_INDEX, make_unibyte_string (name, len));
+    ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
   else
     ASET (font_object, FONT_FULLNAME_INDEX,
          AREF (font_object, FONT_NAME_INDEX));
@@ -1299,7 +1348,7 @@ ftfont_otf_features (gsub_gpos)
      OTF_GSUB_GPOS *gsub_gpos;
 {
   Lisp_Object scripts, langsyses, features, sym;
-  int i, j, k;
+  int i, j, k, l;
 
   for (scripts = Qnil, i = gsub_gpos->ScriptList.ScriptCount - 1; i >= 0; i--)
     {
@@ -1318,7 +1367,10 @@ ftfont_otf_features (gsub_gpos)
 
          for (features = Qnil, k = otf_langsys->FeatureCount - 1; k >= 0; k--)
            {
-             OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[k].FeatureTag);
+             l = otf_langsys->FeatureIndex[k];
+             if (l >= gsub_gpos->FeatureList.FeatureCount)
+               continue;
+             OTF_TAG_SYM (sym, gsub_gpos->FeatureList.Feature[l].FeatureTag);
              features = Fcons (sym, features);
            }
          if (j >= 0)
@@ -1347,9 +1399,11 @@ ftfont_otf_capability (font)
   if (! otf)
     return Qnil;
   gsub_gpos = Fcons (Qnil, Qnil);
-  if (OTF_get_table (otf, "GSUB") == 0)
+  if (OTF_get_table (otf, "GSUB") == 0
+      && otf->gsub->FeatureList.FeatureCount > 0)
     XSETCAR (gsub_gpos, ftfont_otf_features (otf->gsub));
-  if (OTF_get_table (otf, "GPOS") == 0)
+  if (OTF_get_table (otf, "GPOS") == 0
+      && otf->gpos->FeatureList.FeatureCount > 0)
     XSETCDR (gsub_gpos, ftfont_otf_features (otf->gpos));
   return gsub_gpos;
 }
@@ -1480,15 +1534,36 @@ adjust_anchor (FT_Face ft_face, OTF_Anchor *anchor,
     }
   else if (anchor->AnchorFormat == 3)
     {
-      if (anchor->f.f2.XDeviceTable.offset)
+      if (anchor->f.f2.XDeviceTable.offset
+         && anchor->f.f2.XDeviceTable.DeltaValue)
        *x += DEVICE_DELTA (anchor->f.f2.XDeviceTable, x_ppem);
-      if (anchor->f.f2.YDeviceTable.offset)
+      if (anchor->f.f2.YDeviceTable.offset
+         && anchor->f.f2.YDeviceTable.DeltaValue)
        *y += DEVICE_DELTA (anchor->f.f2.YDeviceTable, y_ppem);
     }
 }
 
 static OTF_GlyphString otf_gstring;
 
+static void
+setup_otf_gstring (int size)
+{
+  if (otf_gstring.size == 0)
+    {
+      otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * size);
+      otf_gstring.size = size;
+    }
+  else if (otf_gstring.size < size)
+    {
+      otf_gstring.glyphs = (OTF_Glyph *) realloc (otf_gstring.glyphs,
+                                                 sizeof (OTF_Glyph) * size);
+      otf_gstring.size = size;
+    }
+  otf_gstring.used = size;
+  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * size);
+}
+
+
 static int
 ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
      MFLTFont *font;
@@ -1541,19 +1616,7 @@ ftfont_drive_otf (font, spec, in, from, to, out, adjustment)
        }
     }
 
-  if (otf_gstring.size == 0)
-    {
-      otf_gstring.glyphs = (OTF_Glyph *) malloc (sizeof (OTF_Glyph) * len);
-      otf_gstring.size = len;
-    }
-  else if (otf_gstring.size < len)
-    {
-      otf_gstring.glyphs = (OTF_Glyph *) realloc (otf_gstring.glyphs,
-                                                 sizeof (OTF_Glyph) * len);
-      otf_gstring.size = len;
-    }
-  otf_gstring.used = len;
-  memset (otf_gstring.glyphs, 0, sizeof (OTF_Glyph) * len);
+  setup_otf_gstring (len);
   for (i = 0; i < len; i++)
     {
       otf_gstring.glyphs[i].c = in->glyphs[from + i].c;
@@ -1760,16 +1823,18 @@ static int m17n_flt_initialized;
 
 extern Lisp_Object QCfamily;
 
-Lisp_Object
+static Lisp_Object
 ftfont_shape_by_flt (lgstring, font, ft_face, otf)
      Lisp_Object lgstring;
      struct font *font;
      FT_Face ft_face;
      OTF *otf;
 {
-  EMACS_UINT len = LGSTRING_LENGTH (lgstring);
+  EMACS_UINT len = LGSTRING_GLYPH_LEN (lgstring);
   EMACS_UINT i;
   struct MFLTFontFT flt_font_ft;
+  MFLT *flt = NULL;
+  int with_variation_selector = 0;
 
   if (! m17n_flt_initialized)
     {
@@ -1778,9 +1843,45 @@ ftfont_shape_by_flt (lgstring, font, ft_face, otf)
     }
 
   for (i = 0; i < len; i++)
-    if (NILP (LGSTRING_GLYPH (lgstring, i)))
-      break;
+    {
+      Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
+      int c;
+
+      if (NILP (g))
+       break;
+      c = LGLYPH_CHAR (g);
+      if (CHAR_VARIATION_SELECTOR_P (c))
+       with_variation_selector++;
+    }
   len = i;
+  if (with_variation_selector)
+    {
+      setup_otf_gstring (len);
+      for (i = 0; i < len; i++)
+       {
+         Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
+
+         otf_gstring.glyphs[i].c = LGLYPH_CHAR (g);
+         otf_gstring.glyphs[i].f.index.from = LGLYPH_FROM (g);
+         otf_gstring.glyphs[i].f.index.to = LGLYPH_TO (g);
+       }
+      OTF_drive_cmap (otf, &otf_gstring);
+      for (i = 0; i < otf_gstring.used; i++)
+       {
+         OTF_Glyph *otfg = otf_gstring.glyphs + i;
+         Lisp_Object g0 = LGSTRING_GLYPH (lgstring, otfg->f.index.from);
+         Lisp_Object g1 = LGSTRING_GLYPH (lgstring, otfg->f.index.to);
+
+         LGLYPH_SET_CODE (g0, otfg->glyph_id);
+         LGLYPH_SET_TO (g0, LGLYPH_TO (g1));
+         LGSTRING_SET_GLYPH (lgstring, i, g0);
+       }
+      if (len > otf_gstring.used)
+       {
+         len = otf_gstring.used;
+         LGSTRING_SET_GLYPH (lgstring, len, Qnil);
+       }
+    }
 
   if (gstring.allocated == 0)
     {
@@ -1794,8 +1895,19 @@ ftfont_shape_by_flt (lgstring, font, ft_face, otf)
       gstring.glyphs = realloc (gstring.glyphs,
                                sizeof (MFLTGlyph) * gstring.allocated);
     }
+  memset (gstring.glyphs, 0, sizeof (MFLTGlyph) * len);
   for (i = 0; i < len; i++)
-    gstring.glyphs[i].c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
+    {
+      Lisp_Object g = LGSTRING_GLYPH (lgstring, i);
+
+      gstring.glyphs[i].c = LGLYPH_CHAR (g);
+      if (with_variation_selector)
+       {
+         gstring.glyphs[i].code = LGLYPH_CODE (g);
+         gstring.glyphs[i].encoded = 1;
+       }
+    }
+
   gstring.used = len;
   gstring.r2l = 0;
 
@@ -1806,7 +1918,7 @@ ftfont_shape_by_flt (lgstring, font, ft_face, otf)
       flt_font_ft.flt_font.family = Mnil;
     else
       flt_font_ft.flt_font.family
-       = msymbol ((char *) SDATA (SYMBOL_NAME (family)));
+       = msymbol ((char *) SDATA (Fdowncase (SYMBOL_NAME (family))));
   }
   flt_font_ft.flt_font.x_ppem = ft_face->size->metrics.x_ppem;
   flt_font_ft.flt_font.y_ppem = ft_face->size->metrics.y_ppem;
@@ -1818,16 +1930,22 @@ ftfont_shape_by_flt (lgstring, font, ft_face, otf)
   flt_font_ft.font = font;
   flt_font_ft.ft_face = ft_face;
   flt_font_ft.otf = otf;
+  if (len > 1
+      && gstring.glyphs[1].c >= 0x300 && gstring.glyphs[1].c <= 0x36F)
+    /* A little bit ad hoc.  Perhaps, shaper must get script and
+       language information, and select a proper flt for them
+       here.  */
+    flt = mflt_get (msymbol ("combining"));
   for (i = 0; i < 3; i++)
     {
-      int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, NULL);
+      int result = mflt_run (&gstring, 0, len, &flt_font_ft.flt_font, flt);
       if (result != -2)
        break;
       gstring.allocated += gstring.allocated;
       gstring.glyphs = realloc (gstring.glyphs,
                                sizeof (MFLTGlyph) * gstring.allocated);
     }
-  if (gstring.used > LGSTRING_LENGTH (lgstring))
+  if (gstring.used > LGSTRING_GLYPH_LEN (lgstring))
     return Qnil;
   for (i = 0; i < gstring.used; i++)
     {
@@ -1886,6 +2004,23 @@ ftfont_shape (lgstring)
   return ftfont_shape_by_flt (lgstring, font, ftfont_info->ft_size->face, otf);
 }
 
+#ifdef HAVE_OTF_GET_VARIATION_GLYPHS
+
+static int
+ftfont_variation_glyphs (font, c, variations)
+     struct font *font;
+     int c;
+     unsigned variations[256];
+{
+  struct ftfont_info *ftfont_info = (struct ftfont_info *) font;
+  OTF *otf = ftfont_get_otf (ftfont_info);
+
+  if (! otf)
+    return 0;
+  return OTF_get_variation_glyphs (otf, c, variations);
+}
+
+#endif /* HAVE_OTF_GET_VARIATION_GLYPHS */
 #endif /* HAVE_M17N_FLT */
 #endif /* HAVE_LIBOTF */