[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / controller / text-controller-text-updater.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/controller/text-controller-text-updater.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/math/math-utils.h>
24 #include <memory.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/text/character-set-conversion.h>
28 #include <dali-toolkit/internal/text/characters-helper-functions.h>
29 #include <dali-toolkit/internal/text/controller/text-controller-impl.h>
30 #include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
31 #include <dali-toolkit/internal/text/emoji-helper.h>
32 #include <dali-toolkit/internal/text/markup-processor/markup-processor.h>
33 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
34
35 namespace
36 {
37 #if defined(DEBUG_ENABLED)
38 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
39 #endif
40
41 } // namespace
42
43 namespace Dali
44 {
45 namespace Toolkit
46 {
47 namespace Text
48 {
49 void Controller::TextUpdater::SetText(Controller& controller, const std::string& text)
50 {
51   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText\n");
52
53   Controller::Impl& impl = *controller.mImpl;
54
55   // Reset keyboard as text changed
56   impl.ResetInputMethodContext();
57
58   // Remove the previously set text and style.
59   ResetText(controller);
60
61   // Remove the style.
62   impl.ClearStyleData();
63
64   CharacterIndex lastCursorIndex = 0u;
65
66   EventData*& eventData = impl.mEventData;
67
68   if(nullptr != eventData)
69   {
70     // If popup shown then hide it by switching to Editing state
71     if((EventData::SELECTING == eventData->mState) ||
72        (EventData::EDITING_WITH_POPUP == eventData->mState) ||
73        (EventData::EDITING_WITH_GRAB_HANDLE == eventData->mState) ||
74        (EventData::EDITING_WITH_PASTE_POPUP == eventData->mState))
75     {
76       if((impl.mSelectableControlInterface != nullptr) && (EventData::SELECTING == eventData->mState))
77       {
78         impl.mSelectableControlInterface->SelectionChanged(eventData->mLeftSelectionPosition, eventData->mRightSelectionPosition, eventData->mPrimaryCursorPosition, eventData->mPrimaryCursorPosition);
79       }
80
81       impl.ChangeState(EventData::EDITING);
82     }
83   }
84
85   if(!text.empty())
86   {
87     ModelPtr&        model        = impl.mModel;
88     LogicalModelPtr& logicalModel = model->mLogicalModel;
89     model->mVisualModel->SetTextColor(impl.mTextColor);
90
91     MarkupProcessData markupProcessData(logicalModel->mColorRuns,
92                                         logicalModel->mFontDescriptionRuns,
93                                         logicalModel->mEmbeddedItems,
94                                         logicalModel->mAnchors,
95                                         logicalModel->mUnderlinedCharacterRuns,
96                                         logicalModel->mBackgroundColorRuns,
97                                         logicalModel->mStrikethroughCharacterRuns,
98                                         logicalModel->mBoundedParagraphRuns,
99                                         logicalModel->mCharacterSpacingCharacterRuns);
100
101     Length         textSize = 0u;
102     const uint8_t* utf8     = NULL;
103     if(impl.mMarkupProcessorEnabled)
104     {
105       MarkupPropertyData markupPropertyData(impl.mAnchorColor, impl.mAnchorClickedColor);
106
107       ProcessMarkupString(text, markupPropertyData, markupProcessData);
108       textSize = markupProcessData.markupProcessedText.size();
109
110       // This is a bit horrible but std::string returns a (signed) char*
111       utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
112     }
113     else
114     {
115       textSize = text.size();
116
117       // This is a bit horrible but std::string returns a (signed) char*
118       utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
119     }
120
121     //  Convert text into UTF-32
122     Vector<Character>& utf32Characters = logicalModel->mText;
123     utf32Characters.Resize(textSize);
124
125     // Transform a text array encoded in utf8 into an array encoded in utf32.
126     // It returns the actual number of characters.
127     Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
128     utf32Characters.Resize(characterCount);
129
130     DALI_ASSERT_DEBUG(textSize >= characterCount && "Invalid UTF32 conversion length");
131     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", &controller, textSize, logicalModel->mText.Count());
132
133     // The characters to be added.
134     impl.mTextUpdateInfo.mNumberOfCharactersToAdd = logicalModel->mText.Count();
135
136     // To reset the cursor position
137     lastCursorIndex = characterCount;
138
139     // Update the rest of the model during size negotiation
140     impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
141
142     // The natural size needs to be re-calculated.
143     impl.mRecalculateNaturalSize = true;
144
145     // The text direction needs to be updated.
146     impl.mUpdateTextDirection = true;
147
148     // Apply modifications to the model
149     impl.mOperationsPending = ALL_OPERATIONS;
150   }
151   else
152   {
153     PlaceholderHandler::ShowPlaceholderText(impl);
154   }
155
156   unsigned int oldCursorPos = (nullptr != eventData ? eventData->mPrimaryCursorPosition : 0);
157
158   // Resets the cursor position.
159   controller.ResetCursorPosition(lastCursorIndex);
160
161   // Scrolls the text to make the cursor visible.
162   impl.ResetScrollPosition();
163
164   impl.RequestRelayout();
165
166   if(nullptr != eventData)
167   {
168     // Cancel previously queued events
169     eventData->mEventQueue.clear();
170   }
171
172   // Do this last since it provides callbacks into application code.
173   if(NULL != impl.mEditableControlInterface)
174   {
175     impl.mEditableControlInterface->CursorPositionChanged(oldCursorPos, lastCursorIndex);
176     impl.mEditableControlInterface->TextChanged(true);
177   }
178 }
179
180 void Controller::TextUpdater::InsertText(Controller& controller, const std::string& text, Controller::InsertType type)
181 {
182   Controller::Impl& impl      = *controller.mImpl;
183   EventData*&       eventData = impl.mEventData;
184
185   DALI_ASSERT_DEBUG(nullptr != eventData && "Unexpected InsertText")
186
187   if(NULL == eventData)
188   {
189     return;
190   }
191
192   bool         removedPrevious  = false;
193   bool         removedSelected  = false;
194   bool         maxLengthReached = false;
195   unsigned int oldCursorPos     = eventData->mPrimaryCursorPosition;
196
197   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n", &controller, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"), eventData->mPrimaryCursorPosition, eventData->mPreEditFlag, eventData->mPreEditStartPosition, eventData->mPreEditLength);
198
199   ModelPtr&        model        = impl.mModel;
200   LogicalModelPtr& logicalModel = model->mLogicalModel;
201
202   // TODO: At the moment the underline runs are only for pre-edit.
203   model->mVisualModel->mUnderlineRuns.Clear();
204
205   // Remove the previous InputMethodContext pre-edit.
206   if(eventData->mPreEditFlag && (0u != eventData->mPreEditLength))
207   {
208     removedPrevious = RemoveText(controller,
209                                  -static_cast<int>(eventData->mPrimaryCursorPosition - eventData->mPreEditStartPosition),
210                                  eventData->mPreEditLength,
211                                  DONT_UPDATE_INPUT_STYLE,
212                                  true);
213
214     eventData->mPrimaryCursorPosition = eventData->mPreEditStartPosition;
215     eventData->mPreEditLength         = 0u;
216   }
217   else
218   {
219     // Remove the previous Selection.
220     removedSelected = RemoveSelectedText(controller);
221   }
222
223   Vector<Character> utf32Characters;
224   Length            characterCount = 0u;
225
226   if(!text.empty())
227   {
228     std::string redefinedText = text;
229
230     if(controller.mImpl->mInputFilter != NULL)
231     {
232       bool accepted = false;
233       bool rejected = false;
234
235       accepted = impl.mInputFilter->Filter(Toolkit::InputFilter::Property::ACCEPTED, redefinedText);
236       rejected = impl.mInputFilter->Filter(Toolkit::InputFilter::Property::REJECTED, redefinedText);
237
238       if(accepted)
239       {
240         // Signal emits when the string to be inserted is filtered by the accepted filter.
241         controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::ACCEPTED);
242       }
243       if(rejected)
244       {
245         // Signal emits when the string to be inserted is filtered by the rejected filter.
246         controller.mImpl->mEditableControlInterface->InputFiltered(Toolkit::InputFilter::Property::REJECTED);
247       }
248     }
249
250     //  Convert text into UTF-32
251     utf32Characters.Resize(redefinedText.size());
252
253     // This is a bit horrible but std::string returns a (signed) char*
254     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(redefinedText.c_str());
255
256     // Transform a text array encoded in utf8 into an array encoded in utf32.
257     // It returns the actual number of characters.
258     characterCount = Utf8ToUtf32(utf8, redefinedText.size(), utf32Characters.Begin());
259     utf32Characters.Resize(characterCount);
260
261     DALI_ASSERT_DEBUG(redefinedText.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length");
262     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", redefinedText.size(), utf32Characters.Count());
263   }
264
265   if(0u != utf32Characters.Count()) // Check if Utf8ToUtf32 conversion succeeded
266   {
267     // The placeholder text is no longer needed
268     if(impl.IsShowingPlaceholderText())
269     {
270       ResetText(controller);
271     }
272
273     impl.ChangeState(EventData::EDITING);
274
275     // Handle the InputMethodContext (predicitive text) state changes
276     if(COMMIT == type)
277     {
278       // InputMethodContext is no longer handling key-events
279       impl.ClearPreEditFlag();
280     }
281     else // PRE_EDIT
282     {
283       if(!eventData->mPreEditFlag)
284       {
285         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Entered PreEdit state\n");
286
287         // Record the start of the pre-edit text
288         eventData->mPreEditStartPosition = eventData->mPrimaryCursorPosition;
289       }
290
291       eventData->mPreEditLength = utf32Characters.Count();
292       eventData->mPreEditFlag   = true;
293
294       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", eventData->mPreEditStartPosition, eventData->mPreEditLength);
295     }
296
297     const Length numberOfCharactersInModel = logicalModel->mText.Count();
298
299     // Restrict new text to fit within Maximum characters setting.
300     Length temp_length      = (impl.mMaximumNumberOfCharacters > numberOfCharactersInModel ? impl.mMaximumNumberOfCharacters - numberOfCharactersInModel : 0);
301     Length maxSizeOfNewText = std::min(temp_length, characterCount);
302     maxLengthReached        = (characterCount > maxSizeOfNewText);
303
304     // The cursor position.
305     CharacterIndex& cursorIndex = eventData->mPrimaryCursorPosition;
306
307     // Update the text's style.
308
309     // Updates the text style runs by adding characters.
310     logicalModel->UpdateTextStyleRuns(cursorIndex, maxSizeOfNewText);
311
312     // Get the character index from the cursor index.
313     const CharacterIndex styleIndex = (cursorIndex > 0u) ? cursorIndex - 1u : 0u;
314
315     // Retrieve the text's style for the given index.
316     InputStyle style;
317     impl.RetrieveDefaultInputStyle(style);
318     logicalModel->RetrieveStyle(styleIndex, style);
319
320     InputStyle& inputStyle = eventData->mInputStyle;
321
322     // Whether to add a new text color run.
323     const bool addColorRun = (style.textColor != inputStyle.textColor) && !inputStyle.isDefaultColor;
324
325     // Whether to add a new font run.
326     const bool addFontNameRun   = (style.familyName != inputStyle.familyName) && inputStyle.isFamilyDefined;
327     const bool addFontWeightRun = (style.weight != inputStyle.weight) && inputStyle.isWeightDefined;
328     const bool addFontWidthRun  = (style.width != inputStyle.width) && inputStyle.isWidthDefined;
329     const bool addFontSlantRun  = (style.slant != inputStyle.slant) && inputStyle.isSlantDefined;
330     const bool addFontSizeRun   = (!Dali::Equals(style.size, inputStyle.size)) && inputStyle.isSizeDefined;
331
332     // Add style runs.
333     if(addColorRun)
334     {
335       const VectorBase::SizeType numberOfRuns = logicalModel->mColorRuns.Count();
336       logicalModel->mColorRuns.Resize(numberOfRuns + 1u);
337
338       ColorRun& colorRun                       = *(logicalModel->mColorRuns.Begin() + numberOfRuns);
339       colorRun.color                           = inputStyle.textColor;
340       colorRun.characterRun.characterIndex     = cursorIndex;
341       colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
342     }
343
344     if(addFontNameRun ||
345        addFontWeightRun ||
346        addFontWidthRun ||
347        addFontSlantRun ||
348        addFontSizeRun)
349     {
350       const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
351       logicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
352
353       FontDescriptionRun& fontDescriptionRun = *(logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
354
355       if(addFontNameRun)
356       {
357         fontDescriptionRun.familyLength = inputStyle.familyName.size();
358         fontDescriptionRun.familyName   = new char[fontDescriptionRun.familyLength];
359         memcpy(fontDescriptionRun.familyName, inputStyle.familyName.c_str(), fontDescriptionRun.familyLength);
360         fontDescriptionRun.familyDefined = true;
361
362         // The memory allocated for the font family name is freed when the font description is removed from the logical model.
363       }
364
365       if(addFontWeightRun)
366       {
367         fontDescriptionRun.weight        = inputStyle.weight;
368         fontDescriptionRun.weightDefined = true;
369       }
370
371       if(addFontWidthRun)
372       {
373         fontDescriptionRun.width        = inputStyle.width;
374         fontDescriptionRun.widthDefined = true;
375       }
376
377       if(addFontSlantRun)
378       {
379         fontDescriptionRun.slant        = inputStyle.slant;
380         fontDescriptionRun.slantDefined = true;
381       }
382
383       if(addFontSizeRun)
384       {
385         fontDescriptionRun.size        = static_cast<PointSize26Dot6>(inputStyle.size * impl.GetFontSizeScale() * 64.f);
386         fontDescriptionRun.sizeDefined = true;
387       }
388
389       fontDescriptionRun.characterRun.characterIndex     = cursorIndex;
390       fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
391     }
392
393     // Insert at current cursor position.
394     Vector<Character>& modifyText = logicalModel->mText;
395
396     auto pos = modifyText.End();
397     if(cursorIndex < numberOfCharactersInModel)
398     {
399       pos = modifyText.Begin() + cursorIndex;
400     }
401     unsigned int realPos = static_cast<unsigned int>(pos - modifyText.Begin());
402     modifyText.Insert(pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
403
404     if(NULL != impl.mEditableControlInterface)
405     {
406       impl.mEditableControlInterface->TextInserted(realPos, maxSizeOfNewText, text);
407     }
408
409     TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
410
411     // Mark the first paragraph to be updated.
412     if(Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout())
413     {
414       textUpdateInfo.mCharacterIndex             = 0;
415       textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
416       textUpdateInfo.mNumberOfCharactersToAdd    = numberOfCharactersInModel + maxSizeOfNewText;
417       textUpdateInfo.mClearAll                   = true;
418     }
419     else
420     {
421       textUpdateInfo.mCharacterIndex = std::min(cursorIndex, textUpdateInfo.mCharacterIndex);
422       textUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
423     }
424
425     if(impl.mMarkupProcessorEnabled)
426     {
427       InsertTextAnchor(controller, maxSizeOfNewText, cursorIndex);
428     }
429
430     // Update the cursor index.
431     cursorIndex += maxSizeOfNewText;
432
433     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition);
434   }
435
436   if((0u == logicalModel->mText.Count()) &&
437      impl.IsPlaceholderAvailable())
438   {
439     // Show place-holder if empty after removing the pre-edit text
440     PlaceholderHandler::ShowPlaceholderText(impl);
441     eventData->mUpdateCursorPosition = true;
442     impl.ClearPreEditFlag();
443   }
444   else if(removedPrevious ||
445           removedSelected ||
446           (0 != utf32Characters.Count()))
447   {
448     // Queue an inserted event
449     impl.QueueModifyEvent(ModifyEvent::TEXT_INSERTED);
450
451     eventData->mUpdateCursorPosition = true;
452     if(removedSelected)
453     {
454       eventData->mScrollAfterDelete = true;
455     }
456     else
457     {
458       eventData->mScrollAfterUpdatePosition = true;
459     }
460   }
461
462   if(nullptr != impl.mEditableControlInterface)
463   {
464     impl.mEditableControlInterface->CursorPositionChanged(oldCursorPos, eventData->mPrimaryCursorPosition);
465   }
466
467   if(maxLengthReached)
468   {
469     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", logicalModel->mText.Count());
470
471     impl.ResetInputMethodContext();
472
473     if(NULL != impl.mEditableControlInterface)
474     {
475       // Do this last since it provides callbacks into application code
476       impl.mEditableControlInterface->MaxLengthReached();
477     }
478   }
479 }
480
481 void Controller::TextUpdater::PasteText(Controller& controller, const std::string& stringToPaste)
482 {
483   InsertText(controller, stringToPaste, Text::Controller::COMMIT);
484   Controller::Impl& impl = *controller.mImpl;
485   impl.ChangeState(EventData::EDITING);
486   impl.RequestRelayout();
487
488   if(NULL != impl.mEditableControlInterface)
489   {
490     // Do this last since it provides callbacks into application code
491     impl.mEditableControlInterface->TextChanged(true);
492   }
493 }
494
495 bool Controller::TextUpdater::RemoveText(
496   Controller&          controller,
497   int                  cursorOffset,
498   int                  numberOfCharacters,
499   UpdateInputStyleType type,
500   bool                 isDeletingPreEdit)
501 {
502   bool removed   = false;
503   bool removeAll = false;
504
505   Controller::Impl& impl      = *controller.mImpl;
506   EventData*&       eventData = impl.mEventData;
507
508   if(nullptr == eventData)
509   {
510     return removed;
511   }
512
513   ModelPtr&        model        = impl.mModel;
514   LogicalModelPtr& logicalModel = model->mLogicalModel;
515   VisualModelPtr&  visualModel  = model->mVisualModel;
516
517   DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n", &controller, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters);
518
519   if(!impl.IsShowingPlaceholderText())
520   {
521     // Delete at current cursor position
522     Vector<Character>& currentText         = logicalModel->mText;
523     CharacterIndex&    previousCursorIndex = eventData->mPrimaryCursorPosition;
524
525     CharacterIndex cursorIndex = 0;
526
527     // Validate the cursor position & number of characters
528     if((static_cast<int>(eventData->mPrimaryCursorPosition) + cursorOffset) >= 0)
529     {
530       cursorIndex = eventData->mPrimaryCursorPosition + cursorOffset;
531     }
532
533     //Handle Emoji clustering for cursor handling
534     // Deletion case: this is handling the deletion cases when the cursor is before or after Emoji
535     //  - Before: when use delete key and cursor is before Emoji (cursorOffset = -1)
536     //  - After: when use backspace key and cursor is after Emoji (cursorOffset = 0)
537
538     const Script script = logicalModel->GetScript(cursorIndex);
539     if((numberOfCharacters == 1u) &&
540        (IsOneOfEmojiScripts(script)))
541     {
542       //TODO: Use this clustering for Emoji cases only. This needs more testing to generalize to all scripts.
543       CharacterRun emojiClusteredCharacters = RetrieveClusteredCharactersOfCharacterIndex(visualModel, logicalModel, cursorIndex);
544       Length       actualNumberOfCharacters = emojiClusteredCharacters.numberOfCharacters;
545
546       //Set cursorIndex at the first characterIndex of clustred Emoji
547       cursorIndex = emojiClusteredCharacters.characterIndex;
548
549       numberOfCharacters = actualNumberOfCharacters;
550     }
551
552     if((cursorIndex + numberOfCharacters) > currentText.Count())
553     {
554       numberOfCharacters = currentText.Count() - cursorIndex;
555     }
556
557     if((cursorIndex == 0) && (currentText.Count() - numberOfCharacters == 0))
558     {
559       removeAll = true;
560     }
561
562     TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
563
564     if(eventData->mPreEditFlag || removeAll || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time.
565        ((cursorIndex + numberOfCharacters) <= textUpdateInfo.mPreviousNumberOfCharacters))
566     {
567       // Mark the paragraphs to be updated.
568       if(Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout())
569       {
570         textUpdateInfo.mCharacterIndex             = 0;
571         textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
572         textUpdateInfo.mNumberOfCharactersToAdd    = textUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
573         textUpdateInfo.mClearAll                   = true;
574       }
575       else
576       {
577         textUpdateInfo.mCharacterIndex = std::min(cursorIndex, textUpdateInfo.mCharacterIndex);
578         textUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
579       }
580
581       // Update the input style and remove the text's style before removing the text.
582
583       if(UPDATE_INPUT_STYLE == type)
584       {
585         InputStyle& eventDataInputStyle = eventData->mInputStyle;
586
587         // Keep a copy of the current input style.
588         InputStyle currentInputStyle;
589         currentInputStyle.Copy(eventDataInputStyle);
590
591         // Set first the default input style.
592         impl.RetrieveDefaultInputStyle(eventDataInputStyle);
593
594         // Update the input style.
595         logicalModel->RetrieveStyle(cursorIndex, eventDataInputStyle);
596
597         // Compare if the input style has changed.
598         const bool hasInputStyleChanged = !currentInputStyle.Equal(eventDataInputStyle);
599
600         if(hasInputStyleChanged)
601         {
602           const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(eventDataInputStyle);
603           // Queue the input style changed signal.
604           eventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
605         }
606       }
607
608       // If the number of current text and the number of characters to be deleted are same,
609       // it means all texts should be removed and all Preedit variables should be initialized.
610       if(removeAll)
611       {
612         impl.ClearPreEditFlag();
613         if(!isDeletingPreEdit)
614         {
615           textUpdateInfo.mNumberOfCharactersToAdd = 0;
616         }
617       }
618
619       // Updates the text style runs by removing characters. Runs with no characters are removed.
620       logicalModel->UpdateTextStyleRuns(cursorIndex, -numberOfCharacters);
621
622       // Remove the characters.
623       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
624       Vector<Character>::Iterator last  = first + numberOfCharacters;
625
626       if(NULL != impl.mEditableControlInterface)
627       {
628         std::string utf8;
629         Utf32ToUtf8(first, numberOfCharacters, utf8);
630         impl.mEditableControlInterface->TextDeleted(cursorIndex, numberOfCharacters, utf8);
631       }
632
633       currentText.Erase(first, last);
634
635       if(impl.mMarkupProcessorEnabled)
636       {
637         RemoveTextAnchor(controller, cursorOffset, numberOfCharacters, previousCursorIndex);
638       }
639
640       if(nullptr != impl.mEditableControlInterface)
641       {
642         impl.mEditableControlInterface->CursorPositionChanged(previousCursorIndex, cursorIndex);
643       }
644
645       // Cursor position retreat
646       previousCursorIndex = cursorIndex;
647
648       eventData->mScrollAfterDelete = true;
649
650       if(EventData::INACTIVE == eventData->mState)
651       {
652         impl.ChangeState(EventData::EDITING);
653       }
654
655       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", &controller, numberOfCharacters);
656       removeAll = false;
657       removed   = true;
658     }
659   }
660
661   return removed;
662 }
663
664 bool Controller::TextUpdater::RemoveSelectedText(Controller& controller)
665 {
666   bool textRemoved(false);
667
668   Controller::Impl& impl = *controller.mImpl;
669
670   if(EventData::SELECTING == impl.mEventData->mState)
671   {
672     std::string removedString;
673     uint32_t    oldSelStart = impl.mEventData->mLeftSelectionPosition;
674     uint32_t    oldSelEnd   = impl.mEventData->mRightSelectionPosition;
675
676     impl.RetrieveSelection(removedString, true);
677
678     if(!removedString.empty())
679     {
680       textRemoved = true;
681       impl.ChangeState(EventData::EDITING);
682
683       if(impl.mMarkupProcessorEnabled)
684       {
685         int             cursorOffset        = -1;
686         int             numberOfCharacters  = removedString.length();
687         CharacterIndex& cursorIndex         = impl.mEventData->mPrimaryCursorPosition;
688         CharacterIndex  previousCursorIndex = cursorIndex + numberOfCharacters;
689
690         RemoveTextAnchor(controller, cursorOffset, numberOfCharacters, previousCursorIndex);
691       }
692
693       if(impl.mSelectableControlInterface != nullptr)
694       {
695         impl.mSelectableControlInterface->SelectionChanged(oldSelStart, oldSelEnd, impl.mEventData->mPrimaryCursorPosition, impl.mEventData->mPrimaryCursorPosition);
696       }
697     }
698   }
699
700   return textRemoved;
701 }
702
703 void Controller::TextUpdater::ResetText(Controller& controller)
704 {
705   Controller::Impl& impl         = *controller.mImpl;
706   LogicalModelPtr&  logicalModel = impl.mModel->mLogicalModel;
707
708   // Reset spanned-text
709   logicalModel->mSpannedTextPlaced = false;
710
711   // Reset buffers.
712   logicalModel->mText.Clear();
713
714   // Reset the embedded images buffer.
715   logicalModel->ClearEmbeddedImages();
716
717   // Reset the anchors buffer.
718   logicalModel->ClearAnchors();
719
720   // We have cleared everything including the placeholder-text
721   impl.PlaceholderCleared();
722
723   impl.mTextUpdateInfo.mCharacterIndex             = 0u;
724   impl.mTextUpdateInfo.mNumberOfCharactersToRemove = impl.mTextUpdateInfo.mPreviousNumberOfCharacters;
725   impl.mTextUpdateInfo.mNumberOfCharactersToAdd    = 0u;
726
727   // Clear any previous text.
728   impl.mTextUpdateInfo.mClearAll = true;
729
730   // The natural size needs to be re-calculated.
731   impl.mRecalculateNaturalSize = true;
732
733   // The text direction needs to be updated.
734   impl.mUpdateTextDirection = true;
735
736   // Apply modifications to the model
737   impl.mOperationsPending = ALL_OPERATIONS;
738 }
739
740 void Controller::TextUpdater::InsertTextAnchor(Controller& controller, int numberOfCharacters, CharacterIndex previousCursorIndex)
741 {
742   Controller::Impl& impl         = *controller.mImpl;
743   ModelPtr&         model        = impl.mModel;
744   LogicalModelPtr&  logicalModel = model->mLogicalModel;
745
746   for(auto& anchor : logicalModel->mAnchors)
747   {
748     if(anchor.endIndex < previousCursorIndex) //      [anchor]  CUR
749     {
750       continue;
751     }
752     if(anchor.startIndex < previousCursorIndex) //      [anCURr]
753     {
754       anchor.endIndex += numberOfCharacters;
755     }
756     else // CUR  [anchor]
757     {
758       anchor.startIndex += numberOfCharacters;
759       anchor.endIndex += numberOfCharacters;
760     }
761     DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::InsertTextAnchor[%p] Anchor[%s] start[%d] end[%d]\n", &controller, anchor.href, anchor.startIndex, anchor.endIndex);
762   }
763 }
764
765 void Controller::TextUpdater::RemoveTextAnchor(Controller& controller, int cursorOffset, int numberOfCharacters, CharacterIndex previousCursorIndex)
766 {
767   Controller::Impl&        impl         = *controller.mImpl;
768   ModelPtr&                model        = impl.mModel;
769   LogicalModelPtr&         logicalModel = model->mLogicalModel;
770   Vector<Anchor>::Iterator it           = logicalModel->mAnchors.Begin();
771
772   while(it != logicalModel->mAnchors.End())
773   {
774     Anchor& anchor = *it;
775
776     if(anchor.endIndex <= previousCursorIndex && cursorOffset == 0) // [anchor]    CUR >>
777     {
778       // Nothing happens.
779     }
780     else if(anchor.endIndex <= previousCursorIndex && cursorOffset == -1) // [anchor] << CUR
781     {
782       int endIndex = anchor.endIndex;
783       int offset   = previousCursorIndex - endIndex;
784       int index    = endIndex - (numberOfCharacters - offset);
785
786       if(index < endIndex)
787       {
788         endIndex = index;
789       }
790
791       if((int)anchor.startIndex >= endIndex)
792       {
793         if(anchor.href)
794         {
795           delete[] anchor.href;
796         }
797         it = logicalModel->mAnchors.Erase(it);
798         continue;
799       }
800       else
801       {
802         anchor.endIndex = endIndex;
803       }
804     }
805     else if(anchor.startIndex >= previousCursorIndex && cursorOffset == -1) // << CUR    [anchor]
806     {
807       anchor.startIndex -= numberOfCharacters;
808       anchor.endIndex -= numberOfCharacters;
809     }
810     else if(anchor.startIndex >= previousCursorIndex && cursorOffset == 0) //    CUR >> [anchor]
811     {
812       int startIndex = anchor.startIndex;
813       int endIndex   = anchor.endIndex;
814       int index      = previousCursorIndex + numberOfCharacters - 1;
815
816       if(startIndex > index)
817       {
818         anchor.startIndex -= numberOfCharacters;
819         anchor.endIndex -= numberOfCharacters;
820       }
821       else if(endIndex > index + 1)
822       {
823         anchor.endIndex -= numberOfCharacters;
824       }
825       else
826       {
827         if(anchor.href)
828         {
829           delete[] anchor.href;
830         }
831         it = logicalModel->mAnchors.Erase(it);
832         continue;
833       }
834     }
835     else if(cursorOffset == -1) // [<< CUR]
836     {
837       int startIndex = anchor.startIndex;
838       int index      = previousCursorIndex - numberOfCharacters;
839
840       if(startIndex >= index)
841       {
842         anchor.startIndex = index;
843       }
844       anchor.endIndex -= numberOfCharacters;
845     }
846     else if(cursorOffset == 0) // [CUR >>]
847     {
848       anchor.endIndex -= numberOfCharacters;
849     }
850     else
851     {
852       // When this condition is reached, someting is wrong.
853       DALI_LOG_ERROR("Controller::RemoveTextAnchor[%p] Invaild state cursorOffset[%d]\n", &controller, cursorOffset);
854     }
855
856     DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveTextAnchor[%p] Anchor[%s] start[%d] end[%d]\n", &controller, anchor.href, anchor.startIndex, anchor.endIndex);
857
858     it++;
859   }
860 }
861
862 } // namespace Text
863
864 } // namespace Toolkit
865
866 } // namespace Dali