woohyun pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=46f2d8acdcda3f374c9e393ecb734ff9d00fef7d

commit 46f2d8acdcda3f374c9e393ecb734ff9d00fef7d
Author: Ali Alzyod <ali198...@gmail.com>
Date:   Sat Oct 19 14:01:36 2019 +0900

    evas_object_textblock: add support for variation sequences
    
    Summary: update font processing to handle variation sequences unicodes to 
select proper glypg in respect to variation seqences
    
    Test Plan:
    ```
    #define EFL_EO_API_SUPPORT 1
    #define EFL_BETA_API_SUPPORT 1
    #include <Eina.h>
    #include <Efl.h>
    #include <Elementary.h>
    
    EAPI_MAIN int
    elm_main(int argc, char **argv)
    {
       Evas_Object *win, *textblock;
    
       elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
    
       win = elm_win_util_standard_add("Main", "");
       elm_win_autodel_set(win, EINA_TRUE);
       textblock = evas_object_textblock_add(win);
       efl_canvas_text_style_set(textblock,NULL,"DEFAULT='font=DejaVuSans 
font_fallbacks=SamsungColorEmoji color=#000 font_size=20'");
       evas_object_textblock_text_markup_set(textblock, 
"8&#xfe0f;&#x20E3;&#x262a;&#xfe0f;AAA&#x262a;&#xfe0E;1234567&#xfe0f;&#x20E3;");
    
       evas_object_size_hint_weight_set(textblock, EVAS_HINT_EXPAND, 
EVAS_HINT_EXPAND);
       evas_object_size_hint_align_set(textblock, EVAS_HINT_FILL, 
EVAS_HINT_FILL);
       evas_object_show(textblock);
       evas_object_move(textblock, 0, 0);
       evas_object_resize(textblock, 320, 320);
       evas_object_resize(win, 320, 320);
       evas_object_show(win);
       elm_run();
       return 0;
    
    }
    
    ELM_MAIN()
    
    ```
    
    Reviewers: woohyun, bowonryu, segfaultxavi, cedric, bu5hm4n
    
    Reviewed By: woohyun, cedric
    
    Subscribers: bu5hm4n, subodh6129, herdsman, segfaultxavi, zmike, cedric, 
#committers, #reviewers
    
    Tags: #efl
    
    Differential Revision: https://phab.enlightenment.org/D9053
---
 src/bin/elementary/test.c                  |   2 +
 src/bin/elementary/test_label.c            |  24 +++
 src/lib/evas/common/evas_font.h            |  53 +++++-
 src/lib/evas/common/evas_font_load.c       |   6 +-
 src/lib/evas/common/evas_font_main.c       | 296 ++++++++++++++++++++++++++---
 src/lib/evas/common/evas_font_query.c      |  54 ++++--
 src/lib/evas/common/evas_text_utils.c      |   6 +-
 src/tests/evas/evas_test_textblock.c       |  20 +-
 src/tests/evas/fonts/NotoColorEmoji.ttf    | Bin 0 -> 7297112 bytes
 src/tests/evas/fonts/NotoEmoji-Regular.ttf | Bin 0 -> 418804 bytes
 10 files changed, 412 insertions(+), 49 deletions(-)

diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c
index 8259ed8b0c..bcdb484af3 100644
--- a/src/bin/elementary/test.c
+++ b/src/bin/elementary/test.c
@@ -243,6 +243,7 @@ void test_label_wrap(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);
+void test_label_variation_sequence(void *data, Evas_Object *obj, void 
*event_info);
 void test_conformant(void *data, Evas_Object *obj, void *event_info);
 void test_conformant2(void *data, Evas_Object *obj, void *event_info);
 void test_conformant_indicator(void *data, Evas_Object *obj, void *event_info);
@@ -1210,6 +1211,7 @@ add_tests:
    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);
+   ADD_TEST(NULL, "Text", "Label Variation Sequnece", 
test_label_variation_sequence);
    ADD_TEST_EO(NULL, "Text", "Efl.Ui.Textpath", test_ui_textpath);
 
    //------------------------------//
diff --git a/src/bin/elementary/test_label.c b/src/bin/elementary/test_label.c
index 233ce015b4..72cb2aeca3 100644
--- a/src/bin/elementary/test_label.c
+++ b/src/bin/elementary/test_label.c
@@ -403,6 +403,30 @@ test_label_colors(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, void *ev
    evas_object_show(win);
 }
 
