Merge "Stop setting crazy Z value with controls (at the moment depth is ignored by...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
index 4ce45eb..6552ce8 100644 (file)
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
 #include <dali-toolkit/internal/text/multi-language-support.h>
 #include <dali-toolkit/internal/text/multi-language-support.h>
-#include <dali-toolkit/internal/text/script-run.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
-#include <dali-toolkit/internal/text/text-io.h>
-#include <dali-toolkit/internal/text/text-view.h>
 
 namespace
 {
 
 namespace
 {
@@ -81,8 +77,8 @@ namespace Text
  * @param[in] glyphIndex The index to the first glyph.
  * @param[in] numberOfGlyphs The number of glyphs.
  * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
  * @param[in] glyphIndex The index to the first glyph.
  * @param[in] numberOfGlyphs The number of glyphs.
  * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
- * @param[in]
- * @param[in]
+ * @param[in] visualModel The visual model.
+ * @param[in] fontClient The font client.
  */
 void GetGlyphsMetrics( GlyphIndex glyphIndex,
                        Length numberOfGlyphs,
  */
 void GetGlyphsMetrics( GlyphIndex glyphIndex,
                        Length numberOfGlyphs,
@@ -128,14 +124,16 @@ EventData::EventData( DecoratorPtr decorator )
   mDecoratorUpdated( false ),
   mCursorBlinkEnabled( true ),
   mGrabHandleEnabled( true ),
   mDecoratorUpdated( false ),
   mCursorBlinkEnabled( true ),
   mGrabHandleEnabled( true ),
-  mGrabHandlePopupEnabled( false ),
-  mSelectionEnabled( false ),
+  mGrabHandlePopupEnabled( true ),
+  mSelectionEnabled( true ),
   mHorizontalScrollingEnabled( true ),
   mVerticalScrollingEnabled( false ),
   mUpdateCursorPosition( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
   mHorizontalScrollingEnabled( true ),
   mVerticalScrollingEnabled( false ),
   mUpdateCursorPosition( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
-  mScrollAfterUpdateCursorPosition( false )
+  mScrollAfterUpdatePosition( false ),
+  mScrollAfterDelete( false ),
+  mAllTextSelected( false )
 {}
 
 EventData::~EventData()
 {}
 
 EventData::~EventData()
@@ -151,8 +149,6 @@ bool Controller::Impl::ProcessInputEvents()
     return false;
   }
 
     return false;
   }
 
-  mEventData->mDecoratorUpdated = false;
-
   if( mEventData->mDecorator )
   {
     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
   if( mEventData->mDecorator )
   {
     for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
@@ -161,38 +157,43 @@ bool Controller::Impl::ProcessInputEvents()
     {
       switch( iter->type )
       {
     {
       switch( iter->type )
       {
-      case Event::KEYBOARD_FOCUS_GAIN_EVENT:
-      {
-        OnKeyboardFocus( true );
-        break;
-      }
-      case Event::KEYBOARD_FOCUS_LOST_EVENT:
-      {
-        OnKeyboardFocus( false );
-        break;
-      }
-      case Event::CURSOR_KEY_EVENT:
-      {
-        OnCursorKeyEvent( *iter );
-        break;
-      }
-      case Event::TAP_EVENT:
-      {
-        OnTapEvent( *iter );
-        break;
-      }
-      case Event::PAN_EVENT:
-      {
-        OnPanEvent( *iter );
-        break;
-      }
-      case Event::GRAB_HANDLE_EVENT:
-      case Event::LEFT_SELECTION_HANDLE_EVENT:
-      case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
-      {
-        OnHandleEvent( *iter );
-        break;
-      }
+        case Event::CURSOR_KEY_EVENT:
+        {
+          OnCursorKeyEvent( *iter );
+          break;
+        }
+        case Event::TAP_EVENT:
+        {
+          OnTapEvent( *iter );
+          break;
+        }
+        case Event::LONG_PRESS_EVENT:
+        {
+          OnLongPressEvent( *iter );
+          break;
+        }
+        case Event::PAN_EVENT:
+        {
+          OnPanEvent( *iter );
+          break;
+        }
+        case Event::GRAB_HANDLE_EVENT:
+        case Event::LEFT_SELECTION_HANDLE_EVENT:
+        case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
+        {
+          OnHandleEvent( *iter );
+          break;
+        }
+        case Event::SELECT:
+        {
+          OnSelectEvent( *iter );
+          break;
+        }
+        case Event::SELECT_ALL:
+        {
+          OnSelectAllEvent();
+          break;
+        }
       }
     }
   }
       }
     }
   }
@@ -204,46 +205,76 @@ bool Controller::Impl::ProcessInputEvents()
 
     UpdateCursorPosition();
 
 
     UpdateCursorPosition();
 
-    if( mEventData->mScrollAfterUpdateCursorPosition )
+    if( mEventData->mScrollAfterUpdatePosition )
     {
     {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
+      const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+      ScrollToMakePositionVisible( primaryCursorPosition );
+      mEventData->mScrollAfterUpdatePosition = false;
     }
 
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
   }
     }
 
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
   }
-  else if( mEventData->mUpdateLeftSelectionPosition )
+  else if( mEventData->mScrollAfterDelete )
   {
   {
-    UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
-
-    if( mEventData->mScrollAfterUpdateCursorPosition )
-    {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
-    }
-
+    ScrollTextToMatchCursor();
     mEventData->mDecoratorUpdated = true;
     mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateLeftSelectionPosition = false;
+    mEventData->mScrollAfterDelete = false;
   }
   }
-  else if( mEventData->mUpdateRightSelectionPosition )
+  else
   {
   {
-    UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+    bool leftScroll = false;
+    bool rightScroll = false;
+
+    if( mEventData->mUpdateLeftSelectionPosition )
+    {
+      UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
+
+      if( mEventData->mScrollAfterUpdatePosition )
+      {
+        const Vector2& leftHandlePosition = mEventData->mDecorator->GetPosition( LEFT_SELECTION_HANDLE );
+
+        ScrollToMakePositionVisible( leftHandlePosition );
+        leftScroll = true;
+      }
 
 
-    if( mEventData->mScrollAfterUpdateCursorPosition )
+      SetPopupButtons();
+      mEventData->mDecoratorUpdated = true;
+      mEventData->mUpdateLeftSelectionPosition = false;
+    }
+
+    if( mEventData->mUpdateRightSelectionPosition )
     {
     {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
+      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+
+      if( mEventData->mScrollAfterUpdatePosition )
+      {
+        const Vector2& rightHandlePosition = mEventData->mDecorator->GetPosition( RIGHT_SELECTION_HANDLE );
+
+        ScrollToMakePositionVisible( rightHandlePosition );
+        rightScroll = true;
+      }
+
+      SetPopupButtons();
+      mEventData->mDecoratorUpdated = true;
+      mEventData->mUpdateRightSelectionPosition = false;
     }
 
     }
 
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateRightSelectionPosition = false;
+    if( leftScroll || rightScroll )
+    {
+      mEventData->mScrollAfterUpdatePosition = false;
+    }
   }
 
   mEventData->mEventQueue.clear();
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
   }
 
   mEventData->mEventQueue.clear();
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
-  return mEventData->mDecoratorUpdated;
+
+  const bool decoratorUpdated = mEventData->mDecoratorUpdated;
+  mEventData->mDecoratorUpdated = false;
+
+  return decoratorUpdated;
 }
 
 void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 }
 
 void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
@@ -294,7 +325,6 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     {
       // Retrieves the scripts used in the text.
       multilanguageSupport.SetScripts( utf32Characters,
     {
       // Retrieves the scripts used in the text.
       multilanguageSupport.SetScripts( utf32Characters,
-                                       lineBreakInfo,
                                        scripts );
     }
 
                                        scripts );
     }
 
@@ -317,13 +347,12 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 
   Vector<Character> mirroredUtf32Characters;
   bool textMirrored = false;
 
   Vector<Character> mirroredUtf32Characters;
   bool textMirrored = false;
