cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=4a905a22a485388a5e4ba9fb25ff5ca381420ba7

commit 4a905a22a485388a5e4ba9fb25ff5ca381420ba7
Author: Daniel Hirt <hirt.da...@gmail.com>
Date:   Thu Nov 9 17:53:20 2017 +0200

    Canvas image: add Efl.Canvas.Text.Factory + use in Ui.Text
    
    This interface has a simple 'create' method to create Efl.Canvas.Object
    given a key.
    This is used higher-up in Ui.Text in the next commit.
    
    Ui text: add ability to set item factories
    
    Added API to set an item factory object.
    This is similar to the previous item providers (that worked with
    callbacks).
    
    You instantiate a factory object and set it on the Ui.Text object.
    Each factory implements the "create" method from
    Efl.Canvas.Text.Item_Factory.
    
    This also includes 3 public factories (Image, Emoticon and Fallback):
      - Image factory: creates images from added entries (key strings)
      - Emoticon factory: creates emoticons by querying the theme
      - Fallback: creates image, then falls back to emoticon
    
    If no factory is set, then the fallback (internal) factory is used.
    
    See the added "Ui.text Item Factory" test in elementary_test for an
    example of usage.
    
    @feature
---
 data/elementary/images/Makefile.am                 |   3 +-
 data/elementary/images/image_items.eet             | Bin 0 -> 573646 bytes
 src/Makefile_Elementary.am                         |   6 +
 src/Makefile_Evas.am                               |   1 +
 src/bin/elementary/test.c                          |   2 +
 src/bin/elementary/test_efl_ui_text.c              | 205 ++++++++++++++++++++-
 src/lib/efl/interfaces/efl_text_annotate.eo        |  61 +++---
 src/lib/elementary/Elementary.h                    |   3 +
 src/lib/elementary/efl_ui_text.c                   | 116 +++---------
 src/lib/elementary/efl_ui_text.eo                  |  41 +----
 src/lib/elementary/efl_ui_text_factory_emoticons.c |  52 ++++++
 .../elementary/efl_ui_text_factory_emoticons.eo    |  12 ++
 src/lib/elementary/efl_ui_text_factory_fallback.c  |  62 +++++++
 src/lib/elementary/efl_ui_text_factory_fallback.eo |  16 ++
 src/lib/elementary/efl_ui_text_factory_images.c    | 147 +++++++++++++++
 src/lib/elementary/efl_ui_text_factory_images.eo   |  69 +++++++
 src/lib/evas/Evas_Eo.h                             |   1 +
 src/lib/evas/canvas/efl_canvas_text.eo             |   7 +-
 src/lib/evas/canvas/efl_canvas_text_factory.eo     |  25 +++
 src/lib/evas/canvas/evas_object_textblock.c        |  31 +++-
 src/tests/evas/evas_test_textblock.c               |  12 +-
 21 files changed, 711 insertions(+), 161 deletions(-)

diff --git a/data/elementary/images/Makefile.am 
b/data/elementary/images/Makefile.am
index 6ecc178d52..6f028257cb 100644
--- a/data/elementary/images/Makefile.am
+++ b/data/elementary/images/Makefile.am
@@ -50,7 +50,8 @@ elementary_images_files = \
        elementary/images/pm_fill.png \
        elementary/images/pt.png \
        elementary/images/earth_normal.png \
-       elementary/images/space.png
+       elementary/images/space.png \
+       elementary/images/image_items.eet
 
 elementary_images_glayer_files = \
        elementary/images/g_layer/double_tap_1.png \
diff --git a/data/elementary/images/image_items.eet 
b/data/elementary/images/image_items.eet
new file mode 100644
index 0000000000..1db45dfaa3
Binary files /dev/null and b/data/elementary/images/image_items.eet differ
diff --git a/src/Makefile_Elementary.am b/src/Makefile_Elementary.am
index b080c61f87..86925ce943 100644
--- a/src/Makefile_Elementary.am
+++ b/src/Makefile_Elementary.am
@@ -45,6 +45,9 @@ elm_public_eolian_files = \
        lib/elementary/efl_ui_popup_anchor.eo \
        lib/elementary/efl_ui_text_editable.eo \
        lib/elementary/efl_ui_text_async.eo \
+       lib/elementary/efl_ui_text_factory_images.eo \
+       lib/elementary/efl_ui_text_factory_emoticons.eo \
+       lib/elementary/efl_ui_text_factory_fallback.eo \
        lib/elementary/efl_ui_textpath.eo \
        lib/elementary/efl_ui_translatable.eo \
        lib/elementary/efl_ui_clock.eo \
@@ -738,6 +741,9 @@ lib_elementary_libelementary_la_SOURCES = \
        lib/elementary/efl_ui_table_static.c \
        lib/elementary/efl_ui_table_private.h \
        lib/elementary/efl_ui_text.c \
+       lib/elementary/efl_ui_text_factory_images.c \
+       lib/elementary/efl_ui_text_factory_emoticons.c \
+       lib/elementary/efl_ui_text_factory_fallback.c \
        lib/elementary/efl_ui_clock.c \
        lib/elementary/efl_ui_clock_private.h \
        lib/elementary/efl_ui_image_factory.c \
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index 36298162a2..c26a978943 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -7,6 +7,7 @@ evas_canvas_eolian_pub_files = \
        lib/evas/canvas/efl_canvas_polygon.eo \
        lib/evas/canvas/efl_canvas_rectangle.eo \
        lib/evas/canvas/efl_canvas_text.eo \
+       lib/evas/canvas/efl_canvas_text_factory.eo \
        lib/evas/canvas/efl_canvas_group.eo \
        lib/evas/canvas/efl_canvas_image_internal.eo \
        lib/evas/canvas/evas_canvas3d_camera.eo\
diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c
index 1f75b930cb..0f7fdacfe3 100644
--- a/src/bin/elementary/test.c
+++ b/src/bin/elementary/test.c
@@ -333,6 +333,7 @@ void test_code_diff_inline(void *data, Evas_Object *obj, 
void *event_info);
 void test_efl_ui_text(void *data, Evas_Object *obj, void *event_info);
 void test_efl_ui_text_label(void *data, Evas_Object *obj, void *event_info);
 void test_efl_ui_text_async(void *data, Evas_Object *obj, void *event_info);
+void test_ui_text_item_factory(void *data, Evas_Object *obj, void *event_info);
 void test_evas_mask(void *data, Edje_Object *obj, void *event_info);
 void test_gfx_filters(void *data, Evas_Object *obj, void *event_info);
 void test_evas_snapshot(void *data, Evas_Object *obj, void *event_info);
@@ -834,6 +835,7 @@ add_tests:
    ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text", test_efl_ui_text);
    ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text Label", test_efl_ui_text_label);
    ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text.Async", test_efl_ui_text_async);