+/*** Label variation sequence 
**************************************************************/
+void
+test_label_variation_sequence(void *data EINA_UNUSED, Evas_Object *obj 
EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+   Evas_Object *win, *lb;
+
+   win = elm_win_util_standard_add("label-variation sequence", "Label 
variation sequnece");
+   elm_win_autodel_set(win, EINA_TRUE);
+
+   lb = elm_label_add(win);
+   elm_object_text_set(lb,
+                       "You need to have at least on font contains variation 
sequence<br>"
+                       "Three different 8 glyphs : <br>"
+                       "8<tab>8&#xfe0f;<tab>8&#xfe0f;&#x20E3;<br>"
+                       "line with 3 variation glyphs : <br>"
+                       
"8&#xfe0f;&#x20E3;&#x262a;&#xfe0f;AAA&#x262a;&#xfe0E;1234567&#xfe0f;&#x20E3;"
+                       );
+   evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   elm_win_resize_object_add(win, lb);
+   evas_object_show(lb);
+
+   evas_object_show(win);
+}
+
 /*** Label Emoji *************************************************************/
 static char *
 _fontlist_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part 
EINA_UNUSED)
diff --git a/src/lib/evas/common/evas_font.h b/src/lib/evas/common/evas_font.h
index e16785520d..b4490ea992 100644
--- a/src/lib/evas/common/evas_font.h
+++ b/src/lib/evas/common/evas_font.h
@@ -56,7 +56,32 @@ typedef unsigned long long    DATA64;
 #define LKU(x) eina_lock_release(&(x))
 #define LKDBG(x) eina_lock_debug(&(x))
 
+/**
+ * See explanation of variation_sequences at:
+ * https://unicode.org/Public/UCD/latest/ucd/StandardizedVariants.txt
+ * https://unicode.org/reports/tr37/
+ * https://unicode.org/ivd/
+ * https://www.freetype.org/freetype2/docs/reference/ft2-glyph_variants.html
+*/
+#define VAR_SEQ(x) GENERIC_VARIATION_SEQUENCES(x) | 
IDEOGRAPHICS_VARIATION_SEQUENCES(x) | MANGOLIAN_VARIATION_SEQUENCES(x)
+#define GENERIC_VARIATION_SEQUENCES(x) (x>=0xFE00 && x<=0xFE0F) ? x : 0
+#define IDEOGRAPHICS_VARIATION_SEQUENCES(x) (x>=0xE0100 && x<=0xE01EF) ? x : 0
+#define MANGOLIAN_VARIATION_SEQUENCES(x) (x>=0x180B && x<=0x180D) ? x : 0
+/**
+ * http://unicode.org/emoji/charts/emoji-variants.html
+*/
+#define  VARIATION_EMOJI_PRESENTATION  0xFE0F
+#define  VARIATION_TEXT_PRESENTATION   0xFE0E
+
+/**
+ * These Options (Flags) are used with evas_common_font_glyph_search function
+ */
+#define EVAS_FONT_SEARCH_OPTION_NONE            0x0000
+#define EVAS_FONT_SEARCH_OPTION_SKIP_COLOR      0x0001
+
 
+#define FASH_INT_MAGIC              0x01012345
+#define FASH_GLYPH_MAGIC            0x02012345
 
 enum _Evas_Font_Style
 {
@@ -128,6 +153,10 @@ typedef struct _RGBA_Font_Source      RGBA_Font_Source;
 typedef struct _RGBA_Font_Glyph       RGBA_Font_Glyph;
 typedef struct _RGBA_Font_Glyph_Out   RGBA_Font_Glyph_Out;
 
+typedef struct _Fash_Item_variation_Index_Item  Fash_Item_variation_Index_Item;
+typedef struct _Fash_Item_variation_List        Fash_Item_variation_List;
+typedef struct _Fash_Item_Index_Map_Variations  Fash_Item_Index_Map_Variations;
+
 typedef struct _Fash_Item_Index_Map Fash_Item_Index_Map;
 typedef struct _Fash_Int_Map        Fash_Int_Map;
 typedef struct _Fash_Int_Map2       Fash_Int_Map2;
@@ -139,9 +168,25 @@ struct _Fash_Item_Index_Map
    RGBA_Font_Int *fint;
    int            index;
 };
