Reposition the text's popup when the text is scrolled.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
index f41bddd..9637245 100644 (file)
 // EXTERNAL INCLUDES
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/integration-api/debug.h>
 // EXTERNAL INCLUDES
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/integration-api/debug.h>
+#include <limits>
 
 // 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/color-segmentation.h>
+#include <dali-toolkit/internal/text/cursor-helper-functions.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>
+#include <dali-toolkit/internal/text/text-run-container.h>
 
 namespace
 {
 
 
 namespace
 {
 
-#if defined(DEBUG_ENABLED)
-  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
-#endif
-
 /**
 /**
- * @brief Some characters can be shaped in more than one glyph.
- * This struct is used to retrieve metrics from these group of glyphs.
+ * @brief Struct used to calculate the selection box.
  */
  */
-struct GlyphMetrics
+struct SelectionBoxInfo
 {
 {
-  GlyphMetrics()
-  : fontHeight( 0.f ),
-    advance( 0.f ),
-    ascender( 0.f ),
-    xBearing( 0.f )
-  {}
-
-  ~GlyphMetrics()
-  {}
-
-  float fontHeight; ///< The font's height of that glyphs.
-  float advance;    ///< The sum of all the advances of all the glyphs.
-  float ascender;   ///< The font's ascender.
-  float xBearing;   ///< The x bearing of the first glyph.
+  float lineOffset;
+  float lineHeight;
+  float minX;
+  float maxX;
 };
 
 };
 
-const std::string EMPTY_STRING("");
+#if defined(DEBUG_ENABLED)
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+#endif
+
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+const float MIN_FLOAT = std::numeric_limits<float>::min();
+const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
 
 } // namespace
 
 
 } // namespace
 
@@ -75,54 +66,20 @@ namespace Toolkit
 namespace Text
 {
 
 namespace Text
 {
 
-/**
- * @brief Get some glyph's metrics of a group of glyphs formed as a result of shaping one character.
- *
- * @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]
- */
-void GetGlyphsMetrics( GlyphIndex glyphIndex,
-                       Length numberOfGlyphs,
-                       GlyphMetrics& glyphMetrics,
-                       VisualModelPtr visualModel,
-                       TextAbstraction::FontClient& fontClient )
-{
-  const GlyphInfo* glyphsBuffer = visualModel->mGlyphs.Begin();
-
-  const GlyphInfo& firstGlyph = *( glyphsBuffer + glyphIndex );
-
-  Text::FontMetrics fontMetrics;
-  fontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
-
-  glyphMetrics.fontHeight = fontMetrics.height;
-  glyphMetrics.advance = firstGlyph.advance;
-  glyphMetrics.ascender = fontMetrics.ascender;
-  glyphMetrics.xBearing = firstGlyph.xBearing;
-
-  for( unsigned int i = 1u; i < numberOfGlyphs; ++i )
-  {
-    const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i );
-
-    glyphMetrics.advance += glyphInfo.advance;
-  }
-}
-
 EventData::EventData( DecoratorPtr decorator )
 : mDecorator( decorator ),
 EventData::EventData( DecoratorPtr decorator )
 : mDecorator( decorator ),
+  mImfManager(),
   mPlaceholderTextActive(),
   mPlaceholderTextInactive(),
   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
   mEventQueue(),
   mPlaceholderTextActive(),
   mPlaceholderTextInactive(),
   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
   mEventQueue(),
-  mScrollPosition(),
   mState( INACTIVE ),
   mPrimaryCursorPosition( 0u ),
   mLeftSelectionPosition( 0u ),
   mRightSelectionPosition( 0u ),
   mPreEditStartPosition( 0u ),
   mPreEditLength( 0u ),
   mState( INACTIVE ),
   mPrimaryCursorPosition( 0u ),
   mLeftSelectionPosition( 0u ),
   mRightSelectionPosition( 0u ),
   mPreEditStartPosition( 0u ),
   mPreEditLength( 0u ),
+  mCursorHookPositionX( 0.f ),
   mIsShowingPlaceholderText( false ),
   mPreEditFlag( false ),
   mDecoratorUpdated( false ),
   mIsShowingPlaceholderText( false ),
   mPreEditFlag( false ),
   mDecoratorUpdated( false ),
@@ -130,14 +87,19 @@ EventData::EventData( DecoratorPtr decorator )
   mGrabHandleEnabled( true ),
   mGrabHandlePopupEnabled( true ),
   mSelectionEnabled( true ),
   mGrabHandleEnabled( true ),
   mGrabHandlePopupEnabled( true ),
   mSelectionEnabled( true ),
-  mHorizontalScrollingEnabled( true ),
-  mVerticalScrollingEnabled( false ),
   mUpdateCursorPosition( false ),
   mUpdateCursorPosition( false ),
+  mUpdateGrabHandlePosition( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
+  mIsLeftHandleSelected( false ),
+  mUpdateHighlightBox( false ),
   mScrollAfterUpdatePosition( false ),
   mScrollAfterUpdatePosition( false ),
-  mScrollAfterDelete( false )
-{}
+  mScrollAfterDelete( false ),
+  mAllTextSelected( false ),
+  mUpdateInputStyle( false )
+{
+  mImfManager = ImfManager::Get();
+}
 
 EventData::~EventData()
 {}
 
 EventData::~EventData()
 {}
@@ -160,97 +122,156 @@ bool Controller::Impl::ProcessInputEvents()
     {
       switch( iter->type )
       {
     {
       switch( iter->type )
       {
-      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;
+        }
       }
     }
   }
 
       }
     }
   }
 
+  if( mEventData->mUpdateCursorPosition ||
+      mEventData->mUpdateHighlightBox )
+  {
+    NotifyImfManager();
+  }
+
   // The cursor must also be repositioned after inserts into the model
   if( mEventData->mUpdateCursorPosition )
   {
     // Updates the cursor position and scrolls the text to make it visible.
   // The cursor must also be repositioned after inserts into the model
   if( mEventData->mUpdateCursorPosition )
   {
     // Updates the cursor position and scrolls the text to make it visible.
+    CursorInfo cursorInfo;
+    // Calculate the cursor position from the new cursor index.
+    GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                       cursorInfo );
+
+    if( mEventData->mUpdateCursorHookPosition )
+    {
+      // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
+      mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
+      mEventData->mUpdateCursorHookPosition = false;
+    }
 
 
-    UpdateCursorPosition();
+    // Scroll first the text after delete ...
+    if( mEventData->mScrollAfterDelete )
+    {
+      ScrollTextToMatchCursor( cursorInfo );
+    }
 
 
+    // ... then, text can be scrolled to make the cursor visible.
     if( mEventData->mScrollAfterUpdatePosition )
     {
     if( mEventData->mScrollAfterUpdatePosition )
     {
-      const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
-
-      ScrollToMakePositionVisible( primaryCursorPosition );
-      mEventData->mScrollAfterUpdatePosition = false;
+      const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
+      ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
     }
     }
+    mEventData->mScrollAfterUpdatePosition = false;
+    mEventData->mScrollAfterDelete = false;
+
+    UpdateCursorPosition( cursorInfo );
 
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
 
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
-  }
-  else if( mEventData->mScrollAfterDelete )
-  {
-    ScrollTextToMatchCursor();
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mScrollAfterDelete = false;
+    mEventData->mUpdateGrabHandlePosition = false;
   }
   else
   {
   }
   else
   {
-    bool leftScroll = false;
-    bool rightScroll = false;
+    CursorInfo leftHandleInfo;
+    CursorInfo rightHandleInfo;
 
 
-    if( mEventData->mUpdateLeftSelectionPosition )
+    if( mEventData->mUpdateHighlightBox )
     {
     {
-      UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
+      GetCursorPosition( mEventData->mLeftSelectionPosition,
+                         leftHandleInfo );
 
 
-      if( mEventData->mScrollAfterUpdatePosition )
+      GetCursorPosition( mEventData->mRightSelectionPosition,
+                         rightHandleInfo );
+
+      if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
       {
       {
-        const Vector2& leftHandlePosition = mEventData->mDecorator->GetPosition( LEFT_SELECTION_HANDLE );
+        CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
 
 
-        ScrollToMakePositionVisible( leftHandlePosition );
-        leftScroll = true;
+        const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
+        ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
       }
       }
+    }
+
+    if( mEventData->mUpdateLeftSelectionPosition )
+    {
+      UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
+                             leftHandleInfo );
 
 
+      SetPopupButtons();
       mEventData->mDecoratorUpdated = true;
       mEventData->mUpdateLeftSelectionPosition = false;
     }
 
     if( mEventData->mUpdateRightSelectionPosition )
     {
       mEventData->mDecoratorUpdated = true;
       mEventData->mUpdateLeftSelectionPosition = false;
     }
 
     if( mEventData->mUpdateRightSelectionPosition )
     {
-      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
-
-      if( mEventData->mScrollAfterUpdatePosition )
-      {
-        const Vector2& rightHandlePosition = mEventData->mDecorator->GetPosition( RIGHT_SELECTION_HANDLE );
-
-        ScrollToMakePositionVisible( rightHandlePosition );
-        rightScroll = true;
-      }
+      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
+                             rightHandleInfo );
 
 
+      SetPopupButtons();
       mEventData->mDecoratorUpdated = true;
       mEventData->mUpdateRightSelectionPosition = false;
     }
 
       mEventData->mDecoratorUpdated = true;
       mEventData->mUpdateRightSelectionPosition = false;
     }
 
-    if( leftScroll || rightScroll )
+    if( mEventData->mUpdateHighlightBox )
     {
     {
-      mEventData->mScrollAfterUpdatePosition = false;
+      RepositionSelectionHandles();
+
+      mEventData->mUpdateLeftSelectionPosition = false;
+      mEventData->mUpdateRightSelectionPosition = false;
+      mEventData->mUpdateHighlightBox = false;
     }
     }
+
+    mEventData->mScrollAfterUpdatePosition = false;
+  }
+
+  if( mEventData->mUpdateInputStyle )
+  {
+    // Set the default style first.
+    RetrieveDefaultInputStyle( mEventData->mInputStyle );
+
+    // Get the character index from the cursor index.
+    const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
+
+    // Retrieve the style from the style runs stored in the logical model.
+    mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
+
+    mEventData->mUpdateInputStyle = false;
   }
 
   mEventData->mEventQueue.clear();
   }
 
   mEventData->mEventQueue.clear();
@@ -263,245 +284,989 @@ bool Controller::Impl::ProcessInputEvents()
   return decoratorUpdated;
 }
 
   return decoratorUpdated;
 }
 
