(analyse_bidi_level): New function.
authorhanda <handa>
Wed, 7 Nov 2007 12:03:04 +0000 (12:03 +0000)
committerhanda <handa>
Wed, 7 Nov 2007 12:03:04 +0000 (12:03 +0000)
(visual_order): Do reordering using the already decided
bidi-level.
(compose_glyph_string): Decide bidi-level before calling flt.

src/draw.c

index 6d81532..101eb04 100644 (file)
@@ -100,23 +100,21 @@ static MSymbol MbidiBN;
 static MSymbol MbidiS;
 static MSymbol MbidiNSM;
 
-static void
-visual_order (MGlyphString *gstring)
+static int
+analyse_bidi_level (MGlyphString *gstring)
 {
   int len = gstring->used - 2;
-  MGlyph *glyphs;
   int bidi_sensitive = gstring->control.orientation_reversed;
+  int max_level;
   MGlyph *g;
   int i;
 #ifdef HAVE_FRIBIDI
   FriBidiCharType base = bidi_sensitive ? FRIBIDI_TYPE_RTL : FRIBIDI_TYPE_LTR;
   FriBidiChar *logical = alloca (sizeof (FriBidiChar) * len);
-  FriBidiChar *visual;
-  FriBidiStrIndex *indices;
   FriBidiLevel *levels;
+  FriBidiStrIndex *indices;
 #else  /* not HAVE_FRIBIDI */
   int *logical = alloca (sizeof (int) * len);
-  int *indices;
   char *levels = alloca (len);
 
   memset (levels, 0, sizeof (int) * len);
@@ -149,63 +147,94 @@ visual_order (MGlyphString *gstring)
     }
 
   if (! bidi_sensitive)
-    return;
+    return 0;
 
-  glyphs = alloca (sizeof (MGlyph) * len);
-  memcpy (glyphs, gstring->glyphs + 1, sizeof (MGlyph) * len);
 #ifdef HAVE_FRIBIDI
-  visual = alloca (sizeof (FriBidiChar) * (len + 1));
-  indices = alloca (sizeof (FriBidiStrIndex) * (len + 1));
   levels = alloca (sizeof (FriBidiLevel) * (len + 1));
+  indices = alloca (sizeof (FriBidiStrIndex) * (len + 1));
 
-  fribidi_log2vis (logical, len, &base, visual, indices, NULL, levels);
-#else  /* not HAVE_FRIBIDI */
-  indices = alloca (sizeof (int) * len);
-  for (i = 0; i < len; i++)
+  fribidi_log2vis (logical, len, &base, NULL, NULL, indices, levels);
+#endif /* not HAVE_FRIBIDI */
+
+  MGLYPH (0)->bidi_level = 0;
+  max_level = 0;
+  for (g = MGLYPH (1), i = 0; i < len; g++, i++)
     {
-      if (levels[i])
+      g->bidi_level = levels[i];
+      if (max_level < g->bidi_level)
+       max_level = g->bidi_level;
+    }
+  MGLYPH (i)->bidi_level = 0;
+  return max_level;
+}
+
+static void
+visual_order (MGlyphString *gstring)
+{
+  MGlyph *glyphs = alloca (sizeof (MGlyph) * gstring->used);
+  int i, j, gidx;
+
+  memcpy (glyphs, gstring->glyphs, sizeof (MGlyph) * gstring->used);
+
+  for (i = gidx = 0; i < gstring->used; gidx++)
+    {
+      int level = glyphs[i].bidi_level;
+      
+      gstring->glyphs[gidx] = glyphs[i];
+      glyphs[i].rface = NULL;
+
+      if (level % 2)
        {
-         int j, k;
+         int prev_level = glyphs[i - 1].bidi_level;
 
-         for (j = i + 1; j < len && levels[j]; j++);
-         for (k = j--; i < k; i++, j--)
-           indices[i] = j;
-         i--;
+         if (prev_level == level)
+           i--;
+         else if (prev_level > level)
+           {
+             for (; glyphs[i - 1].bidi_level > level; i--);
+             if (glyphs[i].bidi_level % 2)
+               for (level = glyphs[i].bidi_level;
+                    glyphs[i + 1].bidi_level == level; i++);
+           }
+         else
+           for (i++; ! glyphs[i].rface; i++);
        }
       else
-       indices[i] = i;
-    }
-#endif /* not HAVE_FRIBIDI */
+       {
+         int next_level = glyphs[i + 1].bidi_level;
 
-  for (i = 0; i < len;)
-    {
-      /* Index into gstring->glyphs plus 1 for GLYPHS[i].  */
-      int j = indices[i];
-      /* Length of grapheme-cluster */
-      int seglen;
+         if (next_level == level)
+           i++;
+         else if (next_level > level)
+           {
+             for (; glyphs[i + 1].bidi_level > level; i++);
+             if ((glyphs[i].bidi_level % 2) == 0)
+               for (level = glyphs[i].bidi_level;
+                    glyphs[i - 1].bidi_level == level; i--);
+           }
+         else
+           {
+             int save = i + 1;
 
-      g = glyphs + i;
-#ifdef HAVE_FRIBIDI
-      if (visual[j] != logical[i])
-       {
-         /* Mirrored.  */
-         g->g.c = visual[j];
-         if (g->rface->rfont)
-           g->g.code = mfont__encode_char (NULL, (MFont *) g->rface->rfont,
-                                         NULL, g->g.c);
+             for (i--; glyphs[i].bidi_level >= level; i--);
+             if (! glyphs[i].rface)
+               for (i = save; ! glyphs[i].rface; i++);
+           }
        }
-#endif /* HAVE_FRIBIDI */
-      g->bidi_level = levels[i];
-      for (seglen = 1, g++;
-          i + seglen < len && glyphs[i].g.from == glyphs[i + seglen].g.from;
-          seglen++, g++)
+    }
+  for (i = 1; i < gstring->used - 1; i++)
+    {
+      MGlyph *g = gstring->glyphs + i;
+
+      for (j = i; g->g.from == gstring->glyphs[j + 1].g.from; j++);
+      if (j > i)
        {
-         g->bidi_level = levels[i];
-         if (indices[i + seglen] < j)
-           j = indices[i + seglen];
+         memcpy (glyphs + i, gstring->glyphs + i,
+                 sizeof (MGlyph) * (j - i + 1));
+         for (; i <= j; i++)
+           g[j - i] = glyphs[i];
+         i--;
        }
-      memcpy (MGLYPH (j + 1), glyphs + i, sizeof (MGlyph) * seglen);
-      i += seglen;
     }
 }
 
@@ -308,6 +337,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
   MRealizedFace *rface = default_rface;
   MRealizedFont *rfont;
   int size = gstring->control.fixed_width;
+  int max_bidi_level = 0;
   int i;
 
   MLIST_RESET (gstring);
@@ -408,6 +438,9 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
   APPEND_GLYPH (gstring, g_tmp);
   gstring->to = pos;
 
+  if (gstring->control.enable_bidi)
+    max_bidi_level = analyse_bidi_level (gstring);
+
   /* The next loop is to change each <rface> member for non-ASCII
      characters if necessary.  */
   stop = charset_change = language_change = from;
@@ -547,7 +580,7 @@ compose_glyph_string (MFrame *frame, MText *mt, int from, int to,
     }
 
   /* At last, reorder glyphs visually if necessary.  */
-  if (gstring->control.enable_bidi)
+  if (max_bidi_level > 0)
     visual_order (gstring);
 }