Merge "Added pixel format to fix bug with ktx loader" into devel/graphics
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
1 /*
2  * Copyright (c) 2021 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/text-controller-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/rendering/renderer.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
27 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
28 #include <dali-toolkit/internal/text/bidirectional-support.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/color-segmentation.h>
31 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
32 #include <dali-toolkit/internal/text/hyphenator.h>
33 #include <dali-toolkit/internal/text/multi-language-support.h>
34 #include <dali-toolkit/internal/text/segmentation.h>
35 #include <dali-toolkit/internal/text/shaper.h>
36 #include <dali-toolkit/internal/text/text-control-interface.h>
37 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
38 #include <dali-toolkit/internal/text/text-run-container.h>
39 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
40
41 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
42
43 using namespace Dali;
44
45 namespace
46 {
47 #if defined(DEBUG_ENABLED)
48 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
49 #endif
50
51 struct BackgroundVertex
52 {
53   Vector2 mPosition; ///< Vertex posiiton
54   Vector4 mColor;    ///< Vertex color
55 };
56
57 struct BackgroundMesh
58 {
59   Vector<BackgroundVertex> mVertices; ///< container of vertices
60   Vector<unsigned short>   mIndices;  ///< container of indices
61 };
62
63 const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
64 const Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
65 const Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
66 const Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
67 const Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
68
69 } // namespace
70
71 namespace Dali
72 {
73 namespace Toolkit
74 {
75 namespace Text
76 {
77 EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
78 : mDecorator(decorator),
79   mInputMethodContext(inputMethodContext),
80   mPlaceholderFont(NULL),
81   mPlaceholderTextActive(),
82   mPlaceholderTextInactive(),
83   mPlaceholderTextColor(0.8f, 0.8f, 0.8f, 0.8f), // This color has been published in the Public API (placeholder-properties.h).
84   mEventQueue(),
85   mInputStyleChangedQueue(),
86   mPreviousState(INACTIVE),
87   mState(INACTIVE),
88   mPrimaryCursorPosition(0u),
89   mLeftSelectionPosition(0u),
90   mRightSelectionPosition(0u),
91   mPreEditStartPosition(0u),
92   mPreEditLength(0u),
93   mCursorHookPositionX(0.f),
94   mDoubleTapAction(Controller::NoTextTap::NO_ACTION),
95   mLongPressAction(Controller::NoTextTap::SHOW_SELECTION_POPUP),
96   mIsShowingPlaceholderText(false),
97   mPreEditFlag(false),
98   mDecoratorUpdated(false),
99   mCursorBlinkEnabled(true),
100   mGrabHandleEnabled(true),
101   mGrabHandlePopupEnabled(true),
102   mSelectionEnabled(true),
103   mUpdateCursorHookPosition(false),
104   mUpdateCursorPosition(false),
105   mUpdateGrabHandlePosition(false),
106   mUpdateLeftSelectionPosition(false),
107   mUpdateRightSelectionPosition(false),
108   mIsLeftHandleSelected(false),
109   mIsRightHandleSelected(false),
110   mUpdateHighlightBox(false),
111   mScrollAfterUpdatePosition(false),
112   mScrollAfterDelete(false),
113   mAllTextSelected(false),
114   mUpdateInputStyle(false),
115   mPasswordInput(false),
116   mCheckScrollAmount(false),
117   mIsPlaceholderPixelSize(false),
118   mIsPlaceholderElideEnabled(false),
119   mPlaceholderEllipsisFlag(false),
120   mShiftSelectionFlag(true),
121   mUpdateAlignment(false),
122   mEditingEnabled(true)
123 {
124 }
125
126 bool Controller::Impl::ProcessInputEvents()
127 {
128   return ControllerImplEventHandler::ProcessInputEvents(*this);
129 }
130
131 void Controller::Impl::NotifyInputMethodContext()
132 {
133   if(mEventData && mEventData->mInputMethodContext)
134   {
135     CharacterIndex cursorPosition = GetLogicalCursorPosition();
136
137     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces(0u);
138
139     // Update the cursor position by removing the initial white spaces.
140     if(cursorPosition < numberOfWhiteSpaces)
141     {
142       cursorPosition = 0u;
143     }
144     else
145     {
146       cursorPosition -= numberOfWhiteSpaces;
147     }
148
149     mEventData->mInputMethodContext.SetCursorPosition(cursorPosition);
150     mEventData->mInputMethodContext.NotifyCursorPosition();
151   }
152 }
153
154 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
155 {
156   if(mEventData && mEventData->mInputMethodContext)
157   {
158     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
159     mEventData->mInputMethodContext.NotifyTextInputMultiLine(layout == Text::Layout::Engine::MULTI_LINE_BOX);
160   }
161 }
162
163 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
164 {
165   CharacterIndex cursorPosition = 0u;
166
167   if(mEventData)
168   {
169     if((EventData::SELECTING == mEventData->mState) ||
170        (EventData::SELECTION_HANDLE_PANNING == mEventData->mState))
171     {
172       cursorPosition = std::min(mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition);
173     }
174     else
175     {
176       cursorPosition = mEventData->mPrimaryCursorPosition;
177     }
178   }
179
180   return cursorPosition;
181 }
182
183 Length Controller::Impl::GetNumberOfWhiteSpaces(CharacterIndex index) const
184 {
185   Length numberOfWhiteSpaces = 0u;
186
187   // Get the buffer to the text.
188   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
189
190   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
191   for(; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces)
192   {
193     if(!TextAbstraction::IsWhiteSpace(*(utf32CharacterBuffer + index)))
194     {
195       break;
196     }
197   }
198
199   return numberOfWhiteSpaces;
200 }
201
202 void Controller::Impl::GetText(CharacterIndex index, std::string& text) const
203 {
204   // Get the total number of characters.
205   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
206
207   // Retrieve the text.
208   if(0u != numberOfCharacters)
209   {
210     Utf32ToUtf8(mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text);
211   }
212 }
213
214 void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
215 {
216   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
217   mTextUpdateInfo.mStartGlyphIndex         = 0u;
218   mTextUpdateInfo.mStartLineIndex          = 0u;
219   numberOfCharacters                       = 0u;
220
221   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
222   if(0u == numberOfParagraphs)
223   {
224     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
225     numberOfCharacters                       = 0u;
226
227     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
228
229     // Nothing else to do if there are no paragraphs.
230     return;
231   }
232
233   // Find the paragraphs to be updated.
234   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
235   if(mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters)
236   {
237     // Text is being added at the end of the current text.
238     if(mTextUpdateInfo.mIsLastCharacterNewParagraph)
239     {
240       // Text is being added in a new paragraph after the last character of the text.
241       mTextUpdateInfo.mParagraphCharacterIndex     = mTextUpdateInfo.mPreviousNumberOfCharacters;
242       numberOfCharacters                           = 0u;
243       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
244
245       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
246       mTextUpdateInfo.mStartLineIndex  = mModel->mVisualModel->mLines.Count() - 1u;
247
248       // Nothing else to do;
249       return;
250     }
251
252     paragraphsToBeUpdated.PushBack(numberOfParagraphs - 1u);
253   }
254   else
255   {
256     Length numberOfCharactersToUpdate = 0u;
257     if(mTextUpdateInfo.mFullRelayoutNeeded)
258     {
259       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
260     }
261     else
262     {
263       numberOfCharactersToUpdate = (mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
264     }
265     mModel->mLogicalModel->FindParagraphs(mTextUpdateInfo.mCharacterIndex,
266                                           numberOfCharactersToUpdate,
267                                           paragraphsToBeUpdated);
268   }
269
270   if(0u != paragraphsToBeUpdated.Count())
271   {
272     const ParagraphRunIndex firstParagraphIndex = *(paragraphsToBeUpdated.Begin());
273     const ParagraphRun&     firstParagraph      = *(mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex);
274     mTextUpdateInfo.mParagraphCharacterIndex    = firstParagraph.characterRun.characterIndex;
275
276     ParagraphRunIndex   lastParagraphIndex = *(paragraphsToBeUpdated.End() - 1u);
277     const ParagraphRun& lastParagraph      = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex);
278
279     if((mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) &&                                           // Some character are removed.
280        (lastParagraphIndex < numberOfParagraphs - 1u) &&                                               // There is a next paragraph.
281        ((lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters) == // The last removed character is the new paragraph character.
282         (mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove)))
283     {
284       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
285       const ParagraphRun& lastParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u);
286
287       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
288     }
289     else
290     {
291       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
292     }
293   }
294
295   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
296   mTextUpdateInfo.mStartGlyphIndex             = *(mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex);
297 }
298
299 void Controller::Impl::ClearFullModelData(OperationsMask operations)
300 {
301   if(NO_OPERATION != (GET_LINE_BREAKS & operations))
302   {
303     mModel->mLogicalModel->mLineBreakInfo.Clear();
304     mModel->mLogicalModel->mParagraphInfo.Clear();
305   }
306
307   if(NO_OPERATION != (GET_SCRIPTS & operations))
308   {
309     mModel->mLogicalModel->mScriptRuns.Clear();
310   }
311
312   if(NO_OPERATION != (VALIDATE_FONTS & operations))
313   {
314     mModel->mLogicalModel->mFontRuns.Clear();
315   }
316
317   if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
318   {
319     if(NO_OPERATION != (BIDI_INFO & operations))
320     {
321       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
322       mModel->mLogicalModel->mCharacterDirections.Clear();
323     }
324
325     if(NO_OPERATION != (REORDER & operations))
326     {
327       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
328       for(Vector<BidirectionalLineInfoRun>::Iterator it    = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
329                                                      endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
330           it != endIt;
331           ++it)
332       {
333         BidirectionalLineInfoRun& bidiLineInfo = *it;
334
335         free(bidiLineInfo.visualToLogicalMap);
336         bidiLineInfo.visualToLogicalMap = NULL;
337       }
338       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
339     }
340   }
341
342   if(NO_OPERATION != (SHAPE_TEXT & operations))
343   {
344     mModel->mVisualModel->mGlyphs.Clear();
345     mModel->mVisualModel->mGlyphsToCharacters.Clear();
346     mModel->mVisualModel->mCharactersToGlyph.Clear();
347     mModel->mVisualModel->mCharactersPerGlyph.Clear();
348     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
349     mModel->mVisualModel->mGlyphPositions.Clear();
350   }
351
352   if(NO_OPERATION != (LAYOUT & operations))
353   {
354     mModel->mVisualModel->mLines.Clear();
355   }
356
357   if(NO_OPERATION != (COLOR & operations))
358   {
359     mModel->mVisualModel->mColorIndices.Clear();
360     mModel->mVisualModel->mBackgroundColorIndices.Clear();
361   }
362 }
363
364 void Controller::Impl::ClearCharacterModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
365 {
366   const CharacterIndex endIndexPlusOne = endIndex + 1u;
367
368   if(NO_OPERATION != (GET_LINE_BREAKS & operations))
369   {
370     // Clear the line break info.
371     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
372
373     mModel->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex,
374                                                 lineBreakInfoBuffer + endIndexPlusOne);
375
376     // Clear the paragraphs.
377     ClearCharacterRuns(startIndex,
378                        endIndex,
379                        mModel->mLogicalModel->mParagraphInfo);
380   }
381
382   if(NO_OPERATION != (GET_SCRIPTS & operations))
383   {
384     // Clear the scripts.
385     ClearCharacterRuns(startIndex,
386                        endIndex,
387                        mModel->mLogicalModel->mScriptRuns);
388   }
389
390   if(NO_OPERATION != (VALIDATE_FONTS & operations))
391   {
392     // Clear the fonts.
393     ClearCharacterRuns(startIndex,
394                        endIndex,
395                        mModel->mLogicalModel->mFontRuns);
396   }
397
398   if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
399   {
400     if(NO_OPERATION != (BIDI_INFO & operations))
401     {
402       // Clear the bidirectional paragraph info.
403       ClearCharacterRuns(startIndex,
404                          endIndex,
405                          mModel->mLogicalModel->mBidirectionalParagraphInfo);
406
407       // Clear the character's directions.
408       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
409
410       mModel->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex,
411                                                         characterDirectionsBuffer + endIndexPlusOne);
412     }
413
414     if(NO_OPERATION != (REORDER & operations))
415     {
416       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
417       uint32_t endRemoveIndex   = startRemoveIndex;
418       ClearCharacterRuns(startIndex,
419                          endIndex,
420                          mModel->mLogicalModel->mBidirectionalLineInfo,
421                          startRemoveIndex,
422                          endRemoveIndex);
423
424       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
425
426       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
427       for(Vector<BidirectionalLineInfoRun>::Iterator it    = bidirectionalLineInfoBuffer + startRemoveIndex,
428                                                      endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
429           it != endIt;
430           ++it)
431       {
432         BidirectionalLineInfoRun& bidiLineInfo = *it;
433
434         free(bidiLineInfo.visualToLogicalMap);
435         bidiLineInfo.visualToLogicalMap = NULL;
436       }
437
438       mModel->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex,
439                                                           bidirectionalLineInfoBuffer + endRemoveIndex);
440     }
441   }
442 }
443
444 void Controller::Impl::ClearGlyphModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
445 {
446   const CharacterIndex endIndexPlusOne           = endIndex + 1u;
447   const Length         numberOfCharactersRemoved = endIndexPlusOne - startIndex;
448
449   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
450   GlyphIndex* charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
451   Length*     glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
452
453   const GlyphIndex endGlyphIndexPlusOne  = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex);
454   const Length     numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
455
456   if(NO_OPERATION != (SHAPE_TEXT & operations))
457   {
458     // Update the character to glyph indices.
459     for(Vector<GlyphIndex>::Iterator it    = charactersToGlyphBuffer + endIndexPlusOne,
460                                      endIt = charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
461         it != endIt;
462         ++it)
463     {
464       CharacterIndex& index = *it;
465       index -= numberOfGlyphsRemoved;
466     }
467
468     // Clear the character to glyph conversion table.
469     mModel->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex,
470                                                    charactersToGlyphBuffer + endIndexPlusOne);
471
472     // Clear the glyphs per character table.
473     mModel->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex,
474                                                     glyphsPerCharacterBuffer + endIndexPlusOne);
475
476     // Clear the glyphs buffer.
477     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
478     mModel->mVisualModel->mGlyphs.Erase(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
479                                         glyphsBuffer + endGlyphIndexPlusOne);
480
481     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
482
483     // Update the glyph to character indices.
484     for(Vector<CharacterIndex>::Iterator it    = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
485                                          endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
486         it != endIt;
487         ++it)
488     {
489       CharacterIndex& index = *it;
490       index -= numberOfCharactersRemoved;
491     }
492
493     // Clear the glyphs to characters buffer.
494     mModel->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
495                                                     glyphsToCharactersBuffer + endGlyphIndexPlusOne);
496
497     // Clear the characters per glyph buffer.
498     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
499     mModel->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
500                                                     charactersPerGlyphBuffer + endGlyphIndexPlusOne);
501
502     // Clear the positions buffer.
503     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
504     mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
505                                                 positionsBuffer + endGlyphIndexPlusOne);
506   }
507
508   if(NO_OPERATION != (LAYOUT & operations))
509   {
510     // Clear the lines.
511     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
512     uint32_t endRemoveIndex   = startRemoveIndex;
513     ClearCharacterRuns(startIndex,
514                        endIndex,
515                        mModel->mVisualModel->mLines,
516                        startRemoveIndex,
517                        endRemoveIndex);
518
519     // Will update the glyph runs.
520     startRemoveIndex = mModel->mVisualModel->mLines.Count();
521     endRemoveIndex   = startRemoveIndex;
522     ClearGlyphRuns(mTextUpdateInfo.mStartGlyphIndex,
523                    endGlyphIndexPlusOne - 1u,
524                    mModel->mVisualModel->mLines,
525                    startRemoveIndex,
526                    endRemoveIndex);
527
528     // Set the line index from where to insert the new laid-out lines.
529     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
530
531     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
532     mModel->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
533                                        linesBuffer + endRemoveIndex);
534   }
535
536   if(NO_OPERATION != (COLOR & operations))
537   {
538     if(0u != mModel->mVisualModel->mColorIndices.Count())
539     {
540       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
541       mModel->mVisualModel->mColorIndices.Erase(colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
542                                                 colorIndexBuffer + endGlyphIndexPlusOne);
543     }
544
545     if(0u != mModel->mVisualModel->mBackgroundColorIndices.Count())
546     {
547       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
548       mModel->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
549                                                           backgroundColorIndexBuffer + endGlyphIndexPlusOne);
550     }
551   }
552 }
553
554 void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
555 {
556   if(mTextUpdateInfo.mClearAll ||
557      ((0u == startIndex) &&
558       (mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
559   {
560     ClearFullModelData(operations);
561   }
562   else
563   {
564     // Clear the model data related with characters.
565     ClearCharacterModelData(startIndex, endIndex, operations);
566
567     // Clear the model data related with glyphs.
568     ClearGlyphModelData(startIndex, endIndex, operations);
569   }
570
571   // The estimated number of lines. Used to avoid reallocations when layouting.
572   mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
573
574   mModel->mVisualModel->ClearCaches();
575 }
576
577 bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
578 {
579   DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
580
581   // Calculate the operations to be done.
582   const OperationsMask operations = static_cast<OperationsMask>(mOperationsPending & operationsRequired);
583
584   if(NO_OPERATION == operations)
585   {
586     // Nothing to do if no operations are pending and required.
587     return false;
588   }
589
590   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
591   Vector<Character>  displayCharacters;
592   bool               useHiddenText = false;
593   if(mHiddenInput && mEventData != nullptr && !mEventData->mIsShowingPlaceholderText)
594   {
595     mHiddenInput->Substitute(srcCharacters, displayCharacters);
596     useHiddenText = true;
597   }
598
599   Vector<Character>& utf32Characters    = useHiddenText ? displayCharacters : srcCharacters;
600   const Length       numberOfCharacters = utf32Characters.Count();
601
602   // Index to the first character of the first paragraph to be updated.
603   CharacterIndex startIndex = 0u;
604   // Number of characters of the paragraphs to be removed.
605   Length paragraphCharacters = 0u;
606
607   CalculateTextUpdateIndices(paragraphCharacters);
608
609   // Check whether the indices for updating the text is valid
610   if(numberOfCharacters > 0u &&
611      (mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
612       mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
613   {
614     std::string currentText;
615     Utf32ToUtf8(mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
616
617     DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
618     DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
619
620     // Dump mTextUpdateInfo
621     DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
622     DALI_LOG_ERROR("     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex);
623     DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove);
624     DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd);
625     DALI_LOG_ERROR("     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters);
626     DALI_LOG_ERROR("     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex);
627     DALI_LOG_ERROR("     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters);
628     DALI_LOG_ERROR("     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex);
629     DALI_LOG_ERROR("     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex);
630     DALI_LOG_ERROR("     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines);
631     DALI_LOG_ERROR("     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll);
632     DALI_LOG_ERROR("     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded);
633     DALI_LOG_ERROR("     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph);
634
635     return false;
636   }
637
638   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
639
640   if(mTextUpdateInfo.mClearAll ||
641      (0u != paragraphCharacters))
642   {
643     ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
644   }
645
646   mTextUpdateInfo.mClearAll = false;
647
648   // Whether the model is updated.
649   bool updated = false;
650
651   Vector<LineBreakInfo>& lineBreakInfo               = mModel->mLogicalModel->mLineBreakInfo;
652   const Length           requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
653
654   if(NO_OPERATION != (GET_LINE_BREAKS & operations))
655   {
656     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
657     // calculate the bidirectional info for each 'paragraph'.
658     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
659     // is not shaped together).
660     lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
661
662     SetLineBreakInfo(utf32Characters,
663                      startIndex,
664                      requestedNumberOfCharacters,
665                      lineBreakInfo);
666
667     if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
668        mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
669     {
670       CharacterIndex end                 = startIndex + requestedNumberOfCharacters;
671       LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
672
673       for(CharacterIndex index = startIndex; index < end; index++)
674       {
675         CharacterIndex wordEnd = index;
676         while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
677         {
678           wordEnd++;
679         }
680
681         if((wordEnd + 1) == end) // add last char
682         {
683           wordEnd++;
684         }
685
686         Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
687
688         for(CharacterIndex i = 0; i < (wordEnd - index); i++)
689         {
690           if(hyphens[i])
691           {
692             *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
693           }
694         }
695
696         index = wordEnd;
697       }
698     }
699
700     // Create the paragraph info.
701     mModel->mLogicalModel->CreateParagraphInfo(startIndex,
702                                                requestedNumberOfCharacters);
703     updated = true;
704   }
705
706   const bool getScripts    = NO_OPERATION != (GET_SCRIPTS & operations);
707   const bool validateFonts = NO_OPERATION != (VALIDATE_FONTS & operations);
708
709   Vector<ScriptRun>& scripts    = mModel->mLogicalModel->mScriptRuns;
710   Vector<FontRun>&   validFonts = mModel->mLogicalModel->mFontRuns;
711
712   if(getScripts || validateFonts)
713   {
714     // Validates the fonts assigned by the application or assigns default ones.
715     // It makes sure all the characters are going to be rendered by the correct font.
716     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
717
718     if(getScripts)
719     {
720       // Retrieves the scripts used in the text.
721       multilanguageSupport.SetScripts(utf32Characters,
722                                       startIndex,
723                                       requestedNumberOfCharacters,
724                                       scripts);
725     }
726
727     if(validateFonts)
728     {
729       // Validate the fonts set through the mark-up string.
730       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
731
732       // Get the default font's description.
733       TextAbstraction::FontDescription defaultFontDescription;
734       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
735
736       //Get the number of points per one unit of point-size
737       uint32_t numberOfPointsPerOneUnitOfPointSize = mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
738
739       if(IsShowingPlaceholderText() && mEventData && (nullptr != mEventData->mPlaceholderFont))
740       {
741         // If the placeholder font is set specifically, only placeholder font is changed.
742         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
743         if(mEventData->mPlaceholderFont->sizeDefined)
744         {
745           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
746         }
747       }
748       else if(nullptr != mFontDefaults)
749       {
750         // Set the normal font and the placeholder font.
751         defaultFontDescription = mFontDefaults->mFontDescription;
752
753         if(mTextFitEnabled)
754         {
755           defaultPointSize = mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
756         }
757         else
758         {
759           defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
760         }
761       }
762
763       // Validates the fonts. If there is a character with no assigned font it sets a default one.
764       // After this call, fonts are validated.
765       multilanguageSupport.ValidateFonts(utf32Characters,
766                                          scripts,
767                                          fontDescriptionRuns,
768                                          defaultFontDescription,
769                                          defaultPointSize,
770                                          startIndex,
771                                          requestedNumberOfCharacters,
772                                          validFonts);
773     }
774     updated = true;
775   }
776
777   Vector<Character> mirroredUtf32Characters;
778   bool              textMirrored       = false;
779   const Length      numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
780   if(NO_OPERATION != (BIDI_INFO & operations))
781   {
782     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
783     bidirectionalInfo.Reserve(numberOfParagraphs);
784
785     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
786     SetBidirectionalInfo(utf32Characters,
787                          scripts,
788                          lineBreakInfo,
789                          startIndex,
790                          requestedNumberOfCharacters,
791                          bidirectionalInfo,
792                          mModel->mMatchSystemLanguageDirection,
793                          mLayoutDirection);
794
795     if(0u != bidirectionalInfo.Count())
796     {
797       // Only set the character directions if there is right to left characters.
798       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
799       GetCharactersDirection(bidirectionalInfo,
800                              numberOfCharacters,
801                              startIndex,
802                              requestedNumberOfCharacters,
803                              directions);
804
805       // This paragraph has right to left text. Some characters may need to be mirrored.
806       // TODO: consider if the mirrored string can be stored as well.
807
808       textMirrored = GetMirroredText(utf32Characters,
809                                      directions,
810                                      bidirectionalInfo,
811                                      startIndex,
812                                      requestedNumberOfCharacters,
813                                      mirroredUtf32Characters);
814     }
815     else
816     {
817       // There is no right to left characters. Clear the directions vector.
818       mModel->mLogicalModel->mCharacterDirections.Clear();
819     }
820     updated = true;
821   }
822
823   Vector<GlyphInfo>&      glyphs                = mModel->mVisualModel->mGlyphs;
824   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
825   Vector<Length>&         charactersPerGlyph    = mModel->mVisualModel->mCharactersPerGlyph;
826   Vector<GlyphIndex>      newParagraphGlyphs;
827   newParagraphGlyphs.Reserve(numberOfParagraphs);
828
829   const Length currentNumberOfGlyphs = glyphs.Count();
830   if(NO_OPERATION != (SHAPE_TEXT & operations))
831   {
832     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
833     // Shapes the text.
834     ShapeText(textToShape,
835               lineBreakInfo,
836               scripts,
837               validFonts,
838               startIndex,
839               mTextUpdateInfo.mStartGlyphIndex,
840               requestedNumberOfCharacters,
841               glyphs,
842               glyphsToCharactersMap,
843               charactersPerGlyph,
844               newParagraphGlyphs);
845
846     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
847     mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
848     mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
849
850    updated = true;
851   }
852
853   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
854
855   if(NO_OPERATION != (GET_GLYPH_METRICS & operations))
856   {
857     GlyphInfo* glyphsBuffer = glyphs.Begin();
858     mMetrics->GetGlyphMetrics(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
859
860     // Update the width and advance of all new paragraph characters.
861     for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
862     {
863       const GlyphIndex index = *it;
864       GlyphInfo&       glyph = *(glyphsBuffer + index);
865
866       glyph.xBearing = 0.f;
867       glyph.width    = 0.f;
868       glyph.advance  = 0.f;
869     }
870     updated = true;
871   }
872
873   if((nullptr != mEventData) &&
874      mEventData->mPreEditFlag &&
875      (0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
876   {
877     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
878     mEventData->mInputMethodContext.GetPreeditStyle(attrs);
879     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
880
881     // Check the type of preedit and run it.
882     for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
883     {
884       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
885       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
886       type = attrData.preeditType;
887
888       // Check the number of commit characters for the start position.
889       unsigned int numberOfCommit  = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
890       Length       numberOfIndices = attrData.endIndex - attrData.startIndex;
891
892       switch(type)
893       {
894         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
895         {
896           // Add the underline for the pre-edit text.
897           GlyphRun underlineRun;
898           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
899           underlineRun.numberOfGlyphs = numberOfIndices;
900           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
901
902           //Mark-up processor case
903           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
904           {
905             CopyUnderlinedFromLogicalToVisualModels(false);
906           }
907           break;
908         }
909         case Dali::InputMethodContext::PreeditStyle::REVERSE:
910         {
911           Vector4  textColor = mModel->mVisualModel->GetTextColor();
912           ColorRun backgroundColorRun;
913           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
914           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
915           backgroundColorRun.color                           = textColor;
916           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
917
918           Vector4          backgroundColor = mModel->mVisualModel->GetBackgroundColor();
919           Vector<ColorRun> colorRuns;
920           colorRuns.Resize(1u);
921           ColorRun& colorRun                       = *(colorRuns.Begin());
922           colorRun.color                           = backgroundColor;
923           colorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
924           colorRun.characterRun.numberOfCharacters = numberOfIndices;
925
926           mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
927           break;
928         }
929         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
930         {
931           ColorRun backgroundColorRun;
932           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
933           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
934           backgroundColorRun.color                           = LIGHT_BLUE;
935           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
936           break;
937         }
938         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
939         {
940           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
941           ColorRun backgroundColorRun;
942           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
943           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
944           backgroundColorRun.color                           = BACKGROUND_SUB4;
945           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
946
947           GlyphRun underlineRun;
948           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
949           underlineRun.numberOfGlyphs = numberOfIndices;
950           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
951
952           //Mark-up processor case
953           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
954           {
955             CopyUnderlinedFromLogicalToVisualModels(false);
956           }
957           break;
958         }
959         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
960         {
961           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
962           ColorRun backgroundColorRun;
963           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
964           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
965           backgroundColorRun.color                           = BACKGROUND_SUB5;
966           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
967
968           GlyphRun underlineRun;
969           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
970           underlineRun.numberOfGlyphs = numberOfIndices;
971           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
972
973           //Mark-up processor case
974           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
975           {
976             CopyUnderlinedFromLogicalToVisualModels(false);
977           }
978           break;
979         }
980         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
981         {
982           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
983           ColorRun backgroundColorRun;
984           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
985           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
986           backgroundColorRun.color                           = BACKGROUND_SUB6;
987           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
988
989           GlyphRun underlineRun;
990           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
991           underlineRun.numberOfGlyphs = numberOfIndices;
992           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
993
994           //Mark-up processor case
995           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
996           {
997             CopyUnderlinedFromLogicalToVisualModels(false);
998           }
999           break;
1000         }
1001         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
1002         {
1003           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
1004           ColorRun backgroundColorRun;
1005           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
1006           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1007           backgroundColorRun.color                           = BACKGROUND_SUB7;
1008           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
1009
1010           GlyphRun underlineRun;
1011           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
1012           underlineRun.numberOfGlyphs = numberOfIndices;
1013           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
1014
1015           //Mark-up processor case
1016           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
1017           {
1018             CopyUnderlinedFromLogicalToVisualModels(false);
1019           }
1020           break;
1021         }
1022         case Dali::InputMethodContext::PreeditStyle::NONE:
1023         default:
1024         {
1025           break;
1026         }
1027       }
1028     }
1029     attrs.Clear();
1030     updated = true;
1031   }
1032
1033   if(NO_OPERATION != (COLOR & operations))
1034   {
1035     // Set the color runs in glyphs.
1036     SetColorSegmentationInfo(mModel->mLogicalModel->mColorRuns,
1037                              mModel->mVisualModel->mCharactersToGlyph,
1038                              mModel->mVisualModel->mGlyphsPerCharacter,
1039                              startIndex,
1040                              mTextUpdateInfo.mStartGlyphIndex,
1041                              requestedNumberOfCharacters,
1042                              mModel->mVisualModel->mColors,
1043                              mModel->mVisualModel->mColorIndices);
1044
1045     // Set the background color runs in glyphs.
1046     SetColorSegmentationInfo(mModel->mLogicalModel->mBackgroundColorRuns,
1047                              mModel->mVisualModel->mCharactersToGlyph,
1048                              mModel->mVisualModel->mGlyphsPerCharacter,
1049                              startIndex,
1050                              mTextUpdateInfo.mStartGlyphIndex,
1051                              requestedNumberOfCharacters,
1052                              mModel->mVisualModel->mBackgroundColors,
1053                              mModel->mVisualModel->mBackgroundColorIndices);
1054
1055     updated = true;
1056   }
1057
1058   if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
1059       ! ((nullptr != mEventData) &&
1060          mEventData->mPreEditFlag &&
1061          (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
1062   {
1063     //Mark-up processor case
1064     if(mModel->mVisualModel->IsMarkupProcessorEnabled())
1065     {
1066       CopyUnderlinedFromLogicalToVisualModels(true);
1067     }
1068
1069     updated = true;
1070   }
1071
1072
1073   // The estimated number of lines. Used to avoid reallocations when layouting.
1074   mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
1075
1076   // Set the previous number of characters for the next time the text is updated.
1077   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1078
1079   return updated;
1080 }
1081
1082 void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
1083 {
1084   // Sets the default text's color.
1085   inputStyle.textColor      = mTextColor;
1086   inputStyle.isDefaultColor = true;
1087
1088   inputStyle.familyName.clear();
1089   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1090   inputStyle.width  = TextAbstraction::FontWidth::NORMAL;
1091   inputStyle.slant  = TextAbstraction::FontSlant::NORMAL;
1092   inputStyle.size   = 0.f;
1093
1094   inputStyle.lineSpacing = 0.f;
1095
1096   inputStyle.underlineProperties.clear();
1097   inputStyle.shadowProperties.clear();
1098   inputStyle.embossProperties.clear();
1099   inputStyle.outlineProperties.clear();
1100
1101   inputStyle.isFamilyDefined = false;
1102   inputStyle.isWeightDefined = false;
1103   inputStyle.isWidthDefined  = false;
1104   inputStyle.isSlantDefined  = false;
1105   inputStyle.isSizeDefined   = false;
1106
1107   inputStyle.isLineSpacingDefined = false;
1108
1109   inputStyle.isUnderlineDefined = false;
1110   inputStyle.isShadowDefined    = false;
1111   inputStyle.isEmbossDefined    = false;
1112   inputStyle.isOutlineDefined   = false;
1113
1114   // Sets the default font's family name, weight, width, slant and size.
1115   if(mFontDefaults)
1116   {
1117     if(mFontDefaults->familyDefined)
1118     {
1119       inputStyle.familyName      = mFontDefaults->mFontDescription.family;
1120       inputStyle.isFamilyDefined = true;
1121     }
1122
1123     if(mFontDefaults->weightDefined)
1124     {
1125       inputStyle.weight          = mFontDefaults->mFontDescription.weight;
1126       inputStyle.isWeightDefined = true;
1127     }
1128
1129     if(mFontDefaults->widthDefined)
1130     {
1131       inputStyle.width          = mFontDefaults->mFontDescription.width;
1132       inputStyle.isWidthDefined = true;
1133     }
1134
1135     if(mFontDefaults->slantDefined)
1136     {
1137       inputStyle.slant          = mFontDefaults->mFontDescription.slant;
1138       inputStyle.isSlantDefined = true;
1139     }
1140
1141     if(mFontDefaults->sizeDefined)
1142     {
1143       inputStyle.size          = mFontDefaults->mDefaultPointSize;
1144       inputStyle.isSizeDefined = true;
1145     }
1146   }
1147 }
1148
1149 float Controller::Impl::GetDefaultFontLineHeight()
1150 {
1151   FontId defaultFontId = 0u;
1152   if(nullptr == mFontDefaults)
1153   {
1154     TextAbstraction::FontDescription fontDescription;
1155     defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
1156   }
1157   else
1158   {
1159     defaultFontId = mFontDefaults->GetFontId(mFontClient, mFontDefaults->mDefaultPointSize * mFontSizeScale);
1160   }
1161
1162   Text::FontMetrics fontMetrics;
1163   mMetrics->GetFontMetrics(defaultFontId, fontMetrics);
1164
1165   return (fontMetrics.ascender - fontMetrics.descender);
1166 }
1167
1168 void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd)
1169 {
1170   if(nullptr == mEventData)
1171   {
1172     // Nothing to do if there is no text.
1173     return;
1174   }
1175
1176   if(mEventData->mSelectionEnabled && (pStart || pEnd))
1177   {
1178     uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1179
1180     if(pStart)
1181     {
1182       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
1183     }
1184     if(pEnd)
1185     {
1186       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
1187     }
1188
1189     if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1190     {
1191       ChangeState(EventData::EDITING);
1192       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
1193       mEventData->mUpdateCursorPosition                                       = true;
1194     }
1195     else
1196     {
1197       ChangeState(EventData::SELECTING);
1198       mEventData->mUpdateHighlightBox           = true;
1199       mEventData->mUpdateLeftSelectionPosition  = true;
1200       mEventData->mUpdateRightSelectionPosition = true;
1201     }
1202   }
1203 }
1204
1205 CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
1206 {
1207   if(nullptr == mEventData)
1208   {
1209     return 0;
1210   }
1211   return mEventData->mPrimaryCursorPosition;
1212 }
1213
1214 bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index)
1215 {
1216   if(nullptr == mEventData)
1217   {
1218     // Nothing to do if there is no text.
1219     return false;
1220   }
1221
1222   if(mEventData->mPrimaryCursorPosition == index)
1223   {
1224     // Nothing for same cursor position.
1225     return false;
1226   }
1227
1228   uint32_t length                    = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1229   mEventData->mPrimaryCursorPosition = std::min(index, length);
1230   ChangeState(EventData::EDITING);
1231   mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1232   mEventData->mUpdateCursorPosition                                        = true;
1233   ScrollTextToMatchCursor();
1234   return true;
1235 }
1236
1237 Uint32Pair Controller::Impl::GetTextSelectionRange() const
1238 {
1239   Uint32Pair range;
1240
1241   if(mEventData)
1242   {
1243     range.first  = mEventData->mLeftSelectionPosition;
1244     range.second = mEventData->mRightSelectionPosition;
1245   }
1246
1247   return range;
1248 }
1249
1250 bool Controller::Impl::IsEditable() const
1251 {
1252   return mEventData && mEventData->mEditingEnabled;
1253 }
1254
1255 void Controller::Impl::SetEditable(bool editable)
1256 {
1257   if(mEventData)
1258   {
1259     mEventData->mEditingEnabled = editable;
1260   }
1261 }
1262
1263 void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval)
1264 {
1265   if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1266   {
1267     // Nothing to select if handles are in the same place.
1268     selectedText.clear();
1269     return;
1270   }
1271
1272   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1273
1274   //Get start and end position of selection
1275   const CharacterIndex startOfSelectedText  = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1276   const Length         lengthOfSelectedText = (handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition) - startOfSelectedText;
1277
1278   Vector<Character>& utf32Characters    = mModel->mLogicalModel->mText;
1279   const Length       numberOfCharacters = utf32Characters.Count();
1280
1281   // Validate the start and end selection points
1282   if((startOfSelectedText + lengthOfSelectedText) <= numberOfCharacters)
1283   {
1284     //Get text as a UTF8 string
1285     Utf32ToUtf8(&utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText);
1286
1287     if(deleteAfterRetrieval) // Only delete text if copied successfully
1288     {
1289       // Keep a copy of the current input style.
1290       InputStyle currentInputStyle;
1291       currentInputStyle.Copy(mEventData->mInputStyle);
1292
1293       // Set as input style the style of the first deleted character.
1294       mModel->mLogicalModel->RetrieveStyle(startOfSelectedText, mEventData->mInputStyle);
1295
1296       // Compare if the input style has changed.
1297       const bool hasInputStyleChanged = !currentInputStyle.Equal(mEventData->mInputStyle);
1298
1299       if(hasInputStyleChanged)
1300       {
1301         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mEventData->mInputStyle);
1302         // Queue the input style changed signal.
1303         mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
1304       }
1305
1306       mModel->mLogicalModel->UpdateTextStyleRuns(startOfSelectedText, -static_cast<int>(lengthOfSelectedText));
1307
1308       // Mark the paragraphs to be updated.
1309       if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
1310       {
1311         mTextUpdateInfo.mCharacterIndex             = 0;
1312         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1313         mTextUpdateInfo.mNumberOfCharactersToAdd    = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
1314         mTextUpdateInfo.mClearAll                   = true;
1315       }
1316       else
1317       {
1318         mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
1319         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1320       }
1321
1322       // Delete text between handles
1323       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1324       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1325       utf32Characters.Erase(first, last);
1326
1327       // Will show the cursor at the first character of the selection.
1328       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1329     }
1330     else
1331     {
1332       // Will show the cursor at the last character of the selection.
1333       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1334     }
1335
1336     mEventData->mDecoratorUpdated = true;
1337   }
1338 }
1339
1340 void Controller::Impl::SetSelection(int start, int end)
1341 {
1342   mEventData->mLeftSelectionPosition  = start;
1343   mEventData->mRightSelectionPosition = end;
1344   mEventData->mUpdateCursorPosition   = true;
1345 }
1346
1347 std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
1348 {
1349   return {mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition};
1350 }
1351
1352 void Controller::Impl::ShowClipboard()
1353 {
1354   if(mClipboard)
1355   {
1356     mClipboard.ShowClipboard();
1357   }
1358 }
1359
1360 void Controller::Impl::HideClipboard()
1361 {
1362   if(mClipboard && mClipboardHideEnabled)
1363   {
1364     mClipboard.HideClipboard();
1365   }
1366 }
1367
1368 void Controller::Impl::SetClipboardHideEnable(bool enable)
1369 {
1370   mClipboardHideEnabled = enable;
1371 }
1372
1373 bool Controller::Impl::CopyStringToClipboard(const std::string& source)
1374 {
1375   //Send string to clipboard
1376   return (mClipboard && mClipboard.SetItem(source));
1377 }
1378
1379 void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
1380 {
1381   std::string selectedText;
1382   RetrieveSelection(selectedText, deleteAfterSending);
1383   CopyStringToClipboard(selectedText);
1384   ChangeState(EventData::EDITING);
1385 }
1386
1387 void Controller::Impl::RequestGetTextFromClipboard()
1388 {
1389   if(mClipboard)
1390   {
1391     mClipboard.RequestItem();
1392   }
1393 }
1394
1395 void Controller::Impl::RepositionSelectionHandles()
1396 {
1397   SelectionHandleController::Reposition(*this);
1398 }
1399 void Controller::Impl::RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action)
1400 {
1401   SelectionHandleController::Reposition(*this, visualX, visualY, action);
1402 }
1403
1404 void Controller::Impl::SetPopupButtons()
1405 {
1406   /**
1407    *  Sets the Popup buttons to be shown depending on State.
1408    *
1409    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
1410    *
1411    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
1412    */
1413
1414   bool                        isEditable    = IsEditable();
1415   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
1416
1417   if(EventData::SELECTING == mEventData->mState)
1418   {
1419     buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::COPY);
1420     if(isEditable)
1421     {
1422       buttonsToShow = TextSelectionPopup::Buttons(buttonsToShow | TextSelectionPopup::CUT);
1423     }
1424
1425     if(!IsClipboardEmpty())
1426     {
1427       if(isEditable)
1428       {
1429         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
1430       }
1431       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
1432     }
1433
1434     if(!mEventData->mAllTextSelected)
1435     {
1436       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::SELECT_ALL));
1437     }
1438   }
1439   else if(EventData::EDITING_WITH_POPUP == mEventData->mState)
1440   {
1441     if(mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
1442     {
1443       buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL);
1444     }
1445
1446     if(!IsClipboardEmpty())
1447     {
1448       if(isEditable)
1449       {
1450         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
1451       }
1452       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
1453     }
1454   }
1455   else if(EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState)
1456   {
1457     if(!IsClipboardEmpty())
1458     {
1459       if(isEditable)
1460       {
1461         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
1462       }
1463       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
1464     }
1465   }
1466
1467   mEventData->mDecorator->SetEnabledPopupButtons(buttonsToShow);
1468 }
1469
1470 void Controller::Impl::ChangeState(EventData::State newState)
1471 {
1472   if(nullptr == mEventData)
1473   {
1474     // Nothing to do if there is no text input.
1475     return;
1476   }
1477
1478   DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState);
1479
1480   if(mEventData->mState != newState)
1481   {
1482     mEventData->mPreviousState = mEventData->mState;
1483     mEventData->mState         = newState;
1484
1485     switch(mEventData->mState)
1486     {
1487       case EventData::INACTIVE:
1488       {
1489         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1490         mEventData->mDecorator->StopCursorBlink();
1491         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1492         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1493         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1494         mEventData->mDecorator->SetHighlightActive(false);
1495         mEventData->mDecorator->SetPopupActive(false);
1496         mEventData->mDecoratorUpdated = true;
1497         break;
1498       }
1499       case EventData::INTERRUPTED:
1500       {
1501         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1502         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1503         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1504         mEventData->mDecorator->SetHighlightActive(false);
1505         mEventData->mDecorator->SetPopupActive(false);
1506         mEventData->mDecoratorUpdated = true;
1507         break;
1508       }
1509       case EventData::SELECTING:
1510       {
1511         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1512         mEventData->mDecorator->StopCursorBlink();
1513         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1514         if(mEventData->mGrabHandleEnabled)
1515         {
1516           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1517           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1518         }
1519         mEventData->mDecorator->SetHighlightActive(true);
1520         if(mEventData->mGrabHandlePopupEnabled)
1521         {
1522           SetPopupButtons();
1523           mEventData->mDecorator->SetPopupActive(true);
1524         }
1525         mEventData->mDecoratorUpdated = true;
1526         break;
1527       }
1528       case EventData::EDITING:
1529       {
1530         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1531         if(mEventData->mCursorBlinkEnabled)
1532         {
1533           mEventData->mDecorator->StartCursorBlink();
1534         }
1535         // Grab handle is not shown until a tap is received whilst EDITING
1536         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1537         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1538         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1539         mEventData->mDecorator->SetHighlightActive(false);
1540         if(mEventData->mGrabHandlePopupEnabled)
1541         {
1542           mEventData->mDecorator->SetPopupActive(false);
1543         }
1544         mEventData->mDecoratorUpdated = true;
1545         break;
1546       }
1547       case EventData::EDITING_WITH_POPUP:
1548       {
1549         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
1550
1551         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1552         if(mEventData->mCursorBlinkEnabled)
1553         {
1554           mEventData->mDecorator->StartCursorBlink();
1555         }
1556         if(mEventData->mSelectionEnabled)
1557         {
1558           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1559           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1560           mEventData->mDecorator->SetHighlightActive(false);
1561         }
1562         else if(mEventData->mGrabHandleEnabled)
1563         {
1564           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1565         }
1566         if(mEventData->mGrabHandlePopupEnabled)
1567         {
1568           SetPopupButtons();
1569           mEventData->mDecorator->SetPopupActive(true);
1570         }
1571         mEventData->mDecoratorUpdated = true;
1572         break;
1573       }
1574       case EventData::EDITING_WITH_GRAB_HANDLE:
1575       {
1576         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
1577
1578         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1579         if(mEventData->mCursorBlinkEnabled)
1580         {
1581           mEventData->mDecorator->StartCursorBlink();
1582         }
1583         // Grab handle is not shown until a tap is received whilst EDITING
1584         if(mEventData->mGrabHandleEnabled)
1585         {
1586           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1587         }
1588         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1589         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1590         mEventData->mDecorator->SetHighlightActive(false);
1591         if(mEventData->mGrabHandlePopupEnabled)
1592         {
1593           mEventData->mDecorator->SetPopupActive(false);
1594         }
1595         mEventData->mDecoratorUpdated = true;
1596         break;
1597       }
1598       case EventData::SELECTION_HANDLE_PANNING:
1599       {
1600         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1601         mEventData->mDecorator->StopCursorBlink();
1602         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1603         if(mEventData->mGrabHandleEnabled)
1604         {
1605           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1606           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1607         }
1608         mEventData->mDecorator->SetHighlightActive(true);
1609         if(mEventData->mGrabHandlePopupEnabled)
1610         {
1611           mEventData->mDecorator->SetPopupActive(false);
1612         }
1613         mEventData->mDecoratorUpdated = true;
1614         break;
1615       }
1616       case EventData::GRAB_HANDLE_PANNING:
1617       {
1618         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
1619
1620         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1621         if(mEventData->mCursorBlinkEnabled)
1622         {
1623           mEventData->mDecorator->StartCursorBlink();
1624         }
1625         if(mEventData->mGrabHandleEnabled)
1626         {
1627           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1628         }
1629         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1630         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1631         mEventData->mDecorator->SetHighlightActive(false);
1632         if(mEventData->mGrabHandlePopupEnabled)
1633         {
1634           mEventData->mDecorator->SetPopupActive(false);
1635         }
1636         mEventData->mDecoratorUpdated = true;
1637         break;
1638       }
1639       case EventData::EDITING_WITH_PASTE_POPUP:
1640       {
1641         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
1642
1643         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1644         if(mEventData->mCursorBlinkEnabled)
1645         {
1646           mEventData->mDecorator->StartCursorBlink();
1647         }
1648
1649         if(mEventData->mGrabHandleEnabled)
1650         {
1651           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1652         }
1653         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1654         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1655         mEventData->mDecorator->SetHighlightActive(false);
1656
1657         if(mEventData->mGrabHandlePopupEnabled)
1658         {
1659           SetPopupButtons();
1660           mEventData->mDecorator->SetPopupActive(true);
1661         }
1662         mEventData->mDecoratorUpdated = true;
1663         break;
1664       }
1665       case EventData::TEXT_PANNING:
1666       {
1667         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1668         mEventData->mDecorator->StopCursorBlink();
1669         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1670         if(mEventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
1671            mEventData->mDecorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
1672         {
1673           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1674           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1675           mEventData->mDecorator->SetHighlightActive(true);
1676         }
1677
1678         if(mEventData->mGrabHandlePopupEnabled)
1679         {
1680           mEventData->mDecorator->SetPopupActive(false);
1681         }
1682
1683         mEventData->mDecoratorUpdated = true;
1684         break;
1685       }
1686     }
1687   }
1688 }
1689
1690 void Controller::Impl::GetCursorPosition(CharacterIndex logical,
1691                                          CursorInfo&    cursorInfo)
1692 {
1693   if(!IsShowingRealText())
1694   {
1695     // Do not want to use the place-holder text to set the cursor position.
1696
1697     // Use the line's height of the font's family set to set the cursor's size.
1698     // If there is no font's family set, use the default font.
1699     // Use the current alignment to place the cursor at the beginning, center or end of the box.
1700
1701     cursorInfo.lineOffset          = 0.f;
1702     cursorInfo.lineHeight          = GetDefaultFontLineHeight();
1703     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
1704
1705     bool isRTL = false;
1706     if(mModel->mMatchSystemLanguageDirection)
1707     {
1708       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
1709     }
1710
1711     switch(mModel->mHorizontalAlignment)
1712     {
1713       case Text::HorizontalAlignment::BEGIN:
1714       {
1715         if(isRTL)
1716         {
1717           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1718         }
1719         else
1720         {
1721           cursorInfo.primaryPosition.x = 0.f;
1722         }
1723         break;
1724       }
1725       case Text::HorizontalAlignment::CENTER:
1726       {
1727         cursorInfo.primaryPosition.x = floorf(0.5f * mModel->mVisualModel->mControlSize.width);
1728         break;
1729       }
1730       case Text::HorizontalAlignment::END:
1731       {
1732         if(isRTL)
1733         {
1734           cursorInfo.primaryPosition.x = 0.f;
1735         }
1736         else
1737         {
1738           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1739         }
1740         break;
1741       }
1742     }
1743
1744     // Nothing else to do.
1745     return;
1746   }
1747
1748   const bool                  isMultiLine = (Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout());
1749   GetCursorPositionParameters parameters;
1750   parameters.visualModel  = mModel->mVisualModel;
1751   parameters.logicalModel = mModel->mLogicalModel;
1752   parameters.metrics      = mMetrics;
1753   parameters.logical      = logical;
1754   parameters.isMultiline  = isMultiLine;
1755
1756   Text::GetCursorPosition(parameters,
1757                           cursorInfo);
1758
1759   // Adds Outline offset.
1760   const float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
1761   cursorInfo.primaryPosition.x += outlineWidth;
1762   cursorInfo.primaryPosition.y += outlineWidth;
1763   cursorInfo.secondaryPosition.x += outlineWidth;
1764   cursorInfo.secondaryPosition.y += outlineWidth;
1765
1766   if(isMultiLine)
1767   {
1768     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
1769
1770     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
1771     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
1772
1773     if(0.f > cursorInfo.primaryPosition.x)
1774     {
1775       cursorInfo.primaryPosition.x = 0.f;
1776     }
1777
1778     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>(mEventData->mDecorator->GetCursorWidth());
1779     if(cursorInfo.primaryPosition.x > edgeWidth)
1780     {
1781       cursorInfo.primaryPosition.x = edgeWidth;
1782     }
1783   }
1784 }
1785
1786 CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
1787 {
1788   if(nullptr == mEventData)
1789   {
1790     // Nothing to do if there is no text input.
1791     return 0u;
1792   }
1793
1794   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
1795
1796   const GlyphIndex* const charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
1797   const Length* const     charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1798
1799   GlyphIndex glyphIndex         = *(charactersToGlyphBuffer + index);
1800   Length     numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1801
1802   if(numberOfCharacters > 1u)
1803   {
1804     const Script script = mModel->mLogicalModel->GetScript(index);
1805     if(HasLigatureMustBreak(script))
1806     {
1807       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
1808       numberOfCharacters = 1u;
1809     }
1810   }
1811   else
1812   {
1813     while(0u == numberOfCharacters)
1814     {
1815       ++glyphIndex;
1816       numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1817     }
1818   }
1819
1820   if(index < mEventData->mPrimaryCursorPosition)
1821   {
1822     cursorIndex -= numberOfCharacters;
1823   }
1824   else
1825   {
1826     cursorIndex += numberOfCharacters;
1827   }
1828
1829   // Will update the cursor hook position.
1830   mEventData->mUpdateCursorHookPosition = true;
1831
1832   return cursorIndex;
1833 }
1834
1835 void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
1836 {
1837   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
1838   if(nullptr == mEventData)
1839   {
1840     // Nothing to do if there is no text input.
1841     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
1842     return;
1843   }
1844
1845   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
1846
1847   mEventData->mDecorator->SetGlyphOffset(PRIMARY_CURSOR, cursorInfo.glyphOffset);
1848
1849   // Sets the cursor position.
1850   mEventData->mDecorator->SetPosition(PRIMARY_CURSOR,
1851                                       cursorPosition.x,
1852                                       cursorPosition.y,
1853                                       cursorInfo.primaryCursorHeight,
1854                                       cursorInfo.lineHeight);
1855   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y);
1856
1857   if(mEventData->mUpdateGrabHandlePosition)
1858   {
1859     // Sets the grab handle position.
1860     mEventData->mDecorator->SetPosition(GRAB_HANDLE,
1861                                         cursorPosition.x,
1862                                         cursorInfo.lineOffset + mModel->mScrollPosition.y,
1863                                         cursorInfo.lineHeight);
1864   }
1865
1866   if(cursorInfo.isSecondaryCursor)
1867   {
1868     mEventData->mDecorator->SetPosition(SECONDARY_CURSOR,
1869                                         cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
1870                                         cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
1871                                         cursorInfo.secondaryCursorHeight,
1872                                         cursorInfo.lineHeight);
1873     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y);
1874   }
1875
1876   // Set which cursors are active according the state.
1877   if(EventData::IsEditingState(mEventData->mState) || (EventData::GRAB_HANDLE_PANNING == mEventData->mState))
1878   {
1879     if(cursorInfo.isSecondaryCursor)
1880     {
1881       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_BOTH);
1882     }
1883     else
1884     {
1885       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1886     }
1887   }
1888   else
1889   {
1890     mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1891   }
1892
1893   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n");
1894 }
1895
1896 void Controller::Impl::UpdateSelectionHandle(HandleType        handleType,
1897                                              const CursorInfo& cursorInfo)
1898 {
1899   SelectionHandleController::Update(*this, handleType, cursorInfo);
1900 }
1901
1902 void Controller::Impl::ClampHorizontalScroll(const Vector2& layoutSize)
1903 {
1904   // Clamp between -space & -alignment offset.
1905
1906   if(layoutSize.width > mModel->mVisualModel->mControlSize.width)
1907   {
1908     const float space         = (layoutSize.width - mModel->mVisualModel->mControlSize.width) + mModel->mAlignmentOffset;
1909     mModel->mScrollPosition.x = (mModel->mScrollPosition.x < -space) ? -space : mModel->mScrollPosition.x;
1910     mModel->mScrollPosition.x = (mModel->mScrollPosition.x > -mModel->mAlignmentOffset) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
1911
1912     mEventData->mDecoratorUpdated = true;
1913   }
1914   else
1915   {
1916     mModel->mScrollPosition.x = 0.f;
1917   }
1918 }
1919
1920 void Controller::Impl::ClampVerticalScroll(const Vector2& layoutSize)
1921 {
1922   if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
1923   {
1924     // Nothing to do if the text is single line.
1925     return;
1926   }
1927
1928   // Clamp between -space & 0.
1929   if(layoutSize.height > mModel->mVisualModel->mControlSize.height)
1930   {
1931     const float space         = (layoutSize.height - mModel->mVisualModel->mControlSize.height);
1932     mModel->mScrollPosition.y = (mModel->mScrollPosition.y < -space) ? -space : mModel->mScrollPosition.y;
1933     mModel->mScrollPosition.y = (mModel->mScrollPosition.y > 0.f) ? 0.f : mModel->mScrollPosition.y;
1934
1935     mEventData->mDecoratorUpdated = true;
1936   }
1937   else
1938   {
1939     mModel->mScrollPosition.y = 0.f;
1940   }
1941 }
1942
1943 void Controller::Impl::ScrollToMakePositionVisible(const Vector2& position, float lineHeight)
1944 {
1945   const float cursorWidth = mEventData->mDecorator ? static_cast<float>(mEventData->mDecorator->GetCursorWidth()) : 0.f;
1946
1947   // position is in actor's coords.
1948   const float positionEndX = position.x + cursorWidth;
1949   const float positionEndY = position.y + lineHeight;
1950
1951   // Transform the position to decorator coords.
1952   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
1953   const float decoratorPositionEndX   = positionEndX + mModel->mScrollPosition.x;
1954
1955   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
1956   const float decoratorPositionEndY   = positionEndY + mModel->mScrollPosition.y;
1957
1958   if(decoratorPositionBeginX < 0.f)
1959   {
1960     mModel->mScrollPosition.x = -position.x;
1961   }
1962   else if(decoratorPositionEndX > mModel->mVisualModel->mControlSize.width)
1963   {
1964     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
1965   }
1966
1967   if(Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout())
1968   {
1969     if(decoratorPositionBeginY < 0.f)
1970     {
1971       mModel->mScrollPosition.y = -position.y;
1972     }
1973     else if(decoratorPositionEndY > mModel->mVisualModel->mControlSize.height)
1974     {
1975       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
1976     }
1977   }
1978 }
1979
1980 void Controller::Impl::ScrollTextToMatchCursor(const CursorInfo& cursorInfo)
1981 {
1982   // Get the current cursor position in decorator coords.
1983   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
1984
1985   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter(mEventData->mPrimaryCursorPosition);
1986
1987   // Calculate the offset to match the cursor position before the character was deleted.
1988   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
1989
1990   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
1991   if(mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() - 1u)
1992   {
1993     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset(PRIMARY_CURSOR);
1994     mModel->mScrollPosition.y            = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
1995   }
1996
1997   ClampHorizontalScroll(mModel->mVisualModel->GetLayoutSize());
1998   ClampVerticalScroll(mModel->mVisualModel->GetLayoutSize());
1999
2000   // Makes the new cursor position visible if needed.
2001   ScrollToMakePositionVisible(cursorInfo.primaryPosition, cursorInfo.lineHeight);
2002 }
2003
2004 void Controller::Impl::ScrollTextToMatchCursor()
2005 {
2006   CursorInfo cursorInfo;
2007   GetCursorPosition(mEventData->mPrimaryCursorPosition, cursorInfo);
2008   ScrollTextToMatchCursor(cursorInfo);
2009 }
2010
2011 void Controller::Impl::RequestRelayout()
2012 {
2013   if(nullptr != mControlInterface)
2014   {
2015     mControlInterface->RequestTextRelayout();
2016   }
2017 }
2018
2019 Actor Controller::Impl::CreateBackgroundActor()
2020 {
2021   // NOTE: Currently we only support background color for one line left-to-right text,
2022   //       so the following calculation is based on one line left-to-right text only!
2023
2024   Actor actor;
2025
2026   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
2027   if(numberOfGlyphs > 0u)
2028   {
2029     Vector<GlyphInfo> glyphs;
2030     glyphs.Resize(numberOfGlyphs);
2031
2032     Vector<Vector2> positions;
2033     positions.Resize(numberOfGlyphs);
2034
2035     // Get the line where the glyphs are laid-out.
2036     const LineRun* lineRun         = mModel->mVisualModel->mLines.Begin();
2037     float          alignmentOffset = lineRun->alignmentOffset;
2038     numberOfGlyphs                 = mView.GetGlyphs(glyphs.Begin(),
2039                                      positions.Begin(),
2040                                      alignmentOffset,
2041                                      0u,
2042                                      numberOfGlyphs);
2043
2044     glyphs.Resize(numberOfGlyphs);
2045     positions.Resize(numberOfGlyphs);
2046
2047     const GlyphInfo* const glyphsBuffer    = glyphs.Begin();
2048     const Vector2* const   positionsBuffer = positions.Begin();
2049
2050     BackgroundMesh mesh;
2051     mesh.mVertices.Reserve(4u * glyphs.Size());
2052     mesh.mIndices.Reserve(6u * glyphs.Size());
2053
2054     const Vector2 textSize = mView.GetLayoutSize();
2055
2056     const float offsetX = textSize.width * 0.5f;
2057     const float offsetY = textSize.height * 0.5f;
2058
2059     const Vector4* const    backgroundColorsBuffer       = mView.GetBackgroundColors();
2060     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
2061     const Vector4&          defaultBackgroundColor       = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
2062
2063     Vector4  quad;
2064     uint32_t numberOfQuads = 0u;
2065
2066     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
2067     {
2068       const GlyphInfo& glyph = *(glyphsBuffer + i);
2069
2070       // Get the background color of the character.
2071       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
2072       const ColorIndex backgroundColorIndex = (nullptr == backgroundColorsBuffer) ? 0u : *(backgroundColorIndicesBuffer + i);
2073       const Vector4&   backgroundColor      = (0u == backgroundColorIndex) ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
2074
2075       // Only create quads for glyphs with a background color
2076       if(backgroundColor != Color::TRANSPARENT)
2077       {
2078         const Vector2 position = *(positionsBuffer + i);
2079
2080         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
2081         {
2082           quad.x = position.x;
2083           quad.y = 0.0f;
2084           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
2085           quad.w = textSize.height;
2086         }
2087         else if(i == 0u) // The first glyph in the whole text
2088         {
2089           quad.x = position.x;
2090           quad.y = 0.0f;
2091           quad.z = quad.x - glyph.xBearing + glyph.advance;
2092           quad.w = textSize.height;
2093         }
2094         else if(i == glyphSize - 1u) // The last glyph in the whole text
2095         {
2096           quad.x = position.x - glyph.xBearing;
2097           quad.y = 0.0f;
2098           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
2099           quad.w = textSize.height;
2100         }
2101         else // The glyph in the middle of the text
2102         {
2103           quad.x = position.x - glyph.xBearing;
2104           quad.y = 0.0f;
2105           quad.z = quad.x + glyph.advance;
2106           quad.w = textSize.height;
2107         }
2108
2109         BackgroundVertex vertex;
2110
2111         // Top left
2112         vertex.mPosition.x = quad.x - offsetX;
2113         vertex.mPosition.y = quad.y - offsetY;
2114         vertex.mColor      = backgroundColor;
2115         mesh.mVertices.PushBack(vertex);
2116
2117         // Top right
2118         vertex.mPosition.x = quad.z - offsetX;
2119         vertex.mPosition.y = quad.y - offsetY;
2120         vertex.mColor      = backgroundColor;
2121         mesh.mVertices.PushBack(vertex);
2122
2123         // Bottom left
2124         vertex.mPosition.x = quad.x - offsetX;
2125         vertex.mPosition.y = quad.w - offsetY;
2126         vertex.mColor      = backgroundColor;
2127         mesh.mVertices.PushBack(vertex);
2128
2129         // Bottom right
2130         vertex.mPosition.x = quad.z - offsetX;
2131         vertex.mPosition.y = quad.w - offsetY;
2132         vertex.mColor      = backgroundColor;
2133         mesh.mVertices.PushBack(vertex);
2134
2135         // Six indices in counter clockwise winding
2136         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
2137         mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
2138         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
2139         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
2140         mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
2141         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
2142
2143         numberOfQuads++;
2144       }
2145     }
2146
2147     // Only create the background actor if there are glyphs with background color
2148     if(mesh.mVertices.Count() > 0u)
2149     {
2150       Property::Map quadVertexFormat;
2151       quadVertexFormat["aPosition"] = Property::VECTOR2;
2152       quadVertexFormat["aColor"]    = Property::VECTOR4;
2153
2154       VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
2155       quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
2156
2157       Geometry quadGeometry = Geometry::New();
2158       quadGeometry.AddVertexBuffer(quadVertices);
2159       quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
2160
2161       if(!mShaderBackground)
2162       {
2163         mShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
2164       }
2165
2166       Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, mShaderBackground);
2167       renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
2168       renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
2169
2170       actor = Actor::New();
2171       actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
2172       actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
2173       actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
2174       actor.SetProperty(Actor::Property::SIZE, textSize);
2175       actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
2176       actor.AddRenderer(renderer);
2177     }
2178   }
2179
2180   return actor;
2181 }
2182
2183 void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
2184 {
2185     //Underlined character runs for markup-processor
2186     const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
2187     const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
2188     const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
2189
2190     if(shouldClearPreUnderlineRuns)
2191     {
2192         mModel->mVisualModel->mUnderlineRuns.Clear();
2193     }
2194
2195     for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
2196     {
2197         CharacterIndex characterIndex = it->characterRun.characterIndex;
2198         Length numberOfCharacters = it->characterRun.numberOfCharacters;
2199         for(Length index=0u; index<numberOfCharacters; index++)
2200         {
2201           GlyphRun underlineGlyphRun;
2202           underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
2203           underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
2204           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
2205         }
2206     }
2207 }
2208
2209 } // namespace Text
2210
2211 } // namespace Toolkit
2212
2213 } // namespace Dali