-void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
+void Controller::Impl::NotifyImfManager()
 {
 {
-  // Calculate the operations to be done.
-  const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
-
-  Vector<Character>& utf32Characters = mLogicalModel->mText;
+  if( mEventData && mEventData->mImfManager )
+  {
+    CharacterIndex cursorPosition = GetLogicalCursorPosition();
 
 
-  const Length numberOfCharacters = utf32Characters.Count();
+    const Length numberOfWhiteSpaces = GetNumberOfWhiteSpaces( 0u );
 
 
-  Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
-  if( GET_LINE_BREAKS & operations )
-  {
-    // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
-    // calculate the bidirectional info for each 'paragraph'.
-    // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
-    // is not shaped together).
-    lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
+    // Update the cursor position by removing the initial white spaces.
+    if( cursorPosition < numberOfWhiteSpaces )
+    {
+      cursorPosition = 0u;
+    }
+    else
+    {
+      cursorPosition -= numberOfWhiteSpaces;
+    }
 
 
-    SetLineBreakInfo( utf32Characters,
-                      lineBreakInfo );
+    mEventData->mImfManager.SetCursorPosition( cursorPosition );
+    mEventData->mImfManager.NotifyCursorPosition();
   }
   }
+}
 
 
-  Vector<WordBreakInfo>& wordBreakInfo = mLogicalModel->mWordBreakInfo;
-  if( GET_WORD_BREAKS & operations )
-  {
-    // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
-    wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
+CharacterIndex Controller::Impl::GetLogicalCursorPosition() const
+{
+  CharacterIndex cursorPosition = 0u;
 
 
-    SetWordBreakInfo( utf32Characters,
-                      wordBreakInfo );
+  if( mEventData )
+  {
+    if( ( EventData::SELECTING == mEventData->mState ) ||
+        ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState ) )
+    {
+      cursorPosition = std::min( mEventData->mRightSelectionPosition, mEventData->mLeftSelectionPosition );
+    }
+    else
+    {
+      cursorPosition = mEventData->mPrimaryCursorPosition;
+    }
   }
 
   }
 
-  const bool getScripts = GET_SCRIPTS & operations;
-  const bool validateFonts = VALIDATE_FONTS & operations;
+  return cursorPosition;
+}
 
 
-  Vector<ScriptRun>& scripts = mLogicalModel->mScriptRuns;
-  Vector<FontRun>& validFonts = mLogicalModel->mFontRuns;
+Length Controller::Impl::GetNumberOfWhiteSpaces( CharacterIndex index ) const
+{
+  Length numberOfWhiteSpaces = 0u;
 
 
-  if( getScripts || validateFonts )
-  {
-    // Validates the fonts assigned by the application or assigns default ones.
-    // It makes sure all the characters are going to be rendered by the correct font.
-    MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+  // Get the buffer to the text.
+  Character* utf32CharacterBuffer = mLogicalModel->mText.Begin();
 
 
-    if( getScripts )
+  const Length totalNumberOfCharacters = mLogicalModel->mText.Count();
+  for( ; index < totalNumberOfCharacters; ++index, ++numberOfWhiteSpaces )
+  {
+    if( !TextAbstraction::IsWhiteSpace( *( utf32CharacterBuffer + index ) ) )
     {
     {
-      // Retrieves the scripts used in the text.
-      multilanguageSupport.SetScripts( utf32Characters,
-                                       lineBreakInfo,
-                                       scripts );
+      break;
     }
     }
+  }
 
 
-    if( validateFonts )
-    {
-      if( 0u == validFonts.Count() )
-      {
-        // Copy the requested font defaults received via the property system.
-        // These may not be valid i.e. may not contain glyphs for the necessary scripts.
-        GetDefaultFonts( validFonts, numberOfCharacters );
-      }
+  return numberOfWhiteSpaces;
+}
 
 
-      // Validates the fonts. If there is a character with no assigned font it sets a default one.
-      // After this call, fonts are validated.
-      multilanguageSupport.ValidateFonts( utf32Characters,
-                                          scripts,
-                                          validFonts );
-    }
-  }
+void Controller::Impl::GetText( CharacterIndex index, std::string& text ) const
+{
+  // Get the total number of characters.
+  Length numberOfCharacters = mLogicalModel->mText.Count();
 
 
-  Vector<Character> mirroredUtf32Characters;
-  bool textMirrored = false;
-  if( BIDI_INFO & operations )
+  // Retrieve the text.
+  if( 0u != numberOfCharacters )
   {
   {
-    // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
-    // bidirectional info.
+    Utf32ToUtf8( mLogicalModel->mText.Begin() + index, numberOfCharacters - index, text );
+  }
+}
 
 
-    Length numberOfParagraphs = 0u;
+void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
+{
+  mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+  mTextUpdateInfo.mStartGlyphIndex = 0u;
+  mTextUpdateInfo.mStartLineIndex = 0u;
+  numberOfCharacters = 0u;
 
 
-    const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
-    for( Length index = 0u; index < numberOfCharacters; ++index )
-    {
-      if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
-      {
-        ++numberOfParagraphs;
-      }
-    }
+  const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
+  if( 0u == numberOfParagraphs )
+  {
+    mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    numberOfCharacters = 0u;
 
 
-    Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
-    bidirectionalInfo.Reserve( numberOfParagraphs );
+    mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
 
 
-    // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
-    SetBidirectionalInfo( utf32Characters,
-                          scripts,
-                          lineBreakInfo,
-                          bidirectionalInfo );
+    // Nothing else to do if there are no paragraphs.
+    return;
+  }
 
 
-    if( 0u != bidirectionalInfo.Count() )
+  // Find the paragraphs to be updated.
+  Vector<ParagraphRunIndex> paragraphsToBeUpdated;
+  if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
+  {
+    // Text is being added at the end of the current text.
+    if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
     {
     {
-      // 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.
+      // Text is being added in a new paragraph after the last character of the text.
+      mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+      numberOfCharacters = 0u;
+      mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
 
 
-      textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
+      mTextUpdateInfo.mStartGlyphIndex = mVisualModel->mGlyphs.Count();
+      mTextUpdateInfo.mStartLineIndex = mVisualModel->mLines.Count() - 1u;
 
 
-      // Only set the character directions if there is right to left characters.
-      Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
-      directions.Resize( numberOfCharacters );
+      // Nothing else to do;
+      return;
+    }
 
 
-      GetCharactersDirection( bidirectionalInfo,
-                              directions );
+    paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
+  }
+  else
+  {
+    Length numberOfCharactersToUpdate = 0u;
+    if( mTextUpdateInfo.mFullRelayoutNeeded )
+    {
+      numberOfCharactersToUpdate = mTextUpdateInfo.mPreviousNumberOfCharacters;
     }
     else
     {
     }
     else
     {
-      // There is no right to left characters. Clear the directions vector.
-      mLogicalModel->mCharacterDirections.Clear();
+      numberOfCharactersToUpdate = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
     }
     }
+    mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
+                                   numberOfCharactersToUpdate,
+                                   paragraphsToBeUpdated );
+  }
 
 
-   }
-
-  Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
-  Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
-  Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
-  if( SHAPE_TEXT & operations )
+  if( 0u != paragraphsToBeUpdated.Count() )
   {
   {
-    const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
-    // Shapes the text.
-    ShapeText( textToShape,
-               lineBreakInfo,
-               scripts,
-               validFonts,
-               glyphs,
-               glyphsToCharactersMap,
-               charactersPerGlyph );
+    const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
+    const ParagraphRun& firstParagraph = *( mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
+    mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
 
 
-    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-    mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
-    mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
-  }
+    ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
+    const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
 
 
-  const Length numberOfGlyphs = glyphs.Count();
+    if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
+        ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
+        ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
+          ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
+    {
+      // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
+      const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
 
 
-  if( GET_GLYPH_METRICS & operations )
-  {
-    mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
+      numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+    }
+    else
+    {
+      numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+    }
   }
   }
+
+  mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+  mTextUpdateInfo.mStartGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
 }
 
 }
 
-void Controller::Impl::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
+void Controller::Impl::ClearFullModelData( OperationsMask operations )
 {
 {
-  if( mFontDefaults )
+  if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
   {
   {
-    FontRun fontRun;
-    fontRun.characterRun.characterIndex = 0;
-    fontRun.characterRun.numberOfCharacters = numberOfCharacters;
-    fontRun.fontId = mFontDefaults->GetFontId( mFontClient );
-    fontRun.isDefault = true;
+    mLogicalModel->mLineBreakInfo.Clear();
+    mLogicalModel->mParagraphInfo.Clear();
+  }
 
 
-    fonts.PushBack( fontRun );
+  if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
+  {
+    mLogicalModel->mLineBreakInfo.Clear();
   }
   }
-}
 
 
-void Controller::Impl::OnCursorKeyEvent( const Event& event )
-{
-  if( NULL == mEventData )
+  if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
   {
   {
-    // Nothing to do if there is no text input.
-    return;
+    mLogicalModel->mScriptRuns.Clear();
   }
 
   }
 
-  int keyCode = event.p1.mInt;
+  if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
+  {
+    mLogicalModel->mFontRuns.Clear();
+  }
 
 
-  if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
+  if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
   {
   {
-    if( mEventData->mPrimaryCursorPosition > 0u )
+    if( NO_OPERATION != ( BIDI_INFO & operations ) )
     {
     {
-      mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
+      mLogicalModel->mBidirectionalParagraphInfo.Clear();
+      mLogicalModel->mCharacterDirections.Clear();
     }
     }
-  }
-  else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
-  {
-    if( mLogicalModel->GetNumberOfCharacters() > mEventData->mPrimaryCursorPosition )
+
+    if( NO_OPERATION != ( REORDER & operations ) )
     {
     {
-      mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for( Vector<BidirectionalLineInfoRun>::Iterator it = mLogicalModel->mBidirectionalLineInfo.Begin(),
+             endIt = mLogicalModel->mBidirectionalLineInfo.End();
+           it != endIt;
+           ++it )
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free( bidiLineInfo.visualToLogicalMap );
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+      mLogicalModel->mBidirectionalLineInfo.Clear();
     }
   }
     }
   }
-  else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
+
+  if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
   {
   {
-    // TODO
+    mVisualModel->mGlyphs.Clear();
+    mVisualModel->mGlyphsToCharacters.Clear();
+    mVisualModel->mCharactersToGlyph.Clear();
+    mVisualModel->mCharactersPerGlyph.Clear();
+    mVisualModel->mGlyphsPerCharacter.Clear();
+    mVisualModel->mGlyphPositions.Clear();
   }
   }
-  else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
+
+  if( NO_OPERATION != ( LAYOUT & operations ) )
   {
   {
-    // TODO
+    mVisualModel->mLines.Clear();
   }
 
   }
 
-  mEventData->mUpdateCursorPosition = true;
-  mEventData->mScrollAfterUpdatePosition = true;
+  if( NO_OPERATION != ( COLOR & operations ) )
+  {
+    mVisualModel->mColorIndices.Clear();
+  }
 }
 
 }
 