+  Length numberOfParagraphs = 0u;
   if( BIDI_INFO & operations )
   {
     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
     // bidirectional info.
 
   if( BIDI_INFO & operations )
   {
     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
     // bidirectional info.
 
-    Length numberOfParagraphs = 0u;
-
     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
     for( Length index = 0u; index < numberOfCharacters; ++index )
     {
     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
     for( Length index = 0u; index < numberOfCharacters; ++index )
     {
@@ -347,7 +376,9 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
       // This paragraph has right to left text. Some characters may need to be mirrored.
       // TODO: consider if the mirrored string can be stored as well.
 
       // This paragraph has right to left text. Some characters may need to be mirrored.
       // TODO: consider if the mirrored string can be stored as well.
 
-      textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
+      textMirrored = GetMirroredText( utf32Characters,
+                                      mirroredUtf32Characters,
+                                      bidirectionalInfo );
 
       // Only set the character directions if there is right to left characters.
       Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
 
       // Only set the character directions if there is right to left characters.
       Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
@@ -361,12 +392,14 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
       // There is no right to left characters. Clear the directions vector.
       mLogicalModel->mCharacterDirections.Clear();
     }
       // There is no right to left characters. Clear the directions vector.
       mLogicalModel->mCharacterDirections.Clear();
     }
-
-   }
+  }
 
   Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
   Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
   Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
 
   Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
   Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
   Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex> newParagraphGlyphs;
+  newParagraphGlyphs.Reserve( numberOfParagraphs );
+
   if( SHAPE_TEXT & operations )
   {
     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
   if( SHAPE_TEXT & operations )
   {
     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
@@ -377,7 +410,8 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                validFonts,
                glyphs,
                glyphsToCharactersMap,
                validFonts,
                glyphs,
                glyphsToCharactersMap,
-               charactersPerGlyph );
+               charactersPerGlyph,
+               newParagraphGlyphs );
 
     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
     mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
 
     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
     mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
@@ -388,7 +422,19 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 
   if( GET_GLYPH_METRICS & operations )
   {
 
   if( GET_GLYPH_METRICS & operations )
   {
-    mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
+    GlyphInfo* glyphsBuffer = glyphs.Begin();
+    mFontClient.GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
+
+    // Update the width and advance of all new paragraph characters.
+    for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
+    {
+      const GlyphIndex index = *it;
+      GlyphInfo& glyph = *( glyphsBuffer + index );
+
+      glyph.xBearing = 0.f;
+      glyph.width = 0.f;
+      glyph.advance = 0.f;
+    }
   }
 }
 
   }
 }
 
@@ -406,22 +452,23 @@ void Controller::Impl::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfC
   }
 }
 
   }
 }
 
-void Controller::Impl::OnKeyboardFocus( bool hasFocus )
+float Controller::Impl::GetDefaultFontLineHeight()
 {
 {
-  if( NULL == mEventData )
+  FontId defaultFontId = 0u;
+  if( NULL == mFontDefaults )
   {
   {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  if( !hasFocus )
-  {
-    ChangeState( EventData::INACTIVE );
+    defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
+                                           EMPTY_STRING );
   }
   else
   {
   }
   else
   {
-    ChangeState( EventData::EDITING );
+    defaultFontId = mFontDefaults->GetFontId( mFontClient );
   }
   }
+
+  Text::FontMetrics fontMetrics;
+  mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
+
+  return( fontMetrics.ascender - fontMetrics.descender );
 }
 
 void Controller::Impl::OnCursorKeyEvent( const Event& event )
 }
 
 void Controller::Impl::OnCursorKeyEvent( const Event& event )
@@ -443,7 +490,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   }
   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
   {
   }
   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
   {
-    if( mLogicalModel->GetNumberOfCharacters() > mEventData->mPrimaryCursorPosition )
+    if( mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
     {
       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
     }
     {
       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
     }
@@ -458,7 +505,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   }
 
   mEventData->mUpdateCursorPosition = true;
   }
 
   mEventData->mUpdateCursorPosition = true;
-  mEventData->mScrollAfterUpdateCursorPosition = true;
+  mEventData->mScrollAfterUpdatePosition = true;
 }
 
 void Controller::Impl::OnTapEvent( const Event& event )
 }
 
 void Controller::Impl::OnTapEvent( const Event& event )
@@ -483,12 +530,7 @@ void Controller::Impl::OnTapEvent( const Event& event )
       }
 
       mEventData->mUpdateCursorPosition = true;
       }
 
       mEventData->mUpdateCursorPosition = true;
-      mEventData->mScrollAfterUpdateCursorPosition = true;
-    }
-    else if( mEventData->mSelectionEnabled &&
-             ( 2u == tapCount ) )
-    {
-      RepositionSelectionHandles( event.p2.mFloat, event.p3.mFloat );
+      mEventData->mScrollAfterUpdatePosition = true;
     }
   }
 }
     }
   }
 }
@@ -532,6 +574,15 @@ void Controller::Impl::OnPanEvent( const Event& event )
   }
 }
 
   }
 }
 
+void Controller::Impl::OnLongPressEvent( const Event& event )
+{
+  if  ( EventData::EDITING == mEventData->mState )
+  {
+    ChangeState ( EventData::EDITING_WITH_POPUP );
+    mEventData->mDecoratorUpdated = true;
+  }
+}
+
 void Controller::Impl::OnHandleEvent( const Event& event )
 {
   if( NULL == mEventData )
 void Controller::Impl::OnHandleEvent( const Event& event )
 {
   if( NULL == mEventData )
@@ -541,6 +592,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
   }
 
   const unsigned int state = event.p1.mUint;
   }
 
   const unsigned int state = event.p1.mUint;
+  const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
 
   if( HANDLE_PRESSED == state )
   {
 
   if( HANDLE_PRESSED == state )
   {
@@ -552,7 +604,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
-      ChangeState ( EventData::EDITING );
+      ChangeState ( EventData::GRAB_HANDLE_PANNING );
 
       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
       {
 
       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
       {
@@ -562,220 +614,778 @@ void Controller::Impl::OnHandleEvent( const Event& event )
     }
     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
     {
     }
     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
     {
-      if( handleNewPosition != mEventData->mLeftSelectionPosition )
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mRightSelectionPosition ) )
       {
         mEventData->mLeftSelectionPosition = handleNewPosition;
       {
         mEventData->mLeftSelectionPosition = handleNewPosition;
+
+        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                    mEventData->mRightSelectionPosition );
+
         mEventData->mUpdateLeftSelectionPosition = true;
       }
     }
     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
         mEventData->mUpdateLeftSelectionPosition = true;
       }
     }
     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
-      if( handleNewPosition != mEventData->mRightSelectionPosition )
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
       {
         mEventData->mRightSelectionPosition = handleNewPosition;
       {
         mEventData->mRightSelectionPosition = handleNewPosition;
+
+        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                    mEventData->mRightSelectionPosition );
+
         mEventData->mUpdateRightSelectionPosition = true;
       }
     }
         mEventData->mUpdateRightSelectionPosition = true;
       }
     }
