Index: pango-layout.c
===================================================================
RCS file: /cvs/gnome/pango/pango/pango-layout.c,v
retrieving revision 1.133
diff -u -r1.133 pango-layout.c
--- pango-layout.c	5 Mar 2005 00:50:29 -0000	1.133
+++ pango-layout.c	29 May 2005 22:15:10 -0000
@@ -82,19 +82,23 @@
   /* this run is left-to-right */
   gboolean ltr;
 
-  /* X position where cluster begins, where "begins" means left or
-   * right side according to text direction
-   */
+  /* X position where cluster begins, where "begins" means left side */
   int cluster_x;
 
-  /* Byte index of the cluster start from the run start */
-  int cluster_index;
-  
+  /* The width of the current cluster */
+  int cluster_width;
+
   /* Glyph offset to the current cluster start */
   int cluster_start;
 
-  /* The next cluster_start */
-  int next_cluster_start;
+  /* first glyph in the next cluster */
+  int next_cluster_glyph;
+
+  /* number of unicode chars in current cluster */
+  int cluster_num_chars;
+
+  /* visual position of current character within the cluster */
+  int character_position;
 };
 
 typedef struct _PangoLayoutLinePrivate PangoLayoutLinePrivate;
@@ -4316,23 +4320,61 @@
 }
 
 static int
-cluster_end_index (PangoLayoutIter *iter)
+next_logical_cluster_start_rtl (PangoGlyphString *gs,
+				int               cluster_start)
+{
+  int i;
+
+  i = cluster_start - 1;
+  while (i >=0)
+    {
+      if (gs->glyphs[i].attr.is_cluster_start)
+        return i;
+      
+      --i;
+    }
+
+  return gs->num_glyphs;
+}
+
+static int
+cluster_width (PangoGlyphString *gs,
+	       int               cluster_start)
+{
+  int  i;
+  gint log_cluster;
+  int  width = 0;
+
+  log_cluster = gs->log_clusters[cluster_start];
+  for (i = cluster_start; i < gs->num_glyphs; ++i) 
+    {
+      if (gs->log_clusters[i] != log_cluster)
+	break;
+      width += gs->glyphs[i].geometry.width;
+    }
+
+  return width;
+}
+
+/* Convert glyph-index to byte-index of it's cluster's start
+ * relative to start of run.
+ * glyph_num is converted to item->length.
+ */
+static int
+run_glyph_to_index (PangoLayoutRun *run, 
+		    int             glyph_num)
 {
   PangoGlyphString *gs;
   
-  gs = iter->run->glyphs;
+  gs = run->glyphs;
   
-  if (iter->next_cluster_start == gs->num_glyphs)
+  if (glyph_num >= gs->num_glyphs)
     {
-      /* Use the left or right end of the run */
-      if (iter->ltr)
-        return iter->run->item->length;
-      else
-        return 0;
+      return run->item->length;
     }
   else
     {
-      return gs->log_clusters[iter->next_cluster_start];
+      return gs->log_clusters[glyph_num];
     }
 }
 
@@ -4347,6 +4389,41 @@
   *y += line_ext->baseline;
 }
 
+/* update_cluster
+ * cluster_start_index is relative to start of run
+ */
+static void 
+update_cluster(PangoLayoutIter *iter,
+	       int              cluster_start_index)
+{
+  gchar            *pcluster;
+  PangoGlyphString *gs;
+  int               next_logcluster_glyph;
+  int               cluster_length;
+
+  iter->character_position = 0;
+
+  gs = iter->run->glyphs;
+  iter->cluster_width = cluster_width (gs, iter->cluster_start);
+  iter->next_cluster_glyph = next_cluster_start (gs, iter->cluster_start);
+
+  if (iter->ltr)
+    next_logcluster_glyph = iter->next_cluster_glyph;
+  else
+    next_logcluster_glyph = next_logical_cluster_start_rtl (gs, iter->cluster_start);
+
+  cluster_length = (run_glyph_to_index (iter->run, next_logcluster_glyph) 
+		    - cluster_start_index);
+
+  pcluster = iter->layout->text + iter->run->item->offset + cluster_start_index;
+  iter->cluster_num_chars = g_utf8_strlen (pcluster, cluster_length);
+
+  if (! iter->ltr)
+    pcluster = g_utf8_prev_char (pcluster + cluster_length);
+
+  iter->index = pcluster - iter->layout->text;
+}
+
 static void
 update_run (PangoLayoutIter *iter,
 	    int              run_start_index)
@@ -4387,33 +4464,23 @@
     iter->ltr = (iter->run->item->analysis.level % 2) == 0;
   else
     iter->ltr = TRUE;