+struct _Fash_Item_variation_Index_Item
+{
+   Fash_Item_Index_Map  item;
+   Eina_Unicode         variation_sequence;
+};
+struct _Fash_Item_variation_List
+{
+   Fash_Item_variation_Index_Item  *list;
+   size_t                           length;
+   size_t                           capacity;
+};
+struct _Fash_Item_Index_Map_Variations
+{
+   Fash_Item_Index_Map         item;
+   Fash_Item_variation_List   *variations;
+};
 struct _Fash_Int_Map
 {
-  Fash_Item_Index_Map item[256];
+  Fash_Item_Index_Map_Variations items[256];
 };
 struct _Fash_Int_Map2
 {
@@ -149,6 +194,7 @@ struct _Fash_Int_Map2
 };
 struct _Fash_Int
 {
+   unsigned int MAGIC;
    Fash_Int_Map2 *bucket[256];
    void (*freeme) (Fash_Int *fash);
 };
@@ -166,6 +212,7 @@ struct _Fash_Glyph_Map2
 };
 struct _Fash_Glyph
 {
+   unsigned int MAGIC;
    Fash_Glyph_Map2 *bucket[256];
    void (*freeme) (Fash_Glyph *fash);
 };
@@ -347,7 +394,7 @@ void *evas_common_font_freetype_face_get(RGBA_Font *font); 
/* XXX: Not EAPI on p
 
 EAPI RGBA_Font_Glyph  *evas_common_font_int_cache_glyph_get  (RGBA_Font_Int 
*fi, FT_UInt index);
 EAPI Eina_Bool         evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph 
*fg);
-EAPI FT_UInt           evas_common_get_char_index            (RGBA_Font_Int* 
fi, Eina_Unicode gl);
+EAPI FT_UInt           evas_common_get_char_index            (RGBA_Font_Int* 
fi, Eina_Unicode gl, Eina_Unicode variation_sequence);
 
 /* load */
 EAPI void              evas_common_font_dpi_set              (int dpi_h, int 
dpi_v);
@@ -397,7 +444,7 @@ EAPI void              
evas_common_font_ascent_descent_get(RGBA_Font *fn, const
 
 EAPI void             *evas_common_font_glyph_compress(void *data, int 
num_grays, int pixel_mode, int pitch_data, int w, int h, int *size_ret);
 EAPI DATA8            *evas_common_font_glyph_uncompress(RGBA_Font_Glyph *fg, 
int *wret, int *hret);
-EAPI int               evas_common_font_glyph_search         (RGBA_Font *fn, 
RGBA_Font_Int **fi_ret, Eina_Unicode gl);
+EAPI int               evas_common_font_glyph_search         (RGBA_Font *fn, 
RGBA_Font_Int **fi_ret, Eina_Unicode gl, Eina_Unicode variation_sequence, 
uint32_t evas_font_search_options);
 
 void evas_common_font_load_init(void);
 void evas_common_font_load_shutdown(void);
diff --git a/src/lib/evas/common/evas_font_load.c 
b/src/lib/evas/common/evas_font_load.c
index f2011bd72f..3aa2070499 100644
--- a/src/lib/evas/common/evas_font_load.c
+++ b/src/lib/evas/common/evas_font_load.c
@@ -687,7 +687,11 @@ evas_common_font_free(RGBA_Font *fn)
      evas_common_font_int_unref(fi);
    evas_common_font_flush();
    eina_list_free(fn->fonts);
-   if (fn->fash) fn->fash->freeme(fn->fash);
+   if (fn->fash)
+     {
+        fn->fash->freeme(fn->fash);
+        fn->fash = NULL;
+     }
    LKD(fn->lock);
    free(fn);
 }
diff --git a/src/lib/evas/common/evas_font_main.c 
b/src/lib/evas/common/evas_font_main.c
index 1a163748ca..c41e350dcf 100644
--- a/src/lib/evas/common/evas_font_main.c
+++ b/src/lib/evas/common/evas_font_main.c
@@ -355,33 +355,182 @@ end:
 /* Set of common functions that are used in a couple of places. */
 
 static void