-  }
+  } // end ( HANDLE_PRESSED == state )
   else if( ( HANDLE_RELEASED == state ) ||
   else if( ( HANDLE_RELEASED == state ) ||
-           ( HANDLE_STOP_SCROLLING == state ) )
+           handleStopScrolling )
   {
   {
-    if( mEventData->mGrabHandlePopupEnabled )
+    CharacterIndex handlePosition = 0u;
+    if( handleStopScrolling )
     {
     {
-      ChangeState( EventData::EDITING_WITH_POPUP );
+      // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
+      const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
+      const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+
+      handlePosition = GetClosestCursorIndex( xPosition, yPosition );
     }
     }
+
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
       mEventData->mUpdateCursorPosition = true;
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
       mEventData->mUpdateCursorPosition = true;
 
-      if( HANDLE_STOP_SCROLLING == state )
+      ChangeState( EventData::EDITING_WITH_POPUP );
+
+      if( handleStopScrolling )
       {
       {
-        // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
-        const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
-        const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+        mEventData->mScrollAfterUpdatePosition = mEventData->mPrimaryCursorPosition != handlePosition;
+        mEventData->mPrimaryCursorPosition = handlePosition;
+      }
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
+
+      if( handleStopScrolling )
+      {
+        mEventData->mUpdateLeftSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition );
+        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
+
+        if( mEventData->mUpdateLeftSelectionPosition )
+        {
+          mEventData->mLeftSelectionPosition = handlePosition;
 
 
-        mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
+          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                      mEventData->mRightSelectionPosition );
+        }
+      }
+    }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
 
 
-        mEventData->mScrollAfterUpdateCursorPosition = true;
+      if( handleStopScrolling )
+      {
+        mEventData->mUpdateRightSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition );
+        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
+        if( mEventData->mUpdateRightSelectionPosition )
+        {
+          mEventData->mRightSelectionPosition = handlePosition;
+          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                      mEventData->mRightSelectionPosition );
+        }
       }
     }
       }
     }
+
     mEventData->mDecoratorUpdated = true;
     mEventData->mDecoratorUpdated = true;
-  }
+  } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
   else if( HANDLE_SCROLLING == state )
   {
     const float xSpeed = event.p2.mFloat;
     const Vector2& actualSize = mVisualModel->GetActualSize();
   else if( HANDLE_SCROLLING == state )
   {
     const float xSpeed = event.p2.mFloat;
     const Vector2& actualSize = mVisualModel->GetActualSize();
+    const Vector2 currentScrollPosition = mEventData->mScrollPosition;
 
     mEventData->mScrollPosition.x += xSpeed;
 
     ClampHorizontalScroll( actualSize );
 
 
     mEventData->mScrollPosition.x += xSpeed;
 
     ClampHorizontalScroll( actualSize );
 
-   mEventData->mDecoratorUpdated = true;
-  }
+    bool endOfScroll = false;
+    if( Vector2::ZERO == ( currentScrollPosition - mEventData->mScrollPosition ) )
+    {
+      // Notify the decorator there is no more text to scroll.
+      // The decorator won't send more scroll events.
+      mEventData->mDecorator->NotifyEndOfScroll();
+      // Still need to set the position of the handle.
+      endOfScroll = true;
+    }
+
+    // Set the position of the handle.
+    const bool scrollRightDirection = xSpeed > 0.f;
+    const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
+    const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
+
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::GRAB_HANDLE_PANNING );
+
+      Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
+
+      // Position the grag handle close to either the left or right edge.
+      position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
+
+      // Get the new handle position.
+      // The grab handle's position is in decorator coords. Need to transforms to text coords.
+      const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+                                                                   position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+      mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
+      mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
+      mEventData->mPrimaryCursorPosition = handlePosition;
+    }
+    else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
+    {
+      // TODO: This is recalculating the selection box every time the text is scrolled with the selection handles.
+      //       Think if something can be done to save power.
+
+      ChangeState( EventData::SELECTION_HANDLE_PANNING );
+
+      Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+
+      // Position the selection handle close to either the left or right edge.
+      position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
+
+      // Get the new handle position.
+      // The selection handle's position is in decorator coords. Need to transforms to text coords.
+      const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+                                                                   position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+      if( leftSelectionHandleEvent )
+      {
+        const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
+        mEventData->mUpdateLeftSelectionPosition = endOfScroll || differentHandles;
+        if( differentHandles )
+        {
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
+      }
+      else
+      {
+        const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
+        mEventData->mUpdateRightSelectionPosition = endOfScroll || differentHandles;
+        if( differentHandles )
+        {
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+      }
+
+      if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+      {
+        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+                                    mEventData->mRightSelectionPosition );
+
+        mEventData->mScrollAfterUpdatePosition = true;
+      }
+    }
+    mEventData->mDecoratorUpdated = true;
+  } // end ( HANDLE_SCROLLING == state )
 }
 
 }
 
-void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
+void Controller::Impl::OnSelectEvent( const Event& event )
 {
   if( NULL == mEventData )
   {
 {
   if( NULL == mEventData )
   {
-    // Nothing to do if there is no text input.
+    // Nothing to do if there is no text.
     return;
   }
 
     return;
   }
 
-  // TODO - Find which word was selected
-
-  const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
-  const Vector<Vector2>::SizeType glyphCount = glyphs.Count();
-
-  const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
-  const Vector<Vector2>::SizeType positionCount = positions.Count();
-
-  // Guard against glyphs which did not fit inside the layout
-  const Vector<Vector2>::SizeType count = (positionCount < glyphCount) ? positionCount : glyphCount;
-
-  if( count )
+  if( mEventData->mSelectionEnabled )
   {
   {
-    float primaryX   = positions[0].x + mEventData->mScrollPosition.x;
-    float secondaryX = positions[count-1].x + glyphs[count-1].width + mEventData->mScrollPosition.x;
+    // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
+    const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
+    const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
 
 
-    // TODO - multi-line selection
-    const Vector<LineRun>& lines = mVisualModel->mLines;
-    float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
+    const CharacterIndex leftPosition = mEventData->mLeftSelectionPosition;
+    const CharacterIndex rightPosition = mEventData->mRightSelectionPosition;
 
 
-    mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,     primaryX, mEventData->mScrollPosition.y, height );
-    mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryX, mEventData->mScrollPosition.y, height );
+    RepositionSelectionHandles( xPosition,
+                                yPosition );
 
 
-    mEventData->mDecorator->ClearHighlights();
-    mEventData->mDecorator->AddHighlight( primaryX, mEventData->mScrollPosition.y, secondaryX, height + mEventData->mScrollPosition.y );
+    mEventData->mUpdateLeftSelectionPosition = leftPosition != mEventData->mLeftSelectionPosition;
+    mEventData->mUpdateRightSelectionPosition = rightPosition != mEventData->mRightSelectionPosition;
+
+    mEventData->mScrollAfterUpdatePosition = ( ( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition ) &&
+                                               ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ) );
   }
 }
 
   }
 }
 
-void Controller::Impl::ChangeState( EventData::State newState )
+void Controller::Impl::OnSelectAllEvent()
 {
   if( NULL == mEventData )
   {
 {
   if( NULL == mEventData )
   {
-    // Nothing to do if there is no text input.
+    // Nothing to do if there is no text.
     return;
   }
 
     return;
   }
 
-  if( mEventData->mState != newState )
+  if( mEventData->mSelectionEnabled )
   {
   {
-    mEventData->mState = newState;
+    RepositionSelectionHandles( 0u,
+                                mLogicalModel->mText.Count() );
 
 
-    if( EventData::INACTIVE == mEventData->mState )
-    {
-      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
-      mEventData->mDecorator->StopCursorBlink();
-      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
-      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
-      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
-      mEventData->mDecorator->SetPopupActive( false );
-      mEventData->mDecoratorUpdated = true;
-    }
-    else if ( EventData::SELECTING == mEventData->mState )
-    {
-      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
-      mEventData->mDecorator->StopCursorBlink();
-      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
-      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
-      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
-      mEventData->mDecoratorUpdated = true;
-    }
-    else if( EventData::EDITING == mEventData->mState )
-    {
-      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
-      if( mEventData->mCursorBlinkEnabled )
-      {
-        mEventData->mDecorator->StartCursorBlink();
-      }
-      // Grab handle is not shown until a tap is received whilst EDITING
-      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
-      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
-      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
-      mEventData->mDecoratorUpdated = true;
-    }
-    else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
-    {
-      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
-      if( mEventData->mCursorBlinkEnabled )
-      {
-        mEventData->mDecorator->StartCursorBlink();
-      }
-      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
-      if( mEventData->mSelectionEnabled )
-      {
-        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
-        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
-      }
-      if( mEventData->mGrabHandlePopupEnabled )
-      {
-        mEventData->mDecorator->SetPopupActive( true );
-      }
-      mEventData->mDecoratorUpdated = true;
-    }
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = true;
   }
 }
 
   }
 }
 
