Patch: Tamil OpenType Layout in Pango



Hi,

Included is a patch to tamil-xft.c that adds opentype layout support.
A screenshot of gedit2 displaying the muru.utf sample file with
the code2000.ttf font is in 
http://groups.yahoo.com/group/tamilinix/files/pango/tamil-otl.png

This patch will use the OTL tables if they are available in the font, or fall 
back to rendering the individual glyphs of the cluster in the case OTL tables 
are not available in the font. (e.g. MS Arial Unicode)

The lookups are rather slow now, as it checks every Tamil glyph against all
the relevant GSUB table features ('akhn', 'abvm', 'blws', 'haln', 'pres') for
Tamil. Also positioning of the vowel modifiers (VIRAMA etc.) needs to be 
done. (GPOS tables?)

I would very much appreciate any comments on this.

Thanks,

-Vasee
--- tamil-xft.c	Wed Oct 31 10:00:39 2001
+++ /home/vasee/pango-tamil/tamil-xft.c	Mon Feb  4 21:16:28 2002
@@ -3,6 +3,14 @@
  *
  * Author: Vikram Subramanian (upender vsnl com)
  *         
+ * ChangeLog:
+ *
+ * 2002-02-04	Thuraiappah Vaseeharan <vasee ieee org>
+ *
+ * 	- Added preliminary Open Type Layout support
+ * 	- PUA encoding is not used any more. If OTL tables are not
+ * 	  available in the font, fall back to rendering individual glyphs 
+ * 	  of the cluster
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -23,6 +31,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <glib.h>
+#include "pango-ot.h"
 #include "pangoxft.h"
 #include "pango-engine.h"
 #include "pango-utils.h"
@@ -83,6 +92,66 @@
 
 static gint n_script_engines = G_N_ELEMENTS (script_engines);
 
+/* begin OpenType functions */
+void
+maybe_add_feature (PangoOTRuleset *ruleset,
+		   PangoOTInfo    *info,
+		   guint           script_index,
+		   PangoOTTag      tag,
+		   gulong          property_bit)
+{
+  guint feature_index;
+  
+  /* 0xffff == default language system */
+  if (pango_ot_info_find_feature (info, PANGO_OT_TABLE_GSUB,
+				  tag, script_index, 0xffff, &feature_index)) {
+    pango_ot_ruleset_add_feature (ruleset, PANGO_OT_TABLE_GSUB, feature_index,
+				  property_bit);
+  }
+}
+
+/* Adds OpenType features required for Tamil to the ruleset */
+static PangoOTRuleset *
+get_ruleset (PangoFont *font)
+{
+  PangoOTRuleset *ruleset;
+  static GQuark ruleset_quark = 0;
+
+  PangoOTInfo *info = pango_xft_font_get_ot_info (font);
+
+  if (!ruleset_quark)
+    ruleset_quark = g_quark_from_string ("pango-tamil-ruleset");
+  
+  if (!info)
+    return NULL;
+
+  ruleset = g_object_get_qdata (G_OBJECT (font), ruleset_quark);
+
+  if (!ruleset)
+    {
+      PangoOTTag taml_tag = FT_MAKE_TAG ('t', 'a', 'm', 'l');
+      guint script_index;
+
+      ruleset = pango_ot_ruleset_new (info);
+
+      if (pango_ot_info_find_script (info, PANGO_OT_TABLE_GSUB,
+				     taml_tag, &script_index))
+	{
+	  maybe_add_feature (ruleset, info, script_index, FT_MAKE_TAG ('a','b','v','s'), 0xFFFF);
+	  maybe_add_feature (ruleset, info, script_index, FT_MAKE_TAG ('a','k','h','n'), 0xFFFF);
+	  maybe_add_feature (ruleset, info, script_index, FT_MAKE_TAG ('b','l','w','s'), 0xFFFF);
+	  maybe_add_feature (ruleset, info, script_index, FT_MAKE_TAG ('h','a','l','n'), 0xFFFF);
+	  maybe_add_feature (ruleset, info, script_index, FT_MAKE_TAG ('p','r','e','s'), 0xFFFF);
+	}
+
+      g_object_set_qdata_full (G_OBJECT (font), ruleset_quark, ruleset,
+			       (GDestroyNotify)g_object_unref);
+    }
+
+  return ruleset;
+}
+
+/* end OTL */
 
 /* Return non-zero if c is a akara mey, 0 otherwise
  */
