Evas textblock: Fixed mixed format and text item reordering.
authortasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 30 Jan 2011 10:31:08 +0000 (10:31 +0000)
committertasn <tasn@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 30 Jan 2011 10:31:08 +0000 (10:31 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@56404 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/canvas/evas_object_textblock.c
src/lib/engines/common/evas_bidi_utils.c
src/lib/engines/common/evas_bidi_utils.h
src/lib/engines/common/evas_font_draw.c
src/lib/engines/common/evas_font_query.c

index d40c462..b198adc 100644 (file)
  * @subsection textblock_layout The layout system
  * @todo write @ref textblock_layout
  */
+#include <stdlib.h>
+
 #include "evas_common.h"
 #include "evas_private.h"
 
@@ -286,6 +288,9 @@ struct _Evas_Object_Textblock_Item
    int                              x, w, h;
    int                              inset, baseline;
    size_t                           source_pos;
+#ifdef BIDI_SUPPORT
+   size_t                           visual_pos;
+#endif
    Evas_BiDi_Props                  bidi_props;
 };
 
@@ -294,6 +299,8 @@ struct _Evas_Object_Textblock_Format_Item
    EINA_INLIST;
    const char                          *item;
    Evas_Object_Textblock_Node_Format   *source_node;
+   Evas_Object_Textblock_Node_Text     *text_node;
+   size_t                               text_pos;
    int                                  x, w, h, y, ascent, descent;
    unsigned char                        vsize : 2;
    unsigned char                        size : 2;
@@ -558,7 +565,9 @@ _nodes_clear(const Evas_Object *obj)
        Evas_Object_Textblock_Node_Text *n;
 
        n = o->text_nodes;