-LineIndex Controller::Impl::GetClosestLine( float y ) const
+void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetreival )
 {
 {
-  float totalHeight = 0.f;
-  LineIndex lineIndex = 0u;
+  if( mEventData->mLeftSelectionPosition ==  mEventData->mRightSelectionPosition )
+  {
+    // Nothing to select if handles are in the same place.
+    selectedText="";
+    return;
+  }
 
 
-  const Vector<LineRun>& lines = mVisualModel->mLines;
-  for( LineIndex endLine = lines.Count();
-       lineIndex < endLine;
-       ++lineIndex )
+  //Get start and end position of selection
+  uint32_t startOfSelectedText = mEventData->mLeftSelectionPosition;
+  uint32_t lengthOfSelectedText =  mEventData->mRightSelectionPosition - startOfSelectedText;
+
+  // Validate the start and end selection points
+  if( ( startOfSelectedText >= 0 ) && (  ( startOfSelectedText + lengthOfSelectedText ) <=  mLogicalModel->mText.Count() ) )
   {
   {
-    const LineRun& lineRun = lines[lineIndex];
-    totalHeight += lineRun.ascender + -lineRun.descender;
-    if( y < totalHeight )
+    //Get text as a UTF8 string
+    Vector<Character>& utf32Characters = mLogicalModel->mText;
+
+    Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
+
+    if ( deleteAfterRetreival  ) // Only delete text if copied successfully
     {
     {
-      return lineIndex;
+      // Delete text between handles
+      Vector<Character>& currentText = mLogicalModel->mText;
+
+      Vector<Character>::Iterator first = currentText.Begin() + startOfSelectedText;
+      Vector<Character>::Iterator last  = first + lengthOfSelectedText;
+      currentText.Erase( first, last );
     }
     }
+    mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition;
+    mEventData->mScrollAfterDelete = true;
+    mEventData->mDecoratorUpdated = true;
   }
   }
+}
 
 
-  return lineIndex-1;
+void Controller::Impl::ShowClipboard()
+{
+  if ( mClipboard )
+  {
+    mClipboard.ShowClipboard();
+  }
 }
 
 }
 
-CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
-                                                        float visualY )
+void Controller::Impl::HideClipboard()
 {
 {
-  if( NULL == mEventData )
+  if ( mClipboard )
   {
   {
-    // Nothing to do if there is no text input.
-    return 0u;
+    mClipboard.HideClipboard();
   }
   }
+}
 
 
-  CharacterIndex logicalIndex = 0u;
+bool Controller::Impl::CopyStringToClipboard( std::string& source )
+{
+  //Send string to clipboard
+  return ( mClipboard && mClipboard.SetItem( source ) );
+}
 
 
-  const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
-  const Length numberOfLines  = mVisualModel->mLines.Count();
-  if( 0 == numberOfGlyphs ||
-      0 == numberOfLines )
+void Controller::Impl::SendSelectionToClipboard( bool deleteAfterSending )
+{
+  std::string selectedText;
+  RetrieveSelection( selectedText, deleteAfterSending );
+  CopyStringToClipboard( selectedText );
+  ChangeState( EventData::EDITING );
+}
+
+void Controller::Impl::GetTextFromClipboard( unsigned int itemIndex, std::string& retreivedString )
+{
+  if ( mClipboard )
   {
   {
-    return logicalIndex;
+    retreivedString =  mClipboard.GetItem( itemIndex );
   }
   }
+}
 
 
-  // Find which line is closest
-  const LineIndex lineIndex = GetClosestLine( visualY );
-  const LineRun& line = mVisualModel->mLines[lineIndex];
+void Controller::Impl::RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd )
+{
+  if( selectionStart == selectionEnd )
+  {
+    // Nothing to select if handles are in the same place.
+    return;
+  }
 
 
-  // Get the positions of the glyphs.
-  const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
-  const Vector2* const positionsBuffer = positions.Begin();
+  mEventData->mDecorator->ClearHighlights();
 
 
-  // Get the visual to logical conversion tables.
-  const CharacterIndex* const visualToLogicalBuffer = ( 0u != mLogicalModel->mVisualToLogicalMap.Count() ) ? mLogicalModel->mVisualToLogicalMap.Begin() : NULL;
-  const CharacterIndex* const visualToLogicalCursorBuffer = mLogicalModel->mVisualToLogicalCursorMap.Begin();
+  mEventData->mLeftSelectionPosition = selectionStart;
+  mEventData->mRightSelectionPosition = selectionEnd;
 
 
-  // Get the character to glyph conversion table.
   const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
   const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
-
-  // Get the glyphs per character table.
   const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
   const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+  const GlyphInfo* const glyphsBuffer = mVisualModel->mGlyphs.Begin();
+  const Vector2* const positionsBuffer = mVisualModel->mGlyphPositions.Begin();
+  const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+  const CharacterIndex* const glyphToCharacterBuffer = mVisualModel->mGlyphsToCharacters.Begin();
+  const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
 
 
-  // If the vector is void, there is no right to left characters.
-  const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
+  // TODO: Better algorithm to create the highlight box.
+  // TODO: Multi-line.
+
+  // Get the height of the line.
+  const Vector<LineRun>& lines = mVisualModel->mLines;
+  const LineRun& firstLine = *lines.Begin();
+  const float height = firstLine.ascender + -firstLine.descender;
+
+  // Swap the indices if the start is greater than the end.
+  const bool indicesSwapped = ( selectionStart > selectionEnd );
+  if( indicesSwapped )
+  {
+    std::swap( selectionStart, selectionEnd );
+  }
+
+  // Get the indices to the first and last selected glyphs.
+  const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
+  const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
+  const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
+  const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
+
+  // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
+  const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
+  bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionStart ) );
+
+  // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
+  const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
+  bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionEndMinusOne ) );
+
+  // Tell the decorator to swap the selection handles if needed.
+  mEventData->mDecorator->SwapSelectionHandlesEnabled( firstLine.direction != indicesSwapped );
+
+  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+
+  // Traverse the glyphs.
+  for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
+  {
+    const GlyphInfo& glyph = *( glyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+
+    if( splitStartGlyph )
+    {
+      // 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.
+
+      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
+      const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
+      // Get the direction of the character.
+      CharacterDirection isCurrentRightToLeft = false;
+      if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      {
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
+      }
+
+      // The end point could be in the middle of the ligature.
+      // Calculate the number of characters selected.
+      const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
+
+      const float xPosition = position.x - glyph.xBearing + offset.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
+
+      mEventData->mDecorator->AddHighlight( xPosition,
+                                            offset.y,
+                                            xPosition + static_cast<float>( numberOfCharacters ) * glyphAdvance,
+                                            height );
+
+      splitStartGlyph = false;
+      continue;
+    }
+
+    if( splitEndGlyph && ( index == glyphEnd ) )
+    {
+      // 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.
+
+      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
+      const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
+      // Get the direction of the character.
+      CharacterDirection isCurrentRightToLeft = false;
+      if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      {
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
+      }
+
+      const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
+
+      const float xPosition = position.x - glyph.xBearing + offset.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
+      mEventData->mDecorator->AddHighlight( xPosition,
+                                            offset.y,
+                                            xPosition + static_cast<float>( interGlyphIndex ) * glyphAdvance,
+                                            height );
+
+      splitEndGlyph = false;
+      continue;
+    }
+
+    const float xPosition = position.x - glyph.xBearing + offset.x;
+    mEventData->mDecorator->AddHighlight( xPosition, offset.y, xPosition + glyph.advance, height );
+  }
+
+  CursorInfo primaryCursorInfo;
+  GetCursorPosition( mEventData->mLeftSelectionPosition,
+                     primaryCursorInfo );
+
+  CursorInfo secondaryCursorInfo;
+  GetCursorPosition( mEventData->mRightSelectionPosition,
+                     secondaryCursorInfo );
+
+  const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + offset;
+  const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + offset;
+
+  mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE, primaryPosition.x, primaryPosition.y, primaryCursorInfo.lineHeight );
+
+  mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryPosition.x, secondaryPosition.y, secondaryCursorInfo.lineHeight );
+
+  // Set the flag to update the decorator.
+  mEventData->mDecoratorUpdated = true;
+}
+
+void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  if( IsShowingPlaceholderText() )
+  {
+    // Nothing to do if there is the place-holder text.
+    return;
+  }
+
+  const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
+  const Length numberOfLines  = mVisualModel->mLines.Count();
+  if( 0 == numberOfGlyphs ||
+      0 == numberOfLines )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  // Find which word was selected
+  CharacterIndex selectionStart( 0 );
+  CharacterIndex selectionEnd( 0 );
+  FindSelectionIndices( visualX, visualY, selectionStart, selectionEnd );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
+
+  if( selectionStart == selectionEnd )
+  {
+    ChangeState( EventData::EDITING );
+    // Nothing to select. i.e. a white space, out of bounds
+    return;
+  }
+
+  RepositionSelectionHandles( selectionStart, selectionEnd );
+}
+
+void Controller::Impl::SetPopupButtons()
+{
+  /**
+   *  Sets the Popup buttons to be shown depending on State.
+   *
+   *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
+   *
+   *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
+   */
+
+  TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
+
+  if ( ( EventData::SELECTING == mEventData->mState ) || ( EventData::SELECTION_CHANGED == mEventData->mState ) )
+  {
+    buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+
+    if ( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
+
+    if ( !mEventData->mAllTextSelected )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
+    }
+  }
+  else if  ( EventData::EDITING_WITH_POPUP == mEventData->mState )
+  {
+    if ( mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
+    {
+      buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
+    }
+
+    if ( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
+  }
+
+  mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+}
+
+void Controller::Impl::ChangeState( EventData::State newState )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  if( mEventData->mState != newState )
+  {
+    mEventData->mState = newState;
+
+    if( EventData::INACTIVE == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+      mEventData->mDecorator->StopCursorBlink();
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetPopupActive( false );
+      mEventData->mDecoratorUpdated = true;
+      HideClipboard();
+    }
+    else if ( EventData::INTERRUPTED  == mEventData->mState)
+    {
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetPopupActive( false );
+      mEventData->mDecoratorUpdated = true;
+      HideClipboard();
+    }
+    else if ( EventData::SELECTING == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+      mEventData->mDecorator->StopCursorBlink();
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        SetPopupButtons();
+        mEventData->mDecorator->SetPopupActive( true );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if ( EventData::SELECTION_CHANGED  == mEventData->mState )
+    {
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        SetPopupButtons();
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+        mEventData->mDecorator->SetPopupActive( true );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if( EventData::EDITING == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+      if( mEventData->mCursorBlinkEnabled )
+      {
+        mEventData->mDecorator->StartCursorBlink();
+      }
+      // Grab handle is not shown until a tap is received whilst EDITING
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+      HideClipboard();
+    }
+    else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+      if( mEventData->mCursorBlinkEnabled )
+      {
+        mEventData->mDecorator->StartCursorBlink();
+      }
+      if( mEventData->mSelectionEnabled )
+      {
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      }
+      else
+      {
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+      }
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        SetPopupButtons();
+        mEventData->mDecorator->SetPopupActive( true );
+      }
+      HideClipboard();
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+      if( mEventData->mCursorBlinkEnabled )
+      {
+        mEventData->mDecorator->StartCursorBlink();
+      }
+      // Grab handle is not shown until a tap is received whilst EDITING
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+      HideClipboard();
+    }
+    else if ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+      mEventData->mDecorator->StopCursorBlink();
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if ( EventData::GRAB_HANDLE_PANNING == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+      if( mEventData->mCursorBlinkEnabled )
+      {
+        mEventData->mDecorator->StartCursorBlink();
+      }
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+  }
+}
+
+LineIndex Controller::Impl::GetClosestLine( float y ) const
+{
+  float totalHeight = 0.f;
+  LineIndex lineIndex = 0u;
+
+  const Vector<LineRun>& lines = mVisualModel->mLines;
+  for( LineIndex endLine = lines.Count();
+       lineIndex < endLine;
+       ++lineIndex )
+  {
+    const LineRun& lineRun = lines[lineIndex];
+    totalHeight += lineRun.ascender + -lineRun.descender;
+    if( y < totalHeight )
+    {
+      return lineIndex;
+    }
+  }
+
+  if( lineIndex == 0 )
+  {
+    return 0;
+  }
+
+  return lineIndex-1;
+}
+
+void Controller::Impl::FindSelectionIndices( float visualX, float visualY, CharacterIndex& startIndex, CharacterIndex& endIndex )
+{
+  CharacterIndex hitCharacter = GetClosestCursorIndex( visualX, visualY );
+  if( hitCharacter >= mLogicalModel->mText.Count() )
+  {
+    // Selection out of bounds.
+    return;
+  }
+
+  startIndex = hitCharacter;
+  endIndex = hitCharacter;
+
+  if( !TextAbstraction::IsWhiteSpace( mLogicalModel->mText[hitCharacter] ) )
+  {
+    // Find the start and end of the text
+    for( startIndex = hitCharacter; startIndex > 0; --startIndex )
+    {
+      Character charCode = mLogicalModel->mText[ startIndex-1 ];
+      if( TextAbstraction::IsWhiteSpace( charCode ) )
+      {
+        break;
+      }
+    }
+    const CharacterIndex pastTheEnd = mLogicalModel->mText.Count();
+    for( endIndex = hitCharacter + 1u; endIndex < pastTheEnd; ++endIndex )
+    {
+      Character charCode = mLogicalModel->mText[ endIndex ];
+      if( TextAbstraction::IsWhiteSpace( charCode ) )
+      {
+        break;
+      }
+    }
+  }
+}
+
+CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
+                                                        float visualY )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return 0u;
+  }
+
+  CharacterIndex logicalIndex = 0u;
+
+  const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
+  const Length numberOfLines  = mVisualModel->mLines.Count();
+  if( 0 == numberOfGlyphs ||
+      0 == numberOfLines )
+  {
+    return logicalIndex;
+  }
+
+  // Find which line is closest
+  const LineIndex lineIndex = GetClosestLine( visualY );
+  const LineRun& line = mVisualModel->mLines[lineIndex];
+
+  // Get the positions of the glyphs.
+  const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
+  const Vector2* const positionsBuffer = positions.Begin();
+
+  // Get the visual to logical conversion tables.
+  const CharacterIndex* const visualToLogicalBuffer = ( 0u != mLogicalModel->mVisualToLogicalMap.Count() ) ? mLogicalModel->mVisualToLogicalMap.Begin() : NULL;
+  const CharacterIndex* const visualToLogicalCursorBuffer = mLogicalModel->mVisualToLogicalCursorMap.Begin();
+
+  // Get the character to glyph conversion table.
+  const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+
+  // Get the glyphs per character table.
+  const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+  const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+
+  // If the vector is void, there is no right to left characters.
+  const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
 
   const CharacterIndex startCharacter = line.characterRun.characterIndex;
   const CharacterIndex endCharacter   = line.characterRun.characterIndex + line.characterRun.numberOfCharacters;
 
   const CharacterIndex startCharacter = line.characterRun.characterIndex;
   const CharacterIndex endCharacter   = line.characterRun.characterIndex + line.characterRun.numberOfCharacters;
@@ -791,9 +1401,11 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
     // The character in logical order.
     const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
 
     // The character in logical order.
     const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
 
