Add a callback to get textfitted font size.
[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/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
30 #include <dali-toolkit/internal/text/text-control-interface.h>
31 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
32 #include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
33 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
34 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
35 #include <dali-toolkit/internal/text/text-run-container.h>
36 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
37
38 using namespace Dali;
39
40 namespace
41 {
42 #if defined(DEBUG_ENABLED)
43 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
44 #endif
45
46 struct BackgroundVertex
47 {
48   Vector2 mPosition; ///< Vertex posiiton
49   Vector4 mColor;    ///< Vertex color
50 };
51
52 struct BackgroundMesh
53 {
54   Vector<BackgroundVertex> mVertices; ///< container of vertices
55   Vector<unsigned short>   mIndices;  ///< container of indices
56 };
57
58 } // namespace
59
60 namespace Dali::Toolkit::Text
61 {
62
63 namespace
64 {
65
66 void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const fontDefaults, const Vector4& textColor)
67 {
68   // Sets the default text's color.
69   inputStyle.textColor      = textColor;
70   inputStyle.isDefaultColor = true;
71
72   inputStyle.familyName.clear();
73   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
74   inputStyle.width  = TextAbstraction::FontWidth::NORMAL;
75   inputStyle.slant  = TextAbstraction::FontSlant::NORMAL;
76   inputStyle.size   = 0.f;
77
78   inputStyle.lineSpacing = 0.f;
79
80   inputStyle.underlineProperties.clear();
81   inputStyle.shadowProperties.clear();
82   inputStyle.embossProperties.clear();
83   inputStyle.outlineProperties.clear();
84
85   inputStyle.isFamilyDefined = false;
86   inputStyle.isWeightDefined = false;
87   inputStyle.isWidthDefined  = false;
88   inputStyle.isSlantDefined  = false;
89   inputStyle.isSizeDefined   = false;
90
91   inputStyle.isLineSpacingDefined = false;
92
93   inputStyle.isUnderlineDefined = false;
94   inputStyle.isShadowDefined    = false;
95   inputStyle.isEmbossDefined    = false;
96   inputStyle.isOutlineDefined   = false;
97
98   // Sets the default font's family name, weight, width, slant and size.
99   if(fontDefaults)
100   {
101     if(fontDefaults->familyDefined)
102     {
103       inputStyle.familyName      = fontDefaults->mFontDescription.family;
104       inputStyle.isFamilyDefined = true;
105     }
106
107     if(fontDefaults->weightDefined)
108     {
109       inputStyle.weight          = fontDefaults->mFontDescription.weight;
110       inputStyle.isWeightDefined = true;
111     }
112
113     if(fontDefaults->widthDefined)
114     {
115       inputStyle.width          = fontDefaults->mFontDescription.width;
116       inputStyle.isWidthDefined = true;
117     }
118
119     if(fontDefaults->slantDefined)
120     {
121       inputStyle.slant          = fontDefaults->mFontDescription.slant;
122       inputStyle.isSlantDefined = true;
123     }
124
125     if(fontDefaults->sizeDefined)
126     {
127       inputStyle.size          = fontDefaults->mDefaultPointSize;
128       inputStyle.isSizeDefined = true;
129     }
130   }
131 }
132 } // unnamed Namespace
133
134 EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
135 : mDecorator(decorator),
136   mInputMethodContext(inputMethodContext),
137   mPlaceholderFont(nullptr),
138   mPlaceholderTextActive(),
139   mPlaceholderTextInactive(),
140   mPlaceholderTextColor(0.8f, 0.8f, 0.8f, 0.8f), // This color has been published in the Public API (placeholder-properties.h).
141   mEventQueue(),
142   mInputStyleChangedQueue(),
143   mPreviousState(INACTIVE),
144   mState(INACTIVE),
145   mPrimaryCursorPosition(0u),
146   mLeftSelectionPosition(0u),
147   mRightSelectionPosition(0u),
148   mPreEditStartPosition(0u),
149   mPreEditLength(0u),
150   mCursorHookPositionX(0.f),
151   mDoubleTapAction(Controller::NoTextTap::NO_ACTION),
152   mLongPressAction(Controller::NoTextTap::SHOW_SELECTION_POPUP),
153   mIsShowingPlaceholderText(false),
154   mPreEditFlag(false),
155   mDecoratorUpdated(false),
156   mCursorBlinkEnabled(true),
157   mGrabHandleEnabled(true),
158   mGrabHandlePopupEnabled(true),
159   mSelectionEnabled(true),
160   mUpdateCursorHookPosition(false),
161   mUpdateCursorPosition(false),
162   mUpdateGrabHandlePosition(false),
163   mUpdateLeftSelectionPosition(false),
164   mUpdateRightSelectionPosition(false),
165   mIsLeftHandleSelected(false),
166   mIsRightHandleSelected(false),
167   mUpdateHighlightBox(false),
168   mScrollAfterUpdatePosition(false),
169   mScrollAfterDelete(false),
170   mAllTextSelected(false),
171   mUpdateInputStyle(false),
172   mPasswordInput(false),
173   mCheckScrollAmount(false),
174   mIsPlaceholderPixelSize(false),
175   mIsPlaceholderElideEnabled(false),
176   mPlaceholderEllipsisFlag(false),
177   mShiftSelectionFlag(true),
178   mUpdateAlignment(false),
179   mEditingEnabled(true)
180 {
181 }
182
183 bool Controller::Impl::ProcessInputEvents()
184 {
185   return ControllerImplEventHandler::ProcessInputEvents(*this);
186 }
187
188 void Controller::Impl::NotifyInputMethodContext()
189 {
190   if(mEventData && mEventData->mInputMethodContext)
191   {
192     CharacterIndex cursorPosition = GetLogicalCursorPosition();
193
194     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces(0u);
195
196     // Update the cursor position by removing the initial white spaces.
197     if(cursorPosition < numberOfWhiteSpaces)
198     {
199       cursorPosition = 0u;
200     }
201     else
202     {
203       cursorPosition -= numberOfWhiteSpaces;
204     }
205
206     mEventData->mInputMethodContext.SetCursorPosition(cursorPosition);
207     mEventData->mInputMethodContext.NotifyCursorPosition();
208   }
209 }
210
211 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
212 {
213   if(mEventData && mEventData->mInputMethodContext)
214   {
215     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
216     mEventData->mInputMethodContext.NotifyTextInputMultiLine(layout == Text::Layout::Engine::MULTI_LINE_BOX);
217   }
218 }
219
220 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
221 {
222   CharacterIndex cursorPosition = 0u;
223
224   if(mEventData)
225   {
226     if((EventData::SELECTING == mEventData->mState) ||
227        (EventData::SELECTION_HANDLE_PANNING == mEventData->mState))
228     {
229       cursorPosition = std::min(mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition);
230     }
231     else
232     {
233       cursorPosition = mEventData->mPrimaryCursorPosition;
234     }
235   }
236
237   return cursorPosition;
238 }
239
240 Length Controller::Impl::GetNumberOfWhiteSpaces(CharacterIndex index) const
241 {
242   Length numberOfWhiteSpaces = 0u;
243
244   // Get the buffer to the text.
245   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
246
247   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
248   for(; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces)
249   {
250     if(!TextAbstraction::IsWhiteSpace(*(utf32CharacterBuffer + index)))
251     {
252       break;
253     }
254   }
255
256   return numberOfWhiteSpaces;
257 }
258
259 void Controller::Impl::GetText(CharacterIndex index, std::string& text) const
260 {
261   // Get the total number of characters.
262   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
263
264   // Retrieve the text.
265   if(0u != numberOfCharacters)
266   {
267     Utf32ToUtf8(mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text);
268   }
269 }
270
271 void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
272 {
273   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
274   mTextUpdateInfo.mStartGlyphIndex         = 0u;
275   mTextUpdateInfo.mStartLineIndex          = 0u;
276   numberOfCharacters                       = 0u;
277
278   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
279   if(0u == numberOfParagraphs)
280   {
281     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
282     numberOfCharacters                       = 0u;
283
284     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
285
286     // Nothing else to do if there are no paragraphs.
287     return;
288   }
289
290   // Find the paragraphs to be updated.
291   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
292   if(mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters)
293   {
294     // Text is being added at the end of the current text.
295     if(mTextUpdateInfo.mIsLastCharacterNewParagraph)
296     {
297       // Text is being added in a new paragraph after the last character of the text.
298       mTextUpdateInfo.mParagraphCharacterIndex     = mTextUpdateInfo.mPreviousNumberOfCharacters;
299       numberOfCharacters                           = 0u;
300       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
301
302       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
303       mTextUpdateInfo.mStartLineIndex  = mModel->mVisualModel->mLines.Count() - 1u;
304
305       // Nothing else to do;
306       return;
307     }
308
309     paragraphsToBeUpdated.PushBack(numberOfParagraphs - 1u);
310   }
311   else
312   {
313     Length numberOfCharactersToUpdate = 0u;
314     if(mTextUpdateInfo.mFullRelayoutNeeded)
315     {
316       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
317     }
318     else
319     {
320       numberOfCharactersToUpdate = (mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
321     }
322     mModel->mLogicalModel->FindParagraphs(mTextUpdateInfo.mCharacterIndex,
323                                           numberOfCharactersToUpdate,
324                                           paragraphsToBeUpdated);
325   }
326
327   if(0u != paragraphsToBeUpdated.Count())
328   {
329     const ParagraphRunIndex firstParagraphIndex = *(paragraphsToBeUpdated.Begin());
330     const ParagraphRun&     firstParagraph      = *(mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex);
331     mTextUpdateInfo.mParagraphCharacterIndex    = firstParagraph.characterRun.characterIndex;
332
333     ParagraphRunIndex   lastParagraphIndex = *(paragraphsToBeUpdated.End() - 1u);
334     const ParagraphRun& lastParagraph      = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex);
335
336     if((mTextUpdateInfo.mNumberOfCharactersToRemove > 0u) &&                                           // Some character are removed.
337        (lastParagraphIndex < numberOfParagraphs - 1u) &&                                               // There is a next paragraph.
338        ((lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters) == // The last removed character is the new paragraph character.
339         (mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove)))
340     {
341       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
342       const ParagraphRun& lastParagraph = *(mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u);
343
344       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
345     }
346     else
347     {
348       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
349     }
350   }
351
352   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
353   mTextUpdateInfo.mStartGlyphIndex             = *(mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex);
354 }
355
356 void Controller::Impl::ClearFullModelData(OperationsMask operations)
357 {
358   if(NO_OPERATION != (GET_LINE_BREAKS & operations))
359   {
360     mModel->mLogicalModel->mLineBreakInfo.Clear();
361     mModel->mLogicalModel->mParagraphInfo.Clear();
362   }
363
364   if(NO_OPERATION != (GET_SCRIPTS & operations))
365   {
366     mModel->mLogicalModel->mScriptRuns.Clear();
367   }
368
369   if(NO_OPERATION != (VALIDATE_FONTS & operations))
370   {
371     mModel->mLogicalModel->mFontRuns.Clear();
372   }
373
374   if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
375   {
376     if(NO_OPERATION != (BIDI_INFO & operations))
377     {
378       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
379       mModel->mLogicalModel->mCharacterDirections.Clear();
380     }
381
382     if(NO_OPERATION != (REORDER & operations))
383     {
384       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
385       for(Vector<BidirectionalLineInfoRun>::Iterator it    = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
386                                                      endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
387           it != endIt;
388           ++it)
389       {
390         BidirectionalLineInfoRun& bidiLineInfo = *it;
391
392         free(bidiLineInfo.visualToLogicalMap);
393         bidiLineInfo.visualToLogicalMap = NULL;
394       }
395       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
396     }
397   }
398
399   if(NO_OPERATION != (SHAPE_TEXT & operations))
400   {
401     mModel->mVisualModel->mGlyphs.Clear();
402     mModel->mVisualModel->mGlyphsToCharacters.Clear();
403     mModel->mVisualModel->mCharactersToGlyph.Clear();
404     mModel->mVisualModel->mCharactersPerGlyph.Clear();
405     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
406     mModel->mVisualModel->mGlyphPositions.Clear();
407   }
408
409   if(NO_OPERATION != (LAYOUT & operations))
410   {
411     mModel->mVisualModel->mLines.Clear();
412   }
413
414   if(NO_OPERATION != (COLOR & operations))
415   {
416     mModel->mVisualModel->mColorIndices.Clear();
417     mModel->mVisualModel->mBackgroundColorIndices.Clear();
418   }
419 }
420
421 void Controller::Impl::ClearCharacterModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
422 {
423   const CharacterIndex endIndexPlusOne = endIndex + 1u;
424
425   if(NO_OPERATION != (GET_LINE_BREAKS & operations))
426   {
427     // Clear the line break info.
428     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
429
430     mModel->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex,
431                                                 lineBreakInfoBuffer + endIndexPlusOne);
432
433     // Clear the paragraphs.
434     ClearCharacterRuns(startIndex,
435                        endIndex,
436                        mModel->mLogicalModel->mParagraphInfo);
437   }
438
439   if(NO_OPERATION != (GET_SCRIPTS & operations))
440   {
441     // Clear the scripts.
442     ClearCharacterRuns(startIndex,
443                        endIndex,
444                        mModel->mLogicalModel->mScriptRuns);
445   }
446
447   if(NO_OPERATION != (VALIDATE_FONTS & operations))
448   {
449     // Clear the fonts.
450     ClearCharacterRuns(startIndex,
451                        endIndex,
452                        mModel->mLogicalModel->mFontRuns);
453   }
454
455   if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
456   {
457     if(NO_OPERATION != (BIDI_INFO & operations))
458     {
459       // Clear the bidirectional paragraph info.
460       ClearCharacterRuns(startIndex,
461                          endIndex,
462                          mModel->mLogicalModel->mBidirectionalParagraphInfo);
463
464       // Clear the character's directions.
465       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
466
467       mModel->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex,
468                                                         characterDirectionsBuffer + endIndexPlusOne);
469     }
470
471     if(NO_OPERATION != (REORDER & operations))
472     {
473       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
474       uint32_t endRemoveIndex   = startRemoveIndex;
475       ClearCharacterRuns(startIndex,
476                          endIndex,
477                          mModel->mLogicalModel->mBidirectionalLineInfo,
478                          startRemoveIndex,
479                          endRemoveIndex);
480
481       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
482
483       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
484       for(Vector<BidirectionalLineInfoRun>::Iterator it    = bidirectionalLineInfoBuffer + startRemoveIndex,
485                                                      endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
486           it != endIt;
487           ++it)
488       {
489         BidirectionalLineInfoRun& bidiLineInfo = *it;
490
491         free(bidiLineInfo.visualToLogicalMap);
492         bidiLineInfo.visualToLogicalMap = NULL;
493       }
494
495       mModel->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex,
496                                                           bidirectionalLineInfoBuffer + endRemoveIndex);
497     }
498   }
499 }
500
501 void Controller::Impl::ClearGlyphModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
502 {
503   const CharacterIndex endIndexPlusOne           = endIndex + 1u;
504   const Length         numberOfCharactersRemoved = endIndexPlusOne - startIndex;
505
506   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
507   GlyphIndex* charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
508   Length*     glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
509
510   const GlyphIndex endGlyphIndexPlusOne  = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex);
511   const Length     numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
512
513   if(NO_OPERATION != (SHAPE_TEXT & operations))
514   {
515     // Update the character to glyph indices.
516     for(Vector<GlyphIndex>::Iterator it    = charactersToGlyphBuffer + endIndexPlusOne,
517                                      endIt = charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
518         it != endIt;
519         ++it)
520     {
521       CharacterIndex& index = *it;
522       index -= numberOfGlyphsRemoved;
523     }
524
525     // Clear the character to glyph conversion table.
526     mModel->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex,
527                                                    charactersToGlyphBuffer + endIndexPlusOne);
528
529     // Clear the glyphs per character table.
530     mModel->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex,
531                                                     glyphsPerCharacterBuffer + endIndexPlusOne);
532
533     // Clear the glyphs buffer.
534     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
535     mModel->mVisualModel->mGlyphs.Erase(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
536                                         glyphsBuffer + endGlyphIndexPlusOne);
537
538     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
539
540     // Update the glyph to character indices.
541     for(Vector<CharacterIndex>::Iterator it    = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
542                                          endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
543         it != endIt;
544         ++it)
545     {
546       CharacterIndex& index = *it;
547       index -= numberOfCharactersRemoved;
548     }
549
550     // Clear the glyphs to characters buffer.
551     mModel->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
552                                                     glyphsToCharactersBuffer + endGlyphIndexPlusOne);
553
554     // Clear the characters per glyph buffer.
555     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
556     mModel->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
557                                                     charactersPerGlyphBuffer + endGlyphIndexPlusOne);
558
559     // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout
560     if(0u != mModel->mVisualModel->mGlyphPositions.Count())
561     {
562       // Clear the positions buffer.
563       Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
564       mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
565                                                   positionsBuffer + endGlyphIndexPlusOne);
566     }
567   }
568
569   if(NO_OPERATION != (LAYOUT & operations))
570   {
571     // Clear the lines.
572     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
573     uint32_t endRemoveIndex   = startRemoveIndex;
574     ClearCharacterRuns(startIndex,
575                        endIndex,
576                        mModel->mVisualModel->mLines,
577                        startRemoveIndex,
578                        endRemoveIndex);
579
580     // Will update the glyph runs.
581     startRemoveIndex = mModel->mVisualModel->mLines.Count();
582     endRemoveIndex   = startRemoveIndex;
583     ClearGlyphRuns(mTextUpdateInfo.mStartGlyphIndex,
584                    endGlyphIndexPlusOne - 1u,
585                    mModel->mVisualModel->mLines,
586                    startRemoveIndex,
587                    endRemoveIndex);
588
589     // Set the line index from where to insert the new laid-out lines.
590     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
591
592     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
593     mModel->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
594                                        linesBuffer + endRemoveIndex);
595   }
596
597   if(NO_OPERATION != (COLOR & operations))
598   {
599     if(0u != mModel->mVisualModel->mColorIndices.Count())
600     {
601       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
602       mModel->mVisualModel->mColorIndices.Erase(colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
603                                                 colorIndexBuffer + endGlyphIndexPlusOne);
604     }
605
606     if(0u != mModel->mVisualModel->mBackgroundColorIndices.Count())
607     {
608       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
609       mModel->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
610                                                           backgroundColorIndexBuffer + endGlyphIndexPlusOne);
611     }
612   }
613 }
614
615 void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
616 {
617   if(mTextUpdateInfo.mClearAll ||
618      ((0u == startIndex) &&
619       (mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
620   {
621     ClearFullModelData(operations);
622   }
623   else
624   {
625     // Clear the model data related with characters.
626     ClearCharacterModelData(startIndex, endIndex, operations);
627
628     // Clear the model data related with glyphs.
629     ClearGlyphModelData(startIndex, endIndex, operations);
630   }
631
632   // The estimated number of lines. Used to avoid reallocations when layouting.
633   mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
634
635   mModel->mVisualModel->ClearCaches();
636 }
637
638 bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
639 {
640   return ControllerImplModelUpdater::Update(*this, operationsRequired);
641 }
642
643 void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
644 {
645   SetDefaultInputStyle(inputStyle, mFontDefaults, mTextColor);
646 }
647
648 float Controller::Impl::GetDefaultFontLineHeight()
649 {
650   FontId defaultFontId = 0u;
651   if(nullptr == mFontDefaults)
652   {
653     TextAbstraction::FontDescription fontDescription;
654     defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
655   }
656   else
657   {
658     defaultFontId = mFontDefaults->GetFontId(mFontClient, mFontDefaults->mDefaultPointSize * mFontSizeScale);
659   }
660
661   Text::FontMetrics fontMetrics;
662   mMetrics->GetFontMetrics(defaultFontId, fontMetrics);
663
664   return (fontMetrics.ascender - fontMetrics.descender);
665 }
666
667 void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd)
668 {
669   if(nullptr == mEventData)
670   {
671     // Nothing to do if there is no text.
672     return;
673   }
674
675   if(mEventData->mSelectionEnabled && (pStart || pEnd))
676   {
677     uint32_t length   = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
678     uint32_t oldStart = mEventData->mLeftSelectionPosition;
679     uint32_t oldEnd   = mEventData->mRightSelectionPosition;
680
681     if(pStart)
682     {
683       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
684     }
685     if(pEnd)
686     {
687       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
688     }
689
690     if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
691     {
692       ChangeState(EventData::EDITING);
693       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
694       mEventData->mUpdateCursorPosition                                       = true;
695     }
696     else
697     {
698       ChangeState(EventData::SELECTING);
699       mEventData->mUpdateHighlightBox           = true;
700       mEventData->mUpdateLeftSelectionPosition  = true;
701       mEventData->mUpdateRightSelectionPosition = true;
702     }
703
704     if(mSelectableControlInterface != nullptr)
705     {
706       mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
707     }
708   }
709 }
710
711 CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
712 {
713   if(nullptr == mEventData)
714   {
715     return 0;
716   }
717   return mEventData->mPrimaryCursorPosition;
718 }
719
720 bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
721 {
722   if(nullptr == mEventData)
723   {
724     // Nothing to do if there is no text.
725     return false;
726   }
727
728   if(mEventData->mPrimaryCursorPosition == index && mEventData->mState != EventData::SELECTING)
729   {
730     // Nothing for same cursor position.
731     return false;
732   }
733
734   uint32_t length                    = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
735   uint32_t oldCursorPos              = mEventData->mPrimaryCursorPosition;
736   mEventData->mPrimaryCursorPosition = std::min(index, length);
737   // If there is no focus, only the value is updated.
738   if(focused)
739   {
740     bool     wasInSelectingState = mEventData->mState == EventData::SELECTING;
741     uint32_t oldStart            = mEventData->mLeftSelectionPosition;
742     uint32_t oldEnd              = mEventData->mRightSelectionPosition;
743     ChangeState(EventData::EDITING);
744     mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
745     mEventData->mUpdateCursorPosition                                        = true;
746
747     if(mSelectableControlInterface != nullptr && wasInSelectingState)
748     {
749       mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
750     }
751
752     ScrollTextToMatchCursor();
753   }
754
755   if(nullptr != mEditableControlInterface)
756   {
757     mEditableControlInterface->CursorPositionChanged(oldCursorPos, mEventData->mPrimaryCursorPosition);
758   }
759
760   return true;
761 }
762
763 Uint32Pair Controller::Impl::GetTextSelectionRange() const
764 {
765   Uint32Pair range;
766
767   if(mEventData)
768   {
769     range.first  = mEventData->mLeftSelectionPosition;
770     range.second = mEventData->mRightSelectionPosition;
771   }
772
773   return range;
774 }
775
776 bool Controller::Impl::IsEditable() const
777 {
778   return mEventData && mEventData->mEditingEnabled;
779 }
780
781 void Controller::Impl::SetEditable(bool editable)
782 {
783   if(mEventData)
784   {
785     mEventData->mEditingEnabled = editable;
786   }
787 }
788
789 void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval)
790 {
791   if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
792   {
793     // Nothing to select if handles are in the same place.
794     selectedText.clear();
795     return;
796   }
797
798   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
799
800   //Get start and end position of selection
801   const CharacterIndex startOfSelectedText  = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
802   const Length         lengthOfSelectedText = (handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition) - startOfSelectedText;
803
804   Vector<Character>& utf32Characters    = mModel->mLogicalModel->mText;
805   const Length       numberOfCharacters = utf32Characters.Count();
806
807   // Validate the start and end selection points
808   if((startOfSelectedText + lengthOfSelectedText) <= numberOfCharacters)
809   {
810     //Get text as a UTF8 string
811     Utf32ToUtf8(&utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText);
812
813     if(deleteAfterRetrieval) // Only delete text if copied successfully
814     {
815       // Keep a copy of the current input style.
816       InputStyle currentInputStyle;
817       currentInputStyle.Copy(mEventData->mInputStyle);
818
819       // Set as input style the style of the first deleted character.
820       mModel->mLogicalModel->RetrieveStyle(startOfSelectedText, mEventData->mInputStyle);
821
822       // Compare if the input style has changed.
823       const bool hasInputStyleChanged = !currentInputStyle.Equal(mEventData->mInputStyle);
824
825       if(hasInputStyleChanged)
826       {
827         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mEventData->mInputStyle);
828         // Queue the input style changed signal.
829         mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
830       }
831
832       mModel->mLogicalModel->UpdateTextStyleRuns(startOfSelectedText, -static_cast<int>(lengthOfSelectedText));
833
834       // Mark the paragraphs to be updated.
835       if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
836       {
837         mTextUpdateInfo.mCharacterIndex             = 0;
838         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
839         mTextUpdateInfo.mNumberOfCharactersToAdd    = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
840         mTextUpdateInfo.mClearAll                   = true;
841       }
842       else
843       {
844         mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
845         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
846       }
847
848       // Delete text between handles
849       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
850       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
851       utf32Characters.Erase(first, last);
852
853       // Will show the cursor at the first character of the selection.
854       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
855     }
856     else
857     {
858       // Will show the cursor at the last character of the selection.
859       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
860     }
861
862     mEventData->mDecoratorUpdated = true;
863   }
864 }
865
866 void Controller::Impl::SetSelection(int start, int end)
867 {
868   uint32_t oldStart = mEventData->mLeftSelectionPosition;
869   uint32_t oldEnd   = mEventData->mRightSelectionPosition;
870
871   mEventData->mLeftSelectionPosition  = start;
872   mEventData->mRightSelectionPosition = end;
873   mEventData->mUpdateCursorPosition   = true;
874
875   if(mSelectableControlInterface != nullptr)
876   {
877     mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
878   }
879 }
880
881 std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
882 {
883   return {mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition};
884 }
885
886 void Controller::Impl::ShowClipboard()
887 {
888   if(mClipboard)
889   {
890     mClipboard.ShowClipboard();
891   }
892 }
893
894 void Controller::Impl::HideClipboard()
895 {
896   if(mClipboard && mClipboardHideEnabled)
897   {
898     mClipboard.HideClipboard();
899   }
900 }
901
902 void Controller::Impl::SetClipboardHideEnable(bool enable)
903 {
904   mClipboardHideEnabled = enable;
905 }
906
907 bool Controller::Impl::CopyStringToClipboard(const std::string& source)
908 {
909   //Send string to clipboard
910   return (mClipboard && mClipboard.SetItem(source));
911 }
912
913 void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
914 {
915   std::string selectedText;
916   RetrieveSelection(selectedText, deleteAfterSending);
917   CopyStringToClipboard(selectedText);
918   ChangeState(EventData::EDITING);
919 }
920
921 void Controller::Impl::RequestGetTextFromClipboard()
922 {
923   if(mClipboard)
924   {
925     mClipboard.RequestItem();
926   }
927 }
928
929 void Controller::Impl::RepositionSelectionHandles()
930 {
931   SelectionHandleController::Reposition(*this);
932 }
933 void Controller::Impl::RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action)
934 {
935   SelectionHandleController::Reposition(*this, visualX, visualY, action);
936 }
937
938 void Controller::Impl::SetPopupButtons()
939 {
940   /**
941    *  Sets the Popup buttons to be shown depending on State.
942    *
943    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
944    *
945    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
946    */
947
948   bool                        isEditable    = IsEditable();
949   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
950
951   if(EventData::SELECTING == mEventData->mState)
952   {
953     buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::COPY);
954     if(isEditable)
955     {
956       buttonsToShow = TextSelectionPopup::Buttons(buttonsToShow | TextSelectionPopup::CUT);
957     }
958
959     if(!IsClipboardEmpty())
960     {
961       if(isEditable)
962       {
963         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
964       }
965       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
966     }
967
968     if(!mEventData->mAllTextSelected)
969     {
970       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::SELECT_ALL));
971     }
972   }
973   else if(EventData::EDITING_WITH_POPUP == mEventData->mState)
974   {
975     if(mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
976     {
977       buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL);
978     }
979
980     if(!IsClipboardEmpty())
981     {
982       if(isEditable)
983       {
984         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
985       }
986       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
987     }
988   }
989   else if(EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState)
990   {
991     if(!IsClipboardEmpty())
992     {
993       if(isEditable)
994       {
995         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
996       }
997       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
998     }
999   }
1000
1001   mEventData->mDecorator->SetEnabledPopupButtons(buttonsToShow);
1002 }
1003
1004 void Controller::Impl::ChangeState(EventData::State newState)
1005 {
1006   if(nullptr == mEventData)
1007   {
1008     // Nothing to do if there is no text input.
1009     return;
1010   }
1011
1012   DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState);
1013
1014   if(mEventData->mState != newState)
1015   {
1016     mEventData->mPreviousState = mEventData->mState;
1017     mEventData->mState         = newState;
1018
1019     switch(mEventData->mState)
1020     {
1021       case EventData::INACTIVE:
1022       {
1023         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1024         mEventData->mDecorator->StopCursorBlink();
1025         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1026         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1027         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1028         mEventData->mDecorator->SetHighlightActive(false);
1029         mEventData->mDecorator->SetPopupActive(false);
1030         mEventData->mDecoratorUpdated = true;
1031         break;
1032       }
1033       case EventData::INTERRUPTED:
1034       {
1035         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1036         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1037         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1038         mEventData->mDecorator->SetHighlightActive(false);
1039         mEventData->mDecorator->SetPopupActive(false);
1040         mEventData->mDecoratorUpdated = true;
1041         break;
1042       }
1043       case EventData::SELECTING:
1044       {
1045         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1046         mEventData->mDecorator->StopCursorBlink();
1047         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1048         if(mEventData->mGrabHandleEnabled)
1049         {
1050           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1051           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1052         }
1053         mEventData->mDecorator->SetHighlightActive(true);
1054         if(mEventData->mGrabHandlePopupEnabled)
1055         {
1056           SetPopupButtons();
1057           mEventData->mDecorator->SetPopupActive(true);
1058         }
1059         mEventData->mDecoratorUpdated = true;
1060         break;
1061       }
1062       case EventData::EDITING:
1063       {
1064         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1065         if(mEventData->mCursorBlinkEnabled)
1066         {
1067           mEventData->mDecorator->StartCursorBlink();
1068         }
1069         // Grab handle is not shown until a tap is received whilst EDITING
1070         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1071         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1072         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1073         mEventData->mDecorator->SetHighlightActive(false);
1074         if(mEventData->mGrabHandlePopupEnabled)
1075         {
1076           mEventData->mDecorator->SetPopupActive(false);
1077         }
1078         mEventData->mDecoratorUpdated = true;
1079         break;
1080       }
1081       case EventData::EDITING_WITH_POPUP:
1082       {
1083         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
1084
1085         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1086         if(mEventData->mCursorBlinkEnabled)
1087         {
1088           mEventData->mDecorator->StartCursorBlink();
1089         }
1090         if(mEventData->mSelectionEnabled)
1091         {
1092           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1093           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1094           mEventData->mDecorator->SetHighlightActive(false);
1095         }
1096         else if(mEventData->mGrabHandleEnabled)
1097         {
1098           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1099         }
1100         if(mEventData->mGrabHandlePopupEnabled)
1101         {
1102           SetPopupButtons();
1103           mEventData->mDecorator->SetPopupActive(true);
1104         }
1105         mEventData->mDecoratorUpdated = true;
1106         break;
1107       }
1108       case EventData::EDITING_WITH_GRAB_HANDLE:
1109       {
1110         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
1111
1112         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1113         if(mEventData->mCursorBlinkEnabled)
1114         {
1115           mEventData->mDecorator->StartCursorBlink();
1116         }
1117         // Grab handle is not shown until a tap is received whilst EDITING
1118         if(mEventData->mGrabHandleEnabled)
1119         {
1120           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1121         }
1122         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1123         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1124         mEventData->mDecorator->SetHighlightActive(false);
1125         if(mEventData->mGrabHandlePopupEnabled)
1126         {
1127           mEventData->mDecorator->SetPopupActive(false);
1128         }
1129         mEventData->mDecoratorUpdated = true;
1130         break;
1131       }
1132       case EventData::SELECTION_HANDLE_PANNING:
1133       {
1134         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1135         mEventData->mDecorator->StopCursorBlink();
1136         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1137         if(mEventData->mGrabHandleEnabled)
1138         {
1139           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1140           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1141         }
1142         mEventData->mDecorator->SetHighlightActive(true);
1143         if(mEventData->mGrabHandlePopupEnabled)
1144         {
1145           mEventData->mDecorator->SetPopupActive(false);
1146         }
1147         mEventData->mDecoratorUpdated = true;
1148         break;
1149       }
1150       case EventData::GRAB_HANDLE_PANNING:
1151       {
1152         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
1153
1154         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1155         if(mEventData->mCursorBlinkEnabled)
1156         {
1157           mEventData->mDecorator->StartCursorBlink();
1158         }
1159         if(mEventData->mGrabHandleEnabled)
1160         {
1161           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1162         }
1163         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1164         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1165         mEventData->mDecorator->SetHighlightActive(false);
1166         if(mEventData->mGrabHandlePopupEnabled)
1167         {
1168           mEventData->mDecorator->SetPopupActive(false);
1169         }
1170         mEventData->mDecoratorUpdated = true;
1171         break;
1172       }
1173       case EventData::EDITING_WITH_PASTE_POPUP:
1174       {
1175         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
1176
1177         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1178         if(mEventData->mCursorBlinkEnabled)
1179         {
1180           mEventData->mDecorator->StartCursorBlink();
1181         }
1182
1183         if(mEventData->mGrabHandleEnabled)
1184         {
1185           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1186         }
1187         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1188         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1189         mEventData->mDecorator->SetHighlightActive(false);
1190
1191         if(mEventData->mGrabHandlePopupEnabled)
1192         {
1193           SetPopupButtons();
1194           mEventData->mDecorator->SetPopupActive(true);
1195         }
1196         mEventData->mDecoratorUpdated = true;
1197         break;
1198       }
1199       case EventData::TEXT_PANNING:
1200       {
1201         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1202         mEventData->mDecorator->StopCursorBlink();
1203         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1204         if(mEventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
1205            mEventData->mDecorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
1206         {
1207           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1208           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1209           mEventData->mDecorator->SetHighlightActive(true);
1210         }
1211
1212         if(mEventData->mGrabHandlePopupEnabled)
1213         {
1214           mEventData->mDecorator->SetPopupActive(false);
1215         }
1216
1217         mEventData->mDecoratorUpdated = true;
1218         break;
1219       }
1220     }
1221   }
1222 }
1223
1224 void Controller::Impl::GetCursorPosition(CharacterIndex logical,
1225                                          CursorInfo&    cursorInfo)
1226 {
1227   if(!IsShowingRealText())
1228   {
1229     // Do not want to use the place-holder text to set the cursor position.
1230
1231     // Use the line's height of the font's family set to set the cursor's size.
1232     // If there is no font's family set, use the default font.
1233     // Use the current alignment to place the cursor at the beginning, center or end of the box.
1234
1235     cursorInfo.lineOffset          = 0.f;
1236     cursorInfo.lineHeight          = GetDefaultFontLineHeight();
1237     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
1238
1239     bool isRTL = false;
1240     if(mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS)
1241     {
1242       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
1243     }
1244
1245     switch(mModel->mHorizontalAlignment)
1246     {
1247       case Text::HorizontalAlignment::BEGIN:
1248       {
1249         if(isRTL)
1250         {
1251           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1252         }
1253         else
1254         {
1255           cursorInfo.primaryPosition.x = 0.f;
1256         }
1257         break;
1258       }
1259       case Text::HorizontalAlignment::CENTER:
1260       {
1261         cursorInfo.primaryPosition.x = floorf(0.5f * mModel->mVisualModel->mControlSize.width);
1262         break;
1263       }
1264       case Text::HorizontalAlignment::END:
1265       {
1266         if(isRTL)
1267         {
1268           cursorInfo.primaryPosition.x = 0.f;
1269         }
1270         else
1271         {
1272           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1273         }
1274         break;
1275       }
1276     }
1277
1278     // Nothing else to do.
1279     return;
1280   }
1281
1282   const bool                  isMultiLine = (Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout());
1283   GetCursorPositionParameters parameters;
1284   parameters.visualModel  = mModel->mVisualModel;
1285   parameters.logicalModel = mModel->mLogicalModel;
1286   parameters.metrics      = mMetrics;
1287   parameters.logical      = logical;
1288   parameters.isMultiline  = isMultiLine;
1289
1290   Text::GetCursorPosition(parameters,
1291                           cursorInfo);
1292
1293   // Adds Outline offset.
1294   const float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
1295   cursorInfo.primaryPosition.x += outlineWidth;
1296   cursorInfo.primaryPosition.y += outlineWidth;
1297   cursorInfo.secondaryPosition.x += outlineWidth;
1298   cursorInfo.secondaryPosition.y += outlineWidth;
1299
1300   if(isMultiLine)
1301   {
1302     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
1303
1304     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
1305     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
1306
1307     if(0.f > cursorInfo.primaryPosition.x)
1308     {
1309       cursorInfo.primaryPosition.x = 0.f;
1310     }
1311
1312     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>(mEventData->mDecorator->GetCursorWidth());
1313     if(cursorInfo.primaryPosition.x > edgeWidth)
1314     {
1315       cursorInfo.primaryPosition.x = edgeWidth;
1316     }
1317   }
1318 }
1319
1320 CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
1321 {
1322   if(nullptr == mEventData)
1323   {
1324     // Nothing to do if there is no text input.
1325     return 0u;
1326   }
1327
1328   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
1329
1330   const GlyphIndex* const charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
1331   const Length* const     charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1332
1333   GlyphIndex glyphIndex         = *(charactersToGlyphBuffer + index);
1334   Length     numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1335
1336   if(numberOfCharacters > 1u)
1337   {
1338     const Script script = mModel->mLogicalModel->GetScript(index);
1339     if(HasLigatureMustBreak(script))
1340     {
1341       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
1342       numberOfCharacters = 1u;
1343     }
1344   }
1345   else
1346   {
1347     while(0u == numberOfCharacters)
1348     {
1349       ++glyphIndex;
1350       numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1351     }
1352   }
1353
1354   if(index < mEventData->mPrimaryCursorPosition)
1355   {
1356     cursorIndex -= numberOfCharacters;
1357   }
1358   else
1359   {
1360     cursorIndex += numberOfCharacters;
1361   }
1362
1363   // Will update the cursor hook position.
1364   mEventData->mUpdateCursorHookPosition = true;
1365
1366   return cursorIndex;
1367 }
1368
1369 void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
1370 {
1371   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
1372   if(nullptr == mEventData)
1373   {
1374     // Nothing to do if there is no text input.
1375     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
1376     return;
1377   }
1378
1379   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
1380
1381   mEventData->mDecorator->SetGlyphOffset(PRIMARY_CURSOR, cursorInfo.glyphOffset);
1382
1383   // Sets the cursor position.
1384   mEventData->mDecorator->SetPosition(PRIMARY_CURSOR,
1385                                       cursorPosition.x,
1386                                       cursorPosition.y,
1387                                       cursorInfo.primaryCursorHeight,
1388                                       cursorInfo.lineHeight);
1389   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y);
1390
1391   if(mEventData->mUpdateGrabHandlePosition)
1392   {
1393     // Sets the grab handle position.
1394     mEventData->mDecorator->SetPosition(GRAB_HANDLE,
1395                                         cursorPosition.x,
1396                                         cursorInfo.lineOffset + mModel->mScrollPosition.y,
1397                                         cursorInfo.lineHeight);
1398   }
1399
1400   if(cursorInfo.isSecondaryCursor)
1401   {
1402     mEventData->mDecorator->SetPosition(SECONDARY_CURSOR,
1403                                         cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
1404                                         cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
1405                                         cursorInfo.secondaryCursorHeight,
1406                                         cursorInfo.lineHeight);
1407     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y);
1408   }
1409
1410   // Set which cursors are active according the state.
1411   if(EventData::IsEditingState(mEventData->mState) || (EventData::GRAB_HANDLE_PANNING == mEventData->mState))
1412   {
1413     if(cursorInfo.isSecondaryCursor)
1414     {
1415       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_BOTH);
1416     }
1417     else
1418     {
1419       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1420     }
1421   }
1422   else
1423   {
1424     mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1425   }
1426
1427   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n");
1428 }
1429
1430 void Controller::Impl::UpdateSelectionHandle(HandleType        handleType,
1431                                              const CursorInfo& cursorInfo)
1432 {
1433   SelectionHandleController::Update(*this, handleType, cursorInfo);
1434 }
1435
1436 void Controller::Impl::ClampHorizontalScroll(const Vector2& layoutSize)
1437 {
1438   // Clamp between -space & -alignment offset.
1439
1440   if(layoutSize.width > mModel->mVisualModel->mControlSize.width)
1441   {
1442     const float space         = (layoutSize.width - mModel->mVisualModel->mControlSize.width) + mModel->mAlignmentOffset;
1443     mModel->mScrollPosition.x = (mModel->mScrollPosition.x < -space) ? -space : mModel->mScrollPosition.x;
1444     mModel->mScrollPosition.x = (mModel->mScrollPosition.x > -mModel->mAlignmentOffset) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
1445
1446     mEventData->mDecoratorUpdated = true;
1447   }
1448   else
1449   {
1450     mModel->mScrollPosition.x = 0.f;
1451   }
1452 }
1453
1454 void Controller::Impl::ClampVerticalScroll(const Vector2& layoutSize)
1455 {
1456   if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
1457   {
1458     // Nothing to do if the text is single line.
1459     return;
1460   }
1461
1462   // Clamp between -space & 0.
1463   if(layoutSize.height > mModel->mVisualModel->mControlSize.height)
1464   {
1465     const float space         = (layoutSize.height - mModel->mVisualModel->mControlSize.height);
1466     mModel->mScrollPosition.y = (mModel->mScrollPosition.y < -space) ? -space : mModel->mScrollPosition.y;
1467     mModel->mScrollPosition.y = (mModel->mScrollPosition.y > 0.f) ? 0.f : mModel->mScrollPosition.y;
1468
1469     mEventData->mDecoratorUpdated = true;
1470   }
1471   else
1472   {
1473     mModel->mScrollPosition.y = 0.f;
1474   }
1475 }
1476
1477 void Controller::Impl::ScrollToMakePositionVisible(const Vector2& position, float lineHeight)
1478 {
1479   const float cursorWidth = mEventData->mDecorator ? static_cast<float>(mEventData->mDecorator->GetCursorWidth()) : 0.f;
1480
1481   // position is in actor's coords.
1482   const float positionEndX = position.x + cursorWidth;
1483   const float positionEndY = position.y + lineHeight;
1484
1485   // Transform the position to decorator coords.
1486   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
1487   const float decoratorPositionEndX   = positionEndX + mModel->mScrollPosition.x;
1488
1489   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
1490   const float decoratorPositionEndY   = positionEndY + mModel->mScrollPosition.y;
1491
1492   if(decoratorPositionBeginX < 0.f)
1493   {
1494     mModel->mScrollPosition.x = -position.x;
1495   }
1496   else if(decoratorPositionEndX > mModel->mVisualModel->mControlSize.width)
1497   {
1498     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
1499   }
1500
1501   if(Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout())
1502   {
1503     if(decoratorPositionBeginY < 0.f)
1504     {
1505       mModel->mScrollPosition.y = -position.y;
1506     }
1507     else if(decoratorPositionEndY > mModel->mVisualModel->mControlSize.height)
1508     {
1509       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
1510     }
1511   }
1512 }
1513
1514 void Controller::Impl::ScrollTextToMatchCursor(const CursorInfo& cursorInfo)
1515 {
1516   // Get the current cursor position in decorator coords.
1517   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
1518
1519   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter(mEventData->mPrimaryCursorPosition);
1520
1521   // Calculate the offset to match the cursor position before the character was deleted.
1522   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
1523
1524   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
1525   if(mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() - 1u)
1526   {
1527     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset(PRIMARY_CURSOR);
1528     mModel->mScrollPosition.y            = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
1529   }
1530
1531   ClampHorizontalScroll(mModel->mVisualModel->GetLayoutSize());
1532   ClampVerticalScroll(mModel->mVisualModel->GetLayoutSize());
1533
1534   // Makes the new cursor position visible if needed.
1535   ScrollToMakePositionVisible(cursorInfo.primaryPosition, cursorInfo.lineHeight);
1536 }
1537
1538 void Controller::Impl::ScrollTextToMatchCursor()
1539 {
1540   CursorInfo cursorInfo;
1541   GetCursorPosition(mEventData->mPrimaryCursorPosition, cursorInfo);
1542   ScrollTextToMatchCursor(cursorInfo);
1543 }
1544
1545 void Controller::Impl::RequestRelayout()
1546 {
1547   if(nullptr != mControlInterface)
1548   {
1549     mControlInterface->RequestTextRelayout();
1550   }
1551 }
1552
1553 Actor Controller::Impl::CreateBackgroundActor()
1554 {
1555   // NOTE: Currently we only support background color for left-to-right text.
1556
1557   Actor actor;
1558
1559   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
1560   if(numberOfGlyphs > 0u)
1561   {
1562     Vector<GlyphInfo> glyphs;
1563     glyphs.Resize(numberOfGlyphs);
1564
1565     Vector<Vector2> positions;
1566     positions.Resize(numberOfGlyphs);
1567
1568     // Get the line where the glyphs are laid-out.
1569     const LineRun* lineRun         = mModel->mVisualModel->mLines.Begin();
1570     float          alignmentOffset = lineRun->alignmentOffset;
1571     numberOfGlyphs                 = mView.GetGlyphs(glyphs.Begin(),
1572                                      positions.Begin(),
1573                                      alignmentOffset,
1574                                      0u,
1575                                      numberOfGlyphs);
1576
1577     glyphs.Resize(numberOfGlyphs);
1578     positions.Resize(numberOfGlyphs);
1579
1580     const GlyphInfo* const glyphsBuffer    = glyphs.Begin();
1581     const Vector2* const   positionsBuffer = positions.Begin();
1582
1583     BackgroundMesh mesh;
1584     mesh.mVertices.Reserve(4u * glyphs.Size());
1585     mesh.mIndices.Reserve(6u * glyphs.Size());
1586
1587     const Vector2 textSize = mView.GetLayoutSize();
1588
1589     const float offsetX = alignmentOffset + textSize.width * 0.5f;
1590     const float offsetY = textSize.height * 0.5f;
1591
1592     const Vector4* const    backgroundColorsBuffer       = mView.GetBackgroundColors();
1593     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
1594     const Vector4&          defaultBackgroundColor       = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
1595
1596     Vector4   quad;
1597     uint32_t  numberOfQuads = 0u;
1598     Length    yLineOffset   = 0;
1599     Length    prevLineIndex = 0;
1600     LineIndex lineIndex;
1601     Length    numberOfLines;
1602
1603     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
1604     {
1605       const GlyphInfo& glyph = *(glyphsBuffer + i);
1606
1607       // Get the background color of the character.
1608       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
1609       const bool       isMarkupBackground       = mView.IsMarkupBackgroundColorSet();
1610       const ColorIndex backgroundColorIndex     = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
1611       const bool       isDefaultBackgroundColor = (0u == backgroundColorIndex);
1612       const Vector4&   backgroundColor          = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
1613
1614       mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
1615       Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
1616
1617       if(lineIndex != prevLineIndex)
1618       {
1619         yLineOffset += lineHeight;
1620       }
1621
1622       // Only create quads for glyphs with a background color
1623       if(backgroundColor != Color::TRANSPARENT)
1624       {
1625         const Vector2 position = *(positionsBuffer + i);
1626
1627         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
1628         {
1629           quad.x = position.x;
1630           quad.y = yLineOffset;
1631           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
1632           quad.w = lineHeight;
1633         }
1634         else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
1635         {
1636           quad.x = position.x;
1637           quad.y = yLineOffset;
1638           quad.z = quad.x - glyph.xBearing + glyph.advance;
1639           quad.w = quad.y + lineHeight;
1640         }
1641         else if(i == glyphSize - 1u) // The last glyph in the whole text
1642         {
1643           quad.x = position.x - glyph.xBearing;
1644           quad.y = yLineOffset;
1645           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
1646           quad.w = quad.y + lineHeight;
1647         }
1648         else // The glyph in the middle of the text
1649         {
1650           quad.x = position.x - glyph.xBearing;
1651           quad.y = yLineOffset;
1652           quad.z = quad.x + glyph.advance;
1653           quad.w = quad.y + lineHeight;
1654         }
1655
1656         BackgroundVertex vertex;
1657
1658         // Top left
1659         vertex.mPosition.x = quad.x - offsetX;
1660         vertex.mPosition.y = quad.y - offsetY;
1661         vertex.mColor      = backgroundColor;
1662         mesh.mVertices.PushBack(vertex);
1663
1664         // Top right
1665         vertex.mPosition.x = quad.z - offsetX;
1666         vertex.mPosition.y = quad.y - offsetY;
1667         vertex.mColor      = backgroundColor;
1668         mesh.mVertices.PushBack(vertex);
1669
1670         // Bottom left
1671         vertex.mPosition.x = quad.x - offsetX;
1672         vertex.mPosition.y = quad.w - offsetY;
1673         vertex.mColor      = backgroundColor;
1674         mesh.mVertices.PushBack(vertex);
1675
1676         // Bottom right
1677         vertex.mPosition.x = quad.z - offsetX;
1678         vertex.mPosition.y = quad.w - offsetY;
1679         vertex.mColor      = backgroundColor;
1680         mesh.mVertices.PushBack(vertex);
1681
1682         // Six indices in counter clockwise winding
1683         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
1684         mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
1685         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
1686         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
1687         mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
1688         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
1689
1690         numberOfQuads++;
1691       }
1692
1693       if(lineIndex != prevLineIndex)
1694       {
1695         prevLineIndex = lineIndex;
1696       }
1697     }
1698
1699     // Only create the background actor if there are glyphs with background color
1700     if(mesh.mVertices.Count() > 0u)
1701     {
1702       Property::Map quadVertexFormat;
1703       quadVertexFormat["aPosition"] = Property::VECTOR2;
1704       quadVertexFormat["aColor"]    = Property::VECTOR4;
1705
1706       VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
1707       quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
1708
1709       Geometry quadGeometry = Geometry::New();
1710       quadGeometry.AddVertexBuffer(quadVertices);
1711       quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
1712
1713       if(!mShaderBackground)
1714       {
1715         mShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
1716       }
1717
1718       Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, mShaderBackground);
1719       renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
1720       renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
1721
1722       actor = Actor::New();
1723       actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
1724       actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
1725       actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
1726       actor.SetProperty(Actor::Property::SIZE, textSize);
1727       actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
1728       actor.AddRenderer(renderer);
1729     }
1730   }
1731
1732   return actor;
1733 }
1734
1735 void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
1736 {
1737   //Underlined character runs for markup-processor
1738   const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
1739   const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
1740   const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
1741
1742   if(shouldClearPreUnderlineRuns)
1743   {
1744     mModel->mVisualModel->mUnderlineRuns.Clear();
1745   }
1746
1747   for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
1748   {
1749     CharacterIndex characterIndex     = it->characterRun.characterIndex;
1750     Length         numberOfCharacters = it->characterRun.numberOfCharacters;
1751     for(Length index = 0u; index < numberOfCharacters; index++)
1752     {
1753       GlyphRun underlineGlyphRun;
1754       underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
1755       underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
1756       mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
1757     }
1758   }
1759 }
1760
1761 } // namespace Dali::Toolkit::Text