-        _evas_textblock_node_text_remove(o, n);
+        o->text_nodes = _NODE_TEXT(eina_inlist_remove(
+                 EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n)));
+        _evas_textblock_node_text_free(n);
      }
    while (o->format_nodes)
      {
@@ -1923,12 +1932,14 @@ static inline double
 _layout_line_align_get(Ctxt *c)
 {
 #ifdef BIDI_SUPPORT
-   if (c->align_auto && c->ln && c->ln->items)
+   if (c->align_auto && c->ln)
      {
-        if (c->ln->items->source_node &&
-
+        if ((c->ln->items && c->ln->items->source_node &&
               EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(
-                 c->ln->items->source_node->bidi_props))
+                 c->ln->items->source_node->bidi_props)) ||
+              (c->ln->format_items && c->ln->format_items->text_node &&
+              EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(
+                 c->ln->format_items->text_node->bidi_props)))
           {
              /* Align right*/
              return 1.0;
@@ -1943,6 +1954,177 @@ _layout_line_align_get(Ctxt *c)
    return c->align;
 }
 
+#ifdef BIDI_SUPPORT
+/**
+ * @internal
+ * Reorder the items in a line.
+ *
+ * @param line the line to reorder
+ */
+static void
+_layout_line_reorder(Ctxt *c, Evas_Object_Textblock_Line *line)
+{
+   /*FIXME: do it a bit more efficient - not very efficient ATM. */
+   Evas_Object_Textblock_Item *it;
+   Evas_Object_Textblock_Format_Item *fi;
+   Evas_BiDi_Paragraph_Props *props;
+   EvasBiDiStrIndex *v_to_l = NULL;
+   size_t start, end;
+   size_t len;
+
+   if (line->items && line->items->source_node &&
+         line->items->source_node->bidi_props)
+     {
+        props = line->items->source_node->bidi_props;
+        start = end = line->items->source_pos;
+     }
+   else if (line->format_items && line->format_items->text_node &&
+         line->format_items->text_node->bidi_props)
+     {
+        props = line->format_items->text_node->bidi_props;
+        start = end = line->format_items->text_pos;
+     }
+   else
+     {
+        return;
+     }
+
+   /* Find the first and last positions in the line */
+
+   EINA_INLIST_FOREACH(line->items, it)
+     {
+        if (it->source_pos < start)
+          {
+             start = it->source_pos;
+          }
+        else
+          {
+             int tlen;
+             tlen = eina_unicode_strlen(it->text);
+             if (it->source_pos + tlen > end)
+               {
+                  end = it->source_pos + tlen;
+               }
+          }
+     }
+   EINA_INLIST_FOREACH(line->format_items, fi)
+     {
+        if (fi->text_pos < start)
+          {
+             start = fi->text_pos;
+          }
+        else
+          {
+             if (fi->text_pos + 1 > end)
+               {
+                  end = fi->text_pos + 1;
+               }
+          }
+     }
+
+   len = end - start;
+   evas_bidi_props_reorder_line(NULL, start, len, props, &v_to_l);
+
+   /* Update visual pos */
+     {
+        Evas_Object_Textblock_Item *i;
+        i = line->items;
+        while (i)
+          {
+             i->visual_pos = evas_bidi_position_logical_to_visual(
+                           v_to_l, len, i->source_pos - start);
+             i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(i)->next;
+          }
+     }
+
+   /*FIXME: not very efficient, sort the items arrays. */
+     {
+        Evas_Object_Textblock_Item *i, *j, *min;
+        i = line->items;
+        while (i)
+          {
+             min = i;
+             EINA_INLIST_FOREACH(i, j)
+               {
+                  if (j->visual_pos < min->visual_pos)
+                    {
+                       min = j;
+                    }
+               }
+             if (min != i)
+               {
+                  line->items = (Evas_Object_Textblock_Item *) eina_inlist_remove(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min));
+                  line->items = (Evas_Object_Textblock_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i));
+               }
+
+             i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(min)->next;
+          }
+     }
+     {
+        Evas_Object_Textblock_Format_Item *i, *j, *min;
+        i = line->format_items;
+        while (i)
+          {
+             min = i;
+             EINA_INLIST_FOREACH(i, j)
+               {
+                  if (evas_bidi_position_logical_to_visual(
+                           v_to_l, len, j->text_pos - start) <
+                        evas_bidi_position_logical_to_visual(
+                           v_to_l, len, min->text_pos - start))
+                    {
+                       min = j;
+                    }
+               }
+             if (min != i)
+               {
+                  line->format_items = (Evas_Object_Textblock_Format_Item *)
+                     eina_inlist_remove(EINA_INLIST_GET(line->format_items),
+                           EINA_INLIST_GET(min));
+                  line->format_items = (Evas_Object_Textblock_Format_Item *)
+                     eina_inlist_prepend_relative(EINA_INLIST_GET(line->format_items), EINA_INLIST_GET(min), EINA_INLIST_GET(i));
+               }
+
+             i = (Evas_Object_Textblock_Format_Item *) EINA_INLIST_GET(min)->next;
+          }
+     }
+
+   /* Recalculate the positions according to the new order. */
+     {
+        Evas_Object_Textblock_Format_Item *fi = line->format_items;
+        Evas_Object_Textblock_Item *it = line->items;
+        Evas_Coord x = 0;
+
+        while (it || fi)
+          {
+             if (it && (!fi || ((int) it->visual_pos <
+                   evas_bidi_position_logical_to_visual(v_to_l, len,
+                      fi->text_pos - start))))
+               {
+                  int adv = 0;
+                  it->x = x;
+                  if (it->format->font.font)
+                    adv = c->ENFN->font_h_advance_get(c->ENDT,
+                          it->format->font.font, it->text, &it->bidi_props);
+
+                  x += adv;
+                  it = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(it)->next;
+               }
+             else if (fi)
+               {
+                  fi->x = x;
+                  x += fi->w;
+                  fi = (Evas_Object_Textblock_Format_Item *)
+                     EINA_INLIST_GET(fi)->next;
+               }
+          }
+     }
+
+   /* Fix the order in each line correctly */
+   if (v_to_l) free(v_to_l);
+}
+#endif
+
 /**
  * @internal
  * Create a new line and append it to the lines in the context.
@@ -1956,6 +2138,10 @@ _layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt)
    Evas_Object_Textblock_Item *it;
    Evas_Object_Textblock_Format_Item *fi;
 
+#ifdef BIDI_SUPPORT
+   _layout_line_reorder(c, c->ln);
+#endif
+
    c->maxascent = c->maxdescent = 0;
    if (!c->ln->items)
      _layout_format_ascent_descent_adjust(c, fmt);
@@ -2078,7 +2264,8 @@ _layout_item_new(Ctxt *c __UNUSED__, Evas_Object_Textblock_Format *fmt, const Ei
  * @param c the context to work on - Not NULL.
  * @param fmt the format to use. - Not NULL.
  * @param it the item to check - Not null.
- * @return -1 on error, cutoff index on success.
+ * @return -1 if there is no cutoff (either because there is really none,
+ * or because of an error), cutoff index on success.
  */
 static int
 _layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Item *it)