+    // Get the script of the character.
+    const Script script = mLogicalModel->GetScript( characterLogicalOrderIndex );
+
     // The first glyph for that character in logical order.
     const GlyphIndex glyphLogicalOrderIndex = *( charactersToGlyphBuffer + characterLogicalOrderIndex );
     // The first glyph for that character in logical order.
     const GlyphIndex glyphLogicalOrderIndex = *( charactersToGlyphBuffer + characterLogicalOrderIndex );
-
     // The number of glyphs for that character
     const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
 
     // The number of glyphs for that character
     const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
 
@@ -807,11 +1419,25 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
 
     const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
 
 
     const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
 
-    const float glyphX = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
+    // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ...
+    const Length numberOfCharactersInLigature = HasLigatureMustBreak( script ) ? *( charactersPerGlyphBuffer + glyphLogicalOrderIndex ) : 1u;
+    const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfCharactersInLigature );
+
+    for( GlyphIndex index = 0u; !matched && ( index < numberOfCharactersInLigature ); ++index )
+    {
+      // Find the mid-point of the area containing the glyph
+      const float glyphCenter = -glyphMetrics.xBearing + position.x + ( static_cast<float>( index ) + 0.5f ) * glyphAdvance;
+
+      if( visualX < glyphCenter )
+      {
+        visualIndex += index;
+        matched = true;
+        break;
+      }
+    }
 
 
-    if( visualX < glyphX )
+    if( matched )
     {
     {
-      matched = true;
       break;
     }
   }
       break;
     }
   }
@@ -823,7 +1449,10 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
     visualIndex = endCharacter;
   }
 
     visualIndex = endCharacter;
   }
 
-  return hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
+  logicalIndex = hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p closest visualIndex %d logicalIndex %d\n", this, visualIndex, logicalIndex );
+
+  return logicalIndex;
 }
 
 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 }
 
 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
@@ -833,60 +1462,41 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 
   // Check if the logical position is the first or the last one of the text.
   const bool isFirstPosition = 0u == logical;
 
   // Check if the logical position is the first or the last one of the text.
   const bool isFirstPosition = 0u == logical;
-  const bool isLastPosition = mLogicalModel->GetNumberOfCharacters() == logical;
+  const bool isLastPosition = mLogicalModel->mText.Count() == logical;
 
   if( isFirstPosition && isLastPosition )
   {
 
   if( isFirstPosition && isLastPosition )
   {
-    // There is zero characters. Get the default font.
-
-    FontId defaultFontId = 0u;
-    if( NULL == mFontDefaults )
-    {
-      defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
-                                             EMPTY_STRING );
-    }
-    else
-    {
-      defaultFontId = mFontDefaults->GetFontId( mFontClient );
-    }
-
-    Text::FontMetrics fontMetrics;
-    mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
-
-    cursorInfo.lineHeight = fontMetrics.ascender - fontMetrics.descender;
+    // There is zero characters. Get the default font's line height.
+    cursorInfo.lineHeight = GetDefaultFontLineHeight();
     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
 
     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
 
-    cursorInfo.primaryPosition.x = 0.f;
+    cursorInfo.primaryPosition.x = 1.f;
     cursorInfo.primaryPosition.y = 0.f;
 
     // Nothing else to do.
     return;
   }
 
     cursorInfo.primaryPosition.y = 0.f;
 
     // Nothing else to do.
     return;
   }
 
-  // Get the previous logical index.
-  const CharacterIndex previousLogical = isFirstPosition ? 0u : logical - 1u;
-
-  // Decrease the logical index if it's the last one.
-  if( isLastPosition )
-  {
-    --logical;
-  }
+  // 'logical' is the logical 'cursor' index.
+  // Get the next and current logical 'character' index.
+  const CharacterIndex nextCharacterIndex = logical;
+  const CharacterIndex characterIndex = isFirstPosition ? logical : logical - 1u;
 
 
-  // Get the direction of the character and the previous one.
+  // Get the direction of the character and the next one.
   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
 
   CharacterDirection isCurrentRightToLeft = false;
   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
 
   CharacterDirection isCurrentRightToLeft = false;
-  CharacterDirection isPreviousRightToLeft = false;
+  CharacterDirection isNextRightToLeft = false;
   if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
   {
   if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
   {
-    isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + logical );
-    isPreviousRightToLeft = *( modelCharacterDirectionsBuffer + previousLogical );
+    isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + characterIndex );
+    isNextRightToLeft = *( modelCharacterDirectionsBuffer + nextCharacterIndex );
   }
 
   // Get the line where the character is laid-out.
   }
 
   // Get the line where the character is laid-out.
-  const LineRun* modelLines = mVisualModel->mLines.Begin();
+  const LineRun* const modelLines = mVisualModel->mLines.Begin();
 
 
-  const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( logical );
+  const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( characterIndex );
   const LineRun& line = *( modelLines + lineIndex );
 
   // Get the paragraph's direction.
   const LineRun& line = *( modelLines + lineIndex );
 
   // Get the paragraph's direction.
@@ -894,123 +1504,149 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 
   // Check whether there is an alternative position:
 
 
   // Check whether there is an alternative position:
 
-  cursorInfo.isSecondaryCursor = ( isCurrentRightToLeft != isPreviousRightToLeft ) ||
-    ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
+  cursorInfo.isSecondaryCursor = ( !isLastPosition && ( isCurrentRightToLeft != isNextRightToLeft ) ) ||
+                                 ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
 
   // Set the line height.
   cursorInfo.lineHeight = line.ascender + -line.descender;
 
 
   // Set the line height.
   cursorInfo.lineHeight = line.ascender + -line.descender;
 
-  // Convert the cursor position into the glyph position.
-  CharacterIndex characterIndex = logical;
-  if( cursorInfo.isSecondaryCursor &&
-      ( isRightToLeftParagraph != isCurrentRightToLeft ) )
+  // Calculate the primary cursor.
+
+  CharacterIndex index = characterIndex;
+  if( cursorInfo.isSecondaryCursor )
   {
   {
-    characterIndex = previousLogical;
+    // If there is a secondary position, the primary cursor may be in a different place than the logical index.
+
+    if( isLastPosition )
+    {
+      // The position of the cursor after the last character needs special
+      // care depending on its direction and the direction of the paragraph.
+
+      // Need to find the first character after the last character with the paragraph's direction.
+      // i.e l0 l1 l2 r0 r1 should find r0.
+
+      // TODO: check for more than one line!
+      index = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
+      index = mLogicalModel->GetLogicalCharacterIndex( index );
+    }
+    else
+    {
+      index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? characterIndex : nextCharacterIndex;
+    }
   }
 
   }
 
-  const GlyphIndex currentGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
-  const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
-  const Length numberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() +currentGlyphIndex );
+  const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+  const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+  const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+  const CharacterIndex* const glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
+  const Vector2* const glyphPositionsBuffer = mVisualModel->mGlyphPositions.Begin();
+
+  // Convert the cursor position into the glyph position.
+  const GlyphIndex primaryGlyphIndex = *( charactersToGlyphBuffer + index );
+  const Length primaryNumberOfGlyphs = *( glyphsPerCharacterBuffer + index );
+  const Length primaryNumberOfCharacters = *( charactersPerGlyphBuffer + primaryGlyphIndex );
 
   // Get the metrics for the group of glyphs.
   GlyphMetrics glyphMetrics;
 
   // Get the metrics for the group of glyphs.
   GlyphMetrics glyphMetrics;
-  GetGlyphsMetrics( currentGlyphIndex,
-                    numberOfGlyphs,
+  GetGlyphsMetrics( primaryGlyphIndex,
+                    primaryNumberOfGlyphs,
                     glyphMetrics,
                     mVisualModel,
                     mFontClient );
 
                     glyphMetrics,
                     mVisualModel,
                     mFontClient );
 
