evas/edje: Add evas_textblock_cursor_range_text_valid_markup_get internal API. 08/58208/3
authorYoungbok Shin <youngb.shin@samsung.com>
Wed, 28 Jan 2015 13:06:29 +0000 (22:06 +0900)
committerYoungbok Shin <youngb.shin@samsung.com>
Fri, 29 Jan 2016 04:49:09 +0000 (20:49 -0800)
Change-Id: I779f4e97af31dcb88373e611de957c5322955441

src/lib/edje/edje_entry.c
src/lib/edje/edje_private.h
src/lib/edje/edje_util.c
src/lib/evas/Evas_Common.h
src/lib/evas/canvas/evas_object_textblock.c

index 2ecf30d..3209954 100644 (file)
@@ -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)
 {
index 494fade..ee0e51a 100644 (file)
@@ -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);
index aa77208..357717d 100644 (file)
@@ -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;
 }
index a5b84e9..5c8992a 100755 (executable)
@@ -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).
index df3efbf..d9042d8 100644 (file)
@@ -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, "</%s>", 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)
 {