-  
-  if (iter->ltr)    
-    iter->cluster_x = iter->run_logical_rect.x;
-  else
-    iter->cluster_x = iter->run_logical_rect.x +
-      iter->run_logical_rect.width;
-  
+
   iter->cluster_start = 0;
+  iter->cluster_x = iter->run_logical_rect.x;
 
-  if (iter->run)
-    iter->next_cluster_start = next_cluster_start (iter->run->glyphs,
-                                                   iter->cluster_start);
-  else
-    iter->next_cluster_start = 0;
-  
-  /* Index of the first cluster in the glyph string, relative
-   * to the start of the run
-   */
-  if (iter->run)
-    iter->cluster_index = iter->run->glyphs->log_clusters[0];
+  /* CHECK: do we need to handle the case where num_glyphs==0? */
+  if (iter->run && (iter->run->glyphs->num_glyphs > 0))
+    {
+      update_cluster (iter, iter->run->glyphs->log_clusters[0]);
+    }
   else
-    iter->cluster_index = 0;
-  
-  /* Get an overall index, leaving it unchanged for
-   * a the NULL run
-   */
-  iter->index = run_start_index;
+    {
+      iter->cluster_width = 0;
+      iter->character_position = 0;
+      iter->cluster_num_chars = 0;
+      iter->index = run_start_index;
+    }
+
 }
 
 static PangoLayoutIter *
@@ -4453,9 +4520,13 @@
   new->ltr = iter->ltr;
   
   new->cluster_x = iter->cluster_x;
-  new->cluster_index = iter->cluster_index;
+  new->cluster_width = iter->cluster_x;
+
   new->cluster_start = iter->cluster_start;
-  new->next_cluster_start = iter->next_cluster_start;
+  new->next_cluster_glyph = iter->next_cluster_glyph;
+
+  new->cluster_num_chars = iter->cluster_num_chars;
+  new->character_position = iter->character_position;
 
   return new;
 }
@@ -4484,6 +4555,7 @@
 PangoLayoutIter*
 pango_layout_get_iter (PangoLayout *layout)
 {
+  int run_start_index;
   PangoLayoutIter *iter;
   
   g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
@@ -4499,10 +4571,14 @@
   iter->line = iter->line_list_link->data;
   pango_layout_line_ref (iter->line);
 
+  run_start_index = iter->line->start_index;
   iter->run_list_link = iter->line->runs;
 
   if (iter->run_list_link)
-    iter->run = iter->run_list_link->data;
+    {
+      iter->run = iter->run_list_link->data;
+      run_start_index = iter->run->item->offset;
+    }
   else
     iter->run = NULL;
 
@@ -4514,7 +4590,7 @@
 
   iter->line_extents_link = iter->line_extents;
 
-  update_run (iter, 0);
+  update_run (iter, run_start_index);
 
   return iter;
 }
@@ -4623,51 +4699,24 @@
 gboolean
 pango_layout_iter_next_char (PangoLayoutIter *iter)
 {
-  const char *p;
-  const char *oldp;
-  const char *item_end;
-  int new_index;
-  int next_cluster_index;
-  PangoGlyphString *gs;
-  
+  const char *textp;
+
   if (IS_INVALID (iter))
     return FALSE;
 
   if (iter->run == NULL)
     return pango_layout_iter_next_line (iter);
   
-  gs = iter->run->glyphs;
-
-  next_cluster_index = iter->run->item->offset + cluster_end_index (iter);
+  if (++(iter->character_position) >= iter->cluster_num_chars)
+    return pango_layout_iter_next_cluster (iter);
   
-  oldp = iter->layout->text + iter->index;
-
+  textp = iter->layout->text;
   if (iter->ltr)
-    {
-      item_end = iter->layout->text +
-        iter->run->item->offset +
-        iter->run->item->length;
-      p = g_utf8_next_char (oldp);
-    }
+    iter->index = g_utf8_next_char(textp + iter->index) - textp;
   else
-    {
-      item_end = iter->layout->text + iter->run->item->offset;
-      p = g_utf8_prev_char (oldp);
-    }
-
-  new_index = iter->index + (p - oldp);
-
-  /* Make sure we don't go past the next cluster index */
-  g_assert ((iter->ltr && (new_index <= next_cluster_index)) ||
-            (!iter->ltr && (new_index >= next_cluster_index)));
+    iter->index = g_utf8_prev_char(textp + iter->index) - textp;
   
-  if (new_index == next_cluster_index)
-    return pango_layout_iter_next_cluster (iter);
-  else
-    {
-      iter->index = new_index;
-      return TRUE;
-    }
+  return TRUE;
 }
 
 /**
@@ -4683,6 +4732,7 @@
 pango_layout_iter_next_cluster (PangoLayoutIter *iter)
 {
   PangoGlyphString *gs;
+  int               next_start;
   
   if (IS_INVALID (iter))
     return FALSE;
@@ -4692,19 +4742,15 @@
   
   gs = iter->run->glyphs;
   
-  if (iter->next_cluster_start == gs->num_glyphs)
+  next_start = iter->next_cluster_glyph;
+  if (next_start == gs->num_glyphs)
     return pango_layout_iter_next_run (iter);
   else
     {
-      if (iter->ltr)
-        iter->cluster_x += gs->glyphs[iter->cluster_start].geometry.width;
-      else
-        iter->cluster_x -= gs->glyphs[iter->cluster_start].geometry.width;
-        
-      iter->cluster_start = iter->next_cluster_start;
-      iter->next_cluster_start = next_cluster_start (gs, iter->cluster_start);
-      iter->cluster_index = gs->log_clusters[iter->cluster_start];
-      iter->index = iter->run->item->offset + iter->cluster_index;
+      iter->cluster_start = next_start;
+      iter->cluster_x += iter->cluster_width;
+      update_cluster(iter, gs->log_clusters[iter->cluster_start]);
+
       return TRUE;
     }
 }
@@ -4721,7 +4767,7 @@
 gboolean
 pango_layout_iter_next_run (PangoLayoutIter *iter)
 {
-  gint prev_run_end;
+  gint next_run_start; /* byte index */
   GSList *next_link;
   
   if (IS_INVALID (iter))