-  float interGlyphAdvance = 0.f;
+  // Whether to add the glyph's advance to the cursor position.
+  // i.e if the paragraph is left to right and the logical cursor is zero, the position is the position of the first glyph and the advance is not added,
+  //     if the logical cursor is one, the position is the position of the first glyph and the advance is added.
+  // A 'truth table' was build and an online Karnaugh map tool was used to simplify the logic.
+  //
+  // FLCP A
+  // ------
+  // 0000 1
+  // 0001 1
+  // 0010 0
+  // 0011 0
+  // 0100 1
+  // 0101 0
+  // 0110 1
+  // 0111 0
+  // 1000 0
+  // 1001 x
+  // 1010 x
+  // 1011 1
+  // 1100 x
+  // 1101 x
+  // 1110 x
+  // 1111 x
+  //
+  // Where F -> isFirstPosition
+  //       L -> isLastPosition
+  //       C -> isCurrentRightToLeft
+  //       P -> isRightToLeftParagraph
+  //       A -> Whether to add the glyph's advance.
+
+  const bool addGlyphAdvance = ( ( isLastPosition && !isRightToLeftParagraph ) ||
+                                 ( isFirstPosition && isRightToLeftParagraph ) ||
+                                 ( !isFirstPosition && !isLastPosition && !isCurrentRightToLeft ) );
+
+  float glyphAdvance = addGlyphAdvance ? glyphMetrics.advance : 0.f;
+
   if( !isLastPosition &&
   if( !isLastPosition &&
-      ( numberOfCharacters > 1u ) )
+      ( primaryNumberOfCharacters > 1u ) )
   {
   {
-    const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + currentGlyphIndex );
-    interGlyphAdvance = static_cast<float>( characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( numberOfCharacters );
-  }
+    const CharacterIndex firstIndex = *( glyphsToCharactersBuffer + primaryGlyphIndex );
 
 
-  // Get the glyph position and x bearing.
-  const Vector2& currentPosition = *( mVisualModel->mGlyphPositions.Begin() + currentGlyphIndex );
-
-  // Set the cursor's height.
-  cursorInfo.primaryCursorHeight = glyphMetrics.fontHeight;
-
-  // Set the position.
-  cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + currentPosition.x + ( isCurrentRightToLeft ? glyphMetrics.advance : interGlyphAdvance );
-  cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
-
-  if( isLastPosition )
-  {
-    // The position of the cursor after the last character needs special
-    // care depending on its direction and the direction of the paragraph.
+    bool isCurrentRightToLeft = false;
+    if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+    {
+      isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + index );
+    }
 
 
-    if( cursorInfo.isSecondaryCursor )
+    Length numberOfGlyphAdvance = ( isFirstPosition ? 0u : 1u ) + characterIndex - firstIndex;
+    if( isCurrentRightToLeft )
     {
     {
-      // Need to find the first character after the last character with the paragraph's direction.
-      // i.e l0 l1 l2 r0 r1 should find r0.
+      numberOfGlyphAdvance = primaryNumberOfCharacters - numberOfGlyphAdvance;
+    }
 
 
-      // TODO: check for more than one line!
-      characterIndex = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
-      characterIndex = mLogicalModel->GetLogicalCharacterIndex( characterIndex );
+    glyphAdvance = static_cast<float>( numberOfGlyphAdvance ) * glyphMetrics.advance / static_cast<float>( primaryNumberOfCharacters );
+  }
+
+  // Get the glyph position and x bearing.
+  const Vector2& primaryPosition = *( glyphPositionsBuffer + primaryGlyphIndex );
 
 
-      const GlyphIndex glyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
-      const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
+  // Set the primary cursor's height.
+  cursorInfo.primaryCursorHeight = cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight;
 
 
-      const Vector2& position = *( mVisualModel->mGlyphPositions.Begin() + glyphIndex );
+  // Set the primary cursor's position.
+  cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + primaryPosition.x + glyphAdvance;
+  cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
 
 
-      // Get the metrics for the group of glyphs.
-      GlyphMetrics glyphMetrics;
-      GetGlyphsMetrics( glyphIndex,
-                        numberOfGlyphs,
-                        glyphMetrics,
-                        mVisualModel,
-                        mFontClient );
+  // Calculate the secondary cursor.
 
 
-      cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + position.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
+  if( cursorInfo.isSecondaryCursor )
+  {
+    // Set the secondary cursor's height.
+    cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
 
 
-      cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
-    }
-    else
+    CharacterIndex index = characterIndex;
+    if( !isLastPosition )
     {
     {
-      if( !isCurrentRightToLeft )
-      {
-        cursorInfo.primaryPosition.x += glyphMetrics.advance;
-      }
-      else
-      {
-        cursorInfo.primaryPosition.x -= glyphMetrics.advance;
-      }
+      index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? nextCharacterIndex : characterIndex;
     }
     }
-  }
 
 
-  // Set the alternative cursor position.
-  if( cursorInfo.isSecondaryCursor )
-  {
-    // Convert the cursor position into the glyph position.
-    const CharacterIndex previousCharacterIndex = ( ( isRightToLeftParagraph != isCurrentRightToLeft ) ? logical : previousLogical );
-    const GlyphIndex previousGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + previousCharacterIndex );
-    const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + previousCharacterIndex );
+    const GlyphIndex secondaryGlyphIndex = *( charactersToGlyphBuffer + index );
+    const Length secondaryNumberOfGlyphs = *( glyphsPerCharacterBuffer + index );
 
 
-    // Get the glyph position.
-    const Vector2& previousPosition = *( mVisualModel->mGlyphPositions.Begin() + previousGlyphIndex );
+    const Vector2& secondaryPosition = *( glyphPositionsBuffer + secondaryGlyphIndex );
 
 
-    // Get the metrics for the group of glyphs.
-    GlyphMetrics glyphMetrics;
-    GetGlyphsMetrics( previousGlyphIndex,
-                      numberOfGlyphs,
+    GetGlyphsMetrics( secondaryGlyphIndex,
+                      secondaryNumberOfGlyphs,
                       glyphMetrics,
                       mVisualModel,
                       mFontClient );
 
                       glyphMetrics,
                       mVisualModel,
                       mFontClient );
 
-    // Set the cursor position and height.
-    cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + previousPosition.x + ( ( ( isLastPosition && !isCurrentRightToLeft ) ||
-                                                                                       ( !isLastPosition && isCurrentRightToLeft )    ) ? glyphMetrics.advance : 0.f );
-
-    cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
-
+    // Set the secondary cursor's position.
+    cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + secondaryPosition.x + ( isCurrentRightToLeft ? 0.f : glyphMetrics.advance );
     cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
     cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
-
-    // Update the primary cursor height as well.
-    cursorInfo.primaryCursorHeight *= 0.5f;
   }
 }
 
   }
 }
 
@@ -1024,25 +1660,27 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index )
 
   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
 
 
   CharacterIndex cursorIndex = mEventData->mPrimaryCursorPosition;
 
-  const Script script = mLogicalModel->GetScript( index );
-  const GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
-  const Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+  const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+  const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+
+  GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
+  Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
 
 
-  Length numberOfCharacters = 0u;
-  if( TextAbstraction::LATIN == script )
+  if( numberOfCharacters > 1u )
   {
   {
-    // Prevents to jump the whole Latin ligatures like fi, ff, ...
-    numberOfCharacters = 1u;
+    const Script script = mLogicalModel->GetScript( index );
+    if( HasLigatureMustBreak( script ) )
+    {
+      // Prevents to jump the whole Latin ligatures like fi, ff, or Arabic ﻻ,  ...
+      numberOfCharacters = 1u;
+    }
   }
   else
   {
   }
   else
   {
-    GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
-    numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
-
     while( 0u == numberOfCharacters )
     {
     while( 0u == numberOfCharacters )
     {
-      numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
       ++glyphIndex;
       ++glyphIndex;
+      numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
     }
   }
 
     }
   }
 
@@ -1068,40 +1706,116 @@ void Controller::Impl::UpdateCursorPosition()
     return;
   }
 
     return;
   }
 
