From 222677a7eed9da2eb38f91a94a55a7718408ce20 Mon Sep 17 00:00:00 2001 From: Youngbok Shin Date: Wed, 28 Jan 2015 22:06:29 +0900 Subject: [PATCH] evas/edje: Add evas_textblock_cursor_range_text_valid_markup_get internal API. Change-Id: I779f4e97af31dcb88373e611de957c5322955441 --- src/lib/edje/edje_entry.c | 18 ++ src/lib/edje/edje_private.h | 3 + src/lib/edje/edje_util.c | 7 +- src/lib/evas/Evas_Common.h | 12 + src/lib/evas/canvas/evas_object_textblock.c | 363 +++++++++++++++++++++++++++- 5 files changed, 399 insertions(+), 4 deletions(-) diff --git a/src/lib/edje/edje_entry.c b/src/lib/edje/edje_entry.c index 2ecf30d..3209954 100644 --- a/src/lib/edje/edje_entry.c +++ b/src/lib/edje/edje_entry.c @@ -2815,6 +2815,24 @@ _edje_entry_real_part_configure(Edje *ed, Edje_Real_Part *rp) } } +// TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. +const char * +_edje_entry_selection_valid_markup_get(Edje_Real_Part *rp) +{ + Entry *en; + + if ((rp->type != EDJE_RP_TYPE_TEXT) || + (!rp->typedata.text)) return NULL; + en = rp->typedata.text->entry_data; + if (!en) return NULL; + // get selection - convert to markup + if ((!en->selection) && (en->have_selection)) + en->selection = evas_textblock_cursor_range_text_valid_markup_get + (en->sel_start, en->sel_end); + return en->selection; +} +// + const char * _edje_entry_selection_get(Edje_Real_Part *rp) { diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index 494fade..ee0e51a 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -2616,6 +2616,9 @@ void _edje_entry_shutdown(Edje *ed); void _edje_entry_real_part_init(Edje *ed, Edje_Real_Part *rp); void _edje_entry_real_part_shutdown(Edje *ed, Edje_Real_Part *rp); void _edje_entry_real_part_configure(Edje *ed, Edje_Real_Part *rp); +// TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. +const char *_edje_entry_selection_valid_markup_get(Edje_Real_Part *rp); +// const char *_edje_entry_selection_get(Edje_Real_Part *rp); const char *_edje_entry_text_get(Edje_Real_Part *rp); void _edje_entry_text_markup_set(Edje_Real_Part *rp, const char *text); diff --git a/src/lib/edje/edje_util.c b/src/lib/edje/edje_util.c index aa77208..357717d 100644 --- a/src/lib/edje/edje_util.c +++ b/src/lib/edje/edje_util.c @@ -1872,7 +1872,12 @@ _edje_object_part_text_selection_get(Eo *obj EINA_UNUSED, Edje *ed, const char * rp = _edje_real_part_recursive_get(&ed, part); if (!rp) return NULL; if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) - return _edje_entry_selection_get(rp); + { + // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + //return _edje_entry_selection_get(rp); + return _edje_entry_selection_valid_markup_get(rp); + // + } return NULL; } diff --git a/src/lib/evas/Evas_Common.h b/src/lib/evas/Evas_Common.h index a5b84e9..5c8992a 100755 --- a/src/lib/evas/Evas_Common.h +++ b/src/lib/evas/Evas_Common.h @@ -3741,6 +3741,18 @@ EAPI Eina_List *evas_textblock_cursor_range_format EAPI char *evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2); /** + * @internal + * // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + * @brief Gets the text and markup tags in the range between @a cur1 and @a cur2. + * + * @param cur1 The start of the range + * @param cur2 The end of the range + * @return The text in the range and the markup tags that affect the text + * @see elm_entry_markup_to_utf8() + */ +EAPI char *evas_textblock_cursor_range_text_valid_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2); + +/** * Return the content of the cursor. * * Free the returned string pointer when done (if it is not NULL). diff --git a/src/lib/evas/canvas/evas_object_textblock.c b/src/lib/evas/canvas/evas_object_textblock.c index df3efbf..d9042d8 100644 --- a/src/lib/evas/canvas/evas_object_textblock.c +++ b/src/lib/evas/canvas/evas_object_textblock.c @@ -206,6 +206,14 @@ typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format; */ typedef struct _Evas_Textblock_Selection_Iterator Evas_Textblock_Selection_Iterator; /** + * // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + * @internal + * @typedef Evas_Object_Textblock_Format_Pair_Item + * For *valid_markup_get. + */ +typedef struct _Evas_Object_Textblock_Format_Pair_Item Evas_Object_Textblock_Format_Pair_Item; + +/** * @internal * @def IS_AT_END(ti, ind) * Return true if ind is at the end of the text item, false otherwise. @@ -310,6 +318,14 @@ struct _Evas_Textblock_Node_Format Eina_Bool is_new : 1; /**< EINA_TRUE if its a new format node, else EINA_FALSE */ }; +// TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. +struct _Evas_Object_Textblock_Format_Pair_Item +{ + char *format; + Eina_Bool void_closer; +}; +// + /* The default tags to use */ static const Evas_Object_Style_Tag_Base default_tags[] = { { "b", "+ font_weight=Bold", 1, 18 }, @@ -6965,6 +6981,25 @@ _markup_get_format_append(Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *f } /** + * // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + * @internal + * An helper function to markup get. Prepends the format from fnode to the strbuf txt. + * + * @param txt the strbuf to prepend to. + * @param fnode the format node to process. + */ +static void +_markup_get_format_prepend(Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *fnode) +{ + if (fnode->own_closer) + eina_strbuf_prepend_printf(txt, "<%s/>", fnode->orig_format); + else if (fnode->opener) + eina_strbuf_prepend_printf(txt, "<%s>", fnode->orig_format); + else + eina_strbuf_prepend_printf(txt, "", fnode->orig_format); +} + +/** * @internal * An helper function to _markup_get_text_append and others, used for getting * back only the "dangerous" escapes. @@ -10039,12 +10074,164 @@ evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) } } +/////////////////////////////////////////////////////////////////////////////////// +// TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. +/////////////////////////////////////////////////////////////////////////////////// +static void +_evas_textblock_format_search_prepend(Eina_Strbuf *buf, Evas_Object_Textblock_Node_Format *format_node, Eina_List **invalid_fnodes) +{ + Eina_List *list = NULL, *l = NULL, *l_next = NULL; + Evas_Object_Textblock_Format_Pair_Item *data, *new; + Evas_Object_Textblock_Node_Format *fnode, *fn; + char *simple_format, *copy; + + fnode = format_node; + if (!fnode) return; + + while (fnode) + { + if (fnode->own_closer) goto next; + if (fnode->visible) goto next; + if (fnode->opener) + { + EINA_LIST_FOREACH_SAFE(list, l, l_next, data) + { + if (data->void_closer || + !strncmp(fnode->orig_format, data->format, strlen(data->format))) + { + if (data->format) + free((void *)data->format); + free((void *)data); + list = eina_list_remove_list(list, l); + goto next; + } + } + EINA_LIST_FOREACH_SAFE(*invalid_fnodes, l, l_next, fn) + { + if (!strncmp(fnode->orig_format, fn->orig_format, strlen(fn->orig_format))) + { + *invalid_fnodes = eina_list_remove_list(*invalid_fnodes, l); + goto next; + } + } + _markup_get_format_prepend(buf, fnode); + } + else + { + copy = strdup(fnode->orig_format); + simple_format = strtok(copy, " ,="); + + new = calloc(1, sizeof(Evas_Object_Textblock_Format_Pair_Item)); + if (!simple_format) + { + new->void_closer = EINA_TRUE; + new->format = NULL; + } + else + { + new->void_closer = EINA_FALSE; + new->format = calloc(strlen(simple_format) + 1, 1); + strcpy(new->format, simple_format); + } + + free(copy); + list = eina_list_prepend(list, new); + } +next: + fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->prev); + } + + EINA_LIST_FOREACH(list, l, data) + { + if (data->format) + free((void *)data->format); + free((void *)data); + } + eina_list_free(list); +} + +static void +_evas_textblock_format_search_append(Eina_Strbuf *buf, Evas_Object_Textblock_Node_Format *format_node) +{ + Eina_List *list = NULL, *l = NULL, *l_next = NULL; + Evas_Object_Textblock_Format_Pair_Item *data, *new; + Eina_Bool void_closer = EINA_FALSE; + Evas_Object_Textblock_Node_Format *fnode; + char *simple_format, *copy; + + fnode = format_node; + if (!fnode) return; + + while (fnode) + { + if (fnode->own_closer) goto next; + if (fnode->visible && strncmp(fnode->orig_format, "item", 4)) goto next; + if (!fnode->opener) + { + if (!strcmp(fnode->orig_format, "")) + void_closer = EINA_TRUE; + + EINA_LIST_FOREACH_SAFE(list, l, l_next, data) + { + if (void_closer || (data->void_closer) || + !strncmp(fnode->orig_format, data->format, strlen(data->format))) + { + void_closer = EINA_FALSE; + if (data->format) + free((void *)data->format); + free((void *)data); + list = eina_list_remove_list(list, l); + goto next; + } + } + _markup_get_format_append(buf, fnode); + } + else + { + copy = strdup(fnode->orig_format); + simple_format = strtok(copy, " ,="); + + new = calloc(1, sizeof(Evas_Object_Textblock_Format_Pair_Item)); + if (!simple_format) + { + new->void_closer = EINA_TRUE; + new->format = NULL; + } + else + { + new->format = calloc(strlen(simple_format) + 1, 1); + strcpy(new->format, simple_format); + } + + free(copy); + list = eina_list_prepend(list, new); + } +next: + fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); + } + + EINA_LIST_FOREACH(list, l, data) + { + if (data->format) + free((void *)data->format); + free((void *)data); + } + eina_list_free(list); +} +////////////////////////////////////////////////////////////////////////////////// + static char * -_evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2) +_evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2, Eina_Bool valid_markup) { Evas_Object_Textblock_Node_Text *tnode; Eina_Strbuf *buf; Evas_Textblock_Cursor *cur2; + // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + Evas_Object_Textblock_Node_Format *start_fnode = NULL,*prev_fnode = NULL; + Eina_Bool valid_result = EINA_FALSE; + Eina_List *invalid_fnodes = NULL; + int item_pair = 0; + // buf = eina_strbuf_new(); @@ -10094,6 +10281,13 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, { off = 0; } + + // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + // Keep start position for searching format + if (tnode == cur1->node) + start_fnode = fnode; + ////////////// + while (fnode && (fnode->text_node == tnode)) { Eina_Unicode tmp_ch; @@ -10107,7 +10301,48 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, tmp_ch = text[off]; text[off] = 0; /* Null terminate the part of the string */ _markup_get_text_append(buf, text); - _markup_get_format_append(buf, fnode); + + // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + //_markup_get_format_append(buf, fnode); + if ((!valid_result) && (*text)) + valid_result = EINA_TRUE; + + if (!valid_markup) + { + _markup_get_format_append(buf, fnode); + } + else + { + // Closer item format is invisible and opener item format is visible. + // So, we need to get rid of useless item closer format. + if (!strncmp(fnode->orig_format, "item", 4)) + { + if (fnode->opener) + { + item_pair++; + _markup_get_format_append(buf, fnode); + } + else if (item_pair > 0) + { + item_pair--; + _markup_get_format_append(buf, fnode); + } + } + else + { + if ((!fnode->visible) && (!fnode->opener) && (!valid_result)) + invalid_fnodes = eina_list_append(invalid_fnodes, fnode); + else + { + if (fnode->visible) + valid_result = EINA_TRUE; + _markup_get_format_append(buf, fnode); + } + } + } + //////////////// + + text[off] = tmp_ch; /* Restore the char */ text += off; if (fnode->visible) @@ -10129,6 +10364,98 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, text_base[cur2->pos] = '\0'; _markup_get_text_append(buf, text); free(text_base); + + // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + if ((!valid_result) && (*text)) + valid_result = EINA_TRUE; + + // Search valid opener markup tag + if (valid_markup) + { + if (start_fnode) + { + _evas_textblock_format_search_prepend(buf, _NODE_FORMAT(EINA_INLIST_GET(start_fnode)->prev), &invalid_fnodes); + prev_fnode = NULL; + } + else + { + size_t pos = cur1->pos; + while (pos > 0 && !prev_fnode) + { + prev_fnode = _evas_textblock_node_text_get_first_format_between(cur1->node, + --pos, cur1->pos); + } + if (!prev_fnode) + { + Evas_Object_Textblock_Node_Text *prev_tnode, *text_temp; + Evas_Object_Textblock_Node_Format *format_temp; + + prev_tnode = _NODE_TEXT(EINA_INLIST_GET(cur1->node)->prev); + + if (prev_tnode) + { + while (1) + { + prev_fnode = prev_tnode->format_node; + if (prev_fnode) + break; + text_temp = _NODE_TEXT(EINA_INLIST_GET(prev_tnode)->prev); + if (!text_temp) + break; + prev_tnode = text_temp; + } + } + while (prev_fnode) + { + format_temp = _NODE_FORMAT(EINA_INLIST_GET(prev_fnode)->next); + if (!format_temp || (format_temp->text_node != prev_tnode)) + break; + prev_fnode = format_temp; + } + } + if (prev_fnode) + _evas_textblock_format_search_prepend(buf, prev_fnode, &invalid_fnodes); + } + if (invalid_fnodes) + invalid_fnodes = eina_list_free(invalid_fnodes); + + // Search valid closer markup tag + if (fnode) + { + _evas_textblock_format_search_append(buf, fnode); + } + else if (prev_fnode) + { + _evas_textblock_format_search_append(buf, _NODE_FORMAT(EINA_INLIST_GET(prev_fnode)->next)); + } + else + { + Evas_Object_Textblock_Node_Format *next_fnode = NULL; + next_fnode = _evas_textblock_node_text_get_first_format_between(tnode, cur2->pos, -1); + Evas_Object_Textblock_Node_Text *text_temp; + + if (!next_fnode) + { + Evas_Object_Textblock_Node_Text *next_tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next); + if (next_tnode) + { + while (1) + { + next_fnode = next_tnode->format_node; + if (next_fnode) + break; + text_temp = _NODE_TEXT(EINA_INLIST_GET(next_tnode)->next); + if (!text_temp) + break; + next_tnode = text_temp; + } + } + } + if (next_fnode) + _evas_textblock_format_search_append(buf, next_fnode); + } + } + /////////// break; } else @@ -10136,6 +10463,10 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, /* Add the rest, skip replacement */ _markup_get_text_append(buf, text); free(text_base); + // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + if ((!valid_result) && (*text)) + valid_result = EINA_TRUE; + // } } /* return the string */ @@ -10143,6 +10474,24 @@ _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, char *ret; ret = eina_strbuf_string_steal(buf); eina_strbuf_free(buf); + // TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. + if (valid_markup) + { + char *utf8_ret; + utf8_ret = evas_textblock_text_markup_to_utf8(NULL, ret); + if ((!utf8_ret) || (!strcmp(utf8_ret, ""))) + { + free(utf8_ret); + free(ret); + return NULL; + } + else + { + free(utf8_ret); + return ret; + } + } + // return ret; } } @@ -10287,13 +10636,21 @@ evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Ev obj = eo_data_scope_get(cur1->obj, EVAS_OBJECT_CLASS); evas_object_async_block(obj); if (format == EVAS_TEXTBLOCK_TEXT_MARKUP) - return _evas_textblock_cursor_range_text_markup_get(cur1, cur2); + return _evas_textblock_cursor_range_text_markup_get(cur1, cur2, EINA_FALSE); else if (format == EVAS_TEXTBLOCK_TEXT_PLAIN) return _evas_textblock_cursor_range_text_plain_get(cur1, cur2); else return NULL; /* Not yet supported */ } +// TIZEN_ONLY(20150128): Add evas_textblock_cursor_range_text_valid_markup_get API. +EAPI char * +evas_textblock_cursor_range_text_valid_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) +{ + return _evas_textblock_cursor_range_text_markup_get(cur1, cur2, EINA_TRUE); +} +// + EAPI const char * evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur) { -- 2.7.4