Multiple text background color support for left-to-right text only in TextField
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
1 /*
2  * Copyright (c) 2017 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/public-api/adaptor-framework/key.h>
23 #include <dali/public-api/rendering/renderer.h>
24 #include <dali/integration-api/debug.h>
25 #include <limits>
26
27 // INTERNAL INCLUDES
28 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
29 #include <dali-toolkit/internal/text/bidirectional-support.h>
30 #include <dali-toolkit/internal/text/character-set-conversion.h>
31 #include <dali-toolkit/internal/text/color-segmentation.h>
32 #include <dali-toolkit/internal/text/cursor-helper-functions.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-run-container.h>
38
39 using namespace Dali;
40
41 namespace
42 {
43
44 /**
45  * @brief Struct used to calculate the selection box.
46  */
47 struct SelectionBoxInfo
48 {
49   float lineOffset;
50   float lineHeight;
51   float minX;
52   float maxX;
53 };
54
55 #if defined(DEBUG_ENABLED)
56   Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
57 #endif
58
59 const float MAX_FLOAT = std::numeric_limits<float>::max();
60 const float MIN_FLOAT = std::numeric_limits<float>::min();
61 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
62
63 #define MAKE_SHADER(A)#A
64
65 const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
66 attribute mediump vec2    aPosition;
67 attribute mediump vec4    aColor;
68 varying   mediump vec4    vColor;
69 uniform   highp mat4      uMvpMatrix;
70
71 void main()
72 {
73   mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
74   gl_Position = uMvpMatrix * position;
75   vColor = aColor;
76 }
77 );
78
79 const char* FRAGMENT_SHADER_BACKGROUND = MAKE_SHADER(
80 varying mediump vec4      vColor;
81 uniform lowp    vec4      uColor;
82
83 void main()
84 {
85   gl_FragColor = vColor * uColor;
86 }
87 );
88
89 struct BackgroundVertex
90 {
91   Vector2 mPosition;        ///< Vertex posiiton
92   Vector4 mColor;           ///< Vertex color
93 };
94
95 struct BackgroundMesh
96 {
97   Vector< BackgroundVertex > mVertices;    ///< container of vertices
98   Vector< unsigned short > mIndices;       ///< container of indices
99 };
100
101 } // namespace
102
103 namespace Dali
104 {
105
106 namespace Toolkit
107 {
108
109 namespace Text
110 {
111
112 EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
113 : mDecorator( decorator ),
114   mInputMethodContext( inputMethodContext ),
115   mPlaceholderFont( NULL ),
116   mPlaceholderTextActive(),
117   mPlaceholderTextInactive(),
118   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
119   mEventQueue(),
120   mInputStyleChangedQueue(),
121   mPreviousState( INACTIVE ),
122   mState( INACTIVE ),
123   mPrimaryCursorPosition( 0u ),
124   mLeftSelectionPosition( 0u ),
125   mRightSelectionPosition( 0u ),
126   mPreEditStartPosition( 0u ),
127   mPreEditLength( 0u ),
128   mCursorHookPositionX( 0.f ),
129   mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
130   mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
131   mIsShowingPlaceholderText( false ),
132   mPreEditFlag( false ),
133   mDecoratorUpdated( false ),
134   mCursorBlinkEnabled( true ),
135   mGrabHandleEnabled( true ),
136   mGrabHandlePopupEnabled( true ),
137   mSelectionEnabled( true ),
138   mUpdateCursorHookPosition( false ),
139   mUpdateCursorPosition( false ),
140   mUpdateGrabHandlePosition( false ),
141   mUpdateLeftSelectionPosition( false ),
142   mUpdateRightSelectionPosition( false ),
143   mIsLeftHandleSelected( false ),
144   mIsRightHandleSelected( false ),
145   mUpdateHighlightBox( false ),
146   mScrollAfterUpdatePosition( false ),
147   mScrollAfterDelete( false ),
148   mAllTextSelected( false ),
149   mUpdateInputStyle( false ),
150   mPasswordInput( false ),
151   mCheckScrollAmount( false ),
152   mIsPlaceholderPixelSize( false ),
153   mIsPlaceholderElideEnabled( false ),
154   mPlaceholderEllipsisFlag( false ),
155   mShiftSelectionFlag( true ),
156   mUpdateAlignment( false )
157 {
158 }
159
160 EventData::~EventData()
161 {}
162
163 bool Controller::Impl::ProcessInputEvents()
164 {
165   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
166   if( NULL == mEventData )
167   {
168     // Nothing to do if there is no text input.
169     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
170     return false;
171   }
172
173   if( mEventData->mDecorator )
174   {
175     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
176          iter != mEventData->mEventQueue.end();
177          ++iter )
178     {
179       switch( iter->type )
180       {
181         case Event::CURSOR_KEY_EVENT:
182         {
183           OnCursorKeyEvent( *iter );
184           break;
185         }
186         case Event::TAP_EVENT:
187         {
188           OnTapEvent( *iter );
189           break;
190         }
191         case Event::LONG_PRESS_EVENT:
192         {
193           OnLongPressEvent( *iter );
194           break;
195         }
196         case Event::PAN_EVENT:
197         {
198           OnPanEvent( *iter );
199           break;
200         }
201         case Event::GRAB_HANDLE_EVENT:
202         case Event::LEFT_SELECTION_HANDLE_EVENT:
203         case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
204         {
205           OnHandleEvent( *iter );
206           break;
207         }
208         case Event::SELECT:
209         {
210           OnSelectEvent( *iter );
211           break;
212         }
213         case Event::SELECT_ALL:
214         {
215           OnSelectAllEvent();
216           break;
217         }
218       }
219     }
220   }
221
222   if( mEventData->mUpdateCursorPosition ||
223       mEventData->mUpdateHighlightBox )
224   {
225     NotifyInputMethodContext();
226   }
227
228   // The cursor must also be repositioned after inserts into the model
229   if( mEventData->mUpdateCursorPosition )
230   {
231     // Updates the cursor position and scrolls the text to make it visible.
232     CursorInfo cursorInfo;
233     // Calculate the cursor position from the new cursor index.
234     GetCursorPosition( mEventData->mPrimaryCursorPosition,
235                        cursorInfo );
236
237     if( mEventData->mUpdateCursorHookPosition )
238     {
239       // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
240       mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
241       mEventData->mUpdateCursorHookPosition = false;
242     }
243
244     // Scroll first the text after delete ...
245     if( mEventData->mScrollAfterDelete )
246     {
247       ScrollTextToMatchCursor( cursorInfo );
248     }
249
250     // ... then, text can be scrolled to make the cursor visible.
251     if( mEventData->mScrollAfterUpdatePosition )
252     {
253       const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
254       ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
255     }
256     mEventData->mScrollAfterUpdatePosition = false;
257     mEventData->mScrollAfterDelete = false;
258
259     UpdateCursorPosition( cursorInfo );
260
261     mEventData->mDecoratorUpdated = true;
262     mEventData->mUpdateCursorPosition = false;
263     mEventData->mUpdateGrabHandlePosition = false;
264   }
265   else
266   {
267     CursorInfo leftHandleInfo;
268     CursorInfo rightHandleInfo;
269
270     if( mEventData->mUpdateHighlightBox )
271     {
272       GetCursorPosition( mEventData->mLeftSelectionPosition,
273                          leftHandleInfo );
274
275       GetCursorPosition( mEventData->mRightSelectionPosition,
276                          rightHandleInfo );
277
278       if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
279       {
280         if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
281         {
282           CursorInfo& infoLeft = leftHandleInfo;
283
284           const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
285           ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
286
287           CursorInfo& infoRight = rightHandleInfo;
288
289           const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
290           ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
291         }
292         else
293         {
294           CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
295
296           const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
297           ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
298         }
299       }
300     }
301
302     if( mEventData->mUpdateLeftSelectionPosition )
303     {
304       UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
305                              leftHandleInfo );
306
307       SetPopupButtons();
308       mEventData->mDecoratorUpdated = true;
309       mEventData->mUpdateLeftSelectionPosition = false;
310     }
311
312     if( mEventData->mUpdateRightSelectionPosition )
313     {
314       UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
315                              rightHandleInfo );
316
317       SetPopupButtons();
318       mEventData->mDecoratorUpdated = true;
319       mEventData->mUpdateRightSelectionPosition = false;
320     }
321
322     if( mEventData->mUpdateHighlightBox )
323     {
324       RepositionSelectionHandles();
325
326       mEventData->mUpdateLeftSelectionPosition = false;
327       mEventData->mUpdateRightSelectionPosition = false;
328       mEventData->mUpdateHighlightBox = false;
329       mEventData->mIsLeftHandleSelected = false;
330       mEventData->mIsRightHandleSelected = false;
331     }
332
333     mEventData->mScrollAfterUpdatePosition = false;
334   }
335
336   if( mEventData->mUpdateInputStyle )
337   {
338     // Keep a copy of the current input style.
339     InputStyle currentInputStyle;
340     currentInputStyle.Copy( mEventData->mInputStyle );
341
342     // Set the default style first.
343     RetrieveDefaultInputStyle( mEventData->mInputStyle );
344
345     // Get the character index from the cursor index.
346     const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
347
348     // Retrieve the style from the style runs stored in the logical model.
349     mModel->mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
350
351     // Compare if the input style has changed.
352     const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
353
354     if( hasInputStyleChanged )
355     {
356       const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
357       // Queue the input style changed signal.
358       mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
359     }
360
361     mEventData->mUpdateInputStyle = false;
362   }
363
364   mEventData->mEventQueue.clear();
365
366   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
367
368   const bool decoratorUpdated = mEventData->mDecoratorUpdated;
369   mEventData->mDecoratorUpdated = false;
370
371   return decoratorUpdated;
372 }
373
374 void Controller::Impl::NotifyInputMethodContext()
375 {
376   if( mEventData && mEventData->mInputMethodContext )
377   {
378     CharacterIndex cursorPosition = GetLogicalCursorPosition();
379
380     const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
381
382     // Update the cursor position by removing the initial white spaces.
383     if( cursorPosition < numberOfWhiteSpaces )
384     {
385       cursorPosition = 0u;
386     }
387     else
388     {
389       cursorPosition -= numberOfWhiteSpaces;
390     }
391
392     mEventData->mInputMethodContext.SetCursorPosition( cursorPosition );
393     mEventData->mInputMethodContext.NotifyCursorPosition();
394   }
395 }
396
397 void Controller::Impl::NotifyInputMethodContextMultiLineStatus()
398 {
399   if ( mEventData && mEventData->mInputMethodContext )
400   {
401     Text::Layout::Engine::Type layout = mLayoutEngine.GetLayout();
402     mEventData->mInputMethodContext.NotifyTextInputMultiLine( layout == Text::Layout::Engine::MULTI_LINE_BOX );
403   }
404 }
405
406 CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
407 {
408   CharacterIndex cursorPosition = 0u;
409
410   if( mEventData )
411   {
412     if( ( EventData::SELECTING == mEventData->mState ) ||
413         ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
414     {
415       cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
416     }
417     else
418     {
419       cursorPosition = mEventData->mPrimaryCursorPosition;
420     }
421   }
422
423   return cursorPosition;
424 }
425
426 Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
427 {
428   Length numberOfWhiteSpaces = 0u;
429
430   // Get the buffer to the text.
431   Character* utf32CharacterBuffer = mModel->mLogicalModel->mText.Begin();
432
433   const Length totalNumberOfCharacters = mModel->mLogicalModel->mText.Count();
434   for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
435   {
436     if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
437     {
438       break;
439     }
440   }
441
442   return numberOfWhiteSpaces;
443 }
444
445 void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
446 {
447   // Get the total number of characters.
448   Length numberOfCharacters = mModel->mLogicalModel->mText.Count();
449
450   // Retrieve the text.
451   if( 0u != numberOfCharacters )
452   {
453     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
454   }
455 }
456
457 void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
458 {
459   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
460   mTextUpdateInfo.mStartGlyphIndex = 0u;
461   mTextUpdateInfo.mStartLineIndex = 0u;
462   numberOfCharacters = 0u;
463
464   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
465   if( 0u == numberOfParagraphs )
466   {
467     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
468     numberOfCharacters = 0u;
469
470     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
471
472     // Nothing else to do if there are no paragraphs.
473     return;
474   }
475
476   // Find the paragraphs to be updated.
477   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
478   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
479   {
480     // Text is being added at the end of the current text.
481     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
482     {
483       // Text is being added in a new paragraph after the last character of the text.
484       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
485       numberOfCharacters = 0u;
486       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
487
488       mTextUpdateInfo.mStartGlyphIndex = mModel->mVisualModel->mGlyphs.Count();
489       mTextUpdateInfo.mStartLineIndex = mModel->mVisualModel->mLines.Count() - 1u;
490
491       // Nothing else to do;
492       return;
493     }
494
495     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
496   }
497   else
498   {
499     Length numberOfCharactersToUpdate = 0u;
500     if( mTextUpdateInfo.mFullRelayoutNeeded )
501     {
502       numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
503     }
504     else
505     {
506       numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
507     }
508     mModel->mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
509                                            numberOfCharactersToUpdate,
510                                            paragraphsToBeUpdated );
511   }
512
513   if( 0u != paragraphsToBeUpdated.Count() )
514   {
515     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
516     const ParagraphRun& firstParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
517     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
518
519     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
520     const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
521
522     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
523         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
524         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
525           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
526     {
527       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
528       const ParagraphRun& lastParagraph = *( mModel->mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
529
530       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
531     }
532     else
533     {
534       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
535     }
536   }
537
538   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
539   mTextUpdateInfo.mStartGlyphIndex = *( mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
540 }
541
542 void Controller::Impl::ClearFullModelData( OperationsMask operations )
543 {
544   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
545   {
546     mModel->mLogicalModel->mLineBreakInfo.Clear();
547     mModel->mLogicalModel->mParagraphInfo.Clear();
548   }
549
550   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
551   {
552     mModel->mLogicalModel->mScriptRuns.Clear();
553   }
554
555   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
556   {
557     mModel->mLogicalModel->mFontRuns.Clear();
558   }
559
560   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
561   {
562     if( NO_OPERATION != ( BIDI_INFO & operations ) )
563     {
564       mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
565       mModel->mLogicalModel->mCharacterDirections.Clear();
566     }
567
568     if( NO_OPERATION != ( REORDER & operations ) )
569     {
570       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
571       for( Vector<BidirectionalLineInfoRun>::Iterator it = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
572              endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
573            it != endIt;
574            ++it )
575       {
576         BidirectionalLineInfoRun& bidiLineInfo = *it;
577
578         free( bidiLineInfo.visualToLogicalMap );
579         bidiLineInfo.visualToLogicalMap = NULL;
580       }
581       mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
582     }
583   }
584
585   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
586   {
587     mModel->mVisualModel->mGlyphs.Clear();
588     mModel->mVisualModel->mGlyphsToCharacters.Clear();
589     mModel->mVisualModel->mCharactersToGlyph.Clear();
590     mModel->mVisualModel->mCharactersPerGlyph.Clear();
591     mModel->mVisualModel->mGlyphsPerCharacter.Clear();
592     mModel->mVisualModel->mGlyphPositions.Clear();
593   }
594
595   if( NO_OPERATION != ( LAYOUT & operations ) )
596   {
597     mModel->mVisualModel->mLines.Clear();
598   }
599
600   if( NO_OPERATION != ( COLOR & operations ) )
601   {
602     mModel->mVisualModel->mColorIndices.Clear();
603     mModel->mVisualModel->mBackgroundColorIndices.Clear();
604   }
605 }
606
607 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
608 {
609   const CharacterIndex endIndexPlusOne = endIndex + 1u;
610
611   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
612   {
613     // Clear the line break info.
614     LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
615
616     mModel->mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
617                                                  lineBreakInfoBuffer + endIndexPlusOne );
618
619     // Clear the paragraphs.
620     ClearCharacterRuns( startIndex,
621                         endIndex,
622                         mModel->mLogicalModel->mParagraphInfo );
623   }
624
625   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
626   {
627     // Clear the scripts.
628     ClearCharacterRuns( startIndex,
629                         endIndex,
630                         mModel->mLogicalModel->mScriptRuns );
631   }
632
633   if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
634   {
635     // Clear the fonts.
636     ClearCharacterRuns( startIndex,
637                         endIndex,
638                         mModel->mLogicalModel->mFontRuns );
639   }
640
641   if( 0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count() )
642   {
643     if( NO_OPERATION != ( BIDI_INFO & operations ) )
644     {
645       // Clear the bidirectional paragraph info.
646       ClearCharacterRuns( startIndex,
647                           endIndex,
648                           mModel->mLogicalModel->mBidirectionalParagraphInfo );
649
650       // Clear the character's directions.
651       CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
652
653       mModel->mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
654                                                          characterDirectionsBuffer + endIndexPlusOne );
655     }
656
657     if( NO_OPERATION != ( REORDER & operations ) )
658     {
659       uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
660       uint32_t endRemoveIndex = startRemoveIndex;
661       ClearCharacterRuns( startIndex,
662                           endIndex,
663                           mModel->mLogicalModel->mBidirectionalLineInfo,
664                           startRemoveIndex,
665                           endRemoveIndex );
666
667       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
668
669       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
670       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
671              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
672            it != endIt;
673            ++it )
674       {
675         BidirectionalLineInfoRun& bidiLineInfo = *it;
676
677         free( bidiLineInfo.visualToLogicalMap );
678         bidiLineInfo.visualToLogicalMap = NULL;
679       }
680
681       mModel->mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
682                                                            bidirectionalLineInfoBuffer + endRemoveIndex );
683     }
684   }
685 }
686
687 void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
688 {
689   const CharacterIndex endIndexPlusOne = endIndex + 1u;
690   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
691
692   // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
693   GlyphIndex* charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
694   Length* glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
695
696   const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
697   const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
698
699   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
700   {
701     // Update the character to glyph indices.
702     for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
703            endIt =  charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
704          it != endIt;
705          ++it )
706     {
707       CharacterIndex& index = *it;
708       index -= numberOfGlyphsRemoved;
709     }
710
711     // Clear the character to glyph conversion table.
712     mModel->mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
713                                                     charactersToGlyphBuffer + endIndexPlusOne );
714
715     // Clear the glyphs per character table.
716     mModel->mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
717                                                      glyphsPerCharacterBuffer + endIndexPlusOne );
718
719     // Clear the glyphs buffer.
720     GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
721     mModel->mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
722                                          glyphsBuffer + endGlyphIndexPlusOne );
723
724     CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
725
726     // Update the glyph to character indices.
727     for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
728            endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
729          it != endIt;
730          ++it )
731     {
732       CharacterIndex& index = *it;
733       index -= numberOfCharactersRemoved;
734     }
735
736     // Clear the glyphs to characters buffer.
737     mModel->mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
738                                                      glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
739
740     // Clear the characters per glyph buffer.
741     Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
742     mModel->mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
743                                                      charactersPerGlyphBuffer + endGlyphIndexPlusOne );
744
745     // Clear the positions buffer.
746     Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
747     mModel->mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
748                                                  positionsBuffer + endGlyphIndexPlusOne );
749   }
750
751   if( NO_OPERATION != ( LAYOUT & operations ) )
752   {
753     // Clear the lines.
754     uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
755     uint32_t endRemoveIndex = startRemoveIndex;
756     ClearCharacterRuns( startIndex,
757                         endIndex,
758                         mModel->mVisualModel->mLines,
759                         startRemoveIndex,
760                         endRemoveIndex );
761
762     // Will update the glyph runs.
763     startRemoveIndex = mModel->mVisualModel->mLines.Count();
764     endRemoveIndex = startRemoveIndex;
765     ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
766                     endGlyphIndexPlusOne - 1u,
767                     mModel->mVisualModel->mLines,
768                     startRemoveIndex,
769                     endRemoveIndex );
770
771     // Set the line index from where to insert the new laid-out lines.
772     mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
773
774     LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
775     mModel->mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
776                                         linesBuffer + endRemoveIndex );
777   }
778
779   if( NO_OPERATION != ( COLOR & operations ) )
780   {
781     if( 0u != mModel->mVisualModel->mColorIndices.Count() )
782     {
783       ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
784       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
785                                                  colorIndexBuffer + endGlyphIndexPlusOne );
786     }
787
788     if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
789     {
790       ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
791       mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
792                                                            backgroundColorIndexBuffer + endGlyphIndexPlusOne );
793     }
794   }
795 }
796
797 void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
798 {
799   if( mTextUpdateInfo.mClearAll ||
800       ( ( 0u == startIndex ) &&
801         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
802   {
803     ClearFullModelData( operations );
804   }
805   else
806   {
807     // Clear the model data related with characters.
808     ClearCharacterModelData( startIndex, endIndex, operations );
809
810     // Clear the model data related with glyphs.
811     ClearGlyphModelData( startIndex, endIndex, operations );
812   }
813
814   // The estimated number of lines. Used to avoid reallocations when layouting.
815   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
816
817   mModel->mVisualModel->ClearCaches();
818 }
819
820 bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
821 {
822   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
823
824   // Calculate the operations to be done.
825   const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
826
827   if( NO_OPERATION == operations )
828   {
829     // Nothing to do if no operations are pending and required.
830     return false;
831   }
832
833   Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
834   Vector<Character> displayCharacters;
835   bool useHiddenText = false;
836   if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
837   {
838     mHiddenInput->Substitute( srcCharacters,displayCharacters );
839     useHiddenText = true;
840   }
841
842   Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
843   const Length numberOfCharacters = utf32Characters.Count();
844
845   // Index to the first character of the first paragraph to be updated.
846   CharacterIndex startIndex = 0u;
847   // Number of characters of the paragraphs to be removed.
848   Length paragraphCharacters = 0u;
849
850   CalculateTextUpdateIndices( paragraphCharacters );
851
852   // Check whether the indices for updating the text is valid
853   if ( numberOfCharacters > 0u &&
854        ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
855          mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
856   {
857     std::string currentText;
858     Utf32ToUtf8( mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText );
859
860     DALI_LOG_ERROR( "Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n" );
861     DALI_LOG_ERROR( "Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str() );
862
863     // Dump mTextUpdateInfo
864     DALI_LOG_ERROR( "Dump mTextUpdateInfo:\n" );
865     DALI_LOG_ERROR( "     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex );
866     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove );
867     DALI_LOG_ERROR( "     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd );
868     DALI_LOG_ERROR( "     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters );
869     DALI_LOG_ERROR( "     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex );
870     DALI_LOG_ERROR( "     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters );
871     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex );
872     DALI_LOG_ERROR( "     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex );
873     DALI_LOG_ERROR( "     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines );
874     DALI_LOG_ERROR( "     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll );
875     DALI_LOG_ERROR( "     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded );
876     DALI_LOG_ERROR( "     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph );
877
878     return false;
879   }
880
881   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
882
883   if( mTextUpdateInfo.mClearAll ||
884       ( 0u != paragraphCharacters ) )
885   {
886     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
887   }
888
889   mTextUpdateInfo.mClearAll = false;
890
891   // Whether the model is updated.
892   bool updated = false;
893
894   Vector<LineBreakInfo>& lineBreakInfo = mModel->mLogicalModel->mLineBreakInfo;
895   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
896
897   if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
898   {
899     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
900     // calculate the bidirectional info for each 'paragraph'.
901     // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
902     // is not shaped together).
903     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
904
905     SetLineBreakInfo( utf32Characters,
906                       startIndex,
907                       requestedNumberOfCharacters,
908                       lineBreakInfo );
909
910     // Create the paragraph info.
911     mModel->mLogicalModel->CreateParagraphInfo( startIndex,
912                                                 requestedNumberOfCharacters );
913     updated = true;
914   }
915
916   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
917   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
918
919   Vector<ScriptRun>& scripts = mModel->mLogicalModel->mScriptRuns;
920   Vector<FontRun>& validFonts = mModel->mLogicalModel->mFontRuns;
921
922   if( getScripts || validateFonts )
923   {
924     // Validates the fonts assigned by the application or assigns default ones.
925     // It makes sure all the characters are going to be rendered by the correct font.
926     MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
927
928     if( getScripts )
929     {
930       // Retrieves the scripts used in the text.
931       multilanguageSupport.SetScripts( utf32Characters,
932                                        startIndex,
933                                        requestedNumberOfCharacters,
934                                        scripts );
935     }
936
937     if( validateFonts )
938     {
939       // Validate the fonts set through the mark-up string.
940       Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
941
942       // Get the default font's description.
943       TextAbstraction::FontDescription defaultFontDescription;
944       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
945
946       if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
947       {
948         // If the placeholder font is set specifically, only placeholder font is changed.
949         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
950         if( mEventData->mPlaceholderFont->sizeDefined )
951         {
952           defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
953         }
954       }
955       else if( NULL != mFontDefaults )
956       {
957         // Set the normal font and the placeholder font.
958         defaultFontDescription = mFontDefaults->mFontDescription;
959
960         if( mTextFitEnabled )
961         {
962           defaultPointSize = mFontDefaults->mFitPointSize * 64u;
963         }
964         else
965         {
966           defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
967         }
968       }
969
970       // Validates the fonts. If there is a character with no assigned font it sets a default one.
971       // After this call, fonts are validated.
972       multilanguageSupport.ValidateFonts( utf32Characters,
973                                           scripts,
974                                           fontDescriptionRuns,
975                                           defaultFontDescription,
976                                           defaultPointSize,
977                                           startIndex,
978                                           requestedNumberOfCharacters,
979                                           validFonts );
980     }
981     updated = true;
982   }
983
984   Vector<Character> mirroredUtf32Characters;
985   bool textMirrored = false;
986   const Length numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
987   if( NO_OPERATION != ( BIDI_INFO & operations ) )
988   {
989     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
990     bidirectionalInfo.Reserve( numberOfParagraphs );
991
992     // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
993     SetBidirectionalInfo( utf32Characters,
994                           scripts,
995                           lineBreakInfo,
996                           startIndex,
997                           requestedNumberOfCharacters,
998                           bidirectionalInfo,
999                           mModel->mMatchSystemLanguageDirection,
1000                           mLayoutDirection );
1001
1002     if( 0u != bidirectionalInfo.Count() )
1003     {
1004       // Only set the character directions if there is right to left characters.
1005       Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
1006       GetCharactersDirection( bidirectionalInfo,
1007                               numberOfCharacters,
1008                               startIndex,
1009                               requestedNumberOfCharacters,
1010                               directions );
1011
1012       // This paragraph has right to left text. Some characters may need to be mirrored.
1013       // TODO: consider if the mirrored string can be stored as well.
1014
1015       textMirrored = GetMirroredText( utf32Characters,
1016                                       directions,
1017                                       bidirectionalInfo,
1018                                       startIndex,
1019                                       requestedNumberOfCharacters,
1020                                       mirroredUtf32Characters );
1021     }
1022     else
1023     {
1024       // There is no right to left characters. Clear the directions vector.
1025       mModel->mLogicalModel->mCharacterDirections.Clear();
1026     }
1027     updated = true;
1028   }
1029
1030   Vector<GlyphInfo>& glyphs = mModel->mVisualModel->mGlyphs;
1031   Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
1032   Vector<Length>& charactersPerGlyph = mModel->mVisualModel->mCharactersPerGlyph;
1033   Vector<GlyphIndex> newParagraphGlyphs;
1034   newParagraphGlyphs.Reserve( numberOfParagraphs );
1035
1036   const Length currentNumberOfGlyphs = glyphs.Count();
1037   if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
1038   {
1039     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
1040     // Shapes the text.
1041     ShapeText( textToShape,
1042                lineBreakInfo,
1043                scripts,
1044                validFonts,
1045                startIndex,
1046                mTextUpdateInfo.mStartGlyphIndex,
1047                requestedNumberOfCharacters,
1048                glyphs,
1049                glyphsToCharactersMap,
1050                charactersPerGlyph,
1051                newParagraphGlyphs );
1052
1053     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
1054     mModel->mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1055     mModel->mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
1056     updated = true;
1057   }
1058
1059   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
1060
1061   if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
1062   {
1063     GlyphInfo* glyphsBuffer = glyphs.Begin();
1064     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
1065
1066     // Update the width and advance of all new paragraph characters.
1067     for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
1068     {
1069       const GlyphIndex index = *it;
1070       GlyphInfo& glyph = *( glyphsBuffer + index );
1071
1072       glyph.xBearing = 0.f;
1073       glyph.width = 0.f;
1074       glyph.advance = 0.f;
1075     }
1076     updated = true;
1077   }
1078
1079   if( ( NULL != mEventData ) &&
1080       mEventData->mPreEditFlag &&
1081       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
1082   {
1083     Dali::InputMethodContext::PreeditStyle type = mEventData->mInputMethodContext.GetPreeditStyle();
1084
1085     switch( type )
1086     {
1087       case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
1088       {
1089         // Add the underline for the pre-edit text.
1090         const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
1091         const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
1092
1093         const GlyphIndex glyphStart = *( charactersToGlyphBuffer + mEventData->mPreEditStartPosition );
1094         const CharacterIndex lastPreEditCharacter = mEventData->mPreEditStartPosition + ( ( mEventData->mPreEditLength > 0u ) ? mEventData->mPreEditLength - 1u : 0u );
1095         const Length numberOfGlyphsLastCharacter = *( glyphsPerCharacterBuffer + lastPreEditCharacter );
1096         const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + lastPreEditCharacter ) + ( numberOfGlyphsLastCharacter > 1u ? numberOfGlyphsLastCharacter - 1u : 0u );
1097
1098         GlyphRun underlineRun;
1099         underlineRun.glyphIndex = glyphStart;
1100         underlineRun.numberOfGlyphs = 1u + glyphEnd - glyphStart;
1101
1102         mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
1103         break;
1104       }
1105       // TODO :  At this moment, other styles for preedit are not implemented yet.
1106       case Dali::InputMethodContext::PreeditStyle::REVERSE:
1107       case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
1108       case Dali::InputMethodContext::PreeditStyle::NONE:
1109       default:
1110         break;
1111     }
1112   }
1113
1114   if( NO_OPERATION != ( COLOR & operations ) )
1115   {
1116     // Set the color runs in glyphs.
1117     SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
1118                               mModel->mVisualModel->mCharactersToGlyph,
1119                               mModel->mVisualModel->mGlyphsPerCharacter,
1120                               startIndex,
1121                               mTextUpdateInfo.mStartGlyphIndex,
1122                               requestedNumberOfCharacters,
1123                               mModel->mVisualModel->mColors,
1124                               mModel->mVisualModel->mColorIndices );
1125
1126     // Set the background color runs in glyphs.
1127     SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
1128                               mModel->mVisualModel->mCharactersToGlyph,
1129                               mModel->mVisualModel->mGlyphsPerCharacter,
1130                               startIndex,
1131                               mTextUpdateInfo.mStartGlyphIndex,
1132                               requestedNumberOfCharacters,
1133                               mModel->mVisualModel->mBackgroundColors,
1134                               mModel->mVisualModel->mBackgroundColorIndices );
1135
1136     updated = true;
1137   }
1138
1139
1140   // The estimated number of lines. Used to avoid reallocations when layouting.
1141   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
1142
1143   // Set the previous number of characters for the next time the text is updated.
1144   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
1145
1146   return updated;
1147 }
1148
1149 void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
1150 {
1151   // Sets the default text's color.
1152   inputStyle.textColor = mTextColor;
1153   inputStyle.isDefaultColor = true;
1154
1155   inputStyle.familyName.clear();
1156   inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
1157   inputStyle.width = TextAbstraction::FontWidth::NORMAL;
1158   inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
1159   inputStyle.size = 0.f;
1160
1161   inputStyle.lineSpacing = 0.f;
1162
1163   inputStyle.underlineProperties.clear();
1164   inputStyle.shadowProperties.clear();
1165   inputStyle.embossProperties.clear();
1166   inputStyle.outlineProperties.clear();
1167
1168   inputStyle.isFamilyDefined = false;
1169   inputStyle.isWeightDefined = false;
1170   inputStyle.isWidthDefined = false;
1171   inputStyle.isSlantDefined = false;
1172   inputStyle.isSizeDefined = false;
1173
1174   inputStyle.isLineSpacingDefined = false;
1175
1176   inputStyle.isUnderlineDefined = false;
1177   inputStyle.isShadowDefined = false;
1178   inputStyle.isEmbossDefined = false;
1179   inputStyle.isOutlineDefined = false;
1180
1181   // Sets the default font's family name, weight, width, slant and size.
1182   if( mFontDefaults )
1183   {
1184     if( mFontDefaults->familyDefined )
1185     {
1186       inputStyle.familyName = mFontDefaults->mFontDescription.family;
1187       inputStyle.isFamilyDefined = true;
1188     }
1189
1190     if( mFontDefaults->weightDefined )
1191     {
1192       inputStyle.weight = mFontDefaults->mFontDescription.weight;
1193       inputStyle.isWeightDefined = true;
1194     }
1195
1196     if( mFontDefaults->widthDefined )
1197     {
1198       inputStyle.width = mFontDefaults->mFontDescription.width;
1199       inputStyle.isWidthDefined = true;
1200     }
1201
1202     if( mFontDefaults->slantDefined )
1203     {
1204       inputStyle.slant = mFontDefaults->mFontDescription.slant;
1205       inputStyle.isSlantDefined = true;
1206     }
1207
1208     if( mFontDefaults->sizeDefined )
1209     {
1210       inputStyle.size = mFontDefaults->mDefaultPointSize;
1211       inputStyle.isSizeDefined = true;
1212     }
1213   }
1214 }
1215
1216 float Controller::Impl::GetDefaultFontLineHeight()
1217 {
1218   FontId defaultFontId = 0u;
1219   if( NULL == mFontDefaults )
1220   {
1221     TextAbstraction::FontDescription fontDescription;
1222     defaultFontId = mFontClient.GetFontId( fontDescription );
1223   }
1224   else
1225   {
1226     defaultFontId = mFontDefaults->GetFontId( mFontClient );
1227   }
1228
1229   Text::FontMetrics fontMetrics;
1230   mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
1231
1232   return( fontMetrics.ascender - fontMetrics.descender );
1233 }
1234
1235 void Controller::Impl::OnCursorKeyEvent( const Event& event )
1236 {
1237   if( NULL == mEventData || !IsShowingRealText() )
1238   {
1239     // Nothing to do if there is no text input.
1240     return;
1241   }
1242
1243   int keyCode = event.p1.mInt;
1244   bool isShiftModifier = event.p2.mBool;
1245
1246   CharacterIndex previousPrimaryCursorPosition = mEventData->mPrimaryCursorPosition;
1247
1248   if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
1249   {
1250     if( mEventData->mPrimaryCursorPosition > 0u )
1251     {
1252       if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
1253       {
1254         mEventData->mPrimaryCursorPosition = std::min(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
1255       }
1256       else
1257       {
1258         mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
1259       }
1260     }
1261   }
1262   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
1263   {
1264     if( mModel->mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
1265     {
1266       if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
1267       {
1268         mEventData->mPrimaryCursorPosition = std::max(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
1269       }
1270       else
1271       {
1272         mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
1273       }
1274     }
1275   }
1276   else if( Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier )
1277   {
1278     // Ignore Shift-Up for text selection for now.
1279
1280     // Get first the line index of the current cursor position index.
1281     CharacterIndex characterIndex = 0u;
1282
1283     if( mEventData->mPrimaryCursorPosition > 0u )
1284     {
1285       characterIndex = mEventData->mPrimaryCursorPosition - 1u;
1286     }
1287
1288     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
1289     const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex );
1290
1291     // Retrieve the cursor position info.
1292     CursorInfo cursorInfo;
1293     GetCursorPosition( mEventData->mPrimaryCursorPosition,
1294                        cursorInfo );
1295
1296     // Get the line above.
1297     const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + previousLineIndex );
1298
1299     // Get the next hit 'y' point.
1300     const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
1301
1302     // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
1303     bool matchedCharacter = false;
1304     mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1305                                                                       mModel->mLogicalModel,
1306                                                                       mMetrics,
1307                                                                       mEventData->mCursorHookPositionX,
1308                                                                       hitPointY,
1309                                                                       CharacterHitTest::TAP,
1310                                                                       matchedCharacter );
1311   }
1312   else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode && !isShiftModifier )
1313   {
1314     // Ignore Shift-Down for text selection for now.
1315
1316     // Get first the line index of the current cursor position index.
1317     CharacterIndex characterIndex = 0u;
1318
1319     if( mEventData->mPrimaryCursorPosition > 0u )
1320     {
1321       characterIndex = mEventData->mPrimaryCursorPosition - 1u;
1322     }
1323
1324     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
1325
1326     if( lineIndex + 1u < mModel->mVisualModel->mLines.Count() )
1327     {
1328       // Retrieve the cursor position info.
1329       CursorInfo cursorInfo;
1330       GetCursorPosition( mEventData->mPrimaryCursorPosition,
1331                          cursorInfo );
1332
1333       // Get the line below.
1334       const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + lineIndex + 1u );
1335
1336       // Get the next hit 'y' point.
1337       const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
1338
1339       // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
1340       bool matchedCharacter = false;
1341       mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1342                                                                         mModel->mLogicalModel,
1343                                                                         mMetrics,
1344                                                                         mEventData->mCursorHookPositionX,
1345                                                                         hitPointY,
1346                                                                         CharacterHitTest::TAP,
1347                                                                         matchedCharacter );
1348     }
1349   }
1350
1351   if ( !isShiftModifier && mEventData->mState != EventData::SELECTING )
1352   {
1353     // Update selection position after moving the cursor
1354     mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
1355     mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1356   }
1357
1358   if ( isShiftModifier && IsShowingRealText() && mEventData->mShiftSelectionFlag )
1359   {
1360     // Handle text selection
1361     bool selecting = false;
1362
1363     if ( Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
1364     {
1365       // Shift-Left/Right to select the text
1366       int cursorPositionDelta = mEventData->mPrimaryCursorPosition - previousPrimaryCursorPosition;
1367       if ( cursorPositionDelta > 0 || mEventData->mRightSelectionPosition > 0u ) // Check the boundary
1368       {
1369         mEventData->mRightSelectionPosition += cursorPositionDelta;
1370       }
1371       selecting = true;
1372     }
1373     else if ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition )
1374     {
1375       // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
1376       selecting = true;
1377     }
1378
1379     if ( selecting )
1380     {
1381       // Notify the cursor position to the InputMethodContext.
1382       if( mEventData->mInputMethodContext )
1383       {
1384         mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
1385         mEventData->mInputMethodContext.NotifyCursorPosition();
1386       }
1387
1388       ChangeState( EventData::SELECTING );
1389
1390       mEventData->mUpdateLeftSelectionPosition = true;
1391       mEventData->mUpdateRightSelectionPosition = true;
1392       mEventData->mUpdateGrabHandlePosition = true;
1393       mEventData->mUpdateHighlightBox = true;
1394
1395       // Hide the text selection popup if select the text using keyboard instead of moving grab handles
1396       if( mEventData->mGrabHandlePopupEnabled )
1397       {
1398         mEventData->mDecorator->SetPopupActive( false );
1399       }
1400     }
1401   }
1402   else
1403   {
1404     // Handle normal cursor move
1405     ChangeState( EventData::EDITING );
1406     mEventData->mUpdateCursorPosition = true;
1407   }
1408
1409   mEventData->mUpdateInputStyle = true;
1410   mEventData->mScrollAfterUpdatePosition = true;
1411 }
1412
1413 void Controller::Impl::OnTapEvent( const Event& event )
1414 {
1415   if( NULL != mEventData )
1416   {
1417     const unsigned int tapCount = event.p1.mUint;
1418
1419     if( 1u == tapCount )
1420     {
1421       if( IsShowingRealText() )
1422       {
1423         // Convert from control's coords to text's coords.
1424         const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1425         const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1426
1427         // Keep the tap 'x' position. Used to move the cursor.
1428         mEventData->mCursorHookPositionX = xPosition;
1429
1430         // Whether to touch point hits on a glyph.
1431         bool matchedCharacter = false;
1432         mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1433                                                                           mModel->mLogicalModel,
1434                                                                           mMetrics,
1435                                                                           xPosition,
1436                                                                           yPosition,
1437                                                                           CharacterHitTest::TAP,
1438                                                                           matchedCharacter );
1439
1440         // When the cursor position is changing, delay cursor blinking
1441         mEventData->mDecorator->DelayCursorBlink();
1442       }
1443       else
1444       {
1445         mEventData->mPrimaryCursorPosition = 0u;
1446       }
1447
1448       // Update selection position after tapping
1449       mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
1450       mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
1451
1452       mEventData->mUpdateCursorPosition = true;
1453       mEventData->mUpdateGrabHandlePosition = true;
1454       mEventData->mScrollAfterUpdatePosition = true;
1455       mEventData->mUpdateInputStyle = true;
1456
1457       // Notify the cursor position to the InputMethodContext.
1458       if( mEventData->mInputMethodContext )
1459       {
1460         mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
1461         mEventData->mInputMethodContext.NotifyCursorPosition();
1462       }
1463     }
1464     else if( 2u == tapCount )
1465     {
1466       if( mEventData->mSelectionEnabled )
1467       {
1468         // Convert from control's coords to text's coords.
1469         const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1470         const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1471
1472         // Calculates the logical position from the x,y coords.
1473         RepositionSelectionHandles( xPosition,
1474                                     yPosition,
1475                                     mEventData->mDoubleTapAction );
1476       }
1477     }
1478   }
1479 }
1480
1481 void Controller::Impl::OnPanEvent( const Event& event )
1482 {
1483   if( NULL == mEventData )
1484   {
1485     // Nothing to do if there is no text input.
1486     return;
1487   }
1488
1489   const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
1490   const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
1491
1492   if( !isHorizontalScrollEnabled && !isVerticalScrollEnabled )
1493   {
1494     // Nothing to do if scrolling is not enabled.
1495     return;
1496   }
1497
1498   const int state = event.p1.mInt;
1499
1500   switch( state )
1501   {
1502     case Gesture::Started:
1503     {
1504       // Will remove the cursor, handles or text's popup, ...
1505       ChangeState( EventData::TEXT_PANNING );
1506       break;
1507     }
1508     case Gesture::Continuing:
1509     {
1510       const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1511       const Vector2 currentScroll = mModel->mScrollPosition;
1512
1513       if( isHorizontalScrollEnabled )
1514       {
1515         const float displacementX = event.p2.mFloat;
1516         mModel->mScrollPosition.x += displacementX;
1517
1518         ClampHorizontalScroll( layoutSize );
1519       }
1520
1521       if( isVerticalScrollEnabled )
1522       {
1523         const float displacementY = event.p3.mFloat;
1524         mModel->mScrollPosition.y += displacementY;
1525
1526         ClampVerticalScroll( layoutSize );
1527       }
1528
1529       mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
1530       break;
1531     }
1532     case Gesture::Finished:
1533     case Gesture::Cancelled: // FALLTHROUGH
1534     {
1535       // Will go back to the previous state to show the cursor, handles, the text's popup, ...
1536       ChangeState( mEventData->mPreviousState );
1537       break;
1538     }
1539     default:
1540       break;
1541   }
1542 }
1543
1544 void Controller::Impl::OnLongPressEvent( const Event& event )
1545 {
1546   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
1547
1548   if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
1549   {
1550     ChangeState( EventData::EDITING_WITH_POPUP );
1551     mEventData->mDecoratorUpdated = true;
1552     mEventData->mUpdateInputStyle = true;
1553   }
1554   else
1555   {
1556     if( mEventData->mSelectionEnabled )
1557     {
1558       // Convert from control's coords to text's coords.
1559       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1560       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1561
1562       // Calculates the logical position from the x,y coords.
1563       RepositionSelectionHandles( xPosition,
1564                                   yPosition,
1565                                   mEventData->mLongPressAction );
1566     }
1567   }
1568 }
1569
1570 void Controller::Impl::OnHandleEvent( const Event& event )
1571 {
1572   if( NULL == mEventData )
1573   {
1574     // Nothing to do if there is no text input.
1575     return;
1576   }
1577
1578   const unsigned int state = event.p1.mUint;
1579   const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
1580   const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
1581
1582   if( HANDLE_PRESSED == state )
1583   {
1584     // Convert from decorator's coords to text's coords.
1585     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1586     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1587
1588     // Need to calculate the handle's new position.
1589     bool matchedCharacter = false;
1590     const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1591                                                                           mModel->mLogicalModel,
1592                                                                           mMetrics,
1593                                                                           xPosition,
1594                                                                           yPosition,
1595                                                                           CharacterHitTest::SCROLL,
1596                                                                           matchedCharacter );
1597
1598     if( Event::GRAB_HANDLE_EVENT == event.type )
1599     {
1600       ChangeState ( EventData::GRAB_HANDLE_PANNING );
1601
1602       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
1603       {
1604         // Updates the cursor position if the handle's new position is different than the current one.
1605         mEventData->mUpdateCursorPosition = true;
1606         // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
1607         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1608         mEventData->mPrimaryCursorPosition = handleNewPosition;
1609       }
1610
1611       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1612       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1613     }
1614     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1615     {
1616       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1617
1618       if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
1619           ( handleNewPosition != mEventData->mRightSelectionPosition ) )
1620       {
1621         // Updates the highlight box if the handle's new position is different than the current one.
1622         mEventData->mUpdateHighlightBox = true;
1623         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1624         mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1625         mEventData->mLeftSelectionPosition = handleNewPosition;
1626       }
1627
1628       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1629       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1630
1631       // Will define the order to scroll the text to match the handle position.
1632       mEventData->mIsLeftHandleSelected = true;
1633       mEventData->mIsRightHandleSelected = false;
1634     }
1635     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1636     {
1637       ChangeState ( EventData::SELECTION_HANDLE_PANNING );
1638
1639       if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
1640           ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
1641       {
1642         // Updates the highlight box if the handle's new position is different than the current one.
1643         mEventData->mUpdateHighlightBox = true;
1644         // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
1645         mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1646         mEventData->mRightSelectionPosition = handleNewPosition;
1647       }
1648
1649       // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
1650       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1651
1652       // Will define the order to scroll the text to match the handle position.
1653       mEventData->mIsLeftHandleSelected = false;
1654       mEventData->mIsRightHandleSelected = true;
1655     }
1656   } // end ( HANDLE_PRESSED == state )
1657   else if( ( HANDLE_RELEASED == state ) ||
1658            handleStopScrolling )
1659   {
1660     CharacterIndex handlePosition = 0u;
1661     if( handleStopScrolling || isSmoothHandlePanEnabled )
1662     {
1663       // Convert from decorator's coords to text's coords.
1664       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1665       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1666
1667       bool matchedCharacter = false;
1668       handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1669                                                     mModel->mLogicalModel,
1670                                                     mMetrics,
1671                                                     xPosition,
1672                                                     yPosition,
1673                                                     CharacterHitTest::SCROLL,
1674                                                     matchedCharacter );
1675     }
1676
1677     if( Event::GRAB_HANDLE_EVENT == event.type )
1678     {
1679       mEventData->mUpdateCursorPosition = true;
1680       mEventData->mUpdateGrabHandlePosition = true;
1681       mEventData->mUpdateInputStyle = true;
1682
1683       if( !IsClipboardEmpty() )
1684       {
1685         ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
1686       }
1687
1688       if( handleStopScrolling || isSmoothHandlePanEnabled )
1689       {
1690         mEventData->mScrollAfterUpdatePosition = true;
1691         mEventData->mPrimaryCursorPosition = handlePosition;
1692       }
1693     }
1694     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
1695     {
1696       ChangeState( EventData::SELECTING );
1697
1698       mEventData->mUpdateHighlightBox = true;
1699       mEventData->mUpdateLeftSelectionPosition = true;
1700       mEventData->mUpdateRightSelectionPosition = true;
1701
1702       if( handleStopScrolling || isSmoothHandlePanEnabled )
1703       {
1704         mEventData->mScrollAfterUpdatePosition = true;
1705
1706         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1707             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1708         {
1709           mEventData->mLeftSelectionPosition = handlePosition;
1710         }
1711       }
1712     }
1713     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
1714     {
1715       ChangeState( EventData::SELECTING );
1716
1717       mEventData->mUpdateHighlightBox = true;
1718       mEventData->mUpdateRightSelectionPosition = true;
1719       mEventData->mUpdateLeftSelectionPosition = true;
1720
1721       if( handleStopScrolling || isSmoothHandlePanEnabled )
1722       {
1723         mEventData->mScrollAfterUpdatePosition = true;
1724         if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
1725             ( handlePosition != mEventData->mLeftSelectionPosition ) )
1726         {
1727           mEventData->mRightSelectionPosition = handlePosition;
1728         }
1729       }
1730     }
1731
1732     mEventData->mDecoratorUpdated = true;
1733   } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
1734   else if( HANDLE_SCROLLING == state )
1735   {
1736     const float xSpeed = event.p2.mFloat;
1737     const float ySpeed = event.p3.mFloat;
1738     const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
1739     const Vector2 currentScrollPosition = mModel->mScrollPosition;
1740
1741     mModel->mScrollPosition.x += xSpeed;
1742     mModel->mScrollPosition.y += ySpeed;
1743
1744     ClampHorizontalScroll( layoutSize );
1745     ClampVerticalScroll( layoutSize );
1746
1747     bool endOfScroll = false;
1748     if( Vector2::ZERO == ( currentScrollPosition - mModel->mScrollPosition ) )
1749     {
1750       // Notify the decorator there is no more text to scroll.
1751       // The decorator won't send more scroll events.
1752       mEventData->mDecorator->NotifyEndOfScroll();
1753       // Still need to set the position of the handle.
1754       endOfScroll = true;
1755     }
1756
1757     // Set the position of the handle.
1758     const bool scrollRightDirection = xSpeed > 0.f;
1759     const bool scrollBottomDirection = ySpeed > 0.f;
1760     const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
1761     const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
1762
1763     if( Event::GRAB_HANDLE_EVENT == event.type )
1764     {
1765       ChangeState( EventData::GRAB_HANDLE_PANNING );
1766
1767       // Get the grab handle position in decorator coords.
1768       Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
1769
1770       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1771       {
1772         // Position the grag handle close to either the left or right edge.
1773         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1774       }
1775
1776       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1777       {
1778         position.x = mEventData->mCursorHookPositionX;
1779
1780         // Position the grag handle close to either the top or bottom edge.
1781         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1782       }
1783
1784       // Get the new handle position.
1785       // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
1786       bool matchedCharacter = false;
1787       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1788                                                                          mModel->mLogicalModel,
1789                                                                          mMetrics,
1790                                                                          position.x - mModel->mScrollPosition.x,
1791                                                                          position.y - mModel->mScrollPosition.y,
1792                                                                          CharacterHitTest::SCROLL,
1793                                                                          matchedCharacter );
1794
1795       if( mEventData->mPrimaryCursorPosition != handlePosition )
1796       {
1797         mEventData->mUpdateCursorPosition = true;
1798         mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
1799         mEventData->mScrollAfterUpdatePosition = true;
1800         mEventData->mPrimaryCursorPosition = handlePosition;
1801       }
1802       mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
1803
1804       // Updates the decorator if the soft handle panning is enabled.
1805       mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
1806     }
1807     else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
1808     {
1809       ChangeState( EventData::SELECTION_HANDLE_PANNING );
1810
1811       // Get the selection handle position in decorator coords.
1812       Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
1813
1814       if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
1815       {
1816         // Position the selection handle close to either the left or right edge.
1817         position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
1818       }
1819
1820       if( mEventData->mDecorator->IsVerticalScrollEnabled() )
1821       {
1822         position.x = mEventData->mCursorHookPositionX;
1823
1824         // Position the grag handle close to either the top or bottom edge.
1825         position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
1826       }
1827
1828       // Get the new handle position.
1829       // The selection handle's position is in decorator's coords. Need to transform to text's coords.
1830       bool matchedCharacter = false;
1831       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
1832                                                                          mModel->mLogicalModel,
1833                                                                          mMetrics,
1834                                                                          position.x - mModel->mScrollPosition.x,
1835                                                                          position.y - mModel->mScrollPosition.y,
1836                                                                          CharacterHitTest::SCROLL,
1837                                                                          matchedCharacter );
1838
1839       if( leftSelectionHandleEvent )
1840       {
1841         const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
1842
1843         if( differentHandles || endOfScroll )
1844         {
1845           mEventData->mUpdateHighlightBox = true;
1846           mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
1847           mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
1848           mEventData->mLeftSelectionPosition = handlePosition;
1849         }
1850       }
1851       else
1852       {
1853         const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
1854         if( differentHandles || endOfScroll )
1855         {
1856           mEventData->mUpdateHighlightBox = true;
1857           mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
1858           mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
1859           mEventData->mRightSelectionPosition = handlePosition;
1860         }
1861       }
1862
1863       if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
1864       {
1865         RepositionSelectionHandles();
1866
1867         mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
1868       }
1869     }
1870     mEventData->mDecoratorUpdated = true;
1871   } // end ( HANDLE_SCROLLING == state )
1872 }
1873
1874 void Controller::Impl::OnSelectEvent( const Event& event )
1875 {
1876   if( NULL == mEventData )
1877   {
1878     // Nothing to do if there is no text.
1879     return;
1880   }
1881
1882   if( mEventData->mSelectionEnabled )
1883   {
1884     // Convert from control's coords to text's coords.
1885     const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
1886     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
1887
1888     // Calculates the logical position from the x,y coords.
1889     RepositionSelectionHandles( xPosition,
1890                                 yPosition,
1891                                 Controller::NoTextTap::HIGHLIGHT );
1892   }
1893 }
1894
1895 void Controller::Impl::OnSelectAllEvent()
1896 {
1897   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
1898
1899   if( NULL == mEventData )
1900   {
1901     // Nothing to do if there is no text.
1902     return;
1903   }
1904
1905   if( mEventData->mSelectionEnabled )
1906   {
1907     // Calculates the logical position from the start.
1908     RepositionSelectionHandles( 0.f - mModel->mScrollPosition.x,
1909                                 0.f - mModel->mScrollPosition.y,
1910                                 Controller::NoTextTap::HIGHLIGHT );
1911
1912     mEventData->mLeftSelectionPosition = 0u;
1913     mEventData->mRightSelectionPosition = mModel->mLogicalModel->mText.Count();
1914   }
1915 }
1916
1917 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
1918 {
1919   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
1920   {
1921     // Nothing to select if handles are in the same place.
1922     selectedText.clear();
1923     return;
1924   }
1925
1926   const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
1927
1928   //Get start and end position of selection
1929   const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1930   const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
1931
1932   Vector<Character>& utf32Characters = mModel->mLogicalModel->mText;
1933   const Length numberOfCharacters = utf32Characters.Count();
1934
1935   // Validate the start and end selection points
1936   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
1937   {
1938     //Get text as a UTF8 string
1939     Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
1940
1941     if( deleteAfterRetrieval ) // Only delete text if copied successfully
1942     {
1943       // Keep a copy of the current input style.
1944       InputStyle currentInputStyle;
1945       currentInputStyle.Copy( mEventData->mInputStyle );
1946
1947       // Set as input style the style of the first deleted character.
1948       mModel->mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
1949
1950       // Compare if the input style has changed.
1951       const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
1952
1953       if( hasInputStyleChanged )
1954       {
1955         const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
1956         // Queue the input style changed signal.
1957         mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
1958       }
1959
1960       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
1961
1962       // Mark the paragraphs to be updated.
1963       if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
1964       {
1965         mTextUpdateInfo.mCharacterIndex = 0;
1966         mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
1967         mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
1968         mTextUpdateInfo.mClearAll = true;
1969       }
1970       else
1971       {
1972         mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1973         mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1974       }
1975
1976       // Delete text between handles
1977       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
1978       Vector<Character>::Iterator last  = first + lengthOfSelectedText;
1979       utf32Characters.Erase( first, last );
1980
1981       // Will show the cursor at the first character of the selection.
1982       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
1983     }
1984     else
1985     {
1986       // Will show the cursor at the last character of the selection.
1987       mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
1988     }
1989
1990     mEventData->mDecoratorUpdated = true;
1991   }
1992 }
1993
1994 void Controller::Impl::ShowClipboard()
1995 {
1996   if( mClipboard )
1997   {
1998     mClipboard.ShowClipboard();
1999   }
2000 }
2001
2002 void Controller::Impl::HideClipboard()
2003 {
2004   if( mClipboard && mClipboardHideEnabled )
2005   {
2006     mClipboard.HideClipboard();
2007   }
2008 }
2009
2010 void Controller::Impl::SetClipboardHideEnable(bool enable)
2011 {
2012   mClipboardHideEnabled = enable;
2013 }
2014
2015 bool Controller::Impl::CopyStringToClipboard( std::string& source )
2016 {
2017   //Send string to clipboard
2018   return ( mClipboard && mClipboard.SetItem( source ) );
2019 }
2020
2021 void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
2022 {
2023   std::string selectedText;
2024   RetrieveSelection( selectedText, deleteAfterSending );
2025   CopyStringToClipboard( selectedText );
2026   ChangeState( EventData::EDITING );
2027 }
2028
2029 void Controller::Impl::RequestGetTextFromClipboard()
2030 {
2031   if ( mClipboard )
2032   {
2033     mClipboard.RequestItem();
2034   }
2035 }
2036
2037 void Controller::Impl::RepositionSelectionHandles()
2038 {
2039   CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
2040   CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
2041
2042   if( selectionStart == selectionEnd )
2043   {
2044     // Nothing to select if handles are in the same place.
2045     // So, deactive Highlight box.
2046     mEventData->mDecorator->SetHighlightActive( false );
2047     return;
2048   }
2049
2050   mEventData->mDecorator->ClearHighlights();
2051
2052   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
2053   const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
2054   const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
2055   const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
2056   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
2057   const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
2058   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
2059
2060   const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
2061   const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
2062   const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
2063
2064   // Swap the indices if the start is greater than the end.
2065   const bool indicesSwapped = selectionStart > selectionEnd;
2066
2067   // Tell the decorator to flip the selection handles if needed.
2068   mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
2069
2070   if( indicesSwapped )
2071   {
2072     std::swap( selectionStart, selectionEnd );
2073   }
2074
2075   // Get the indices to the first and last selected glyphs.
2076   const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
2077   const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
2078   const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
2079   const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
2080
2081   // Get the lines where the glyphs are laid-out.
2082   const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
2083
2084   LineIndex lineIndex = 0u;
2085   Length numberOfLines = 0u;
2086   mModel->mVisualModel->GetNumberOfLines( glyphStart,
2087                                           1u + glyphEnd - glyphStart,
2088                                           lineIndex,
2089                                           numberOfLines );
2090   const LineIndex firstLineIndex = lineIndex;
2091
2092   // Create the structure to store some selection box info.
2093   Vector<SelectionBoxInfo> selectionBoxLinesInfo;
2094   selectionBoxLinesInfo.Resize( numberOfLines );
2095
2096   SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
2097   selectionBoxInfo->minX = MAX_FLOAT;
2098   selectionBoxInfo->maxX = MIN_FLOAT;
2099
2100   // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
2101   float minHighlightX = std::numeric_limits<float>::max();
2102   float maxHighlightX = std::numeric_limits<float>::min();
2103   Size highLightSize;
2104   Vector2 highLightPosition; // The highlight position in decorator's coords.
2105
2106   // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
2107
2108   // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
2109   selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
2110                                                       firstLineIndex );
2111
2112   // Transform to decorator's (control) coords.
2113   selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
2114
2115   lineRun += firstLineIndex;
2116
2117   // The line height is the addition of the line ascender and the line descender.
2118   // However, the line descender has a negative value, hence the subtraction.
2119   selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
2120
2121   GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
2122
2123   // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
2124   const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
2125   bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionStart ) );
2126
2127   // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ï»», etc which needs special code.
2128   const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
2129   bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
2130
2131   // The number of quads of the selection box.
2132   const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
2133   mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
2134
2135   // Count the actual number of quads.
2136   unsigned int actualNumberOfQuads = 0u;
2137   Vector4 quad;
2138
2139   // Traverse the glyphs.
2140   for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
2141   {
2142     const GlyphInfo& glyph = *( glyphsBuffer + index );
2143     const Vector2& position = *( positionsBuffer + index );
2144
2145     if( splitStartGlyph )
2146     {
2147       // If the first glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
2148
2149       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
2150       const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
2151       // Get the direction of the character.
2152       CharacterDirection isCurrentRightToLeft = false;
2153       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
2154       {
2155         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
2156       }
2157
2158       // The end point could be in the middle of the ligature.
2159       // Calculate the number of characters selected.
2160       const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
2161
2162       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
2163       quad.y = selectionBoxInfo->lineOffset;
2164       quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
2165       quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
2166
2167       // Store the min and max 'x' for each line.
2168       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2169       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2170
2171       mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
2172       ++actualNumberOfQuads;
2173
2174       splitStartGlyph = false;
2175       continue;
2176     }
2177
2178     if( splitEndGlyph && ( index == glyphEnd ) )
2179     {
2180       // Equally, if the last glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
2181
2182       const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
2183       const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
2184       // Get the direction of the character.
2185       CharacterDirection isCurrentRightToLeft = false;
2186       if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
2187       {
2188         isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
2189       }
2190
2191       const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
2192
2193       quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
2194       quad.y = selectionBoxInfo->lineOffset;
2195       quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
2196       quad.w = quad.y + selectionBoxInfo->lineHeight;
2197
2198       // Store the min and max 'x' for each line.
2199       selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2200       selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2201
2202       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2203                                             quad );
2204       ++actualNumberOfQuads;
2205
2206       splitEndGlyph = false;
2207       continue;
2208     }
2209
2210     quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
2211     quad.y = selectionBoxInfo->lineOffset;
2212     quad.z = quad.x + glyph.advance;
2213     quad.w = quad.y + selectionBoxInfo->lineHeight;
2214
2215     // Store the min and max 'x' for each line.
2216     selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
2217     selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
2218
2219     mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2220                                           quad );
2221     ++actualNumberOfQuads;
2222
2223     // Whether to retrieve the next line.
2224     if( index == lastGlyphOfLine )
2225     {
2226       ++lineIndex;
2227       if( lineIndex < firstLineIndex + numberOfLines )
2228       {
2229         // Retrieve the next line.
2230         ++lineRun;
2231
2232         // Get the last glyph of the new line.
2233         lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
2234
2235         // Keep the offset and height of the current selection box.
2236         const float currentLineOffset = selectionBoxInfo->lineOffset;
2237         const float currentLineHeight = selectionBoxInfo->lineHeight;
2238
2239         // Get the selection box info for the next line.
2240         ++selectionBoxInfo;
2241
2242         selectionBoxInfo->minX = MAX_FLOAT;
2243         selectionBoxInfo->maxX = MIN_FLOAT;
2244
2245         // Update the line's vertical offset.
2246         selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
2247
2248         // The line height is the addition of the line ascender and the line descender.
2249         // However, the line descender has a negative value, hence the subtraction.
2250         selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
2251       }
2252     }
2253   }
2254
2255   // Traverses all the lines and updates the min and max 'x' positions and the total height.
2256   // The final width is calculated after 'boxifying' the selection.
2257   for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
2258          endIt = selectionBoxLinesInfo.End();
2259        it != endIt;
2260        ++it )
2261   {
2262     const SelectionBoxInfo& info = *it;
2263
2264     // Update the size of the highlighted text.
2265     highLightSize.height += info.lineHeight;
2266     minHighlightX = std::min( minHighlightX, info.minX );
2267     maxHighlightX = std::max( maxHighlightX, info.maxX );
2268   }
2269
2270   // Add extra geometry to 'boxify' the selection.
2271
2272   if( 1u < numberOfLines )
2273   {
2274     // Boxify the first line.
2275     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
2276     const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2277
2278     bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
2279     bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
2280
2281     if( boxifyBegin )
2282     {
2283       quad.x = 0.f;
2284       quad.y = firstSelectionBoxLineInfo.lineOffset;
2285       quad.z = firstSelectionBoxLineInfo.minX;
2286       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2287
2288       // Boxify at the beginning of the line.
2289       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2290                                             quad );
2291       ++actualNumberOfQuads;
2292
2293       // Update the size of the highlighted text.
2294       minHighlightX = 0.f;
2295     }
2296
2297     if( boxifyEnd )
2298     {
2299       quad.x = firstSelectionBoxLineInfo.maxX;
2300       quad.y = firstSelectionBoxLineInfo.lineOffset;
2301       quad.z = mModel->mVisualModel->mControlSize.width;
2302       quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
2303
2304       // Boxify at the end of the line.
2305       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2306                                             quad );
2307       ++actualNumberOfQuads;
2308
2309       // Update the size of the highlighted text.
2310       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2311     }
2312
2313     // Boxify the central lines.
2314     if( 2u < numberOfLines )
2315     {
2316       for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
2317              endIt = selectionBoxLinesInfo.End() - 1u;
2318            it != endIt;
2319            ++it )
2320       {
2321         const SelectionBoxInfo& info = *it;
2322
2323         quad.x = 0.f;
2324         quad.y = info.lineOffset;
2325         quad.z = info.minX;
2326         quad.w = info.lineOffset + info.lineHeight;
2327
2328         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2329                                               quad );
2330         ++actualNumberOfQuads;
2331
2332         quad.x = info.maxX;
2333         quad.y = info.lineOffset;
2334         quad.z = mModel->mVisualModel->mControlSize.width;
2335         quad.w = info.lineOffset + info.lineHeight;
2336
2337         mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2338                                               quad );
2339         ++actualNumberOfQuads;
2340       }
2341
2342       // Update the size of the highlighted text.
2343       minHighlightX = 0.f;
2344       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2345     }
2346
2347     // Boxify the last line.
2348     lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
2349     const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
2350
2351     boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
2352     boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
2353
2354     if( boxifyBegin )
2355     {
2356       quad.x = 0.f;
2357       quad.y = lastSelectionBoxLineInfo.lineOffset;
2358       quad.z = lastSelectionBoxLineInfo.minX;
2359       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2360
2361       // Boxify at the beginning of the line.
2362       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2363                                             quad );
2364       ++actualNumberOfQuads;
2365
2366       // Update the size of the highlighted text.
2367       minHighlightX = 0.f;
2368     }
2369
2370     if( boxifyEnd )
2371     {
2372       quad.x = lastSelectionBoxLineInfo.maxX;
2373       quad.y = lastSelectionBoxLineInfo.lineOffset;
2374       quad.z = mModel->mVisualModel->mControlSize.width;
2375       quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
2376
2377       // Boxify at the end of the line.
2378       mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
2379                                             quad );
2380       ++actualNumberOfQuads;
2381
2382       // Update the size of the highlighted text.
2383       maxHighlightX = mModel->mVisualModel->mControlSize.width;
2384     }
2385   }
2386
2387   // Set the actual number of quads.
2388   mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
2389
2390   // Sets the highlight's size and position. In decorator's coords.
2391   // The highlight's height has been calculated above (before 'boxifying' the highlight).
2392   highLightSize.width = maxHighlightX - minHighlightX;
2393
2394   highLightPosition.x = minHighlightX;
2395   const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
2396   highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
2397
2398   mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
2399
2400   if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
2401   {
2402     CursorInfo primaryCursorInfo;
2403     GetCursorPosition( mEventData->mLeftSelectionPosition,
2404                        primaryCursorInfo );
2405
2406     const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2407
2408     mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
2409                                          primaryPosition.x,
2410                                          primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2411                                          primaryCursorInfo.lineHeight );
2412
2413     CursorInfo secondaryCursorInfo;
2414     GetCursorPosition( mEventData->mRightSelectionPosition,
2415                        secondaryCursorInfo );
2416
2417     const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
2418
2419     mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
2420                                          secondaryPosition.x,
2421                                          secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
2422                                          secondaryCursorInfo.lineHeight );
2423   }
2424
2425   // Set the flag to update the decorator.
2426   mEventData->mDecoratorUpdated = true;
2427 }
2428
2429 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
2430 {
2431   if( NULL == mEventData )
2432   {
2433     // Nothing to do if there is no text input.
2434     return;
2435   }
2436
2437   if( IsShowingPlaceholderText() )
2438   {
2439     // Nothing to do if there is the place-holder text.
2440     return;
2441   }
2442
2443   const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
2444   const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
2445   if( ( 0 == numberOfGlyphs ) ||
2446       ( 0 == numberOfLines ) )
2447   {
2448     // Nothing to do if there is no text.
2449     return;
2450   }
2451
2452   // Find which word was selected
2453   CharacterIndex selectionStart( 0 );
2454   CharacterIndex selectionEnd( 0 );
2455   CharacterIndex noTextHitIndex( 0 );
2456   const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
2457                                                   mModel->mLogicalModel,
2458                                                   mMetrics,
2459                                                   visualX,
2460                                                   visualY,
2461                                                   selectionStart,
2462                                                   selectionEnd,
2463                                                   noTextHitIndex );
2464   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
2465
2466   if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
2467   {
2468     ChangeState( EventData::SELECTING );
2469
2470     mEventData->mLeftSelectionPosition = selectionStart;
2471     mEventData->mRightSelectionPosition = selectionEnd;
2472
2473     mEventData->mUpdateLeftSelectionPosition = true;
2474     mEventData->mUpdateRightSelectionPosition = true;
2475     mEventData->mUpdateHighlightBox = true;
2476
2477     // It may happen an InputMethodContext commit event arrives before the selection event
2478     // if the InputMethodContext is in pre-edit state. The commit event will set the
2479     // mEventData->mUpdateCursorPosition flag to true. If it's not set back
2480     // to false, the highlight box won't be updated.
2481     mEventData->mUpdateCursorPosition = false;
2482
2483     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
2484
2485     // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
2486     mEventData->mPrimaryCursorPosition = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
2487   }
2488   else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
2489   {
2490     // Nothing to select. i.e. a white space, out of bounds
2491     ChangeState( EventData::EDITING_WITH_POPUP );
2492
2493     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2494
2495     mEventData->mUpdateCursorPosition = true;
2496     mEventData->mUpdateGrabHandlePosition = true;
2497     mEventData->mScrollAfterUpdatePosition = true;
2498     mEventData->mUpdateInputStyle = true;
2499   }
2500   else if( Controller::NoTextTap::NO_ACTION == action )
2501   {
2502     // Nothing to select. i.e. a white space, out of bounds
2503     mEventData->mPrimaryCursorPosition = noTextHitIndex;
2504
2505     mEventData->mUpdateCursorPosition = true;
2506     mEventData->mUpdateGrabHandlePosition = true;
2507     mEventData->mScrollAfterUpdatePosition = true;
2508     mEventData->mUpdateInputStyle = true;
2509   }
2510 }
2511
2512 void Controller::Impl::SetPopupButtons()
2513 {
2514   /**
2515    *  Sets the Popup buttons to be shown depending on State.
2516    *
2517    *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
2518    *
2519    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
2520    */
2521
2522   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
2523
2524   if( EventData::SELECTING == mEventData->mState )
2525   {
2526     buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
2527
2528     if( !IsClipboardEmpty() )
2529     {
2530       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2531       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2532     }
2533
2534     if( !mEventData->mAllTextSelected )
2535     {
2536       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
2537     }
2538   }
2539   else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
2540   {
2541     if( mModel->mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
2542     {
2543       buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
2544     }
2545
2546     if( !IsClipboardEmpty() )
2547     {
2548       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2549       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2550     }
2551   }
2552   else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
2553   {
2554     if ( !IsClipboardEmpty() )
2555     {
2556       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
2557       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
2558     }
2559   }
2560
2561   mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
2562 }
2563
2564 void Controller::Impl::ChangeState( EventData::State newState )
2565 {
2566   if( NULL == mEventData )
2567   {
2568     // Nothing to do if there is no text input.
2569     return;
2570   }
2571
2572   DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
2573
2574   if( mEventData->mState != newState )
2575   {
2576     mEventData->mPreviousState = mEventData->mState;
2577     mEventData->mState = newState;
2578
2579     switch( mEventData->mState )
2580     {
2581       case EventData::INACTIVE:
2582       {
2583         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2584         mEventData->mDecorator->StopCursorBlink();
2585         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2586         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2587         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2588         mEventData->mDecorator->SetHighlightActive( false );
2589         mEventData->mDecorator->SetPopupActive( false );
2590         mEventData->mDecoratorUpdated = true;
2591         break;
2592       }
2593       case EventData::INTERRUPTED:
2594       {
2595         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2596         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2597         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2598         mEventData->mDecorator->SetHighlightActive( false );
2599         mEventData->mDecorator->SetPopupActive( false );
2600         mEventData->mDecoratorUpdated = true;
2601         break;
2602       }
2603       case EventData::SELECTING:
2604       {
2605         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2606         mEventData->mDecorator->StopCursorBlink();
2607         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2608         if ( mEventData->mGrabHandleEnabled )
2609         {
2610           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2611           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2612         }
2613         mEventData->mDecorator->SetHighlightActive( true );
2614         if( mEventData->mGrabHandlePopupEnabled )
2615         {
2616           SetPopupButtons();
2617           mEventData->mDecorator->SetPopupActive( true );
2618         }
2619         mEventData->mDecoratorUpdated = true;
2620         break;
2621       }
2622       case EventData::EDITING:
2623       {
2624         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2625         if( mEventData->mCursorBlinkEnabled )
2626         {
2627           mEventData->mDecorator->StartCursorBlink();
2628         }
2629         // Grab handle is not shown until a tap is received whilst EDITING
2630         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2631         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2632         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2633         mEventData->mDecorator->SetHighlightActive( false );
2634         if( mEventData->mGrabHandlePopupEnabled )
2635         {
2636           mEventData->mDecorator->SetPopupActive( false );
2637         }
2638         mEventData->mDecoratorUpdated = true;
2639         break;
2640       }
2641       case EventData::EDITING_WITH_POPUP:
2642       {
2643         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
2644
2645         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2646         if( mEventData->mCursorBlinkEnabled )
2647         {
2648           mEventData->mDecorator->StartCursorBlink();
2649         }
2650         if( mEventData->mSelectionEnabled )
2651         {
2652           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2653           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2654           mEventData->mDecorator->SetHighlightActive( false );
2655         }
2656         else if ( mEventData->mGrabHandleEnabled )
2657         {
2658           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2659         }
2660         if( mEventData->mGrabHandlePopupEnabled )
2661         {
2662           SetPopupButtons();
2663           mEventData->mDecorator->SetPopupActive( true );
2664         }
2665         mEventData->mDecoratorUpdated = true;
2666         break;
2667       }
2668       case EventData::EDITING_WITH_GRAB_HANDLE:
2669       {
2670         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
2671
2672         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2673         if( mEventData->mCursorBlinkEnabled )
2674         {
2675           mEventData->mDecorator->StartCursorBlink();
2676         }
2677         // Grab handle is not shown until a tap is received whilst EDITING
2678         if ( mEventData->mGrabHandleEnabled )
2679         {
2680           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2681         }
2682         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2683         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2684         mEventData->mDecorator->SetHighlightActive( false );
2685         if( mEventData->mGrabHandlePopupEnabled )
2686         {
2687           mEventData->mDecorator->SetPopupActive( false );
2688         }
2689         mEventData->mDecoratorUpdated = true;
2690         break;
2691       }
2692       case EventData::SELECTION_HANDLE_PANNING:
2693       {
2694         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2695         mEventData->mDecorator->StopCursorBlink();
2696         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2697         if ( mEventData->mGrabHandleEnabled )
2698         {
2699           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
2700           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
2701         }
2702         mEventData->mDecorator->SetHighlightActive( true );
2703         if( mEventData->mGrabHandlePopupEnabled )
2704         {
2705           mEventData->mDecorator->SetPopupActive( false );
2706         }
2707         mEventData->mDecoratorUpdated = true;
2708         break;
2709       }
2710       case EventData::GRAB_HANDLE_PANNING:
2711       {
2712         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
2713
2714         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2715         if( mEventData->mCursorBlinkEnabled )
2716         {
2717           mEventData->mDecorator->StartCursorBlink();
2718         }
2719         if ( mEventData->mGrabHandleEnabled )
2720         {
2721           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2722         }
2723         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2724         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2725         mEventData->mDecorator->SetHighlightActive( false );
2726         if( mEventData->mGrabHandlePopupEnabled )
2727         {
2728           mEventData->mDecorator->SetPopupActive( false );
2729         }
2730         mEventData->mDecoratorUpdated = true;
2731         break;
2732       }
2733       case EventData::EDITING_WITH_PASTE_POPUP:
2734       {
2735         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
2736
2737         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2738         if( mEventData->mCursorBlinkEnabled )
2739         {
2740           mEventData->mDecorator->StartCursorBlink();
2741         }
2742
2743         if ( mEventData->mGrabHandleEnabled )
2744         {
2745           mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
2746         }
2747         mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2748         mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2749         mEventData->mDecorator->SetHighlightActive( false );
2750
2751         if( mEventData->mGrabHandlePopupEnabled )
2752         {
2753           SetPopupButtons();
2754           mEventData->mDecorator->SetPopupActive( true );
2755         }
2756         mEventData->mDecoratorUpdated = true;
2757         break;
2758       }
2759       case EventData::TEXT_PANNING:
2760       {
2761         mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2762         mEventData->mDecorator->StopCursorBlink();
2763         mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
2764         if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
2765             mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
2766         {
2767           mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
2768           mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
2769           mEventData->mDecorator->SetHighlightActive( true );
2770         }
2771
2772         if( mEventData->mGrabHandlePopupEnabled )
2773         {
2774           mEventData->mDecorator->SetPopupActive( false );
2775         }
2776
2777         mEventData->mDecoratorUpdated = true;
2778         break;
2779       }
2780     }
2781   }
2782 }
2783
2784 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
2785                                           CursorInfo& cursorInfo )
2786 {
2787   if( !IsShowingRealText() )
2788   {
2789     // Do not want to use the place-holder text to set the cursor position.
2790
2791     // Use the line's height of the font's family set to set the cursor's size.
2792     // If there is no font's family set, use the default font.
2793     // Use the current alignment to place the cursor at the beginning, center or end of the box.
2794
2795     cursorInfo.lineOffset = 0.f;
2796     cursorInfo.lineHeight = GetDefaultFontLineHeight();
2797     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
2798
2799     bool isRTL = false;
2800     if( mModel->mMatchSystemLanguageDirection )
2801     {
2802       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
2803     }
2804
2805     switch( mModel->mHorizontalAlignment )
2806     {
2807       case Text::HorizontalAlignment::BEGIN :
2808       {
2809         if( isRTL )
2810         {
2811           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2812         }
2813         else
2814         {
2815           cursorInfo.primaryPosition.x = 0.f;
2816         }
2817         break;
2818       }
2819       case Text::HorizontalAlignment::CENTER:
2820       {
2821         cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
2822         break;
2823       }
2824       case Text::HorizontalAlignment::END:
2825       {
2826         if( isRTL )
2827         {
2828           cursorInfo.primaryPosition.x = 0.f;
2829         }
2830         else
2831         {
2832           cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
2833         }
2834         break;
2835       }
2836     }
2837
2838     // Nothing else to do.
2839     return;
2840   }
2841
2842   const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
2843   GetCursorPositionParameters parameters;
2844   parameters.visualModel = mModel->mVisualModel;
2845   parameters.logicalModel = mModel->mLogicalModel;
2846   parameters.metrics = mMetrics;
2847   parameters.logical = logical;
2848   parameters.isMultiline = isMultiLine;
2849
2850   Text::GetCursorPosition( parameters,
2851                            cursorInfo );
2852
2853   // Adds Outline offset.
2854   const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
2855   cursorInfo.primaryPosition.x += outlineWidth;
2856   cursorInfo.primaryPosition.y += outlineWidth;
2857   cursorInfo.secondaryPosition.x += outlineWidth;
2858   cursorInfo.secondaryPosition.y += outlineWidth;
2859
2860   if( isMultiLine )
2861   {
2862     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
2863
2864     // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
2865     // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
2866
2867     if( 0.f > cursorInfo.primaryPosition.x )
2868     {
2869       cursorInfo.primaryPosition.x = 0.f;
2870     }
2871
2872     const float edgeWidth = mModel->mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
2873     if( cursorInfo.primaryPosition.x > edgeWidth )
2874     {
2875       cursorInfo.primaryPosition.x = edgeWidth;
2876     }
2877   }
2878 }
2879
2880 CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index ) const
2881 {
2882   if( NULL == mEventData )
2883   {
2884     // Nothing to do if there is no text input.
2885     return 0u;
2886   }
2887
2888   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
2889
2890   const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
2891   const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
2892
2893   GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
2894   Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2895
2896   if( numberOfCharacters > 1u )
2897   {
2898     const Script script = mModel->mLogicalModel->GetScript( index );
2899     if( HasLigatureMustBreak( script ) )
2900     {
2901       // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ï»», ...
2902       numberOfCharacters = 1u;
2903     }
2904   }
2905   else
2906   {
2907     while( 0u == numberOfCharacters )
2908     {
2909       ++glyphIndex;
2910       numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
2911     }
2912   }
2913
2914   if( index < mEventData->mPrimaryCursorPosition )
2915   {
2916     cursorIndex -= numberOfCharacters;
2917   }
2918   else
2919   {
2920     cursorIndex += numberOfCharacters;
2921   }
2922
2923   // Will update the cursor hook position.
2924   mEventData->mUpdateCursorHookPosition = true;
2925
2926   return cursorIndex;
2927 }
2928
2929 void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
2930 {
2931   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
2932   if( NULL == mEventData )
2933   {
2934     // Nothing to do if there is no text input.
2935     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition no event data\n" );
2936     return;
2937   }
2938
2939   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
2940
2941   mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
2942
2943   // Sets the cursor position.
2944   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
2945                                        cursorPosition.x,
2946                                        cursorPosition.y,
2947                                        cursorInfo.primaryCursorHeight,
2948                                        cursorInfo.lineHeight );
2949   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
2950
2951   if( mEventData->mUpdateGrabHandlePosition )
2952   {
2953     // Sets the grab handle position.
2954     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
2955                                          cursorPosition.x,
2956                                          cursorInfo.lineOffset + mModel->mScrollPosition.y,
2957                                          cursorInfo.lineHeight );
2958   }
2959
2960   if( cursorInfo.isSecondaryCursor )
2961   {
2962     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
2963                                          cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x,
2964                                          cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y,
2965                                          cursorInfo.secondaryCursorHeight,
2966                                          cursorInfo.lineHeight );
2967     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mModel->mScrollPosition.x, cursorInfo.secondaryPosition.y + mModel->mScrollPosition.y );
2968   }
2969
2970   // Set which cursors are active according the state.
2971   if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
2972   {
2973     if( cursorInfo.isSecondaryCursor )
2974     {
2975       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
2976     }
2977     else
2978     {
2979       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
2980     }
2981   }
2982   else
2983   {
2984     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
2985   }
2986
2987   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
2988 }
2989
2990 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
2991                                               const CursorInfo& cursorInfo )
2992 {
2993   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
2994       ( RIGHT_SELECTION_HANDLE != handleType ) )
2995   {
2996     return;
2997   }
2998
2999   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
3000
3001   // Sets the handle's position.
3002   mEventData->mDecorator->SetPosition( handleType,
3003                                        cursorPosition.x,
3004                                        cursorInfo.lineOffset + mModel->mScrollPosition.y,
3005                                        cursorInfo.lineHeight );
3006
3007   // If selection handle at start of the text and other at end of the text then all text is selected.
3008   const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
3009   const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
3010   mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mModel->mLogicalModel->mText.Count() );
3011 }
3012
3013 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
3014 {
3015   // Clamp between -space & -alignment offset.
3016
3017   if( layoutSize.width > mModel->mVisualModel->mControlSize.width )
3018   {
3019     const float space = ( layoutSize.width - mModel->mVisualModel->mControlSize.width ) + mModel->mAlignmentOffset;
3020     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x < -space ) ? -space : mModel->mScrollPosition.x;
3021     mModel->mScrollPosition.x = ( mModel->mScrollPosition.x > -mModel->mAlignmentOffset ) ? -mModel->mAlignmentOffset : mModel->mScrollPosition.x;
3022
3023     mEventData->mDecoratorUpdated = true;
3024   }
3025   else
3026   {
3027     mModel->mScrollPosition.x = 0.f;
3028   }
3029 }
3030
3031 void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
3032 {
3033   if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
3034   {
3035     // Nothing to do if the text is single line.
3036     return;
3037   }
3038
3039   // Clamp between -space & 0.
3040   if( layoutSize.height > mModel->mVisualModel->mControlSize.height )
3041   {
3042     const float space = ( layoutSize.height - mModel->mVisualModel->mControlSize.height );
3043     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y < -space ) ? -space : mModel->mScrollPosition.y;
3044     mModel->mScrollPosition.y = ( mModel->mScrollPosition.y > 0.f ) ? 0.f : mModel->mScrollPosition.y;
3045
3046     mEventData->mDecoratorUpdated = true;
3047   }
3048   else
3049   {
3050     mModel->mScrollPosition.y = 0.f;
3051   }
3052 }
3053
3054 void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
3055 {
3056   const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
3057
3058   // position is in actor's coords.
3059   const float positionEndX = position.x + cursorWidth;
3060   const float positionEndY = position.y + lineHeight;
3061
3062   // Transform the position to decorator coords.
3063   const float decoratorPositionBeginX = position.x + mModel->mScrollPosition.x;
3064   const float decoratorPositionEndX = positionEndX + mModel->mScrollPosition.x;
3065
3066   const float decoratorPositionBeginY = position.y + mModel->mScrollPosition.y;
3067   const float decoratorPositionEndY = positionEndY + mModel->mScrollPosition.y;
3068
3069   if( decoratorPositionBeginX < 0.f )
3070   {
3071     mModel->mScrollPosition.x = -position.x;
3072   }
3073   else if( decoratorPositionEndX > mModel->mVisualModel->mControlSize.width )
3074   {
3075     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
3076   }
3077
3078   if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
3079   {
3080     if( decoratorPositionBeginY < 0.f )
3081     {
3082       mModel->mScrollPosition.y = -position.y;
3083     }
3084     else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
3085     {
3086       mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
3087     }
3088   }
3089 }
3090
3091 void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
3092 {
3093   // Get the current cursor position in decorator coords.
3094   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
3095
3096   const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
3097
3098
3099
3100   // Calculate the offset to match the cursor position before the character was deleted.
3101   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
3102
3103   //If text control has more than two lines and current line index is not last, calculate scrollpositionY
3104   if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
3105   {
3106     const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
3107     mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
3108   }
3109
3110
3111   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
3112   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
3113
3114   // Makes the new cursor position visible if needed.
3115   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
3116 }
3117
3118 void Controller::Impl::RequestRelayout()
3119 {
3120   if( NULL != mControlInterface )
3121   {
3122     mControlInterface->RequestTextRelayout();
3123   }
3124 }
3125
3126 Actor Controller::Impl::CreateBackgroundActor()
3127 {
3128   // NOTE: Currently we only support background color for one line left-to-right text,
3129   //       so the following calculation is based on one line left-to-right text only!
3130
3131   Actor actor;
3132
3133   Length numberOfGlyphs = mView.GetNumberOfGlyphs();
3134   if( numberOfGlyphs > 0u )
3135   {
3136     Vector<GlyphInfo> glyphs;
3137     glyphs.Resize( numberOfGlyphs );
3138
3139     Vector<Vector2> positions;
3140     positions.Resize( numberOfGlyphs );
3141
3142     // Get the line where the glyphs are laid-out.
3143     const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
3144     float alignmentOffset = lineRun->alignmentOffset;
3145     numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
3146                                       positions.Begin(),
3147                                       alignmentOffset,
3148                                       0u,
3149                                       numberOfGlyphs );
3150
3151     glyphs.Resize( numberOfGlyphs );
3152     positions.Resize( numberOfGlyphs );
3153
3154     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
3155     const Vector2* const positionsBuffer = positions.Begin();
3156
3157     BackgroundMesh mesh;
3158     mesh.mVertices.Reserve( 4u * glyphs.Size() );
3159     mesh.mIndices.Reserve( 6u * glyphs.Size() );
3160
3161     const Vector2 textSize = mView.GetLayoutSize();
3162
3163     const float offsetX = textSize.width * 0.5f;
3164     const float offsetY = textSize.height * 0.5f;
3165
3166     const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
3167     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
3168
3169     Vector4 quad;
3170     uint32_t numberOfQuads = 0u;
3171
3172     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
3173     {
3174       const GlyphInfo& glyph = *( glyphsBuffer + i );
3175
3176       // Get the background color of the character.
3177       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
3178       const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
3179       const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? Color::TRANSPARENT : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
3180
3181       // Only create quads for glyphs with a background color
3182       if ( backgroundColor != Color::TRANSPARENT )
3183       {
3184         const Vector2 position = *( positionsBuffer + i );
3185
3186         if ( i == 0u && glyphSize == 1u ) // Only one glyph in the whole text
3187         {
3188           quad.x = position.x;
3189           quad.y = 0.0f;
3190           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
3191           quad.w = textSize.height;
3192         }
3193         else if ( i == 0u ) // The first glyph in the whole text
3194         {
3195           quad.x = position.x;
3196           quad.y = 0.0f;
3197           quad.z = quad.x - glyph.xBearing + glyph.advance;
3198           quad.w = textSize.height;
3199         }
3200         else if ( i == glyphSize - 1u ) // The last glyph in the whole text
3201         {
3202           quad.x = position.x - glyph.xBearing;
3203           quad.y = 0.0f;
3204           quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
3205           quad.w = textSize.height;
3206         }
3207         else // The glyph in the middle of the text
3208         {
3209           quad.x = position.x - glyph.xBearing;
3210           quad.y = 0.0f;
3211           quad.z = quad.x + glyph.advance;
3212           quad.w = textSize.height;
3213         }
3214
3215         BackgroundVertex vertex;
3216
3217         // Top left
3218         vertex.mPosition.x = quad.x - offsetX;
3219         vertex.mPosition.y = quad.y - offsetY;
3220         vertex.mColor = backgroundColor;
3221         mesh.mVertices.PushBack( vertex );
3222
3223         // Top right
3224         vertex.mPosition.x = quad.z - offsetX;
3225         vertex.mPosition.y = quad.y - offsetY;
3226         vertex.mColor = backgroundColor;
3227         mesh.mVertices.PushBack( vertex );
3228
3229         // Bottom left
3230         vertex.mPosition.x = quad.x - offsetX;
3231         vertex.mPosition.y = quad.w - offsetY;
3232         vertex.mColor = backgroundColor;
3233         mesh.mVertices.PushBack( vertex );
3234
3235         // Bottom right
3236         vertex.mPosition.x = quad.z - offsetX;
3237         vertex.mPosition.y = quad.w - offsetY;
3238         vertex.mColor = backgroundColor;
3239         mesh.mVertices.PushBack( vertex );
3240
3241         // Six indices in counter clockwise winding
3242         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
3243         mesh.mIndices.PushBack( 0u + 4 * numberOfQuads );
3244         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
3245         mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
3246         mesh.mIndices.PushBack( 3u + 4 * numberOfQuads );
3247         mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
3248
3249         numberOfQuads++;
3250       }
3251     }
3252
3253     // Only create the background actor if there are glyphs with background color
3254     if ( mesh.mVertices.Count() > 0u )
3255     {
3256       Property::Map quadVertexFormat;
3257       quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
3258       quadVertexFormat[ "aColor" ] = Property::VECTOR4;
3259
3260       PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
3261       quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
3262
3263       Geometry quadGeometry = Geometry::New();
3264       quadGeometry.AddVertexBuffer( quadVertices );
3265       quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
3266
3267       if( !mShaderBackground )
3268       {
3269         mShaderBackground = Shader::New( VERTEX_SHADER_BACKGROUND, FRAGMENT_SHADER_BACKGROUND );
3270       }
3271
3272       Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
3273       renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
3274       renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
3275
3276       actor = Actor::New();
3277       actor.SetName( "TextBackgroundColorActor" );
3278       actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
3279       actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
3280       actor.SetSize( textSize );
3281       actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
3282       actor.AddRenderer( renderer );
3283     }
3284   }
3285
3286   return actor;
3287 }
3288
3289 } // namespace Text
3290
3291 } // namespace Toolkit
3292
3293 } // namespace Dali