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