evas_textblock: content fit feature 79/219979/2
authorAli Alzyod <ali198724@gmail.com>
Thu, 12 Dec 2019 05:22:45 +0000 (14:22 +0900)
committerWooHyun Jung <wh0705.jung@samsung.com>
Thu, 12 Dec 2019 06:51:51 +0000 (06:51 +0000)
Summary:
**Content Fit Feature for Evas_Object_Textblock**

This Feature is available at **Evas **object level.  And **Edje **level (where it is internally use evas functionality)
This feature will allow text block to fit its content font size to proper size to fit its area.

**Main Properties:**
Fit Modes        :   None=Default, Width, Height, All [Width+Height]
Fit Size Range :   Contains maximum and minimum font size to be used (and in between).
Fit Step Size    :   Step(Jump) value when trying fonts sizes between Size_Range max and min.
Fit Size Array   :   Other way to resize font, where you explicitly select font sizes to be uses    (for example [20, 50, 100] it will try 3 sizes only)

Text Fit feature was available in Edje but:
1- It doesn't effected by ellipsis or warping in font style (or do not handle the in right way)
2- Accuracy is not good (specially if you have fix pixel size elements (spaces,tabs,items))
3- No (Step size, Size Array) available.

Test Plan:
To check the Feature
> elementary_test
> fit
> textbock fit
You can modify all the modes and properties

These are two examples, One using Evas other uses Edje

**Evas**

```

enum BUTTON{
   BUTTON_MODE             = 0,
   BUTTON_MAX              = 1,
   BUTTON_MIN              = 2,
   BUTTON_STEP             = 3,
   BUTTON_ARRAY            = 4,
   BUTTON_CONTENT          = 5,
   BUTTON_STYLE            = 6,
   BUTTON_ALL              = BUTTON_STYLE+1,
};

char* BUTTON_STR[BUTTON_ALL] ={
   "MODE",
   "MAX",
   "MIN",
   "STEP",
   "ARRAY",
   "CONTENT",
   "STYLE",
};

char *contents[] = {
   "Hello World",
   "This is Line<br>THis is other Line",
   "This text contains <font_size=20 color=#F00>SPECIFIC SIZE</font_size> that does not effected by fit mode"
   };

char *styles[] = {
   "DEFAULT='font=sans font_size=30 color=#000 wrap=mixed ellipsis=1.0'",
   "DEFAULT='font=sans font_size=30 color=#000 wrap=mixed'",
   "DEFAULT='font=sans font_size=30 color=#000 ellipsis=1.0'",
   "DEFAULT='font=sans font_size=30 color=#000'",
   };

char *styles_names[] = {
   "wrap=<color=#F00>mixed</color> ellipsis=<color=#F00>1.0</color>",
   "wrap=<color=#F00>mixed</color> ellipsis=<color=#F00>NONE</color>",
   "wrap=<color=#F00>NONE</color> ellipsis=<color=#F00>1.0</color>",
   "wrap=<color=#F00>NONE</color> ellipsis=<color=#F00>NONE</color>",
   };

typedef struct _APP
{
   Evas_Object *win, *box, *txtblock,*bg, *boxHor, *boxHor2;
   Eo *btn[BUTTON_ALL];
   Eo *lbl_status;
   char * str;
   unsigned int i_contnet, i_style;
} APP;
APP *app;

char * get_fit_status(Eo * textblock);

static void _btn_clicked(void *data EINA_UNUSED, Eo *obj, void *eventInfo EINA_UNUSED){
   if (obj == app->btn[BUTTON_MODE])
     {
        unsigned int options;
        evas_textblock_fit_options_get(app->txtblock, &options);
        if (options == TEXTBLOCK_FIT_MODE_NONE)
           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_HEIGHT);
        else if (options == TEXTBLOCK_FIT_MODE_HEIGHT)
           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_WIDTH);
        else if (options == TEXTBLOCK_FIT_MODE_WIDTH)
           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_ALL);
        else if (options == TEXTBLOCK_FIT_MODE_ALL)
           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_NONE);
     }
   else if (obj == app->btn[BUTTON_MAX])
     {
        unsigned int min, max;
        evas_textblock_fit_size_range_get(app->txtblock, &min, &max);
        max -= 5;
        evas_textblock_fit_size_range_set(app->txtblock, min, max);
     }
   else if (obj == app->btn[BUTTON_MIN])
     {
        unsigned int min, max;
        evas_textblock_fit_size_range_get(app->txtblock, &min, &max);
        min += 5;
        evas_textblock_fit_size_range_set(app->txtblock, min, max);
     }
   else if (obj == app->btn[BUTTON_STEP])
     {
        unsigned int step;
        evas_textblock_fit_step_size_get(app->txtblock, &step);
        step++;
        evas_textblock_fit_step_size_set(app->txtblock, step);
     }
   else if (obj == app->btn[BUTTON_ARRAY])
     {
        unsigned int font_size[] = {10, 50, 100 ,150};
        evas_textblock_fit_size_array_set(app->txtblock,font_size,4);
     }
   else if (obj == app->btn[BUTTON_CONTENT])
     {
        app->i_contnet++;
        if(app->i_contnet>=sizeof(contents)/sizeof(char*))
           app->i_contnet=0;
        evas_object_textblock_text_markup_set(app->txtblock,contents[app->i_contnet]);
     }
   else if (obj == app->btn[BUTTON_STYLE])
     {
        app->i_style++;
        if(app->i_style>=sizeof(styles)/sizeof(char*))
           app->i_style=0;

        Evas_Textblock_Style *style = evas_object_textblock_style_get(app->txtblock);
        evas_textblock_style_set(style,styles[app->i_style]);
     }

   elm_object_text_set(app->lbl_status, get_fit_status(app->txtblock));
}

char * get_fit_status(Eo * textblock)
{
   static char status[0xFFF];
   unsigned int options,min,max,step,size_array[256];
   size_t size_array_len;
   evas_textblock_fit_options_get(textblock,&options);
   evas_textblock_fit_size_range_get(textblock,&min,&max);
   evas_textblock_fit_step_size_get(textblock,&step);
   evas_textblock_fit_size_array_get(textblock,NULL,&size_array_len,0);
   if (size_array_len>255)
      size_array_len = 255;
   evas_textblock_fit_size_array_get(textblock,size_array,NULL,size_array_len);

   strcpy(status,"Mode : ");
   if (options == TEXTBLOCK_FIT_MODE_NONE)
      strcat(status,"MODE_NONE");
   else if (options == TEXTBLOCK_FIT_MODE_HEIGHT)
      strcat(status,"MODE_HEIGHT");
   else if (options == TEXTBLOCK_FIT_MODE_WIDTH)
      strcat(status,"MODE_WIDTH");
   else if (options == TEXTBLOCK_FIT_MODE_ALL)
      strcat(status,"MODE_ALL");

   strcat(status,"<br>");
   sprintf(status + strlen(status),"Max   : %d<br>",max);
   sprintf(status + strlen(status),"Min   : %d<br>",min);
   sprintf(status + strlen(status),"Step  : %d<br>",step);
   sprintf(status + strlen(status),"Array  : [ ");
   for (size_t i = 0 ; i < 10 ; i++)
     {
        if(i<size_array_len)
           sprintf(status + strlen(status)," %d,",size_array[i]);
     }

   if(10<size_array_len)
      sprintf(status + strlen(status)," ... ");
   sprintf(status + strlen(status)," ]");

   sprintf(status + strlen(status),"<br>");
   sprintf(status + strlen(status),"%s",styles_names[app->i_style]);

   return status;
}

int elm_main(int argc, char **argv)
{
  app = calloc(sizeof(APP), 1);

   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);

   app->win = elm_win_util_standard_add("Main", "App");
   elm_win_autodel_set(app->win, EINA_TRUE);

   app->box = elm_box_add(app->win);
   app->boxHor = elm_box_add(app->box);
   app->boxHor2 = elm_box_add(app->box);
   app->txtblock = evas_object_textblock_add(app->box);
   app->bg = elm_bg_add(app->box);
   elm_bg_color_set(app->bg,255,255,255);

   Evas_Textblock_Style *style = evas_textblock_style_new();
   evas_textblock_style_set(style,styles[0]);
   evas_object_textblock_style_set(app->txtblock,style);
   evas_object_textblock_text_markup_set(app->txtblock,contents[0]);

   elm_box_horizontal_set(app->boxHor, EINA_TRUE);
   elm_box_horizontal_set(app->boxHor2, EINA_TRUE);

   evas_object_size_hint_weight_set(app->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(app->box, EVAS_HINT_FILL, EVAS_HINT_FILL);

   evas_object_size_hint_weight_set(app->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(app->box, EVAS_HINT_FILL, EVAS_HINT_FILL);

   evas_object_show(app->txtblock);
   evas_object_show(app->bg);
   evas_object_show(app->box);
   evas_object_show(app->boxHor);
   evas_object_show(app->boxHor2);

   elm_box_pack_end(app->box, app->bg);
   elm_box_pack_end(app->box, app->boxHor);
   elm_box_pack_end(app->box, app->boxHor2);

   elm_object_content_set(app->bg,app->txtblock);

   elm_win_resize_object_add(app->win, app->box);
   evas_object_resize(app->win, 320, 480);

   for(int i = 0 ; i < BUTTON_ALL ; i++)
     {
        app->btn[i] = elm_button_add(app->boxHor);
        evas_object_smart_callback_add(app->btn[i], "clicked", _btn_clicked, NULL);
        elm_object_text_set(app->btn[i], BUTTON_STR[i]);
        elm_box_pack_end(app->boxHor, app->btn[i]);
        evas_object_show(app->btn[i]);
     }

   app->lbl_status = elm_label_add(app->boxHor2);
   elm_object_text_set(app->lbl_status, get_fit_status(app->txtblock));
   elm_box_pack_end(app->boxHor2, app->lbl_status);
   evas_object_show(app->lbl_status);

   evas_object_size_hint_weight_set(app->txtblock, EVAS_HINT_EXPAND,EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(app->txtblock, EVAS_HINT_FILL, EVAS_HINT_FILL);

   evas_object_size_hint_weight_set(app->bg, EVAS_HINT_EXPAND,EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(app->bg, EVAS_HINT_FILL, EVAS_HINT_FILL);

   evas_object_show(app->win);
   elm_run();
   return 0;
}

ELM_MAIN()
```