-void Controller::Impl::OnTapEvent( const Event& event )
+void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
 {
 {
-  if( NULL != mEventData )
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+
+  if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
   {
   {
-    const unsigned int tapCount = event.p1.mUint;
+    // Clear the line break info.
+    LineBreakInfo* lineBreakInfoBuffer = mLogicalModel->mLineBreakInfo.Begin();
 
 
-    if( 1u == tapCount )
-    {
-      if( ! IsShowingPlaceholderText() )
-      {
-        const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
-        const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+    mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
+                                         lineBreakInfoBuffer + endIndexPlusOne );
 
 
-        mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
-                                                                    yPosition );
-      }
-      else
-      {
-        mEventData->mPrimaryCursorPosition = 0u;
-      }
+    // Clear the paragraphs.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mParagraphInfo );
+  }
 
 
-      mEventData->mUpdateCursorPosition = true;
-      mEventData->mScrollAfterUpdatePosition = true;
-    }
-    else if( mEventData->mSelectionEnabled &&
-             ( 2u == tapCount ) )
-    {
-      // 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;
+  if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
+  {
+    // Clear the word break info.
+    WordBreakInfo* wordBreakInfoBuffer = mLogicalModel->mWordBreakInfo.Begin();
 
 
-      RepositionSelectionHandles( xPosition,
-                                  yPosition );
+    mLogicalModel->mWordBreakInfo.Erase( wordBreakInfoBuffer + startIndex,
+                                         wordBreakInfoBuffer + endIndexPlusOne );
+  }
+
+  if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
+  {
+    // Clear the scripts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mScriptRuns );
+  }
+
+  if( NO_OPERATION != ( VALIDATE_FONTS & operations ) )
+  {
+    // Clear the fonts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mFontRuns );
+  }
+
+  if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
+  {
+    if( NO_OPERATION != ( BIDI_INFO & operations ) )
+    {
+      // Clear the bidirectional paragraph info.
+      ClearCharacterRuns( startIndex,
+                          endIndex,
+                          mLogicalModel->mBidirectionalParagraphInfo );
+
+      // Clear the character's directions.
+      CharacterDirection* characterDirectionsBuffer = mLogicalModel->mCharacterDirections.Begin();
+
+      mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
+                                                 characterDirectionsBuffer + endIndexPlusOne );
+    }
+
+    if( NO_OPERATION != ( REORDER & operations ) )
+    {
+      uint32_t startRemoveIndex = mLogicalModel->mBidirectionalLineInfo.Count();
+      uint32_t endRemoveIndex = startRemoveIndex;
+      ClearCharacterRuns( startIndex,
+                          endIndex,
+                          mLogicalModel->mBidirectionalLineInfo,
+                          startRemoveIndex,
+                          endRemoveIndex );
+
+      BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mLogicalModel->mBidirectionalLineInfo.Begin();
+
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
+             endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
+           it != endIt;
+           ++it )
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free( bidiLineInfo.visualToLogicalMap );
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+
+      mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
+                                                   bidirectionalLineInfoBuffer + endRemoveIndex );
+    }
+  }
+}
+
+void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+  const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
+
+  // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
+  GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+  Length* glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+
+  const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
+  const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
+
+  if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
+  {
+    // Update the character to glyph indices.
+    for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
+           endIt =  charactersToGlyphBuffer + mVisualModel->mCharactersToGlyph.Count();
+         it != endIt;
+         ++it )
+    {
+      CharacterIndex& index = *it;
+      index -= numberOfGlyphsRemoved;
+    }
+
+    // Clear the character to glyph conversion table.
+    mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
+                                            charactersToGlyphBuffer + endIndexPlusOne );
+
+    // Clear the glyphs per character table.
+    mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
+                                             glyphsPerCharacterBuffer + endIndexPlusOne );
+
+    // Clear the glyphs buffer.
+    GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
+    mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                 glyphsBuffer + endGlyphIndexPlusOne );
+
+    CharacterIndex* glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
+
+    // Update the glyph to character indices.
+    for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
+           endIt = glyphsToCharactersBuffer + mVisualModel->mGlyphsToCharacters.Count();
+         it != endIt;
+         ++it )
+    {
+      CharacterIndex& index = *it;
+      index -= numberOfCharactersRemoved;
+    }
+
+    // Clear the glyphs to characters buffer.
+    mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                             glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
+
+    // Clear the characters per glyph buffer.
+    Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+    mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                             charactersPerGlyphBuffer + endGlyphIndexPlusOne );
+
+    // Clear the positions buffer.
+    Vector2* positionsBuffer = mVisualModel->mGlyphPositions.Begin();
+    mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                         positionsBuffer + endGlyphIndexPlusOne );
+  }
+
+  if( NO_OPERATION != ( LAYOUT & operations ) )
+  {
+    // Clear the lines.
+    uint32_t startRemoveIndex = mVisualModel->mLines.Count();
+    uint32_t endRemoveIndex = startRemoveIndex;
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mVisualModel->mLines,
+                        startRemoveIndex,
+                        endRemoveIndex );
+
+    // Will update the glyph runs.
+    startRemoveIndex = mVisualModel->mLines.Count();
+    endRemoveIndex = startRemoveIndex;
+    ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
+                    endGlyphIndexPlusOne - 1u,
+                    mVisualModel->mLines,
+                    startRemoveIndex,
+                    endRemoveIndex );
+
+    // Set the line index from where to insert the new laid-out lines.
+    mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
+
+    LineRun* linesBuffer = mVisualModel->mLines.Begin();
+    mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
+                                linesBuffer + endRemoveIndex );
+  }
+
+  if( NO_OPERATION != ( COLOR & operations ) )
+  {
+    if( 0u != mVisualModel->mColorIndices.Count() )
+    {
+      ColorIndex* colorIndexBuffer = mVisualModel->mColorIndices.Begin();
+      mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                         colorIndexBuffer + endGlyphIndexPlusOne );
+    }
+  }
+}
+
+void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  if( mTextUpdateInfo.mClearAll ||
+      ( ( 0u == startIndex ) &&
+        ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
+  {
+    ClearFullModelData( operations );
+  }
+  else
+  {
+    // Clear the model data related with characters.
+    ClearCharacterModelData( startIndex, endIndex, operations );
+
+    // Clear the model data related with glyphs.
+    ClearGlyphModelData( startIndex, endIndex, operations );
+  }
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
+
+  mVisualModel->ClearCaches();
+}
+
+bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
+
+  // Calculate the operations to be done.
+  const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
+
+  if( NO_OPERATION == operations )
+  {
+    // Nothing to do if no operations are pending and required.
+    return false;
+  }
+
+  Vector<Character>& utf32Characters = mLogicalModel->mText;
+
+  const Length numberOfCharacters = utf32Characters.Count();
+
+  // Index to the first character of the first paragraph to be updated.
+  CharacterIndex startIndex = 0u;
+  // Number of characters of the paragraphs to be removed.
+  Length paragraphCharacters = 0u;
+
+  CalculateTextUpdateIndices( paragraphCharacters );
+  startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
+
+  if( mTextUpdateInfo.mClearAll ||
+      ( 0u != paragraphCharacters ) )
+  {
+    ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operations );
+  }
+
+  mTextUpdateInfo.mClearAll = false;
+
+  // Whether the model is updated.
+  bool updated = false;
+
+  Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
+  const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
+
+  if( NO_OPERATION != ( GET_LINE_BREAKS & operations ) )
+  {
+    // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
+    // calculate the bidirectional info for each 'paragraph'.
+    // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
+    // is not shaped together).
+    lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
+
+    SetLineBreakInfo( utf32Characters,
+                      startIndex,
+                      requestedNumberOfCharacters,
+                      lineBreakInfo );
+
+    // Create the paragraph info.
+    mLogicalModel->CreateParagraphInfo( startIndex,
+                                        requestedNumberOfCharacters );
+    updated = true;
+  }
+
+  Vector<WordBreakInfo>& wordBreakInfo = mLogicalModel->mWordBreakInfo;
+  if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
+  {
+    // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
+    wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
+
+    SetWordBreakInfo( utf32Characters,
+                      startIndex,
+                      requestedNumberOfCharacters,
+                      wordBreakInfo );
+    updated = true;
+  }
+
+  const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
+  const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
+
+  Vector<ScriptRun>& scripts = mLogicalModel->mScriptRuns;
+  Vector<FontRun>& validFonts = mLogicalModel->mFontRuns;
+
+  if( getScripts || validateFonts )
+  {
+    // Validates the fonts assigned by the application or assigns default ones.
+    // It makes sure all the characters are going to be rendered by the correct font.
+    MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
+
+    if( getScripts )
+    {
+      // Retrieves the scripts used in the text.
+      multilanguageSupport.SetScripts( utf32Characters,
+                                       startIndex,
+                                       requestedNumberOfCharacters,
+                                       scripts );
+    }
+
+    if( validateFonts )
+    {
+      // Validate the fonts set through the mark-up string.
+      Vector<FontDescriptionRun>& fontDescriptionRuns = mLogicalModel->mFontDescriptionRuns;
+
+      // Get the default font id.
+      const FontId defaultFontId = ( NULL == mFontDefaults ) ? 0u : mFontDefaults->GetFontId( mFontClient );
+
+      // Validates the fonts. If there is a character with no assigned font it sets a default one.
+      // After this call, fonts are validated.
+      multilanguageSupport.ValidateFonts( utf32Characters,
+                                          scripts,
+                                          fontDescriptionRuns,
+                                          defaultFontId,
+                                          startIndex,
+                                          requestedNumberOfCharacters,
+                                          validFonts );
+    }
+    updated = true;
+  }
+
+  Vector<Character> mirroredUtf32Characters;
+  bool textMirrored = false;
+  const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
+  if( NO_OPERATION != ( BIDI_INFO & operations ) )
+  {
+    Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
+    bidirectionalInfo.Reserve( numberOfParagraphs );
+
+    // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
+    SetBidirectionalInfo( utf32Characters,
+                          scripts,
+                          lineBreakInfo,
+                          startIndex,
+                          requestedNumberOfCharacters,
+                          bidirectionalInfo );
+
+    if( 0u != bidirectionalInfo.Count() )
+    {
+      // Only set the character directions if there is right to left characters.
+      Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
+      GetCharactersDirection( bidirectionalInfo,
+                              numberOfCharacters,
+                              startIndex,
+                              requestedNumberOfCharacters,
+                              directions );
+
+      // 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,
+                                      directions,
+                                      bidirectionalInfo,
+                                      startIndex,
+                                      requestedNumberOfCharacters,
+                                      mirroredUtf32Characters );
+    }
+    else
+    {
+      // There is no right to left characters. Clear the directions vector.
+      mLogicalModel->mCharacterDirections.Clear();
+    }
+    updated = true;
+  }
+
+  Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
+  Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
+  Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex> newParagraphGlyphs;
+  newParagraphGlyphs.Reserve( numberOfParagraphs );
+
+  const Length currentNumberOfGlyphs = glyphs.Count();
+  if( NO_OPERATION != ( SHAPE_TEXT & operations ) )
+  {
+    const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
+    // Shapes the text.
+    ShapeText( textToShape,
+               lineBreakInfo,
+               scripts,
+               validFonts,
+               startIndex,
+               mTextUpdateInfo.mStartGlyphIndex,
+               requestedNumberOfCharacters,
+               glyphs,
+               glyphsToCharactersMap,
+               charactersPerGlyph,
+               newParagraphGlyphs );
+
+    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+    mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+    mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+    updated = true;
+  }
+
+  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
+
+  if( NO_OPERATION != ( GET_GLYPH_METRICS & operations ) )
+  {
+    GlyphInfo* glyphsBuffer = glyphs.Begin();
+    mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, 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;
+    }
+    updated = true;
+  }
+
+  if( NO_OPERATION != ( COLOR & operations ) )
+  {
+    // Set the color runs in glyphs.
+    SetColorSegmentationInfo( mLogicalModel->mColorRuns,
+                              mVisualModel->mCharactersToGlyph,
+                              mVisualModel->mGlyphsPerCharacter,
+                              startIndex,
+                              mTextUpdateInfo.mStartGlyphIndex,
+                              requestedNumberOfCharacters,
+                              mVisualModel->mColors,
+                              mVisualModel->mColorIndices );
+
+    updated = true;
+  }
+
+  if( ( NULL != mEventData ) &&
+      mEventData->mPreEditFlag &&
+      ( 0u != mVisualModel->mCharactersToGlyph.Count() ) )
+  {
+    // Add the underline for the pre-edit text.
+    const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+    const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+
+    const GlyphIndex glyphStart = *( charactersToGlyphBuffer + mEventData->mPreEditStartPosition );
+    const CharacterIndex lastPreEditCharacter = mEventData->mPreEditStartPosition + ( ( mEventData->mPreEditLength > 0u ) ? mEventData->mPreEditLength - 1u : 0u );
+    const Length numberOfGlyphsLastCharacter = *( glyphsPerCharacterBuffer + lastPreEditCharacter );
+    const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + lastPreEditCharacter ) + ( numberOfGlyphsLastCharacter > 1u ? numberOfGlyphsLastCharacter - 1u : 0u );
+
+    GlyphRun underlineRun;
+    underlineRun.glyphIndex = glyphStart;
+    underlineRun.numberOfGlyphs = 1u + glyphEnd - glyphStart;
+
+    // TODO: At the moment the underline runs are only for pre-edit.
+    mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+  }
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
+
+  // Set the previous number of characters for the next time the text is updated.
+  mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
+
+  return updated;
+}
+
+void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
+{
+  // Sets the default text's color.
+  inputStyle.textColor = mTextColor;
+  inputStyle.isDefaultColor = true;
+
+  inputStyle.familyName.clear();
+  inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
+  inputStyle.width = TextAbstraction::FontWidth::NORMAL;
+  inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
+  inputStyle.size = 0.f;
+
+  inputStyle.familyDefined = false;
+  inputStyle.weightDefined = false;
+  inputStyle.widthDefined = false;
+  inputStyle.slantDefined = false;
+  inputStyle.sizeDefined = false;
+
+  // Sets the default font's family name, weight, width, slant and size.
+  if( mFontDefaults )
+  {
+    if( mFontDefaults->familyDefined )
+    {
+      inputStyle.familyName = mFontDefaults->mFontDescription.family;
+      inputStyle.familyDefined = true;
+    }
+
+    if( mFontDefaults->weightDefined )
+    {
+      inputStyle.weight = mFontDefaults->mFontDescription.weight;
+      inputStyle.weightDefined = true;
+    }
+
+    if( mFontDefaults->widthDefined )
+    {
+      inputStyle.width = mFontDefaults->mFontDescription.width;
+      inputStyle.widthDefined = true;
+    }
+
+    if( mFontDefaults->slantDefined )
+    {
+      inputStyle.slant = mFontDefaults->mFontDescription.slant;
+      inputStyle.slantDefined = true;
+    }
+
+    if( mFontDefaults->sizeDefined )
+    {
+      inputStyle.size = mFontDefaults->mDefaultPointSize;
+      inputStyle.sizeDefined = true;
+    }
+  }
+}
+
+float Controller::Impl::GetDefaultFontLineHeight()
+{
+  FontId defaultFontId = 0u;
+  if( NULL == mFontDefaults )
+  {
+    TextAbstraction::FontDescription fontDescription;
+    defaultFontId = mFontClient.GetFontId( fontDescription );
+  }
+  else
+  {
+    defaultFontId = mFontDefaults->GetFontId( mFontClient );
+  }
 
 
+  Text::FontMetrics fontMetrics;
+  mMetrics->GetFontMetrics( defaultFontId, fontMetrics );
+
+  return( fontMetrics.ascender - fontMetrics.descender );
+}
+
+void Controller::Impl::OnCursorKeyEvent( const Event& event )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  int keyCode = event.p1.mInt;
+
+  if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
+  {
+    if( mEventData->mPrimaryCursorPosition > 0u )
+    {
+      mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
+    }
+  }
+  else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
+  {
+    if( mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
+    {
+      mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
+    }
+  }
+  else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
+  {
+    // Get first the line index of the current cursor position index.
+    CharacterIndex characterIndex = 0u;
+
+    if( mEventData->mPrimaryCursorPosition > 0u )
+    {
+      characterIndex = mEventData->mPrimaryCursorPosition - 1u;
+    }
+
+    const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( characterIndex );
+
+    if( lineIndex > 0u )
+    {
+      // Retrieve the cursor position info.
+      CursorInfo cursorInfo;
+      GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                         cursorInfo );
+
+      // Get the line above.
+      const LineRun& line = *( mVisualModel->mLines.Begin() + ( lineIndex - 1u ) );
+
+      // Get the next hit 'y' point.
+      const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
+
+      // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+      mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel,
+                                                                        mLogicalModel,
+                                                                        mMetrics,
+                                                                        mEventData->mCursorHookPositionX,
+                                                                        hitPointY );
+    }
+  }
+  else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
+  {
+    // Get first the line index of the current cursor position index.
+    CharacterIndex characterIndex = 0u;
+
+    if( mEventData->mPrimaryCursorPosition > 0u )
+    {
+      characterIndex = mEventData->mPrimaryCursorPosition - 1u;
+    }
+
+    const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( characterIndex );
+
+    if( lineIndex + 1u < mVisualModel->mLines.Count() )
+    {
+      // Retrieve the cursor position info.
+      CursorInfo cursorInfo;
+      GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                         cursorInfo );
+
+      // Get the line below.
+      const LineRun& line = *( mVisualModel->mLines.Begin() + lineIndex + 1u );
+
+      // Get the next hit 'y' point.
+      const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
+
+      // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+      mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel,
+                                                                        mLogicalModel,
+                                                                        mMetrics,
+                                                                        mEventData->mCursorHookPositionX,
+                                                                        hitPointY );
+    }
+  }
+
+  mEventData->mUpdateCursorPosition = true;
+  mEventData->mUpdateInputStyle = true;
+  mEventData->mScrollAfterUpdatePosition = true;
+}
+
+void Controller::Impl::OnTapEvent( const Event& event )
+{
+  if( NULL != mEventData )
+  {
+    const unsigned int tapCount = event.p1.mUint;
+
+    if( 1u == tapCount )
+    {
+      if( IsShowingRealText() )
+      {
+        // Convert from control's coords to text's coords.
+        const float xPosition = event.p2.mFloat - mScrollPosition.x;
+        const float yPosition = event.p3.mFloat - mScrollPosition.y;
+
+        // Keep the tap 'x' position. Used to move the cursor.
+        mEventData->mCursorHookPositionX = xPosition;
+
+        mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel,
+                                                                          mLogicalModel,
+                                                                          mMetrics,
+                                                                          xPosition,
+                                                                          yPosition );
+
+        // When the cursor position is changing, delay cursor blinking
+        mEventData->mDecorator->DelayCursorBlink();
+      }
+      else
+      {
+        mEventData->mPrimaryCursorPosition = 0u;
+      }
+
+      mEventData->mUpdateCursorPosition = true;
+      mEventData->mUpdateGrabHandlePosition = true;
       mEventData->mScrollAfterUpdatePosition = true;
       mEventData->mScrollAfterUpdatePosition = true;
-      mEventData->mUpdateLeftSelectionPosition = true;
-      mEventData->mUpdateRightSelectionPosition = true;
+      mEventData->mUpdateInputStyle = true;
+
+      // Notify the cursor position to the imf manager.
+      if( mEventData->mImfManager )
+      {
+        mEventData->mImfManager.SetCursorPosition( mEventData->mPrimaryCursorPosition );
+        mEventData->mImfManager.NotifyCursorPosition();
+      }
+    }
+  }
+}
+
+void Controller::Impl::OnPanEvent( const Event& event )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
+  const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
+
+  if( !isHorizontalScrollEnabled && !isVerticalScrollEnabled )
+  {
+    // Nothing to do if scrolling is not enabled.
+    return;
+  }
+
+  const int state = event.p1.mInt;
+
+  switch( state )
+  {
+    case Gesture::Started:
+    {
+      // Will remove the cursor, handles or text's popup, ...
+      ChangeState( EventData::TEXT_PANNING );
+      break;
+    }
+    case Gesture::Continuing:
+    {
+      const Vector2& layoutSize = mVisualModel->GetLayoutSize();
+      const Vector2 currentScroll = mScrollPosition;
+
+      if( isHorizontalScrollEnabled )
+      {
+        const float displacementX = event.p2.mFloat;
+        mScrollPosition.x += displacementX;
+
+        ClampHorizontalScroll( layoutSize );
+      }
+
+      if( isVerticalScrollEnabled )
+      {
+        const float displacementY = event.p3.mFloat;
+        mScrollPosition.y += displacementY;
+
+        ClampVerticalScroll( layoutSize );
+      }
+
+      mEventData->mDecorator->UpdatePositions( mScrollPosition - currentScroll );
+      break;
+    }
+    case Gesture::Finished:
+    case Gesture::Cancelled: // FALLTHROUGH
+    {
+      // Will go back to the previous state to show the cursor, handles, the text's popup, ...
+      ChangeState( mEventData->mPreviousState );
+      break;
     }
     }