-_fash_int2_free(Fash_Int_Map2 *fash)
-{
+_fash_int_map_and_variations_free(Fash_Int_Map *map)
+ {
+   if(!map)
+     return;
    int i;
 
-   for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]);
-   free(fash);
+   for (i = 0; i < 256; i++)
+     {
+        if (map->items[i].variations)
+          {
+             if (map->items[i].variations->list)
+               {
+                  free(map->items[i].variations->list);
+                  map->items[i].variations->list = NULL;
+                  map->items[i].variations->capacity = 0;
+                  map->items[i].variations->length = 0;
+               }
+             free(map->items[i].variations);
+             map->items[i].variations = NULL;
+          }
+     }
+
+   free(map);
+}
+
+static void
+_fash_int2_free(Fash_Int_Map2 *fash)
+ {
+   int i;
+   if (fash)
+     {
+        for (i = 0; i < 256; i++)
+          if (fash->bucket[i])
+            {
+               _fash_int_map_and_variations_free(fash->bucket[i]);
+               fash->bucket[i] = NULL;
+            }
+        free(fash);
+        fash = NULL;
+     }
 }
 
 static void
 _fash_int_free(Fash_Int *fash)
 {
    int i;
+   if (fash)
+     {
+        if (fash->MAGIC != FASH_INT_MAGIC)
+          {
+             return;
+          }
 
-   for (i = 0; i < 256; i++) if (fash->bucket[i]) 
_fash_int2_free(fash->bucket[i]);
-   free(fash);
+        for (i = 0; i < 256; i++)
+          {
+             if (fash->bucket[i])
+               {
+                  _fash_int2_free(fash->bucket[i]);
+                  fash->bucket[i] = NULL;
+               }
+          }
+        free(fash);
+     }
 }
 
 static Fash_Int *
 _fash_int_new(void)
 {
    Fash_Int *fash = calloc(1, sizeof(Fash_Int));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
+   fash->MAGIC = FASH_INT_MAGIC;
    fash->freeme = _fash_int_free;
    return fash;
 }
 
+static Fash_Item_variation_List *
+_variations_list_new(void)
+{
+   Fash_Item_variation_List *variations = calloc(1, 
sizeof(Fash_Item_variation_List));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(variations, NULL);
+   variations->capacity = 0;
+   variations->length = 0;
+   variations->list = 0;
+   return variations;
+}
+
+static void
+_variations_list_add(Fash_Item_variation_List *variations,RGBA_Font_Int *fint, 
int index, Eina_Unicode variation_sequence)
+{
+   Fash_Item_variation_Index_Item *list = variations->list;
+   if (variations->capacity == variations->length)
+     {
+        list = (Fash_Item_variation_Index_Item *) realloc(list, 
(variations->capacity + 4) * sizeof(Fash_Item_variation_Index_Item));
+        if (list)
+          {
+             variations->list = list;
+             variations->capacity += 4;
+          }
+     }
+
+   EINA_SAFETY_ON_NULL_RETURN(list);
+
+   int start = 0;
+   int end = variations->length;
+   if (end == 0)
+     {
+        // if only on element just add it in 0 index
+        variations->list[0].item.fint = fint;
+        variations->list[0].item.index = index;
+        variations->list[0].variation_sequence = variation_sequence;
+        variations->length++;
+     }
+   else
+     {
+        // find lower bound
+        while (end > start)
+          {
+             int middle = start + (end - start) / 2;
+             if (variations->list[middle].variation_sequence >= 
variation_sequence)
+               end = middle;
+             else
+               start = middle + 1;
+          }
+
+        // if passed value founded in list, just replace it
+        if (start < (int)variations->length && 
variations->list[start].variation_sequence == variation_sequence)
+          {
+             variations->list[start].item.fint = fint;
+             variations->list[start].item.index = index;
+             variations->list[start].variation_sequence = variation_sequence;
+             return;
+          }
+
+        // shift array to insert item
+        for (int i = (variations->length - 1) ; i >= start; i--)
+          {
+             variations->list[i + 1] = variations->list[i];
+          }
+
+        // insert new item and keep array sorted
+        variations->list[start].item.fint = fint;
+        variations->list[start].item.index = index;
+        variations->list[start].variation_sequence = variation_sequence;
+        variations->length++;
+     }
+}
+
+
 static Fash_Item_Index_Map *