@@ -2275,6 +2462,74 @@ _layout_word_next(Eina_Unicode *str, int p)
 
 /**
  * @internal
+ * Adds the item to the list, updates the item's properties (e.g, x,w,h)
+ * and splits the items to text runs, i.e splits each item to rtl/ltr runs of
+ * text.
+ *
+ * @param c the context
+ * @param fmt the format of the item.
+ * @param it the item itself.
+ */
+static void
+_layout_text_add_and_split_item(Ctxt *c, Evas_Object_Textblock_Format *fmt,
+      Evas_Object_Textblock_Item *it)
+{
+   int tw, th, adv, inset;
+
+#ifdef BIDI_SUPPORT
+   int cutoff, len;
+
+
+   len = eina_unicode_strlen(it->text);
+   do
+     {
+        Evas_Object_Textblock_Item *new_it;
+        cutoff = evas_bidi_end_of_run_get(&it->bidi_props, len);
+        if (cutoff > 0)
+          {
+             new_it = _layout_item_new(c, fmt, it->text + cutoff);
+             _layout_item_text_cutoff(c, it, cutoff);
+          }
+#endif
+
+        tw = th = 0;
+        if (fmt->font.font)
+          c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text,
+                &it->bidi_props, &tw, &th);
+        it->w = tw;
+        it->h = th;
+        inset = 0;
+        if (fmt->font.font)
+          inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font,
+                it->text);
+        it->inset = inset;
+        it->x = c->x;
+        adv = 0;
+        if (fmt->font.font)
+          adv = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font,
+                it->text, &it->bidi_props);
+        c->x += adv;
+        c->ln->items = (Evas_Object_Textblock_Item *)
+           eina_inlist_append(EINA_INLIST_GET(c->ln->items),
+                 EINA_INLIST_GET(it));
+
+#ifdef BIDI_SUPPORT
+        if (cutoff > 0)
+          {
+             new_it->source_node = it->source_node;
+             new_it->source_pos = it->source_pos + cutoff;
+             new_it->bidi_props.start = new_it->source_pos;
+             new_it->bidi_props.props = new_it->source_node->bidi_props;
+             it = new_it;
+             len -= cutoff;
+          }
+     }
+   while (cutoff > 0);
+#endif
+}
+
+/**
+ * @internal
  * Appends the text from node n starting at start ending at off to the layout.
  * It uses the fmt for the formatting.
  *
@@ -2288,7 +2543,7 @@ _layout_word_next(Eina_Unicode *str, int p)
 static void
 _layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node_Text *n, int start, int off, const char *repch)
 {
-   int adv, inset, tw, th, new_line, empty_item;
+   int tw, th, new_line, empty_item;
    int wrap, twrap, ch, index, white_stripped;
    Eina_Unicode *alloc_str = NULL;
    const Eina_Unicode *str = EINA_UNICODE_EMPTY_STRING;
@@ -2353,9 +2608,9 @@ _layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Text
              str = alloc_str;
           }
      }
+
 skip:
    tbase = str;
-   //   printf("add: wrap: %i|%i, width: %i '%s'\n", fmt->wrap_word, fmt->wrap_char, c->w, str);
    new_line = 0;
    empty_item = 0;
 
@@ -2380,6 +2635,8 @@ skip:
         tw = th = 0;
         if (fmt->font.font)
           c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &it->bidi_props, &tw, &th);
+        /* Check if we need to wrap, i.e the text is bigger than the width
+         * Only calculate wrapping if the width of the object is > 0 */
         if ((c->w >= 0) &&
               ((fmt->wrap_word) || (fmt->wrap_char)) &&
               ((c->x + tw) >
@@ -2387,8 +2644,10 @@ skip:
                 c->marginl - c->marginr)))
           {
              wrap = _layout_text_cutoff_get(c, fmt, it);
+             /* Avoiding too small textblocks to even contain one char */
              if (wrap == 0)
                GET_NEXT(str, wrap);
+             /* We need to wrap and found the position that overflows */
              if (wrap > 0)
                {
                   if (fmt->wrap_word)
@@ -2397,6 +2656,8 @@ skip:
                        ch = GET_NEXT(str, index);
                        if (!_is_white(ch))
                          wrap = _layout_word_start(str, wrap);
+                       /* If we found where to cut the text at, i.e the start
+                        * of the word we were pointing at */
                        if (wrap > 0)
                          {
                             twrap = wrap;
@@ -2406,10 +2667,6 @@ skip:
                               {
                                  _layout_item_text_cutoff(c, it, wrap);
                                  twrap = wrap;
-                                 /*we don't want to move next, that's why it's
-                                  * commented out.
-                                  * ch = evas_common_font_utf8_get_next((unsigned char *)str, &twrap);
-                                  */
                                  str += twrap;
                               }
                             /* intersects a word */
@@ -2427,6 +2684,7 @@ skip:
                                  else
                                    {
                                       empty_item = 1;
+                                      /* FIXME: use proper cleaning here */
                                       if (it->text) free(it->text);
                                       _format_unref_free(c->obj, it->format);
                                       free(it);
@@ -2446,17 +2704,25 @@ skip:
                                    }
                               }
                          }
+                       /* If we weren't able to find the start of the word we
+                        * are currently pointing at, or we were able but it's
+                        * the first word */
                        else
                          {
                             /* wrap now is the index of the word START */
                             index = wrap;
                             ch = GET_NEXT(str, index);
 
+                            /* If there are already items in this line, we
+                             * should just try creating a new line for it */
                             if (c->ln->items)
                               {
                                  white_stripped = _layout_item_abort(c, fmt, it);
                                  empty_item = 1;
                               }
+                            /* If there were no items in this line, try to do
+                             * our best wrapping possible since it's the middle
+                             * of the word */
                             else
                               {
                                  wrap = 0;
@@ -2479,10 +2745,16 @@ skip:
                        _layout_item_text_cutoff(c, it, wrap);
                        str += wrap;
                     }
+                  /* Marked we wrapped and we want to start a new line */
                   new_line = 1;
                }
+             /* We need to wrap, but for some reason we failed obatining the
+              * overflow position. */
              else
                {
+                  /*FIXME: sanitize this error handling - should probably
+                   * never get here anyway unless something really bad
+                   * has happend */
                   /* wrap now is the index of the word START */
                   if (wrap < 0) wrap = 0;
                   index = wrap;
@@ -2513,31 +2785,21 @@ skip:
                        new_line = 1;
                     }
                }