+    default:
+      break;
   }
 }
 
   }
 }
 
-void Controller::Impl::OnPanEvent( const Event& event )
+void Controller::Impl::OnLongPressEvent( const Event& event )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
+
+  if( EventData::EDITING == mEventData->mState )
+  {
+    ChangeState ( EventData::EDITING_WITH_POPUP );
+    mEventData->mDecoratorUpdated = true;
+  }
+}
+
+void Controller::Impl::OnHandleEvent( const Event& event )
 {
   if( NULL == mEventData )
   {
 {
   if( NULL == mEventData )
   {
@@ -509,262 +1274,782 @@ void Controller::Impl::OnPanEvent( const Event& event )
     return;
   }
 
     return;
   }
 
-  int state = event.p1.mInt;
+  const unsigned int state = event.p1.mUint;
+  const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
+  const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
+
+  if( HANDLE_PRESSED == state )
+  {
+    // Convert from decorator's coords to text's coords.
+    const float xPosition = event.p2.mFloat - mScrollPosition.x;
+    const float yPosition = event.p3.mFloat - mScrollPosition.y;
+
+    // Need to calculate the handle's new position.
+    const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mVisualModel,
+                                                                          mLogicalModel,
+                                                                          mMetrics,
+                                                                          xPosition,
+                                                                          yPosition );
+
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      ChangeState ( EventData::GRAB_HANDLE_PANNING );
+
+      if( handleNewPosition != mEventData->mPrimaryCursorPosition )
+      {
+        // Updates the cursor position if the handle's new position is different than the current one.
+        mEventData->mUpdateCursorPosition = true;
+        // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
+        mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
+        mEventData->mPrimaryCursorPosition = handleNewPosition;
+      }
+
+      // 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.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mRightSelectionPosition ) )
+      {
+        // Updates the highlight box if the handle's new position is different than the current one.
+        mEventData->mUpdateHighlightBox = true;
+        // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
+        mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
+        mEventData->mLeftSelectionPosition = handleNewPosition;
+      }
+
+      // 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.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+
+      // Will define the order to scroll the text to match the handle position.
+      mEventData->mIsLeftHandleSelected = true;
+    }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
+      {
+        // Updates the highlight box if the handle's new position is different than the current one.
+        mEventData->mUpdateHighlightBox = true;
+        // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
+        mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
+        mEventData->mRightSelectionPosition = handleNewPosition;
+      }
+
+      // 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.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
 
 
-  if( Gesture::Started    == state ||
-      Gesture::Continuing == state )
+      // Will define the order to scroll the text to match the handle position.
+      mEventData->mIsLeftHandleSelected = false;
+    }
+  } // end ( HANDLE_PRESSED == state )
+  else if( ( HANDLE_RELEASED == state ) ||
+           handleStopScrolling )
   {
   {
-    const Vector2& actualSize = mVisualModel->GetActualSize();
-    const Vector2 currentScroll = mEventData->mScrollPosition;
+    CharacterIndex handlePosition = 0u;
+    if( handleStopScrolling || isSmoothHandlePanEnabled )
+    {
+      // Convert from decorator's coords to text's coords.
+      const float xPosition = event.p2.mFloat - mScrollPosition.x;
+      const float yPosition = event.p3.mFloat - mScrollPosition.y;
+
+      handlePosition = Text::GetClosestCursorIndex( mVisualModel,
+                                                    mLogicalModel,
+                                                    mMetrics,
+                                                    xPosition,
+                                                    yPosition );
+    }
+
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      mEventData->mUpdateCursorPosition = true;
+      mEventData->mUpdateGrabHandlePosition = true;
+      mEventData->mUpdateInputStyle = true;
+
+      if( !IsClipboardEmpty() )
+      {
+        ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
+      }
+
+      if( handleStopScrolling || isSmoothHandlePanEnabled )
+      {
+        mEventData->mScrollAfterUpdatePosition = true;
+        mEventData->mPrimaryCursorPosition = handlePosition;
+      }
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
+
+      mEventData->mUpdateHighlightBox = true;
+      mEventData->mUpdateLeftSelectionPosition = true;
+      mEventData->mUpdateRightSelectionPosition = true;
+
+      if( handleStopScrolling || isSmoothHandlePanEnabled )
+      {
+        mEventData->mScrollAfterUpdatePosition = true;
 
 
-    if( mEventData->mHorizontalScrollingEnabled )
+        if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
+            ( handlePosition != mEventData->mLeftSelectionPosition ) )
+        {
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
+      }
+    }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
     {
-      const float displacementX = event.p2.mFloat;
-      mEventData->mScrollPosition.x += displacementX;
+      ChangeState( EventData::SELECTING );
+
+      mEventData->mUpdateHighlightBox = true;
+      mEventData->mUpdateRightSelectionPosition = true;
+      mEventData->mUpdateLeftSelectionPosition = true;
+
+      if( handleStopScrolling || isSmoothHandlePanEnabled )
+      {
+        mEventData->mScrollAfterUpdatePosition = true;
+        if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
+            ( handlePosition != mEventData->mLeftSelectionPosition ) )
+        {
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+      }
+    }
+
+    mEventData->mDecoratorUpdated = true;
+  } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
+  else if( HANDLE_SCROLLING == state )
+  {
+    const float xSpeed = event.p2.mFloat;
+    const float ySpeed = event.p3.mFloat;
+    const Vector2& layoutSize = mVisualModel->GetLayoutSize();
+    const Vector2 currentScrollPosition = mScrollPosition;
+
+    mScrollPosition.x += xSpeed;
+    mScrollPosition.y += ySpeed;
+
+    ClampHorizontalScroll( layoutSize );
+    ClampVerticalScroll( layoutSize );
 
 
-      ClampHorizontalScroll( actualSize );
+    bool endOfScroll = false;
+    if( Vector2::ZERO == ( currentScrollPosition - 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;
     }
 
     }
 
-    if( mEventData->mVerticalScrollingEnabled )
+    // Set the position of the handle.
+    const bool scrollRightDirection = xSpeed > 0.f;
+    const bool scrollBottomDirection = ySpeed > 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 );
+
+      // Get the grab handle position in decorator coords.
+      Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
+
+      if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
+      {
+        // Position the grag handle close to either the left or right edge.
+        position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
+      }
+
+      if( mEventData->mDecorator->IsVerticalScrollEnabled() )
+      {
+        position.x = mEventData->mCursorHookPositionX;
+
+        // Position the grag handle close to either the top or bottom edge.
+        position.y = scrollBottomDirection ? 0.f : mVisualModel->mControlSize.height;
+      }
+
+      // Get the new handle position.
+      // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
+      const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel,
+                                                                         mLogicalModel,
+                                                                         mMetrics,
+                                                                         position.x - mScrollPosition.x,
+                                                                         position.y - mScrollPosition.y );
+
+      if( mEventData->mPrimaryCursorPosition != handlePosition )
+      {
+        mEventData->mUpdateCursorPosition = true;
+        mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
+        mEventData->mScrollAfterUpdatePosition = true;
+        mEventData->mPrimaryCursorPosition = handlePosition;
+      }
+      mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
+
+      // Updates the decorator if the soft handle panning is enabled.
+      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+    }
+    else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
     {
     {
-      const float displacementY = event.p3.mFloat;
-      mEventData->mScrollPosition.y += displacementY;
+      ChangeState( EventData::SELECTION_HANDLE_PANNING );
+
+      // Get the selection handle position in decorator coords.
+      Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+
+      if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
+      {
+        // Position the selection handle close to either the left or right edge.
+        position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
+      }
+
+      if( mEventData->mDecorator->IsVerticalScrollEnabled() )
+      {
+        position.x = mEventData->mCursorHookPositionX;
+
+        // Position the grag handle close to either the top or bottom edge.
+        position.y = scrollBottomDirection ? 0.f : mVisualModel->mControlSize.height;
+      }
+
+      // Get the new handle position.
+      // The selection handle's position is in decorator's coords. Need to transform to text's coords.
+      const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel,
+                                                                         mLogicalModel,
+                                                                         mMetrics,
+                                                                         position.x - mScrollPosition.x,
+                                                                         position.y - mScrollPosition.y );
+
+      if( leftSelectionHandleEvent )
+      {
+        const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
+
+        if( differentHandles || endOfScroll )
+        {
+          mEventData->mUpdateHighlightBox = true;
+          mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
+          mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
+      }
+      else
+      {
+        const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
+        if( differentHandles || endOfScroll )
+        {
+          mEventData->mUpdateHighlightBox = true;
+          mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
+          mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+      }
+
+      if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+      {
+        RepositionSelectionHandles();
 
 
-      ClampVerticalScroll( actualSize );
+        mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
+      }
     }
     }
+    mEventData->mDecoratorUpdated = true;
+  } // end ( HANDLE_SCROLLING == state )
+}
+
+void Controller::Impl::OnSelectEvent( const Event& event )
+{
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  if( mEventData->mSelectionEnabled )
+  {
+    // Convert from control's coords to text's coords.
+    const float xPosition = event.p2.mFloat - mScrollPosition.x;
+    const float yPosition = event.p3.mFloat - mScrollPosition.y;
+
+    // Calculates the logical position from the x,y coords.
+    RepositionSelectionHandles( xPosition,
+                                yPosition );
+  }
+}
+
+void Controller::Impl::OnSelectAllEvent()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
+
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  if( mEventData->mSelectionEnabled )
+  {
+    ChangeState( EventData::SELECTING );
+
+    mEventData->mLeftSelectionPosition = 0u;
+    mEventData->mRightSelectionPosition = mLogicalModel->mText.Count();
+
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = true;
+    mEventData->mUpdateHighlightBox = true;
+  }
+}
+
+void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
+{
+  if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
+  {
+    // Nothing to select if handles are in the same place.
+    selectedText.clear();
+    return;
+  }
+
+  const bool handlesCrossed = mEventData->mLeftSelectionPosition > mEventData->mRightSelectionPosition;
+
+  //Get start and end position of selection
+  const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+  const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
+
+  Vector<Character>& utf32Characters = mLogicalModel->mText;
+  const Length numberOfCharacters = utf32Characters.Count();
+
+  // Validate the start and end selection points
+  if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
+  {
+    //Get text as a UTF8 string
+    Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
+
+    if( deleteAfterRetrieval ) // Only delete text if copied successfully
+    {
+      // Set as input style the style of the first deleted character.
+      mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
+
+      mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
+
+      // Mark the paragraphs to be updated.
+      mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
 
 
-    if( mEventData->mDecorator )
+      // Delete text between handles
+      Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
+      Vector<Character>::Iterator last  = first + lengthOfSelectedText;
+      utf32Characters.Erase( first, last );
+
+      // Will show the cursor at the first character of the selection.
+      mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+    }
+    else
     {
     {
-      mEventData->mDecorator->UpdatePositions( mEventData->mScrollPosition - currentScroll );
+      // Will show the cursor at the last character of the selection.
+      mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
     }
     }
+
+    mEventData->mDecoratorUpdated = true;
+  }
+}
+
+void Controller::Impl::ShowClipboard()
+{
+  if( mClipboard )
+  {
+    mClipboard.ShowClipboard();
+  }
+}
+
+void Controller::Impl::HideClipboard()
+{
+  if( mClipboard && mClipboardHideEnabled )
+  {
+    mClipboard.HideClipboard();
+  }
+}
+
+void Controller::Impl::SetClipboardHideEnable(bool enable)
+{
+  mClipboardHideEnabled = enable;
+}
+
+bool Controller::Impl::CopyStringToClipboard( std::string& source )
+{
+  //Send string to clipboard
+  return ( mClipboard && mClipboard.SetItem( source ) );
+}
+
+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& retrievedString )
+{
+  if ( mClipboard )
+  {
+    retrievedString =  mClipboard.GetItem( itemIndex );
   }
 }
 
   }
 }
 