-_fash_int_find(Fash_Int *fash, int item)
+_variations_list_find(Fash_Item_variation_List * variations, Eina_Unicode 
variation_sequence)
+{
+   if (!variations)
+     return NULL;
+
+   if (!variations->list)
+     return NULL;
+
+   int start = 0;
+   int end = variations->length;
+
+   while(end > start)
+     {
+        int middle = start + (end - start) / 2;
+        if (variations->list[middle].variation_sequence == variation_sequence)
+          return &(variations->list[middle].item);
+        else if (variations->list[middle].variation_sequence < 
variation_sequence)
+          start = middle + 1;
+        else
+          end = middle - 1;
+     }
+
+   return NULL;
+}
+
+static const Fash_Item_Index_Map *
+_fash_int_find(Fash_Int *fash, int item, Eina_Unicode variation_sequence)
 {
    int grp, maj, min;
 
@@ -391,14 +540,22 @@ _fash_int_find(Fash_Int *fash, int item)
    min = item & 0xff;
    if (!fash->bucket[grp]) return NULL;
    if (!fash->bucket[grp]->bucket[maj]) return NULL;
-   return &(fash->bucket[grp]->bucket[maj]->item[min]);
+   if (!variation_sequence)
+     return &(fash->bucket[grp]->bucket[maj]->items[min].item);
+   else
+     return 
_variations_list_find(fash->bucket[grp]->bucket[maj]->items[min].variations, 
variation_sequence);
 }
 
 static void
-_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx)
+_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx, 
Eina_Unicode variation_sequence)
 {
    int grp, maj, min;
 
+   // If we already have cached passed item, skip adding it again
+   const Fash_Item_Index_Map *fm = _fash_int_find(fash, item, 
variation_sequence);
+   if (fm && fm->fint)
+     return;
+
    // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use 
(plane 16)
    grp = (item >> 16) & 0xff;
    maj = (item >> 8) & 0xff;
@@ -409,8 +566,20 @@ _fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int 
*fint, int idx)
    if (!fash->bucket[grp]->bucket[maj])
      fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map));
    EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
-   fash->bucket[grp]->bucket[maj]->item[min].fint = fint;
-   fash->bucket[grp]->bucket[maj]->item[min].index = idx;
+   if (variation_sequence)
+     {
+         if (!fash->bucket[grp]->bucket[maj]->items[min].variations)
+           {
+              fash->bucket[grp]->bucket[maj]->items[min].variations 
=_variations_list_new();
+              
EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]->items[min].variations);
+           }
+         
_variations_list_add(fash->bucket[grp]->bucket[maj]->items[min].variations, 
fint, idx, variation_sequence);
+     }
+   else
+     {
+        fash->bucket[grp]->bucket[maj]->items[min].item.fint = fint;
+        fash->bucket[grp]->bucket[maj]->items[min].item.index = idx;
+     }
 }
 
 static void
@@ -462,24 +631,45 @@ _fash_gl2_free(Fash_Glyph_Map2 *fash)
    int i;
 
    // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use 
(plane 16)
-   for (i = 0; i < 256; i++) if (fash->bucket[i]) 
_fash_glyph_free(fash->bucket[i]);
+   for (i = 0; i < 256; i++)
+     {
+        if (fash->bucket[i])
+          {
+             _fash_glyph_free(fash->bucket[i]);
+             fash->bucket[i] = NULL;
+          }
+     }
    free(fash);
 }
 
 static void
 _fash_gl_free(Fash_Glyph *fash)
 {
-   int i;
+   if (fash)
+     {
+        if (fash->MAGIC != FASH_GLYPH_MAGIC)
+          return;
 
-    // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use 
(plane 16)
-   for (i = 0; i < 256; i++) if (fash->bucket[i]) 
_fash_gl2_free(fash->bucket[i]);
-   free(fash);
+        int i;
+          // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private 
use (plane 16)
+        for (i = 0; i < 256; i++)
+          {
+            if (fash->bucket[i])
+              {
+                 _fash_gl2_free(fash->bucket[i]);
+                 fash->bucket[i] = NULL;
+              }
+          }
+         free(fash);
+     }
 }
 
 static Fash_Glyph *
 _fash_gl_new(void)
 {
    Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
+   fash->MAGIC = FASH_GLYPH_MAGIC;
    fash->freeme = _fash_gl_free;
    return fash;
 }
