diff --git a/src/lib/edje/Edje_Legacy.h b/src/lib/edje/Edje_Legacy.h index af89a4939c..f36cb53953 100644 --- a/src/lib/edje/Edje_Legacy.h +++ b/src/lib/edje/Edje_Legacy.h @@ -3146,6 +3146,44 @@ EAPI void edje_object_perspective_set(Evas_Object *obj, Edje_Perspective *ps); */ EAPI const Edje_Perspective *edje_object_perspective_get(const Evas_Object *obj); +/** + * @brief Sets Edje text class for edje file (if loaded) + * + * This function sets the text class for All Edje Objects created from Edje file. + * (if edje file loaded before) + * + * @param[in] file edje file path + * @param[in] text_class The text class name + * @param[in] font Font name + * @param[in] size Font Size + * + * @return @c true, on success or @c false, on error + */ +EAPI Eina_Bool edje_file_text_class_set(const char *file, const char *text_class, const char *font, Evas_Font_Size size); + +/** + * @brief Delete the file text class. + * + * This function deletes any values at the file level for the specified + * file and text class. + * + * @param[in] text_class The text class to be deleted. + */ +EAPI Eina_Bool edje_file_text_class_del(const char *file, const char *text_class); + +/** + * @brief Gets font and font size from edje file if loaded. + * + * This function gets the font and the font size from the file text class. + * + * @param[in] text_class The text class name + * @param[out] font Font name + * @param[out] size Font Size + * + * @return @c true, on success or @c false, on error + */ +EAPI Eina_Bool edje_file_text_class_get(const char *file, const char * text_class, const char **font, Evas_Font_Size *size); + /** * @} */ diff --git a/src/lib/edje/edje_cache.c b/src/lib/edje/edje_cache.c index 64eb6ad5ec..e58584cba4 100644 --- a/src/lib/edje/edje_cache.c +++ b/src/lib/edje/edje_cache.c @@ -600,8 +600,13 @@ _edje_file_open(const Eina_File *f, int *error_ret, time_t mtime, Eina_Bool coll edf->text_hash = eina_hash_string_small_new(NULL); EINA_LIST_FOREACH(edf->text_classes, l, tc) - if (tc->name) - eina_hash_direct_add(edf->text_hash, tc->name, tc); + { + if (tc->name) + eina_hash_direct_add(edf->text_hash, tc->name, tc); + + if (tc->font) + tc->font = eina_stringshare_add(tc->font); + } edf->size_hash = eina_hash_string_small_new(NULL); EINA_LIST_FOREACH(edf->size_classes, l, sc) @@ -713,7 +718,7 @@ _edje_file_cache_trash_pop(const Eina_File *file) return NULL; } -static inline Edje_File* +Edje_File* _edje_file_cache_find(const Eina_File *file) { Edje_File *edf; diff --git a/src/lib/edje/edje_load.c b/src/lib/edje/edje_load.c index 92713a2325..0e74db9fca 100644 --- a/src/lib/edje/edje_load.c +++ b/src/lib/edje/edje_load.c @@ -2081,6 +2081,7 @@ _edje_file_del(Edje *ed) _edje_text_part_on_del(ed, ep); _edje_color_class_on_del(ed, ep); } + _edje_object_textblock_styles_cache_cleanup(ed); _edje_cache_coll_unref(ed->file, ed->collection); ed->collection = NULL; diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index 9a293e2e33..9abbb50962 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -1723,6 +1723,7 @@ struct _Edje Eina_List *groups; + Eina_Hash *styles; Edje_Perspective *persp; Ecore_Animator *animator; @@ -2802,14 +2803,17 @@ void _edje_message_del (Edje *ed); Evas_Textblock_Style * _edje_textblock_style_get(Edje *ed, const char *style); void _edje_textblock_styles_add(Edje *ed, Edje_Real_Part *ep); void _edje_textblock_styles_del(Edje *ed, Edje_Part *pt); +void _edje_object_textblock_style_all_update_text_class(Edje *ed, const char *text_class); +void _edje_object_textblock_styles_cache_cleanup(Edje *ed); // Edje File level textblock style api void _edje_file_textblock_style_all_update(Edje_File *ed); -void _edje_file_textblock_style_all_update_text_class(Edje_File *edf, const char *text_class); +void _edje_file_textblock_styles_all_update_text_class(Edje *ed, const char *text_class); void _edje_file_textblock_style_parse_and_fix(Edje_File *edf); void _edje_file_textblock_style_cleanup(Edje_File *edf); Edje_File *_edje_cache_file_coll_open(const Eina_File *file, const char *coll, int *error_ret, Edje_Part_Collection **edc_ret, Edje *ed); +Edje_File *_edje_file_cache_find(const Eina_File *file); void _edje_cache_coll_clean(Edje_File *edf); void _edje_cache_coll_flush(Edje_File *edf); void _edje_cache_coll_unref(Edje_File *edf, Edje_Part_Collection *edc); diff --git a/src/lib/edje/edje_smart.c b/src/lib/edje/edje_smart.c index f8d42d9069..d0d794790b 100644 --- a/src/lib/edje/edje_smart.c +++ b/src/lib/edje/edje_smart.c @@ -504,7 +504,12 @@ _efl_canvas_layout_efl_observer_update(Eo *obj EINA_UNUSED, Edje *ed, Efl_Object } else if (obs == _edje_text_class_member) { - _edje_file_textblock_style_all_update_text_class(ed->file, key); + if (data == ed) + // Object level update + _edje_object_textblock_style_all_update_text_class(ed, key); + else if ((data == ed->file) || // File level update will pass ed->file + (!data)) // Global update will pass NULL + _edje_file_textblock_styles_all_update_text_class(ed, key); #ifdef EDJE_CALC_CACHE ed->text_part_change = EINA_TRUE; #endif diff --git a/src/lib/edje/edje_textblock_styles.c b/src/lib/edje/edje_textblock_styles.c index 3618d201c4..0eec7bca80 100644 --- a/src/lib/edje/edje_textblock_styles.c +++ b/src/lib/edje/edje_textblock_styles.c @@ -1,5 +1,72 @@ #include "edje_private.h" +void _edje_textblock_style_update(Edje *ed, Edje_Style *stl); + +static Edje_Style * +_edje_textblock_style_copy(Edje_Style *stl) +{ + Edje_Style *new_stl; + + new_stl = calloc(1, sizeof(Edje_Style)); + if (!new_stl) return NULL; + + new_stl->style = evas_textblock_style_new(); + evas_textblock_style_set(new_stl->style, NULL); + + // just keep a reference. + new_stl->tags = stl->tags; + new_stl->name = stl->name; + new_stl->cache = EINA_FALSE; + + return new_stl; +} + +static void +_edje_object_textblock_styles_cache_style_free(void *data) +{ + Edje_Style *obj_stl = data; + + if (!obj_stl) return; + + if (obj_stl->style) evas_textblock_style_free(obj_stl->style); + free(obj_stl); +} + +static Edje_Style * +_edje_object_textblock_styles_cache_add(Edje *ed, Edje_Style *stl) +{ + Edje_Style *obj_stl = eina_hash_find(ed->styles, stl->name); + // Find the style in the object cache + + if (!obj_stl) + { + obj_stl = _edje_textblock_style_copy(stl); + + if (obj_stl) + { + if (!ed->styles) ed->styles = eina_hash_stringshared_new(_edje_object_textblock_styles_cache_style_free); + eina_hash_direct_add(ed->styles, obj_stl->name, obj_stl); + _edje_textblock_style_update(ed, obj_stl); + } + } + return obj_stl; +} + +void +_edje_object_textblock_styles_cache_cleanup(Edje *ed) +{ + if (!ed || !ed->styles) return; + eina_hash_free(ed->styles); + ed->styles = NULL; +} + +static Edje_Style * +_edje_object_textblock_styles_cache_get(Edje *ed, const char *stl) +{ + // Find the style in the object cache + return eina_hash_find(ed->styles, stl); +} + static int _edje_font_is_embedded(Edje_File *edf, const char *font) { @@ -230,26 +297,6 @@ _edje_textblock_style_update(Edje *ed, Edje_Style *stl) eina_strbuf_free(txt); } -/* - * mark all the styles in the Edje_File dirty (except readonly styles)so that - * subsequent request to style will update before giving the style. - * Note: this will enable lazy style computation (only when some - * widget request for new style it will get computed). - * - * @param ed The edje containing styles which need to be updated - */ -void -_edje_file_textblock_style_all_update(Edje_File *edf) -{ - Eina_List *l; - Edje_Style *stl; - - if (!edf) return; - - EINA_LIST_FOREACH(edf->styles, l, stl) - if (stl && !stl->readonly) stl->cache = EINA_FALSE; -} - static inline Edje_Style * _edje_textblock_style_search(Edje *ed, const char *style) { @@ -371,9 +418,18 @@ _edje_textblock_styles_del(Edje *ed, Edje_Part *pt) Evas_Textblock_Style * _edje_textblock_style_get(Edje *ed, const char *style) { + Edje_Style *stl; + if (!style) return NULL; - Edje_Style *stl = _edje_textblock_style_search(ed, style); + // First search in Edje_Object styles list + stl = _edje_object_textblock_styles_cache_get(ed, style); + + if (!stl) + { + // If not found in Edje_Object search in Edje_File styles list + stl = _edje_textblock_style_search(ed, style); + } if (!stl) return NULL; @@ -387,19 +443,21 @@ _edje_textblock_style_get(Edje *ed, const char *style) return stl->style; } -/* - * Finds all the styles having text class tag as text_class and - * updates them. - */ -void -_edje_file_textblock_style_all_update_text_class(Edje_File *edf, const char *text_class) +static void +_edje_textblock_style_all_update_text_class(Edje *ed, const char *text_class, Eina_Bool is_object_level) { - Eina_List *l, *ll; + Eina_List *ll, *l; Edje_Style *stl; + Edje_Style *obj_stl; + Edje_File *edf; - if (!edf) return; + if (!ed) return; + if (!ed->file) return; if (!text_class) return; + edf = ed->file; + + // check if there is styles in file that uses this text_class EINA_LIST_FOREACH(edf->styles, l, stl) { Edje_Style_Tag *tag; @@ -412,15 +470,49 @@ _edje_file_textblock_style_all_update_text_class(Edje_File *edf, const char *tex if (!strcmp(tag->text_class, text_class)) { - // just mark it dirty so the next request - // for this style will trigger recomputation. - stl->cache = EINA_FALSE; + if (is_object_level) + { + obj_stl = _edje_object_textblock_styles_cache_get(ed, stl->name); + if (obj_stl) + // If already in Edje styles just make it dirty + obj_stl->cache = EINA_FALSE; + else + // create a copy from it if it's not exists + _edje_object_textblock_styles_cache_add(ed, stl); + } + else + { + // just mark it dirty so the next request + // for this style will trigger recomputation. + stl->cache = EINA_FALSE; + } + // don't need to continue searching break; } } } } +/* + * Finds all the styles having text class tag as text_class and + * updates them in object level. + */ +void +_edje_object_textblock_style_all_update_text_class(Edje *ed, const char *text_class) +{ + _edje_textblock_style_all_update_text_class(ed, text_class, EINA_TRUE); +} + +/* + * Finds all the styles having text class tag as text_class and + * updates them in file level. + */ +void +_edje_file_textblock_styles_all_update_text_class(Edje *ed, const char *text_class) +{ + _edje_textblock_style_all_update_text_class(ed, text_class, EINA_FALSE); +} + /* When we get to here the edje file had been read into memory * the name of the style is established as well as the name and * data for the tags. This function will create the Evas_Style diff --git a/src/lib/edje/edje_util.c b/src/lib/edje/edje_util.c index f699f835ff..0e6bc3e9ba 100644 --- a/src/lib/edje/edje_util.c +++ b/src/lib/edje/edje_util.c @@ -1336,6 +1336,140 @@ _edje_text_class_list_foreach(const Eina_Hash *hash EINA_UNUSED, const void *key return EINA_TRUE; } +static Edje_File * +_edje_file_find(const char *file) +{ + char *tmp = NULL; + Eina_File *f = NULL; + Edje_File *edf = NULL; + + if (!file) return NULL; + + tmp = eina_vpath_resolve(file); + if (!tmp) return NULL; + + f = eina_file_open(tmp, EINA_FALSE); + + if (tmp) free(tmp); + if (!f) return NULL; + + edf = _edje_file_cache_find(f); + + eina_file_close(f); + return edf; +} + +EAPI Eina_Bool +edje_file_text_class_get(const char *file, const char * text_class, const char **font, Evas_Font_Size *size) +{ + Edje_Text_Class *tc = NULL; + Edje_File *edf = NULL; + Eina_Bool ret = EINA_FALSE; + + if (font) *font = NULL; + if (size) *size = 0; + + if ((!file) || (!text_class)) return ret; + if ((!font) && (!size)) return ret; // No need to go deep + + edf = _edje_file_find(file); + if (!edf) return ret; + + tc = eina_hash_find(edf->text_hash, text_class); + if (!tc) goto end; + + if (font) *font = tc->font; + if (size) *size = tc->size; + ret = EINA_TRUE; + +end: + _edje_cache_file_unref(edf); + return ret; +} + +EAPI Eina_Bool +edje_file_text_class_del(const char *file, const char *text_class) +{ + Edje_Text_Class *tc = NULL; + Edje_File *edf = NULL; + Eina_Bool ret = EINA_FALSE; + if ((!file) || (!text_class)) return ret; + + edf = _edje_file_find(file); + if (!edf) return ret; + + tc = eina_hash_find(edf->text_hash, text_class); + if (!tc) goto end; + + eina_hash_del(edf->text_hash, text_class, tc); + eina_stringshare_del(tc->name); + eina_stringshare_del(tc->font); + free(tc); + + /* Tell all members of the text class to recalc */ + efl_observable_observers_update(_edje_text_class_member, text_class, edf); + + ret = EINA_TRUE; +end: + _edje_cache_file_unref(edf); + return ret; +} + +EAPI Eina_Bool +edje_file_text_class_set(const char *file, const char *text_class, const char *font, Evas_Font_Size size) +{ + Edje_File *edf = NULL; + Edje_Text_Class *tc = NULL; + Eina_Bool ret = EINA_FALSE; + + if ((!file) || (!text_class)) return ret; + + edf = _edje_file_find(file); + if (!edf) return ret; + + // update text_class properties, or create new text_class if not found + if (edf->text_hash) tc = eina_hash_find(edf->text_hash, text_class); + if (!tc) + { + /* Create new text class */ + tc = calloc(1, sizeof(Edje_Text_Class)); + if (!tc) goto error_end; + tc->name = eina_stringshare_add(text_class); + if (!tc->name) + { + free(tc); + goto error_end; + } + if (!edf->text_hash) edf->text_hash = eina_hash_string_small_new(NULL); + eina_hash_direct_add(edf->text_hash, text_class, tc); + + tc->font = eina_stringshare_add(font); + tc->size = size; + } + else + { + /* Match and the same, return */ + if (((tc->font && font) && !strcmp(tc->font, font)) && + (tc->size == size)) + goto success_end; + + /* Update the class found */ + eina_stringshare_replace(&tc->font, font); + tc->size = size; + } + + + /* Tell all members of the text class to recalc */ + efl_observable_observers_update(_edje_text_class_member, text_class, edf); + +success_end: + ret = EINA_TRUE; + +error_end: + _edje_cache_file_unref(edf); + return ret; +} + EAPI Eina_Bool edje_object_text_class_set(Evas_Object *obj, const char *text_class, const char *font, Evas_Font_Size size) { @@ -1401,7 +1535,7 @@ _efl_canvas_layout_efl_gfx_text_class_text_class_set(Eo *obj EINA_UNUSED, Edje * text_class, font, size); } - efl_observer_update(obj, _edje_text_class_member, text_class, NULL); + efl_observer_update(obj, _edje_text_class_member, text_class, ed); return EINA_TRUE; } @@ -1460,7 +1594,7 @@ _efl_canvas_layout_efl_gfx_text_class_text_class_del(Eo *obj EINA_UNUSED, Edje * efl_gfx_text_class_del(rp->typedata.swallow->swallowed_object, text_class); } - efl_observer_update(obj, _edje_text_class_member, text_class, NULL); + efl_observer_update(obj, _edje_text_class_member, text_class, ed); } typedef struct _Edje_File_Text_Class_Iterator Edje_File_Text_Class_Iterator; @@ -5828,24 +5962,28 @@ _edje_color_class_on_del(Edje *ed, Edje_Part *ep) Edje_Text_Class * _edje_text_class_find(Edje *ed, const char *text_class) { - Edje_Text_Class *tc; + Edje_Text_Class *tc = NULL; - if ((!ed) || (!text_class)) return NULL; + if (!text_class) return NULL; + + if (!ed) + { + /* If ed object is NULL, then look through the global scope only */ + return eina_hash_find(_edje_text_class_hash, text_class); + } /* first look through the object scope */ tc = eina_hash_find(ed->text_classes, text_class); - if (tc) return tc; - + /* next look through the global scope */ - tc = eina_hash_find(_edje_text_class_hash, text_class); - if (tc) return tc; + if (!tc) + tc = eina_hash_find(_edje_text_class_hash, text_class); /* finally, look through the file scope */ - if (ed->file) + if (!tc && ed->file) tc = eina_hash_find(ed->file->text_hash, text_class); - if (tc) return tc; - return NULL; + return tc; } static Eina_Bool diff --git a/src/tests/elementary/elm_test_entry.c b/src/tests/elementary/elm_test_entry.c index 1b383b2936..4655a688ba 100644 --- a/src/tests/elementary/elm_test_entry.c +++ b/src/tests/elementary/elm_test_entry.c @@ -518,6 +518,78 @@ EFL_START_TEST(elm_entry_file_get_set) } EFL_END_TEST +EFL_START_TEST(elm_entry_test_text_class) +{ + Evas_Object *win, *entry1, *entry2, *entry3, *entry4; + const char *filename = NULL; + int w1 = 0, h1 = 0, w2 = 0, h2 = 0, w3 = 0, h3 = 0; + const char *font; + int font_size; + + win = win_add(NULL, "entry", ELM_WIN_BASIC); + entry1 = elm_entry_add(win); + entry2 = elm_entry_add(win); + entry3 = elm_entry_add(win); + + elm_object_text_set(entry1, "hello"); + elm_object_text_set(entry2, "hello"); + elm_object_text_set(entry3, "hello"); + + edje_object_file_get(elm_layout_edje_get(entry1), &filename, NULL); + ck_assert(filename != NULL); + + ck_assert(edje_file_text_class_set(filename, "entry_text", "Serif:Style=Bold", 24)); + + ck_assert(edje_object_text_class_get(elm_layout_edje_get(entry1), "entry_text", &font, &font_size)); + ck_assert_int_eq(font_size, 24); + ck_assert_str_eq(font, "Serif:Style=Bold"); + ck_assert(edje_object_text_class_get(elm_layout_edje_get(entry2), "entry_text", &font, &font_size)); + ck_assert_int_eq(font_size, 24); + ck_assert_str_eq(font, "Serif:Style=Bold"); + ck_assert(edje_object_text_class_get(elm_layout_edje_get(entry3), "entry_text", &font, &font_size)); + ck_assert_int_eq(font_size, 24); + ck_assert_str_eq(font, "Serif:Style=Bold"); + + evas_object_textblock_size_formatted_get(elm_entry_textblock_get(entry1), &w1, &h1); + evas_object_textblock_size_formatted_get(elm_entry_textblock_get(entry2), &w2, &h2); + evas_object_textblock_size_formatted_get(elm_entry_textblock_get(entry3), &w3, &h3); + + ck_assert_int_eq(w1, w2); + ck_assert_int_eq(h1, h2); + ck_assert_int_eq(w2, w3); + ck_assert_int_eq(h2, h3); + + ck_assert(edje_object_text_class_set(elm_layout_edje_get(entry1), "entry_text", "Sans", 50)); + ck_assert(edje_object_text_class_set(elm_layout_edje_get(entry2), "entry_text", "Serif", 20)); + + ck_assert(edje_object_text_class_get(elm_layout_edje_get(entry1), "entry_text", &font, &font_size)); + ck_assert_int_eq(font_size, 50); + ck_assert_str_eq(font, "Sans"); + ck_assert(edje_object_text_class_get(elm_layout_edje_get(entry2), "entry_text", &font, &font_size)); + ck_assert_int_eq(font_size, 20); + ck_assert_str_eq(font, "Serif"); + ck_assert(edje_object_text_class_get(elm_layout_edje_get(entry3), "entry_text", &font, &font_size)); + ck_assert_int_eq(font_size, 24); + ck_assert_str_eq(font, "Serif:Style=Bold"); + + evas_object_textblock_size_formatted_get(elm_entry_textblock_get(entry1), &w1, &h1); + evas_object_textblock_size_formatted_get(elm_entry_textblock_get(entry2), &w2, &h2); + evas_object_textblock_size_formatted_get(elm_entry_textblock_get(entry3), &w3, &h3); + + ck_assert_int_ne(w1, w2); + ck_assert_int_ne(h1, h2); + ck_assert_int_ne(w2, w3); + ck_assert_int_ne(h2, h3); + + entry4 = elm_entry_add(win); + + elm_object_text_set(entry4, "hello"); + ck_assert(edje_object_text_class_get(elm_layout_edje_get(entry4), "entry_text", &font, &font_size)); + ck_assert_int_eq(font_size, 24); + ck_assert_str_eq(font, "Serif:Style=Bold"); +} +EFL_END_TEST + void elm_test_entry(TCase *tc) { tcase_add_test(tc, elm_entry_legacy_type_check); @@ -535,4 +607,5 @@ void elm_test_entry(TCase *tc) tcase_add_test(tc, elm_entry_text_set); tcase_add_test(tc, elm_entry_magnifier); tcase_add_test(tc, elm_entry_file_get_set); + tcase_add_test(tc, elm_entry_test_text_class); }