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