Merge "(Text Controller) Moved some input properties into a different class & some...
[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     if(mEventData->mDecorator)
788     {
789       mEventData->mDecorator->SetEditable(editable);
790     }
791   }
792 }
793
794 void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval)
795 {
796   if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
797   {
798     // Nothing to select if handles are in the same place.
799     selectedText.clear();
800     return;
801   }
802
803   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
804
805   //Get start and end position of selection
806   const CharacterIndex startOfSelectedText  = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
807   const Length         lengthOfSelectedText = (handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition) - startOfSelectedText;
808
809   Vector<Character>& utf32Characters    = mModel->mLogicalModel->mText;
810   const Length       numberOfCharacters = utf32Characters.Count();
811
812   // Validate the start and end selection points
813   if((startOfSelectedText + lengthOfSelectedText) <= numberOfCharacters)
814   {
815     //Get text as a UTF8 string
816     Utf32ToUtf8(&utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText);
817
818     if(deleteAfterRetrieval) // Only delete text if copied successfully
819     {
820       // Keep a copy of the current input style.
821       InputStyle currentInputStyle;
822       currentInputStyle.Copy(mEventData->mInputStyle);
823
824       // Set as input style the style of the first deleted character.
825       mModel->mLogicalModel->RetrieveStyle(startOfSelectedText, mEventData->mInputStyle);
826
827       // Compare if the input style has changed.
828       const bool hasInputStyleChanged = !currentInputStyle.Equal(mEventData->mInputStyle);
829
830       if(hasInputStyleChanged)
831       {
832         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mEventData->mInputStyle);
833         // Queue the input style changed signal.
834         mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
835       }
836
837       mModel->mLogicalModel->UpdateTextStyleRuns(startOfSelectedText, -static_cast<int>(lengthOfSelectedText));
838
839       // Mark the paragraphs to be updated.
840       if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
841       {
842         mTextUpdateInfo.mCharacterIndex             = 0;
843         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
844         mTextUpdateInfo.mNumberOfCharactersToAdd    = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
845         mTextUpdateInfo.mClearAll                   = true;
846       }
847       else
848       {
849         mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
850         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
851       }
852
853       // Delete text between handles
854       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
855       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
856       utf32Characters.Erase(first, last);
857
858       // Will show the cursor at the first character of the selection.
859       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
860     }
861     else
862     {
863       // Will show the cursor at the last character of the selection.
864       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
865     }
866
867     mEventData->mDecoratorUpdated = true;
868   }
869 }
870
871 void Controller::Impl::SetSelection(int start, int end)
872 {
873   uint32_t oldStart = mEventData->mLeftSelectionPosition;
874   uint32_t oldEnd   = mEventData->mRightSelectionPosition;
875
876   mEventData->mLeftSelectionPosition  = start;
877   mEventData->mRightSelectionPosition = end;
878   mEventData->mUpdateCursorPosition   = true;
879
880   if(mSelectableControlInterface != nullptr)
881   {
882     mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
883   }
884 }
885
886 std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
887 {
888   return {mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition};
889 }
890
891 void Controller::Impl::ShowClipboard()
892 {
893   if(mClipboard)
894   {
895     mClipboard.ShowClipboard();
896   }
897 }
898
899 void Controller::Impl::HideClipboard()
900 {
901   if(mClipboard && mClipboardHideEnabled)
902   {
903     mClipboard.HideClipboard();
904   }
905 }
906
907 void Controller::Impl::SetClipboardHideEnable(bool enable)
908 {
909   mClipboardHideEnabled = enable;
910 }
911
912 bool Controller::Impl::CopyStringToClipboard(const std::string& source)
913 {
914   //Send string to clipboard
915   return (mClipboard && mClipboard.SetItem(source));
916 }
917
918 void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
919 {
920   std::string selectedText;
921   RetrieveSelection(selectedText, deleteAfterSending);
922   CopyStringToClipboard(selectedText);
923   ChangeState(EventData::EDITING);
924 }
925
926 void Controller::Impl::RequestGetTextFromClipboard()
927 {
928   if(mClipboard)
929   {
930     mClipboard.RequestItem();
931   }
932 }
933
934 void Controller::Impl::RepositionSelectionHandles()
935 {
936   SelectionHandleController::Reposition(*this);
937 }
938 void Controller::Impl::RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action)
939 {
940   SelectionHandleController::Reposition(*this, visualX, visualY, action);
941 }
942
943 void Controller::Impl::SetPopupButtons()
944 {
945   /**
946    *  Sets the Popup buttons to be shown depending on State.
947    *
948    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
949    *
950    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
951    */
952
953   bool                        isEditable    = IsEditable();
954   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
955
956   if(EventData::SELECTING == mEventData->mState)
957   {
958     buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::COPY);
959     if(isEditable)
960     {
961       buttonsToShow = TextSelectionPopup::Buttons(buttonsToShow | TextSelectionPopup::CUT);
962     }
963
964     if(!IsClipboardEmpty())
965     {
966       if(isEditable)
967       {
968         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
969       }
970       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
971     }
972
973     if(!mEventData->mAllTextSelected)
974     {
975       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::SELECT_ALL));
976     }
977   }
978   else if(EventData::EDITING_WITH_POPUP == mEventData->mState)
979   {
980     if(mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
981     {
982       buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL);
983     }
984
985     if(!IsClipboardEmpty())
986     {
987       if(isEditable)
988       {
989         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
990       }
991       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
992     }
993   }
994   else if(EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState)
995   {
996     if(!IsClipboardEmpty())
997     {
998       if(isEditable)
999       {
1000         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
1001       }
1002       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
1003     }
1004   }
1005
1006   mEventData->mDecorator->SetEnabledPopupButtons(buttonsToShow);
1007 }
1008
1009 void Controller::Impl::ChangeState(EventData::State newState)
1010 {
1011   if(nullptr == mEventData)
1012   {
1013     // Nothing to do if there is no text input.
1014     return;
1015   }
1016
1017   DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState);
1018
1019   if(mEventData->mState != newState)
1020   {
1021     mEventData->mPreviousState = mEventData->mState;
1022     mEventData->mState         = newState;
1023
1024     switch(mEventData->mState)
1025     {
1026       case EventData::INACTIVE:
1027       {
1028         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1029         mEventData->mDecorator->StopCursorBlink();
1030         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1031         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1032         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1033         mEventData->mDecorator->SetHighlightActive(false);
1034         mEventData->mDecorator->SetPopupActive(false);
1035         mEventData->mDecoratorUpdated = true;
1036         break;
1037       }
1038       case EventData::INTERRUPTED:
1039       {
1040         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1041         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1042         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1043         mEventData->mDecorator->SetHighlightActive(false);
1044         mEventData->mDecorator->SetPopupActive(false);
1045         mEventData->mDecoratorUpdated = true;
1046         break;
1047       }
1048       case EventData::SELECTING:
1049       {
1050         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1051         mEventData->mDecorator->StopCursorBlink();
1052         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1053         if(mEventData->mGrabHandleEnabled)
1054         {
1055           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1056           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1057         }
1058         mEventData->mDecorator->SetHighlightActive(true);
1059         if(mEventData->mGrabHandlePopupEnabled)
1060         {
1061           SetPopupButtons();
1062           mEventData->mDecorator->SetPopupActive(true);
1063         }
1064         mEventData->mDecoratorUpdated = true;
1065         break;
1066       }
1067       case EventData::EDITING:
1068       {
1069         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1070         if(mEventData->mCursorBlinkEnabled)
1071         {
1072           mEventData->mDecorator->StartCursorBlink();
1073         }
1074         // Grab handle is not shown until a tap is received whilst EDITING
1075         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1076         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1077         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1078         mEventData->mDecorator->SetHighlightActive(false);
1079         if(mEventData->mGrabHandlePopupEnabled)
1080         {
1081           mEventData->mDecorator->SetPopupActive(false);
1082         }
1083         mEventData->mDecoratorUpdated = true;
1084         break;
1085       }
1086       case EventData::EDITING_WITH_POPUP:
1087       {
1088         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
1089
1090         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1091         if(mEventData->mCursorBlinkEnabled)
1092         {
1093           mEventData->mDecorator->StartCursorBlink();
1094         }
1095         if(mEventData->mSelectionEnabled)
1096         {
1097           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1098           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1099           mEventData->mDecorator->SetHighlightActive(false);
1100         }
1101         else if(mEventData->mGrabHandleEnabled)
1102         {
1103           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1104         }
1105         if(mEventData->mGrabHandlePopupEnabled)
1106         {
1107           SetPopupButtons();
1108           mEventData->mDecorator->SetPopupActive(true);
1109         }
1110         mEventData->mDecoratorUpdated = true;
1111         break;
1112       }
1113       case EventData::EDITING_WITH_GRAB_HANDLE:
1114       {
1115         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
1116
1117         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1118         if(mEventData->mCursorBlinkEnabled)
1119         {
1120           mEventData->mDecorator->StartCursorBlink();
1121         }
1122         // Grab handle is not shown until a tap is received whilst EDITING
1123         if(mEventData->mGrabHandleEnabled)
1124         {
1125           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1126         }
1127         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1128         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1129         mEventData->mDecorator->SetHighlightActive(false);
1130         if(mEventData->mGrabHandlePopupEnabled)
1131         {
1132           mEventData->mDecorator->SetPopupActive(false);
1133         }
1134         mEventData->mDecoratorUpdated = true;
1135         break;
1136       }
1137       case EventData::SELECTION_HANDLE_PANNING:
1138       {
1139         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1140         mEventData->mDecorator->StopCursorBlink();
1141         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1142         if(mEventData->mGrabHandleEnabled)
1143         {
1144           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1145           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1146         }
1147         mEventData->mDecorator->SetHighlightActive(true);
1148         if(mEventData->mGrabHandlePopupEnabled)
1149         {
1150           mEventData->mDecorator->SetPopupActive(false);
1151         }
1152         mEventData->mDecoratorUpdated = true;
1153         break;
1154       }
1155       case EventData::GRAB_HANDLE_PANNING:
1156       {
1157         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
1158
1159         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1160         if(mEventData->mCursorBlinkEnabled)
1161         {
1162           mEventData->mDecorator->StartCursorBlink();
1163         }
1164         if(mEventData->mGrabHandleEnabled)
1165         {
1166           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1167         }
1168         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1169         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1170         mEventData->mDecorator->SetHighlightActive(false);
1171         if(mEventData->mGrabHandlePopupEnabled)
1172         {
1173           mEventData->mDecorator->SetPopupActive(false);
1174         }
1175         mEventData->mDecoratorUpdated = true;
1176         break;
1177       }
1178       case EventData::EDITING_WITH_PASTE_POPUP:
1179       {
1180         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
1181
1182         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1183         if(mEventData->mCursorBlinkEnabled)
1184         {
1185           mEventData->mDecorator->StartCursorBlink();
1186         }
1187
1188         if(mEventData->mGrabHandleEnabled)
1189         {
1190           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1191         }
1192         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1193         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1194         mEventData->mDecorator->SetHighlightActive(false);
1195
1196         if(mEventData->mGrabHandlePopupEnabled)
1197         {
1198           SetPopupButtons();
1199           mEventData->mDecorator->SetPopupActive(true);
1200         }
1201         mEventData->mDecoratorUpdated = true;
1202         break;
1203       }
1204       case EventData::TEXT_PANNING:
1205       {
1206         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1207         mEventData->mDecorator->StopCursorBlink();
1208         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1209         if(mEventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
1210            mEventData->mDecorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
1211         {
1212           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1213           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1214           mEventData->mDecorator->SetHighlightActive(true);
1215         }
1216
1217         if(mEventData->mGrabHandlePopupEnabled)
1218         {
1219           mEventData->mDecorator->SetPopupActive(false);
1220         }
1221
1222         mEventData->mDecoratorUpdated = true;
1223         break;
1224       }
1225     }
1226   }
1227 }
1228
1229 void Controller::Impl::GetCursorPosition(CharacterIndex logical,
1230                                          CursorInfo&    cursorInfo)
1231 {
1232   if(!IsShowingRealText())
1233   {
1234     // Do not want to use the place-holder text to set the cursor position.
1235
1236     // Use the line's height of the font's family set to set the cursor's size.
1237     // If there is no font's family set, use the default font.
1238     // Use the current alignment to place the cursor at the beginning, center or end of the box.
1239
1240     cursorInfo.lineOffset          = 0.f;
1241     cursorInfo.lineHeight          = GetDefaultFontLineHeight();
1242     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
1243
1244     bool isRTL = false;
1245     if(mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS)
1246     {
1247       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
1248     }
1249
1250     switch(mModel->mHorizontalAlignment)
1251     {
1252       case Text::HorizontalAlignment::BEGIN:
1253       {
1254         if(isRTL)
1255         {
1256           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1257         }
1258         else
1259         {
1260           cursorInfo.primaryPosition.x = 0.f;
1261         }
1262         break;
1263       }
1264       case Text::HorizontalAlignment::CENTER:
1265       {
1266         cursorInfo.primaryPosition.x = floorf(0.5f * mModel->mVisualModel->mControlSize.width);
1267         break;
1268       }
1269       case Text::HorizontalAlignment::END:
1270       {
1271         if(isRTL)
1272         {
1273           cursorInfo.primaryPosition.x = 0.f;
1274         }
1275         else
1276         {
1277           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1278         }
1279         break;
1280       }
1281     }
1282
1283     // Nothing else to do.
1284     return;
1285   }
1286
1287   const bool                  isMultiLine = (Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout());
1288   GetCursorPositionParameters parameters;
1289   parameters.visualModel  = mModel->mVisualModel;
1290   parameters.logicalModel = mModel->mLogicalModel;
1291   parameters.metrics      = mMetrics;
1292   parameters.logical      = logical;
1293   parameters.isMultiline  = isMultiLine;
1294
1295   Text::GetCursorPosition(parameters,
1296                           cursorInfo);
1297
1298   // Adds Outline offset.
1299   const float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
1300   cursorInfo.primaryPosition.x += outlineWidth;
1301   cursorInfo.primaryPosition.y += outlineWidth;
1302   cursorInfo.secondaryPosition.x += outlineWidth;
1303   cursorInfo.secondaryPosition.y += outlineWidth;
1304
1305   if(isMultiLine)
1306   {
1307     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
1308
1309     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
1310     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
1311
1312     if(0.f > cursorInfo.primaryPosition.x)
1313     {
1314       cursorInfo.primaryPosition.x = 0.f;
1315     }
1316
1317     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>(mEventData->mDecorator->GetCursorWidth());
1318     if(cursorInfo.primaryPosition.x > edgeWidth)
1319     {
1320       cursorInfo.primaryPosition.x = edgeWidth;
1321     }
1322   }
1323 }
1324
1325 CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
1326 {
1327   if(nullptr == mEventData)
1328   {
1329     // Nothing to do if there is no text input.
1330     return 0u;
1331   }
1332
1333   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
1334
1335   const GlyphIndex* const charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
1336   const Length* const     charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1337
1338   GlyphIndex glyphIndex         = *(charactersToGlyphBuffer + index);
1339   Length     numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1340
1341   if(numberOfCharacters > 1u)
1342   {
1343     const Script script = mModel->mLogicalModel->GetScript(index);
1344     if(HasLigatureMustBreak(script))
1345     {
1346       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
1347       numberOfCharacters = 1u;
1348     }
1349   }
1350   else
1351   {
1352     while(0u == numberOfCharacters)
1353     {
1354       ++glyphIndex;
1355       numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1356     }
1357   }
1358
1359   if(index < mEventData->mPrimaryCursorPosition)
1360   {
1361     cursorIndex -= numberOfCharacters;
1362   }
1363   else
1364   {
1365     cursorIndex += numberOfCharacters;
1366   }
1367
1368   // Will update the cursor hook position.
1369   mEventData->mUpdateCursorHookPosition = true;
1370
1371   return cursorIndex;
1372 }
1373
1374 void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
1375 {
1376   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
1377   if(nullptr == mEventData)
1378   {
1379     // Nothing to do if there is no text input.
1380     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
1381     return;
1382   }
1383
1384   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
1385
1386   mEventData->mDecorator->SetGlyphOffset(PRIMARY_CURSOR, cursorInfo.glyphOffset);
1387
1388   // Sets the cursor position.
1389   mEventData->mDecorator->SetPosition(PRIMARY_CURSOR,
1390                                       cursorPosition.x,
1391                                       cursorPosition.y,
1392                                       cursorInfo.primaryCursorHeight,
1393                                       cursorInfo.lineHeight);
1394   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y);
1395
1396   if(mEventData->mUpdateGrabHandlePosition)
1397   {
1398     // Sets the grab handle position.
1399     mEventData->mDecorator->SetPosition(GRAB_HANDLE,
1400                                         cursorPosition.x,
1401                                         cursorInfo.lineOffset + mModel->mScrollPosition.y,
1402                                         cursorInfo.lineHeight);
1403   }
1404
1405   if(cursorInfo.isSecondaryCursor)
1406   {
1407     mEventData->mDecorator->SetPosition(SECONDARY_CURSOR,
1408                                         cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
1409                                         cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
1410                                         cursorInfo.secondaryCursorHeight,
1411                                         cursorInfo.lineHeight);
1412     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y);
1413   }
1414
1415   // Set which cursors are active according the state.
1416   if(EventData::IsEditingState(mEventData->mState) || (EventData::GRAB_HANDLE_PANNING == mEventData->mState))
1417   {
1418     if(cursorInfo.isSecondaryCursor)
1419     {
1420       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_BOTH);
1421     }
1422     else
1423     {
1424       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1425     }
1426   }
1427   else
1428   {
1429     mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1430   }
1431
1432   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n");
1433 }
1434
1435 void Controller::Impl::UpdateSelectionHandle(HandleType        handleType,
1436                                              const CursorInfo& cursorInfo)
1437 {
1438   SelectionHandleController::Update(*this, handleType, cursorInfo);
1439 }
1440
1441 void Controller::Impl::ClampHorizontalScroll(const Vector2& layoutSize)
1442 {
1443   // Clamp between -space & -alignment offset.
1444
1445   if(layoutSize.width > mModel->mVisualModel->mControlSize.width)
1446   {
1447     const float space         = (layoutSize.width - mModel->mVisualModel->mControlSize.width) + mModel->mAlignmentOffset;
1448     mModel->mScrollPosition.x = (mModel->mScrollPosition.x < -space) ? -space : mModel->mScrollPosition.x;
1449     mModel->mScrollPosition.x = (mModel->mScrollPosition.x > -mModel->mAlignmentOffset) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
1450
1451     mEventData->mDecoratorUpdated = true;
1452   }
1453   else
1454   {
1455     mModel->mScrollPosition.x = 0.f;
1456   }
1457 }
1458
1459 void Controller::Impl::ClampVerticalScroll(const Vector2& layoutSize)
1460 {
1461   if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
1462   {
1463     // Nothing to do if the text is single line.
1464     return;
1465   }
1466
1467   // Clamp between -space & 0.
1468   if(layoutSize.height > mModel->mVisualModel->mControlSize.height)
1469   {
1470     const float space         = (layoutSize.height - mModel->mVisualModel->mControlSize.height);
1471     mModel->mScrollPosition.y = (mModel->mScrollPosition.y < -space) ? -space : mModel->mScrollPosition.y;
1472     mModel->mScrollPosition.y = (mModel->mScrollPosition.y > 0.f) ? 0.f : mModel->mScrollPosition.y;
1473
1474     mEventData->mDecoratorUpdated = true;
1475   }
1476   else
1477   {
1478     mModel->mScrollPosition.y = 0.f;
1479   }
1480 }
1481
1482 void Controller::Impl::ScrollToMakePositionVisible(const Vector2& position, float lineHeight)
1483 {
1484   const float cursorWidth = mEventData->mDecorator ? static_cast<float>(mEventData->mDecorator->GetCursorWidth()) : 0.f;
1485
1486   // position is in actor's coords.
1487   const float positionEndX = position.x + cursorWidth;
1488   const float positionEndY = position.y + lineHeight;
1489
1490   // Transform the position to decorator coords.
1491   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
1492   const float decoratorPositionEndX   = positionEndX + mModel->mScrollPosition.x;
1493
1494   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
1495   const float decoratorPositionEndY   = positionEndY + mModel->mScrollPosition.y;
1496
1497   if(decoratorPositionBeginX < 0.f)
1498   {
1499     mModel->mScrollPosition.x = -position.x;
1500   }
1501   else if(decoratorPositionEndX > mModel->mVisualModel->mControlSize.width)
1502   {
1503     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
1504   }
1505
1506   if(Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout())
1507   {
1508     if(decoratorPositionBeginY < 0.f)
1509     {
1510       mModel->mScrollPosition.y = -position.y;
1511     }
1512     else if(decoratorPositionEndY > mModel->mVisualModel->mControlSize.height)
1513     {
1514       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
1515     }
1516   }
1517 }
1518
1519 void Controller::Impl::ScrollTextToMatchCursor(const CursorInfo& cursorInfo)
1520 {
1521   // Get the current cursor position in decorator coords.
1522   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
1523
1524   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter(mEventData->mPrimaryCursorPosition);
1525
1526   // Calculate the offset to match the cursor position before the character was deleted.
1527   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
1528
1529   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
1530   if(mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() - 1u)
1531   {
1532     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset(PRIMARY_CURSOR);
1533     mModel->mScrollPosition.y            = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
1534   }
1535
1536   ClampHorizontalScroll(mModel->mVisualModel->GetLayoutSize());
1537   ClampVerticalScroll(mModel->mVisualModel->GetLayoutSize());
1538
1539   // Makes the new cursor position visible if needed.
1540   ScrollToMakePositionVisible(cursorInfo.primaryPosition, cursorInfo.lineHeight);
1541 }
1542
1543 void Controller::Impl::ScrollTextToMatchCursor()
1544 {
1545   CursorInfo cursorInfo;
1546   GetCursorPosition(mEventData->mPrimaryCursorPosition, cursorInfo);
1547   ScrollTextToMatchCursor(cursorInfo);
1548 }
1549
1550 void Controller::Impl::RequestRelayout()
1551 {
1552   if(nullptr != mControlInterface)
1553   {
1554     mControlInterface->RequestTextRelayout();
1555   }
1556 }
1557
1558 Actor Controller::Impl::CreateBackgroundActor()
1559 {
1560   // NOTE: Currently we only support background color for left-to-right text.
1561
1562   Actor actor;
1563
1564   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
1565   if(numberOfGlyphs > 0u)
1566   {
1567     Vector<GlyphInfo> glyphs;
1568     glyphs.Resize(numberOfGlyphs);
1569
1570     Vector<Vector2> positions;
1571     positions.Resize(numberOfGlyphs);
1572
1573     // Get the line where the glyphs are laid-out.
1574     const LineRun* lineRun         = mModel->mVisualModel->mLines.Begin();
1575     float          alignmentOffset = lineRun->alignmentOffset;
1576     numberOfGlyphs                 = mView.GetGlyphs(glyphs.Begin(),
1577                                      positions.Begin(),
1578                                      alignmentOffset,
1579                                      0u,
1580                                      numberOfGlyphs);
1581
1582     glyphs.Resize(numberOfGlyphs);
1583     positions.Resize(numberOfGlyphs);
1584
1585     const GlyphInfo* const glyphsBuffer    = glyphs.Begin();
1586     const Vector2* const   positionsBuffer = positions.Begin();
1587
1588     BackgroundMesh mesh;
1589     mesh.mVertices.Reserve(4u * glyphs.Size());
1590     mesh.mIndices.Reserve(6u * glyphs.Size());
1591
1592     const Vector2 textSize = mView.GetLayoutSize();
1593
1594     const float offsetX = alignmentOffset + textSize.width * 0.5f;
1595     const float offsetY = textSize.height * 0.5f;
1596
1597     const Vector4* const    backgroundColorsBuffer       = mView.GetBackgroundColors();
1598     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
1599     const Vector4&          defaultBackgroundColor       = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
1600
1601     Vector4   quad;
1602     uint32_t  numberOfQuads = 0u;
1603     Length    yLineOffset   = 0;
1604     Length    prevLineIndex = 0;
1605     LineIndex lineIndex;
1606     Length    numberOfLines;
1607
1608     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
1609     {
1610       const GlyphInfo& glyph = *(glyphsBuffer + i);
1611
1612       // Get the background color of the character.
1613       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
1614       const bool       isMarkupBackground       = mView.IsMarkupBackgroundColorSet();
1615       const ColorIndex backgroundColorIndex     = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
1616       const bool       isDefaultBackgroundColor = (0u == backgroundColorIndex);
1617       const Vector4&   backgroundColor          = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
1618
1619       mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
1620       Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
1621
1622       if(lineIndex != prevLineIndex)
1623       {
1624         yLineOffset += lineHeight;
1625       }
1626
1627       // Only create quads for glyphs with a background color
1628       if(backgroundColor != Color::TRANSPARENT)
1629       {
1630         const Vector2 position = *(positionsBuffer + i);
1631
1632         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
1633         {
1634           quad.x = position.x;
1635           quad.y = yLineOffset;
1636           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
1637           quad.w = lineHeight;
1638         }
1639         else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
1640         {
1641           quad.x = position.x;
1642           quad.y = yLineOffset;
1643           quad.z = quad.x - glyph.xBearing + glyph.advance;
1644           quad.w = quad.y + lineHeight;
1645         }
1646         else if(i == glyphSize - 1u) // The last glyph in the whole text
1647         {
1648           quad.x = position.x - glyph.xBearing;
1649           quad.y = yLineOffset;
1650           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
1651           quad.w = quad.y + lineHeight;
1652         }
1653         else // The glyph in the middle of the text
1654         {
1655           quad.x = position.x - glyph.xBearing;
1656           quad.y = yLineOffset;
1657           quad.z = quad.x + glyph.advance;
1658           quad.w = quad.y + lineHeight;
1659         }
1660
1661         BackgroundVertex vertex;
1662
1663         // Top left
1664         vertex.mPosition.x = quad.x - offsetX;
1665         vertex.mPosition.y = quad.y - offsetY;
1666         vertex.mColor      = backgroundColor;
1667         mesh.mVertices.PushBack(vertex);
1668
1669         // Top right
1670         vertex.mPosition.x = quad.z - offsetX;
1671         vertex.mPosition.y = quad.y - offsetY;
1672         vertex.mColor      = backgroundColor;
1673         mesh.mVertices.PushBack(vertex);
1674
1675         // Bottom left
1676         vertex.mPosition.x = quad.x - offsetX;
1677         vertex.mPosition.y = quad.w - offsetY;
1678         vertex.mColor      = backgroundColor;
1679         mesh.mVertices.PushBack(vertex);
1680
1681         // Bottom right
1682         vertex.mPosition.x = quad.z - offsetX;
1683         vertex.mPosition.y = quad.w - offsetY;
1684         vertex.mColor      = backgroundColor;
1685         mesh.mVertices.PushBack(vertex);
1686
1687         // Six indices in counter clockwise winding
1688         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
1689         mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
1690         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
1691         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
1692         mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
1693         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
1694
1695         numberOfQuads++;
1696       }
1697
1698       if(lineIndex != prevLineIndex)
1699       {
1700         prevLineIndex = lineIndex;
1701       }
1702     }
1703
1704     // Only create the background actor if there are glyphs with background color
1705     if(mesh.mVertices.Count() > 0u)
1706     {
1707       Property::Map quadVertexFormat;
1708       quadVertexFormat["aPosition"] = Property::VECTOR2;
1709       quadVertexFormat["aColor"]    = Property::VECTOR4;
1710
1711       VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
1712       quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
1713
1714       Geometry quadGeometry = Geometry::New();
1715       quadGeometry.AddVertexBuffer(quadVertices);
1716       quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
1717
1718       if(!mShaderBackground)
1719       {
1720         mShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
1721       }
1722
1723       Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, mShaderBackground);
1724       renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
1725       renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
1726
1727       actor = Actor::New();
1728       actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
1729       actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
1730       actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
1731       actor.SetProperty(Actor::Property::SIZE, textSize);
1732       actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
1733       actor.AddRenderer(renderer);
1734     }
1735   }
1736
1737   return actor;
1738 }
1739
1740 void Controller::Impl::RelayoutForNewLineSize()
1741 {
1742   // relayout all characters
1743   mTextUpdateInfo.mCharacterIndex             = 0;
1744   mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1745   mTextUpdateInfo.mNumberOfCharactersToAdd    = mModel->mLogicalModel->mText.Count();
1746   mOperationsPending                          = static_cast<OperationsMask>(mOperationsPending | LAYOUT);
1747
1748   //remove selection
1749   if(mEventData && mEventData->mState == EventData::SELECTING)
1750   {
1751     ChangeState(EventData::EDITING);
1752   }
1753
1754   RequestRelayout();
1755 }
1756
1757 bool Controller::Impl::IsInputStyleChangedSignalsQueueEmpty()
1758 {
1759   return (NULL == mEventData) || (0u == mEventData->mInputStyleChangedQueue.Count());
1760 }
1761
1762 void Controller::Impl::ProcessInputStyleChangedSignals()
1763 {
1764   if(mEventData)
1765   {
1766     if(mEditableControlInterface)
1767     {
1768       // Emit the input style changed signal for each mask
1769       std::for_each(mEventData->mInputStyleChangedQueue.begin(),
1770                     mEventData->mInputStyleChangedQueue.end(),
1771                     [&](const auto mask) { mEditableControlInterface->InputStyleChanged(mask); } );
1772     }
1773
1774     mEventData->mInputStyleChangedQueue.Clear();
1775   }
1776 }
1777
1778 void Controller::Impl::ScrollBy(Vector2 scroll)
1779 {
1780   if(mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
1781   {
1782     const Vector2& layoutSize    = mModel->mVisualModel->GetLayoutSize();
1783     const Vector2  currentScroll = mModel->mScrollPosition;
1784
1785     scroll.x = -scroll.x;
1786     scroll.y = -scroll.y;
1787
1788     if(fabs(scroll.x) > Math::MACHINE_EPSILON_0)
1789     {
1790       mModel->mScrollPosition.x += scroll.x;
1791       ClampHorizontalScroll(layoutSize);
1792     }
1793
1794     if(fabs(scroll.y) > Math::MACHINE_EPSILON_0)
1795     {
1796       mModel->mScrollPosition.y += scroll.y;
1797       ClampVerticalScroll(layoutSize);
1798     }
1799
1800     if(mModel->mScrollPosition != currentScroll)
1801     {
1802       mEventData->mDecorator->UpdatePositions(mModel->mScrollPosition - currentScroll);
1803       RequestRelayout();
1804     }
1805   }
1806 }
1807
1808 float Controller::Impl::GetHorizontalScrollPosition()
1809 {
1810   // Scroll values are negative internally so we convert them to positive numbers
1811   return mEventData ? -mModel->mScrollPosition.x : 0.0f;
1812 }
1813
1814 float Controller::Impl::GetVerticalScrollPosition()
1815 {
1816   // Scroll values are negative internally so we convert them to positive numbers
1817   return mEventData ? -mModel->mScrollPosition.y : 0.0f;
1818 }
1819
1820 void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
1821 {
1822   //Underlined character runs for markup-processor
1823   const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
1824   const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
1825   const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
1826
1827   if(shouldClearPreUnderlineRuns)
1828   {
1829     mModel->mVisualModel->mUnderlineRuns.Clear();
1830   }
1831
1832   for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
1833   {
1834     CharacterIndex characterIndex     = it->characterRun.characterIndex;
1835     Length         numberOfCharacters = it->characterRun.numberOfCharacters;
1836     for(Length index = 0u; index < numberOfCharacters; index++)
1837     {
1838       GlyphRun underlineGlyphRun;
1839       underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
1840       underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
1841       mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
1842     }
1843   }
1844 }
1845
1846 } // namespace Dali::Toolkit::Text