**Edje**

```
// compile: edje_cc source.edc
// run: edje_player source.edje
collections {
   styles
   {
      style
      {
         name: "text_style";
         base: "font=sans font_size=30 color=#FFF wrap=mixed ellipsis=1.0";
         tag: "br" "\n";
         tag: "ps" "ps";
         tag: "tab" "\t";
         tag: "b" "+ font_weight=Bold";
      }
   }
   group {
      name: "my_group"; // must be the same as in source.c
      parts {

         part
         {
            name: "background";
            type: RECT;
            scale: 1;
            description
            {
               color: 0 0 0 0;
               rel1.relative: 0.0 0.0;
               rel2.relative: 1.0 1.0;
            }
         }

         part
         {
            name: "text";
            type: TEXTBLOCK;
            scale: 1;
            entry_mode: NONE;
            effect: OUTLINE_SHADOW;
            description
            {
               state: "default" 0.0;
               rel1.to : "background";
               rel1.relative: 0.0 0.0;
               rel2.to : "background";
               rel2.relative: 1.0 1.0;
               text
               {
                  style: "text_style";
                  align: 0.0 0.0;
                  text: "Hello World This is Me";
                  fit: 1 1;
                  fit_step: 1;
                  size_range: 30 200;
                  //fit_size_array: 20 40 60 80 100 200;
               }
            }
         }
      }
   }
}
```

Found Task T5724 relative to this Feature

Reviewers: woohyun, bowonryu, cedric, raster

Reviewed By: woohyun

Subscribers: a.srour, #committers, #reviewers, cedric

Tags: #efl

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

Change-Id: I0fab88e03c77966c6b2fd0fb4c40a1e9e55bd803

src/bin/edje/edje_cc_handlers.c
src/bin/elementary/test.c
src/bin/elementary/test_label.c
src/lib/edje/edje_data.c
src/lib/edje/edje_private.h
src/lib/edje/edje_textblock.c
src/lib/eet/Eet.h
src/lib/evas/canvas/evas_object_textblock.c
src/lib/evas/canvas/evas_textblock_legacy.h
src/tests/evas/evas_test_textblock.c

index d61f6fb..e920d9b 100644 (file)
@@ -418,6 +418,8 @@ static void       st_collections_group_parts_part_description_text_repch(void);
 static void       st_collections_group_parts_part_description_text_size(void);
 static void       st_collections_group_parts_part_description_text_size_range(void);
 static void       st_collections_group_parts_part_description_text_fit(void);
+static void       st_collections_group_parts_part_description_text_fit_step(void);
+static void       st_collections_group_parts_part_description_text_fit_size_array(void);
 static void       st_collections_group_parts_part_description_text_min(void);
 static void       st_collections_group_parts_part_description_text_max(void);
 static void       st_collections_group_parts_part_description_text_align(void);
@@ -965,6 +967,8 @@ New_Statement_Handler statement_handlers[] =
    {"collections.group.parts.part.description.text.size", st_collections_group_parts_part_description_text_size},
    {"collections.group.parts.part.description.text.size_range", st_collections_group_parts_part_description_text_size_range},
    {"collections.group.parts.part.description.text.fit", st_collections_group_parts_part_description_text_fit},
+   {"collections.group.parts.part.description.text.fit_step", st_collections_group_parts_part_description_text_fit_step},
+   {"collections.group.parts.part.description.text.fit_size_array", st_collections_group_parts_part_description_text_fit_size_array},
    {"collections.group.parts.part.description.text.min", st_collections_group_parts_part_description_text_min},
    {"collections.group.parts.part.description.text.max", st_collections_group_parts_part_description_text_max},
    {"collections.group.parts.part.description.text.align", st_collections_group_parts_part_description_text_align},
@@ -11782,6 +11786,83 @@ st_collections_group_parts_part_description_text_fit(void)
    ed->text.fit_y = parse_bool(1);
 }
 