-void Controller::Impl::OnHandleEvent( const Event& event )
-{
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
+void Controller::Impl::RepositionSelectionHandles()
+{
+  CharacterIndex selectionStart = mEventData->mLeftSelectionPosition;
+  CharacterIndex selectionEnd = mEventData->mRightSelectionPosition;
+
+  if( selectionStart == selectionEnd )
+  {
+    // Nothing to select if handles are in the same place.
+    return;
+  }
+
+  mEventData->mDecorator->ClearHighlights();
+
+  const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.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;
+
+  const bool isLastCharacter = selectionEnd >= mLogicalModel->mText.Count();
+  const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
+  const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
+
+  // Swap the indices if the start is greater than the end.
+  const bool indicesSwapped = selectionStart > selectionEnd;
+
+  // Tell the decorator to flip the selection handles if needed.
+  mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
+
+  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 );
+
+  // Get the lines where the glyphs are laid-out.
+  const LineRun* lineRun = mVisualModel->mLines.Begin();
+
+  LineIndex lineIndex = 0u;
+  Length numberOfLines = 0u;
+  mVisualModel->GetNumberOfLines( glyphStart,
+                                  1u + glyphEnd - glyphStart,
+                                  lineIndex,
+                                  numberOfLines );
+  const LineIndex firstLineIndex = lineIndex;
+
+  // Create the structure to store some selection box info.
+  Vector<SelectionBoxInfo> selectionBoxLinesInfo;
+  selectionBoxLinesInfo.Resize( numberOfLines );
+
+  SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
+  selectionBoxInfo->minX = MAX_FLOAT;
+  selectionBoxInfo->maxX = MIN_FLOAT;
+
+  // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
+  float minHighlightX = std::numeric_limits<float>::max();
+  float maxHighlightX = std::numeric_limits<float>::min();
+  Size highLightSize;
+  Vector2 highLightPosition; // The highlight position in decorator's coords.
+
+  // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
+
+  // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
+  selectionBoxInfo->lineOffset = CalculateLineOffset( mVisualModel->mLines,
+                                                      firstLineIndex );
+
+  // Transform to decorator's (control) coords.
+  selectionBoxInfo->lineOffset += mScrollPosition.y;
+
+  lineRun += firstLineIndex;
+
+  // The line height is the addition of the line ascender and the line descender.
+  // However, the line descender has a negative value, hence the subtraction.
+  selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
 
 
-  const unsigned int state = event.p1.mUint;
-  const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
+  GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
 
 
-  if( HANDLE_PRESSED == state )
-  {
-    // 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;
+  // 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 ) );
 
 
-    const CharacterIndex handleNewPosition = GetClosestCursorIndex( xPosition, yPosition );
+  // 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 ) );
 
 
-    if( Event::GRAB_HANDLE_EVENT == event.type )
+  // Traverse the glyphs.
+  for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
+  {
+    const GlyphInfo& glyph = *( glyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+
+    if( splitStartGlyph )
     {
     {
-      ChangeState ( EventData::GRAB_HANDLE_PANNING );
+      // 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.
 
 
-      if( handleNewPosition != mEventData->mPrimaryCursorPosition )
+      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.
       {
       {
-        mEventData->mPrimaryCursorPosition = handleNewPosition;
-        mEventData->mUpdateCursorPosition = true;
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
       }
       }
-    }
-    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
-    {
-      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
 
 
-      if( handleNewPosition != mEventData->mLeftSelectionPosition )
-      {
-        mEventData->mLeftSelectionPosition = handleNewPosition;
+      // 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 );
 
 
-        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                    mEventData->mRightSelectionPosition );
+      const float xPosition = lineRun->alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
+      const float xPositionAdvance = xPosition + static_cast<float>( numberOfCharacters ) * glyphAdvance;
+      const float yPosition = selectionBoxInfo->lineOffset;
 
 
-        mEventData->mUpdateLeftSelectionPosition = true;
-      }
+      // Store the min and max 'x' for each line.
+      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, xPosition );
+      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, xPositionAdvance );
+
+      mEventData->mDecorator->AddHighlight( xPosition,
+                                            yPosition,
+                                            xPositionAdvance,
+                                            yPosition + selectionBoxInfo->lineHeight );
+
+      splitStartGlyph = false;
+      continue;
     }
     }
-    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+
+    if( splitEndGlyph && ( index == glyphEnd ) )
     {
     {
-      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+      // 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.
 
 
-      if( handleNewPosition != mEventData->mRightSelectionPosition )
+      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.
       {
       {
-        mEventData->mRightSelectionPosition = handleNewPosition;
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
+      }
 
 
-        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                    mEventData->mRightSelectionPosition );
+      const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
 
 
-        mEventData->mUpdateRightSelectionPosition = true;
-      }
-    }
-  } // end ( HANDLE_PRESSED == state )
-  else if( ( HANDLE_RELEASED == state ) ||
-           handleStopScrolling )
-  {
-    CharacterIndex handlePosition = 0u;
-    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;
+      const float xPosition = lineRun->alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
+      const float xPositionAdvance = xPosition + static_cast<float>( interGlyphIndex ) * glyphAdvance;
+      const float yPosition = selectionBoxInfo->lineOffset;
+
+      // Store the min and max 'x' for each line.
+      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, xPosition );
+      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, xPositionAdvance );
 
 
-      handlePosition = GetClosestCursorIndex( xPosition, yPosition );
+      mEventData->mDecorator->AddHighlight( xPosition,
+                                            yPosition,
+                                            xPositionAdvance,
+                                            yPosition + selectionBoxInfo->lineHeight );
+
+      splitEndGlyph = false;
+      continue;
     }
 
     }
 