-  CursorInfo cursorInfo;
-  GetCursorPosition( mEventData->mPrimaryCursorPosition,
-                     cursorInfo );
+  if( IsShowingPlaceholderText() )
+  {
+    // Do not want to use the place-holder text to set the cursor position.
 
 
-  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
-  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+    // Use the line's height of the font's family set to set the cursor's size.
+    // If there is no font's family set, use the default font.
+    // Use the current alignment to place the cursor at the beginning, center or end of the box.
 
 
-  // Sets the cursor position.
-  mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                       cursorPosition.x,
-                                       cursorPosition.y,
-                                       cursorInfo.primaryCursorHeight,
-                                       cursorInfo.lineHeight );
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
+    float lineHeight = 0.f;
 
 
-  // Sets the grab handle position.
-  mEventData->mDecorator->SetPosition( GRAB_HANDLE,
-                                       cursorPosition.x,
-                                       cursorPosition.y,
-                                       cursorInfo.lineHeight );
+    FontId defaultFontId = 0u;
+    if( NULL == mFontDefaults )
+    {
+      defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
+                                             EMPTY_STRING );
+    }
+    else
+    {
+      defaultFontId = mFontDefaults->GetFontId( mFontClient );
+    }
 
 
-  if( cursorInfo.isSecondaryCursor )
-  {
-    mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
-    mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
-                                         cursorInfo.secondaryPosition.x + offset.x,
-                                         cursorInfo.secondaryPosition.y + offset.y,
-                                         cursorInfo.secondaryCursorHeight,
-                                         cursorInfo.lineHeight );
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
+    Text::FontMetrics fontMetrics;
+    mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
+
+    lineHeight = fontMetrics.ascender - fontMetrics.descender;
+
+
+    Vector2 cursorPosition;
+
+    switch( mLayoutEngine.GetHorizontalAlignment() )
+    {
+      case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
+      {
+        cursorPosition.x = 1.f;
+        break;
+      }
+      case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
+      {
+        cursorPosition.x = floor( 0.5f * mVisualModel->mControlSize.width );
+        break;
+      }
+      case LayoutEngine::HORIZONTAL_ALIGN_END:
+      {
+        cursorPosition.x = mVisualModel->mControlSize.width;
+        break;
+      }
+    }
+
+    switch( mLayoutEngine.GetVerticalAlignment() )
+    {
+      case LayoutEngine::VERTICAL_ALIGN_TOP:
+      {
+        cursorPosition.y = 0.f;
+        break;
+      }
+      case LayoutEngine::VERTICAL_ALIGN_CENTER:
+      {
+        cursorPosition.y = floorf( 0.5f * ( mVisualModel->mControlSize.height - lineHeight ) );
+        break;
+      }
+      case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
+      {
+        cursorPosition.y = mVisualModel->mControlSize.height - lineHeight;
+        break;
+      }
+    }
+
+    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+                                         cursorPosition.x,
+                                         cursorPosition.y,
+                                         lineHeight,
+                                         lineHeight );
   }
   else
   {
   }
   else
   {
-    mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+    CursorInfo cursorInfo;
+    GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                       cursorInfo );
+
+    const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+    const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+
+    // Sets the cursor position.
+    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+                                         cursorPosition.x,
+                                         cursorPosition.y,
+                                         cursorInfo.primaryCursorHeight,
+                                         cursorInfo.lineHeight );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
+
+    // Sets the grab handle position.
+    mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+                                         cursorPosition.x,
+                                         cursorPosition.y,
+                                         cursorInfo.lineHeight );
+
+    if( cursorInfo.isSecondaryCursor )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
+      mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+                                           cursorInfo.secondaryPosition.x + offset.x,
+                                           cursorInfo.secondaryPosition.y + offset.y,
+                                           cursorInfo.secondaryCursorHeight,
+                                           cursorInfo.lineHeight );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
+    }
+    else
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+    }
   }
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
 }
   }
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
 }
@@ -1129,14 +1843,19 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
                                        cursorPosition.x,
                                        cursorPosition.y,
                                        cursorInfo.lineHeight );
                                        cursorPosition.x,
                                        cursorPosition.y,
                                        cursorInfo.lineHeight );
+
+  // If selection handle at start of the text and other at end of the text then all text is selected.
+  const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
+  const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
+  mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mLogicalModel->mText.Count() );
 }
 
 void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
 }
 
 void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
-  if( actualSize.width > mControlSize.width )
+  if( actualSize.width > mVisualModel->mControlSize.width )
   {
   {
-    const float space = ( actualSize.width - mControlSize.width ) + mAlignmentOffset.x;
+    const float space = ( actualSize.width - mVisualModel->mControlSize.width ) + mAlignmentOffset.x;
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
 
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
 
@@ -1151,9 +1870,9 @@ void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
 void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
 void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
-  if( actualSize.height > mControlSize.height )
+  if( actualSize.height > mVisualModel->mControlSize.height )
   {
   {
-    const float space = ( actualSize.height - mControlSize.height ) + mAlignmentOffset.y;
+    const float space = ( actualSize.height - mVisualModel->mControlSize.height ) + mAlignmentOffset.y;
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
 
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
 
@@ -1165,27 +1884,19 @@ void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
   }
 }
 
   }
 }
 
-void Controller::Impl::ScrollToMakeCursorVisible()
+void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position )
 {
 {
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
-
   Vector2 offset;
   bool updateDecorator = false;
   Vector2 offset;
   bool updateDecorator = false;
-  if( primaryCursorPosition.x < 0.f )
+  if( position.x < 0.f )
   {
   {
-    offset.x = -primaryCursorPosition.x;
+    offset.x = -position.x;
     mEventData->mScrollPosition.x += offset.x;
     updateDecorator = true;
   }
     mEventData->mScrollPosition.x += offset.x;
     updateDecorator = true;
   }
-  else if( primaryCursorPosition.x > mControlSize.width )
+  else if( position.x > mVisualModel->mControlSize.width )
   {
   {
-    offset.x = mControlSize.width - primaryCursorPosition.x;
+    offset.x = mVisualModel->mControlSize.width - position.x;
     mEventData->mScrollPosition.x += offset.x;
     updateDecorator = true;
   }
     mEventData->mScrollPosition.x += offset.x;
     updateDecorator = true;
   }
@@ -1198,6 +1909,67 @@ void Controller::Impl::ScrollToMakeCursorVisible()
   // TODO : calculate the vertical scroll.
 }
 
   // TODO : calculate the vertical scroll.
 }
 
+void Controller::Impl::ScrollTextToMatchCursor()
+{
+  // Get the current cursor position in decorator coords.
+  const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+  // Calculate the new cursor position.
+  CursorInfo cursorInfo;
+  GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                     cursorInfo );
+
+  // Calculate the offset to match the cursor position before the character was deleted.
+  mEventData->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x - mAlignmentOffset.x;
+
+  ClampHorizontalScroll( mVisualModel->GetActualSize() );
+
+  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+
+  // Sets the cursor position.
+  mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
+                                       cursorInfo.primaryCursorHeight,
+                                       cursorInfo.lineHeight );
+
+  // Sets the grab handle position.
+  mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
+                                       cursorInfo.lineHeight );
+
+  if( cursorInfo.isSecondaryCursor )
+  {
+    mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+                                         cursorInfo.secondaryPosition.x + offset.x,
+                                         cursorInfo.secondaryPosition.y + offset.y,
+                                         cursorInfo.secondaryCursorHeight,
+                                         cursorInfo.lineHeight );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
+  }
+
+  // Set which cursors are active according the state.
+  if( ( EventData::EDITING == mEventData->mState ) ||
+      ( EventData::EDITING_WITH_POPUP == mEventData->mState ) ||
+      ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
+  {
+    if( cursorInfo.isSecondaryCursor )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
+    }
+    else
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+    }
+  }
+  else
+  {
+    mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+  }
+}
+
 void Controller::Impl::RequestRelayout()
 {
   mControlInterface.RequestTextRelayout();
 void Controller::Impl::RequestRelayout()
 {
   mControlInterface.RequestTextRelayout();