+
+/**
+    @page edcref
+
+    @property
+        fit_step
+    @parameters
+        [font step size in points (pt)]
+    @effect
+        Sets the font step size for the text part. when fitting text
+
+        Defaults: 1
+    @since 1.24.0
+    @endproperty
+ */
+static void
+st_collections_group_parts_part_description_text_fit_step(void)
+{
+   Edje_Part_Description_Text *ed;
+
+   check_arg_count(1);
+
+   if (current_part->type != EDJE_PART_TYPE_TEXTBLOCK)
+     {
+        ERR("parse error %s:%i. text attributes in non-TEXTBLOCK part.",
+            file_in, line - 1);
+        exit(-1);
+     }
+
+   ed = (Edje_Part_Description_Text *)current_desc;
+
+   ed->text.fit_step = parse_int(0);
+
+   if (ed->text.fit_step < 1)
+     {
+          ERR("parse error %s:%i. fit step less than 1.",
+            file_in, line - 1);
+        exit(-1);
+     }
+}
+
+/**
+    @page edcref
+
+    @property
+        fit
+    @parameters
+        [Array of font sizes in points]
+    @effect
+        Sets the allowed font sizes array for the text part.
+    @since 1.24.0
+    @endproperty
+ */
+static void
+st_collections_group_parts_part_description_text_fit_size_array(void)
+{
+   int n, argc;
+   Edje_Part_Description_Text *ed;
+
+   if (current_part->type != EDJE_PART_TYPE_TEXTBLOCK)
+     {
+        ERR("parse error %s:%i. text attributes in non-TEXTBLOCK part.",
+            file_in, line - 1);
+        exit(-1);
+     }
+
+   ed = (Edje_Part_Description_Text *)current_desc;
+   check_min_arg_count(1);
+
+   for (n = 0, argc = get_arg_count(); n < argc; n++)
+     {
+        unsigned int *value = malloc(sizeof(unsigned int));
+        *value = (unsigned int) parse_int(n);
+        ed->text.fit_size_array = eina_list_append(ed->text.fit_size_array, value);
+     }
+}
+
 /**
     @page edcref
 
index cab1923..966d164 100644 (file)
@@ -240,6 +240,7 @@ void test_flip_page_eo(void *data, Evas_Object *obj, void *event_info);
 void test_label(void *data, Evas_Object *obj, void *event_info);
 void test_label_slide(void *data, Evas_Object *obj, void *event_info);
 void test_label_wrap(void *data, Evas_Object *obj, void *event_info);
+void test_textblock_fit(void *data, Evas_Object *obj, void *event_info);
 void test_label_ellipsis(void *data, Evas_Object *obj, void *event_info);
 void test_label_colors(void *data, Evas_Object *obj, void *event_info);
 void test_label_emoji(void *data, Evas_Object *obj, void *event_info);
@@ -1206,6 +1207,7 @@ add_tests:
    ADD_TEST(NULL, "Text", "Label", test_label);
    ADD_TEST(NULL, "Text", "Label Slide", test_label_slide);
    ADD_TEST(NULL, "Text", "Label Wrap", test_label_wrap);
+   ADD_TEST(NULL, "Text", "Textblock Fit", test_textblock_fit);
    ADD_TEST(NULL, "Text", "Label Ellipsis", test_label_ellipsis);
    ADD_TEST(NULL, "Text", "Label Colors", test_label_colors);
    ADD_TEST(NULL, "Text", "Label Emoji", test_label_emoji);
index 233ce01..929d06b 100644 (file)
@@ -309,6 +309,238 @@ test_label_slide(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve
    evas_object_show(win);
 }
 
+
+
+/*** FIT TEXT **************************************************************/
+enum BUTTON{
+   BUTTON_MODE             = 0,
+   BUTTON_MAX              = 1,
+   BUTTON_MIN              = 2,
+   BUTTON_STEP             = 3,
+   BUTTON_ARRAY            = 4,
+   BUTTON_CONTENT          = 5,
+   BUTTON_STYLE            = 6,
+   BUTTON_ALL              = BUTTON_STYLE+1,
+};
+
+char* BUTTON_STR[BUTTON_ALL] ={
+   "MODE",
+   "MAX",
+   "MIN",
+   "STEP",
+   "ARRAY",
+   "CONTENT",
+   "STYLE",
+};
+
+char *contents[] = {
+   "Hello World",
+   "This is Line<br>THis is other Line",
+   "This text contains <font_size=20 color=#F00>SPECIFIC SIZE</font_size>that does not effected by fit mode"
+   };
+
+char *styles[] = {
+   "DEFAULT='font=sans font_size=30 color=#000 wrap=mixed ellipsis=1.0'",
+   "DEFAULT='font=sans font_size=30 color=#000 wrap=mixed'",
+   "DEFAULT='font=sans font_size=30 color=#000 ellipsis=1.0'",
+   "DEFAULT='font=sans font_size=30 color=#000'",
+   };
+
+char *styles_names[] = {
+   "wrap=<color=#F00>mixed</color> ellipsis=<color=#F00>1.0</color>",
+   "wrap=<color=#F00>mixed</color> ellipsis=<color=#F00>NONE</color>",
+   "wrap=<color=#F00>NONE</color> ellipsis=<color=#F00>1.0</color>",
+   "wrap=<color=#F00>NONE</color> ellipsis=<color=#F00>NONE</color>",
+   };
+
+typedef struct _APP
+{
+   Evas_Object *win, *box, *txtblock,*bg, *boxHor, *boxHor2;
+   Eo *btn[BUTTON_ALL];
+   Eo *lbl_status;
+   char * str;
+   unsigned int i_contnet, i_style;
+} APP;
+APP *app;
+
+char * get_fit_status(Eo * textblock);
+
+static void _btn_clicked(void *data EINA_UNUSED, Eo *obj, void *eventInfo EINA_UNUSED){
+   if (obj == app->btn[BUTTON_MODE])
+     {
+        unsigned int options;
+        evas_textblock_fit_options_get(app->txtblock, &options);
+        if (options == TEXTBLOCK_FIT_MODE_NONE)
+           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_HEIGHT);
+        else if (options == TEXTBLOCK_FIT_MODE_HEIGHT)
+           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_WIDTH);
+        else if (options == TEXTBLOCK_FIT_MODE_WIDTH)
+           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_ALL);
+        else if (options == TEXTBLOCK_FIT_MODE_ALL)
+           evas_textblock_fit_options_set(app->txtblock, TEXTBLOCK_FIT_MODE_NONE);
+     }
+   else if (obj == app->btn[BUTTON_MAX])
+     {
+        unsigned int min, max;
+        evas_textblock_fit_size_range_get(app->txtblock, &min, &max);
+        max -= 5;
+        evas_textblock_fit_size_range_set(app->txtblock, min, max);
+     }
+   else if (obj == app->btn[BUTTON_MIN])
+     {
+        unsigned int min, max;
+        evas_textblock_fit_size_range_get(app->txtblock, &min, &max);
+        min += 5;
+        evas_textblock_fit_size_range_set(app->txtblock, min, max);
+     }
+   else if (obj == app->btn[BUTTON_STEP])
+     {
+        unsigned int step;
+        evas_textblock_fit_step_size_get(app->txtblock, &step);
+        step++;
+        evas_textblock_fit_step_size_set(app->txtblock, step);
+     }
+   else if (obj == app->btn[BUTTON_ARRAY])
+     {
+        unsigned int font_size[] = {10, 50, 100 ,150};
+        evas_textblock_fit_size_array_set(app->txtblock,font_size,4);
+     }
+   else if (obj == app->btn[BUTTON_CONTENT])
+     {
+        app->i_contnet++;
+        if(app->i_contnet>=sizeof(contents)/sizeof(char*))
+           app->i_contnet=0;
+        evas_object_textblock_text_markup_set(app->txtblock,contents[app->i_contnet]);
+     }
+   else if (obj == app->btn[BUTTON_STYLE])
+     {
+        app->i_style++;
+        if(app->i_style>=sizeof(styles)/sizeof(char*))
+           app->i_style=0;
+
+        Evas_Textblock_Style *style = evas_object_textblock_style_get(app->txtblock);
+        evas_textblock_style_set(style,styles[app->i_style]);
+     }
+
+   elm_object_text_set(app->lbl_status, get_fit_status(app->txtblock));
+}
+
+char * get_fit_status(Eo * textblock)
+{
+   static char status[0xFFF];
+   unsigned int options,min,max,step,size_array[256];
+   size_t size_array_len;
+   evas_textblock_fit_options_get(textblock,&options);
+   evas_textblock_fit_size_range_get(textblock,&min,&max);
+   evas_textblock_fit_step_size_get(textblock,&step);
+   evas_textblock_fit_size_array_get(textblock,NULL,&size_array_len,0);
+   if (size_array_len>255)
+      size_array_len = 255;
+   evas_textblock_fit_size_array_get(textblock,size_array,NULL,size_array_len);
+
+   strcpy(status,"Mode : ");
+   if (options == TEXTBLOCK_FIT_MODE_NONE)
+      strcat(status,"MODE_NONE");
+   else if (options == TEXTBLOCK_FIT_MODE_HEIGHT)
+      strcat(status,"MODE_HEIGHT");
+   else if (options == TEXTBLOCK_FIT_MODE_WIDTH)
+      strcat(status,"MODE_WIDTH");
+   else if (options == TEXTBLOCK_FIT_MODE_ALL)
+      strcat(status,"MODE_ALL");
+
+   strcat(status,"<br>");
+   sprintf(status + strlen(status),"Max   : %d<br>",max);
+   sprintf(status + strlen(status),"Min   : %d<br>",min);
+   sprintf(status + strlen(status),"Step  : %d<br>",step);
+   sprintf(status + strlen(status),"Array  : [ ");
+   for (size_t i = 0 ; i < 10 ; i++)
+     {
+        if(i<size_array_len)
+           sprintf(status + strlen(status)," %d,",size_array[i]);
+     }
+
+   if(10<size_array_len)
+      sprintf(status + strlen(status)," ... ");
+   sprintf(status + strlen(status)," ]");
+
+   sprintf(status + strlen(status),"<br>");
+   sprintf(status + strlen(status),"%s",styles_names[app->i_style]);
+
+
+
+   return status;
+}
+
+void
+test_textblock_fit(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+  app = calloc(sizeof(APP), 1);
+
+   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+
+   app->win = elm_win_util_standard_add("Main", "App");
+   elm_win_autodel_set(app->win, EINA_TRUE);
+
+   app->box = elm_box_add(app->win);
+   app->boxHor = elm_box_add(app->box);
+   app->boxHor2 = elm_box_add(app->box);
+   app->txtblock = evas_object_textblock_add(app->box);
+   app->bg = elm_bg_add(app->box);
+   elm_bg_color_set(app->bg,255,255,255);
+
+   Evas_Textblock_Style *style = evas_textblock_style_new();
+   evas_textblock_style_set(style,styles[0]);
+   evas_object_textblock_style_set(app->txtblock,style);
+   evas_object_textblock_text_markup_set(app->txtblock,contents[0]);
+
+   elm_box_horizontal_set(app->boxHor, EINA_TRUE);
+   elm_box_horizontal_set(app->boxHor2, EINA_TRUE);
+
+   evas_object_size_hint_weight_set(app->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(app->box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+
+   evas_object_size_hint_weight_set(app->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(app->box, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   evas_object_show(app->txtblock);
+   evas_object_show(app->bg);
+   evas_object_show(app->box);
+   evas_object_show(app->boxHor);
+   evas_object_show(app->boxHor2);
+
+   elm_box_pack_end(app->box, app->bg);
+   elm_box_pack_end(app->box, app->boxHor);
+   elm_box_pack_end(app->box, app->boxHor2);
+
+   elm_object_content_set(app->bg,app->txtblock);
+
+   elm_win_resize_object_add(app->win, app->box);
+   evas_object_resize(app->win, 320, 480);
+
+   for(int i = 0 ; i < BUTTON_ALL ; i++)
+     {
+        app->btn[i] = elm_button_add(app->boxHor);
+        evas_object_smart_callback_add(app->btn[i], "clicked", _btn_clicked, NULL);
+        elm_object_text_set(app->btn[i], BUTTON_STR[i]);
+        elm_box_pack_end(app->boxHor, app->btn[i]);
+        evas_object_show(app->btn[i]);
+     }
+
+   app->lbl_status = elm_label_add(app->boxHor2);
+   elm_object_text_set(app->lbl_status, get_fit_status(app->txtblock));
+   elm_box_pack_end(app->boxHor2, app->lbl_status);
+   evas_object_show(app->lbl_status);
+
+   evas_object_size_hint_weight_set(app->txtblock, EVAS_HINT_EXPAND,EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(app->txtblock, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   evas_object_size_hint_weight_set(app->bg, EVAS_HINT_EXPAND,EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(app->bg, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   evas_object_show(app->win);
+}
+
 /*** Label Wrap **************************************************************/
 void
 test_label_wrap(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
index b9d5545..bf8fbd0 100644 (file)
@@ -1228,6 +1228,8 @@ _edje_edd_init(void)
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.size_range_max", text.size_range_max, EET_T_INT);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.fit_x", text.fit_x, EET_T_UCHAR);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.fit_y", text.fit_y, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.fit_step", text.fit_step, EET_T_UINT);
+   EET_DATA_DESCRIPTOR_ADD_LIST_UINT(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.fit_size_array", text.fit_size_array);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.min_x", text.min_x, EET_T_UCHAR);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.min_y", text.min_y, EET_T_UCHAR);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description_textblock, Edje_Part_Description_Text, "text.max_x", text.max_x, EET_T_UCHAR);
index d42a3fb..8e6a343 100644 (file)
@@ -1496,6 +1496,9 @@ struct _Edje_Part_Description_Spec_Text
    int            id_text_source; /* -1 if none */
    int            size_range_min;
    int            size_range_max; /* -1 means, no bound. */
+   unsigned int   fit_step;
+   /*FIXME THIS SHOULD BE EINA_LIST*/
+   Eina_List     *fit_size_array;
 
    unsigned char  fit_x; /* resize font size down to fit in x dir */
    unsigned char  fit_y; /* resize font size down to fit in y dir */
index f66b1d6..602f67a 100644 (file)
@@ -1,25 +1,5 @@
 #include "edje_private.h"
 
-static double
-_edje_part_recalc_single_textblock_scale_range_adjust(Edje_Part_Description_Text *chosen_desc, double base_scale, double scale)
-{
-   double size, min, max;
-
-   if (chosen_desc->text.size == 0)
-     return scale;
-
-   min = base_scale * chosen_desc->text.size_range_min;
-   max = chosen_desc->text.size_range_max * base_scale;
-   size = chosen_desc->text.size * scale;
-
-   if ((size > max) && (max > 0))
-     scale = max / (double)chosen_desc->text.size;
-   else if (size < min)
-     scale = min / (double)chosen_desc->text.size;
-
-   return scale;
-}
-
 /*
  * Legacy function for min/max calculation of textblock part.
  * It can't calculate min/max properly in many cases.
@@ -606,7 +586,6 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
 
    if (chosen_desc)
      {
-        Eina_Size2D size;
 
         if (ep->part->scale)
           evas_object_scale_set(ep->object, TO_DOUBLE(sc));
@@ -639,15 +618,19 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
                   }
                   if (chosen_desc->text.fit_x)
                     {
-                       if (size.w > 0)
-                         {
-                            s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, base_s,
-                                                                                      orig_s * TO_INT(params->eval.w) / size.w);
-                            efl_gfx_entity_scale_set(ep->object, s);
-                            efl_canvas_textblock_size_native_get(ep->object);
-                         }
+                       size_array[size_array_len++] = *value;
                     }
+                 unsigned int mode = TEXTBLOCK_FIT_MODE_NONE;
+
+                  if (chosen_desc->text.fit_x)
+                    mode |= TEXTBLOCK_FIT_MODE_WIDTH;
                   if (chosen_desc->text.fit_y)
+                    mode |= TEXTBLOCK_FIT_MODE_HEIGHT;
+                  evas_textblock_fit_options_set(ep->object, mode);
+                  evas_textblock_fit_step_size_set(ep->object, chosen_desc->text.fit_step);
+                  if ( chosen_desc->text.size_range_min || chosen_desc->text.size_range_max)
+                     evas_textblock_fit_size_range_set(ep->object, chosen_desc->text.size_range_min,  chosen_desc->text.size_range_max);
+                  if (size_array_len>0)
                     {
                        if (size.h > 0)
                          {
@@ -700,131 +683,28 @@ _edje_part_recalc_single_textblock(FLOAT_T sc,
               */
              if ((chosen_desc->text.fit_x) || (chosen_desc->text.fit_y))
                {
-                  double orig_scale = 1.0;
-                  double result_scale;
-                  double fit_x_scale;
-                  double fit_y_scale;
-                  int given_w, given_h;
-                  Evas_Coord tw, th;
-
-                  given_w = TO_INT(params->eval.w);
-                  given_h = TO_INT(params->eval.h);
-
-                  if (minw && *minw > given_w)
-                    given_w = *minw;
-
-                  if (minh && *minh > given_h)
-                    given_h = *minh;
-
-                  if (ep->part->scale) orig_scale = TO_DOUBLE(sc);
-                  efl_gfx_entity_scale_set(ep->object, orig_scale);
-                  evas_object_textblock_ellipsis_disabled_set(ep->object, EINA_TRUE);
-                  efl_gfx_entity_size_set(ep->object, EINA_SIZE2D(given_w, given_h));
-
-                  result_scale = 0.0;
-                  fit_x_scale = orig_scale;
-                  fit_y_scale = orig_scale;
-
-                  if (chosen_desc->text.fit_x)
+                  unsigned int size_array[255];
+                  size_t size_array_len = 0;
+                  Eina_List *l;
+                  unsigned int *value;
+                  EINA_LIST_FOREACH(chosen_desc->text.fit_size_array, l, value)
                     {
-                       size = efl_canvas_textblock_size_native_get(ep->object);
-                       tw = size.w;
-                       if (tw > 0)
-                         {
-                            fit_x_scale = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, orig_scale,
-                                                                                                orig_scale * (double)given_w / tw);
-                         }
-
-                       result_scale = fit_x_scale;
+                       size_array[size_array_len++] = *value;
                     }
+                 unsigned int mode = TEXTBLOCK_FIT_MODE_NONE;
 
+                  if (chosen_desc->text.fit_x)
+                    mode |= TEXTBLOCK_FIT_MODE_WIDTH;
                   if (chosen_desc->text.fit_y)
+                    mode |= TEXTBLOCK_FIT_MODE_HEIGHT;
+                  evas_textblock_fit_options_set(ep->object, mode);
+                  evas_textblock_fit_step_size_set(ep->object, chosen_desc->text.fit_step);
+                  if ( chosen_desc->text.size_range_min || chosen_desc->text.size_range_max)
+                     evas_textblock_fit_size_range_set(ep->object, chosen_desc->text.size_range_min,  chosen_desc->text.size_range_max);
+                  if (size_array_len>0)
                     {
-                       size = efl_canvas_textblock_size_formatted_get(ep->object);
-                       th = size.h;
-                       if (th > 0)
-                         {
-                            double given_size = (double)given_w * (double)given_w + (double)given_h * (double)given_h;
-                            double current_size = (double)given_w * (double)given_w + (double)th * (double)th;
-
-                            fit_y_scale = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, orig_scale,
-                                                                                                orig_scale * given_size / current_size);
-                         }
-
-                       if (!chosen_desc->text.fit_x)
-                         result_scale = fit_y_scale;
-                       else if (fit_y_scale < result_scale)
-                         result_scale = fit_y_scale;
+                       evas_textblock_fit_size_array_set(ep->object,size_array,size_array_len);
                     }
-
-                  efl_gfx_entity_scale_set(ep->object, result_scale);
-                  size = efl_canvas_textblock_size_native_get(ep->object);
-                  tw = size.w;
-                  size = efl_canvas_textblock_size_formatted_get(ep->object);
-                  th = size.h;
-
-                  /* Final tuning, try going down/up by 5% at a time, hoping it'll
-                   * actually end up being correct. */
-                  if (((chosen_desc->text.fit_x && (tw > given_w))) ||
-                      (chosen_desc->text.fit_y && (th > given_h)))
-                    {
-                       int i = 5;   /* Tries before we give up. */
-
-                       while ((i > 0) &&
-                              ((chosen_desc->text.fit_x && (tw > given_w)) ||
-                               (chosen_desc->text.fit_y && (th > given_h))))
-                         {
-                            double tmp_s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, orig_scale, result_scale * 0.95);
-
-                            /* Break if we are not making any progress. */
-                            if (fabs(tmp_s - result_scale) <= DBL_EPSILON)
-                              break;
-                            result_scale = tmp_s;
-
-                            efl_gfx_entity_scale_set(ep->object, result_scale);
-                            size = efl_canvas_textblock_size_native_get(ep->object);
-                            tw = size.w;
-                            size = efl_canvas_textblock_size_formatted_get(ep->object);
-                            th = size.h;
-                            i--;
-                         }
-                    }
-                  else if (((chosen_desc->text.fit_x && (tw < given_w)) ||
-                            (chosen_desc->text.fit_y && (th < given_h))))
-                    {
-                       int i = 5;   /* Tries before we give up. */
-
-                       while ((i > 0) &&
-                              ((chosen_desc->text.fit_x && (tw < given_w)) ||
-                               (chosen_desc->text.fit_y && (th < given_h))))
-                         {
-                            double tmp_s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, orig_scale, result_scale * 1.05);
-
-                            /* Break if we are not making any progress. */
-                            if (fabs(tmp_s - result_scale) <= DBL_EPSILON)
-                              break;
-
-                            efl_gfx_entity_scale_set(ep->object, tmp_s);
-                            size = efl_canvas_textblock_size_native_get(ep->object);
-                            tw = size.w;
-                            size = efl_canvas_textblock_size_formatted_get(ep->object);
-                            th = size.h;
-
-                            /* It can't be bigger than given size.
-                             * Restore scale for the object. */
-                            if (((chosen_desc->text.fit_x && (tw > given_w)) ||
-                                 (chosen_desc->text.fit_y && (th > given_h))))
-                              {
-                                 efl_gfx_entity_scale_set(ep->object, result_scale);
-                                 break;
-                              }
-
-                            result_scale = tmp_s;
-                            i--;
-                         }
-                    }
-
-                  evas_object_textblock_ellipsis_disabled_set(ep->object, EINA_FALSE);
                }
              /*******
               * END *
index 9c3f666..5bc0889 100644 (file)
@@ -3786,6 +3786,29 @@ eet_data_descriptor_encode(Eet_Data_Descriptor *edd,
 
 /**
  * @ingroup Eet_Data_Group
+ * @brief Adds a linked list of unsigned integers to a data descriptor.
+ * @param edd The data descriptor to add the type to.
+ * @param struct_type The type of the struct.
+ * @param name The string name to use to encode/decode this member
+ *        (must be a constant global and never change).
+ * @param member The struct member itself to be encoded.
+ *
+ * This macro lets you easily add a linked list of unsigned int. All the
+ * parameters are the same as for EET_DATA_DESCRIPTOR_ADD_BASIC().
+ *
+ * @since 1.24.0
+ */
+#define EET_DATA_DESCRIPTOR_ADD_LIST_UINT(edd, struct_type, name, member) \
+  do {                                                                      \
+       struct_type ___ett;                                                  \
+       eet_data_descriptor_element_add(edd, name, EET_T_UINT, EET_G_LIST, \
+                                       (char *)(& (___ett.member)) -        \
+                                       (char *)(& (___ett)),                \
+                                       0, /* 0,  */ NULL, NULL);            \
+    } while (0)
+
+/**
+ * @ingroup Eet_Data_Group
  * @brief Adds a hash type to a data descriptor.
  * @param edd The data descriptor to add the type to.
  * @param struct_type The type of the struct.
index f1f1d6e..f41115f 100644 (file)
@@ -165,6 +165,12 @@ static const char o_type[] = "textblock";
 #define EINA_INLIST_REMOVE(l,i) do { l = (__typeof__(l)) eina_inlist_remove(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
 #define EINA_INLIST_APPEND(l,i) do { l = (__typeof__(l)) eina_inlist_append(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
 
+/**
+ * @internal
+ * @typedef TEXT_FIT_CONTENT_CONFIG
+ * Configurations used to fit content inside Textblock
+ */
+typedef struct _TEXT_FIT_CONTENT_CONFIG TEXT_FIT_CONTENT_CONFIG;
 
 /**
  * @internal
@@ -446,6 +452,20 @@ typedef struct _User_Style_Entry
    const char *key;
 } User_Style_Entry;
 
+struct _TEXT_FIT_CONTENT_CONFIG
+{
+      unsigned int options;
+      unsigned int min_font_size,max_font_size;
+      unsigned int step_size;
+      unsigned int *p_size_array;
+      size_t size_list_length;
+      Eina_Size2D size_cache[256+1]; /** used hash font sizes 1-255 */
+      Eina_Size2D last_size;
+      int last_size_index;
+      Eina_Bool force_refit;
+      char fit_style[256];
+};
+
 #define _FMT(x) (o->default_format.format.x)
 #define _FMT_INFO(x) (o->default_format.info.x)
 
@@ -535,6 +555,7 @@ struct _Evas_Object_Textblock
    Eina_Bool                           ellipsis_disabled : 1;
    /* END */
 
+   TEXT_FIT_CONTENT_CONFIG             fit_content_config;
    Eina_Bool                           redraw : 1;
    Eina_Bool                           changed : 1;
    Eina_Bool                           pause_change : 1;
@@ -549,6 +570,7 @@ struct _Evas_Object_Textblock
    Eina_Bool                           multiline : 1;
    Eina_Bool                           wrap_changed : 1;
    Eina_Bool                           auto_styles : 1;
+   Eina_Bool                           fit_in_progress : 1;
 };
 
 struct _Evas_Textblock_Selection_Iterator
@@ -678,6 +700,19 @@ static void _evas_textblock_cursor_copy(Efl_Text_Cursor_Handle *dst, const Efl_T
 static void
 _textblock_style_generic_set(Evas_Object *eo_obj, Evas_Textblock_Style *ts, const char *key);
 
+
+/*********Internal fitting Functions and Defines*********/
+int fit_cache_clear(TEXT_FIT_CONTENT_CONFIG *fc,const unsigned int fit_cache_flags);
+int fit_text_block(Evas_Object *eo_obj);
+int fit_fill_internal_list(TEXT_FIT_CONTENT_CONFIG *fc);
+int fit_start_fitting(Evas_Object *eo_obj);
+int fit_finish_fitting(Evas_Object *eo_obj);
+Eina_Bool fit_is_fitting(const Evas_Object *eo_obj);
+const unsigned int FIT_CACHE_CANVAS_SIZE         =    0x0001;
+const unsigned int FIT_CACHE_INTERNAL_SIZE_ARRAY =    0x0002;
+const unsigned int FIT_CACHE_FORCE_REFIT         =    0x0004;
+const unsigned int FIT_CACHE_ALL                 =    0x000F;
+
 /** selection iterator */
 /**
   * @internal
@@ -7619,6 +7654,11 @@ _layout_setup(Ctxt *c, const Eo *eo_obj, Evas_Coord w, Evas_Coord h)
                   finalize = EINA_TRUE;
                }
           }
+          /* Extra Style used by fitting configure*/
+          if (*o->fit_content_config.fit_style)
+            {
+               _format_fill(c->obj, c->fmt, o->fit_content_config.fit_style, EINA_FALSE);
+            }
 
         if (finalize)
            _format_finalize(c->obj, c->fmt);
@@ -7719,7 +7759,9 @@ _relayout_if_needed(const Evas_Object *eo_obj, Efl_Canvas_Textblock_Data *o)
    if (obj->delete_me) return EINA_TRUE;
 
    /* XXX const */
-   evas_object_textblock_coords_recalc((Evas_Object *)eo_obj, obj, obj->private_data);
+   if(!fit_is_fitting(eo_obj))
+      evas_object_textblock_coords_recalc((Evas_Object *)eo_obj, obj, obj->private_data);
+
    if (o->formatted.valid)
      {
         return EINA_TRUE;
@@ -7880,6 +7922,10 @@ _efl_canvas_textblock_efl_object_constructor(Eo *eo_obj, Efl_Canvas_Textblock_Da
    _FMT(ellipsis) = -1;
    _FMT_INFO(bitmap_scalable) = EFL_TEXT_FONT_BITMAP_SCALABLE_COLOR;
 
+   /* Fit default properties*/
+   evas_textblock_fit_size_range_set(eo_obj,1,255);
+   evas_textblock_fit_step_size_set(eo_obj,1);
+
    o->auto_styles = EINA_TRUE;
 
    return eo_obj;
@@ -11621,10 +11667,13 @@ _evas_textblock_changed(Efl_Canvas_Textblock_Data *o, Evas_Object *eo_obj)
    o->formatted.valid = 0;
    o->native.valid = 0;
    o->content_changed = 1;
-   if (o->markup_text)
+   if (!fit_is_fitting(eo_obj))
      {
-        eina_stringshare_del(o->markup_text);
-        o->markup_text = NULL;
+        if (o->markup_text)
+          {
+             eina_stringshare_del(o->markup_text);
+             o->markup_text = NULL;
+          }
      }
 
    // FIXME: emit ONCE after this following checks
@@ -11634,6 +11683,15 @@ _evas_textblock_changed(Efl_Canvas_Textblock_Data *o, Evas_Object *eo_obj)
         _cursor_emit_if_changed(data_obj);
      }
 
+   /*
+      If format changed we need to refit content again.
+      If content already fitting then ignore fitting (fitting cause fall to this callback)
+   */
+   if (!fit_is_fitting(eo_obj))
+     {
+        fit_cache_clear(&o->fit_content_config, FIT_CACHE_ALL);
+        fit_text_block(eo_obj);
+     }
    evas_object_change(eo_obj, obj);
 }
 
@@ -14990,6 +15048,11 @@ evas_object_textblock_free(Evas_Object *eo_obj)
 
    /* remove obstacles */
    _obstacles_free(eo_obj, o);
+   if (o->fit_content_config.p_size_array)
+     {
+        free(o->fit_content_config.p_size_array);
+        o->fit_content_config.p_size_array = NULL;
+     }
 
 #ifdef HAVE_HYPHEN
   /* Hyphenation */
@@ -16076,6 +16139,7 @@ _efl_canvas_textblock_efl_gfx_filter_filter_source_get(const Eo *obj EINA_UNUSED
    return eina_hash_find(pd->gfx_filter.sources, name);
 }
 
+
 static void
 evas_object_textblock_coords_recalc(Evas_Object *eo_obj,
                                     Evas_Object_Protected_Data *obj,
@@ -16133,6 +16197,17 @@ evas_object_textblock_coords_recalc(Evas_Object *eo_obj,
         o->formatted.valid = 0;
         o->changed = 1;
      }
+
+   Evas_Coord x,y,w,h;
+   evas_object_geometry_get(eo_obj, &x, &y, &w, &h);
+   if (
+       (w!=o->fit_content_config.last_size.w || h!=o->fit_content_config.last_size.h) &&
+       (o->fit_content_config.options & TEXTBLOCK_FIT_MODE_ALL) != TEXTBLOCK_FIT_MODE_NONE
+      )
+     {
+        fit_cache_clear(&o->fit_content_config, FIT_CACHE_INTERNAL_SIZE_ARRAY);
+        fit_text_block(eo_obj);
+     }
 }
 
 static void
@@ -16260,6 +16335,54 @@ done:
                                          eo_obj, is_v, was_v);
 }
 