@@ -4729,9 +4775,7 @@
 
   if (iter->run == NULL)
     return pango_layout_iter_next_line (iter);
-  else
-    prev_run_end = iter->run->item->offset + iter->run->item->length;
-  
+
   next_link = iter->run_list_link->next;
 
   if (next_link == NULL)
@@ -4739,6 +4783,7 @@
       /* Moving on to the zero-width "virtual run" at the end of each
        * line
        */
+      next_run_start = iter->run->item->offset + iter->run->item->length; 
       iter->run = NULL;
       iter->run_list_link = NULL;
     }
@@ -4746,9 +4791,10 @@
     {
       iter->run_list_link = next_link;
       iter->run = iter->run_list_link->data;
+      next_run_start = iter->run->item->offset;
     }
   
-  update_run (iter, prev_run_end);
+  update_run (iter, next_run_start);
   
   return TRUE;
 }
@@ -4821,15 +4867,8 @@
                                     PangoRectangle  *logical_rect)
 {
   PangoRectangle cluster_rect;
-  int end_index;
-  int start_index;
-  const char *p;
-  const char *end;
-  const char *current;
-  int char_count;
-  int cluster_offset;
-  double char_width;
-  
+  double         char_width;
+
   if (IS_INVALID (iter))
     return;
 
@@ -4847,46 +4886,14 @@
       return;
     }
   
-  /* count chars in the cluster */
-  end_index = iter->run->item->offset + cluster_end_index (iter);
-  start_index = iter->run->item->offset + iter->cluster_index;
+  g_assert (cluster_rect.width == iter->cluster_width);
 
-  if (end_index < start_index)
-    {
-      int tmp = end_index;
-      end_index = start_index;
-      start_index = tmp;
-    }
-
-  g_assert (start_index < end_index);
-  
-  p = iter->layout->text + start_index;
-  current = iter->layout->text + iter->index;
-  end = iter->layout->text + end_index;
-
-  g_assert (p < end);
-  g_assert (p <= current);
-  g_assert (current < end);
-  
-  char_count = 0;
-  cluster_offset = 0;
-  while (p != end)
-    {
-      if (p < current)
-        ++cluster_offset;
-      ++char_count;
-      p = g_utf8_next_char (p);
-    }
-
-  char_width = ((double)cluster_rect.width) / char_count;
+  char_width = ((double)cluster_rect.width) / iter->cluster_num_chars;
   logical_rect->width = char_width;
   logical_rect->height = cluster_rect.height;
   logical_rect->y = cluster_rect.y;
-  
-  if (iter->ltr)
-    logical_rect->x = cluster_rect.x + char_width * cluster_offset;
-  else
-    logical_rect->x = cluster_rect.x + cluster_rect.width - char_width * cluster_offset;
+  logical_rect->x = cluster_rect.x + char_width * iter->character_position;
+
 }
 
 /**
@@ -4918,7 +4925,7 @@
   
   pango_glyph_string_extents_range (iter->run->glyphs,
                                     iter->cluster_start,
-                                    iter->next_cluster_start,
+                                    iter->next_cluster_glyph,
                                     iter->run->item->analysis.font,
                                     ink_rect,
                                     logical_rect);
