CanvasView: Do ApplyNativeFragmentShader for NativeImage buffer
[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     // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout
511     if(0u != mModel->mVisualModel->mGlyphPositions.Count())
512     {
513       // Clear the positions buffer.
514       Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
515       mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
516                                                   positionsBuffer + endGlyphIndexPlusOne);
517     }
518   }
519
520   if(NO_OPERATION != (LAYOUT & operations))
521   {
522     // Clear the lines.
523     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
524     uint32_t endRemoveIndex   = startRemoveIndex;
525     ClearCharacterRuns(startIndex,
526                        endIndex,
527                        mModel->mVisualModel->mLines,
528                        startRemoveIndex,
529                        endRemoveIndex);
530
531     // Will update the glyph runs.
532     startRemoveIndex = mModel->mVisualModel->mLines.Count();
533     endRemoveIndex   = startRemoveIndex;
534     ClearGlyphRuns(mTextUpdateInfo.mStartGlyphIndex,
535                    endGlyphIndexPlusOne - 1u,
536                    mModel->mVisualModel->mLines,
537                    startRemoveIndex,
538                    endRemoveIndex);
539
540     // Set the line index from where to insert the new laid-out lines.
541     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
542
543     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
544     mModel->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
545                                        linesBuffer + endRemoveIndex);
546   }
547
548   if(NO_OPERATION != (COLOR & operations))
549   {
550     if(0u != mModel->mVisualModel->mColorIndices.Count())
551     {
552       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
553       mModel->mVisualModel->mColorIndices.Erase(colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
554                                                 colorIndexBuffer + endGlyphIndexPlusOne);
555     }
556
557     if(0u != mModel->mVisualModel->mBackgroundColorIndices.Count())
558     {
559       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
560       mModel->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
561                                                           backgroundColorIndexBuffer + endGlyphIndexPlusOne);
562     }
563   }
564 }
565
566 void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
567 {
568   if(mTextUpdateInfo.mClearAll ||
569      ((0u == startIndex) &&
570       (mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
571   {
572     ClearFullModelData(operations);
573   }
574   else
575   {
576     // Clear the model data related with characters.
577     ClearCharacterModelData(startIndex, endIndex, operations);
578
579     // Clear the model data related with glyphs.
580     ClearGlyphModelData(startIndex, endIndex, operations);
581   }
582
583   // The estimated number of lines. Used to avoid reallocations when layouting.
584   mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
585
586   mModel->mVisualModel->ClearCaches();
587 }
588
589 bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
590 {
591   DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
592
593   // Calculate the operations to be done.
594   const OperationsMask operations = static_cast<OperationsMask>(mOperationsPending & operationsRequired);
595
596   if(NO_OPERATION == operations)
597   {
598     // Nothing to do if no operations are pending and required.
599     return false;
600   }
601
602   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
603   Vector<Character>  displayCharacters;
604   bool               useHiddenText = false;
605   if(mHiddenInput && mEventData != nullptr && !mEventData->mIsShowingPlaceholderText)
606   {
607     mHiddenInput->Substitute(srcCharacters, displayCharacters);
608     useHiddenText = true;
609   }
610
611   Vector<Character>& utf32Characters    = useHiddenText ? displayCharacters : srcCharacters;
612   const Length       numberOfCharacters = utf32Characters.Count();
613
614   // Index to the first character of the first paragraph to be updated.
615   CharacterIndex startIndex = 0u;
616   // Number of characters of the paragraphs to be removed.
617   Length paragraphCharacters = 0u;
618
619   CalculateTextUpdateIndices(paragraphCharacters);
620
621   // Check whether the indices for updating the text is valid
622   if(numberOfCharacters > 0u &&
623      (mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
624       mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
625   {
626     std::string currentText;
627     Utf32ToUtf8(mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
628
629     DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
630     DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
631
632     // Dump mTextUpdateInfo
633     DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
634     DALI_LOG_ERROR("     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex);
635     DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove);
636     DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd);
637     DALI_LOG_ERROR("     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters);
638     DALI_LOG_ERROR("     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex);
639     DALI_LOG_ERROR("     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters);
640     DALI_LOG_ERROR("     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex);
641     DALI_LOG_ERROR("     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex);
642     DALI_LOG_ERROR("     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines);
643     DALI_LOG_ERROR("     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll);
644     DALI_LOG_ERROR("     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded);
645     DALI_LOG_ERROR("     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph);
646
647     return false;
648   }
649
650   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
651
652   if(mTextUpdateInfo.mClearAll ||
653      (0u != paragraphCharacters))
654   {
655     ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
656   }
657
658   mTextUpdateInfo.mClearAll = false;
659
660   // Whether the model is updated.
661   bool updated = false;
662
663   Vector<LineBreakInfo>& lineBreakInfo               = mModel->mLogicalModel->mLineBreakInfo;
664   const Length           requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
665
666   if(NO_OPERATION != (GET_LINE_BREAKS & operations))
667   {
668     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
669     // calculate the bidirectional info for each 'paragraph'.
670     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
671     // is not shaped together).
672     lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
673
674     SetLineBreakInfo(utf32Characters,
675                      startIndex,
676                      requestedNumberOfCharacters,
677                      lineBreakInfo);
678
679     if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
680        mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
681     {
682       CharacterIndex end                 = startIndex + requestedNumberOfCharacters;
683       LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
684
685       for(CharacterIndex index = startIndex; index < end; index++)
686       {
687         CharacterIndex wordEnd = index;
688         while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
689         {
690           wordEnd++;
691         }
692
693         if((wordEnd + 1) == end) // add last char
694         {
695           wordEnd++;
696         }
697
698         Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
699
700         for(CharacterIndex i = 0; i < (wordEnd - index); i++)
701         {
702           if(hyphens[i])
703           {
704             *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
705           }
706         }
707
708         index = wordEnd;
709       }
710     }
711
712     // Create the paragraph info.
713     mModel->mLogicalModel->CreateParagraphInfo(startIndex,
714                                                requestedNumberOfCharacters);
715     updated = true;
716   }
717
718   const bool getScripts    = NO_OPERATION != (GET_SCRIPTS & operations);
719   const bool validateFonts = NO_OPERATION != (VALIDATE_FONTS & operations);
720
721   Vector<ScriptRun>& scripts    = mModel->mLogicalModel->mScriptRuns;
722   Vector<FontRun>&   validFonts = mModel->mLogicalModel->mFontRuns;
723
724   if(getScripts || validateFonts)
725   {
726     // Validates the fonts assigned by the application or assigns default ones.
727     // It makes sure all the characters are going to be rendered by the correct font.
728     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
729
730     if(getScripts)
731     {
732       // Retrieves the scripts used in the text.
733       multilanguageSupport.SetScripts(utf32Characters,
734                                       startIndex,
735                                       requestedNumberOfCharacters,
736                                       scripts);
737     }
738
739     if(validateFonts)
740     {
741       // Validate the fonts set through the mark-up string.
742       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
743
744       // Get the default font's description.
745       TextAbstraction::FontDescription defaultFontDescription;
746       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
747
748       //Get the number of points per one unit of point-size
749       uint32_t numberOfPointsPerOneUnitOfPointSize = mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
750
751       if(IsShowingPlaceholderText() && mEventData && (nullptr != mEventData->mPlaceholderFont))
752       {
753         // If the placeholder font is set specifically, only placeholder font is changed.
754         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
755         if(mEventData->mPlaceholderFont->sizeDefined)
756         {
757           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
758         }
759       }
760       else if(nullptr != mFontDefaults)
761       {
762         // Set the normal font and the placeholder font.
763         defaultFontDescription = mFontDefaults->mFontDescription;
764
765         if(mTextFitEnabled)
766         {
767           defaultPointSize = mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
768         }
769         else
770         {
771           defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
772         }
773       }
774
775       // Validates the fonts. If there is a character with no assigned font it sets a default one.
776       // After this call, fonts are validated.
777       multilanguageSupport.ValidateFonts(utf32Characters,
778                                          scripts,
779                                          fontDescriptionRuns,
780                                          defaultFontDescription,
781                                          defaultPointSize,
782                                          startIndex,
783                                          requestedNumberOfCharacters,
784                                          validFonts);
785     }
786     updated = true;
787   }
788
789   Vector<Character> mirroredUtf32Characters;
790   bool              textMirrored       = false;
791   const Length      numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
792   if(NO_OPERATION != (BIDI_INFO & operations))
793   {
794     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
795     bidirectionalInfo.Reserve(numberOfParagraphs);
796
797     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
798     SetBidirectionalInfo(utf32Characters,
799                          scripts,
800                          lineBreakInfo,
801                          startIndex,
802                          requestedNumberOfCharacters,
803                          bidirectionalInfo,
804                          (mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS),
805                          mLayoutDirection);
806
807     if(0u != bidirectionalInfo.Count())
808     {
809       // Only set the character directions if there is right to left characters.
810       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
811       GetCharactersDirection(bidirectionalInfo,
812                              numberOfCharacters,
813                              startIndex,
814                              requestedNumberOfCharacters,
815                              directions);
816
817       // This paragraph has right to left text. Some characters may need to be mirrored.
818       // TODO: consider if the mirrored string can be stored as well.
819
820       textMirrored = GetMirroredText(utf32Characters,
821                                      directions,
822                                      bidirectionalInfo,
823                                      startIndex,
824                                      requestedNumberOfCharacters,
825                                      mirroredUtf32Characters);
826     }
827     else
828     {
829       // There is no right to left characters. Clear the directions vector.
830       mModel->mLogicalModel->mCharacterDirections.Clear();
831     }
832     updated = true;
833   }
834
835   Vector<GlyphInfo>&      glyphs                = mModel->mVisualModel->mGlyphs;
836   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
837   Vector<Length>&         charactersPerGlyph    = mModel->mVisualModel->mCharactersPerGlyph;
838   Vector<GlyphIndex>      newParagraphGlyphs;
839   newParagraphGlyphs.Reserve(numberOfParagraphs);
840
841   const Length currentNumberOfGlyphs = glyphs.Count();
842   if(NO_OPERATION != (SHAPE_TEXT & operations))
843   {
844     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
845     // Shapes the text.
846     ShapeText(textToShape,
847               lineBreakInfo,
848               scripts,
849               validFonts,
850               startIndex,
851               mTextUpdateInfo.mStartGlyphIndex,
852               requestedNumberOfCharacters,
853               glyphs,
854               glyphsToCharactersMap,
855               charactersPerGlyph,
856               newParagraphGlyphs);
857
858     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
859     mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
860     mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
861
862     updated = true;
863   }
864
865   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
866
867   if(NO_OPERATION != (GET_GLYPH_METRICS & operations))
868   {
869     GlyphInfo* glyphsBuffer = glyphs.Begin();
870     mMetrics->GetGlyphMetrics(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
871
872     // Update the width and advance of all new paragraph characters.
873     for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
874     {
875       const GlyphIndex index = *it;
876       GlyphInfo&       glyph = *(glyphsBuffer + index);
877
878       glyph.xBearing = 0.f;
879       glyph.width    = 0.f;
880       glyph.advance  = 0.f;
881     }
882     updated = true;
883   }
884
885   if((nullptr != mEventData) &&
886      mEventData->mPreEditFlag &&
887      (0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
888   {
889     Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
890     mEventData->mInputMethodContext.GetPreeditStyle(attrs);
891     Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
892
893     // Check the type of preedit and run it.
894     for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
895     {
896       Dali::InputMethodContext::PreeditAttributeData attrData = *it;
897       DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
898       type = attrData.preeditType;
899
900       // Check the number of commit characters for the start position.
901       unsigned int numberOfCommit  = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
902       Length       numberOfIndices = attrData.endIndex - attrData.startIndex;
903
904       switch(type)
905       {
906         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
907         {
908           // Add the underline for the pre-edit text.
909           GlyphRun underlineRun;
910           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
911           underlineRun.numberOfGlyphs = numberOfIndices;
912           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
913
914           //Mark-up processor case
915           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
916           {
917             CopyUnderlinedFromLogicalToVisualModels(false);
918           }
919           break;
920         }
921         case Dali::InputMethodContext::PreeditStyle::REVERSE:
922         {
923           Vector4  textColor = mModel->mVisualModel->GetTextColor();
924           ColorRun backgroundColorRun;
925           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
926           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
927           backgroundColorRun.color                           = textColor;
928           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
929
930           Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
931           if(backgroundColor.a == 0) // There is no text background color.
932           {
933             // Try use the control's background color.
934             if(nullptr != mEditableControlInterface)
935             {
936               mEditableControlInterface->GetControlBackgroundColor(backgroundColor);
937               if(backgroundColor.a == 0) // There is no control background color.
938               {
939                 // Determines black or white color according to text color.
940                 // Based on W3C Recommendations (https://www.w3.org/TR/WCAG20/)
941                 float L         = CONSTANT_R * textColor.r + CONSTANT_G * textColor.g + CONSTANT_B * textColor.b;
942                 backgroundColor = L > BRIGHTNESS_THRESHOLD ? BLACK : WHITE;
943               }
944             }
945           }
946
947           Vector<ColorRun> colorRuns;
948           colorRuns.Resize(1u);
949           ColorRun& colorRun                       = *(colorRuns.Begin());
950           colorRun.color                           = backgroundColor;
951           colorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
952           colorRun.characterRun.numberOfCharacters = numberOfIndices;
953           mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
954
955           //Mark-up processor case
956           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
957           {
958             CopyUnderlinedFromLogicalToVisualModels(false);
959           }
960           break;
961         }
962         case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
963         {
964           ColorRun backgroundColorRun;
965           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
966           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
967           backgroundColorRun.color                           = LIGHT_BLUE;
968           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
969
970           //Mark-up processor case
971           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
972           {
973             CopyUnderlinedFromLogicalToVisualModels(false);
974           }
975           break;
976         }
977         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
978         {
979           // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
980           ColorRun backgroundColorRun;
981           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
982           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
983           backgroundColorRun.color                           = BACKGROUND_SUB4;
984           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
985
986           GlyphRun underlineRun;
987           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
988           underlineRun.numberOfGlyphs = numberOfIndices;
989           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
990
991           //Mark-up processor case
992           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
993           {
994             CopyUnderlinedFromLogicalToVisualModels(false);
995           }
996           break;
997         }
998         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
999         {
1000           // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
1001           ColorRun backgroundColorRun;
1002           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
1003           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1004           backgroundColorRun.color                           = BACKGROUND_SUB5;
1005           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
1006
1007           GlyphRun underlineRun;
1008           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
1009           underlineRun.numberOfGlyphs = numberOfIndices;
1010           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
1011
1012           //Mark-up processor case
1013           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
1014           {
1015             CopyUnderlinedFromLogicalToVisualModels(false);
1016           }
1017           break;
1018         }
1019         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
1020         {
1021           // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
1022           ColorRun backgroundColorRun;
1023           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
1024           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1025           backgroundColorRun.color                           = BACKGROUND_SUB6;
1026           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
1027
1028           GlyphRun underlineRun;
1029           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
1030           underlineRun.numberOfGlyphs = numberOfIndices;
1031           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
1032
1033           //Mark-up processor case
1034           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
1035           {
1036             CopyUnderlinedFromLogicalToVisualModels(false);
1037           }
1038           break;
1039         }
1040         case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
1041         {
1042           // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
1043           ColorRun backgroundColorRun;
1044           backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
1045           backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
1046           backgroundColorRun.color                           = BACKGROUND_SUB7;
1047           mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
1048
1049           GlyphRun underlineRun;
1050           underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
1051           underlineRun.numberOfGlyphs = numberOfIndices;
1052           mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
1053
1054           //Mark-up processor case
1055           if(mModel->mVisualModel->IsMarkupProcessorEnabled())
1056           {
1057             CopyUnderlinedFromLogicalToVisualModels(false);
1058           }
1059           break;
1060         }
1061         case Dali::InputMethodContext::PreeditStyle::NONE:
1062         default:
1063         {
1064           break;
1065         }
1066       }
1067     }
1068     attrs.Clear();
1069     updated = true;
1070   }
1071
1072   if(NO_OPERATION != (COLOR & operations))
1073   {
1074     // Set the color runs in glyphs.
1075     SetColorSegmentationInfo(mModel->mLogicalModel->mColorRuns,
1076                              mModel->mVisualModel->mCharactersToGlyph,
1077                              mModel->mVisualModel->mGlyphsPerCharacter,
1078                              startIndex,
1079                              mTextUpdateInfo.mStartGlyphIndex,
1080                              requestedNumberOfCharacters,
1081                              mModel->mVisualModel->mColors,
1082                              mModel->mVisualModel->mColorIndices);
1083
1084     // Set the background color runs in glyphs.
1085     SetColorSegmentationInfo(mModel->mLogicalModel->mBackgroundColorRuns,
1086                              mModel->mVisualModel->mCharactersToGlyph,
1087                              mModel->mVisualModel->mGlyphsPerCharacter,
1088                              startIndex,
1089                              mTextUpdateInfo.mStartGlyphIndex,
1090                              requestedNumberOfCharacters,
1091                              mModel->mVisualModel->mBackgroundColors,
1092                              mModel->mVisualModel->mBackgroundColorIndices);
1093
1094     updated = true;
1095   }
1096
1097   if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
1098      !((nullptr != mEventData) &&
1099        mEventData->mPreEditFlag &&
1100        (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
1101   {
1102     //Mark-up processor case
1103     if(mModel->mVisualModel->IsMarkupProcessorEnabled())
1104     {
1105       CopyUnderlinedFromLogicalToVisualModels(true);
1106     }
1107
1108     updated = true;
1109   }
1110
1111   // The estimated number of lines. Used to avoid reallocations when layouting.
1112   mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
1113
1114   // Set the previous number of characters for the next time the text is updated.
1115   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1116
1117   return updated;
1118 }
1119
1120 void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
1121 {
1122   // Sets the default text's color.
1123   inputStyle.textColor      = mTextColor;
1124   inputStyle.isDefaultColor = true;
1125
1126   inputStyle.familyName.clear();
1127   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1128   inputStyle.width  = TextAbstraction::FontWidth::NORMAL;
1129   inputStyle.slant  = TextAbstraction::FontSlant::NORMAL;
1130   inputStyle.size   = 0.f;
1131
1132   inputStyle.lineSpacing = 0.f;
1133
1134   inputStyle.underlineProperties.clear();
1135   inputStyle.shadowProperties.clear();
1136   inputStyle.embossProperties.clear();
1137   inputStyle.outlineProperties.clear();
1138
1139   inputStyle.isFamilyDefined = false;
1140   inputStyle.isWeightDefined = false;
1141   inputStyle.isWidthDefined  = false;
1142   inputStyle.isSlantDefined  = false;
1143   inputStyle.isSizeDefined   = false;
1144
1145   inputStyle.isLineSpacingDefined = false;
1146
1147   inputStyle.isUnderlineDefined = false;
1148   inputStyle.isShadowDefined    = false;
1149   inputStyle.isEmbossDefined    = false;
1150   inputStyle.isOutlineDefined   = false;
1151
1152   // Sets the default font's family name, weight, width, slant and size.
1153   if(mFontDefaults)
1154   {
1155     if(mFontDefaults->familyDefined)
1156     {
1157       inputStyle.familyName      = mFontDefaults->mFontDescription.family;
1158       inputStyle.isFamilyDefined = true;
1159     }
1160
1161     if(mFontDefaults->weightDefined)
1162     {
1163       inputStyle.weight          = mFontDefaults->mFontDescription.weight;
1164       inputStyle.isWeightDefined = true;
1165     }
1166
1167     if(mFontDefaults->widthDefined)
1168     {
1169       inputStyle.width          = mFontDefaults->mFontDescription.width;
1170       inputStyle.isWidthDefined = true;
1171     }
1172
1173     if(mFontDefaults->slantDefined)
1174     {
1175       inputStyle.slant          = mFontDefaults->mFontDescription.slant;
1176       inputStyle.isSlantDefined = true;
1177     }
1178
1179     if(mFontDefaults->sizeDefined)
1180     {
1181       inputStyle.size          = mFontDefaults->mDefaultPointSize;
1182       inputStyle.isSizeDefined = true;
1183     }
1184   }
1185 }
1186
1187 float Controller::Impl::GetDefaultFontLineHeight()
1188 {
1189   FontId defaultFontId = 0u;
1190   if(nullptr == mFontDefaults)
1191   {
1192     TextAbstraction::FontDescription fontDescription;
1193     defaultFontId = mFontClient.GetFontId(fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale);
1194   }
1195   else
1196   {
1197     defaultFontId = mFontDefaults->GetFontId(mFontClient, mFontDefaults->mDefaultPointSize * mFontSizeScale);
1198   }
1199
1200   Text::FontMetrics fontMetrics;
1201   mMetrics->GetFontMetrics(defaultFontId, fontMetrics);
1202
1203   return (fontMetrics.ascender - fontMetrics.descender);
1204 }
1205
1206 void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd)
1207 {
1208   if(nullptr == mEventData)
1209   {
1210     // Nothing to do if there is no text.
1211     return;
1212   }
1213
1214   if(mEventData->mSelectionEnabled && (pStart || pEnd))
1215   {
1216     uint32_t length   = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1217     uint32_t oldStart = mEventData->mLeftSelectionPosition;
1218     uint32_t oldEnd   = mEventData->mRightSelectionPosition;
1219
1220     if(pStart)
1221     {
1222       mEventData->mLeftSelectionPosition = std::min(*pStart, length);
1223     }
1224     if(pEnd)
1225     {
1226       mEventData->mRightSelectionPosition = std::min(*pEnd, length);
1227     }
1228
1229     if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1230     {
1231       ChangeState(EventData::EDITING);
1232       mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
1233       mEventData->mUpdateCursorPosition                                       = true;
1234     }
1235     else
1236     {
1237       ChangeState(EventData::SELECTING);
1238       mEventData->mUpdateHighlightBox           = true;
1239       mEventData->mUpdateLeftSelectionPosition  = true;
1240       mEventData->mUpdateRightSelectionPosition = true;
1241     }
1242
1243     if(mSelectableControlInterface != nullptr)
1244     {
1245       mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
1246     }
1247   }
1248 }
1249
1250 CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
1251 {
1252   if(nullptr == mEventData)
1253   {
1254     return 0;
1255   }
1256   return mEventData->mPrimaryCursorPosition;
1257 }
1258
1259 bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
1260 {
1261   if(nullptr == mEventData)
1262   {
1263     // Nothing to do if there is no text.
1264     return false;
1265   }
1266
1267   if(mEventData->mPrimaryCursorPosition == index && mEventData->mState != EventData::SELECTING)
1268   {
1269     // Nothing for same cursor position.
1270     return false;
1271   }
1272
1273   uint32_t length                    = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
1274   uint32_t oldCursorPos              = mEventData->mPrimaryCursorPosition;
1275   mEventData->mPrimaryCursorPosition = std::min(index, length);
1276   // If there is no focus, only the value is updated.
1277   if(focused)
1278   {
1279     bool     wasInSelectingState = mEventData->mState == EventData::SELECTING;
1280     uint32_t oldStart            = mEventData->mLeftSelectionPosition;
1281     uint32_t oldEnd              = mEventData->mRightSelectionPosition;
1282     ChangeState(EventData::EDITING);
1283     mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1284     mEventData->mUpdateCursorPosition                                        = true;
1285
1286     if(mSelectableControlInterface != nullptr && wasInSelectingState)
1287     {
1288       mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
1289     }
1290
1291     ScrollTextToMatchCursor();
1292   }
1293
1294   if(nullptr != mEditableControlInterface)
1295   {
1296     mEditableControlInterface->CursorPositionChanged(oldCursorPos, mEventData->mPrimaryCursorPosition);
1297   }
1298
1299   return true;
1300 }
1301
1302 Uint32Pair Controller::Impl::GetTextSelectionRange() const
1303 {
1304   Uint32Pair range;
1305
1306   if(mEventData)
1307   {
1308     range.first  = mEventData->mLeftSelectionPosition;
1309     range.second = mEventData->mRightSelectionPosition;
1310   }
1311
1312   return range;
1313 }
1314
1315 bool Controller::Impl::IsEditable() const
1316 {
1317   return mEventData && mEventData->mEditingEnabled;
1318 }
1319
1320 void Controller::Impl::SetEditable(bool editable)
1321 {
1322   if(mEventData)
1323   {
1324     mEventData->mEditingEnabled = editable;
1325   }
1326 }
1327
1328 void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval)
1329 {
1330   if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
1331   {
1332     // Nothing to select if handles are in the same place.
1333     selectedText.clear();
1334     return;
1335   }
1336
1337   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1338
1339   //Get start and end position of selection
1340   const CharacterIndex startOfSelectedText  = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1341   const Length         lengthOfSelectedText = (handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition) - startOfSelectedText;
1342
1343   Vector<Character>& utf32Characters    = mModel->mLogicalModel->mText;
1344   const Length       numberOfCharacters = utf32Characters.Count();
1345
1346   // Validate the start and end selection points
1347   if((startOfSelectedText + lengthOfSelectedText) <= numberOfCharacters)
1348   {
1349     //Get text as a UTF8 string
1350     Utf32ToUtf8(&utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText);
1351
1352     if(deleteAfterRetrieval) // Only delete text if copied successfully
1353     {
1354       // Keep a copy of the current input style.
1355       InputStyle currentInputStyle;
1356       currentInputStyle.Copy(mEventData->mInputStyle);
1357
1358       // Set as input style the style of the first deleted character.
1359       mModel->mLogicalModel->RetrieveStyle(startOfSelectedText, mEventData->mInputStyle);
1360
1361       // Compare if the input style has changed.
1362       const bool hasInputStyleChanged = !currentInputStyle.Equal(mEventData->mInputStyle);
1363
1364       if(hasInputStyleChanged)
1365       {
1366         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mEventData->mInputStyle);
1367         // Queue the input style changed signal.
1368         mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
1369       }
1370
1371       mModel->mLogicalModel->UpdateTextStyleRuns(startOfSelectedText, -static_cast<int>(lengthOfSelectedText));
1372
1373       // Mark the paragraphs to be updated.
1374       if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
1375       {
1376         mTextUpdateInfo.mCharacterIndex             = 0;
1377         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1378         mTextUpdateInfo.mNumberOfCharactersToAdd    = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
1379         mTextUpdateInfo.mClearAll                   = true;
1380       }
1381       else
1382       {
1383         mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
1384         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1385       }
1386
1387       // Delete text between handles
1388       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1389       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1390       utf32Characters.Erase(first, last);
1391
1392       // Will show the cursor at the first character of the selection.
1393       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1394     }
1395     else
1396     {
1397       // Will show the cursor at the last character of the selection.
1398       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1399     }
1400
1401     mEventData->mDecoratorUpdated = true;
1402   }
1403 }
1404
1405 void Controller::Impl::SetSelection(int start, int end)
1406 {
1407   uint32_t oldStart = mEventData->mLeftSelectionPosition;
1408   uint32_t oldEnd   = mEventData->mRightSelectionPosition;
1409
1410   mEventData->mLeftSelectionPosition  = start;
1411   mEventData->mRightSelectionPosition = end;
1412   mEventData->mUpdateCursorPosition   = true;
1413
1414   if(mSelectableControlInterface != nullptr)
1415   {
1416     mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
1417   }
1418 }
1419
1420 std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
1421 {
1422   return {mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition};
1423 }
1424
1425 void Controller::Impl::ShowClipboard()
1426 {
1427   if(mClipboard)
1428   {
1429     mClipboard.ShowClipboard();
1430   }
1431 }
1432
1433 void Controller::Impl::HideClipboard()
1434 {
1435   if(mClipboard && mClipboardHideEnabled)
1436   {
1437     mClipboard.HideClipboard();
1438   }
1439 }
1440
1441 void Controller::Impl::SetClipboardHideEnable(bool enable)
1442 {
1443   mClipboardHideEnabled = enable;
1444 }
1445
1446 bool Controller::Impl::CopyStringToClipboard(const std::string& source)
1447 {
1448   //Send string to clipboard
1449   return (mClipboard && mClipboard.SetItem(source));
1450 }
1451
1452 void Controller::Impl::SendSelectionToClipboard(bool deleteAfterSending)
1453 {
1454   std::string selectedText;
1455   RetrieveSelection(selectedText, deleteAfterSending);
1456   CopyStringToClipboard(selectedText);
1457   ChangeState(EventData::EDITING);
1458 }
1459
1460 void Controller::Impl::RequestGetTextFromClipboard()
1461 {
1462   if(mClipboard)
1463   {
1464     mClipboard.RequestItem();
1465   }
1466 }
1467
1468 void Controller::Impl::RepositionSelectionHandles()
1469 {
1470   SelectionHandleController::Reposition(*this);
1471 }
1472 void Controller::Impl::RepositionSelectionHandles(float visualX, float visualY, Controller::NoTextTap::Action action)
1473 {
1474   SelectionHandleController::Reposition(*this, visualX, visualY, action);
1475 }
1476
1477 void Controller::Impl::SetPopupButtons()
1478 {
1479   /**
1480    *  Sets the Popup buttons to be shown depending on State.
1481    *
1482    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
1483    *
1484    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
1485    */
1486
1487   bool                        isEditable    = IsEditable();
1488   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
1489
1490   if(EventData::SELECTING == mEventData->mState)
1491   {
1492     buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::COPY);
1493     if(isEditable)
1494     {
1495       buttonsToShow = TextSelectionPopup::Buttons(buttonsToShow | TextSelectionPopup::CUT);
1496     }
1497
1498     if(!IsClipboardEmpty())
1499     {
1500       if(isEditable)
1501       {
1502         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
1503       }
1504       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
1505     }
1506
1507     if(!mEventData->mAllTextSelected)
1508     {
1509       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::SELECT_ALL));
1510     }
1511   }
1512   else if(EventData::EDITING_WITH_POPUP == mEventData->mState)
1513   {
1514     if(mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
1515     {
1516       buttonsToShow = TextSelectionPopup::Buttons(TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL);
1517     }
1518
1519     if(!IsClipboardEmpty())
1520     {
1521       if(isEditable)
1522       {
1523         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
1524       }
1525       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
1526     }
1527   }
1528   else if(EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState)
1529   {
1530     if(!IsClipboardEmpty())
1531     {
1532       if(isEditable)
1533       {
1534         buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::PASTE));
1535       }
1536       buttonsToShow = TextSelectionPopup::Buttons((buttonsToShow | TextSelectionPopup::CLIPBOARD));
1537     }
1538   }
1539
1540   mEventData->mDecorator->SetEnabledPopupButtons(buttonsToShow);
1541 }
1542
1543 void Controller::Impl::ChangeState(EventData::State newState)
1544 {
1545   if(nullptr == mEventData)
1546   {
1547     // Nothing to do if there is no text input.
1548     return;
1549   }
1550
1551   DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState);
1552
1553   if(mEventData->mState != newState)
1554   {
1555     mEventData->mPreviousState = mEventData->mState;
1556     mEventData->mState         = newState;
1557
1558     switch(mEventData->mState)
1559     {
1560       case EventData::INACTIVE:
1561       {
1562         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1563         mEventData->mDecorator->StopCursorBlink();
1564         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1565         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1566         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1567         mEventData->mDecorator->SetHighlightActive(false);
1568         mEventData->mDecorator->SetPopupActive(false);
1569         mEventData->mDecoratorUpdated = true;
1570         break;
1571       }
1572       case EventData::INTERRUPTED:
1573       {
1574         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1575         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1576         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1577         mEventData->mDecorator->SetHighlightActive(false);
1578         mEventData->mDecorator->SetPopupActive(false);
1579         mEventData->mDecoratorUpdated = true;
1580         break;
1581       }
1582       case EventData::SELECTING:
1583       {
1584         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1585         mEventData->mDecorator->StopCursorBlink();
1586         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1587         if(mEventData->mGrabHandleEnabled)
1588         {
1589           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1590           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1591         }
1592         mEventData->mDecorator->SetHighlightActive(true);
1593         if(mEventData->mGrabHandlePopupEnabled)
1594         {
1595           SetPopupButtons();
1596           mEventData->mDecorator->SetPopupActive(true);
1597         }
1598         mEventData->mDecoratorUpdated = true;
1599         break;
1600       }
1601       case EventData::EDITING:
1602       {
1603         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1604         if(mEventData->mCursorBlinkEnabled)
1605         {
1606           mEventData->mDecorator->StartCursorBlink();
1607         }
1608         // Grab handle is not shown until a tap is received whilst EDITING
1609         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1610         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1611         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1612         mEventData->mDecorator->SetHighlightActive(false);
1613         if(mEventData->mGrabHandlePopupEnabled)
1614         {
1615           mEventData->mDecorator->SetPopupActive(false);
1616         }
1617         mEventData->mDecoratorUpdated = true;
1618         break;
1619       }
1620       case EventData::EDITING_WITH_POPUP:
1621       {
1622         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
1623
1624         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1625         if(mEventData->mCursorBlinkEnabled)
1626         {
1627           mEventData->mDecorator->StartCursorBlink();
1628         }
1629         if(mEventData->mSelectionEnabled)
1630         {
1631           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1632           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1633           mEventData->mDecorator->SetHighlightActive(false);
1634         }
1635         else if(mEventData->mGrabHandleEnabled)
1636         {
1637           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1638         }
1639         if(mEventData->mGrabHandlePopupEnabled)
1640         {
1641           SetPopupButtons();
1642           mEventData->mDecorator->SetPopupActive(true);
1643         }
1644         mEventData->mDecoratorUpdated = true;
1645         break;
1646       }
1647       case EventData::EDITING_WITH_GRAB_HANDLE:
1648       {
1649         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
1650
1651         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1652         if(mEventData->mCursorBlinkEnabled)
1653         {
1654           mEventData->mDecorator->StartCursorBlink();
1655         }
1656         // Grab handle is not shown until a tap is received whilst EDITING
1657         if(mEventData->mGrabHandleEnabled)
1658         {
1659           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1660         }
1661         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1662         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1663         mEventData->mDecorator->SetHighlightActive(false);
1664         if(mEventData->mGrabHandlePopupEnabled)
1665         {
1666           mEventData->mDecorator->SetPopupActive(false);
1667         }
1668         mEventData->mDecoratorUpdated = true;
1669         break;
1670       }
1671       case EventData::SELECTION_HANDLE_PANNING:
1672       {
1673         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1674         mEventData->mDecorator->StopCursorBlink();
1675         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1676         if(mEventData->mGrabHandleEnabled)
1677         {
1678           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
1679           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
1680         }
1681         mEventData->mDecorator->SetHighlightActive(true);
1682         if(mEventData->mGrabHandlePopupEnabled)
1683         {
1684           mEventData->mDecorator->SetPopupActive(false);
1685         }
1686         mEventData->mDecoratorUpdated = true;
1687         break;
1688       }
1689       case EventData::GRAB_HANDLE_PANNING:
1690       {
1691         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
1692
1693         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1694         if(mEventData->mCursorBlinkEnabled)
1695         {
1696           mEventData->mDecorator->StartCursorBlink();
1697         }
1698         if(mEventData->mGrabHandleEnabled)
1699         {
1700           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1701         }
1702         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1703         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1704         mEventData->mDecorator->SetHighlightActive(false);
1705         if(mEventData->mGrabHandlePopupEnabled)
1706         {
1707           mEventData->mDecorator->SetPopupActive(false);
1708         }
1709         mEventData->mDecoratorUpdated = true;
1710         break;
1711       }
1712       case EventData::EDITING_WITH_PASTE_POPUP:
1713       {
1714         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
1715
1716         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1717         if(mEventData->mCursorBlinkEnabled)
1718         {
1719           mEventData->mDecorator->StartCursorBlink();
1720         }
1721
1722         if(mEventData->mGrabHandleEnabled)
1723         {
1724           mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
1725         }
1726         mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1727         mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1728         mEventData->mDecorator->SetHighlightActive(false);
1729
1730         if(mEventData->mGrabHandlePopupEnabled)
1731         {
1732           SetPopupButtons();
1733           mEventData->mDecorator->SetPopupActive(true);
1734         }
1735         mEventData->mDecoratorUpdated = true;
1736         break;
1737       }
1738       case EventData::TEXT_PANNING:
1739       {
1740         mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1741         mEventData->mDecorator->StopCursorBlink();
1742         mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
1743         if(mEventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
1744            mEventData->mDecorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
1745         {
1746           mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
1747           mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
1748           mEventData->mDecorator->SetHighlightActive(true);
1749         }
1750
1751         if(mEventData->mGrabHandlePopupEnabled)
1752         {
1753           mEventData->mDecorator->SetPopupActive(false);
1754         }
1755
1756         mEventData->mDecoratorUpdated = true;
1757         break;
1758       }
1759     }
1760   }
1761 }
1762
1763 void Controller::Impl::GetCursorPosition(CharacterIndex logical,
1764                                          CursorInfo&    cursorInfo)
1765 {
1766   if(!IsShowingRealText())
1767   {
1768     // Do not want to use the place-holder text to set the cursor position.
1769
1770     // Use the line's height of the font's family set to set the cursor's size.
1771     // If there is no font's family set, use the default font.
1772     // Use the current alignment to place the cursor at the beginning, center or end of the box.
1773
1774     cursorInfo.lineOffset          = 0.f;
1775     cursorInfo.lineHeight          = GetDefaultFontLineHeight();
1776     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
1777
1778     bool isRTL = false;
1779     if(mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS)
1780     {
1781       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
1782     }
1783
1784     switch(mModel->mHorizontalAlignment)
1785     {
1786       case Text::HorizontalAlignment::BEGIN:
1787       {
1788         if(isRTL)
1789         {
1790           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1791         }
1792         else
1793         {
1794           cursorInfo.primaryPosition.x = 0.f;
1795         }
1796         break;
1797       }
1798       case Text::HorizontalAlignment::CENTER:
1799       {
1800         cursorInfo.primaryPosition.x = floorf(0.5f * mModel->mVisualModel->mControlSize.width);
1801         break;
1802       }
1803       case Text::HorizontalAlignment::END:
1804       {
1805         if(isRTL)
1806         {
1807           cursorInfo.primaryPosition.x = 0.f;
1808         }
1809         else
1810         {
1811           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
1812         }
1813         break;
1814       }
1815     }
1816
1817     // Nothing else to do.
1818     return;
1819   }
1820
1821   const bool                  isMultiLine = (Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout());
1822   GetCursorPositionParameters parameters;
1823   parameters.visualModel  = mModel->mVisualModel;
1824   parameters.logicalModel = mModel->mLogicalModel;
1825   parameters.metrics      = mMetrics;
1826   parameters.logical      = logical;
1827   parameters.isMultiline  = isMultiLine;
1828
1829   Text::GetCursorPosition(parameters,
1830                           cursorInfo);
1831
1832   // Adds Outline offset.
1833   const float outlineWidth = static_cast<float>(mModel->GetOutlineWidth());
1834   cursorInfo.primaryPosition.x += outlineWidth;
1835   cursorInfo.primaryPosition.y += outlineWidth;
1836   cursorInfo.secondaryPosition.x += outlineWidth;
1837   cursorInfo.secondaryPosition.y += outlineWidth;
1838
1839   if(isMultiLine)
1840   {
1841     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
1842
1843     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
1844     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
1845
1846     if(0.f > cursorInfo.primaryPosition.x)
1847     {
1848       cursorInfo.primaryPosition.x = 0.f;
1849     }
1850
1851     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>(mEventData->mDecorator->GetCursorWidth());
1852     if(cursorInfo.primaryPosition.x > edgeWidth)
1853     {
1854       cursorInfo.primaryPosition.x = edgeWidth;
1855     }
1856   }
1857 }
1858
1859 CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) const
1860 {
1861   if(nullptr == mEventData)
1862   {
1863     // Nothing to do if there is no text input.
1864     return 0u;
1865   }
1866
1867   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
1868
1869   const GlyphIndex* const charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
1870   const Length* const     charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
1871
1872   GlyphIndex glyphIndex         = *(charactersToGlyphBuffer + index);
1873   Length     numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1874
1875   if(numberOfCharacters > 1u)
1876   {
1877     const Script script = mModel->mLogicalModel->GetScript(index);
1878     if(HasLigatureMustBreak(script))
1879     {
1880       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
1881       numberOfCharacters = 1u;
1882     }
1883   }
1884   else
1885   {
1886     while(0u == numberOfCharacters)
1887     {
1888       ++glyphIndex;
1889       numberOfCharacters = *(charactersPerGlyphBuffer + glyphIndex);
1890     }
1891   }
1892
1893   if(index < mEventData->mPrimaryCursorPosition)
1894   {
1895     cursorIndex -= numberOfCharacters;
1896   }
1897   else
1898   {
1899     cursorIndex += numberOfCharacters;
1900   }
1901
1902   // Will update the cursor hook position.
1903   mEventData->mUpdateCursorHookPosition = true;
1904
1905   return cursorIndex;
1906 }
1907
1908 void Controller::Impl::UpdateCursorPosition(const CursorInfo& cursorInfo)
1909 {
1910   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this);
1911   if(nullptr == mEventData)
1912   {
1913     // Nothing to do if there is no text input.
1914     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n");
1915     return;
1916   }
1917
1918   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
1919
1920   mEventData->mDecorator->SetGlyphOffset(PRIMARY_CURSOR, cursorInfo.glyphOffset);
1921
1922   // Sets the cursor position.
1923   mEventData->mDecorator->SetPosition(PRIMARY_CURSOR,
1924                                       cursorPosition.x,
1925                                       cursorPosition.y,
1926                                       cursorInfo.primaryCursorHeight,
1927                                       cursorInfo.lineHeight);
1928   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y);
1929
1930   if(mEventData->mUpdateGrabHandlePosition)
1931   {
1932     // Sets the grab handle position.
1933     mEventData->mDecorator->SetPosition(GRAB_HANDLE,
1934                                         cursorPosition.x,
1935                                         cursorInfo.lineOffset + mModel->mScrollPosition.y,
1936                                         cursorInfo.lineHeight);
1937   }
1938
1939   if(cursorInfo.isSecondaryCursor)
1940   {
1941     mEventData->mDecorator->SetPosition(SECONDARY_CURSOR,
1942                                         cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
1943                                         cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
1944                                         cursorInfo.secondaryCursorHeight,
1945                                         cursorInfo.lineHeight);
1946     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y);
1947   }
1948
1949   // Set which cursors are active according the state.
1950   if(EventData::IsEditingState(mEventData->mState) || (EventData::GRAB_HANDLE_PANNING == mEventData->mState))
1951   {
1952     if(cursorInfo.isSecondaryCursor)
1953     {
1954       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_BOTH);
1955     }
1956     else
1957     {
1958       mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
1959     }
1960   }
1961   else
1962   {
1963     mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
1964   }
1965
1966   DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n");
1967 }
1968
1969 void Controller::Impl::UpdateSelectionHandle(HandleType        handleType,
1970                                              const CursorInfo& cursorInfo)
1971 {
1972   SelectionHandleController::Update(*this, handleType, cursorInfo);
1973 }
1974
1975 void Controller::Impl::ClampHorizontalScroll(const Vector2& layoutSize)
1976 {
1977   // Clamp between -space & -alignment offset.
1978
1979   if(layoutSize.width > mModel->mVisualModel->mControlSize.width)
1980   {
1981     const float space         = (layoutSize.width - mModel->mVisualModel->mControlSize.width) + mModel->mAlignmentOffset;
1982     mModel->mScrollPosition.x = (mModel->mScrollPosition.x < -space) ? -space : mModel->mScrollPosition.x;
1983     mModel->mScrollPosition.x = (mModel->mScrollPosition.x > -mModel->mAlignmentOffset) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
1984
1985     mEventData->mDecoratorUpdated = true;
1986   }
1987   else
1988   {
1989     mModel->mScrollPosition.x = 0.f;
1990   }
1991 }
1992
1993 void Controller::Impl::ClampVerticalScroll(const Vector2& layoutSize)
1994 {
1995   if(Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout())
1996   {
1997     // Nothing to do if the text is single line.
1998     return;
1999   }
2000
2001   // Clamp between -space & 0.
2002   if(layoutSize.height > mModel->mVisualModel->mControlSize.height)
2003   {
2004     const float space         = (layoutSize.height - mModel->mVisualModel->mControlSize.height);
2005     mModel->mScrollPosition.y = (mModel->mScrollPosition.y < -space) ? -space : mModel->mScrollPosition.y;
2006     mModel->mScrollPosition.y = (mModel->mScrollPosition.y > 0.f) ? 0.f : mModel->mScrollPosition.y;
2007
2008     mEventData->mDecoratorUpdated = true;
2009   }
2010   else
2011   {
2012     mModel->mScrollPosition.y = 0.f;
2013   }
2014 }
2015
2016 void Controller::Impl::ScrollToMakePositionVisible(const Vector2& position, float lineHeight)
2017 {
2018   const float cursorWidth = mEventData->mDecorator ? static_cast<float>(mEventData->mDecorator->GetCursorWidth()) : 0.f;
2019
2020   // position is in actor's coords.
2021   const float positionEndX = position.x + cursorWidth;
2022   const float positionEndY = position.y + lineHeight;
2023
2024   // Transform the position to decorator coords.
2025   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
2026   const float decoratorPositionEndX   = positionEndX + mModel->mScrollPosition.x;
2027
2028   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
2029   const float decoratorPositionEndY   = positionEndY + mModel->mScrollPosition.y;
2030
2031   if(decoratorPositionBeginX < 0.f)
2032   {
2033     mModel->mScrollPosition.x = -position.x;
2034   }
2035   else if(decoratorPositionEndX > mModel->mVisualModel->mControlSize.width)
2036   {
2037     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
2038   }
2039
2040   if(Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout())
2041   {
2042     if(decoratorPositionBeginY < 0.f)
2043     {
2044       mModel->mScrollPosition.y = -position.y;
2045     }
2046     else if(decoratorPositionEndY > mModel->mVisualModel->mControlSize.height)
2047     {
2048       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
2049     }
2050   }
2051 }
2052
2053 void Controller::Impl::ScrollTextToMatchCursor(const CursorInfo& cursorInfo)
2054 {
2055   // Get the current cursor position in decorator coords.
2056   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition(PRIMARY_CURSOR);
2057
2058   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter(mEventData->mPrimaryCursorPosition);
2059
2060   // Calculate the offset to match the cursor position before the character was deleted.
2061   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
2062
2063   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
2064   if(mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() - 1u)
2065   {
2066     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset(PRIMARY_CURSOR);
2067     mModel->mScrollPosition.y            = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
2068   }
2069
2070   ClampHorizontalScroll(mModel->mVisualModel->GetLayoutSize());
2071   ClampVerticalScroll(mModel->mVisualModel->GetLayoutSize());
2072
2073   // Makes the new cursor position visible if needed.
2074   ScrollToMakePositionVisible(cursorInfo.primaryPosition, cursorInfo.lineHeight);
2075 }
2076
2077 void Controller::Impl::ScrollTextToMatchCursor()
2078 {
2079   CursorInfo cursorInfo;
2080   GetCursorPosition(mEventData->mPrimaryCursorPosition, cursorInfo);
2081   ScrollTextToMatchCursor(cursorInfo);
2082 }
2083
2084 void Controller::Impl::RequestRelayout()
2085 {
2086   if(nullptr != mControlInterface)
2087   {
2088     mControlInterface->RequestTextRelayout();
2089   }
2090 }
2091
2092 Actor Controller::Impl::CreateBackgroundActor()
2093 {
2094   // NOTE: Currently we only support background color for left-to-right text.
2095
2096   Actor actor;
2097
2098   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
2099   if(numberOfGlyphs > 0u)
2100   {
2101     Vector<GlyphInfo> glyphs;
2102     glyphs.Resize(numberOfGlyphs);
2103
2104     Vector<Vector2> positions;
2105     positions.Resize(numberOfGlyphs);
2106
2107     // Get the line where the glyphs are laid-out.
2108     const LineRun* lineRun         = mModel->mVisualModel->mLines.Begin();
2109     float          alignmentOffset = lineRun->alignmentOffset;
2110     numberOfGlyphs                 = mView.GetGlyphs(glyphs.Begin(),
2111                                      positions.Begin(),
2112                                      alignmentOffset,
2113                                      0u,
2114                                      numberOfGlyphs);
2115
2116     glyphs.Resize(numberOfGlyphs);
2117     positions.Resize(numberOfGlyphs);
2118
2119     const GlyphInfo* const glyphsBuffer    = glyphs.Begin();
2120     const Vector2* const   positionsBuffer = positions.Begin();
2121
2122     BackgroundMesh mesh;
2123     mesh.mVertices.Reserve(4u * glyphs.Size());
2124     mesh.mIndices.Reserve(6u * glyphs.Size());
2125
2126     const Vector2 textSize = mView.GetLayoutSize();
2127
2128     const float offsetX = textSize.width * 0.5f;
2129     const float offsetY = textSize.height * 0.5f;
2130
2131     const Vector4* const    backgroundColorsBuffer       = mView.GetBackgroundColors();
2132     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
2133     const Vector4&          defaultBackgroundColor       = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
2134
2135     Vector4   quad;
2136     uint32_t  numberOfQuads = 0u;
2137     Length    yLineOffset   = 0;
2138     Length    prevLineIndex = 0;
2139     LineIndex lineIndex;
2140     Length    numberOfLines;
2141
2142     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
2143     {
2144       const GlyphInfo& glyph = *(glyphsBuffer + i);
2145
2146       // Get the background color of the character.
2147       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
2148       const bool       isMarkupBackground       = mView.IsMarkupBackgroundColorSet();
2149       const ColorIndex backgroundColorIndex     = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
2150       const bool       isDefaultBackgroundColor = (0u == backgroundColorIndex);
2151       const Vector4&   backgroundColor          = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
2152
2153       mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
2154       Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
2155
2156       if(lineIndex != prevLineIndex)
2157       {
2158         yLineOffset += lineHeight;
2159       }
2160
2161       // Only create quads for glyphs with a background color
2162       if(backgroundColor != Color::TRANSPARENT)
2163       {
2164         const Vector2 position = *(positionsBuffer + i);
2165
2166         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
2167         {
2168           quad.x = position.x;
2169           quad.y = yLineOffset;
2170           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
2171           quad.w = lineHeight;
2172         }
2173         else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
2174         {
2175           quad.x = position.x;
2176           quad.y = yLineOffset;
2177           quad.z = quad.x - glyph.xBearing + glyph.advance;
2178           quad.w = quad.y + lineHeight;
2179         }
2180         else if(i == glyphSize - 1u) // The last glyph in the whole text
2181         {
2182           quad.x = position.x - glyph.xBearing;
2183           quad.y = yLineOffset;
2184           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
2185           quad.w = quad.y + lineHeight;
2186         }
2187         else // The glyph in the middle of the text
2188         {
2189           quad.x = position.x - glyph.xBearing;
2190           quad.y = yLineOffset;
2191           quad.z = quad.x + glyph.advance;
2192           quad.w = quad.y + lineHeight;
2193         }
2194
2195         BackgroundVertex vertex;
2196
2197         // Top left
2198         vertex.mPosition.x = quad.x - offsetX;
2199         vertex.mPosition.y = quad.y - offsetY;
2200         vertex.mColor      = backgroundColor;
2201         mesh.mVertices.PushBack(vertex);
2202
2203         // Top right
2204         vertex.mPosition.x = quad.z - offsetX;
2205         vertex.mPosition.y = quad.y - offsetY;
2206         vertex.mColor      = backgroundColor;
2207         mesh.mVertices.PushBack(vertex);
2208
2209         // Bottom left
2210         vertex.mPosition.x = quad.x - offsetX;
2211         vertex.mPosition.y = quad.w - offsetY;
2212         vertex.mColor      = backgroundColor;
2213         mesh.mVertices.PushBack(vertex);
2214
2215         // Bottom right
2216         vertex.mPosition.x = quad.z - offsetX;
2217         vertex.mPosition.y = quad.w - offsetY;
2218         vertex.mColor      = backgroundColor;
2219         mesh.mVertices.PushBack(vertex);
2220
2221         // Six indices in counter clockwise winding
2222         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
2223         mesh.mIndices.PushBack(0u + 4 * numberOfQuads);
2224         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
2225         mesh.mIndices.PushBack(2u + 4 * numberOfQuads);
2226         mesh.mIndices.PushBack(3u + 4 * numberOfQuads);
2227         mesh.mIndices.PushBack(1u + 4 * numberOfQuads);
2228
2229         numberOfQuads++;
2230       }
2231
2232       if(lineIndex != prevLineIndex)
2233       {
2234         prevLineIndex = lineIndex;
2235       }
2236     }
2237
2238     // Only create the background actor if there are glyphs with background color
2239     if(mesh.mVertices.Count() > 0u)
2240     {
2241       Property::Map quadVertexFormat;
2242       quadVertexFormat["aPosition"] = Property::VECTOR2;
2243       quadVertexFormat["aColor"]    = Property::VECTOR4;
2244
2245       VertexBuffer quadVertices = VertexBuffer::New(quadVertexFormat);
2246       quadVertices.SetData(&mesh.mVertices[0], mesh.mVertices.Size());
2247
2248       Geometry quadGeometry = Geometry::New();
2249       quadGeometry.AddVertexBuffer(quadVertices);
2250       quadGeometry.SetIndexBuffer(&mesh.mIndices[0], mesh.mIndices.Size());
2251
2252       if(!mShaderBackground)
2253       {
2254         mShaderBackground = Shader::New(SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_VERT, SHADER_TEXT_CONTROLLER_BACKGROUND_SHADER_FRAG);
2255       }
2256
2257       Dali::Renderer renderer = Dali::Renderer::New(quadGeometry, mShaderBackground);
2258       renderer.SetProperty(Dali::Renderer::Property::BLEND_MODE, BlendMode::ON);
2259       renderer.SetProperty(Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT);
2260
2261       actor = Actor::New();
2262       actor.SetProperty(Dali::Actor::Property::NAME, "TextBackgroundColorActor");
2263       actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
2264       actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
2265       actor.SetProperty(Actor::Property::SIZE, textSize);
2266       actor.SetProperty(Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR);
2267       actor.AddRenderer(renderer);
2268     }
2269   }
2270
2271   return actor;
2272 }
2273
2274 void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
2275 {
2276   //Underlined character runs for markup-processor
2277   const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
2278   const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
2279   const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
2280
2281   if(shouldClearPreUnderlineRuns)
2282   {
2283     mModel->mVisualModel->mUnderlineRuns.Clear();
2284   }
2285
2286   for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
2287   {
2288     CharacterIndex characterIndex     = it->characterRun.characterIndex;
2289     Length         numberOfCharacters = it->characterRun.numberOfCharacters;
2290     for(Length index = 0u; index < numberOfCharacters; index++)
2291     {
2292       GlyphRun underlineGlyphRun;
2293       underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
2294       underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
2295       mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
2296     }
2297   }
2298 }
2299
2300 } // namespace Text
2301
2302 } // namespace Toolkit
2303
2304 } // namespace Dali