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