-    if( Event::GRAB_HANDLE_EVENT == event.type )
-    {
-      mEventData->mUpdateCursorPosition = true;
+    const float xPosition = lineRun->alignmentOffset + position.x - glyph.xBearing + mScrollPosition.x;
+    const float xPositionAdvance = xPosition + glyph.advance;
+    const float yPosition = selectionBoxInfo->lineOffset;
 
 
-      ChangeState( EventData::EDITING_WITH_POPUP );
+    // Store the min and max 'x' for each line.
+    selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, xPosition );
+    selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, xPositionAdvance );
 
 
-      if( handleStopScrolling )
-      {
-        mEventData->mScrollAfterUpdatePosition = mEventData->mPrimaryCursorPosition != handlePosition;
-        mEventData->mPrimaryCursorPosition = handlePosition;
-      }
-    }
-    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    mEventData->mDecorator->AddHighlight( xPosition,
+                                          yPosition,
+                                          xPositionAdvance,
+                                          yPosition + selectionBoxInfo->lineHeight );
+
+    // Whether to retrieve the next line.
+    if( index == lastGlyphOfLine )
     {
     {
-      ChangeState( EventData::SELECTING );
+      // Retrieve the next line.
+      ++lineRun;
+
+      // Get the last glyph of the new line.
+      lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
 
 
-      if( handleStopScrolling )
+      ++lineIndex;
+      if( lineIndex < firstLineIndex + numberOfLines )
       {
       {
-        mEventData->mUpdateLeftSelectionPosition = mEventData->mLeftSelectionPosition != handlePosition;
-        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
-        mEventData->mLeftSelectionPosition = handlePosition;
+        // Keep the offset and height of the current selection box.
+        const float currentLineOffset = selectionBoxInfo->lineOffset;
+        const float currentLineHeight = selectionBoxInfo->lineHeight;
 
 
-        if( mEventData->mUpdateLeftSelectionPosition )
-        {
-          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                      mEventData->mRightSelectionPosition );
-        }
-      }
-    }
-    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
-    {
-      ChangeState( EventData::SELECTING );
+        // Get the selection box info for the next line.
+        ++selectionBoxInfo;
 
 
-      if( handleStopScrolling )
-      {
-        mEventData->mUpdateRightSelectionPosition = mEventData->mRightSelectionPosition != handlePosition;
-        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
-        mEventData->mRightSelectionPosition = handlePosition;
+        selectionBoxInfo->minX = MAX_FLOAT;
+        selectionBoxInfo->maxX = MIN_FLOAT;
 
 
-        if( mEventData->mUpdateRightSelectionPosition )
-        {
-          RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                      mEventData->mRightSelectionPosition );
-        }
+        // Update the line's vertical offset.
+        selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
+
+        // The line height is the addition of the line ascender and the line descender.
+        // However, the line descender has a negative value, hence the subtraction.
+        selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
       }
     }
       }
     }
+  }
 
 
-    mEventData->mDecoratorUpdated = true;
-  } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
-  else if( HANDLE_SCROLLING == state )
+  // Traverses all the lines and updates the min and max 'x' positions and the total height.
+  // The final width is calculated after 'boxifying' the selection.
+  for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
+         endIt = selectionBoxLinesInfo.End();
+       it != endIt;
+       ++it )
   {
   {
-    const float xSpeed = event.p2.mFloat;
-    const Vector2& actualSize = mVisualModel->GetActualSize();
+    const SelectionBoxInfo& info = *it;
 
 
-    mEventData->mScrollPosition.x += xSpeed;
+    // Update the size of the highlighted text.
+    highLightSize.height += selectionBoxInfo->lineHeight;
+    minHighlightX = std::min( minHighlightX, info.minX );
+    maxHighlightX = std::max( maxHighlightX, info.maxX );
+  }
 
 
-    ClampHorizontalScroll( actualSize );
+  // Add extra geometry to 'boxify' the selection.
 
 
-    const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
-    const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
+  if( 1u < numberOfLines )
+  {
+    // Boxify the first line.
+    lineRun = mVisualModel->mLines.Begin() + firstLineIndex;
+    const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
 
 
-    if( Event::GRAB_HANDLE_EVENT == event.type )
+    bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
+    bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
+
+    if( boxifyBegin )
     {
     {
-      ChangeState( EventData::GRAB_HANDLE_PANNING );
+      // Boxify at the beginning of the line.
+      mEventData->mDecorator->AddHighlight( 0.f,
+                                            firstSelectionBoxLineInfo.lineOffset,
+                                            firstSelectionBoxLineInfo.minX,
+                                            firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight );
+
+      // Update the size of the highlighted text.
+      minHighlightX = 0.f;
     }
     }
-    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 );
+    if( boxifyEnd )
+    {
+      // Boxify at the end of the line.
+      mEventData->mDecorator->AddHighlight( firstSelectionBoxLineInfo.maxX,
+                                            firstSelectionBoxLineInfo.lineOffset,
+                                            mVisualModel->mControlSize.width,
+                                            firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight );
+
+      // Update the size of the highlighted text.
+      maxHighlightX = mVisualModel->mControlSize.width;
+    }
 
 
-      const Vector2& position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+    // Boxify the central lines.
+    if( 2u < numberOfLines )
+    {
+      for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
+             endIt = selectionBoxLinesInfo.End() - 1u;
+           it != endIt;
+           ++it )
+      {
+        const SelectionBoxInfo& info = *it;
 
 
-      // 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 );
+        mEventData->mDecorator->AddHighlight( 0.f,
+                                              info.lineOffset,
+                                              info.minX,
+                                              info.lineOffset + info.lineHeight );
 
 
-      if( leftSelectionHandleEvent )
-      {
-        mEventData->mUpdateLeftSelectionPosition = handlePosition != mEventData->mLeftSelectionPosition;
-        mEventData->mLeftSelectionPosition = handlePosition;
-      }
-      else
-      {
-        mEventData->mUpdateRightSelectionPosition = handlePosition != mEventData->mRightSelectionPosition;
-        mEventData->mRightSelectionPosition = handlePosition;
+        mEventData->mDecorator->AddHighlight( info.maxX,
+                                              info.lineOffset,
+                                              mVisualModel->mControlSize.width,
+                                              info.lineOffset + info.lineHeight );
       }
 
       }
 
-      if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
-      {
-        RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
-                                    mEventData->mRightSelectionPosition );
-      }
+      // Update the size of the highlighted text.
+      minHighlightX = 0.f;
+      maxHighlightX = mVisualModel->mControlSize.width;
     }
     }
-    mEventData->mDecoratorUpdated = true;
-  } // end ( HANDLE_SCROLLING == state )
-}
-
-void Controller::Impl::RepositionSelectionHandles( CharacterIndex selectionStart, CharacterIndex selectionEnd )
-{
-  mEventData->mDecorator->ClearHighlights();
-
-  mEventData->mLeftSelectionPosition = selectionStart;
-  mEventData->mRightSelectionPosition = selectionEnd;
 
 
-  const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
-  const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
-  const GlyphInfo* const glyphsBuffer = mVisualModel->mGlyphs.Begin();
-  const Vector2* const positionsBuffer = mVisualModel->mGlyphPositions.Begin();
+    // Boxify the last line.
+    lineRun = mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
+    const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
 
 
-  // TODO: Better algorithm to create the highlight box.
-  // TODO: Multi-line.
+    boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
+    boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
 
 
-  const Vector<LineRun>& lines = mVisualModel->mLines;
-  const float height = lines[0].ascender + -lines[0].descender;
+    if( boxifyBegin )
+    {
+      // Boxify at the beginning of the line.
+      mEventData->mDecorator->AddHighlight( 0.f,
+                                            lastSelectionBoxLineInfo.lineOffset,
+                                            lastSelectionBoxLineInfo.minX,
+                                            lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight );
+
+      // Update the size of the highlighted text.
+      minHighlightX = 0.f;
+    }
 
 
-  const bool indicesSwapped = selectionStart > selectionEnd;
-  if( indicesSwapped )
-  {
-    std::swap( selectionStart, selectionEnd );
+    if( boxifyEnd )
+    {
+      // Boxify at the end of the line.
+      mEventData->mDecorator->AddHighlight( lastSelectionBoxLineInfo.maxX,
+                                            lastSelectionBoxLineInfo.lineOffset,
+                                            mVisualModel->mControlSize.width,
+                                            lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight );
+
+      // Update the size of the highlighted text.
+      maxHighlightX = mVisualModel->mControlSize.width;
+    }
   }
 
   }
 
-  GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
-  GlyphIndex glyphEnd = *( charactersToGlyphBuffer + ( selectionEnd - 1u ) ) + *( glyphsPerCharacterBuffer + ( selectionEnd - 1u ) ) - 1u;
+  // Sets the highlight's size and position. In decorator's coords.
+  // The highlight's height has been calculated above (before 'boxifying' the highlight).
+  highLightSize.width = maxHighlightX - minHighlightX;
 
 
-  mEventData->mDecorator->SwapSelectionHandlesEnabled( indicesSwapped );
+  highLightPosition.x = minHighlightX;
+  const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
+  highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
 
 
-  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+  mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize );
 
 
-  for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
+  if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
   {
   {
-    const GlyphInfo& glyph = *( glyphsBuffer + index );
-    const Vector2& position = *( positionsBuffer + index );
+    CursorInfo primaryCursorInfo;
+    GetCursorPosition( mEventData->mLeftSelectionPosition,
+                       primaryCursorInfo );
 
 
-    const float xPosition = position.x - glyph.xBearing + offset.x;
-    mEventData->mDecorator->AddHighlight( xPosition, offset.y, xPosition + glyph.advance, height );
-  }
+    const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mScrollPosition;
 
 
-  CursorInfo primaryCursorInfo;
-  GetCursorPosition( mEventData->mLeftSelectionPosition,
-                     primaryCursorInfo );
+    mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
+                                         primaryPosition.x,
+                                         primaryCursorInfo.lineOffset + mScrollPosition.y,
+                                         primaryCursorInfo.lineHeight );
 
 
-  CursorInfo secondaryCursorInfo;
-  GetCursorPosition( mEventData->mRightSelectionPosition,
-                     secondaryCursorInfo );
+    CursorInfo secondaryCursorInfo;
+    GetCursorPosition( mEventData->mRightSelectionPosition,
+                       secondaryCursorInfo );
 
 
-  const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + offset;
-  const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + offset;
+    const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mScrollPosition;
 
 
-  mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE, primaryPosition.x, primaryPosition.y, primaryCursorInfo.lineHeight );
+    mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
+                                         secondaryPosition.x,
+                                         secondaryCursorInfo.lineOffset + mScrollPosition.y,
+                                         secondaryCursorInfo.lineHeight );
+  }
 
 
-  mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryPosition.x, secondaryPosition.y, secondaryCursorInfo.lineHeight );
+  // Cursor to be positioned at end of selection so if selection interrupted and edit mode restarted the cursor will be at end of selection
+  mEventData->mPrimaryCursorPosition = ( indicesSwapped ) ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
 
   // Set the flag to update the decorator.
   mEventData->mDecoratorUpdated = true;
 
   // Set the flag to update the decorator.
   mEventData->mDecoratorUpdated = true;
@@ -786,8 +2071,8 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY
 
   const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
   const Length numberOfLines  = mVisualModel->mLines.Count();
 
   const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
   const Length numberOfLines  = mVisualModel->mLines.Count();