+void fit_style_update(Evas_Object *object, int i_font_size, Eina_Bool disable_ellipsis, Eina_Bool disable_wrap)
+{
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(object, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+   memset(fc->fit_style,0,sizeof(fc->fit_style));
+   char * fit_style = fc->fit_style;
+   if (i_font_size >= 0)
+     {
+        char font_size[0xF] = {0};
+        char *pfont = font_size;
+        sprintf(font_size, "font_size=%i ", i_font_size);
+        while (*pfont)
+          {
+             *fit_style = *pfont;
+             pfont++;
+             fit_style++;
+          }
+     }
+
+   if (disable_ellipsis == EINA_TRUE)
+     {
+        *fit_style = ' ';
+        fit_style++;
+        char *p = "ellipsis=2.0";
+        while (*p)
+          {
+             *fit_style = *p;
+             p++;
+             fit_style++;
+          }
+     }
+
+   if (disable_wrap == EINA_TRUE)
+     {
+        *fit_style = ' ';
+        fit_style++;
+        char *p = "wrap=none";
+        while (*p)
+          {
+             *fit_style = *p;
+             p++;
+             fit_style++;
+          }
+     }
+
+  _canvas_text_format_changed(object,o);
+}
+
 static void
 evas_object_textblock_render_post(Evas_Object *eo_obj EINA_UNUSED,
                                   Evas_Object_Protected_Data *obj,
@@ -17752,6 +17875,371 @@ _efl_canvas_textblock_async_layout(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Textblock_
          NULL, ctx);
    return f;
 }
+/* Fitting Internal Functions*/
+
+int fit_cache_clear(TEXT_FIT_CONTENT_CONFIG *fc, unsigned int fit_cache_flags)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(fc, EVAS_ERROR_INVALID_PARAM);
+   if ((fit_cache_flags&FIT_CACHE_CANVAS_SIZE) == FIT_CACHE_CANVAS_SIZE)
+     fc->last_size = EINA_SIZE2D(0, 0);
+   if ((fit_cache_flags&FIT_CACHE_INTERNAL_SIZE_ARRAY) == FIT_CACHE_INTERNAL_SIZE_ARRAY)
+     for(int i = 0 ; i < 255 ; i++) fc->size_cache[i] = EINA_SIZE2D(0,0);
+   if ((fit_cache_flags&FIT_CACHE_FORCE_REFIT) == FIT_CACHE_FORCE_REFIT)
+     fc->force_refit = EINA_TRUE;
+   return EVAS_ERROR_SUCCESS;
+}
+
+int fit_start_fitting(Evas_Object *eo_obj)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(eo_obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
+   if (o->fit_in_progress == EINA_TRUE)
+     return EVAS_ERROR_INVALID_OPERATION;
+
+   o->fit_in_progress = EINA_TRUE;
+   return EVAS_ERROR_SUCCESS;
+}
+
+int fit_finish_fitting(Evas_Object *eo_obj)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(eo_obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
+   if (o->fit_in_progress == EINA_FALSE)
+     return EVAS_ERROR_INVALID_OPERATION;
+
+   o->fit_in_progress = EINA_FALSE;
+   return EVAS_ERROR_SUCCESS;
+}
+
+Eina_Bool fit_is_fitting(const Evas_Object *eo_obj)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(eo_obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
+   return o->fit_in_progress;
+}
+
+int fit_text_block(Evas_Object *eo_obj)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(eo_obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
+   Evas_Coord x,y,w,h;
+   Evas_Coord wf_new,hf_new;
+
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+
+   if (fc->options == TEXTBLOCK_FIT_MODE_NONE && !fc->force_refit)
+     return EVAS_ERROR_SUCCESS;
+
+
+   if (fc->options == TEXTBLOCK_FIT_MODE_NONE)
+     {
+        fit_start_fitting(eo_obj);
+        fc->force_refit = 0;
+        fit_style_update(eo_obj,-1, EINA_FALSE, EINA_FALSE);
+        fit_finish_fitting(eo_obj);
+        return EVAS_ERROR_SUCCESS;
+     }
+
+   evas_object_geometry_get(eo_obj, &x, &y, &w, &h);
+
+   if (w > 0 && h > 0)
+     {
+        Eina_Bool b_fit_width = ((fc->options & TEXTBLOCK_FIT_MODE_WIDTH) == TEXTBLOCK_FIT_MODE_WIDTH);
+        Eina_Bool b_fit_height = ((fc->options & TEXTBLOCK_FIT_MODE_HEIGHT) == TEXTBLOCK_FIT_MODE_HEIGHT);
+        //FIXME uncomment condition when style is not warp
+        if ( fc->force_refit || /*(w != fc->last_size.w && b_fit_width) || (h != fc->last_size.h && b_fit_height)*/ EINA_TRUE)
+          {
+             /* Extra Check to reduce recalculate */
+             Eina_Bool b_max_reached = (fc->last_size_index == ((int)fc->size_list_length) - 1);
+             Eina_Bool b_min_reached = (fc->last_size_index == 0);
+             /* 1 - If max font size reached and text block size increased*/
+             if (!fc->force_refit && b_max_reached && ((b_fit_width ? (w >= fc->last_size.w) : EINA_TRUE) && (b_fit_height ? (h >= fc->last_size.h) : EINA_TRUE)))
+               return EVAS_ERROR_SUCCESS;
+             /* 2- If min font size reached and text block size decreased*/
+             if (!fc->force_refit && b_min_reached && ((b_fit_width ? (w <= fc->last_size.w) : EINA_TRUE) && (b_fit_height ? (h <= fc->last_size.h) : EINA_TRUE)))
+               {
+                  /*This is needed to recalculate ellipsis, inside fitting to avoid losing markup_text*/
+                  fit_start_fitting(eo_obj);
+                  _canvas_text_format_changed(eo_obj, o);
+                  fit_finish_fitting(eo_obj);
+                  return EVAS_ERROR_SUCCESS;
+               }
+
+             fit_start_fitting(eo_obj);
+
+             fc->force_refit = EINA_FALSE;
+             fc->last_size.w = w;
+             fc->last_size.h = h;
+
+             int r = fc->size_list_length;
+             int l = 0;
+
+             Eina_Bool bwrap = EINA_FALSE;
+             if (fc->options == TEXTBLOCK_FIT_MODE_WIDTH)
+               {
+                  bwrap = EINA_TRUE;
+               }
+
+             while(r > l)
+               {
+                  int mid = (r + l) / 2;
+                  /*cache font sizes vaules from 0-255 in size_cache array*/
+                  size_t font_size = fc->p_size_array[mid];
+                  if (font_size <= 0xFF && (fc->size_cache[font_size].w != 0 && fc->size_cache[font_size].h != 0))
+                    {
+                        wf_new = fc->size_cache[font_size].w;
+                        hf_new = fc->size_cache[font_size].h;
+                    }
+                  else
+                    {
+                       fit_style_update(eo_obj,fc->p_size_array[mid],EINA_TRUE,bwrap);
+                       Eina_Size2D size = efl_canvas_textblock_size_formatted_get(eo_obj);
+                       wf_new = size.w;
+                       hf_new = size.h;
+                       if (fc->p_size_array[mid]<255)
+                         {
+                             fc->size_cache[font_size].w = wf_new;
+                             fc->size_cache[font_size].h = hf_new;
+                         }
+                    }
+
+                  if (
+                      ((wf_new > w) & ((fc->options & TEXTBLOCK_FIT_MODE_WIDTH) == TEXTBLOCK_FIT_MODE_WIDTH)) ||
+                      ((hf_new > h) & ((fc->options & TEXTBLOCK_FIT_MODE_HEIGHT) == TEXTBLOCK_FIT_MODE_HEIGHT)))
+                    {
+                       r = mid;
+                    }
+                  else
+                    {
+                       l = mid + 1;
+                    }
+                }
+
+                /*Lower bound founded, subtract one to move for nearest value*/
+                fc->last_size_index = MAX(l-1, 0);
+                fit_style_update(eo_obj,fc->p_size_array[fc->last_size_index],(fc->last_size_index != 0) && fc->options != TEXTBLOCK_FIT_MODE_HEIGHT ,EINA_FALSE);
+                fit_finish_fitting(eo_obj);
+          }
+     }
+   return EVAS_ERROR_SUCCESS;
+}
+
+int fit_fill_internal_list(TEXT_FIT_CONTENT_CONFIG *fc)
+{
+   int diff = (fc->max_font_size - fc->min_font_size);
+   if (fc->p_size_array)
+     {
+        free(fc->p_size_array);
+        fc->p_size_array = NULL;
+     }
+   if (diff == 0)
+     {
+        fc->size_list_length = 1;
+        fc->p_size_array = malloc(sizeof(unsigned int) * fc->size_list_length);
+        if (!fc->p_size_array)
+           return EVAS_ERROR_NO_MEMORY;
+        fc->p_size_array[0] = fc->max_font_size;
+        return EVAS_ERROR_SUCCESS;
+     }
+
+   fc->size_list_length = 2 + diff / MAX(fc->step_size, 1);
+   fc->p_size_array = malloc(sizeof(unsigned int) * fc->size_list_length);
+   if (!fc->p_size_array)
+     return EVAS_ERROR_NO_MEMORY;
+
+   size_t i ;
+   for (i = 0 ; i < fc->size_list_length - 1; i++)
+     {
+        fc->p_size_array[i] = fc->min_font_size + i * MAX(fc->step_size, 1);
+     }
+   fc->p_size_array[fc->size_list_length - 1] = fc->max_font_size;
+   fc->last_size_index = -1;
+   return EVAS_ERROR_SUCCESS;
+}
+
+
+
+EAPI int evas_textblock_fit_options_set(Evas_Object *obj,  unsigned int options)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+   if (fc->options == options)
+     return EVAS_ERROR_SUCCESS;
+
+   fc->options = options;
+   fit_cache_clear(fc, FIT_CACHE_ALL);
+   fit_text_block(obj);
+   return EVAS_ERROR_SUCCESS;
+}
+
+EAPI int evas_textblock_fit_options_get(const Evas_Object *obj,  unsigned int *p_options)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+   if (p_options)
+     *p_options = fc->options;
+   return EVAS_ERROR_SUCCESS;
+}
+
+EAPI int evas_textblock_fit_size_range_set(Evas_Object *obj,  unsigned int min_font_size, unsigned int max_font_size)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+
+   Eina_Bool max_changed = fc->max_font_size != max_font_size;
+   Eina_Bool min_changed = fc->min_font_size != min_font_size;
+
+   /* last_selected_size used for optimization calculations
+    * If last_size_index already recach last element in p_size_array
+    * Skip optimization by setting last_selected_size to -1
+   */
+   int last_selected_size = fc->last_size_index;
+   if (last_selected_size == ((int)fc->size_list_length-1))
+     last_selected_size = -1;
+
+   if (!max_changed && !min_changed)
+     return EVAS_ERROR_SUCCESS;
+
+   if (min_font_size < 0 || max_font_size <0)
+     return EVAS_ERROR_INVALID_PARAM;
+
+   if (max_font_size < min_font_size)
+     return EVAS_ERROR_INVALID_PARAM;
+
+   fc->max_font_size = max_font_size;
+   fc->min_font_size = min_font_size;
+
+   int n_ret = EVAS_ERROR_SUCCESS;
+   n_ret = fit_cache_clear(fc,FIT_CACHE_FORCE_REFIT);
+   if (n_ret) return n_ret;
+   n_ret = fit_fill_internal_list(fc);
+   if (n_ret) return n_ret;
+
+   /* Optimization to reduce calculations
+    * If only max size changed and last fit size index is still valid, then no need to recalculation
+    * Where changing max font size will not change content of p_size_array for sizes < max_size
+   */
+   if (min_changed || (last_selected_size == -1 || last_selected_size > ((int)fc->size_list_length-1)))
+     {
+        n_ret = fit_text_block(obj);
+        if (n_ret) return n_ret;
+     }
+   else
+     {
+        /* Keep fit size index */
+        fc->last_size_index = last_selected_size;
+     }
+   return EVAS_ERROR_SUCCESS;
+}
+
+EAPI int evas_textblock_fit_size_range_get(const Evas_Object *obj,  unsigned int *p_min_font_size, unsigned int *p_max_font_size)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+
+   if (p_min_font_size)
+     *p_min_font_size = fc->min_font_size;
+
+   if (p_max_font_size)
+     *p_max_font_size = fc->max_font_size;
+
+   return EVAS_ERROR_SUCCESS;
+}
+
+EAPI int evas_textblock_fit_step_size_set(Evas_Object *obj,  unsigned int step_size)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+   if (fc->step_size == step_size)
+     return EVAS_ERROR_SUCCESS;
+
+   if (step_size == 0)
+     return EVAS_ERROR_INVALID_PARAM;
+
+   fc->step_size = step_size;
+   int n_ret = EVAS_ERROR_SUCCESS;
+   n_ret = fit_cache_clear(fc, FIT_CACHE_FORCE_REFIT);
+   if (n_ret) return n_ret;
+   n_ret = fit_fill_internal_list(fc);
+   if (n_ret) return n_ret;
+   n_ret = fit_text_block(obj);
+   if (n_ret) return n_ret;
+   return EVAS_ERROR_SUCCESS;
+}
+
+EAPI int evas_textblock_fit_step_size_get(const Evas_Object *obj,  unsigned int * p_step_size)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+   if (p_step_size)
+     *p_step_size = fc->step_size;
+   return EVAS_ERROR_SUCCESS;
+}
+
+int compareUINT(const void * a, const void * b)
+{
+   unsigned int a_value = *(const unsigned int*)a;
+   unsigned int b_value = *(const unsigned int*)b;
+
+   if(a_value > b_value) return 1;
+   else if(a_value < b_value) return -1;
+   else return 0;
+}
+
+EAPI int evas_textblock_fit_size_array_set(Evas_Object *obj, const unsigned int *p_size_array, size_t size_array_len)
+{
+   int n_ret = EVAS_ERROR_SUCCESS;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+   if (size_array_len == 0)
+     return EVAS_ERROR_INVALID_PARAM;
+
+   if (fc->p_size_array)
+     {
+        free(fc->p_size_array);
+        fc->p_size_array = NULL;
+        fc->size_list_length = 0;
+     }
+
+   fc->p_size_array = malloc(sizeof(unsigned int) * size_array_len);
+   if (!fc->p_size_array) return EVAS_ERROR_NO_MEMORY;
+   memcpy(fc->p_size_array,p_size_array,sizeof(unsigned int) * size_array_len);
+   fc->size_list_length = size_array_len;
+
+   fc->last_size_index = -1;
+
+   qsort(fc->p_size_array,fc->size_list_length,sizeof(unsigned int),compareUINT);
+
+   n_ret = fit_cache_clear(fc, FIT_CACHE_FORCE_REFIT);
+   if (n_ret) return n_ret;
+   n_ret = fit_text_block(obj);
+   if (n_ret) return n_ret;
+   return EVAS_ERROR_SUCCESS;
+}
+
+EAPI int evas_textblock_fit_size_array_get(const Evas_Object *obj, unsigned int *p_size_array, size_t *p_size_array_len, size_t passed_array_size)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EVAS_ERROR_INVALID_PARAM);
+   Efl_Canvas_Textblock_Data *o = efl_data_scope_get(obj, MY_CLASS);
+   TEXT_FIT_CONTENT_CONFIG * fc = &o->fit_content_config;
+   if (p_size_array)
+     {
+        size_t num = MIN(passed_array_size,fc->size_list_length);
+        memcpy(p_size_array,fc->p_size_array,sizeof(unsigned int)* num);
+     }
+   if (p_size_array_len)
+     {
+        *p_size_array_len = fc->size_list_length;
+     }
+   return EVAS_ERROR_SUCCESS;
+}
 
 /*********************************************************************************
  * TIZEN_ONLY(20171110): Import TIZEN_ONLY functions for
index c2b3509..38744b4 100644 (file)
@@ -1074,6 +1074,105 @@ EAPI void evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur);
  */
 EAPI Evas_Textblock_Cursor *evas_object_textblock_cursor_get(const Evas_Object *obj);
 