@@ -680,7 +870,7 @@ struct _Font_Char_Index
 };
 
 EAPI FT_UInt
-evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
+evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl, Eina_Unicode 
variation_sequence)
 {
    static const unsigned short mapfix[] =
      {
@@ -742,7 +932,10 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode 
gl)
     * that something else try to use it.
     */
    /* FTLOCK(); */
-   result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
+   if (variation_sequence)
+     result.index = FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, 
variation_sequence);
+   else
+     result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
    /* FTUNLOCK(); */
    result.gl = gl;
 
@@ -774,7 +967,10 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode 
gl)
                {
                   gl = mapfix[(i << 1) + 1];
                   FTLOCK();
-                  result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
+                  if (variation_sequence)
+                    result.index = 
FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, variation_sequence);
+                  else
+                    result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
                   FTUNLOCK();
                   break;
                }
@@ -799,20 +995,49 @@ evas_common_get_char_index(RGBA_Font_Int* fi, 
Eina_Unicode gl)
    return result.index;
 }
 
+
+/*
+ * @internal
+ * Search for unicode glyph inside all font files, and return font and glyph 
index
+ *
+ * @param[in] fn the font to use.
+ * @param[out] fi_ret founded font.
+ * @param[in] gl unicode glyph to search for
+ * @param[in] variation_sequence for the gl glyph
+ * @param[in] evas_font_search_options search options when searching font files
+ *
+ */
+
 EAPI int
-evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, 
Eina_Unicode gl)
+evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, 
Eina_Unicode gl, Eina_Unicode variation_sequence, uint32_t 
evas_font_search_options)
 {
    Eina_List *l;
 
    if (fn->fash)
      {
-        Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl);
+        const Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl, 
variation_sequence);
         if (fm)
           {
              if (fm->fint)
                {
-                  *fi_ret = fm->fint;
-                  return fm->index;
+                  if (evas_font_search_options == EVAS_FONT_SEARCH_OPTION_NONE)
+                    {
+                        *fi_ret = fm->fint;
+                        return fm->index;
+                    }
+                  else if( (evas_font_search_options & 
EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR)
+                    {
+                       if (!fm->fint->src->ft.face)
+                         {
+                            evas_common_font_int_reload(fm->fint);
+                         }
+
+                       if (fm->fint->src->ft.face && 
!FT_HAS_COLOR(fm->fint->src->ft.face))
+                         {
+                            *fi_ret = fm->fint;
+                            return fm->index;
+                         }
+                    }
                }
              else if (fm->index == -1) return 0;
           }
@@ -851,20 +1076,35 @@ evas_common_font_glyph_search(RGBA_Font *fn, 
RGBA_Font_Int **fi_ret, Eina_Unicod
           }
         if (fi->src->ft.face)
           {
-             idx = evas_common_get_char_index(fi, gl);
+             Eina_Bool is_color_only = (evas_font_search_options & 
EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR &&
+                 FT_HAS_COLOR(fi->src->ft.face);
+
+             if (is_color_only)
+               {
+                  /* This is color font ignore it */
+                  continue;
+               }
+
+             idx = (int) evas_common_get_char_index(fi, gl, 
variation_sequence);
              if (idx != 0)
                {
                   if (!fi->ft.size)
                     evas_common_font_int_load_complete(fi);
-                  if (!fn->fash) fn->fash = _fash_int_new();
-                  if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx);
+                  if (!is_color_only)
+                    {
+                       if (!fn->fash) fn->fash = _fash_int_new();
+                       if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx, 
variation_sequence);
+                    }
                   *fi_ret = fi;
                   return idx;
                }
              else
                {
-                  if (!fn->fash) fn->fash = _fash_int_new();
-                  if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1);
+                  if (!is_color_only)
+                    {
+                        if (!fn->fash) fn->fash = _fash_int_new();
+                        if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1, 
variation_sequence);
+                    }
                }
           }
      }