-  if( 0 == numberOfGlyphs ||
-      0 == numberOfLines )
+  if( ( 0 == numberOfGlyphs ) ||
+      ( 0 == numberOfLines ) )
   {
     // Nothing to do if there is no text.
     return;
   {
     // Nothing to do if there is no text.
     return;
@@ -796,463 +2081,366 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY
   // Find which word was selected
   CharacterIndex selectionStart( 0 );
   CharacterIndex selectionEnd( 0 );
   // Find which word was selected
   CharacterIndex selectionStart( 0 );
   CharacterIndex selectionEnd( 0 );
-  FindSelectionIndices( visualX, visualY, selectionStart, selectionEnd );
+  const bool indicesFound = FindSelectionIndices( mVisualModel,
+                                                  mLogicalModel,
+                                                  mMetrics,
+                                                  visualX,
+                                                  visualY,
+                                                  selectionStart,
+                                                  selectionEnd );
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
 
-  if( selectionStart == selectionEnd )
+  if( indicesFound )
   {
   {
-    ChangeState( EventData::EDITING );
-    // Nothing to select. i.e. a white space, out of bounds
-    return;
-  }
+    ChangeState( EventData::SELECTING );
 
 
-  RepositionSelectionHandles( selectionStart, selectionEnd );
-}
-
-void Controller::Impl::ChangeState( EventData::State newState )
-{
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
+    mEventData->mLeftSelectionPosition = selectionStart;
+    mEventData->mRightSelectionPosition = selectionEnd;
 
 
-  if( mEventData->mState != newState )
-  {
-    mEventData->mState = newState;
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = true;
+    mEventData->mUpdateHighlightBox = true;
 
 
-    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 );
-      if( mEventData->mGrabHandlePopupEnabled )
-      {
-        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;
-    }
-    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 )
-      {
-        mEventData->mDecorator->SetPopupActive( true );
-      }
-      mEventData->mDecoratorUpdated = true;
-    }
-    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;
-    }
+    mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
   }
   }
-}
-
-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 )
+  else
   {
   {
-    const LineRun& lineRun = lines[lineIndex];
-    totalHeight += lineRun.ascender + -lineRun.descender;
-    if( y < totalHeight )
-    {
-      return lineIndex;
-    }
-  }
+    // Nothing to select. i.e. a white space, out of bounds
+    ChangeState( EventData::EDITING );
 
 
-  if( lineIndex == 0 )
-  {
-    return 0;
-  }
+    mEventData->mPrimaryCursorPosition = selectionEnd;
 
 
-  return lineIndex-1;
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mUpdateGrabHandlePosition = true;
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateInputStyle = true;
+  }
 }
 
 }
 
-void Controller::Impl::FindSelectionIndices( float visualX, float visualY, CharacterIndex& startIndex, CharacterIndex& endIndex )
+void Controller::Impl::SetPopupButtons()
 {
 {
-  CharacterIndex hitCharacter = GetClosestCursorIndex( visualX, visualY );
-  if( hitCharacter >= mLogicalModel->mText.Count() )
-  {
-    // Selection out of bounds.
-    return;
-  }
+  /**
+   *  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
+   */
 
 
-  startIndex = hitCharacter;
-  endIndex = hitCharacter;
+  TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
 
 
-  if( !TextAbstraction::IsWhiteSpace( mLogicalModel->mText[hitCharacter] ) )
+  if( EventData::SELECTING == mEventData->mState )
   {
   {
-    // Find the start and end of the text
-    for( startIndex = hitCharacter; startIndex > 0; --startIndex )
+    buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+
+    if( !IsClipboardEmpty() )
     {
     {
-      Character charCode = mLogicalModel->mText[ startIndex-1 ];
-      if( TextAbstraction::IsWhiteSpace( charCode ) )
-      {
-        break;
-      }
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
     }
     }
-    const CharacterIndex pastTheEnd = mLogicalModel->mText.Count();
-    for( endIndex = hitCharacter + 1u; endIndex < pastTheEnd; ++endIndex )
+
+    if( !mEventData->mAllTextSelected )
     {
     {
-      Character charCode = mLogicalModel->mText[ endIndex ];
-      if( TextAbstraction::IsWhiteSpace( charCode ) )
-      {
-        break;
-      }
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
     }
   }
     }
   }
-}
-
-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();
-
-  // 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;
-  DALI_ASSERT_DEBUG( endCharacter <= mLogicalModel->mText.Count() && "Invalid line info" );
-
-  // Whether there is a hit on a glyph.
-  bool matched = false;
-
-  // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
-  CharacterIndex visualIndex = startCharacter;
-  for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
+  else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
   {
   {
-    // The character in logical order.
-    const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
-
-    // 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 );
-
-    // Get the metrics for the group of glyphs.
-    GlyphMetrics glyphMetrics;
-    GetGlyphsMetrics( glyphLogicalOrderIndex,
-                      numberOfGlyphs,
-                      glyphMetrics,
-                      mVisualModel,
-                      mFontClient );
-
-    const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
-
-    // Find the mid-point of the area containing the glyph
-    const float glyphCenter = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
-
-    if( visualX < glyphCenter )
+    if( mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
     {
     {
-      matched = true;
-      break;
+      buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
     }
     }
-  }
-
-  // Return the logical position of the cursor in characters.
-
-  if( !matched )
-  {
-    visualIndex = endCharacter;
-  }
-
-  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,
-                                          CursorInfo& cursorInfo )
-{
-  // TODO: Check for multiline with \n, etc...
-
-  // 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;
-
-  if( isFirstPosition && isLastPosition )
-  {
-    // There is zero characters. Get the default font.
-
-    FontId defaultFontId = 0u;
-    if( NULL == mFontDefaults )
+    if( !IsClipboardEmpty() )
     {
     {
-      defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
-                                             EMPTY_STRING );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
     }
     }
-    else
+  }
+  else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
+  {
+    if ( !IsClipboardEmpty() )
     {
     {
-      defaultFontId = mFontDefaults->GetFontId( mFontClient );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
     }
     }
-
-    Text::FontMetrics fontMetrics;
-    mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
-
-    cursorInfo.lineHeight = fontMetrics.ascender - fontMetrics.descender;
-    cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
-
-    cursorInfo.primaryPosition.x = 0.f;
-    cursorInfo.primaryPosition.y = 0.f;
-
-    // Nothing else to do.
-    return;
   }
 
   }
 
-  // Get the previous logical index.
-  const CharacterIndex previousLogical = isFirstPosition ? 0u : logical - 1u;
+  mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+}
 
 
-  // Decrease the logical index if it's the last one.
-  if( isLastPosition )
+void Controller::Impl::ChangeState( EventData::State newState )
+{
+  if( NULL == mEventData )
   {
   {
-    --logical;
+    // Nothing to do if there is no text input.
+    return;
   }
 
   }
 
-  // Get the direction of the character and the previous one.
-  const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
 
 
-  CharacterDirection isCurrentRightToLeft = false;
-  CharacterDirection isPreviousRightToLeft = false;
-  if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+  if( mEventData->mState != newState )
   {
   {
-    isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + logical );
-    isPreviousRightToLeft = *( modelCharacterDirectionsBuffer + previousLogical );
-  }
-
-  // Get the line where the character is laid-out.
-  const LineRun* modelLines = mVisualModel->mLines.Begin();
+    mEventData->mPreviousState = mEventData->mState;
+    mEventData->mState = newState;
 
 
-  const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( logical );
-  const LineRun& line = *( modelLines + lineIndex );
+    switch( mEventData->mState )
+    {
+      case EventData::INACTIVE:
+      {
+        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->SetHighlightActive( false );
+        mEventData->mDecorator->SetPopupActive( false );
+        mEventData->mDecoratorUpdated = true;
+        HideClipboard();
+        break;
+      }
+      case EventData::INTERRUPTED:
+      {
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
+        mEventData->mDecorator->SetPopupActive( false );
+        mEventData->mDecoratorUpdated = true;
+        HideClipboard();
+        break;
+      }
+      case EventData::SELECTING:
+      {
+        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->mDecorator->SetHighlightActive( true );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          SetPopupButtons();
+          mEventData->mDecorator->SetPopupActive( true );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING:
+      {
+        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->mDecorator->SetHighlightActive( false );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        HideClipboard();
+        break;
+      }
+      case EventData::EDITING_WITH_POPUP:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
 
 
-  // Get the paragraph's direction.
-  const CharacterDirection isRightToLeftParagraph = line.direction;
+        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 );
+          mEventData->mDecorator->SetHighlightActive( false );
+        }
+        else
+        {
+          mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        }
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          SetPopupButtons();
+          mEventData->mDecorator->SetPopupActive( true );
+        }
+        HideClipboard();
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_GRAB_HANDLE:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
 
 
-  // Check whether there is an alternative position:
+        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 );
+        mEventData->mDecorator->SetHighlightActive( false );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        HideClipboard();
+        break;
+      }
+      case EventData::SELECTION_HANDLE_PANNING:
+      {
+        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->mDecorator->SetHighlightActive( true );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::GRAB_HANDLE_PANNING:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
 
 
-  cursorInfo.isSecondaryCursor = ( isCurrentRightToLeft != isPreviousRightToLeft ) ||
-    ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
+        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 );
+        mEventData->mDecorator->SetHighlightActive( false );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_PASTE_POPUP:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
 
 
-  // Set the line height.
-  cursorInfo.lineHeight = line.ascender + -line.descender;
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mEventData->mCursorBlinkEnabled )
+        {
+          mEventData->mDecorator->StartCursorBlink();
+        }
 
 
-  // Convert the cursor position into the glyph position.
-  CharacterIndex characterIndex = logical;
-  if( cursorInfo.isSecondaryCursor &&
-      ( isRightToLeftParagraph != isCurrentRightToLeft ) )
-  {
-    characterIndex = previousLogical;
-  }
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHighlightActive( false );
 
 
-  const GlyphIndex currentGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
-  const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
-  const Length numberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() +currentGlyphIndex );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          SetPopupButtons();
+          mEventData->mDecorator->SetPopupActive( true );
+        }
+        HideClipboard();
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::TEXT_PANNING:
+      {
+        mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+        mEventData->mDecorator->StopCursorBlink();
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+        if( mEventData->mDecorator->IsHandleActive( LEFT_SELECTION_HANDLE ) ||
+            mEventData->mDecorator->IsHandleActive( RIGHT_SELECTION_HANDLE ) )
+        {
+          mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+          mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+          mEventData->mDecorator->SetHighlightActive( true );
+        }
 
 
-  // Get the metrics for the group of glyphs.
-  GlyphMetrics glyphMetrics;
-  GetGlyphsMetrics( currentGlyphIndex,
-                    numberOfGlyphs,
-                    glyphMetrics,
-                    mVisualModel,
-                    mFontClient );
+        if( mEventData->mGrabHandlePopupEnabled )
+        {
+          mEventData->mDecorator->SetPopupActive( false );
+        }
 
 
-  float interGlyphAdvance = 0.f;
-  if( !isLastPosition &&
-      ( numberOfCharacters > 1u ) )
-  {
-    const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + currentGlyphIndex );
-    interGlyphAdvance = static_cast<float>( characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( numberOfCharacters );
+        mEventData->mDecoratorUpdated = true;
+        break;
+      }
+    }
   }
   }