+
+
+/* TEXT BLOCK FIT OPTIONS FLAGS*/
+#define TEXTBLOCK_FIT_MODE_NONE        0x0000
+#define TEXTBLOCK_FIT_MODE_WIDTH       0x0001
+#define TEXTBLOCK_FIT_MODE_HEIGHT      0x0002
+#define TEXTBLOCK_FIT_MODE_ALL         0x0003
+
+/* TEXT BLOCK ERROR CODES*/
+/* FIXME this hould go to other public place*/
+#define EVAS_ERROR_SUCCESS              0x0000
+#define EVAS_ERROR_INVALID_PARAM        0x0001
+#define EVAS_ERROR_NO_MEMORY            0x0002
+#define EVAS_ERROR_INVALID_OPERATION    0x0003
+
+
+/** Get the object's content it options.
+ *
+ * @param obj The textblock object.
+ * @param[out] options content fitting options.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_options_get(const Evas_Object *obj,  unsigned int * p_options);
+
+/** Set the object's content it options.
+ *
+ * @param obj The textblock object.
+ * @param[in] options content fitting options.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_options_set(Evas_Object *obj,  unsigned int options);
+
+/** Get the object's max and min font sizes used for fitting content.
+ *
+ * @param obj The textblock object.
+ * @param[out] p_min_font_size min font size used when fitting content.
+ * @param[out] p_max_font_size max font size used when fitting content.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_size_range_get(const Evas_Object *obj,  unsigned int *p_min_font_size, unsigned int *p_max_font_size);
+
+/** Set the object's max and min font sizes used for fitting content.
+ *
+ * @param obj The textblock object.
+ * @param[in] min_font_size min font size used when fitting content.
+ * @param[in] max_font_size max font size used when fitting content.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_size_range_set(Evas_Object *obj,  unsigned int min_font_size, unsigned int max_font_size);
+
+
+/** Get the object's fitting step size when trying fonts between min font size and
+ *  max font size.
+ *
+ * @param obj The textblock object.
+ * @param[out] p_step_size step jumps between min and max font size.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_step_size_get(const Evas_Object *obj,  unsigned int *p_step_size);
+
+
+/** Set the object's fitting step size when trying fonts between min font size and
+ *  max font size.
+ *
+ * @param obj The textblock object.
+ * @param[out] step_size step jumps between min and max font size.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_step_size_set(Evas_Object *obj,  unsigned int step_size);
+
+/** Get copy of the object's fitting font size array used internally
+ *
+ * @param obj The textblock object.
+ * @param[out] p_size_array pointer to size array (passing NULL will ignore filling array).
+ * @param[out] p_size_array_len the length of internall font sizes array.
+ * @param[out] request_size_array request to fill specific amount in p_size_array.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_size_array_get(const Evas_Object *obj,  unsigned int *p_size_array, size_t *p_size_array_len,size_t request_size_array);
+
+/** Set the object's fitting font size array that will be used internally
+ *  Changing fitting step_size,min_font_size,max_font size will generate new array
+ *  Internall array will be sorted
+ *
+ * @param obj The textblock object.
+ * @param[in] p_size_array pointer to font sizes array.
+ * @param[in] size_array_len the length passed font sizes array.
+ * @return Returns error code.
+ */
+EAPI int evas_textblock_fit_size_array_set(Evas_Object *obj,  const unsigned int *p_size_array, size_t size_array_len);
+
+
+
+
+
+
+
+
+
 #include "canvas/efl_canvas_textblock_eo.legacy.h"
 
 /* TIZEN_ONLY(20180709): fix build failure caused by missing legacy types */