diff --git a/src/lib/evas/common/evas_font_query.c 
b/src/lib/evas/common/evas_font_query.c
index 1ff0447963..7b50a74e62 100644
--- a/src/lib/evas/common/evas_font_query.c
+++ b/src/lib/evas/common/evas_font_query.c
@@ -32,6 +32,9 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
              (evas_common_language_char_script_get(*base_char) != script) ;
              base_char++)
            ;
+        /* If counter reach variation sequence it is safe to pick default font 
*/
+        if(VAR_SEQ(*base_char) || (base_char != run_end && 
VAR_SEQ(*(base_char+1)))) goto get_top_font;
+
         if (base_char == run_end) base_char = text;
 
         /* Find the first renderable char */
@@ -40,7 +43,7 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
              /* 0x1F is the last ASCII contral char, just a hack in
               * the meanwhile. */
              if ((*base_char > 0x1F) &&
-                   evas_common_font_glyph_search(fn, &fi, *base_char))
+                   evas_common_font_glyph_search(fn, &fi, *base_char, 0, 
EVAS_FONT_SEARCH_OPTION_NONE))
                 break;
              base_char++;
           }
@@ -49,7 +52,8 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
         /* If everything else fails, at least try to find a font for the
          * replacement char */
         if (base_char == run_end)
-           evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR);
+           evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR, 0, 
EVAS_FONT_SEARCH_OPTION_NONE);
+get_top_font:
 
         if (!fi)
            fi = fn->fonts->data;
@@ -80,15 +84,17 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
              if (evas_common_language_char_script_get(*itr) == 
EVAS_SCRIPT_INHERITED)
                 continue;
 
+             Eina_Unicode variation_sequence =  VAR_SEQ(*(itr+1));
+
              /* Break if either it's not in the font, or if it is in the
               * script's font. */
-             if (!evas_common_get_char_index(fi, *itr))
-                break;
+             if (!evas_common_get_char_index(fi, *itr, variation_sequence))
+               break;
 
              if (fi != *script_fi)
                {
-                  if (evas_common_get_char_index(*script_fi, *itr))
-                     break;
+                  if (evas_common_get_char_index(*script_fi, *itr, 
variation_sequence))
+                    break;
                }
           }
 
@@ -102,10 +108,25 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
              /* If we can find a font, use it. Otherwise, find the first
               * char the run of chars that can't be rendered until the first
               * one that can. */
-             if (evas_common_font_glyph_search(fn, &tmp_fi, *itr))
+             Eina_Unicode variation_sequence =  VAR_SEQ(*(itr+1));
+             if (evas_common_font_glyph_search(fn, &tmp_fi, *itr, 
variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE))
                {
                   fi = tmp_fi;
                }
+             else if ( (variation_sequence == VARIATION_TEXT_PRESENTATION) && 
evas_common_font_glyph_search(fn, &tmp_fi, *itr, 0, 
EVAS_FONT_SEARCH_OPTION_SKIP_COLOR))
+               {
+                   /* If we can not find unicode with variation sequence, then 
we will
+                      Search and find for non color glyph because variation 
sequence is Text
+                   */
+                  fi = tmp_fi;
+               }
+             else if ( variation_sequence && evas_common_font_glyph_search(fn, 
&tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_NONE))
+               {
+                   /* If we can not find unicode with variation sequence, then 
we will
+                      Search and find glyph without the variation sequence
+                   */
+                  fi = tmp_fi;
+               }
              else
                {
                   itr++;
@@ -113,9 +134,13 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
                    * font */
                   for ( ; itr < run_end ; itr++)
                     {
+                       if(VAR_SEQ(*itr))
+                          continue;
+
+                       Eina_Unicode variation_sequence =  VAR_SEQ(*(itr+1));
                        tmp_fi = fi;
-                       if (evas_common_get_char_index(fi, *itr) ||
-                             evas_common_font_glyph_search(fn, &tmp_fi, *itr))
+                       if (evas_common_get_char_index(fi, *itr, 
variation_sequence) ||
+                             evas_common_font_glyph_search(fn, &tmp_fi, *itr, 
variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE))
                          {
                             fi = tmp_fi;
                             break;
@@ -127,9 +152,9 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
                    * find a font most suitable for the replacement char and
                    * break */
                   if ((itr == run_end) ||
-                        !evas_common_get_char_index(fi, REPLACEMENT_CHAR))
+                        !evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0))
                     {
-                       evas_common_font_glyph_search(fn, &fi, 
REPLACEMENT_CHAR);
+                       evas_common_font_glyph_search(fn, &fi, 
REPLACEMENT_CHAR, 0, EVAS_FONT_SEARCH_OPTION_NONE);
                        break;
                     }
                }
