Evas text: Fix Evas Text truncated text case. 65/59165/1
authorYoungbok Shin <youngb.shin@samsung.com>
Wed, 9 Dec 2015 07:50:33 +0000 (09:50 +0200)
committerYoungbok Shin <youngb.shin@samsung.com>
Thu, 11 Feb 2016 05:44:35 +0000 (14:44 +0900)
Summary:
Evas Text only concerns about a advance of each text item.
When a width of last character is bigger than its advance, the last character can be truncated.
And the different line size calculation caused different aligning between Evas Text and Evas Textblock.
So, the width of last character will be considered in Evas Text just like Evas Textblock.
@fix

Test Plan:
The following text shows how the size calculation is different between Evas Textblock and Text.
Get native size from Evas Textblock and get width(geometry) of Evas Text.
You can see the width of Evas Text is bigger than native size of Evas Textblock.
(adv > width)
こんにちは。

The following text will be truncated without this patch.
(adv < width)
ନୂଁ

Reviewers: woohyun, tasn, herdsman

Subscribers: jpeg, cedric

Differential Revision: https://phab.enlightenment.org/D3004

Change-Id: I53eefb462fa2a6efecde83b6e5d116b455c82a42

src/lib/evas/canvas/evas_object_text.c
src/tests/evas/evas_test_text.c

index 8e1cebf..f5eb94b 100644 (file)
@@ -54,7 +54,7 @@ struct _Evas_Text_Data
       Evas_Object_Text_Item    *ellipsis_end;
       Evas_Coord                w, h;
       int                       advance;
-      int                       advance_without_ellipsis;
+      int                       width_without_ellipsis;
       Eina_Bool                 ellipsis;
    } last_computed;
 
@@ -344,9 +344,9 @@ _evas_object_text_char_at_coords(const Evas_Object *eo_obj,
 }
 
 static Evas_Coord
-_evas_object_text_horiz_advance_without_ellipsis_get(const Evas_Text_Data *o)
+_evas_object_text_horiz_width_without_ellipsis_get(const Evas_Text_Data *o)
 {
-   return o->last_computed.advance_without_ellipsis;
+   return o->last_computed.width_without_ellipsis;
 }
 
 static Evas_Coord
@@ -686,7 +686,7 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
 {
    Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
    EvasBiDiStrIndex *v_to_l = NULL;
-   Evas_Coord advance = 0;
+   Evas_Coord advance = 0, width = 0;
    size_t pos, visual_pos;
    int len = eina_unicode_strlen(text);
    int l = 0, r = 0;
@@ -733,6 +733,8 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
 
    if (text)
      {
+        const Evas_Object_Text_Item *last_it = NULL;
+
         while (len > 0)
           {
              Evas_Font_Instance *script_fi = NULL;
@@ -770,15 +772,22 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
                   pos += run_len;
                   script_len -= run_len;
                   len -= run_len;
+
+                  if (it->w > 0)
+                    last_it = it;
                }
           }
+
+        width = advance;
+        if (last_it)
+          width += last_it->w - last_it->adv;
      }
-   o->last_computed.advance_without_ellipsis = advance;
+   o->last_computed.width_without_ellipsis = width;
 
    _evas_object_text_pad_get(eo_obj, o, &l, &r, NULL, NULL);
 
    /* Handle ellipsis */
-   if (pos && (o->cur.ellipsis >= 0.0) && (advance + l + r > obj->cur->geometry.w) && (obj->cur->geometry.w > 0))
+   if (pos && (o->cur.ellipsis >= 0.0) && (width + l + r > obj->cur->geometry.w) && (obj->cur->geometry.w > 0))
      {
         Evas_Coord ellip_frame = obj->cur->geometry.w;
         Evas_Object_Text_Item *start_ellip_it = NULL, *end_ellip_it = NULL;
@@ -800,7 +809,7 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
                   start_ellip_it = _layout_ellipsis_item_new(obj, o);
                }
              o->last_computed.ellipsis_start = start_ellip_it;
-             ellip_frame -= start_ellip_it->adv;
+             ellip_frame -= start_ellip_it->w;
           }
         if (o->cur.ellipsis != 1)
           {
@@ -816,18 +825,18 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
                   end_ellip_it = _layout_ellipsis_item_new(obj, o);
                }
              o->last_computed.ellipsis_end = end_ellip_it;
-             ellip_frame -= end_ellip_it->adv;
+             ellip_frame -= end_ellip_it->w;
           }
 
         /* The point where we should start from, going for the full
          * ellip frame. */