-             if (!empty_item)
-               {
-                  tw = th = 0;
-                  if (fmt->font.font)
-                    c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, it->text, &it->bidi_props, &tw, &th);
-               }
           }
         else
           str = NULL;
-        if (empty_item) empty_item = 0;
+
+        /* Set item properties */
+        if (empty_item)
+          {
+             empty_item = 0;
+          }
         else
           {
-             it->w = tw;
-             it->h = th;
-             inset = 0;
-             if (fmt->font.font)
-               inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font, it->text);
-             it->inset = inset;
-             it->x = c->x;
-             adv = 0;
-             if (fmt->font.font)
-               adv = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font, it->text, &it->bidi_props);
-             c->x += adv;
-             c->ln->items = (Evas_Object_Textblock_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->items), EINA_INLIST_GET(it));
+             _layout_text_add_and_split_item(c, fmt, it);
           }
+
+
         if (new_line)
           {
              if (str)
@@ -2553,6 +2815,7 @@ skip:
              _layout_line_advance(c, fmt);
           }
      }
+
    if (alloc_str) free(alloc_str);
 }
 
@@ -2576,6 +2839,12 @@ _layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node_Format *n, const cha
    fi->source_node = n;
    c->ln->format_items = (Evas_Object_Textblock_Format_Item *)eina_inlist_append(EINA_INLIST_GET(c->ln->format_items),
          EINA_INLIST_GET(fi));