@@ -140,8 +165,11 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, 
RGBA_Font_Int **script_fi
              /* If this char is not renderable by any font, but the replacement
               * char can be rendered using the currentfont, continue this
               * run. */
-             if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr) &&
-                   evas_common_get_char_index(fi, REPLACEMENT_CHAR))
+             Eina_Unicode variation_sequence =  VAR_SEQ(*(itr+1));
+
+             if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr, 
variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE) &&
+                 (variation_sequence ? !evas_common_font_glyph_search(fn, 
&tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_NONE) : 1) &&
+                 evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0))
                {
                   itr++;
                }
diff --git a/src/lib/evas/common/evas_text_utils.c 
b/src/lib/evas/common/evas_text_utils.c
index e9c5cc2c94..acf7cf8fb7 100644
--- a/src/lib/evas/common/evas_text_utils.c
+++ b/src/lib/evas/common/evas_text_utils.c
@@ -1066,7 +1066,7 @@ _content_create_ot(RGBA_Font_Int *fi, const Eina_Unicode 
*text,
         /* If we got a malformed index, show the replacement char instead */
         if (gl_itr->index == 0)
           {
-             gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR);
+             gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR, 
0);
              is_replacement = EINA_TRUE;
           }
         idx = gl_itr->index;
@@ -1172,10 +1172,10 @@ _content_create_regular(RGBA_Font_Int *fi, const 
Eina_Unicode *text,
         _gl = *text;
         if (_gl == 0) break;
 
-        idx = evas_common_get_char_index(fi, _gl);
+        idx = evas_common_get_char_index(fi, _gl, 0);
         if (idx == 0)
           {
-             idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR);
+             idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0);
           }
 
         fg = evas_common_font_int_cache_glyph_get(fi, idx);
diff --git a/src/tests/evas/evas_test_textblock.c 
b/src/tests/evas/evas_test_textblock.c
index f61574c065..2db6888b12 100644
--- a/src/tests/evas/evas_test_textblock.c
+++ b/src/tests/evas/evas_test_textblock.c
@@ -1,6 +1,6 @@
 /*
  * TODO:
- * * Test different font lodaing mechanisms.
+ * * Test different font loading mechanisms.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -4129,6 +4129,23 @@ EFL_START_TEST(evas_textblock_obstacle)
 }
 EFL_END_TEST;
 
+EFL_START_TEST(evas_textblock_variation_sequence)
+{
+   START_TB_TEST();
+   evas_font_path_global_prepend("..");
+   const char *str1 = "8&#xfe0f;&#x262a;&#xfe0f;";
+   const char *str2 = "8&#xfe0e;&#x262a;&#xfe0e;";
+   Evas_Coord fw, fh,fw_new, fh_new;
+   evas_object_textblock_text_markup_set(tb, str1);
+   evas_object_textblock_size_formatted_get(tb, &fw, &fh);
+   evas_object_textblock_text_markup_set(tb, str2);
+   evas_object_textblock_size_formatted_get(tb, &fw_new, &fh_new);
+   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)
@@ -4729,6 +4746,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_variation_sequence);
 #ifdef HAVE_HYPHEN
    tcase_add_test(tc, evas_textblock_hyphenation);
 #endif
diff --git a/src/tests/evas/fonts/NotoColorEmoji.ttf 
b/src/tests/evas/fonts/NotoColorEmoji.ttf
new file mode 100644
index 0000000000..69cf21a1a9
Binary files /dev/null and b/src/tests/evas/fonts/NotoColorEmoji.ttf differ
diff --git a/src/tests/evas/fonts/NotoEmoji-Regular.ttf 
b/src/tests/evas/fonts/NotoEmoji-Regular.ttf
new file mode 100644
index 0000000000..19b7badf4a
Binary files /dev/null and b/src/tests/evas/fonts/NotoEmoji-Regular.ttf differ

-- 


Reply via email to