index 786be4a..a450ebc 100644 (file)
@@ -4134,6 +4134,32 @@ EFL_START_TEST(evas_textblock_obstacle)
 }
 EFL_END_TEST;
 
+EFL_START_TEST(evas_textblock_fit)
+{
+   START_TB_TEST();
+   Evas_Coord fw, fh,fw_new, fh_new;
+   int n_ret;
+   const char *buf =
+      "This is an example text to demonstrate the textblock object"
+      " with content fit feature.";
+   evas_object_textblock_text_markup_set(tb, buf);
+   evas_object_resize(tb, 300, 300);
+   evas_object_textblock_size_formatted_get(tb, &fw, &fh);
+   n_ret = evas_textblock_fit_options_set(tb,TEXTBLOCK_FIT_MODE_ALL);
+   fail_if(n_ret != EVAS_ERROR_SUCCESS);
+   n_ret = evas_textblock_fit_size_range_set(tb,1,50);
+   fail_if(n_ret != EVAS_ERROR_SUCCESS);
+   evas_object_textblock_size_formatted_get(tb, &fw_new, &fh_new);
+   fail_if(fw_new == fw && fh_new == fh);
+   unsigned int size_array[3] = {150,200,250};
+   n_ret = evas_textblock_fit_size_array_set(tb,size_array,3);
+   fail_if(n_ret != EVAS_ERROR_SUCCESS);
+   evas_object_textblock_size_formatted_get(tb, &fw, &fh);
+   fail_if(fw_new == fw && fh_new == fh);
+   END_TB_TEST();
+}
+EFL_END_TEST;
+
 #ifdef HAVE_HYPHEN
 static void
 _hyphenation_width_stress(Evas_Object *tb, Evas_Textblock_Cursor *cur)
@@ -4654,6 +4680,7 @@ void evas_test_textblock(TCase *tc)
    tcase_add_test(tc, evas_textblock_items);
    tcase_add_test(tc, evas_textblock_delete);
    tcase_add_test(tc, evas_textblock_obstacle);
+   tcase_add_test(tc, evas_textblock_fit);
 #ifdef HAVE_HYPHEN
    tcase_add_test(tc, evas_textblock_hyphenation);
 #endif