+   if (n)
+     {
+        fi->text_node = n->text_node;
+        /* FIXME: make it more efficient */
+        fi->text_pos = _evas_textblock_node_format_pos_get(n);
+     }
    return fi;
 }
 
@@ -2926,6 +3195,7 @@ _layout(const Evas_Object *obj, int calc_only, int w, int h, int *w_ret, int *h_
           }
         _layout_text_append(c, fmt, n, start, -1, o->repch);
      }
+
    /* Advance the line so it'll calculate the size */
    if ((c->ln) && (c->ln->items || c->ln->format_items) && (fmt))
      _layout_line_advance(c, fmt);
@@ -4724,12 +4994,38 @@ evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur)
      }
 
    if (!ln) return;
+   if (ln->items)
+     {
+        Evas_Object_Textblock_Item *i;
+        it = ln->items;
+        EINA_INLIST_FOREACH(ln->items, i)
+          {
+             if (it->source_pos > i->source_pos)
+               {
+                  it = i;
+               }
+          }
+     }
+   else
+     it = NULL;
 
-   it = (Evas_Object_Textblock_Item *)ln->items;
-   fi = (Evas_Object_Textblock_Format_Item *)ln->format_items;
+   if (ln->format_items)
+     {
+        Evas_Object_Textblock_Format_Item *i;
+        fi = ln->format_items;
+        EINA_INLIST_FOREACH(ln->format_items, i)
+          {
+             if (fi->text_pos > i->text_pos)
+               {
+                  fi = i;
+               }
+          }
+     }
+   else
+     fi = NULL;
    if ((it) && (fi))
      {
-       if (it->x < fi->x) fi = NULL;
+       if (it->source_pos < fi->text_pos) fi = NULL;
        else it = NULL;
      }
    if (it)
@@ -4795,17 +5091,37 @@ evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur)
 
    if (!ln) return;
    if (ln->items)
-     it = (Evas_Object_Textblock_Item *)((EINA_INLIST_GET(ln->items))->last);
+     {
+        Evas_Object_Textblock_Item *i;
+        it = ln->items;
+        EINA_INLIST_FOREACH(ln->items, i)
+          {
+             if (it->source_pos < i->source_pos)
+               {
+                  it = i;
+               }
+          }
+     }
    else
      it = NULL;
 
    if (ln->format_items)
-     fi = (Evas_Object_Textblock_Format_Item *)((EINA_INLIST_GET(ln->format_items))->last);
+     {
+        Evas_Object_Textblock_Format_Item *i;
+        fi = ln->format_items;
+        EINA_INLIST_FOREACH(ln->format_items, i)
+          {
+             if (fi->text_pos < i->text_pos)
+               {
+                  fi = i;
+               }
+          }
+     }
    else
      fi = NULL;
    if ((it) && (fi))
      {
-       if ((it->x + it->w) > (fi->x + fi->w)) fi = NULL;
+       if (it->source_pos > fi->text_pos) fi = NULL;
        else it = NULL;
      }
    if (it)
