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