+}
 
 
-  // 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 )
+void Controller::Impl::GetCursorPosition( CharacterIndex logical,
+                                          CursorInfo& cursorInfo )
+{
+  if( !IsShowingRealText() )
   {
   {
-    // The position of the cursor after the last character needs special
-    // care depending on its direction and the direction of the paragraph.
-
-    if( cursorInfo.isSecondaryCursor )
-    {
-      // 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!
-      characterIndex = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
-      characterIndex = mLogicalModel->GetLogicalCharacterIndex( characterIndex );
-
-      const GlyphIndex glyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
-      const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
-
-      const Vector2& position = *( mVisualModel->mGlyphPositions.Begin() + glyphIndex );
+    // Do not want to use the place-holder text to set the cursor position.
 
 
-      // Get the metrics for the group of glyphs.
-      GlyphMetrics glyphMetrics;
-      GetGlyphsMetrics( glyphIndex,
-                        numberOfGlyphs,
-                        glyphMetrics,
-                        mVisualModel,
-                        mFontClient );
+    // 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.
 
 
-      cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + position.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
+    cursorInfo.lineOffset = 0.f;
+    cursorInfo.lineHeight = GetDefaultFontLineHeight();
+    cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
 
 
-      cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
-    }
-    else
+    switch( mLayoutEngine.GetHorizontalAlignment() )
     {
     {
-      if( !isCurrentRightToLeft )
+      case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
       {
       {
-        cursorInfo.primaryPosition.x += glyphMetrics.advance;
+        cursorInfo.primaryPosition.x = 0.f;
+        break;
       }
       }
-      else
+      case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
+      {
+        cursorInfo.primaryPosition.x = floorf( 0.5f * mVisualModel->mControlSize.width );
+        break;
+      }
+      case LayoutEngine::HORIZONTAL_ALIGN_END:
       {
       {
-        cursorInfo.primaryPosition.x -= glyphMetrics.advance;
+        cursorInfo.primaryPosition.x = mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+        break;
       }
     }
       }
     }
-  }
-
-  // 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 );
 
 
-    // Get the glyph position.
-    const Vector2& previousPosition = *( mVisualModel->mGlyphPositions.Begin() + previousGlyphIndex );
+    // Nothing else to do.
+    return;
+  }
 
 
-    // Get the metrics for the group of glyphs.
-    GlyphMetrics glyphMetrics;
-    GetGlyphsMetrics( previousGlyphIndex,
-                      numberOfGlyphs,
-                      glyphMetrics,
-                      mVisualModel,
-                      mFontClient );
+  Text::GetCursorPosition( mVisualModel,
+                           mLogicalModel,
+                           mMetrics,
+                           logical,
+                           cursorInfo );
 
 
-    // Set the cursor position and height.
-    cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + previousPosition.x + ( ( ( isLastPosition && !isCurrentRightToLeft ) ||
-                                                                                       ( !isLastPosition && isCurrentRightToLeft )    ) ? glyphMetrics.advance : 0.f );
+  if( LayoutEngine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
+  {
+    // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
 
 
-    cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
+    // Note the white spaces laid-out at the end of the line might exceed the boundaries of the control.
+    // The reason is a wrapped line must not start with a white space so they are laid-out at the end of the line.
 
 
-    cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
+    if( 0.f > cursorInfo.primaryPosition.x )
+    {
+      cursorInfo.primaryPosition.x = 0.f;
+    }
 
 
-    // Update the primary cursor height as well.
-    cursorInfo.primaryCursorHeight *= 0.5f;
+    const float edgeWidth = mVisualModel->mControlSize.width - static_cast<float>( mEventData->mDecorator->GetCursorWidth() );
+    if( cursorInfo.primaryPosition.x > edgeWidth )
+    {
+      cursorInfo.primaryPosition.x = edgeWidth;
+    }
   }
 }
 
   }
 }
 
@@ -1266,25 +2454,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 );
     }
   }
 
     }
   }
 
@@ -1297,10 +2487,13 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index )
     cursorIndex += numberOfCharacters;
   }
 
     cursorIndex += numberOfCharacters;
   }
 
+  // Will update the cursor hook position.
+  mEventData->mUpdateCursorHookPosition = true;
+
   return cursorIndex;
 }
 
   return cursorIndex;
 }
 
-void Controller::Impl::UpdateCursorPosition()
+void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
   if( NULL == mEventData )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::UpdateCursorPosition %p\n", this );
   if( NULL == mEventData )
@@ -1310,121 +2503,57 @@ void Controller::Impl::UpdateCursorPosition()
     return;
   }
 
     return;
   }
 
-  if( IsShowingPlaceholderText() )
-  {
-    // Do not want to use the place-holder text to set the cursor position.
-
-    // 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.
-
-    float lineHeight = 0.f;
-
-    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 );
-
-    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 * mControlSize.width );
-        break;
-      }
-      case LayoutEngine::HORIZONTAL_ALIGN_END:
-      {
-        cursorPosition.x = mControlSize.width;
-        break;
-      }
-    }
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + mScrollPosition;
 
 
-    switch( mLayoutEngine.GetVerticalAlignment() )
-    {
-      case LayoutEngine::VERTICAL_ALIGN_TOP:
-      {
-        cursorPosition.y = 0.f;
-        break;
-      }
-      case LayoutEngine::VERTICAL_ALIGN_CENTER:
-      {
-        cursorPosition.y = floorf( 0.5f * ( mControlSize.height - lineHeight ) );
-        break;
-      }
-      case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
-      {
-        cursorPosition.y = mControlSize.height - lineHeight;
-        break;
-      }
-    }
+  // 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 );
 
 
-    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
-                                         lineHeight,
-                                         lineHeight );
-  }
-  else
+  if( mEventData->mUpdateGrabHandlePosition )
   {
   {
-    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,
     // Sets the grab handle position.
     mEventData->mDecorator->SetPosition( GRAB_HANDLE,
                                          cursorPosition.x,
-                                         cursorPosition.y,
+                                         cursorInfo.lineOffset + mScrollPosition.y,
+                                         cursorInfo.lineHeight );
+  }
+
+  if( cursorInfo.isSecondaryCursor )
+  {
+    mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+                                         cursorInfo.secondaryPosition.x + mScrollPosition.x,
+                                         cursorInfo.secondaryPosition.y + mScrollPosition.y,
+                                         cursorInfo.secondaryCursorHeight,
                                          cursorInfo.lineHeight );
                                          cursorInfo.lineHeight );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + mScrollPosition.x, cursorInfo.secondaryPosition.y + mScrollPosition.y );
+  }
 
 
+  // Set which cursors are active according the state.
+  if( EventData::IsEditingState( mEventData->mState ) || ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
+  {
     if( cursorInfo.isSecondaryCursor )
     {
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
     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 );
     }
   }
     }
     else
     {
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
     }
   }
+  else
+  {
+    mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+  }
+
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
 }
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::UpdateCursorPosition\n" );
 }
 
-void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
+void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
+                                              const CursorInfo& cursorInfo )
 {
   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
       ( RIGHT_SELECTION_HANDLE != handleType ) )
 {
   if( ( LEFT_SELECTION_HANDLE != handleType ) &&
       ( RIGHT_SELECTION_HANDLE != handleType ) )
@@ -1432,131 +2561,103 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
     return;
   }
 
     return;
   }
 
-  const bool leftSelectionHandle = LEFT_SELECTION_HANDLE == handleType;
-  const CharacterIndex index = leftSelectionHandle ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + mScrollPosition;
 
 
-  CursorInfo cursorInfo;
-  GetCursorPosition( index,
-                     cursorInfo );
-
-  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
-  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
-
-  // Sets the grab handle position.
+  // Sets the handle's position.
   mEventData->mDecorator->SetPosition( handleType,
                                        cursorPosition.x,
   mEventData->mDecorator->SetPosition( handleType,
                                        cursorPosition.x,
-                                       cursorPosition.y,
+                                       cursorInfo.lineOffset + mScrollPosition.y,
                                        cursorInfo.lineHeight );
                                        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 )
+void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
 {
 {
-  // Clamp between -space & 0 (and the text alignment).
-  if( actualSize.width > mControlSize.width )
+  // Clamp between -space & 0.
+
+  if( layoutSize.width > mVisualModel->mControlSize.width )
   {
   {
-    const float space = ( actualSize.width - 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;
+    const float space = ( layoutSize.width - mVisualModel->mControlSize.width );
+    mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x;
+    mScrollPosition.x = ( mScrollPosition.x > 0.f ) ? 0.f : mScrollPosition.x;
 
     mEventData->mDecoratorUpdated = true;
   }
   else
   {
 
     mEventData->mDecoratorUpdated = true;
   }
   else
   {
-    mEventData->mScrollPosition.x = 0.f;
+    mScrollPosition.x = 0.f;
   }
 }
 
   }
 }
 
-void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
+void Controller::Impl::ClampVerticalScroll( const Vector2& layoutSize )
 {
 {
-  // Clamp between -space & 0 (and the text alignment).
-  if( actualSize.height > mControlSize.height )
+  // Clamp between -space & 0.
+  if( layoutSize.height > mVisualModel->mControlSize.height )
   {
   {
-    const float space = ( actualSize.height - 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;
+    const float space = ( layoutSize.height - mVisualModel->mControlSize.height );
+    mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y;
+    mScrollPosition.y = ( mScrollPosition.y > 0.f ) ? 0.f : mScrollPosition.y;
 
     mEventData->mDecoratorUpdated = true;
   }
   else
   {
 
     mEventData->mDecoratorUpdated = true;
   }
   else
   {
-    mEventData->mScrollPosition.y = 0.f;
+    mScrollPosition.y = 0.f;
   }
 }
 
   }
 }
 
-void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position )
+void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, float lineHeight )
 {
 {
-  Vector2 offset;
-  bool updateDecorator = false;
-  if( position.x < 0.f )
+  const float cursorWidth = mEventData->mDecorator ? static_cast<float>( mEventData->mDecorator->GetCursorWidth() ) : 0.f;
+
+  // position is in actor's coords.
+  const float positionEndX = position.x + cursorWidth;
+  const float positionEndY = position.y + lineHeight;
+
+  // Transform the position to decorator coords.
+  const float decoratorPositionBeginX = position.x + mScrollPosition.x;
+  const float decoratorPositionEndX = positionEndX + mScrollPosition.x;
+
+  const float decoratorPositionBeginY = position.y + mScrollPosition.y;
+  const float decoratorPositionEndY = positionEndY + mScrollPosition.y;
+
+  if( decoratorPositionBeginX < 0.f )
   {
   {
-    offset.x = -position.x;
-    mEventData->mScrollPosition.x += offset.x;
-    updateDecorator = true;
+    mScrollPosition.x = -position.x;
   }
   }
-  else if( position.x > mControlSize.width )
+  else if( decoratorPositionEndX > mVisualModel->mControlSize.width )
   {
   {
-    offset.x = mControlSize.width - position.x;
-    mEventData->mScrollPosition.x += offset.x;
-    updateDecorator = true;
+    mScrollPosition.x = mVisualModel->mControlSize.width - positionEndX;
   }
 
   }
 
-  if( updateDecorator && mEventData->mDecorator )
+  if( decoratorPositionBeginY < 0.f )
   {
   {
-    mEventData->mDecorator->UpdatePositions( offset );
+    mScrollPosition.y = -position.y;
+  }
+  else if( decoratorPositionEndY > mVisualModel->mControlSize.height )
+  {
+    mScrollPosition.y = mVisualModel->mControlSize.height - positionEndY;
   }
   }
-
-  // TODO : calculate the vertical scroll.
 }
 
 }
 
-void Controller::Impl::ScrollTextToMatchCursor()
+void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
 {
   // Get the current cursor position in decorator coords.
   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
 
 {
   // 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.
   // 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() );
-  bool updateCursorPosition = true;
-
-  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
-  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
-
-  if( updateCursorPosition )
-  {
-    // Sets the cursor position.
-    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
-                                         cursorInfo.primaryCursorHeight,
-                                         cursorInfo.lineHeight );
+  mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
+  mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset;
 
 
-    // Sets the grab handle position.
-    mEventData->mDecorator->SetPosition( GRAB_HANDLE,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
-                                         cursorInfo.lineHeight );
+  ClampHorizontalScroll( mVisualModel->GetLayoutSize() );
+  ClampVerticalScroll( mVisualModel->GetLayoutSize() );
 
 
-    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 );
-    }
-  }
+  // Makes the new cursor position visible if needed.
+  ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
 }
 
 void Controller::Impl::RequestRelayout()
 }
 
 void Controller::Impl::RequestRelayout()