+   ADD_TEST_EO(NULL, "Entries", "Ui.Text Item Factory", 
test_ui_text_item_factory);
 
    //------------------------------//
    ADD_TEST(NULL, "Advanced Entries", "Code Syntax", test_code_syntax);
diff --git a/src/bin/elementary/test_efl_ui_text.c 
b/src/bin/elementary/test_efl_ui_text.c
index b53c427b9a..e28ba3bc64 100644
--- a/src/bin/elementary/test_efl_ui_text.c
+++ b/src/bin/elementary/test_efl_ui_text.c
@@ -144,8 +144,8 @@ static void
 my_efl_ui_text_bt_4(void *data, Evas_Object *obj EINA_UNUSED, void *event_info 
EINA_UNUSED)
 {
    Evas_Object *en = data;
-   efl_text_cursor_object_item_insert(en, efl_text_cursor_get(en, 
EFL_TEXT_CURSOR_GET_MAIN),
-         "size=32x32 href=emoticon/evil-laugh");
+   efl_text_cursor_item_insert(en, efl_text_cursor_get(en, 
EFL_TEXT_CURSOR_GET_MAIN),
+         "emoticon/evil-laugh", "size=32x32");
 }
 
 static void
@@ -187,6 +187,7 @@ test_efl_ui_text(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, void *eve
 {
    Evas_Object *win, *bx, *bx2, *bx3, *bt, *en;
    Efl_Text_Cursor_Cursor *main_cur, *cur;
+   char buf[128];
 
    win = elm_win_util_standard_add("entry", "Entry");
    elm_win_autodel_set(win, EINA_TRUE);
@@ -215,9 +216,10 @@ test_efl_ui_text(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, void *eve
    cur = efl_text_cursor_new(en);
 
    efl_text_cursor_position_set(en, cur, 2);
-   efl_text_cursor_object_item_insert(en, cur, "size=32x32 href=emoticon");
+   efl_text_cursor_item_insert(en, cur, "emoticon/happy", "size=32x32");
    efl_text_cursor_position_set(en, cur, 50);
-   efl_text_cursor_object_item_insert(en, cur, "size=32x32 href=emoticon");
+   sprintf(buf, "file://%s/images/sky_01.jpg", elm_app_data_dir_get());
+   efl_text_cursor_item_insert(en, cur, buf, "size=32x32");
 
    efl_text_cursor_position_set(en, main_cur, 5);
    efl_text_cursor_position_set(en, cur, 20);
@@ -297,7 +299,7 @@ test_efl_ui_text_async(void *data EINA_UNUSED, Evas_Object 
*obj EINA_UNUSED, voi
    elm_win_resize_object_add(win, bx);
    evas_object_show(bx);
 
-   en = efl_add(EFL_UI_TEXT_ASYNC_CLASS, win,
+   en = efl_add(EFL_UI_TEXT_CLASS, win,
          efl_text_wrap_set(efl_added, EFL_TEXT_FORMAT_WRAP_WORD),
          efl_text_multiline_set(efl_added, EINA_TRUE)
          );
@@ -332,3 +334,196 @@ test_efl_ui_text_async(void *data EINA_UNUSED, 
Evas_Object *obj EINA_UNUSED, voi
    evas_object_resize(win, 480, 320);
    evas_object_show(win);
 }
+
+#define IMAGES_SZ 5
+
+static const char *images[IMAGES_SZ] = {
+     "sky", "logo", "dog", "eet_rock", "eet_plant" };
+
+static void
+my_efl_ui_text_item_factory_bt_image(void *data, Evas_Object *obj EINA_UNUSED,
+      void *event_info EINA_UNUSED)
+{
+   Evas_Object *en = data;
+   static int image_idx = 0;
+
+   image_idx = (image_idx + 1) % IMAGES_SZ;
+   efl_text_cursor_item_insert(en,
+         efl_text_cursor_get(en, EFL_TEXT_CURSOR_GET_MAIN),
+         images[image_idx], "size=32x32");
+   printf("Inserted image: key = %s\n", images[image_idx]);
+}
+
+static void
+my_efl_ui_text_item_factory_bt_emoticon(void *data, Evas_Object *obj 
EINA_UNUSED,
+      void *event_info EINA_UNUSED)
+{
+   Evas_Object *en = data;
+   efl_text_cursor_item_insert(en, efl_text_cursor_get(en, 
EFL_TEXT_CURSOR_GET_MAIN),
+         "emoticon/evil-laugh", "size=32x32");
+}
+
+static struct
+{
+   const char *name;
+   Eo *item_factory;
+} factories[3];
+
+static void
+my_efl_ui_text_item_factory_bt_change(void *data, Evas_Object *obj EINA_UNUSED,
+      void *event_info EINA_UNUSED)
+{
+   Evas_Object *en = data;
+   static int item_factory_idx = 0;
+
+   item_factory_idx = (item_factory_idx + 1) % 3;
+   efl_ui_text_item_factory_set(en, factories[item_factory_idx].item_factory);
+   printf("Factory set to: %s\n", factories[item_factory_idx].name);
+}
+
+#define FACTORY_NONE     0
+#define FACTORY_IMAGE    1
+#define FACTORY_EMOTICON 2
+
+static void
+_ui_text_factory_del(void *data, const Efl_Event *ev EINA_UNUSED)
+{
+   Eina_File *f = data;
+   eina_file_close(f);
+   efl_del(factories[FACTORY_IMAGE].item_factory);
+   efl_del(factories[FACTORY_EMOTICON].item_factory);
+}
+
+void
+test_ui_text_item_factory(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   Evas_Object *win, *bx, *bx2, *bx3, *bt, *en;
+   Efl_Text_Cursor_Cursor *main_cur, *cur;
+   char buf[128];
+   Eina_File *f;
+
+   win = elm_win_util_standard_add("entry", "Entry");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   bx = elm_box_add(win);
+   evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, bx);
+   evas_object_show(bx);
+
+   en = efl_add(EFL_UI_TEXT_CLASS, win,
+         efl_text_multiline_set(efl_added, EINA_TRUE));
+
+   factories[FACTORY_NONE].name = "None (Fallback)";
+   factories[FACTORY_NONE].item_factory = NULL;
+
+   factories[FACTORY_IMAGE].name = "Image Factory";
+   factories[FACTORY_IMAGE].item_factory =
+      efl_add(EFL_UI_TEXT_FACTORY_IMAGES_CLASS, win);
+
+   factories[FACTORY_EMOTICON].name = "Emoticon Factory";
+   factories[FACTORY_EMOTICON].item_factory =
+      efl_add(EFL_UI_TEXT_FACTORY_EMOTICONS_CLASS, win);
+
+   // Test assigning file path source
+   sprintf(buf, "%s/images/sky_01.jpg", elm_app_data_dir_get());
+   
efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory,
+         images[0], buf, NULL);
+   sprintf(buf, "%s/images/logo.png", elm_app_data_dir_get());
+   
efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory,
+         images[1], buf, NULL);
+   sprintf(buf, "%s/images/mystrale.jpg", elm_app_data_dir_get());
+   
efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory,
+         images[2], buf, NULL);
+
+   // Open EET source w/ key
+   sprintf(buf, "%s/images/image_items.eet", elm_app_data_dir_get());
+   f = eina_file_open(buf, EINA_FALSE);
+   if (f)
+     {
+        efl_event_callback_add(en, EFL_EVENT_DEL, _ui_text_factory_del, f);
+
+        efl_ui_text_factory_images_matches_mmap_add(
+              factories[FACTORY_IMAGE].item_factory,
+              "eet_rock", f, "rock");
+        efl_ui_text_factory_images_matches_mmap_add(
+              factories[FACTORY_IMAGE].item_factory,
+              "eet_plant", f, "plant");
+     }
+   else
+     {
+        printf("Error loading test file. Please review test.");
+     }
+
+
+   printf("Added Efl.Ui.Text object\n");
+   efl_text_set(en, "Hello world! Goodbye world! This is a test text for the"
+         " new UI Text widget.\xE2\x80\xA9This is the next paragraph.\nThis"
+         " is the next line.\nThis is Yet another line! Line and paragraph"
+         " separators are actually different!");
+   efl_text_font_set(en, "Sans", 14);
+   efl_text_normal_color_set(en, 255, 255, 255, 255);
+
+   main_cur = efl_text_cursor_get(en, EFL_TEXT_CURSOR_GET_MAIN);
+   cur = efl_text_cursor_new(en);
+
+   efl_text_cursor_position_set(en, cur, 2);
+   efl_text_cursor_item_insert(en, cur, "emoticon/happy", "size=32x32");
+   efl_text_cursor_position_set(en, cur, 50);
+
+   sprintf(buf, "file://%s/images/sky_01.jpg", elm_app_data_dir_get());
+   efl_text_cursor_item_insert(en, cur, buf, "size=32x32");
+   efl_text_cursor_position_set(en, main_cur, 5);
+
+   efl_ui_text_interactive_editable_set(en, EINA_TRUE);
+   efl_ui_text_scrollable_set(en, EINA_TRUE);
+   elm_box_pack_end(bx, en);
+   elm_object_focus_set(en, EINA_TRUE);
+
+   bx2 = elm_box_add(win);
+   elm_box_horizontal_set(bx2, EINA_TRUE);
+   evas_object_size_hint_weight_set(bx2, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(bx2, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   bt = elm_button_add(win);
+   elm_object_text_set(bt, "Image");
+   evas_object_smart_callback_add(bt, "clicked",
+         my_efl_ui_text_item_factory_bt_image, en);
+   evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
+   elm_box_pack_end(bx2, bt);
+   elm_object_focus_allow_set(bt, EINA_FALSE);
+   evas_object_show(bt);
+
+   bt = elm_button_add(win);
+   elm_object_text_set(bt, "Emoticon");
+   evas_object_smart_callback_add(bt, "clicked",
+         my_efl_ui_text_item_factory_bt_emoticon, en);
+   evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
+   elm_box_pack_end(bx2, bt);
+   elm_object_focus_allow_set(bt, EINA_FALSE);
+   evas_object_show(bt);
+
+   bt = elm_button_add(win);
+   elm_object_text_set(bt, "Factory");
+   evas_object_smart_callback_add(bt, "clicked",
+         my_efl_ui_text_item_factory_bt_change, en);
+   evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
+   elm_box_pack_end(bx2, bt);
+   elm_object_focus_allow_set(bt, EINA_FALSE);
+   evas_object_show(bt);
+
+   bx3 = elm_box_add(win);
+   elm_box_horizontal_set(bx3, EINA_TRUE);
+   evas_object_size_hint_weight_set(bx3, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(bx3, EVAS_HINT_FILL, EVAS_HINT_FILL);
+
+   elm_box_pack_end(bx, bx3);
+   elm_box_pack_end(bx, bx2);
+   evas_object_show(bx3);
+   evas_object_show(bx2);
+
+   evas_object_resize(win, 480, 320);
+   evas_object_show(win);
+}
diff --git a/src/lib/efl/interfaces/efl_text_annotate.eo 
b/src/lib/efl/interfaces/efl_text_annotate.eo
index 002505356c..7826d07991 100644
--- a/src/lib/efl/interfaces/efl_text_annotate.eo
+++ b/src/lib/efl/interfaces/efl_text_annotate.eo
@@ -76,23 +76,6 @@ interface Efl.Text.Annotate {
          }
          return: bool; [[$true on success, $false otherwise.]]
       }
-      object_item_geometry_get {
-         [[Queries a given object item for its geometry.
-
-           Note that the provided annotation should be an object item type.
-
-           @since 1.18
-         ]]
-         legacy: null;
-         params {
-            @in an: ptr(const(Efl.Text.Annotate.Annotation)); [[Given 
annotation to query]]
-            @out x: int; [[X coordinate of the annotation]]
-            @out y: int; [[Y coordinate of the annotation]]
-            @out w: int; [[Width of the annotation]]
-            @out h: int; [[Height of the annotation]]
-         }
-         return: bool; [[$true if given annotation is an object item, $false 
otherwise]]
-      }
       annotation_positions_get {
          [[Sets given cursors to the start and end positions of the annotation.
 
@@ -111,8 +94,41 @@ interface Efl.Text.Annotate {
              position of the annotation in the text]]
          }
       }
+      annotation_is_item {
+         [[Whether this is an "item" type of annotation. Should be used before
+           querying the annotation's geometry, as only "item" annotations have
+           a geometry.
+
+           see @.cursor_item_insert
+           see @.item_geometry_get
+
+           @since 1.21
+         ]]
+         legacy: null;
+         params {
+            annotation: ptr(Efl.Text.Annotate.Annotation); [[Given annotation]]
+         }
+         return: bool; [[$true if given annotation is an object item, $false 
otherwise]]
+      }
+      item_geometry_get {
+         [[Queries a given object item for its geometry.
+
+           Note that the provided annotation should be an object item type.
+
+           @since 1.18
+         ]]
+         legacy: null;
+         params {
+            @in an: ptr(const(Efl.Text.Annotate.Annotation)); [[Given 
annotation to query]]
+            @out x: int; [[X coordinate of the annotation]]
+            @out y: int; [[Y coordinate of the annotation]]
+            @out w: int; [[Width of the annotation]]
+            @out h: int; [[Height of the annotation]]
+         }
+         return: bool; [[$true if given annotation is an object item, $false 
otherwise]]
+      }
       // Cursor
-      @property cursor_object_item_annotation {
+      @property cursor_item_annotation {
          [[The object-item annotation at the cursor's position.]]
          get {
             legacy: null;
@@ -124,7 +140,7 @@ interface Efl.Text.Annotate {
             cur: ptr(Efl.Text.Cursor.Cursor); [[Cursor object]]
          }
       }
-      cursor_object_item_insert {
+      cursor_item_insert {
          [[Inserts a object item at specified position.
 
            This adds a placeholder to be queried by higher-level code,
@@ -134,8 +150,11 @@ interface Efl.Text.Annotate {
          legacy: null;
          params {
             cur: ptr(Efl.Text.Cursor.Cursor); [[Cursor object]]
-            @in format: string; [[Format of the inserted item.
-            See Format styles.]]
+            @in item: string;   [[Item key to be used in higher-up
+                                  code to query and decided what image, 
emoticon
+                                  etc. to embed.]]
+            @in format: string; [[Size format of the inserted item.
+                                  This hints how to size the item in the 
text.]]
          }
          return: ptr(Efl.Text.Annotate.Annotation); [[The annotation handle of 
the
          inserted item.]]
diff --git a/src/lib/elementary/Elementary.h b/src/lib/elementary/Elementary.h
index a16e3f8a0f..0880126512 100644
--- a/src/lib/elementary/Elementary.h
+++ b/src/lib/elementary/Elementary.h
@@ -311,6 +311,9 @@ typedef Eo Efl_Ui_Focus_Manager;
 # include <efl_ui_popup_alert_scroll.eo.h>
 # include <efl_ui_popup_alert_text.eo.h>
 # include <efl_ui_popup_anchor.eo.h>
+# include <efl_ui_text_factory_images.eo.h>
+# include <efl_ui_text_factory_emoticons.eo.h>
+# include <efl_ui_text_factory_fallback.eo.h>
 # include <efl_ui_text_editable.eo.h>
 # include <efl_ui_text_async.eo.h>
 # include <efl_ui_clock.eo.h>
diff --git a/src/lib/elementary/efl_ui_text.c b/src/lib/elementary/efl_ui_text.c
index ed4f5d1718..ae74e5c42a 100644
--- a/src/lib/elementary/efl_ui_text.c
+++ b/src/lib/elementary/efl_ui_text.c
@@ -63,7 +63,8 @@ struct _Efl_Ui_Text_Data
    Eina_List                            *sel;
    Eina_List                            *items; /** context menu item list */
    Item_Obj                             *item_objs;
-   Eina_List                            *item_providers;
+   Efl_Canvas_Text_Factory              *item_factory;
+   Efl_Canvas_Text_Factory              *item_fallback_factory;
    Eina_List                            *markup_filters;
    Ecore_Job                            *hov_deljob;
    Mod_Api                              *api; // module api if supplied
@@ -131,6 +132,7 @@ struct _Efl_Ui_Text_Data
    Eina_Bool                             scroll : 1;
    Eina_Bool                             input_panel_show_on_demand : 1;
    Eina_Bool                             anchors_updated : 1;
+   Eina_Bool                             fallback_item_provider_disabled : 1;
 };
 
 struct _Anchor
@@ -2485,43 +2487,22 @@ _entry_mouse_triple_signal_cb(void *data,
 static Evas_Object *
 _item_get(void *data, const char *item)
 {
-   Eina_List *l;
-   Evas_Object *o;
-   Elm_Entry_Item_Provider *ip;
-   const char *style = elm_widget_style_get(data);
+   Evas_Object *o = NULL;
 
    EFL_UI_TEXT_DATA_GET(data, sd);
 
-   EINA_LIST_FOREACH(sd->item_providers, l, ip)
-     {
-        o = ip->func(ip->data, data, item);
-        if (o) return o;
-     }
-   if (item && !strncmp(item, "file://", 7))
+   if (item)
      {
-        const char *fname = item + 7;
-
-        o = evas_object_image_filled_add(evas_object_evas_get(data));
-        evas_object_image_file_set(o, fname, NULL);
-        if (evas_object_image_load_error_get(o) == EVAS_LOAD_ERROR_NONE)
+        if (sd->item_factory)
           {
-             evas_object_show(o);
+             o = efl_canvas_text_factory_create(sd->item_factory, data, item);
           }
-        else
+        else if (sd->item_fallback_factory)
           {
-             evas_object_del(o);
-             o = edje_object_add(evas_object_evas_get(data));
-             elm_widget_theme_object_set
-               (data, o, "text/emoticon", "wtf", style);
+             o = efl_canvas_text_factory_create(sd->item_fallback_factory,
+                   data, item);
           }
-        return o;
      }
-
-   o = edje_object_add(evas_object_evas_get(data));
-   if (!elm_widget_theme_object_set
-         (data, o, "text", item, style))
-     elm_widget_theme_object_set
-       (data, o, "text/emoticon", "wtf", style);
    return o;
 }
 
@@ -3215,6 +3196,7 @@ _efl_ui_text_efl_object_constructor(Eo *obj, 
Efl_Ui_Text_Data *sd)
    if (_elm_config->desktop_entry)
      sd->sel_handler_disabled = EINA_TRUE;
 
+   sd->item_fallback_factory = efl_add(EFL_UI_TEXT_FACTORY_FALLBACK_CLASS, 
obj);
    _create_text_cursors(obj, sd);
 
    return obj;
@@ -3224,7 +3206,6 @@ EOLIAN static void
 _efl_ui_text_efl_object_destructor(Eo *obj, Efl_Ui_Text_Data *sd)
 {
    Elm_Entry_Context_Menu_Item *it;
-   Elm_Entry_Item_Provider *ip;
    Elm_Entry_Markup_Filter *tf;
    Eo *text_obj;
 
@@ -3270,10 +3251,6 @@ _efl_ui_text_efl_object_destructor(Eo *obj, 
Efl_Ui_Text_Data *sd)
         eina_stringshare_del(it->icon_group);
         free(it);
      }
-   EINA_LIST_FREE(sd->item_providers, ip)
-     {
-        free(ip);
-     }
    EINA_LIST_FREE(sd->markup_filters, tf)
      {
         _filter_free(tf);
@@ -3314,6 +3291,9 @@ _efl_ui_text_efl_object_destructor(Eo *obj, 
Efl_Ui_Text_Data *sd)
    ecore_job_del(sd->deferred_decoration_job);
    sd->deferred_decoration_job = NULL;
 
+   if (sd->item_factory) efl_unref(sd->item_factory);
+   if (sd->item_fallback_factory) efl_del(sd->item_fallback_factory);
+
    efl_destructor(efl_super(obj, MY_CLASS));
 }
 
@@ -3539,55 +3519,6 @@ _efl_ui_text_context_menu_disabled_get(Eo *obj 
EINA_UNUSED, Efl_Ui_Text_Data *sd
    return !sd->context_menu;
 }
 
-EOLIAN static void
-_efl_ui_text_item_provider_append(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *sd, 
Elm_Entry_Item_Provider_Cb func, void *data)
-{
-   Elm_Entry_Item_Provider *ip;
-
-   EINA_SAFETY_ON_NULL_RETURN(func);
-
-   ip = calloc(1, sizeof(Elm_Entry_Item_Provider));
-   if (!ip) return;
-
-   ip->func = func;
-   ip->data = data;
-   sd->item_providers = eina_list_append(sd->item_providers, ip);
-}
-
-EOLIAN static void
-_efl_ui_text_item_provider_prepend(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *sd, 
Elm_Entry_Item_Provider_Cb func, void *data)
-{
-   Elm_Entry_Item_Provider *ip;
-
-   EINA_SAFETY_ON_NULL_RETURN(func);
-
-   ip = calloc(1, sizeof(Elm_Entry_Item_Provider));
-   if (!ip) return;
-
-   ip->func = func;
-   ip->data = data;
-   sd->item_providers = eina_list_prepend(sd->item_providers, ip);
-}
-
-EOLIAN static void
-_efl_ui_text_item_provider_remove(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *sd, 
Elm_Entry_Item_Provider_Cb func, void *data)
-{
-   Eina_List *l;
-   Elm_Entry_Item_Provider *ip;
-
-   EINA_SAFETY_ON_NULL_RETURN(func);
-
-   EINA_LIST_FOREACH(sd->item_providers, l, ip)
-     {
-        if ((ip->func == func) && ((!data) || (ip->data == data)))
-          {
-             sd->item_providers = eina_list_remove_list(sd->item_providers, l);
-             free(ip);
-             return;
-          }
-     }
-}
-
 EOLIAN static Eina_Bool
 _efl_ui_text_efl_file_file_set(Eo *obj, Efl_Ui_Text_Data *sd, const char 
*file, const char *group EINA_UNUSED)
 {
@@ -4927,8 +4858,7 @@ _anchors_create(Eo *obj, Efl_Ui_Text_Data *sd)
         Eina_Bool is_anchor = EINA_FALSE;
         Eina_Bool is_item = EINA_FALSE;
 
-        if (efl_text_object_item_geometry_get(obj, anchor,
-                 NULL, NULL, NULL, NULL))
+        if (efl_text_annotation_is_item(obj, anchor))
           {
              is_anchor = EINA_TRUE;
              is_item = EINA_TRUE;
@@ -5052,7 +4982,7 @@ _anchors_update(Eo *o, Efl_Ui_Text_Data *sd)
                     {
                        rect->obj = ob;
 
-                       efl_text_object_item_geometry_get(an->obj,
+                       efl_text_item_geometry_get(an->obj,
                              an->annotation, &cx, &cy, &cw, &ch);
                        evas_object_move(rect->obj, x + cx, y + cy);
                        evas_object_resize(rect->obj, cw, ch);
@@ -5296,6 +5226,20 @@ _efl_ui_text_move_cb(void *data, Evas *e EINA_UNUSED,
    _decoration_defer_all(data);
 }
 
+static void
+_efl_ui_text_item_factory_set(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *pd,
+      Efl_Canvas_Text_Factory *item_factory)
+{
+   if (pd->item_factory) efl_unref(pd->item_factory);
+   pd->item_factory = efl_ref(item_factory);
+}
+
+static Eo *
+_efl_ui_text_item_factory_get(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *pd)
+{
+   return pd->item_factory;
+}
+
 #if 0
 /* Efl.Part begin */
 
diff --git a/src/lib/elementary/efl_ui_text.eo 
b/src/lib/elementary/efl_ui_text.eo
index 341a951679..515fc0dfda 100644
--- a/src/lib/elementary/efl_ui_text.eo
+++ b/src/lib/elementary/efl_ui_text.eo
@@ -233,13 +233,12 @@ class Efl.Ui.Text (Efl.Ui.Layout, 
Elm.Interface_Scrollable, Efl.Ui.Clickable,
             enabled: bool; [[If $enabled is $true, the return key is 
automatically disabled when the entry has no text.]]
          }
       }
-      item_provider_prepend {
-         [[This prepends a custom item provider to the list for that entry
-
-           This prepends the given callback.]]
-         params {
-            @in func: Elm_Entry_Item_Provider_Cb; [[The function called to 
provide the item object.]]
-            @in data: void_ptr @optional; [[The data passed to $func.]]
+      @property item_factory {
+         [[The factory that provides item in the text e.g.
+           "emoticon/happy" or "href=file://image.jpg" etc.
+         ]]
+         values {
+            item_factory: Efl.Canvas.Text.Factory; [[Factory to create items]]
          }
       }
       input_panel_show {
@@ -252,17 +251,6 @@ class Efl.Ui.Text (Efl.Ui.Layout, 
Elm.Interface_Scrollable, Efl.Ui.Clickable,
       selection_copy {
          [[This executes a "copy" action on the selected text in the entry.]]
       }
-      item_provider_remove {
-         [[This removes a custom item provider to the list for that entry
-
-           This removes the given callback. See @.item_provider_append for
-           more information
-         ]]
-         params {
-            @in func: Elm_Entry_Item_Provider_Cb; [[The function called to 
provide the item object.]]
-            @in data: void_ptr @optional; [[The data passed to $func.]]
-         }
-      }
       context_menu_clear {
          [[This clears and frees the items in a entry's contextual (longpress)
            menu.
@@ -306,23 +294,6 @@ class Efl.Ui.Text (Efl.Ui.Layout, 
Elm.Interface_Scrollable, Efl.Ui.Clickable,
       selection_cut {
          [[This executes a "cut" action on the selected text in the entry.]]
       }
-      item_provider_append {
-         [[This appends a custom item provider to the list for that entry
-
-           This appends the given callback. The list is walked from beginning 
to end
-           with each function called given the item href string in the text. 
If the
-           function returns an object handle other than $null (it should 
create an
-           object to do this), then this object is used to replace that item. 
If
-           not the next provider is called until one provides an item object, 
or the
-           default provider in entry does.
-
-           See also \@ref entry-items.
-         ]]
-         params {
-            @in func: Elm_Entry_Item_Provider_Cb; [[The function called to 
provide the item object.]]
-            @in data: void_ptr @optional; [[The data passed to $func.]]
-         }
-      }
       context_menu_item_add {
          [[This adds an item to the entry's contextual menu.
 
diff --git a/src/lib/elementary/efl_ui_text_factory_emoticons.c 
b/src/lib/elementary/efl_ui_text_factory_emoticons.c
new file mode 100644
index 0000000000..55818af33d
--- /dev/null
+++ b/src/lib/elementary/efl_ui_text_factory_emoticons.c
@@ -0,0 +1,52 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include <Elementary_Cursor.h>
+#include "elm_priv.h"
+
+#define MY_CLASS EFL_UI_TEXT_FACTORY_EMOTICONS_CLASS
+
+typedef struct _Efl_Ui_Text_Factory_Emoticons_Data 
Efl_Ui_Text_Factory_Emoticons_Data;
+
+struct _Efl_Ui_Text_Factory_Emoticons_Data
+{
+   const char *name;
+};
+
+EOLIAN static Eo *
+_efl_ui_text_factory_emoticons_efl_object_constructor(Eo *obj,
+     Efl_Ui_Text_Factory_Emoticons_Data *pd EINA_UNUSED)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   return obj;
+}
+
+EOLIAN static void
+_efl_ui_text_factory_emoticons_efl_object_destructor(Eo *obj,
+     Efl_Ui_Text_Factory_Emoticons_Data *pd EINA_UNUSED)
+{
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+
+EOLIAN static Efl_Canvas_Object
+*_efl_ui_text_factory_emoticons_efl_canvas_text_factory_create(
+      Eo *obj EINA_UNUSED,
+      Efl_Ui_Text_Factory_Emoticons_Data *pd EINA_UNUSED,
+      Efl_Canvas_Object *object,
+      const char *key)
+{
+   Eo *o;
+   const char *style = elm_widget_style_get(object);
+
+   o = edje_object_add(evas_object_evas_get(object));
+   if (!_elm_theme_object_set
+         (object, o, "text", key, style))
+     _elm_theme_object_set
+       (object, o, "text/emoticon", "wtf", style);
+   return o;
+}
+
+#include "efl_ui_text_factory_emoticons.eo.c"
diff --git a/src/lib/elementary/efl_ui_text_factory_emoticons.eo 
b/src/lib/elementary/efl_ui_text_factory_emoticons.eo
new file mode 100644
index 0000000000..38269ea7d5
--- /dev/null
+++ b/src/lib/elementary/efl_ui_text_factory_emoticons.eo
@@ -0,0 +1,12 @@
+class Efl.Ui.Text.Factory.Emoticons (Efl.Object, Efl.Canvas.Text.Factory)
+{
+   [[Factory that creates emoticons from the current theme given a key.
+
+     @since 1.21
+   ]]
+   implements {
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+      Efl.Canvas.Text.Factory.create;
+   }
+}
diff --git a/src/lib/elementary/efl_ui_text_factory_fallback.c 
b/src/lib/elementary/efl_ui_text_factory_fallback.c
new file mode 100644
index 0000000000..4ee456e1e0
--- /dev/null
+++ b/src/lib/elementary/efl_ui_text_factory_fallback.c
@@ -0,0 +1,62 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include <Elementary_Cursor.h>
+#include "elm_priv.h"
+
+#define MY_CLASS EFL_UI_TEXT_FACTORY_FALLBACK_CLASS
+
+typedef struct _Efl_Ui_Text_Factory_Fallback_Data 
Efl_Ui_Text_Factory_Fallback_Data;
+
+struct _Efl_Ui_Text_Factory_Fallback_Data
+{
+   Efl_Canvas_Text_Factory *emoticon_factory, *image_factory;
+};
+
+EOLIAN static Eo *
+_efl_ui_text_factory_fallback_efl_object_constructor(Eo *obj,
+     Efl_Ui_Text_Factory_Fallback_Data *pd EINA_UNUSED)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   pd->image_factory = efl_add(EFL_UI_TEXT_FACTORY_IMAGES_CLASS, obj);
+   pd->emoticon_factory = efl_add(EFL_UI_TEXT_FACTORY_EMOTICONS_CLASS, obj);
+   return obj;
+}
+
+EOLIAN static void
+_efl_ui_text_factory_fallback_efl_object_destructor(Eo *obj,
+     Efl_Ui_Text_Factory_Fallback_Data *pd EINA_UNUSED)
+{
+   efl_del(pd->emoticon_factory);
+   efl_del(pd->image_factory);
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+
+EOLIAN static Efl_Canvas_Object
+*_efl_ui_text_factory_fallback_efl_canvas_text_factory_create(
+      Eo *obj EINA_UNUSED,
+      Efl_Ui_Text_Factory_Fallback_Data *pd EINA_UNUSED,
+      Efl_Canvas_Object *object,
+      const char *key)
+{
+   Efl_Canvas_Object *o = NULL;
+
+   // Parse the string. Can be either:
+   //   1. some/name - an emoticon (load from theme)
+   //   2. file:// - image file
+   if (key && !strncmp(key, "file://", 7))
+     {
+        const char *fname = key + 7;
+        o = efl_canvas_text_factory_create(pd->image_factory, object, fname);
+     }
+   else
+     {
+        o = efl_canvas_text_factory_create(pd->emoticon_factory, object, key);
+     }
+   return o;
+}
+
+#include "efl_ui_text_factory_fallback.eo.c"
diff --git a/src/lib/elementary/efl_ui_text_factory_fallback.eo 
b/src/lib/elementary/efl_ui_text_factory_fallback.eo
new file mode 100644
index 0000000000..830fa5b637
--- /dev/null
+++ b/src/lib/elementary/efl_ui_text_factory_fallback.eo
@@ -0,0 +1,16 @@
+class Efl.Ui.Text.Factory.Fallback (Efl.Object, Efl.Canvas.Text.Factory)
+{
+   [[Internal factory for fallback cases.
+
+     This wraps some internal functionality:
+       - Contains 2 factories: image and emoticon
+       - Strips off "file://" prefix for image items, to be used with the image
+         factory.
+     @since 1.21
+   ]]
+   implements {
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+      Efl.Canvas.Text.Factory.create;
+   }
+}
diff --git a/src/lib/elementary/efl_ui_text_factory_images.c 
b/src/lib/elementary/efl_ui_text_factory_images.c
new file mode 100644
index 0000000000..91325f15b2
--- /dev/null
+++ b/src/lib/elementary/efl_ui_text_factory_images.c
@@ -0,0 +1,147 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+
+#include <Elementary.h>
+#include <Elementary_Cursor.h>
+#include "elm_priv.h"
+
+#define MY_CLASS EFL_UI_TEXT_FACTORY_IMAGES_CLASS
+
+typedef struct _Efl_Ui_Text_Factory_Images_Data 
Efl_Ui_Text_Factory_Images_Data;
+
+struct _Efl_Ui_Text_Factory_Images_Data
+{
+   const char *name;
+   Eina_Hash  *hash;
+};
+
+typedef struct
+{
+   Eina_File  *file;
+   const char *key;
+} File_Entry;
+
+static void
+_entry_free_cb(void *data)
+{
+   File_Entry *e = data;
+   eina_file_close(e->file);
+   eina_stringshare_del(e->key);
+   free(e);
+}
+
+EOLIAN static Eo *
+_efl_ui_text_factory_images_efl_object_constructor(Eo *obj,
+     Efl_Ui_Text_Factory_Images_Data *pd EINA_UNUSED)
+{
+   obj = efl_constructor(efl_super(obj, MY_CLASS));
+   pd->hash = eina_hash_string_superfast_new(_entry_free_cb);
+   return obj;
+}
+
+EOLIAN static void
+_efl_ui_text_factory_images_efl_object_destructor(Eo *obj,
+     Efl_Ui_Text_Factory_Images_Data *pd EINA_UNUSED)
+{
+   eina_hash_free(pd->hash);
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+EOLIAN static Efl_Canvas_Object *
+_efl_ui_text_factory_images_efl_canvas_text_factory_create(Eo *obj EINA_UNUSED,
+      Efl_Ui_Text_Factory_Images_Data *pd EINA_UNUSED,
+      Efl_Canvas_Object *object,
+      const char *key)
+{
+   Efl_Canvas_Object *o;
+   File_Entry *e;
+
+   o = efl_add(EFL_CANVAS_IMAGE_CLASS, object);
+   e = eina_hash_find(pd->hash, key);
+   if (e)
+     {
+        efl_file_mmap_set(o, e->file, e->key);
+     }
+   else
+     {
+        efl_file_set(o, key, NULL);
+     }
+
+   if (efl_file_load_error_get(o) != EFL_IMAGE_LOAD_ERROR_NONE)
+     {
+        efl_del(o);
+        o = NULL;
+     }
+
+   return o;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_text_factory_images_matches_add(Eo *obj EINA_UNUSED,
+      Efl_Ui_Text_Factory_Images_Data *pd,
+      const char *name, const char *file, const char *key)
+{
+   File_Entry *e;
+   Eina_File *f = eina_file_open(file, EINA_FALSE);
+
+   if (!f) return EINA_FALSE;
+
+   e = malloc(sizeof(*e));
+   e->file = f;
+   e->key = eina_stringshare_add(key);
+
+   if (!eina_hash_add(pd->hash, name, e))
+     {
+        ERR("Failed to add file path %s to key %s\n", file, key);
+        eina_file_close(f);
+        free(e);
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_text_factory_images_matches_del(Eo *obj EINA_UNUSED,
+      Efl_Ui_Text_Factory_Images_Data *pd,
+      const char *name)
+{
+   return eina_hash_del(pd->hash, name, NULL);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_text_factory_images_matches_mmap_add(Eo *obj EINA_UNUSED,
+      Efl_Ui_Text_Factory_Images_Data *pd,
+      const char *name, const Eina_File *file, const char *key)
+{
+   File_Entry *e;
+   Eina_File *f;
+
+   if (!file) return EINA_FALSE;
+
+   f = eina_file_dup(file);
+   e = malloc(sizeof(*e));
+   e->file = f;
+   e->key = eina_stringshare_add(key);
+
+   if (!eina_hash_add(pd->hash, name, e))
+     {
+        ERR("Failed to add Eina_File %p to key %s\n", file, key);
+        eina_file_close(f);
+        free(e);
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_text_factory_images_matches_mmap_del(Eo *obj EINA_UNUSED,
+      Efl_Ui_Text_Factory_Images_Data *pd,
+      const char *name)
+{
+   return eina_hash_del(pd->hash, name, NULL);
+}
+
+#include "efl_ui_text_factory_images.eo.c"
diff --git a/src/lib/elementary/efl_ui_text_factory_images.eo 
b/src/lib/elementary/efl_ui_text_factory_images.eo
new file mode 100644
index 0000000000..d682e294a7
--- /dev/null
+++ b/src/lib/elementary/efl_ui_text_factory_images.eo
@@ -0,0 +1,69 @@
+class Efl.Ui.Text.Factory.Images (Efl.Object, Efl.Canvas.Text.Factory)
+{
+   [[Factory that creates images given key string
+
+     The key can be either a full image path, or associated with one. The
+     factory will fallback if key was not matches with an image, and try
+     to load it as a full path.
+
+     @since 1.21
+   ]]
+   methods {
+      matches_add {
+         [[Associates given name with a path of an image or EET file.
+
+          This can be used for quick retrieval (instead of
+          providing actual filenames.
+
+          This $file is associated with $name is considered a full file path.
+
+          see @.matches_mmap_add for mmap version
+          see @.matches_del
+         ]]
+         params {
+            name: string; [[the name associated with filename]]
+            path: string; [[the image or EET file path]]
+            key: string; [[the key to use (in cases of loading an EET file]]
+         }
+         return: bool; [[$true if successful, $false otherwise]]
+      }
+      matches_del {
+         [[Deletes an association of $key with its respective file path.
+
+          see @.matches_add
+         ]]
+         params {
+            key: string; [[the entry's key to delete]]
+         }
+         return: bool; [[$true if successful, $false otherwise]]
+      }
+      matches_mmap_add {
+         [[Associates given name with a mmap'd image or EET file and key.
+
+          see @.matches_add for string file path version
+          see @.matches_mmap_del
+         ]]
+         params {
+            name: string; [[the name associated with filename]]
+            file: ptr(const(Eina.File)); [[the image or EET file]]
+            key: string; [[the key to use (in cases of loading an EET file]]
+         }
+         return: bool; [[$true if successful, $false otherwise]]
+      }
+      matches_mmap_del {
+         [[Deletes an association of $key with its respective file.
+
+          see @.matches_mmap_add
+         ]]
+         params {
+            key: string; [[the entry's key to delete]]
+         }
+         return: bool; [[$true if successful, $false otherwise]]
+      }
+   }
+   implements {
+      Efl.Object.constructor;
+      Efl.Object.destructor;
+      Efl.Canvas.Text.Factory.create;
+   }
+}
diff --git a/src/lib/evas/Evas_Eo.h b/src/lib/evas/Evas_Eo.h
index d6664a2ddd..f2b2f6d372 100644
--- a/src/lib/evas/Evas_Eo.h
+++ b/src/lib/evas/Evas_Eo.h
@@ -21,6 +21,7 @@
  */
 //#include "canvas/efl_canvas_text_cursor.eo.h"
 #include "canvas/efl_canvas_text.eo.h"
+#include "canvas/efl_canvas_text_factory.eo.h"
 /**
  * @}
  */
diff --git a/src/lib/evas/canvas/efl_canvas_text.eo 
b/src/lib/evas/canvas/efl_canvas_text.eo
index a021fbacef..73367b0f58 100644
--- a/src/lib/evas/canvas/efl_canvas_text.eo
+++ b/src/lib/evas/canvas/efl_canvas_text.eo
@@ -345,10 +345,11 @@ class Efl.Canvas.Text (Efl.Canvas.Object, Efl.Text, 
Efl.Text.Properties,
       Efl.Text.Annotate.range_annotations_get;
       Efl.Text.Annotate.annotation_insert;
       Efl.Text.Annotate.annotation_del;
-      Efl.Text.Annotate.object_item_geometry_get;
+      Efl.Text.Annotate.annotation_is_item;
+      Efl.Text.Annotate.item_geometry_get;
       Efl.Text.Annotate.annotation_positions_get;
-      Efl.Text.Annotate.cursor_object_item_annotation { get; }
-      Efl.Text.Annotate.cursor_object_item_insert;
+      Efl.Text.Annotate.cursor_item_annotation { get; }
+      Efl.Text.Annotate.cursor_item_insert;
       Efl.Text.Markup.markup { set; get; }
       Efl.Text.Markup.cursor_markup_insert;
       Efl.Gfx.scale { set; }
diff --git a/src/lib/evas/canvas/efl_canvas_text_factory.eo 
b/src/lib/evas/canvas/efl_canvas_text_factory.eo
new file mode 100644
index 0000000000..240cfb4669
--- /dev/null
+++ b/src/lib/evas/canvas/efl_canvas_text_factory.eo
@@ -0,0 +1,25 @@
+interface Efl.Canvas.Text.Factory ()
+{
+   [[Object factory that creates Efl.Canvas.Object objects.
+
+     Translates a given key to an object (item), to be later placed in a text
+     for higher level usages. The translation implementation is left to be
+     decided by the inheriting class, whether it is by treating the $key as an
+     image path, or a key associated with a real-path in a hashtable
+     or something else entirely.
+
+     @since 1.21
+   ]]
+   methods {
+      create {
+         [[Translates a given $key to an item object, and returns the object.
+           The returned object should be owned by the passed $object.
+         ]]
+         params {
+            object: Efl.Canvas.Object; [[The parent of the created object]]
+            key: string; [[Key that is associated to an item object]]
+         }
+         return: Efl.Canvas.Object @owned;
+      }
+   }
+}
diff --git a/src/lib/evas/canvas/evas_object_textblock.c 
b/src/lib/evas/canvas/evas_object_textblock.c
index 70c5618390..1a0023da5f 100644
--- a/src/lib/evas/canvas/evas_object_textblock.c
+++ b/src/lib/evas/canvas/evas_object_textblock.c
@@ -15123,16 +15123,24 @@ 
_efl_canvas_text_efl_text_annotate_range_annotations_get(Eo *eo_obj EINA_UNUSED,
 }
 
 EOLIAN static Efl_Text_Annotate_Annotation *
-_efl_canvas_text_efl_text_annotate_cursor_object_item_insert(Eo *eo_obj, 
Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Cursor *cur, const char 
*format)
+_efl_canvas_text_efl_text_annotate_cursor_item_insert(Eo *eo_obj,
+      Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Cursor *cur,
+      const char *item, const char *format)
 {
+   Eina_Strbuf *buf = eina_strbuf_new();
+
+   eina_strbuf_append_printf(buf, "%s href=%s", format, item);
+
    Efl_Text_Annotate_Annotation *ret =
-      _textblock_annotation_insert(cur->obj, o, cur, cur, format, EINA_TRUE);
+      _textblock_annotation_insert(cur->obj, o, cur, cur,
+            eina_strbuf_string_get(buf), EINA_TRUE);
+   eina_strbuf_free(buf);
    efl_event_callback_legacy_call(eo_obj, EFL_CANVAS_TEXT_EVENT_CHANGED, NULL);
    return ret;
 }
 
 EOLIAN static Efl_Text_Annotate_Annotation *
-_efl_canvas_text_efl_text_annotate_cursor_object_item_annotation_get(Eo 
*eo_obj EINA_UNUSED,
+_efl_canvas_text_efl_text_annotate_cursor_item_annotation_get(Eo *eo_obj 
EINA_UNUSED,
       Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Cursor *cur)
 {
    Eina_Iterator *it;
@@ -15153,7 +15161,21 @@ 
_efl_canvas_text_efl_text_annotate_cursor_object_item_annotation_get(Eo *eo_obj
 }
 
 EOLIAN static Eina_Bool
-_efl_canvas_text_efl_text_annotate_object_item_geometry_get(Eo *eo_obj, 
Efl_Canvas_Text_Data *o EINA_UNUSED,
+_efl_canvas_text_efl_text_annotate_annotation_is_item(Eo *eo_obj EINA_UNUSED,
+      Efl_Canvas_Text_Data *o EINA_UNUSED,
+      Efl_Text_Annotate_Annotation *annotation)
+{
+   if (!annotation || (annotation->obj != eo_obj))
+     {
+        ERR("Used invalid handle or of a different object");
+        return EINA_FALSE;
+     }
+
+   return annotation->is_item;
+}
+
+EOLIAN static Eina_Bool
+_efl_canvas_text_efl_text_annotate_item_geometry_get(Eo *eo_obj, 
Efl_Canvas_Text_Data *o EINA_UNUSED,
       const Efl_Text_Annotate_Annotation *an, Evas_Coord *cx, Evas_Coord *cy, 
Evas_Coord *cw, Evas_Coord *ch)
 {
    Efl_Text_Cursor_Cursor cur;
@@ -16264,3 +16286,4 @@ _efl_canvas_text_async_layout(Eo *eo_obj EINA_UNUSED, 
Efl_Canvas_Text_Data *o)
 }
 
 #include "canvas/efl_canvas_text.eo.c"
+#include "canvas/efl_canvas_text_factory.eo.c" // interface
diff --git a/src/tests/evas/evas_test_textblock.c 
b/src/tests/evas/evas_test_textblock.c
index 0e6057cf58..14d04a7e10 100644
--- a/src/tests/evas/evas_test_textblock.c
+++ b/src/tests/evas/evas_test_textblock.c
@@ -4371,8 +4371,8 @@ START_TEST(evas_textblock_annotation)
    /* Check "item" annotations */
    efl_text_set(tb, "abcd");
    evas_textblock_cursor_pos_set(cur, 4);
-   an = efl_text_cursor_object_item_insert(tb, cur, "size=16x16");
-   _test_check_annotation(tb, 4, 4, _COMP_PARAMS("size=16x16"));
+   an = efl_text_cursor_item_insert(tb, cur, "", "size=16x16");
+   _test_check_annotation(tb, 4, 4, _COMP_PARAMS("size=16x16 href="));
 
    /* Check that format is not extended if it's an "object item" */
    evas_textblock_cursor_pos_set(cur, 5);
@@ -4417,14 +4417,14 @@ START_TEST(evas_textblock_annotation)
 
    /* Test getting of object item */
    evas_textblock_cursor_pos_set(cur, 4);
-   an = efl_text_cursor_object_item_annotation_get(tb, cur);
+   an = efl_text_cursor_item_annotation_get(tb, cur);
    ck_assert(!an);
 
-   an = efl_text_cursor_object_item_insert(tb, cur, "size=16x16");
+   an = efl_text_cursor_item_insert(tb, cur, "", "size=16x16");
    evas_textblock_cursor_pos_set(cur, 4);
-   an = efl_text_cursor_object_item_annotation_get(tb, cur);
+   an = efl_text_cursor_item_annotation_get(tb, cur);
    ck_assert(an);
-   ck_assert_str_eq("size=16x16", efl_text_annotation_get(tb, an));
+   ck_assert_str_eq("size=16x16 href=", efl_text_annotation_get(tb, an));
 
    END_TB_TEST();
 }

-- 


Reply via email to