@@ -5960,7 +6276,6 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form
 
         /* Advance all the cursors after our cursor */
         _evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, 1);
-
         if (_IS_PARAGRAPH_SEPARATOR(format))
           {
              _evas_textblock_cursor_break_paragraph(cur, n);
@@ -5973,7 +6288,6 @@ evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *form
                    eina_ustrbuf_string_get(cur->node->unicode));
 #endif
           }
-
      }
 
     _evas_textblock_changed(o, cur->obj);
@@ -6625,6 +6939,7 @@ evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C
      {
         _find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it);
      }
+
    if (ln && it)
      {
         pos = cur->pos - it->source_pos;
@@ -6638,11 +6953,29 @@ evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C
                    pos,
                    &x, &y, &w, &h);
           }
-       x += ln->x + it->x;
-       if (x < ln->x)
-         {
-            x = ln->x;
-         }
+
+        /* Handle bidi adjustments */
+        if (_evas_textblock_cursor_is_at_the_end(cur))
+          {
+#ifdef BIDI_SUPPORT
+             if (EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(it->bidi_props.props))
+               {
+                  x = ln->x;
+               }
+             else
+#endif
+               {
+                  x = ln->x + ln->w;
+               }
+          }
+        else
+          {
+             x += ln->x + it->x - it->inset;
+          }
+        if (x < ln->x)
+          {
+             x = ln->x;
+          }
        y = ln->y;
        h = ln->h;
      }
@@ -6658,7 +6991,17 @@ evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_C
                }
              else
                {
-                  x = ln->x + fi->x + fi->w;
+#ifdef BIDI_SUPPORT
+                  if (EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(
+                           fi->text_node->bidi_props))
+                    {
+                       x = ln->x;
+                    }
+                  else
+#endif
+                    {
+                       x = ln->x + ln->w;
+                    }
                   y = ln->y;
                }
              w = 0;
@@ -7890,7 +8233,7 @@ _evas_object_textblock_rehint(Evas_Object *obj)
  */
 
 
-#if 0
+#if 1
 /* Good for debugging */
 void
 pfnode(Evas_Object_Textblock_Node_Format *n)
@@ -7898,7 +8241,7 @@ pfnode(Evas_Object_Textblock_Node_Format *n)
    printf("Format Node: %p\n", n);
    printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last);
    printf("text_node = %p, offset = %u, visible = %d\n", n->text_node, n->offset, n->visible);
-   printf("%s\n", eina_strbuf_string_get(n->format));
+   printf("'%s'\n", eina_strbuf_string_get(n->format));
 }
 
 void
@@ -7907,7 +8250,7 @@ ptnode(Evas_Object_Textblock_Node_Text *n)
    printf("Text Node: %p\n", n);
    printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last);
    printf("format_node = %p\n", n->format_node);
-   printf("%ls\n", eina_ustrbuf_string_get(n->unicode));
+   printf("'%ls'\n", eina_ustrbuf_string_get(n->unicode));
 }
 #endif
 
index ed83fe5..b814201 100644 (file)
@@ -167,6 +167,11 @@ evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr)
       return NULL;
 
 
+   if (!evas_bidi_is_rtl_str(eina_ustr)) /* No need to handle bidi */
+     {
+        len = -1;
+        goto cleanup;
+     }
 
    len = eina_unicode_strlen(eina_ustr);
    /* The size of fribidichar s different than eina_unicode, convert */
@@ -181,13 +186,6 @@ evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr)
         ustr = (const FriBidiChar *) eina_ustr;
      }
 
-
-   if (!evas_bidi_is_rtl_str(eina_ustr)) /* No need to handle bidi */
-     {
-        len = -1;
-        goto cleanup;
-     }
-
    bidi_props = evas_bidi_paragraph_props_new();
 
    /* Prep work for reordering */