@@ -121,17 +190,23 @@
 {
   
   /* Modifier which appears as suffix */
-  if (modifier == U_KAAL)
+  if ((modifier >= U_KAAL && modifier <= U_UMODI2) 
+		  || modifier == U_PULLI)
     {
       glyph_str[0] = base;
-      glyph_str[1] = U_KAAL;
+      glyph_str[1] = modifier ;
       *num_glyphs  = 2;
       return;
     }
   
+  /* Don't use PUA for ligatures. 
+   * If OTL tables are not available in the font, 
+   * we will fall back to rendering the 
+   * individual characrters of the cluster */
+
+# if 0
   /* Modifiers which produce completely new glyphs */
-  if ((modifier >= U_KOKKI1 && modifier <= U_UMODI2) ||
-      (modifier == U_PULLI))
+  if (modifier >= U_UMODI1 && modifier <= U_UMODI2) 
     {
       /* modifier_block_pos and cons_pos are global variables */
       glyph_str[0] = (LIG_BLOCK_START + 
@@ -141,6 +216,7 @@
       *num_glyphs  = 1;
       return;
     }
+# endif
   
   /* Modifiers which appear as prefix */
   if (modifier >= U_KOMBU1 && modifier <= U_AIMODI)
@@ -204,10 +280,15 @@
 /* Fills in the attributes of the ith glyph in the glyph string 
  */
 static void
-set_glyph (PangoFont *font, FT_Face face,PangoGlyphString *glyphs, int i, 
-	   int offset, PangoGlyph glyph)
+set_glyph (
+	PangoFont *font, 
+	FT_Face face,PangoGlyphString *glyphs, 
+	int i, 
+	int offset, 
+	PangoGlyph glyph
+	)
 {
-  PangoRectangle logical_rect;
+  PangoRectangle logical_rect; 
   PangoGlyph index;
 
   index = find_char (face, font, glyph);
@@ -217,18 +298,15 @@
   else
     glyphs->glyphs[i].glyph = pango_xft_font_get_unknown_glyph (font, glyph);
   
-
+  glyphs->log_clusters[i] = offset;  
   glyphs->glyphs[i].geometry.x_offset = 0;
   glyphs->glyphs[i].geometry.y_offset = 0;
   
-  glyphs->log_clusters[i] = offset;
-  
-  pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect);
-  glyphs->glyphs[i].geometry.width = logical_rect.width;
+ pango_font_get_glyph_extents (font, glyphs->glyphs[i].glyph, NULL, &logical_rect);
+ glyphs->glyphs[i].geometry.width = logical_rect.width;
 }
 
 
-
 /* Convert UTF-8 to glyph string
  */
 static void 
@@ -241,36 +319,40 @@
   int n_chars, n_glyph;
   int i, j;
   const char *cluster_start;
-  const char *p;
-  gunichar *wc, prevchar;  
+  const char *p; 
+  gunichar *wc, prevchar ;  
   int complete; /* Whether the prev char is gauranteed to be complete 
 		   i.e not modified by modifiers */
   
   int nuni;     /* No. of unicode characters in a cluster */
   FT_Face face;
-
+  PangoOTRuleset *ruleset;
+  gulong *properties = NULL;
   
   g_return_if_fail (font != NULL);
   g_return_if_fail (text != NULL);
   g_return_if_fail (length >= 0);
   g_return_if_fail (analysis != NULL);
   
-  
   face = pango_xft_font_get_face (font);
   g_assert (face);
   
-  /* temporarily set the size to 3 times the number of unicode chars */
   n_chars = g_utf8_strlen (text, length);  
-  pango_glyph_string_set_size (glyphs, n_chars * 3);
-  
-  wc = (gunichar *)g_malloc(sizeof(gunichar) * n_chars);  
+  /* temporarily set the size to 2 times the number of unicode chars */
+  n_glyph = n_chars * 2 ;
+  pango_glyph_string_set_size (glyphs, n_glyph);
+
+  properties = g_new0 (gulong, n_glyph);
+  for (i = 0; i < n_glyph; i++) 
+		properties[i] = 0x0 ;
+
+  wc = (gunichar *)g_malloc(sizeof(gunichar) * n_glyph);  
   p = text;
   for (i=0; i < n_chars; i++)
     {
       wc[i] = g_utf8_get_char (p);
       p = g_utf8_next_char (p);
     }
-
   
   /* Convertion starts here */
   prevchar = 0;complete = 1;/* One character look behind */
@@ -288,9 +370,8 @@
 	      /* Useful in lessons           */
 	      set_glyph (font, face, glyphs, n_glyph, 
 			 cluster_start - text, wc[j]);
-	      
-	      n_glyph++;
-	      nuni = 1;
+	  	n_glyph++;
+	  	nuni = 1;	
 	      
 	    }
 	  else
@@ -312,8 +393,8 @@
 	      
 	      /* 2 unicode chars in this just written cluster */
 	      nuni = 2;
-	    }     
-	  complete = 1; /* A character has ended */
+	     complete = 1; /* A character has ended */
+	    }
 	  
 	  /* NOTE : Double modifiers are not handled but the display will be 
 	   * correct since the vowel sign is appended.However cluster info
@@ -325,10 +406,9 @@
 	{ /* Non-modifiers */
 	  
 	  /* Write out the previous char which is waiting to get completed */
-	  if (!complete){
+	  if (!complete) {
 	    set_glyph (font, face, glyphs, n_glyph, cluster_start - text, 
 		       prevchar);
-	    
 	    n_glyph++;
 	    
 	    /* Set the cluster start properly for the current char */
@@ -338,7 +418,7 @@
 	  /* Check the type of the current char further */
 	  if (is_consonant(wc[j]))
 	    {		
-	      prevchar = wc[j]; /* Store this consonant         */
+	      prevchar = wc[j] ; /* Store this consonant      */
 	      complete = 0;     /* May get modified             */
 	      nuni     = 0;     /* NO unicode character written */
 	      
@@ -346,9 +426,9 @@
 	  else
 	    {
 	      /* Write it out then and there */
+
 	      set_glyph (font, face, glyphs, n_glyph, cluster_start - text, 
 			 wc[j]);
-	      
 	      n_glyph++;
 	      nuni = 1;
 	      
@@ -360,7 +440,7 @@
       /* Set the beginning for the next cluster */
       while (nuni-- > 0)
 	cluster_start = g_utf8_next_char (cluster_start);
-      
+
     } /* for */ 
   
   
@@ -373,6 +453,26 @@
     }
   
   /* Set the correct size for the glyph string */
+   pango_glyph_string_set_size (glyphs, n_glyph);
+
+  /* apply ligatures from OTL GSUB table, if available */
+  ruleset = get_ruleset(font) ;
+   
+  if (ruleset)
+    {
+        pango_ot_ruleset_shape (ruleset, glyphs, properties);
+	n_glyph = glyphs->num_glyphs ;
+	/* re-adjust the font metrics */
+	for (i=0 ; i < n_glyph; 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;
+		}
+	}
+    }
+
   pango_glyph_string_set_size (glyphs, n_glyph);
   g_free(wc);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]