2005-11-23  Behdad Esfahbod  <behdad@gnome.org>

	* modules/basic/basic-fc.c: Reworked basic shaper with OpenType
	support. (#101079, based on patch from Denis Jacquerye and Noah Levitt)

	* modules/basic/basic-fc.c (basic_scripts): Added Unicode 4.1 addition
	script PANGO_SCRIPT_GLAGOLITIC that is a "simple" script.

	* modules/arabic/arabic-fc.c, modules/syriac/syriac-fc.c: Replace
	g_utf8_to_ucs4_fast() with g_utf8_strlen()!

	* pango/opentype/pango-ot-ruleset.c (pango_ot_ruleset_add_feature):
	Remove reference in docs to pango_ot_ruleset_shape() that was
	removed long ago.

Index: modules/arabic/arabic-fc.c
===================================================================
RCS file: /cvs/gnome/pango/modules/arabic/arabic-fc.c,v
retrieving revision 1.19
diff -u -p -r1.19 arabic-fc.c
--- modules/arabic/arabic-fc.c	23 Jul 2005 19:24:46 -0000	1.19
+++ modules/arabic/arabic-fc.c	23 Nov 2005 11:43:27 -0000
@@ -169,8 +169,7 @@ fallback_shape (PangoEngineShape *engine
 		PangoGlyphString *glyphs)
 {
   PangoFcFont *fc_font = PANGO_FC_FONT (font);
-  glong n_chars;
-  gunichar *wcs = g_utf8_to_ucs4_fast (text, length, &n_chars);
+  glong n_chars = g_utf8_strlen (text, length);
   const char *p;
   int i;
   
@@ -236,8 +235,6 @@ fallback_shape (PangoEngineShape *engine
       /* Swap all glyphs */
       swap_range (glyphs, 0, glyphs->num_glyphs);
     }
-
-  g_free (wcs);
 }
 
 static void 
@@ -284,6 +281,8 @@ arabic_engine_shape (PangoEngineShape *e
   properties = g_new0 (gulong, n_chars);
       
   Arabic_Assign_Properties (wcs, properties, n_chars);
+
+  g_free (wcs);
   
   p = text;
   for (i=0; i < n_chars; i++)
@@ -346,7 +345,6 @@ arabic_engine_shape (PangoEngineShape *e
   pango_ot_ruleset_position (ruleset, buffer);
   pango_ot_buffer_output (buffer, glyphs);
   
-  g_free (wcs);
   g_free (properties);
   pango_ot_buffer_destroy (buffer);
 
Index: modules/basic/basic-fc.c
===================================================================
RCS file: /cvs/gnome/pango/modules/basic/basic-fc.c,v
retrieving revision 1.20
diff -u -p -r1.20 basic-fc.c
--- modules/basic/basic-fc.c	23 Jul 2005 19:24:46 -0000	1.20
+++ modules/basic/basic-fc.c	23 Nov 2005 11:43:27 -0000
@@ -26,9 +26,10 @@
 #include "pango-engine.h"
 #include "pango-utils.h"
 #include "pangofc-font.h"
+#include "pango-ot.h"
 
 #include "basic-common.h"
-
+  
 /* No extra fields needed */
 typedef PangoEngineShape      BasicEngineFc;
 typedef PangoEngineShapeClass BasicEngineFcClass;
@@ -56,6 +57,8 @@ static PangoEngineScriptInfo basic_scrip
   { PANGO_SCRIPT_RUNIC,     "*" },
   { PANGO_SCRIPT_CANADIAN_ABORIGINAL, "*" },
   { PANGO_SCRIPT_YI,       "*" },
+
+  /* Unicode-4.0 additions */
   { PANGO_SCRIPT_BRAILLE,  "*" },
   { PANGO_SCRIPT_CYPRIOT,  "*" },
   { PANGO_SCRIPT_LIMBU,    "*" },
@@ -63,6 +66,9 @@ static PangoEngineScriptInfo basic_scrip
   { PANGO_SCRIPT_SHAVIAN,  "*" },
   { PANGO_SCRIPT_LINEAR_B, "*" },
   { PANGO_SCRIPT_UGARITIC, "*" },
+
+  /* Unicode-4.1 additions */
+  { PANGO_SCRIPT_GLAGOLITIC, "*" },
     
   { PANGO_SCRIPT_COMMON,   "" }
 };
@@ -119,44 +125,44 @@ set_glyph (PangoFont        *font,
 }
 
 static void 
-basic_engine_shape (PangoEngineShape *engine,
-		    PangoFont        *font,
-		    const char       *text,
-		    gint              length,
-		    PangoAnalysis    *analysis,
-		    PangoGlyphString *glyphs)
+fallback_shape (PangoEngineShape *engine,
+		PangoFont        *font,
+		const char       *text,
+		gint              length,
+		PangoAnalysis    *analysis,
+		PangoGlyphString *glyphs)
 {
   PangoFcFont *fc_font = PANGO_FC_FONT (font);
-  int n_chars;
-  int i;
+  glong n_chars = g_utf8_strlen (text, length);
   const char *p;
-
-  g_return_if_fail (font != NULL);
-  g_return_if_fail (text != NULL);
-  g_return_if_fail (length >= 0);
-  g_return_if_fail (analysis != NULL);
-
-  n_chars = g_utf8_strlen (text, length);
+  int i;
+  
   pango_glyph_string_set_size (glyphs, n_chars);
-
-  pango_fc_font_lock_face (fc_font);
-
   p = text;
-  for (i = 0; i < n_chars; i++)
+  
+  for (i=0; i < n_chars; i++)
     {
       gunichar wc;
       gunichar mirrored_ch;
       PangoGlyph index;
+      char buf[6];
+      const char *input;
 
       wc = g_utf8_get_char (p);
 
+      input = p;
       if (analysis->level % 2)
 	if (pango_get_mirror_char (wc, &mirrored_ch))
-	  wc = mirrored_ch;
+	  {
+	    wc = mirrored_ch;
+	    
+	    g_unichar_to_utf8 (wc, buf);
+	    input = buf;
+	  }
 
       if (wc == 0xa0)	/* non-break-space */
 	wc = 0x20;
-		
+
       if (pango_is_zero_width (wc))
 	{
 	  set_glyph (font, glyphs, i, p - text, 0);
@@ -166,9 +172,9 @@ basic_engine_shape (PangoEngineShape *en
 	  index = pango_fc_font_get_glyph (fc_font, wc);
 
 	  if (!index)
-	    {
-	      set_glyph (font, glyphs, i, p - text,
-			 pango_fc_font_get_unknown_glyph (fc_font, wc));
+            {
+	      index = pango_fc_font_get_unknown_glyph (fc_font, wc);
+              set_glyph (font, glyphs, i, p - text, index);
 	    }
 	  else
 	    {
@@ -199,31 +205,206 @@ basic_engine_shape (PangoEngineShape *en
       p = g_utf8_next_char (p);
     }
 
-  /* Simple bidi support; most bidi languages (Arabic, Hebrew, Syriac)
-   * are in fact handled in other modules.
-   */
-  if (analysis->level % 2)
+  /* Apply default positioning */
+  for (i = 0; i < glyphs->num_glyphs; i++)
+    {
+      if (glyphs->glyphs[i].glyph)
+	{
+	  PangoRectangle logical_rect;
+	  
+	  pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect);
+	  glyphs->glyphs[i].geometry.width = logical_rect.width;
+	}
+      else
+	glyphs->glyphs[i].geometry.width = 0;
+      
+      glyphs->glyphs[i].geometry.x_offset = 0;
+      glyphs->glyphs[i].geometry.y_offset = 0;
+    }
+  
+  if (analysis->level % 2 != 0)
     {
-      int start, end;
-
       /* Swap all glyphs */
-      swap_range (glyphs, 0, n_chars);
+      swap_range (glyphs, 0, glyphs->num_glyphs);
+    }
+}
+
+static const gchar scripts[][5] =
+{
+  "latn",
+  "cyrl",
+  "grek",
+  "armn",
+  "geor",
+  "runr",
+  "ogam"
+};
+
+static const gchar gsub_features[][5] =
+{
+  "ccmp",
+  "liga",
+  "clig",
+};
+
+static const gchar gpos_features[][5] =
+{
+  "kern",
+  "mark",
+  "mkmk"
+};
+
+static PangoOTRuleset *
+get_ruleset (FT_Face face)
+{
+  PangoOTRuleset *ruleset;
+  PangoOTInfo *info = NULL;
+  static GQuark ruleset_quark = 0;
+  unsigned int i, j;
+
+  info = pango_ot_info_get (face);
+  if (!info)
+	  return FALSE;
+
+  if (!ruleset_quark)
+	  ruleset_quark = g_quark_from_string ("pango-basic-ruleset");
+
+  ruleset = g_object_get_qdata (G_OBJECT (info), ruleset_quark);
+
+  if (!ruleset)
+  {
+    ruleset = pango_ot_ruleset_new (info);
+
+    for (i = 0; i < G_N_ELEMENTS (scripts); i++)
+      {
+         PangoOTTag script_tag = FT_MAKE_TAG (scripts[i][0], scripts[i][1], scripts[i][2], scripts[i][3]);
+         guint script_index;
+
+
+         if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GPOS, script_tag, &script_index))
+           for (j = 0; j < G_N_ELEMENTS (gpos_features); j++)
+	     {
+               PangoOTTag feature_tag = FT_MAKE_TAG (gpos_features[j][0], gpos_features[j][1], 
+                                                     gpos_features[j][2], gpos_features[j][3]);
+               guint feature_index;
+
+               /* 0xffff means default language */
+               if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GPOS, feature_tag, script_index, 0xffff,&feature_index))
+               {
+                 pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GPOS, feature_index, 0xffff);
+	       }
+	     }
+
+          if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GSUB, script_tag, &script_index))
+            for (j = 0; j < G_N_ELEMENTS (gsub_features); j++)
+              {
+                PangoOTTag feature_tag = FT_MAKE_TAG (gsub_features[j][0], gsub_features[j][1], 
+                                                      gsub_features[j][2], gsub_features[j][3]);
+                guint feature_index;
+
+                /* 0xffff means default language */
+                if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GSUB, feature_tag, 
+                                                script_index, 0xffff, &feature_index))
+                  {
+                    pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GSUB, feature_index, 0xffff);
+                  }
+              }
+      } 
+
+    g_object_set_qdata_full (G_OBJECT (info), ruleset_quark, ruleset, (GDestroyNotify) g_object_unref);
+  }
+
+  return ruleset;
+
+}
+
+static void 
+basic_engine_shape (PangoEngineShape *engine,
+		    PangoFont        *font,
+		    const char       *text,
+		    gint              length,
+		    PangoAnalysis    *analysis,
+		    PangoGlyphString *glyphs)
+{
+  PangoFcFont *fc_font = PANGO_FC_FONT (font);
+  FT_Face face;
+  PangoOTRuleset *ruleset;
+  PangoOTBuffer *buffer;
+  gint unknown_property = 0;
+  int n_chars;
+  int i;
+  const char *p;
+
+  g_return_if_fail (font != NULL);
+  g_return_if_fail (text != NULL);
+  g_return_if_fail (length >= 0);
+  g_return_if_fail (analysis != NULL);
+
+  n_chars = g_utf8_strlen (text, length);
+  pango_glyph_string_set_size (glyphs, n_chars);
+
+  face = pango_fc_font_lock_face (fc_font);
+  g_assert (face != NULL);
+
+
+  ruleset = get_ruleset (face);
+  if (!ruleset)
+    {
+      fallback_shape (engine, font, text, length, analysis, glyphs);
+      pango_fc_font_kern_glyphs (fc_font, glyphs);
+      goto out;
+    }
+
+  buffer = pango_ot_buffer_new (fc_font);
+  pango_ot_buffer_set_rtl (buffer, analysis->level % 2 != 0);
+
+  p = text;
+  for (i=0; i < n_chars; i++)
+    {
+      gunichar wc;
+      gunichar mirrored_ch;
+      PangoGlyph index;
+      char buf[6];
+      const char *input;
+      int cluster = 0;
+
+      wc = g_utf8_get_char (p);
+      input = p;
+      if (analysis->level % 2)
+	if (pango_get_mirror_char (wc, &mirrored_ch))
+	  {
+	    wc = mirrored_ch;
+	    
+	    g_unichar_to_utf8 (wc, buf);
+	    input = buf;
+	  }
+
+      index = pango_fc_font_get_glyph (fc_font, wc);
       
-      /* Now reorder glyphs within each cluster back to LTR */
-      for (start = 0; start < n_chars;)
+      if (!index)
 	{
-	  end = start;
-	  while (end < n_chars &&
-		 glyphs->log_clusters[end] == glyphs->log_clusters[start])
-	    end++;
+	  pango_ot_buffer_add_glyph (buffer, pango_fc_font_get_unknown_glyph (fc_font, wc),
+				     unknown_property, p - text);
+	}
+      else
+	{
+	  cluster = p - text;
 	  
-	  swap_range (glyphs, start, end);
-	  start = end;
+	  pango_ot_buffer_add_glyph (buffer, index,
+				     unknown_property, cluster);
 	}
+      
+      p = g_utf8_next_char (p);
     }
 
-  pango_fc_font_kern_glyphs (fc_font, glyphs);
 
+  pango_ot_ruleset_substitute (ruleset, buffer);
+  pango_ot_ruleset_position (ruleset, buffer);
+  pango_ot_buffer_output (buffer, glyphs);
+  
+  pango_ot_buffer_destroy (buffer);
+
+out:
   pango_fc_font_unlock_face (fc_font);
 }
 
