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