@@ -260,30 +258,33 @@ evas_bidi_props_copy_and_ref(const Evas_BiDi_Props *src, Evas_BiDi_Props *dst)
  * Reorders ustr according to the bidi props.
  *
  * @param ustr the string to reorder. - Null is ok, will just populate the map.
- * @param intl_props the intl properties to rerorder according to.
+ * @param start the start of the line
+ * @param len the length of the line
+ * @param props the paragraph props to reorder according to
  * @param _v_to_l The visual to logical map to populate - if NULL it won't populate it.
  * @return #EINA_FALSE on success, #EINA_TRUE on error.
  */
 Eina_Bool
-evas_bidi_props_reorder_line(Eina_Unicode *eina_ustr, const Evas_BiDi_Props *intl_props, EvasBiDiStrIndex **_v_to_l)
+evas_bidi_props_reorder_line(Eina_Unicode *eina_ustr, size_t start, size_t len, const Evas_BiDi_Paragraph_Props *props, EvasBiDiStrIndex **_v_to_l)
 {
    EvasBiDiStrIndex *v_to_l = NULL;
-   FriBidiChar *ustr, *base_ustr = NULL;
-   size_t len;
+   FriBidiChar *ustr = NULL, *base_ustr = NULL;
 
-   if (!intl_props->props)
+   if (!props)
      return EINA_FALSE;
 
-   len = eina_unicode_strlen(eina_ustr);
-   /* The size of fribidichar is different than eina_unicode, convert */
-   if (sizeof(Eina_Unicode) != sizeof(FriBidiChar))
+   if (eina_ustr)
      {
-        base_ustr = ustr = calloc(len + 1, sizeof(FriBidiChar));
-        ustr = _evas_bidi_unicode_to_fribidichar(ustr, eina_ustr);
-     }
-   else
-     {
-        ustr = (FriBidiChar *) eina_ustr;
+        /* The size of fribidichar is different than eina_unicode, convert */
+        if (sizeof(Eina_Unicode) != sizeof(FriBidiChar))
+          {
+             base_ustr = ustr = calloc(len + 1, sizeof(FriBidiChar));
+             ustr = _evas_bidi_unicode_to_fribidichar(ustr, eina_ustr);
+          }
+        else
+          {
+             ustr = (FriBidiChar *) eina_ustr;
+          }
      }
 
 
@@ -304,9 +305,9 @@ evas_bidi_props_reorder_line(Eina_Unicode *eina_ustr, const Evas_BiDi_Props *int
    /* Shaping must be done *BEFORE* breaking to lines so there's no choice but
     doing it in textblock. */
    if (!fribidi_reorder_line (FRIBIDI_FLAGS_DEFAULT,
-            intl_props->props->char_types + intl_props->start,
-            len, 0, intl_props->props->direction,
-            intl_props->props->embedding_levels + intl_props->start,
+            props->char_types + start,
+            len, 0, props->direction,
+            props->embedding_levels + start,
             ustr, v_to_l))
      {
         goto error;
@@ -316,7 +317,7 @@ evas_bidi_props_reorder_line(Eina_Unicode *eina_ustr, const Evas_BiDi_Props *int
    /* The size of fribidichar is different than eina_unicode, convert */
    if (sizeof(Eina_Unicode) != sizeof(FriBidiChar))
      {
-        eina_ustr = _evas_bidi_fribidichar_to_unicode(eina_ustr, base_ustr);
+        _evas_bidi_fribidichar_to_unicode(eina_ustr, base_ustr);
         free(base_ustr);
      }
    return EINA_FALSE;
@@ -330,6 +331,36 @@ error:
 
 /**
  * @internal
+ * Returns the end of the current run of text
+ *
+ * @param bidi_props the properties
+ * @param len the length of the string
+ * @return the position of the end of the run (offset from
+ * bidi_props->props->start), 0 when there is no end (i.e all the text)
+ */
+int
+evas_bidi_end_of_run_get(const Evas_BiDi_Props *bidi_props, int len)
+{
+   EvasBiDiLevel *i;
+   EvasBiDiLevel base;
+
+   if (!bidi_props || !bidi_props->props || (len <= 0))
+     return 0;
+
+   i = bidi_props->props->embedding_levels + bidi_props->start;
+   base = *i;
+   for ( ; (len > 0) && (base == *i) ; len--, i++)
+     ;
+
+   if (len == 0)
+     {
+        return 0;
+     }
+   return i - (bidi_props->props->embedding_levels + bidi_props->start);
+}
+
+/**
+ * @internal
  * Returns the visual string index from the logical string index.
  *
  * @param v_to_l the visual to logical map
index 86a83f1..4587c18 100644 (file)
@@ -39,6 +39,8 @@
  * these types in function declarations. Defining as void should help ensuring that.
  */
 
+/* Evas_BiDi_Direction is defined in evas.h */
+
 #ifdef USE_FRIBIDI
 # define _EVAS_BIDI_TYPEDEF(type) \
    typedef FriBidi ## type EvasBiDi ## type
@@ -108,8 +110,11 @@ evas_bidi_is_rtl_str(const Eina_Unicode *str);
 Eina_Bool
 evas_bidi_is_rtl_char(const Evas_BiDi_Props *bidi_props, EvasBiDiStrIndex index);
 
+int
+evas_bidi_end_of_run_get(const Evas_BiDi_Props *bidi_props, int len);
+
 Eina_Bool
-evas_bidi_props_reorder_line(Eina_Unicode *text, const Evas_BiDi_Props *intl_props, EvasBiDiStrIndex **_v_to_l);
+evas_bidi_props_reorder_line(Eina_Unicode *eina_ustr, size_t start, size_t len, const Evas_BiDi_Paragraph_Props *props, EvasBiDiStrIndex **_v_to_l);
 
 Evas_BiDi_Paragraph_Props *
 evas_bidi_paragraph_props_get(const Eina_Unicode *eina_ustr) EINA_ARG_NONNULL(1) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
index 6067f92..4a4e20b 100644 (file)
@@ -505,7 +505,8 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, RGBA_Font
 
    if (visual_text)
      {
-        evas_bidi_props_reorder_line(visual_text, intl_props, NULL);
+        evas_bidi_props_reorder_line(visual_text, intl_props->start,
+              eina_unicode_strlen(visual_text), intl_props->props, NULL);
         text = visual_text;
      }
    else
index e570f69..e6bc70b 100644 (file)
@@ -95,7 +95,6 @@ evas_common_font_query_size(RGBA_Font *fn, const Eina_Unicode *text, const Evas_
         int gl, kern;
 
        gl = *text;
-       if (gl == 0) break;
        index = evas_common_font_glyph_search(fn, &fi, gl);
        LKL(fi->ft_mutex);
         if (fi->src->current_size != fi->size)
@@ -349,7 +348,9 @@ evas_common_font_query_char_coords(RGBA_Font *fn, const Eina_Unicode *in_text, c
    visual_text = eina_unicode_strdup(in_text);
    if (visual_text)
      {
-        evas_bidi_props_reorder_line(visual_text, intl_props, &visual_to_logical);
+        evas_bidi_props_reorder_line(visual_text, intl_props->start,
+              eina_unicode_strlen(visual_text), intl_props->props,
+              &visual_to_logical);
         text = visual_text;
      }
    else
@@ -518,7 +519,9 @@ evas_common_font_query_char_at_coords(RGBA_Font *fn, const Eina_Unicode *in_text
 
    if (visual_text)
      {
-        evas_bidi_props_reorder_line(visual_text, intl_props, &visual_to_logical);
+        evas_bidi_props_reorder_line(visual_text, intl_props->start,
+              eina_unicode_strlen(visual_text), intl_props->props,
+              &visual_to_logical);
         text = visual_text;
      }
    else