Index: modules/syriac/syriac-fc.c
===================================================================
RCS file: /cvs/gnome/pango/modules/syriac/syriac-fc.c,v
retrieving revision 1.4
diff -u -p -r1.4 syriac-fc.c
--- modules/syriac/syriac-fc.c	4 Nov 2005 23:43:12 -0000	1.4
+++ modules/syriac/syriac-fc.c	23 Nov 2005 11:43:27 -0000
@@ -180,8 +180,7 @@ fallback_shape (PangoEngineShape *engine
 		PangoGlyphString *glyphs)
 {
   PangoFcFont *fc_font = PANGO_FC_FONT (font);
-  glong n_chars;
-  gunichar *wcs = g_utf8_to_ucs4_fast (text, length, &n_chars);
+  glong n_chars = g_utf8_strlen (text, length);
   const char *p;
   int i;
   
@@ -239,8 +238,6 @@ fallback_shape (PangoEngineShape *engine
       /* Swap all glyphs */
       swap_range (glyphs, 0, glyphs->num_glyphs);
     }
-
-  g_free (wcs);
 }
 
 static void 
@@ -287,6 +284,8 @@ syriac_engine_shape (PangoEngineShape *e
   properties = g_new0 (gulong, n_chars);
       
   syriac_assign_properties (wcs, properties, n_chars);
+
+  g_free (wcs);
   
   p = text;
   for (i=0; i < n_chars; i++)
@@ -331,7 +330,6 @@ syriac_engine_shape (PangoEngineShape *e
   pango_ot_ruleset_position (ruleset, buffer);
   pango_ot_buffer_output (buffer, glyphs);
   
-  g_free (wcs);
   g_free (properties);
   pango_ot_buffer_destroy (buffer);
 
Index: pango/opentype/pango-ot-ruleset.c
===================================================================
RCS file: /cvs/gnome/pango/pango/opentype/pango-ot-ruleset.c,v
retrieving revision 1.14
diff -u -p -r1.14 pango-ot-ruleset.c
--- pango/opentype/pango-ot-ruleset.c	4 Nov 2005 23:55:38 -0000	1.14
+++ pango/opentype/pango-ot-ruleset.c	23 Nov 2005 11:43:27 -0000
@@ -115,10 +115,10 @@ pango_ot_ruleset_new (PangoOTInfo *info)
  * @ruleset: a #PangoOTRuleset.
  * @table_type: the table type to add a feature to.
  * @feature_index: the index of the feature to add.
- * @property_bit: the property bit to use for this feature. 
+ * @property_bit: the property bit to use for this feature. Used to identify
+ *                the glyphs that this feature should be applied to.
  *
- * Adds a feature to the ruleset. See pango_ot_ruleset_shape()
- * for an explanation of @property_bit.
+ * Adds a feature to the ruleset.
  **/
 void
 pango_ot_ruleset_add_feature (PangoOTRuleset   *ruleset,

