summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bin/elementary/test.c2
-rw-r--r--src/bin/elementary/test_label.c24
-rw-r--r--src/lib/evas/common/evas_font.h53
-rw-r--r--src/lib/evas/common/evas_font_load.c6
-rw-r--r--src/lib/evas/common/evas_font_main.c296
-rw-r--r--src/lib/evas/common/evas_font_query.c54
-rw-r--r--src/lib/evas/common/evas_text_utils.c6
-rw-r--r--src/tests/evas/evas_test_textblock.c20
-rw-r--r--src/tests/evas/fonts/NotoColorEmoji.ttfbin0 -> 7297112 bytes
-rw-r--r--src/tests/evas/fonts/NotoEmoji-Regular.ttfbin0 -> 418804 bytes
10 files changed, 412 insertions, 49 deletions
diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c
index 8259ed8..bcdb484 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);
243void test_label_ellipsis(void *data, Evas_Object *obj, void *event_info); 243void test_label_ellipsis(void *data, Evas_Object *obj, void *event_info);
244void test_label_colors(void *data, Evas_Object *obj, void *event_info); 244void test_label_colors(void *data, Evas_Object *obj, void *event_info);
245void test_label_emoji(void *data, Evas_Object *obj, void *event_info); 245void test_label_emoji(void *data, Evas_Object *obj, void *event_info);
246void test_label_variation_sequence(void *data, Evas_Object *obj, void *event_info);
246void test_conformant(void *data, Evas_Object *obj, void *event_info); 247void test_conformant(void *data, Evas_Object *obj, void *event_info);
247void test_conformant2(void *data, Evas_Object *obj, void *event_info); 248void test_conformant2(void *data, Evas_Object *obj, void *event_info);
248void test_conformant_indicator(void *data, Evas_Object *obj, void *event_info); 249void test_conformant_indicator(void *data, Evas_Object *obj, void *event_info);
@@ -1210,6 +1211,7 @@ add_tests:
1210 ADD_TEST(NULL, "Text", "Label Ellipsis", test_label_ellipsis); 1211 ADD_TEST(NULL, "Text", "Label Ellipsis", test_label_ellipsis);
1211 ADD_TEST(NULL, "Text", "Label Colors", test_label_colors); 1212 ADD_TEST(NULL, "Text", "Label Colors", test_label_colors);
1212 ADD_TEST(NULL, "Text", "Label Emoji", test_label_emoji); 1213 ADD_TEST(NULL, "Text", "Label Emoji", test_label_emoji);
1214 ADD_TEST(NULL, "Text", "Label Variation Sequnece", test_label_variation_sequence);
1213 ADD_TEST_EO(NULL, "Text", "Efl.Ui.Textpath", test_ui_textpath); 1215 ADD_TEST_EO(NULL, "Text", "Efl.Ui.Textpath", test_ui_textpath);
1214 1216
1215 //------------------------------// 1217 //------------------------------//
diff --git a/src/bin/elementary/test_label.c b/src/bin/elementary/test_label.c
index 233ce01..72cb2ae 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
403 evas_object_show(win); 403 evas_object_show(win);
404} 404}
405 405
406/*** Label variation sequence **************************************************************/
407void
408test_label_variation_sequence(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
409{
410 Evas_Object *win, *lb;
411
412 win = elm_win_util_standard_add("label-variation sequence", "Label variation sequnece");
413 elm_win_autodel_set(win, EINA_TRUE);
414
415 lb = elm_label_add(win);
416 elm_object_text_set(lb,
417 "You need to have at least on font contains variation sequence<br>"
418 "Three different 8 glyphs : <br>"
419 "8<tab>8&#xfe0f;<tab>8&#xfe0f;&#x20E3;<br>"
420 "line with 3 variation glyphs : <br>"
421 "8&#xfe0f;&#x20E3;&#x262a;&#xfe0f;AAA&#x262a;&#xfe0E;1234567&#xfe0f;&#x20E3;"
422 );
423 evas_object_size_hint_weight_set(lb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
424 elm_win_resize_object_add(win, lb);
425 evas_object_show(lb);
426
427 evas_object_show(win);
428}
429
406/*** Label Emoji *************************************************************/ 430/*** Label Emoji *************************************************************/
407static char * 431static char *
408_fontlist_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED) 432_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 e167855..b4490ea 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;
56#define LKU(x) eina_lock_release(&(x)) 56#define LKU(x) eina_lock_release(&(x))
57#define LKDBG(x) eina_lock_debug(&(x)) 57#define LKDBG(x) eina_lock_debug(&(x))
58 58
59/**
60 * See explanation of variation_sequences at:
61 * https://unicode.org/Public/UCD/latest/ucd/StandardizedVariants.txt
62 * https://unicode.org/reports/tr37/
63 * https://unicode.org/ivd/
64 * https://www.freetype.org/freetype2/docs/reference/ft2-glyph_variants.html
65*/
66#define VAR_SEQ(x) GENERIC_VARIATION_SEQUENCES(x) | IDEOGRAPHICS_VARIATION_SEQUENCES(x) | MANGOLIAN_VARIATION_SEQUENCES(x)
67#define GENERIC_VARIATION_SEQUENCES(x) (x>=0xFE00 && x<=0xFE0F) ? x : 0
68#define IDEOGRAPHICS_VARIATION_SEQUENCES(x) (x>=0xE0100 && x<=0xE01EF) ? x : 0
69#define MANGOLIAN_VARIATION_SEQUENCES(x) (x>=0x180B && x<=0x180D) ? x : 0
70/**
71 * http://unicode.org/emoji/charts/emoji-variants.html
72*/
73#define VARIATION_EMOJI_PRESENTATION 0xFE0F
74#define VARIATION_TEXT_PRESENTATION 0xFE0E
75
76/**
77 * These Options (Flags) are used with evas_common_font_glyph_search function
78 */
79#define EVAS_FONT_SEARCH_OPTION_NONE 0x0000
80#define EVAS_FONT_SEARCH_OPTION_SKIP_COLOR 0x0001
81
59 82
83#define FASH_INT_MAGIC 0x01012345
84#define FASH_GLYPH_MAGIC 0x02012345
60 85
61enum _Evas_Font_Style 86enum _Evas_Font_Style
62{ 87{
@@ -128,6 +153,10 @@ typedef struct _RGBA_Font_Source RGBA_Font_Source;
128typedef struct _RGBA_Font_Glyph RGBA_Font_Glyph; 153typedef struct _RGBA_Font_Glyph RGBA_Font_Glyph;
129typedef struct _RGBA_Font_Glyph_Out RGBA_Font_Glyph_Out; 154typedef struct _RGBA_Font_Glyph_Out RGBA_Font_Glyph_Out;
130 155
156typedef struct _Fash_Item_variation_Index_Item Fash_Item_variation_Index_Item;
157typedef struct _Fash_Item_variation_List Fash_Item_variation_List;
158typedef struct _Fash_Item_Index_Map_Variations Fash_Item_Index_Map_Variations;
159
131typedef struct _Fash_Item_Index_Map Fash_Item_Index_Map; 160typedef struct _Fash_Item_Index_Map Fash_Item_Index_Map;
132typedef struct _Fash_Int_Map Fash_Int_Map; 161typedef struct _Fash_Int_Map Fash_Int_Map;
133typedef struct _Fash_Int_Map2 Fash_Int_Map2; 162typedef struct _Fash_Int_Map2 Fash_Int_Map2;
@@ -139,9 +168,25 @@ struct _Fash_Item_Index_Map
139 RGBA_Font_Int *fint; 168 RGBA_Font_Int *fint;
140 int index; 169 int index;
141}; 170};
171struct _Fash_Item_variation_Index_Item
172{
173 Fash_Item_Index_Map item;
174 Eina_Unicode variation_sequence;
175};
176struct _Fash_Item_variation_List
177{
178 Fash_Item_variation_Index_Item *list;
179 size_t length;
180 size_t capacity;
181};
182struct _Fash_Item_Index_Map_Variations
183{
184 Fash_Item_Index_Map item;
185 Fash_Item_variation_List *variations;
186};
142struct _Fash_Int_Map 187struct _Fash_Int_Map
143{ 188{
144 Fash_Item_Index_Map item[256]; 189 Fash_Item_Index_Map_Variations items[256];
145}; 190};
146struct _Fash_Int_Map2 191struct _Fash_Int_Map2
147{ 192{
@@ -149,6 +194,7 @@ struct _Fash_Int_Map2
149}; 194};
150struct _Fash_Int 195struct _Fash_Int
151{ 196{
197 unsigned int MAGIC;
152 Fash_Int_Map2 *bucket[256]; 198 Fash_Int_Map2 *bucket[256];
153 void (*freeme) (Fash_Int *fash); 199 void (*freeme) (Fash_Int *fash);
154}; 200};
@@ -166,6 +212,7 @@ struct _Fash_Glyph_Map2
166}; 212};
167struct _Fash_Glyph 213struct _Fash_Glyph
168{ 214{
215 unsigned int MAGIC;
169 Fash_Glyph_Map2 *bucket[256]; 216 Fash_Glyph_Map2 *bucket[256];
170 void (*freeme) (Fash_Glyph *fash); 217 void (*freeme) (Fash_Glyph *fash);
171}; 218};
@@ -347,7 +394,7 @@ void *evas_common_font_freetype_face_get(RGBA_Font *font); /* XXX: Not EAPI on p
347 394
348EAPI RGBA_Font_Glyph *evas_common_font_int_cache_glyph_get (RGBA_Font_Int *fi, FT_UInt index); 395EAPI RGBA_Font_Glyph *evas_common_font_int_cache_glyph_get (RGBA_Font_Int *fi, FT_UInt index);
349EAPI Eina_Bool evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg); 396EAPI Eina_Bool evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg);
350EAPI FT_UInt evas_common_get_char_index (RGBA_Font_Int* fi, Eina_Unicode gl); 397EAPI FT_UInt evas_common_get_char_index (RGBA_Font_Int* fi, Eina_Unicode gl, Eina_Unicode variation_sequence);
351 398
352/* load */ 399/* load */
353EAPI void evas_common_font_dpi_set (int dpi_h, int dpi_v); 400EAPI 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
397 444
398EAPI void *evas_common_font_glyph_compress(void *data, int num_grays, int pixel_mode, int pitch_data, int w, int h, int *size_ret); 445EAPI void *evas_common_font_glyph_compress(void *data, int num_grays, int pixel_mode, int pitch_data, int w, int h, int *size_ret);
399EAPI DATA8 *evas_common_font_glyph_uncompress(RGBA_Font_Glyph *fg, int *wret, int *hret); 446EAPI DATA8 *evas_common_font_glyph_uncompress(RGBA_Font_Glyph *fg, int *wret, int *hret);
400EAPI int evas_common_font_glyph_search (RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl); 447EAPI 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);
401 448
402void evas_common_font_load_init(void); 449void evas_common_font_load_init(void);
403void evas_common_font_load_shutdown(void); 450void 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 f2011bd..3aa2070 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)
687 evas_common_font_int_unref(fi); 687 evas_common_font_int_unref(fi);
688 evas_common_font_flush(); 688 evas_common_font_flush();
689 eina_list_free(fn->fonts); 689 eina_list_free(fn->fonts);
690 if (fn->fash) fn->fash->freeme(fn->fash); 690 if (fn->fash)
691 {
692 fn->fash->freeme(fn->fash);
693 fn->fash = NULL;
694 }
691 LKD(fn->lock); 695 LKD(fn->lock);
692 free(fn); 696 free(fn);
693} 697}
diff --git a/src/lib/evas/common/evas_font_main.c b/src/lib/evas/common/evas_font_main.c
index 1a16374..c41e350 100644
--- a/src/lib/evas/common/evas_font_main.c
+++ b/src/lib/evas/common/evas_font_main.c
@@ -355,33 +355,182 @@ end:
355/* Set of common functions that are used in a couple of places. */ 355/* Set of common functions that are used in a couple of places. */
356 356
357static void 357static void
358_fash_int2_free(Fash_Int_Map2 *fash) 358_fash_int_map_and_variations_free(Fash_Int_Map *map)
359{ 359 {
360 if(!map)
361 return;
360 int i; 362 int i;
361 363
362 for (i = 0; i < 256; i++) if (fash->bucket[i]) free(fash->bucket[i]); 364 for (i = 0; i < 256; i++)
363 free(fash); 365 {
366 if (map->items[i].variations)
367 {
368 if (map->items[i].variations->list)
369 {
370 free(map->items[i].variations->list);
371 map->items[i].variations->list = NULL;
372 map->items[i].variations->capacity = 0;
373 map->items[i].variations->length = 0;
374 }
375 free(map->items[i].variations);
376 map->items[i].variations = NULL;
377 }
378 }
379
380 free(map);
381}
382
383static void
384_fash_int2_free(Fash_Int_Map2 *fash)
385 {
386 int i;
387 if (fash)
388 {
389 for (i = 0; i < 256; i++)
390 if (fash->bucket[i])
391 {
392 _fash_int_map_and_variations_free(fash->bucket[i]);
393 fash->bucket[i] = NULL;
394 }
395 free(fash);
396 fash = NULL;
397 }
364} 398}
365 399
366static void 400static void
367_fash_int_free(Fash_Int *fash) 401_fash_int_free(Fash_Int *fash)
368{ 402{
369 int i; 403 int i;
404 if (fash)
405 {
406 if (fash->MAGIC != FASH_INT_MAGIC)
407 {
408 return;
409 }
370 410
371 for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_int2_free(fash->bucket[i]); 411 for (i = 0; i < 256; i++)
372 free(fash); 412 {
413 if (fash->bucket[i])
414 {
415 _fash_int2_free(fash->bucket[i]);
416 fash->bucket[i] = NULL;
417 }
418 }
419 free(fash);
420 }
373} 421}
374 422
375static Fash_Int * 423static Fash_Int *
376_fash_int_new(void) 424_fash_int_new(void)
377{ 425{
378 Fash_Int *fash = calloc(1, sizeof(Fash_Int)); 426 Fash_Int *fash = calloc(1, sizeof(Fash_Int));
427 EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
428 fash->MAGIC = FASH_INT_MAGIC;
379 fash->freeme = _fash_int_free; 429 fash->freeme = _fash_int_free;
380 return fash; 430 return fash;
381} 431}
382 432
433static Fash_Item_variation_List *
434_variations_list_new(void)
435{
436 Fash_Item_variation_List *variations = calloc(1, sizeof(Fash_Item_variation_List));
437 EINA_SAFETY_ON_NULL_RETURN_VAL(variations, NULL);
438 variations->capacity = 0;
439 variations->length = 0;
440 variations->list = 0;
441 return variations;
442}
443
444static void
445_variations_list_add(Fash_Item_variation_List *variations,RGBA_Font_Int *fint, int index, Eina_Unicode variation_sequence)
446{
447 Fash_Item_variation_Index_Item *list = variations->list;
448 if (variations->capacity == variations->length)
449 {
450 list = (Fash_Item_variation_Index_Item *) realloc(list, (variations->capacity + 4) * sizeof(Fash_Item_variation_Index_Item));
451 if (list)
452 {
453 variations->list = list;
454 variations->capacity += 4;
455 }
456 }
457
458 EINA_SAFETY_ON_NULL_RETURN(list);
459
460 int start = 0;
461 int end = variations->length;
462 if (end == 0)
463 {
464 // if only on element just add it in 0 index
465 variations->list[0].item.fint = fint;
466 variations->list[0].item.index = index;
467 variations->list[0].variation_sequence = variation_sequence;
468 variations->length++;
469 }
470 else
471 {
472 // find lower bound
473 while (end > start)
474 {
475 int middle = start + (end - start) / 2;
476 if (variations->list[middle].variation_sequence >= variation_sequence)
477 end = middle;
478 else
479 start = middle + 1;
480 }
481
482 // if passed value founded in list, just replace it
483 if (start < (int)variations->length && variations->list[start].variation_sequence == variation_sequence)
484 {
485 variations->list[start].item.fint = fint;
486 variations->list[start].item.index = index;
487 variations->list[start].variation_sequence = variation_sequence;
488 return;
489 }
490
491 // shift array to insert item
492 for (int i = (variations->length - 1) ; i >= start; i--)
493 {
494 variations->list[i + 1] = variations->list[i];
495 }
496
497 // insert new item and keep array sorted
498 variations->list[start].item.fint = fint;
499 variations->list[start].item.index = index;
500 variations->list[start].variation_sequence = variation_sequence;
501 variations->length++;
502 }
503}
504
505
383static Fash_Item_Index_Map * 506static Fash_Item_Index_Map *
384_fash_int_find(Fash_Int *fash, int item) 507_variations_list_find(Fash_Item_variation_List * variations, Eina_Unicode variation_sequence)
508{
509 if (!variations)
510 return NULL;
511
512 if (!variations->list)
513 return NULL;
514
515 int start = 0;
516 int end = variations->length;
517
518 while(end > start)
519 {
520 int middle = start + (end - start) / 2;
521 if (variations->list[middle].variation_sequence == variation_sequence)
522 return &(variations->list[middle].item);
523 else if (variations->list[middle].variation_sequence < variation_sequence)
524 start = middle + 1;
525 else
526 end = middle - 1;
527 }
528
529 return NULL;
530}
531
532static const Fash_Item_Index_Map *
533_fash_int_find(Fash_Int *fash, int item, Eina_Unicode variation_sequence)
385{ 534{
386 int grp, maj, min; 535 int grp, maj, min;
387 536
@@ -391,14 +540,22 @@ _fash_int_find(Fash_Int *fash, int item)
391 min = item & 0xff; 540 min = item & 0xff;
392 if (!fash->bucket[grp]) return NULL; 541 if (!fash->bucket[grp]) return NULL;
393 if (!fash->bucket[grp]->bucket[maj]) return NULL; 542 if (!fash->bucket[grp]->bucket[maj]) return NULL;
394 return &(fash->bucket[grp]->bucket[maj]->item[min]); 543 if (!variation_sequence)
544 return &(fash->bucket[grp]->bucket[maj]->items[min].item);
545 else
546 return _variations_list_find(fash->bucket[grp]->bucket[maj]->items[min].variations, variation_sequence);
395} 547}
396 548
397static void 549static void
398_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx) 550_fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx, Eina_Unicode variation_sequence)
399{ 551{
400 int grp, maj, min; 552 int grp, maj, min;
401 553
554 // If we already have cached passed item, skip adding it again
555 const Fash_Item_Index_Map *fm = _fash_int_find(fash, item, variation_sequence);
556 if (fm && fm->fint)
557 return;
558
402 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16) 559 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
403 grp = (item >> 16) & 0xff; 560 grp = (item >> 16) & 0xff;
404 maj = (item >> 8) & 0xff; 561 maj = (item >> 8) & 0xff;
@@ -409,8 +566,20 @@ _fash_int_add(Fash_Int *fash, int item, RGBA_Font_Int *fint, int idx)
409 if (!fash->bucket[grp]->bucket[maj]) 566 if (!fash->bucket[grp]->bucket[maj])
410 fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map)); 567 fash->bucket[grp]->bucket[maj] = calloc(1, sizeof(Fash_Int_Map));
411 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]); 568 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]);
412 fash->bucket[grp]->bucket[maj]->item[min].fint = fint; 569 if (variation_sequence)
413 fash->bucket[grp]->bucket[maj]->item[min].index = idx; 570 {
571 if (!fash->bucket[grp]->bucket[maj]->items[min].variations)
572 {
573 fash->bucket[grp]->bucket[maj]->items[min].variations =_variations_list_new();
574 EINA_SAFETY_ON_NULL_RETURN(fash->bucket[grp]->bucket[maj]->items[min].variations);
575 }
576 _variations_list_add(fash->bucket[grp]->bucket[maj]->items[min].variations, fint, idx, variation_sequence);
577 }
578 else
579 {
580 fash->bucket[grp]->bucket[maj]->items[min].item.fint = fint;
581 fash->bucket[grp]->bucket[maj]->items[min].item.index = idx;
582 }
414} 583}
415 584
416static void 585static void
@@ -462,24 +631,45 @@ _fash_gl2_free(Fash_Glyph_Map2 *fash)
462 int i; 631 int i;
463 632
464 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16) 633 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
465 for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_glyph_free(fash->bucket[i]); 634 for (i = 0; i < 256; i++)
635 {
636 if (fash->bucket[i])
637 {
638 _fash_glyph_free(fash->bucket[i]);
639 fash->bucket[i] = NULL;
640 }
641 }
466 free(fash); 642 free(fash);
467} 643}
468 644
469static void 645static void
470_fash_gl_free(Fash_Glyph *fash) 646_fash_gl_free(Fash_Glyph *fash)
471{ 647{
472 int i; 648 if (fash)
649 {
650 if (fash->MAGIC != FASH_GLYPH_MAGIC)
651 return;
473 652
474 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16) 653 int i;
475 for (i = 0; i < 256; i++) if (fash->bucket[i]) _fash_gl2_free(fash->bucket[i]); 654 // 24bits for unicode - v6 up to E01EF (chrs) & 10FFFD for private use (plane 16)
476 free(fash); 655 for (i = 0; i < 256; i++)
656 {
657 if (fash->bucket[i])
658 {
659 _fash_gl2_free(fash->bucket[i]);
660 fash->bucket[i] = NULL;
661 }
662 }
663 free(fash);
664 }
477} 665}
478 666
479static Fash_Glyph * 667static Fash_Glyph *
480_fash_gl_new(void) 668_fash_gl_new(void)
481{ 669{
482 Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph)); 670 Fash_Glyph *fash = calloc(1, sizeof(Fash_Glyph));
671 EINA_SAFETY_ON_NULL_RETURN_VAL(fash, NULL);
672 fash->MAGIC = FASH_GLYPH_MAGIC;
483 fash->freeme = _fash_gl_free; 673 fash->freeme = _fash_gl_free;
484 return fash; 674 return fash;
485} 675}
@@ -680,7 +870,7 @@ struct _Font_Char_Index
680}; 870};
681 871
682EAPI FT_UInt 872EAPI FT_UInt
683evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl) 873evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl, Eina_Unicode variation_sequence)
684{ 874{
685 static const unsigned short mapfix[] = 875 static const unsigned short mapfix[] =
686 { 876 {
@@ -742,7 +932,10 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
742 * that something else try to use it. 932 * that something else try to use it.
743 */ 933 */
744 /* FTLOCK(); */ 934 /* FTLOCK(); */
745 result.index = FT_Get_Char_Index(fi->src->ft.face, gl); 935 if (variation_sequence)
936 result.index = FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, variation_sequence);
937 else
938 result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
746 /* FTUNLOCK(); */ 939 /* FTUNLOCK(); */
747 result.gl = gl; 940 result.gl = gl;
748 941
@@ -774,7 +967,10 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
774 { 967 {
775 gl = mapfix[(i << 1) + 1]; 968 gl = mapfix[(i << 1) + 1];
776 FTLOCK(); 969 FTLOCK();
777 result.index = FT_Get_Char_Index(fi->src->ft.face, gl); 970 if (variation_sequence)
971 result.index = FT_Face_GetCharVariantIndex(fi->src->ft.face, gl, variation_sequence);
972 else
973 result.index = FT_Get_Char_Index(fi->src->ft.face, gl);
778 FTUNLOCK(); 974 FTUNLOCK();
779 break; 975 break;
780 } 976 }
@@ -799,20 +995,49 @@ evas_common_get_char_index(RGBA_Font_Int* fi, Eina_Unicode gl)
799 return result.index; 995 return result.index;
800} 996}
801 997
998
999/*
1000 * @internal
1001 * Search for unicode glyph inside all font files, and return font and glyph index
1002 *
1003 * @param[in] fn the font to use.
1004 * @param[out] fi_ret founded font.
1005 * @param[in] gl unicode glyph to search for
1006 * @param[in] variation_sequence for the gl glyph
1007 * @param[in] evas_font_search_options search options when searching font files
1008 *
1009 */
1010
802EAPI int 1011EAPI int
803evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl) 1012evas_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)
804{ 1013{
805 Eina_List *l; 1014 Eina_List *l;
806 1015
807 if (fn->fash) 1016 if (fn->fash)
808 { 1017 {
809 Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl); 1018 const Fash_Item_Index_Map *fm = _fash_int_find(fn->fash, gl, variation_sequence);
810 if (fm) 1019 if (fm)
811 { 1020 {
812 if (fm->fint) 1021 if (fm->fint)
813 { 1022 {
814 *fi_ret = fm->fint; 1023 if (evas_font_search_options == EVAS_FONT_SEARCH_OPTION_NONE)
815 return fm->index; 1024 {
1025 *fi_ret = fm->fint;
1026 return fm->index;
1027 }
1028 else if( (evas_font_search_options & EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR)
1029 {
1030 if (!fm->fint->src->ft.face)
1031 {
1032 evas_common_font_int_reload(fm->fint);
1033 }
1034
1035 if (fm->fint->src->ft.face && !FT_HAS_COLOR(fm->fint->src->ft.face))
1036 {
1037 *fi_ret = fm->fint;
1038 return fm->index;
1039 }
1040 }
816 } 1041 }
817 else if (fm->index == -1) return 0; 1042 else if (fm->index == -1) return 0;
818 } 1043 }
@@ -851,20 +1076,35 @@ evas_common_font_glyph_search(RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicod
851 } 1076 }
852 if (fi->src->ft.face) 1077 if (fi->src->ft.face)
853 { 1078 {
854 idx = evas_common_get_char_index(fi, gl); 1079 Eina_Bool is_color_only = (evas_font_search_options & EVAS_FONT_SEARCH_OPTION_SKIP_COLOR) == EVAS_FONT_SEARCH_OPTION_SKIP_COLOR &&
1080 FT_HAS_COLOR(fi->src->ft.face);
1081
1082 if (is_color_only)
1083 {
1084 /* This is color font ignore it */
1085 continue;
1086 }
1087
1088 idx = (int) evas_common_get_char_index(fi, gl, variation_sequence);
855 if (idx != 0) 1089 if (idx != 0)
856 { 1090 {
857 if (!fi->ft.size) 1091 if (!fi->ft.size)
858 evas_common_font_int_load_complete(fi); 1092 evas_common_font_int_load_complete(fi);
859 if (!fn->fash) fn->fash = _fash_int_new(); 1093 if (!is_color_only)
860 if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx); 1094 {
1095 if (!fn->fash) fn->fash = _fash_int_new();
1096 if (fn->fash) _fash_int_add(fn->fash, gl, fi, idx, variation_sequence);
1097 }
861 *fi_ret = fi; 1098 *fi_ret = fi;
862 return idx; 1099 return idx;
863 } 1100 }
864 else 1101 else
865 { 1102 {
866 if (!fn->fash) fn->fash = _fash_int_new(); 1103 if (!is_color_only)
867 if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1); 1104 {
1105 if (!fn->fash) fn->fash = _fash_int_new();
1106 if (fn->fash) _fash_int_add(fn->fash, gl, NULL, -1, variation_sequence);
1107 }
868 } 1108 }
869 } 1109 }
870 } 1110 }
diff --git a/src/lib/evas/common/evas_font_query.c b/src/lib/evas/common/evas_font_query.c
index 1ff0447..7b50a74 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
32 (evas_common_language_char_script_get(*base_char) != script) ; 32 (evas_common_language_char_script_get(*base_char) != script) ;
33 base_char++) 33 base_char++)
34 ; 34 ;
35 /* If counter reach variation sequence it is safe to pick default font */
36 if(VAR_SEQ(*base_char) || (base_char != run_end && VAR_SEQ(*(base_char+1)))) goto get_top_font;
37
35 if (base_char == run_end) base_char = text; 38 if (base_char == run_end) base_char = text;
36 39
37 /* Find the first renderable char */ 40 /* 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
40 /* 0x1F is the last ASCII contral char, just a hack in 43 /* 0x1F is the last ASCII contral char, just a hack in
41 * the meanwhile. */ 44 * the meanwhile. */
42 if ((*base_char > 0x1F) && 45 if ((*base_char > 0x1F) &&
43 evas_common_font_glyph_search(fn, &fi, *base_char)) 46 evas_common_font_glyph_search(fn, &fi, *base_char, 0, EVAS_FONT_SEARCH_OPTION_NONE))
44 break; 47 break;
45 base_char++; 48 base_char++;
46 } 49 }
@@ -49,7 +52,8 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
49 /* If everything else fails, at least try to find a font for the 52 /* If everything else fails, at least try to find a font for the
50 * replacement char */ 53 * replacement char */
51 if (base_char == run_end) 54 if (base_char == run_end)
52 evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR); 55 evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR, 0, EVAS_FONT_SEARCH_OPTION_NONE);
56get_top_font:
53 57
54 if (!fi) 58 if (!fi)
55 fi = fn->fonts->data; 59 fi = fn->fonts->data;
@@ -80,15 +84,17 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
80 if (evas_common_language_char_script_get(*itr) == EVAS_SCRIPT_INHERITED) 84 if (evas_common_language_char_script_get(*itr) == EVAS_SCRIPT_INHERITED)
81 continue; 85 continue;
82 86
87 Eina_Unicode variation_sequence = VAR_SEQ(*(itr+1));
88
83 /* Break if either it's not in the font, or if it is in the 89 /* Break if either it's not in the font, or if it is in the
84 * script's font. */ 90 * script's font. */
85 if (!evas_common_get_char_index(fi, *itr)) 91 if (!evas_common_get_char_index(fi, *itr, variation_sequence))
86 break; 92 break;
87 93
88 if (fi != *script_fi) 94 if (fi != *script_fi)
89 { 95 {
90 if (evas_common_get_char_index(*script_fi, *itr)) 96 if (evas_common_get_char_index(*script_fi, *itr, variation_sequence))
91 break; 97 break;
92 } 98 }
93 } 99 }
94 100
@@ -102,10 +108,25 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
102 /* If we can find a font, use it. Otherwise, find the first 108 /* If we can find a font, use it. Otherwise, find the first
103 * char the run of chars that can't be rendered until the first 109 * char the run of chars that can't be rendered until the first
104 * one that can. */ 110 * one that can. */
105 if (evas_common_font_glyph_search(fn, &tmp_fi, *itr)) 111 Eina_Unicode variation_sequence = VAR_SEQ(*(itr+1));
112 if (evas_common_font_glyph_search(fn, &tmp_fi, *itr, variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE))
106 { 113 {
107 fi = tmp_fi; 114 fi = tmp_fi;
108 } 115 }
116 else if ( (variation_sequence == VARIATION_TEXT_PRESENTATION) && evas_common_font_glyph_search(fn, &tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_SKIP_COLOR))
117 {
118 /* If we can not find unicode with variation sequence, then we will
119 Search and find for non color glyph because variation sequence is Text
120 */
121 fi = tmp_fi;
122 }
123 else if ( variation_sequence && evas_common_font_glyph_search(fn, &tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_NONE))
124 {
125 /* If we can not find unicode with variation sequence, then we will
126 Search and find glyph without the variation sequence
127 */
128 fi = tmp_fi;
129 }
109 else 130 else
110 { 131 {
111 itr++; 132 itr++;
@@ -113,9 +134,13 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
113 * font */ 134 * font */
114 for ( ; itr < run_end ; itr++) 135 for ( ; itr < run_end ; itr++)
115 { 136 {
137 if(VAR_SEQ(*itr))
138 continue;
139
140 Eina_Unicode variation_sequence = VAR_SEQ(*(itr+1));
116 tmp_fi = fi; 141 tmp_fi = fi;
117 if (evas_common_get_char_index(fi, *itr) || 142 if (evas_common_get_char_index(fi, *itr, variation_sequence) ||
118 evas_common_font_glyph_search(fn, &tmp_fi, *itr)) 143 evas_common_font_glyph_search(fn, &tmp_fi, *itr, variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE))
119 { 144 {
120 fi = tmp_fi; 145 fi = tmp_fi;
121 break; 146 break;
@@ -127,9 +152,9 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
127 * find a font most suitable for the replacement char and 152 * find a font most suitable for the replacement char and
128 * break */ 153 * break */
129 if ((itr == run_end) || 154 if ((itr == run_end) ||
130 !evas_common_get_char_index(fi, REPLACEMENT_CHAR)) 155 !evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0))
131 { 156 {
132 evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR); 157 evas_common_font_glyph_search(fn, &fi, REPLACEMENT_CHAR, 0, EVAS_FONT_SEARCH_OPTION_NONE);
133 break; 158 break;
134 } 159 }
135 } 160 }
@@ -140,8 +165,11 @@ evas_common_font_query_run_font_end_get(RGBA_Font *fn, RGBA_Font_Int **script_fi
140 /* If this char is not renderable by any font, but the replacement 165 /* If this char is not renderable by any font, but the replacement
141 * char can be rendered using the currentfont, continue this 166 * char can be rendered using the currentfont, continue this
142 * run. */ 167 * run. */
143 if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr) && 168 Eina_Unicode variation_sequence = VAR_SEQ(*(itr+1));
144 evas_common_get_char_index(fi, REPLACEMENT_CHAR)) 169
170 if (!evas_common_font_glyph_search(fn, &tmp_fi, *itr, variation_sequence, EVAS_FONT_SEARCH_OPTION_NONE) &&
171 (variation_sequence ? !evas_common_font_glyph_search(fn, &tmp_fi, *itr, 0, EVAS_FONT_SEARCH_OPTION_NONE) : 1) &&
172 evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0))
145 { 173 {
146 itr++; 174 itr++;
147 } 175 }
diff --git a/src/lib/evas/common/evas_text_utils.c b/src/lib/evas/common/evas_text_utils.c
index e9c5cc2..acf7cf8 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,
1066 /* If we got a malformed index, show the replacement char instead */ 1066 /* If we got a malformed index, show the replacement char instead */
1067 if (gl_itr->index == 0) 1067 if (gl_itr->index == 0)
1068 { 1068 {
1069 gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR); 1069 gl_itr->index = evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0);
1070 is_replacement = EINA_TRUE; 1070 is_replacement = EINA_TRUE;
1071 } 1071 }
1072 idx = gl_itr->index; 1072 idx = gl_itr->index;
@@ -1172,10 +1172,10 @@ _content_create_regular(RGBA_Font_Int *fi, const Eina_Unicode *text,
1172 _gl = *text; 1172 _gl = *text;
1173 if (_gl == 0) break; 1173 if (_gl == 0) break;
1174 1174
1175 idx = evas_common_get_char_index(fi, _gl); 1175 idx = evas_common_get_char_index(fi, _gl, 0);
1176 if (idx == 0) 1176 if (idx == 0)
1177 { 1177 {
1178 idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR); 1178 idx = evas_common_get_char_index(fi, REPLACEMENT_CHAR, 0);
1179 } 1179 }
1180 1180
1181 fg = evas_common_font_int_cache_glyph_get(fi, idx); 1181 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 f61574c..2db6888 100644
--- a/src/tests/evas/evas_test_textblock.c
+++ b/src/tests/evas/evas_test_textblock.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * TODO: 2 * TODO:
3 * * Test different font lodaing mechanisms. 3 * * Test different font loading mechanisms.
4 */ 4 */
5 5
6#ifdef HAVE_CONFIG_H 6#ifdef HAVE_CONFIG_H
@@ -4129,6 +4129,23 @@ EFL_START_TEST(evas_textblock_obstacle)
4129} 4129}
4130EFL_END_TEST; 4130EFL_END_TEST;
4131 4131
4132EFL_START_TEST(evas_textblock_variation_sequence)
4133{
4134 START_TB_TEST();
4135 evas_font_path_global_prepend("..");
4136 const char *str1 = "8&#xfe0f;&#x262a;&#xfe0f;";
4137 const char *str2 = "8&#xfe0e;&#x262a;&#xfe0e;";
4138 Evas_Coord fw, fh,fw_new, fh_new;
4139 evas_object_textblock_text_markup_set(tb, str1);
4140 evas_object_textblock_size_formatted_get(tb, &fw, &fh);
4141 evas_object_textblock_text_markup_set(tb, str2);
4142 evas_object_textblock_size_formatted_get(tb, &fw_new, &fh_new);
4143 fail_if(fw_new == fw && fh_new == fh);
4144
4145 END_TB_TEST();
4146}
4147EFL_END_TEST;
4148
4132#ifdef HAVE_HYPHEN 4149#ifdef HAVE_HYPHEN
4133static void 4150static void
4134_hyphenation_width_stress(Evas_Object *tb, Evas_Textblock_Cursor *cur) 4151_hyphenation_width_stress(Evas_Object *tb, Evas_Textblock_Cursor *cur)
@@ -4729,6 +4746,7 @@ void evas_test_textblock(TCase *tc)
4729 tcase_add_test(tc, evas_textblock_items); 4746 tcase_add_test(tc, evas_textblock_items);
4730 tcase_add_test(tc, evas_textblock_delete); 4747 tcase_add_test(tc, evas_textblock_delete);
4731 tcase_add_test(tc, evas_textblock_obstacle); 4748 tcase_add_test(tc, evas_textblock_obstacle);
4749 tcase_add_test(tc, evas_textblock_variation_sequence);
4732#ifdef HAVE_HYPHEN 4750#ifdef HAVE_HYPHEN
4733 tcase_add_test(tc, evas_textblock_hyphenation); 4751 tcase_add_test(tc, evas_textblock_hyphenation);
4734#endif 4752#endif
diff --git a/src/tests/evas/fonts/NotoColorEmoji.ttf b/src/tests/evas/fonts/NotoColorEmoji.ttf
new file mode 100644
index 0000000..69cf21a
--- /dev/null
+++ b/src/tests/evas/fonts/NotoColorEmoji.ttf
Binary files differ
diff --git a/src/tests/evas/fonts/NotoEmoji-Regular.ttf b/src/tests/evas/fonts/NotoEmoji-Regular.ttf
new file mode 100644
index 0000000..19b7bad
--- /dev/null
+++ b/src/tests/evas/fonts/NotoEmoji-Regular.ttf
Binary files differ