-        Evas_Coord ellipsis_coord = o->cur.ellipsis * (advance - ellip_frame);
+        Evas_Coord ellipsis_coord = o->cur.ellipsis * (width - ellip_frame);
         if (start_ellip_it)
           {
              Evas_Object_Text_Item *itr = o->items;
              advance = 0;
 
-             while (itr && (advance + l + r + itr->adv < ellipsis_coord))
+             while (itr && (advance + l + r + itr->w < ellipsis_coord))
                {
                   Eina_Inlist *itrn = EINA_INLIST_GET(itr)->next;
                   if ((itr != start_ellip_it) && (itr != end_ellip_it))
@@ -869,7 +878,7 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
                {
                   if (itr != end_ellip_it) /* was start_ellip_it */
                     {
-                       if (advance + l + r + itr->adv >= ellip_frame)
+                       if (advance + l + r + itr->w >= ellip_frame)
                          {
                             break;
                          }
@@ -2170,7 +2179,7 @@ _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text)
         int w, h;
         int l = 0, r = 0, t = 0, b = 0;
 
-        w = _evas_object_text_horiz_advance_without_ellipsis_get(o);
+        w = _evas_object_text_horiz_width_without_ellipsis_get(o);
         h = _evas_object_text_vert_advance_get(eo_obj, o);
         _evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
 
index 90ce19d..d6417cd 100644 (file)
@@ -141,6 +141,20 @@ START_TEST(evas_text_geometries)
    pos = evas_object_text_last_up_to_pos(to, -50, 0);
    ck_assert_int_eq(pos, -1);
 
+   /* Obviously, adv > width case */
+   evas_object_text_text_set(to, "こんにちは。");
+   adv = evas_object_text_horiz_advance_get(to);
+   evas_object_geometry_get(to, NULL, NULL, &w, NULL);
+   ck_assert_int_lt(w, adv);
+
+#ifdef HAVE_HARFBUZZ
+   /* Obviously, adv < width case */
+   evas_object_text_text_set(to, "ନୂଁ");
+   adv = evas_object_text_horiz_advance_get(to);
+   evas_object_geometry_get(to, NULL, NULL, &w, NULL);
+   ck_assert_int_lt(adv, w);
+#endif
+
    END_TEXT_TEST();
 }
 END_TEST
@@ -172,27 +186,36 @@ END_TEST
 static void
 _test_ellipsis(Evas_Object *to, const char *buf, const char *font, Evas_Font_Size size, double ellipsis)
 {
+   Evas_Coord text_width;
+   Evas_Coord w, h;
+
    evas_object_text_ellipsis_set(to, ellipsis);
    evas_object_move(to, 0, 0);
-   evas_object_resize(to, 500, 500);
    evas_object_text_font_set(to, font, size);
    evas_object_text_text_set(to, buf);
+   /* Besure to give a enough width for text. */
+   evas_object_resize(to, 500, 500);
+   /* Because of the way text object behaves, this will actually force
+    * a resize. */
+   evas_object_geometry_get(to, NULL, NULL, &w, NULL);
+
+   text_width = w;
+   /* Force a resize. */
+   evas_object_resize(to, text_width - 1, 500);
+   evas_object_geometry_get(to, NULL, NULL, &w, NULL);
+   ck_assert_int_ne(text_width, w);
 
    /* Make it smaller to force ellipsis and check the resulting size. */
-     {
-        Evas_Coord w, h;
-        evas_object_geometry_get(to, NULL, NULL, NULL, &h);
-        evas_object_resize(to, 140, h);
-
-        /* Because of the way text object behaves, this will actually force
-         * a resize. */
-        evas_object_geometry_get(to, NULL, NULL, &w, NULL);
-        /* If it's gotten way too small, it means we have an issue. */
-        fail_if(w < 100);
-
-        w = evas_object_text_horiz_advance_get(to);
-        fail_if(w < 100);
-     }
+   evas_object_geometry_get(to, NULL, NULL, NULL, &h);
+   evas_object_resize(to, 140, h);
+
+   /* Force a resize. */
+   evas_object_geometry_get(to, NULL, NULL, &w, NULL);
+   /* If it's gotten way too small, it means we have an issue. */
+   fail_if(w < 100);
+
+   w = evas_object_text_horiz_advance_get(to);
+   fail_if(w < 100);
 }
 
 START_TEST(evas_text_ellipsis)
@@ -225,6 +248,18 @@ START_TEST(evas_text_ellipsis)
    buf = "Fffffffffffffffffffffffffffffffffff";
    _test_ellipsis(to, buf, font, size, 0.0);
 
+   /* Obviously, adv > width case */
+   buf = "This is a test for adv > width case. こんにちは。";
+   _test_ellipsis(to, buf, font, size, 0.0);
+   _test_ellipsis(to, buf, font, size, 0.5);
+   _test_ellipsis(to, buf, font, size, 1.0);
+
+   /* Obviously, adv < width case */
+   buf = "This is a test for adv < width case. ନୂଁ";
+   _test_ellipsis(to, buf, font, size, 0.0);
+   _test_ellipsis(to, buf, font, size, 0.5);
+   _test_ellipsis(to, buf, font, size, 1.0);
+
    /* Check ellipsis value with NULL */
    fail_if(evas_object_text_ellipsis_get(NULL) != -1.0);