Index: app/text/gimptextlayout.c
===================================================================
RCS file: /cvs/gnome/gimp/app/text/gimptextlayout.c,v
retrieving revision 1.16
diff -u -p -r1.16 gimptextlayout.c
--- app/text/gimptextlayout.c	1 Oct 2003 11:52:52 -0000	1.16
+++ app/text/gimptextlayout.c	25 Oct 2003 15:26:25 -0000
@@ -38,6 +38,8 @@ static void   gimp_text_layout_class_ini
 static void   gimp_text_layout_init        (GimpTextLayout      *layout);
 static void   gimp_text_layout_finalize    (GObject             *object);
 
+static void   gimp_text_layout_set_text    (GimpTextLayout      *layout,
+                                            GimpText            *text);
 static void   gimp_text_layout_position    (GimpTextLayout      *layout);
 
 static PangoContext * gimp_text_get_pango_context (GimpText     *text,
@@ -165,7 +167,7 @@ gimp_text_layout_new (GimpText  *text,
   pango_layout_set_font_description (layout->layout, font_desc);
   pango_font_description_free (font_desc);
 
-  pango_layout_set_text (layout->layout, text->text, -1);
+  gimp_text_layout_set_text (layout, text);
 
   switch (text->justify)
     {
@@ -250,6 +252,115 @@ gimp_text_layout_get_offsets (GimpTextLa
     *x = layout->extents.x;
   if (y)
     *y = layout->extents.y;
+}
+
+
+static inline gboolean
+gimp_unichar_is_special (gunichar c)
+{
+  switch (g_unichar_type (c))
+    {
+    case G_UNICODE_CONTROL:
+    case G_UNICODE_FORMAT:
+    case G_UNICODE_UNASSIGNED:
+    case G_UNICODE_PRIVATE_USE:
+    case G_UNICODE_SURROGATE:
+    case G_UNICODE_COMBINING_MARK:
+    case G_UNICODE_ENCLOSING_MARK:
+    case G_UNICODE_NON_SPACING_MARK:
+    case G_UNICODE_LINE_SEPARATOR:
+    case G_UNICODE_PARAGRAPH_SEPARATOR:
+      return TRUE;
+    default:
+      return FALSE;
+    }
+}
+
+#define ZERO_WIDTH_NOBREAK_SPACE  0xFEFF
+
+static void
+gimp_text_layout_set_text (GimpTextLayout *layout,
+                           GimpText       *text)
+{
+  gsize len = text->text ? strlen (text->text) : 0;
+
+  pango_layout_set_text (layout->layout, text->text, len);
+
+  if (len == 0 || fabs (text->letter_spacing) < (1.0 / PANGO_SCALE))
+    {
+      pango_layout_set_text (layout->layout, text->text, len);
+    }
+  else
+    {
+      PangoAttrList   *attributes;
+      PangoAttribute  *attr;
+      PangoLayoutIter *iter;
+      PangoRectangle   ink_rect     = { 0, 0, 0, 0 };
+      PangoRectangle   logical_rect = { 0, 0, 0, 0 };
+      GString         *str;
+      gchar           *normal;
+      gchar           *ptr;
+      gint             start;
+      gint             end;
+
+      logical_rect.width = text->letter_spacing * PANGO_SCALE;
+
+      str = g_string_new_len (NULL, len * 2);
+
+      normal = g_utf8_normalize (text->text, len, G_NORMALIZE_DEFAULT_COMPOSE);
+
+      for (ptr = normal; *ptr;)
+        {
+          gunichar c = g_utf8_get_char (ptr);
+
+          g_string_append_unichar (str, c);
+
+          ptr = g_utf8_next_char (ptr);
+
+          if (*ptr && ! gimp_unichar_is_special (c))
+            {
+              c = g_utf8_get_char (ptr);
+
+              if (! gimp_unichar_is_special (c))
+                g_string_append_unichar (str, ZERO_WIDTH_NOBREAK_SPACE);
+            }
+        }
+
+      g_free (normal);
+
+      pango_layout_set_text (layout->layout, str->str, str->len);
+
+      attributes = pango_attr_list_new ();
+
+      iter  = pango_layout_get_iter (layout->layout);
+      start = pango_layout_iter_get_index (iter);
+
+      while (pango_layout_iter_next_cluster (iter))
+        {
+          end = pango_layout_iter_get_index (iter);
+
+          if (g_utf8_get_char (str->str + start) == ZERO_WIDTH_NOBREAK_SPACE)
+            {
+              attr = pango_attr_shape_new (&ink_rect, &logical_rect);
+
+              attr->start_index = start;
+              attr->end_index   = end;
+
+              g_print ("%d -> %d\n", start, end);
+
+              pango_attr_list_insert (attributes, attr);
+            }
+
+          start = end;
+        }
+
+      pango_layout_iter_free (iter);
+
+      pango_layout_set_attributes (layout->layout, attributes);
+      pango_attr_list_unref (attributes);
+
+      g_string_free (str, TRUE);
+    }
 }
 
 static void
Index: app/tools/gimptextoptions.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimptextoptions.c,v
retrieving revision 1.29
diff -u -p -r1.29 gimptextoptions.c
--- app/tools/gimptextoptions.c	14 Oct 2003 16:40:02 -0000	1.29
+++ app/tools/gimptextoptions.c	25 Oct 2003 15:26:26 -0000
@@ -275,7 +275,7 @@ gimp_text_options_gui (GimpToolOptions *
 
   dialog_factory = gimp_dialog_factory_from_name ("dock");
 
-  table = gtk_table_new (10, 3, FALSE);
+  table = gtk_table_new (11, 3, FALSE);
   gtk_table_set_col_spacings (GTK_TABLE (table), 2);
   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
   gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
@@ -325,7 +325,8 @@ gimp_text_options_gui (GimpToolOptions *
   gtk_widget_set_sensitive (auto_button, options->text->hinting);
   g_object_set_data (G_OBJECT (button), "set_sensitive", auto_button);
 
-  button = gimp_prop_check_button_new (config, "antialias", _("Antialiasing"));
+  button = gimp_prop_check_button_new (config,
+				       "antialias", _("Antialiasing"));
   gtk_table_attach (GTK_TABLE (table), button, 1, 3, 5, 6,
                     GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
   gtk_widget_show (button);
@@ -350,11 +351,19 @@ gimp_text_options_gui (GimpToolOptions *
                              _("Indent:"), 1.0, 0.5,
                              spinbutton, 1, FALSE);
 
-  spinbutton = gimp_prop_spin_button_new (config, "line-spacing", 1.0, 10.0, 1);
+  spinbutton = gimp_prop_spin_button_new (config,
+					  "line-spacing", 1.0, 10.0, 1);
   gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 5);
   gimp_table_attach_stock (GTK_TABLE (table), 9,
                            _("Line\nSpacing:"), 0.0,
 			   spinbutton, 1, GIMP_STOCK_LINE_SPACING);
+
+  spinbutton = gimp_prop_spin_button_new (config,
+					  "letter-spacing", 1.0, 10.0, 1);
+  gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 5);
+  gimp_table_attach_stock (GTK_TABLE (table), 10,
+                           _("Letter\nSpacing:"), 0.0,
+			   spinbutton, 1, GIMP_STOCK_LETTER_SPACING);
 
   button = gtk_button_new_with_label (_("Create Path from Text"));
   gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
