Merge "TextController - Update the text model." into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
index 35c43b0..f64c266 100644 (file)
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/color-segmentation.h>
+#include <dali-toolkit/internal/text/glyph-metrics-helper.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
 {
 
 #if defined(DEBUG_ENABLED)
 
 namespace
 {
 
 #if defined(DEBUG_ENABLED)
-  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_CONTROLS");
+  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
 #endif
 
 #endif
 
-/**
- * @brief Some characters can be shaped in more than one glyph.
- * This struct is used to retrieve metrics from these group of glyphs.
- */
-struct GlyphMetrics
-{
-  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.
-};
-
-const std::string EMPTY_STRING("");
-
 } // namespace
 
 namespace Dali
 } // namespace
 
 namespace Dali
@@ -75,43 +50,9 @@ 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 ),
   mPlaceholderTextActive(),
   mPlaceholderTextInactive(),
   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
@@ -128,15 +69,20 @@ EventData::EventData( DecoratorPtr decorator )
   mDecoratorUpdated( false ),
   mCursorBlinkEnabled( true ),
   mGrabHandleEnabled( true ),
   mDecoratorUpdated( false ),
   mCursorBlinkEnabled( true ),
   mGrabHandleEnabled( true ),
-  mGrabHandlePopupEnabled( false ),
-  mSelectionEnabled( false ),
+  mGrabHandlePopupEnabled( true ),
+  mSelectionEnabled( true ),
   mHorizontalScrollingEnabled( true ),
   mVerticalScrollingEnabled( false ),
   mUpdateCursorPosition( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
   mHorizontalScrollingEnabled( true ),
   mVerticalScrollingEnabled( false ),
   mUpdateCursorPosition( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
-  mScrollAfterUpdateCursorPosition( false )
-{}
+  mScrollAfterUpdatePosition( false ),
+  mScrollAfterDelete( false ),
+  mAllTextSelected( false ),
+  mUpdateInputStyle( false )
+{
+  mImfManager = ImfManager::Get();
+}
 
 EventData::~EventData()
 {}
 
 EventData::~EventData()
 {}
@@ -159,28 +105,43 @@ 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;
+        }
       }
     }
   }
       }
     }
   }
@@ -189,64 +150,525 @@ bool Controller::Impl::ProcessInputEvents()
   if( mEventData->mUpdateCursorPosition )
   {
     // Updates the cursor position and scrolls the text to make it visible.
   if( mEventData->mUpdateCursorPosition )
   {
     // Updates the cursor position and scrolls the text to make it visible.
+    CursorInfo cursorInfo;
+    GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                       cursorInfo );
 
 
-    UpdateCursorPosition();
-
-    if( mEventData->mScrollAfterUpdateCursorPosition )
+    if( mEventData->mScrollAfterUpdatePosition )
+    {
+      ScrollToMakePositionVisible( cursorInfo.primaryPosition );
+      mEventData->mScrollAfterUpdatePosition = false;
+    }
+    else if( mEventData->mScrollAfterDelete )
     {
     {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
+      ScrollTextToMatchCursor( cursorInfo );
+      mEventData->mScrollAfterDelete = false;
     }
 
     }
 
+    UpdateCursorPosition( cursorInfo );
+
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
   }
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
   }
-  else if( mEventData->mUpdateLeftSelectionPosition )
+  else
   {
   {
-    UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
+    bool leftScroll = false;
+    bool rightScroll = false;
 
 
-    if( mEventData->mScrollAfterUpdateCursorPosition )
+    CursorInfo leftHandleInfo;
+    CursorInfo rightHandleInfo;
+
+    if( mEventData->mUpdateLeftSelectionPosition )
     {
     {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
+      GetCursorPosition( mEventData->mLeftSelectionPosition,
+                         leftHandleInfo );
+
+      if( mEventData->mScrollAfterUpdatePosition )
+      {
+        ScrollToMakePositionVisible( leftHandleInfo.primaryPosition );
+        leftScroll = true;
+      }
     }
 
     }
 
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateLeftSelectionPosition = false;
-  }
-  else if( mEventData->mUpdateRightSelectionPosition )
-  {
-    UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+    if( mEventData->mUpdateRightSelectionPosition )
+    {
+      GetCursorPosition( mEventData->mRightSelectionPosition,
+                         rightHandleInfo );
+
+      if( mEventData->mScrollAfterUpdatePosition )
+      {
+        ScrollToMakePositionVisible( rightHandleInfo.primaryPosition );
+        rightScroll = true;
+      }
+    }
+
+    if( mEventData->mUpdateLeftSelectionPosition )
+    {
+      UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
+                             leftHandleInfo );
 
 
-    if( mEventData->mScrollAfterUpdateCursorPosition )
+      SetPopupButtons();
+      mEventData->mDecoratorUpdated = true;
+    }
+
+    if( mEventData->mUpdateRightSelectionPosition )
     {
     {
-      ScrollToMakeCursorVisible();
-      mEventData->mScrollAfterUpdateCursorPosition = false;
+      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
+                             rightHandleInfo );
+
+      SetPopupButtons();
+      mEventData->mDecoratorUpdated = true;
     }
 
     }
 
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateRightSelectionPosition = false;
+    if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+    {
+      RepositionSelectionHandles();
+
+      mEventData->mUpdateLeftSelectionPosition = false;
+      mEventData->mUpdateRightSelectionPosition = false;
+    }
+
+    if( leftScroll || rightScroll )
+    {
+      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();
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
 
   }
 
   mEventData->mEventQueue.clear();
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
 
-  bool decoratorUpdated = mEventData->mDecoratorUpdated;
+  const bool decoratorUpdated = mEventData->mDecoratorUpdated;
   mEventData->mDecoratorUpdated = false;
   mEventData->mDecoratorUpdated = false;
+
   return decoratorUpdated;
 }
 
   return decoratorUpdated;
 }
 
+void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
+{
+  mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+  mTextUpdateInfo.mStartGlyphIndex = 0u;
+  mTextUpdateInfo.mStartLineIndex = 0u;
+  numberOfCharacters = 0u;
+
+  const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
+  if( 0u == numberOfParagraphs )
+  {
+    mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+    numberOfCharacters = 0u;
+
+    mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+
+    // Nothing else to do if there are no paragraphs.
+    return;
+  }
+
+  // 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 )
+    {
+      // 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;
+
+      mTextUpdateInfo.mStartGlyphIndex = mVisualModel->mGlyphs.Count();
+      mTextUpdateInfo.mStartLineIndex = mVisualModel->mLines.Count() - 1u;
+
+      // Nothing else to do;
+      return;
+    }
+
+    paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
+  }
+  else
+  {
+    CharacterIndex lastIndex = 0u;
+    if( mTextUpdateInfo.mFullRelayoutNeeded )
+    {
+      lastIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+    }
+    else
+    {
+      lastIndex = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
+    }
+    mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
+                                   lastIndex,
+                                   paragraphsToBeUpdated );
+  }
+
+  if( 0u != paragraphsToBeUpdated.Count() )
+  {
+    const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
+    const ParagraphRun& firstParagraph = *( mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
+    mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
+
+    ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
+    const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
+
+    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 );
+
+      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::ClearFullModelData( OperationsMask operations )
+{
+  if( GET_LINE_BREAKS & operations )
+  {
+    mLogicalModel->mLineBreakInfo.Clear();
+    mLogicalModel->mParagraphInfo.Clear();
+  }
+
+  if( GET_WORD_BREAKS & operations )
+  {
+    mLogicalModel->mLineBreakInfo.Clear();
+  }
+
+  if( GET_SCRIPTS & operations )
+  {
+    mLogicalModel->mScriptRuns.Clear();
+  }
+
+  if( VALIDATE_FONTS & operations )
+  {
+    mLogicalModel->mFontRuns.Clear();
+  }
+
+  if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
+  {
+    if( BIDI_INFO & operations )
+    {
+      mLogicalModel->mBidirectionalParagraphInfo.Clear();
+      mLogicalModel->mCharacterDirections.Clear();
+    }
+
+    if( REORDER & operations )
+    {
+      // 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();
+
+      mLogicalModel->mLogicalToVisualMap.Clear();
+      mLogicalModel->mVisualToLogicalMap.Clear();
+    }
+  }
+
+  if( SHAPE_TEXT & operations )
+  {
+    mVisualModel->mGlyphs.Clear();
+    mVisualModel->mGlyphsToCharacters.Clear();
+    mVisualModel->mCharactersToGlyph.Clear();
+    mVisualModel->mCharactersPerGlyph.Clear();
+    mVisualModel->mGlyphsPerCharacter.Clear();
+    mVisualModel->mGlyphPositions.Clear();
+  }
+
+  if( LAYOUT & operations )
+  {
+    mVisualModel->mLines.Clear();
+  }
+}
+
+void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+
+  if( GET_LINE_BREAKS & operations )
+  {
+    // Clear the line break info.
+    LineBreakInfo* lineBreakInfoBuffer = mLogicalModel->mLineBreakInfo.Begin();
+
+    mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
+                                         lineBreakInfoBuffer + endIndexPlusOne );
+
+    // Clear the paragraphs.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mParagraphInfo );
+  }
+
+  if( GET_WORD_BREAKS & operations )
+  {
+    // Clear the word break info.
+    WordBreakInfo* wordBreakInfoBuffer = mLogicalModel->mWordBreakInfo.Begin();
+
+    mLogicalModel->mWordBreakInfo.Erase( wordBreakInfoBuffer + startIndex,
+                                         wordBreakInfoBuffer + endIndexPlusOne );
+  }
+
+  if( GET_SCRIPTS & operations )
+  {
+    // Clear the scripts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mScriptRuns );
+  }
+
+  if( VALIDATE_FONTS & operations )
+  {
+    // Clear the fonts.
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mLogicalModel->mFontRuns );
+  }
+
+  if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
+  {
+    if( 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( 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 );
+
+      // Clear the logical to visual and the visual to logical conversion tables.
+      CharacterIndex* logicalToVisualMapBuffer = mLogicalModel->mLogicalToVisualMap.Begin();
+      mLogicalModel->mLogicalToVisualMap.Erase( logicalToVisualMapBuffer + startIndex,
+                                                logicalToVisualMapBuffer + endIndexPlusOne );
+
+      CharacterIndex* visualToLogicalMapBuffer = mLogicalModel->mVisualToLogicalMap.Begin();
+      mLogicalModel->mVisualToLogicalMap.Erase( visualToLogicalMapBuffer + startIndex,
+                                                visualToLogicalMapBuffer + endIndexPlusOne );
+    }
+  }
+}
+
+void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+  const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
+
+  const bool clearShape = SHAPE_TEXT & operations;
+  const bool clearLayout = LAYOUT & operations;
+
+  if( clearShape || clearLayout )
+  {
+    // 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 endGlyphIndex = *( charactersToGlyphBuffer + endIndex );
+    const GlyphIndex endGlyphIndexPlusOne = endGlyphIndex + *( glyphsPerCharacterBuffer + endIndex );
+    const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
+
+    if( clearShape )
+    {
+      // 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( clearLayout )
+    {
+      // 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.
+      uint32_t startRemoveGlyphIndex = mVisualModel->mLines.Count();
+      uint32_t endRemoveGlyphIndex = startRemoveIndex;
+      ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
+                      endGlyphIndex,
+                      mVisualModel->mLines,
+                      startRemoveGlyphIndex,
+                      endRemoveGlyphIndex );
+
+      // 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 );
+    }
+  }
+}
+
+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();
+
+  // TODO finish the mark-up.
+  mVisualModel->mColorRuns.Clear();
+}
+
 void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 {
 void 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 );
 
   // 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;
+  }
+
   Vector<Character>& utf32Characters = mLogicalModel->mText;
 
   const Length numberOfCharacters = utf32Characters.Count();
 
   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 ), operationsRequired );
+  }
+
+  mTextUpdateInfo.mClearAll = false;
+
   Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
   Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
+  const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
+
   if( GET_LINE_BREAKS & operations )
   {
     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
   if( GET_LINE_BREAKS & operations )
   {
     // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
@@ -256,7 +678,13 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
 
     SetLineBreakInfo( utf32Characters,
     lineBreakInfo.Resize( numberOfCharacters, TextAbstraction::LINE_NO_BREAK );
 
     SetLineBreakInfo( utf32Characters,
+                      startIndex,
+                      requestedNumberOfCharacters,
                       lineBreakInfo );
                       lineBreakInfo );
+
+    // Create the paragraph info.
+    mLogicalModel->CreateParagraphInfo( startIndex,
+                                        requestedNumberOfCharacters );
   }
 
   Vector<WordBreakInfo>& wordBreakInfo = mLogicalModel->mWordBreakInfo;
   }
 
   Vector<WordBreakInfo>& wordBreakInfo = mLogicalModel->mWordBreakInfo;
@@ -266,6 +694,8 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
 
     SetWordBreakInfo( utf32Characters,
     wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
 
     SetWordBreakInfo( utf32Characters,
+                      startIndex,
+                      requestedNumberOfCharacters,
                       wordBreakInfo );
   }
 
                       wordBreakInfo );
   }
 
@@ -285,45 +715,36 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     {
       // Retrieves the scripts used in the text.
       multilanguageSupport.SetScripts( utf32Characters,
     {
       // Retrieves the scripts used in the text.
       multilanguageSupport.SetScripts( utf32Characters,
-                                       lineBreakInfo,
+                                       startIndex,
+                                       requestedNumberOfCharacters,
                                        scripts );
     }
 
     if( validateFonts )
     {
                                        scripts );
     }
 
     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 );
-      }
+      // 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,
 
       // 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 );
     }
   }
 
   Vector<Character> mirroredUtf32Characters;
   bool textMirrored = false;
                                           validFonts );
     }
   }
 
   Vector<Character> mirroredUtf32Characters;
   bool textMirrored = false;
+  const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
   if( BIDI_INFO & operations )
   {
   if( BIDI_INFO & operations )
   {
-    // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
-    // bidirectional info.
-
-    Length numberOfParagraphs = 0u;
-
-    const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
-    for( Length index = 0u; index < numberOfCharacters; ++index )
-    {
-      if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
-      {
-        ++numberOfParagraphs;
-      }
-    }
-
     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
     bidirectionalInfo.Reserve( numberOfParagraphs );
 
     Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
     bidirectionalInfo.Reserve( numberOfParagraphs );
 
@@ -331,33 +752,44 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     SetBidirectionalInfo( utf32Characters,
                           scripts,
                           lineBreakInfo,
     SetBidirectionalInfo( utf32Characters,
                           scripts,
                           lineBreakInfo,
+                          startIndex,
+                          requestedNumberOfCharacters,
                           bidirectionalInfo );
 
     if( 0u != bidirectionalInfo.Count() )
     {
                           bidirectionalInfo );
 
     if( 0u != bidirectionalInfo.Count() )
     {
-      // This paragraph has right to left text. Some characters may need to be mirrored.
-      // TODO: consider if the mirrored string can be stored as well.
-
-      textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
-
       // Only set the character directions if there is right to left characters.
       Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
       // Only set the character directions if there is right to left characters.
       Vector<CharacterDirection>& directions = mLogicalModel->mCharacterDirections;
-      directions.Resize( numberOfCharacters );
-
       GetCharactersDirection( bidirectionalInfo,
       GetCharactersDirection( bidirectionalInfo,
+                              numberOfCharacters,
+                              startIndex,
+                              requestedNumberOfCharacters,
                               directions );
                               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();
     }
     }
     else
     {
       // There is no right to left characters. Clear the directions vector.
       mLogicalModel->mCharacterDirections.Clear();
     }
-
-   }
+  }
 
   Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
   Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
   Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
 
   Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
   Vector<CharacterIndex>& glyphsToCharactersMap = mVisualModel->mGlyphsToCharacters;
   Vector<Length>& charactersPerGlyph = mVisualModel->mCharactersPerGlyph;
+  Vector<GlyphIndex> newParagraphGlyphs;
+  newParagraphGlyphs.Reserve( numberOfParagraphs );
+
+  const Length currentNumberOfGlyphs = glyphs.Count();
   if( SHAPE_TEXT & operations )
   {
     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
   if( SHAPE_TEXT & operations )
   {
     const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
@@ -366,35 +798,137 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                lineBreakInfo,
                scripts,
                validFonts,
                lineBreakInfo,
                scripts,
                validFonts,
+               startIndex,
+               mTextUpdateInfo.mStartGlyphIndex,
+               requestedNumberOfCharacters,
                glyphs,
                glyphsToCharactersMap,
                glyphs,
                glyphsToCharactersMap,
-               charactersPerGlyph );
+               charactersPerGlyph,
+               newParagraphGlyphs );
 
     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
 
     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-    mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
-    mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
+    mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+    mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
   }
 
   }
 
-  const Length numberOfGlyphs = glyphs.Count();
+  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
 
   if( GET_GLYPH_METRICS & operations )
   {
 
   if( GET_GLYPH_METRICS & operations )
   {
-    mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
+    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;
+    }
   }
   }
+
+  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;
+}
+
+bool Controller::Impl::UpdateModelStyle( OperationsMask operationsRequired )
+{
+  bool updated = false;
+
+  if( COLOR & operationsRequired )
+  {
+    // Set the color runs in glyphs.
+    SetColorSegmentationInfo( mLogicalModel->mColorRuns,
+                              mVisualModel->mCharactersToGlyph,
+                              mVisualModel->mGlyphsPerCharacter,
+                              mVisualModel->mColorRuns );
+
+    updated = true;
+  }
+
+  return updated;
 }
 
 }
 
-void Controller::Impl::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
+void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
 {
 {
+  // Sets the default text's color.
+  inputStyle.textColor = mTextColor;
+
+  // Sets the default font's family name, weight, width, slant and size.
   if( mFontDefaults )
   {
   if( mFontDefaults )
   {
-    FontRun fontRun;
-    fontRun.characterRun.characterIndex = 0;
-    fontRun.characterRun.numberOfCharacters = numberOfCharacters;
-    fontRun.fontId = mFontDefaults->GetFontId( mFontClient );
-    fontRun.isDefault = true;
+    inputStyle.familyName = mFontDefaults->mFontDescription.family;
+    inputStyle.weight = mFontDefaults->mFontDescription.weight;
+    inputStyle.width = mFontDefaults->mFontDescription.width;
+    inputStyle.slant = mFontDefaults->mFontDescription.slant;
+    inputStyle.size = mFontDefaults->mDefaultPointSize;
+
+    inputStyle.familyDefined = mFontDefaults->familyDefined;
+    inputStyle.weightDefined = mFontDefaults->weightDefined;
+    inputStyle.widthDefined = mFontDefaults->widthDefined;
+    inputStyle.slantDefined = mFontDefaults->slantDefined;
+    inputStyle.sizeDefined = mFontDefaults->sizeDefined;
+  }
+  else
+  {
+    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;
+  }
+}
 
 
-    fonts.PushBack( fontRun );
+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 )
 }
 
 void Controller::Impl::OnCursorKeyEvent( const Event& event )
@@ -416,7 +950,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   }
   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
   {
   }
   else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
   {
-    if( mLogicalModel->GetNumberOfCharacters() > mEventData->mPrimaryCursorPosition )
+    if( mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
     {
       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
     }
     {
       mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
     }
@@ -431,7 +965,8 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   }
 
   mEventData->mUpdateCursorPosition = true;
   }
 
   mEventData->mUpdateCursorPosition = true;
-  mEventData->mScrollAfterUpdateCursorPosition = true;
+  mEventData->mUpdateInputStyle = true;
+  mEventData->mScrollAfterUpdatePosition = true;
 }
 
 void Controller::Impl::OnTapEvent( const Event& event )
 }
 
 void Controller::Impl::OnTapEvent( const Event& event )
@@ -442,13 +977,16 @@ void Controller::Impl::OnTapEvent( const Event& event )
 
     if( 1u == tapCount )
     {
 
     if( 1u == tapCount )
     {
-      if( ! IsShowingPlaceholderText() )
+      if( IsShowingRealText() )
       {
         const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
         const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
 
         mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
                                                                     yPosition );
       {
         const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
         const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
 
         mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
                                                                     yPosition );
+
+        // When the cursor position is changing, delay cursor blinking
+        mEventData->mDecorator->DelayCursorBlink();
       }
       else
       {
       }
       else
       {
@@ -456,12 +994,15 @@ void Controller::Impl::OnTapEvent( const Event& event )
       }
 
       mEventData->mUpdateCursorPosition = true;
       }
 
       mEventData->mUpdateCursorPosition = true;
-      mEventData->mScrollAfterUpdateCursorPosition = true;
-    }
-    else if( mEventData->mSelectionEnabled &&
-             ( 2u == tapCount ) )
-    {
-      RepositionSelectionHandles( event.p2.mFloat, event.p3.mFloat );
+      mEventData->mScrollAfterUpdatePosition = true;
+      mEventData->mUpdateInputStyle = true;
+
+      // Notify the cursor position to the imf manager.
+      if( mEventData->mImfManager )
+      {
+        mEventData->mImfManager.SetCursorPosition( mEventData->mPrimaryCursorPosition );
+        mEventData->mImfManager.NotifyCursorPosition();
+      }
     }
   }
 }
     }
   }
 }
@@ -479,7 +1020,7 @@ void Controller::Impl::OnPanEvent( const Event& event )
   if( Gesture::Started    == state ||
       Gesture::Continuing == state )
   {
   if( Gesture::Started    == state ||
       Gesture::Continuing == state )
   {
-    const Vector2& actualSize = mVisualModel->GetActualSize();
+    const Vector2& actualSize = mVisualModel->GetLayoutSize();
     const Vector2 currentScroll = mEventData->mScrollPosition;
 
     if( mEventData->mHorizontalScrollingEnabled )
     const Vector2 currentScroll = mEventData->mScrollPosition;
 
     if( mEventData->mHorizontalScrollingEnabled )
@@ -505,6 +1046,17 @@ 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 )
 void Controller::Impl::OnHandleEvent( const Event& event )
 {
   if( NULL == mEventData )
@@ -514,6 +1066,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
   }
 
   const unsigned int state = event.p1.mUint;
   }
 
   const unsigned int state = event.p1.mUint;
+  const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
 
   if( HANDLE_PRESSED == state )
   {
 
   if( HANDLE_PRESSED == state )
   {
@@ -525,7 +1078,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
-      ChangeState ( EventData::EDITING );
+      ChangeState ( EventData::GRAB_HANDLE_PANNING );
 
       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
       {
 
       if( handleNewPosition != mEventData->mPrimaryCursorPosition )
       {
@@ -535,58 +1088,471 @@ void Controller::Impl::OnHandleEvent( const Event& event )
     }
     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
     {
     }
     else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
     {
-      if( handleNewPosition != mEventData->mLeftSelectionPosition )
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mRightSelectionPosition ) )
       {
         mEventData->mLeftSelectionPosition = handleNewPosition;
       {
         mEventData->mLeftSelectionPosition = handleNewPosition;
+
         mEventData->mUpdateLeftSelectionPosition = true;
       }
     }
     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
         mEventData->mUpdateLeftSelectionPosition = true;
       }
     }
     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
-      if( handleNewPosition != mEventData->mRightSelectionPosition )
+      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
+
+      if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
+          ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
       {
         mEventData->mRightSelectionPosition = handleNewPosition;
       {
         mEventData->mRightSelectionPosition = handleNewPosition;
+
         mEventData->mUpdateRightSelectionPosition = true;
       }
     }
         mEventData->mUpdateRightSelectionPosition = true;
       }
     }
-  }
+  } // end ( HANDLE_PRESSED == state )
   else if( ( HANDLE_RELEASED == state ) ||
   else if( ( HANDLE_RELEASED == state ) ||
-           ( HANDLE_STOP_SCROLLING == state ) )
+           handleStopScrolling )
   {
   {
-    if( mEventData->mGrabHandlePopupEnabled )
+    CharacterIndex handlePosition = 0u;
+    if( handleStopScrolling )
     {
     {
-      ChangeState( EventData::EDITING_WITH_POPUP );
+      // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
+      const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
+      const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+
+      handlePosition = GetClosestCursorIndex( xPosition, yPosition );
     }
     }
+
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
       mEventData->mUpdateCursorPosition = true;
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
       mEventData->mUpdateCursorPosition = true;
+      mEventData->mUpdateInputStyle = true;
 
 
-      if( HANDLE_STOP_SCROLLING == state )
+      if( !IsClipboardEmpty() )
       {
       {
-        // 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;
+        ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
+      }
+
+      if( handleStopScrolling )
+      {
+        mEventData->mScrollAfterUpdatePosition = mEventData->mPrimaryCursorPosition != handlePosition;
+        mEventData->mPrimaryCursorPosition = handlePosition;
+      }
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
 
 
-        mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
+      if( handleStopScrolling )
+      {
+        mEventData->mUpdateLeftSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition );
+        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
 
 
-        mEventData->mScrollAfterUpdateCursorPosition = true;
+        if( mEventData->mUpdateLeftSelectionPosition )
+        {
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
       }
     }
       }
     }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::SELECTING );
+
+      if( handleStopScrolling )
+      {
+        mEventData->mUpdateRightSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition );
+        mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
+        if( mEventData->mUpdateRightSelectionPosition )
+        {
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+      }
+    }
+
     mEventData->mDecoratorUpdated = true;
     mEventData->mDecoratorUpdated = true;
-  }
+  } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
   else if( HANDLE_SCROLLING == state )
   {
     const float xSpeed = event.p2.mFloat;
   else if( HANDLE_SCROLLING == state )
   {
     const float xSpeed = event.p2.mFloat;
-    const Vector2& actualSize = mVisualModel->GetActualSize();
+    const Vector2& actualSize = mVisualModel->GetLayoutSize();
+    const Vector2 currentScrollPosition = mEventData->mScrollPosition;
 
     mEventData->mScrollPosition.x += xSpeed;
 
     ClampHorizontalScroll( actualSize );
 
 
     mEventData->mScrollPosition.x += xSpeed;
 
     ClampHorizontalScroll( actualSize );
 
-   mEventData->mDecoratorUpdated = true;
+    bool endOfScroll = false;
+    if( Vector2::ZERO == ( currentScrollPosition - mEventData->mScrollPosition ) )
+    {
+      // Notify the decorator there is no more text to scroll.
+      // The decorator won't send more scroll events.
+      mEventData->mDecorator->NotifyEndOfScroll();
+      // Still need to set the position of the handle.
+      endOfScroll = true;
+    }
+
+    // Set the position of the handle.
+    const bool scrollRightDirection = xSpeed > 0.f;
+    const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
+    const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
+
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      ChangeState( EventData::GRAB_HANDLE_PANNING );
+
+      Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
+
+      // Position the grag handle close to either the left or right edge.
+      position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
+
+      // Get the new handle position.
+      // The grab handle's position is in decorator coords. Need to transforms to text coords.
+      const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+                                                                   position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+      mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
+      mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
+      mEventData->mPrimaryCursorPosition = handlePosition;
+      mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
+    }
+    else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
+    {
+      // TODO: This is recalculating the selection box every time the text is scrolled with the selection handles.
+      //       Think if something can be done to save power.
+
+      ChangeState( EventData::SELECTION_HANDLE_PANNING );
+
+      Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+
+      // Position the selection handle close to either the left or right edge.
+      position.x = scrollRightDirection ? 0.f : mVisualModel->mControlSize.width;
+
+      // Get the new handle position.
+      // The selection handle's position is in decorator coords. Need to transforms to text coords.
+      const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+                                                                   position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+      if( leftSelectionHandleEvent )
+      {
+        const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
+        mEventData->mUpdateLeftSelectionPosition = endOfScroll || differentHandles;
+        if( differentHandles )
+        {
+          mEventData->mLeftSelectionPosition = handlePosition;
+        }
+      }
+      else
+      {
+        const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
+        mEventData->mUpdateRightSelectionPosition = endOfScroll || differentHandles;
+        if( differentHandles )
+        {
+          mEventData->mRightSelectionPosition = handlePosition;
+        }
+      }
+
+      if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+      {
+        RepositionSelectionHandles();
+
+        mEventData->mScrollAfterUpdatePosition = true;
+      }
+    }
+    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 )
+  {
+    // 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;
+
+    // Calculates the logical position from the x,y coords.
+    RepositionSelectionHandles( xPosition,
+                                yPosition );
+
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = true;
+
+    mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
+  }
+}
+
+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 )
+  {
+    mEventData->mLeftSelectionPosition = 0u;
+    mEventData->mRightSelectionPosition = mLogicalModel->mText.Count();
+
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateLeftSelectionPosition = true;
+    mEventData->mUpdateRightSelectionPosition = 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;
+
+      // Delete text between handles
+      Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
+      Vector<Character>::Iterator last  = first + lengthOfSelectedText;
+      utf32Characters.Erase( first, last );
+
+      // Scroll after delete.
+      mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
+      mEventData->mScrollAfterDelete = true;
+    }
+    // Udpade the cursor position and the decorator.
+    // Scroll after the position is updated if is not scrolling after delete.
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mScrollAfterUpdatePosition = !mEventData->mScrollAfterDelete;
+    mEventData->mDecoratorUpdated = true;
   }
 }
 
   }
 }
 
+void Controller::Impl::ShowClipboard()
+{
+  if( mClipboard )
+  {
+    mClipboard.ShowClipboard();
+  }
+}
+
+void Controller::Impl::HideClipboard()
+{
+  if( mClipboard )
+  {
+    mClipboard.HideClipboard();
+  }
+}
+
+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::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;
+
+  // TODO: Better algorithm to create the highlight box.
+  // TODO: Multi-line.
+
+  // Get the height of the line.
+  const Vector<LineRun>& lines = mVisualModel->mLines;
+  const LineRun& firstLine = *lines.Begin();
+  const float height = firstLine.ascender + -firstLine.descender;
+
+  const bool isLastCharacter = selectionEnd >= mLogicalModel->mText.Count();
+  const bool startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
+  const bool 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 );
+
+  // Check if the first glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
+  const Length numberOfCharactersStart = *( charactersPerGlyphBuffer + glyphStart );
+  bool splitStartGlyph = ( numberOfCharactersStart > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionStart ) );
+
+  // Check if the last glyph is a ligature that must be broken like Latin ff, fi, or Arabic ﻻ, etc which needs special code.
+  const Length numberOfCharactersEnd = *( charactersPerGlyphBuffer + glyphEnd );
+  bool splitEndGlyph = ( glyphStart != glyphEnd ) && ( numberOfCharactersEnd > 1u ) && HasLigatureMustBreak( mLogicalModel->GetScript( selectionEndMinusOne ) );
+
+  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+
+  // Traverse the glyphs.
+  for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
+  {
+    const GlyphInfo& glyph = *( glyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+
+    if( splitStartGlyph )
+    {
+      // If the first glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
+
+      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersStart );
+      const CharacterIndex interGlyphIndex = selectionStart - *( glyphToCharacterBuffer + glyphStart );
+      // Get the direction of the character.
+      CharacterDirection isCurrentRightToLeft = false;
+      if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      {
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionStart );
+      }
+
+      // The end point could be in the middle of the ligature.
+      // Calculate the number of characters selected.
+      const Length numberOfCharacters = ( glyphStart == glyphEnd ) ? ( selectionEnd - selectionStart ) : ( numberOfCharactersStart - interGlyphIndex );
+
+      const float xPosition = position.x - glyph.xBearing + offset.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
+
+      mEventData->mDecorator->AddHighlight( xPosition,
+                                            offset.y,
+                                            xPosition + static_cast<float>( numberOfCharacters ) * glyphAdvance,
+                                            offset.y + height );
+
+      splitStartGlyph = false;
+      continue;
+    }
+
+    if( splitEndGlyph && ( index == glyphEnd ) )
+    {
+      // Equally, if the last glyph is a ligature that must be broken it may be needed to add only part of the glyph to the highlight box.
+
+      const float glyphAdvance = glyph.advance / static_cast<float>( numberOfCharactersEnd );
+      const CharacterIndex interGlyphIndex = selectionEnd - *( glyphToCharacterBuffer + glyphEnd );
+      // Get the direction of the character.
+      CharacterDirection isCurrentRightToLeft = false;
+      if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+      {
+        isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + selectionEnd );
+      }
+
+      const Length numberOfCharacters = numberOfCharactersEnd - interGlyphIndex;
+
+      const float xPosition = position.x - glyph.xBearing + offset.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
+      mEventData->mDecorator->AddHighlight( xPosition,
+                                            offset.y,
+                                            xPosition + static_cast<float>( interGlyphIndex ) * glyphAdvance,
+                                            offset.y + height );
+
+      splitEndGlyph = false;
+      continue;
+    }
+
+    const float xPosition = position.x - glyph.xBearing + offset.x;
+    mEventData->mDecorator->AddHighlight( xPosition,
+                                          offset.y,
+                                          xPosition + glyph.advance,
+                                          offset.y + height );
+  }
+
+  CursorInfo primaryCursorInfo;
+  GetCursorPosition( mEventData->mLeftSelectionPosition,
+                     primaryCursorInfo );
+
+  CursorInfo secondaryCursorInfo;
+  GetCursorPosition( mEventData->mRightSelectionPosition,
+                     secondaryCursorInfo );
+
+  const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + offset;
+  const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + offset;
+
+  mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
+                                       primaryPosition.x,
+                                       primaryCursorInfo.lineOffset + offset.y,
+                                       primaryCursorInfo.lineHeight );
+
+  mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
+                                       secondaryPosition.x,
+                                       secondaryCursorInfo.lineOffset + offset.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;
+}
+
 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
 {
   if( NULL == mEventData )
 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
 {
   if( NULL == mEventData )
@@ -595,32 +1561,88 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY
     return;
   }
 
     return;
   }
 
-  // TODO - Find which word was selected
+  if( IsShowingPlaceholderText() )
+  {
+    // Nothing to do if there is the place-holder text.
+    return;
+  }
+
+  const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
+  const Length numberOfLines  = mVisualModel->mLines.Count();
+  if( ( 0 == numberOfGlyphs ) ||
+      ( 0 == numberOfLines ) )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
 
 
-  const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
-  const Vector<Vector2>::SizeType glyphCount = glyphs.Count();
+  // Find which word was selected
+  CharacterIndex selectionStart( 0 );
+  CharacterIndex selectionEnd( 0 );
+  FindSelectionIndices( visualX, visualY, selectionStart, selectionEnd );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
 
 
-  const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
-  const Vector<Vector2>::SizeType positionCount = positions.Count();
+  if( selectionStart == selectionEnd )
+  {
+    ChangeState( EventData::EDITING );
+    // Nothing to select. i.e. a white space, out of bounds
+    return;
+  }
 
 
-  // Guard against glyphs which did not fit inside the layout
-  const Vector<Vector2>::SizeType count = (positionCount < glyphCount) ? positionCount : glyphCount;
+  mEventData->mLeftSelectionPosition = selectionStart;
+  mEventData->mRightSelectionPosition = selectionEnd;
+}
 
 
-  if( count )
+void Controller::Impl::SetPopupButtons()
+{
+  /**
+   *  Sets the Popup buttons to be shown depending on State.
+   *
+   *  If SELECTING :  CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
+   *
+   *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
+   */
+
+  TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
+
+  if( EventData::SELECTING == mEventData->mState )
   {
   {
-    float primaryX   = positions[0].x + mEventData->mScrollPosition.x;
-    float secondaryX = positions[count-1].x + glyphs[count-1].width + mEventData->mScrollPosition.x;
+    buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
 
 
-    // TODO - multi-line selection
-    const Vector<LineRun>& lines = mVisualModel->mLines;
-    float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
+    if( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
 
 
-    mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,     primaryX, mEventData->mScrollPosition.y, height );
-    mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryX, mEventData->mScrollPosition.y, height );
+    if( !mEventData->mAllTextSelected )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
+    }
+  }
+  else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
+  {
+    if( mLogicalModel->mText.Count() && !IsShowingPlaceholderText() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
+    }
 
 
-    mEventData->mDecorator->ClearHighlights();
-    mEventData->mDecorator->AddHighlight( primaryX, mEventData->mScrollPosition.y, secondaryX, height + mEventData->mScrollPosition.y );
+    if( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
+  }
+  else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
+  {
+    if ( !IsClipboardEmpty() )
+    {
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+    }
   }
   }
+
+  mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
 }
 
 void Controller::Impl::ChangeState( EventData::State newState )
 }
 
 void Controller::Impl::ChangeState( EventData::State newState )
@@ -631,6 +1653,8 @@ void Controller::Impl::ChangeState( EventData::State newState )
     return;
   }
 
     return;
   }
 
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState );
+
   if( mEventData->mState != newState )
   {
     mEventData->mState = newState;
   if( mEventData->mState != newState )
   {
     mEventData->mState = newState;
@@ -644,14 +1668,29 @@ void Controller::Impl::ChangeState( EventData::State newState )
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
       mEventData->mDecorator->SetPopupActive( false );
       mEventData->mDecoratorUpdated = true;
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
       mEventData->mDecorator->SetPopupActive( false );
       mEventData->mDecoratorUpdated = true;
+      HideClipboard();
     }
     }
-    else if ( EventData::SELECTING == mEventData->mState )
+    else if( EventData::INTERRUPTED  == mEventData->mState)
+    {
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetPopupActive( false );
+      mEventData->mDecoratorUpdated = true;
+      HideClipboard();
+    }
+    else if( EventData::SELECTING == mEventData->mState )
     {
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
       mEventData->mDecorator->StopCursorBlink();
       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
     {
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
       mEventData->mDecorator->StopCursorBlink();
       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        SetPopupButtons();
+        mEventData->mDecorator->SetPopupActive( true );
+      }
       mEventData->mDecoratorUpdated = true;
     }
     else if( EventData::EDITING == mEventData->mState )
       mEventData->mDecoratorUpdated = true;
     }
     else if( EventData::EDITING == mEventData->mState )
@@ -665,25 +1704,110 @@ void Controller::Impl::ChangeState( EventData::State newState )
       mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
       mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
       mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
       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;
       mEventData->mDecoratorUpdated = true;
+      HideClipboard();
     }
     else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
     {
     }
     else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
     {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState );
+
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
       if( mEventData->mCursorBlinkEnabled )
       {
         mEventData->mDecorator->StartCursorBlink();
       }
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
       if( mEventData->mCursorBlinkEnabled )
       {
         mEventData->mDecorator->StartCursorBlink();
       }
-      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
       if( mEventData->mSelectionEnabled )
       {
       if( mEventData->mSelectionEnabled )
       {
-        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
-        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      }
+      else
+      {
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
       }
       if( mEventData->mGrabHandlePopupEnabled )
       {
       }
       if( mEventData->mGrabHandlePopupEnabled )
       {
+        SetPopupButtons();
+        mEventData->mDecorator->SetPopupActive( true );
+      }
+      HideClipboard();
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState );
+
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+      if( mEventData->mCursorBlinkEnabled )
+      {
+        mEventData->mDecorator->StartCursorBlink();
+      }
+      // Grab handle is not shown until a tap is received whilst EDITING
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+      HideClipboard();
+    }
+    else if( EventData::SELECTION_HANDLE_PANNING == mEventData->mState )
+    {
+      mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+      mEventData->mDecorator->StopCursorBlink();
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
+      if( mEventData->mGrabHandlePopupEnabled )
+      {
+        mEventData->mDecorator->SetPopupActive( false );
+      }
+      mEventData->mDecoratorUpdated = true;
+    }
+    else if( EventData::GRAB_HANDLE_PANNING == mEventData->mState )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState );
+
+      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;
+    }
+    else if( EventData::EDITING_WITH_PASTE_POPUP == mEventData->mState )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState );
+
+      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 )
+      {
+        SetPopupButtons();
         mEventData->mDecorator->SetPopupActive( true );
       }
         mEventData->mDecorator->SetPopupActive( true );
       }
+      HideClipboard();
       mEventData->mDecoratorUpdated = true;
     }
   }
       mEventData->mDecoratorUpdated = true;
     }
   }
@@ -707,12 +1831,65 @@ LineIndex Controller::Impl::GetClosestLine( float y ) const
     }
   }
 
     }
   }
 
+  if( lineIndex == 0 )
+  {
+    return 0;
+  }
+
   return lineIndex-1;
 }
 
   return lineIndex-1;
 }
 
+void Controller::Impl::FindSelectionIndices( float visualX, float visualY, CharacterIndex& startIndex, CharacterIndex& endIndex )
+{
+  CharacterIndex hitCharacter = GetClosestCursorIndex( visualX, visualY );
+  DALI_ASSERT_DEBUG( hitCharacter <= mLogicalModel->mText.Count() && "GetClosestCursorIndex returned out of bounds index" );
+
+  if( mLogicalModel->mText.Count() == 0 )
+  {
+    return;  // if model empty
+  }
+
+  if( hitCharacter >= mLogicalModel->mText.Count() )
+  {
+    // Closest hit character is the last character.
+    if( hitCharacter ==  mLogicalModel->mText.Count() )
+    {
+      hitCharacter--; //Hit character index set to last character in logical model
+    }
+    else
+    {
+      // hitCharacter is out of bounds
+      return;
+    }
+  }
+
+  startIndex = hitCharacter;
+  endIndex = hitCharacter;
+  bool isHitCharacterWhitespace = TextAbstraction::IsWhiteSpace( mLogicalModel->mText[hitCharacter] );
+
+  // Find the start and end of the text
+  for( startIndex = hitCharacter; startIndex > 0; --startIndex )
+  {
+    if( isHitCharacterWhitespace != TextAbstraction::IsWhiteSpace( mLogicalModel->mText[ startIndex-1 ] ) )
+    {
+      break;
+    }
+  }
+  const CharacterIndex pastTheEnd = mLogicalModel->mText.Count();
+  for( endIndex = hitCharacter + 1u; endIndex < pastTheEnd; ++endIndex )
+  {
+    if( isHitCharacterWhitespace != TextAbstraction::IsWhiteSpace( mLogicalModel->mText[ endIndex ] ) )
+    {
+      break;
+    }
+  }
+}
+
 CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
                                                         float visualY )
 {
 CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
                                                         float visualY )
 {
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetClosestCursorIndex %p closest visualX %f visualY %f\n", this, visualX, visualY );
+
   if( NULL == mEventData )
   {
     // Nothing to do if there is no text input.
   if( NULL == mEventData )
   {
     // Nothing to do if there is no text input.
@@ -723,8 +1900,8 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
 
   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 ) )
   {
     return logicalIndex;
   }
   {
     return logicalIndex;
   }
@@ -747,6 +1924,9 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
   // Get the glyphs per character table.
   const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
 
   // Get the glyphs per character table.
   const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
 
+  // Get the glyph's info buffer.
+  const GlyphInfo* const glyphInfoBuffer = mVisualModel->mGlyphs.Begin();
+
   // If the vector is void, there is no right to left characters.
   const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
 
   // If the vector is void, there is no right to left characters.
   const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
 
@@ -759,36 +1939,68 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
 
   // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
   CharacterIndex visualIndex = startCharacter;
 
   // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
   CharacterIndex visualIndex = startCharacter;
+  Length numberOfCharacters = 0u;
   for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
   {
     // The character in logical order.
     const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
 
   for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
   {
     // 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 );
+    // Get the script of the character.
+    const Script script = mLogicalModel->GetScript( characterLogicalOrderIndex );
 
     // The number of glyphs for that character
     const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
 
     // The number of glyphs for that character
     const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
+    ++numberOfCharacters;
 
 
-    // Get the metrics for the group of glyphs.
-    GlyphMetrics glyphMetrics;
-    GetGlyphsMetrics( glyphLogicalOrderIndex,
-                      numberOfGlyphs,
-                      glyphMetrics,
-                      mVisualModel,
-                      mFontClient );
 
 
-    const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
+    if( 0u != numberOfGlyphs )
+    {
+      // Get the first character/glyph of the group of glyphs.
+      const CharacterIndex firstVisualCharacterIndex = 1u + visualIndex - numberOfCharacters;
+      const CharacterIndex firstLogicalCharacterIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + firstVisualCharacterIndex ) : firstVisualCharacterIndex;
+      const GlyphIndex firstLogicalGlyphIndex = *( charactersToGlyphBuffer + firstLogicalCharacterIndex );
 
 
-    const float glyphX = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
+      // Get the metrics for the group of glyphs.
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( firstLogicalGlyphIndex,
+                        numberOfGlyphs,
+                        glyphMetrics,
+                        glyphInfoBuffer,
+                        mMetrics );
 
 
-    if( visualX < glyphX )
-    {
-      matched = true;
-      break;
+      // Get the position of the first glyph.
+      const Vector2& position = *( positionsBuffer + firstLogicalGlyphIndex );
+
+      // Whether the glyph can be split, like Latin ligatures fi, ff or Arabic ﻻ.
+      const bool isInterglyphIndex = ( numberOfCharacters > numberOfGlyphs ) && HasLigatureMustBreak( script );
+      const Length numberOfBlocks = isInterglyphIndex ? numberOfCharacters : 1u;
+      const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfBlocks );
+
+      GlyphIndex index = 0u;
+      for( ; !matched && ( index < numberOfBlocks ); ++index )
+      {
+        // Find the mid-point of the area containing the glyph
+        const float glyphCenter = -glyphMetrics.xBearing + position.x + ( static_cast<float>( index ) + 0.5f ) * glyphAdvance;
+
+        if( visualX < glyphCenter )
+        {
+          matched = true;
+          break;
+        }
+      }
+
+      if( matched )
+      {
+        visualIndex = firstVisualCharacterIndex + index;
+        break;
+      }
+
+      numberOfCharacters = 0u;
     }
     }
+
   }
 
   }
 
+
   // Return the logical position of the cursor in characters.
 
   if( !matched )
   // Return the logical position of the cursor in characters.
 
   if( !matched )
@@ -796,7 +2008,12 @@ CharacterIndex Controller::Impl::GetClosestCursorIndex( float visualX,
     visualIndex = endCharacter;
   }
 
     visualIndex = endCharacter;
   }
 
-  return hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
+  logicalIndex = hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p closest visualIndex %d logicalIndex %d\n", this, visualIndex, logicalIndex );
+
+  DALI_ASSERT_DEBUG( ( logicalIndex <= mLogicalModel->mText.Count() && logicalIndex >= 0 ) && "GetClosestCursorIndex - Out of bounds index" );
+
+  return logicalIndex;
 }
 
 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 }
 
 void Controller::Impl::GetCursorPosition( CharacterIndex logical,
@@ -804,62 +2021,85 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 {
   // TODO: Check for multiline with \n, etc...
 
 {
   // 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 )
+  const Length numberOfCharacters = mLogicalModel->mText.Count();
+  if( !IsShowingRealText() )
   {
   {
-    // There is zero characters. Get the default font.
+    // 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.
+
+    cursorInfo.lineOffset = 0.f;
+    cursorInfo.lineHeight = GetDefaultFontLineHeight();
+    cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
 
 
-    FontId defaultFontId = 0u;
-    if( NULL == mFontDefaults )
+    switch( mLayoutEngine.GetHorizontalAlignment() )
     {
     {
-      defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
-                                             EMPTY_STRING );
+      case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
+      {
+        cursorInfo.primaryPosition.x = 0.f;
+        break;
+      }
+      case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
+      {
+        cursorInfo.primaryPosition.x = floorf( 0.5f * mVisualModel->mControlSize.width );
+        break;
+      }
+      case LayoutEngine::HORIZONTAL_ALIGN_END:
+      {
+        cursorInfo.primaryPosition.x = mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
+        break;
+      }
     }
     }
-    else
+
+    switch( mLayoutEngine.GetVerticalAlignment() )
     {
     {
-      defaultFontId = mFontDefaults->GetFontId( mFontClient );
+      case LayoutEngine::VERTICAL_ALIGN_TOP:
+      {
+        cursorInfo.primaryPosition.y = 0.f;
+        break;
+      }
+      case LayoutEngine::VERTICAL_ALIGN_CENTER:
+      {
+        cursorInfo.primaryPosition.y = floorf( 0.5f * ( mVisualModel->mControlSize.height - cursorInfo.lineHeight ) );
+        break;
+      }
+      case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
+      {
+        cursorInfo.primaryPosition.y = mVisualModel->mControlSize.height - cursorInfo.lineHeight;
+        break;
+      }
     }
 
     }
 
-    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;
   }
 
     // Nothing else to do.
     return;
   }
 
-  // Get the previous logical index.
-  const CharacterIndex previousLogical = isFirstPosition ? 0u : logical - 1u;
+  // Check if the logical position is the first or the last one of the text.
+  const bool isFirstPosition = 0u == logical;
+  const bool isLastPosition = numberOfCharacters == logical;
 
 
-  // Decrease the logical index if it's the last one.
-  if( isLastPosition )
-  {
-    --logical;
-  }
+  // 'logical' is the logical 'cursor' index.
+  // Get the next and current logical 'character' index.
+  const CharacterIndex nextCharacterIndex = logical;
+  const CharacterIndex characterIndex = isFirstPosition ? logical : logical - 1u;
 
 
-  // Get the direction of the character and the previous one.
+  // Get the direction of the character and the next one.
   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
 
   CharacterDirection isCurrentRightToLeft = false;
   const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
 
   CharacterDirection isCurrentRightToLeft = false;
-  CharacterDirection isPreviousRightToLeft = false;
+  CharacterDirection isNextRightToLeft = false;
   if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
   {
   if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
   {
-    isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + logical );
-    isPreviousRightToLeft = *( modelCharacterDirectionsBuffer + previousLogical );
+    isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + characterIndex );
+    isNextRightToLeft = *( modelCharacterDirectionsBuffer + nextCharacterIndex );
   }
 
   // Get the line where the character is laid-out.
   }
 
   // Get the line where the character is laid-out.
-  const LineRun* modelLines = mVisualModel->mLines.Begin();
+  const LineRun* const modelLines = mVisualModel->mLines.Begin();
 
 
-  const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( logical );
+  const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( characterIndex );
   const LineRun& line = *( modelLines + lineIndex );
 
   // Get the paragraph's direction.
   const LineRun& line = *( modelLines + lineIndex );
 
   // Get the paragraph's direction.
@@ -867,123 +2107,170 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
 
   // Check whether there is an alternative position:
 
 
   // Check whether there is an alternative position:
 
-  cursorInfo.isSecondaryCursor = ( isCurrentRightToLeft != isPreviousRightToLeft ) ||
-    ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
+  cursorInfo.isSecondaryCursor = ( !isLastPosition && ( isCurrentRightToLeft != isNextRightToLeft ) ) ||
+                                 ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
 
 
-  // Set the line height.
+  // Set the line offset and height.
+  cursorInfo.lineOffset = 0.f;
   cursorInfo.lineHeight = line.ascender + -line.descender;
 
   cursorInfo.lineHeight = line.ascender + -line.descender;
 
-  // Convert the cursor position into the glyph position.
-  CharacterIndex characterIndex = logical;
-  if( cursorInfo.isSecondaryCursor &&
-      ( isRightToLeftParagraph != isCurrentRightToLeft ) )
+  // Calculate the primary cursor.
+
+  CharacterIndex index = characterIndex;
+  if( cursorInfo.isSecondaryCursor )
   {
   {
-    characterIndex = previousLogical;
+    // If there is a secondary position, the primary cursor may be in a different place than the logical index.
+
+    if( isLastPosition )
+    {
+      // The position of the cursor after the last character needs special
+      // care depending on its direction and the direction of the paragraph.
+
+      // Need to find the first character after the last character with the paragraph's direction.
+      // i.e l0 l1 l2 r0 r1 should find r0.
+
+      // TODO: check for more than one line!
+      index = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
+      index = mLogicalModel->GetLogicalCharacterIndex( index );
+    }
+    else
+    {
+      index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? characterIndex : nextCharacterIndex;
+    }
   }
 
   }
 
-  const GlyphIndex currentGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
-  const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
-  const Length numberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() +currentGlyphIndex );
+  const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+  const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+  const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+  const CharacterIndex* const glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
+  const Vector2* const glyphPositionsBuffer = mVisualModel->mGlyphPositions.Begin();
+  const GlyphInfo* const glyphInfoBuffer = mVisualModel->mGlyphs.Begin();
+
+  // Convert the cursor position into the glyph position.
+  const GlyphIndex primaryGlyphIndex = *( charactersToGlyphBuffer + index );
+  const Length primaryNumberOfGlyphs = *( glyphsPerCharacterBuffer + index );
+  const Length primaryNumberOfCharacters = *( charactersPerGlyphBuffer + primaryGlyphIndex );
 
   // Get the metrics for the group of glyphs.
   GlyphMetrics glyphMetrics;
 
   // Get the metrics for the group of glyphs.
   GlyphMetrics glyphMetrics;
-  GetGlyphsMetrics( currentGlyphIndex,
-                    numberOfGlyphs,
+  GetGlyphsMetrics( primaryGlyphIndex,
+                    primaryNumberOfGlyphs,
                     glyphMetrics,
                     glyphMetrics,
-                    mVisualModel,
-                    mFontClient );
+                    glyphInfoBuffer,
+                    mMetrics );
+
+  // Whether to add the glyph's advance to the cursor position.
+  // i.e if the paragraph is left to right and the logical cursor is zero, the position is the position of the first glyph and the advance is not added,
+  //     if the logical cursor is one, the position is the position of the first glyph and the advance is added.
+  // A 'truth table' was build and an online Karnaugh map tool was used to simplify the logic.
+  //
+  // FLCP A
+  // ------
+  // 0000 1
+  // 0001 1
+  // 0010 0
+  // 0011 0
+  // 0100 1
+  // 0101 0
+  // 0110 1
+  // 0111 0
+  // 1000 0
+  // 1001 x
+  // 1010 x
+  // 1011 1
+  // 1100 x
+  // 1101 x
+  // 1110 x
+  // 1111 x
+  //
+  // Where F -> isFirstPosition
+  //       L -> isLastPosition
+  //       C -> isCurrentRightToLeft
+  //       P -> isRightToLeftParagraph
+  //       A -> Whether to add the glyph's advance.
+
+  const bool addGlyphAdvance = ( ( isLastPosition && !isRightToLeftParagraph ) ||
+                                 ( isFirstPosition && isRightToLeftParagraph ) ||
+                                 ( !isFirstPosition && !isLastPosition && !isCurrentRightToLeft ) );
+
+  float glyphAdvance = addGlyphAdvance ? glyphMetrics.advance : 0.f;
 
 
-  float interGlyphAdvance = 0.f;
   if( !isLastPosition &&
   if( !isLastPosition &&
-      ( numberOfCharacters > 1u ) )
+      ( primaryNumberOfCharacters > 1u ) )
   {
   {
-    const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + currentGlyphIndex );
-    interGlyphAdvance = static_cast<float>( characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( numberOfCharacters );
+    const CharacterIndex firstIndex = *( glyphsToCharactersBuffer + primaryGlyphIndex );
+
+    bool isCurrentRightToLeft = false;
+    if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+    {
+      isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + index );
+    }
+
+    Length numberOfGlyphAdvance = ( isFirstPosition ? 0u : 1u ) + characterIndex - firstIndex;
+    if( isCurrentRightToLeft )
+    {
+      numberOfGlyphAdvance = primaryNumberOfCharacters - numberOfGlyphAdvance;
+    }
+
+    glyphAdvance = static_cast<float>( numberOfGlyphAdvance ) * glyphMetrics.advance / static_cast<float>( primaryNumberOfCharacters );
   }
 
   // Get the glyph position and x bearing.
   }
 
   // Get the glyph position and x bearing.
-  const Vector2& currentPosition = *( mVisualModel->mGlyphPositions.Begin() + currentGlyphIndex );
+  const Vector2& primaryPosition = *( glyphPositionsBuffer + primaryGlyphIndex );
 
 
-  // Set the cursor's height.
-  cursorInfo.primaryCursorHeight = glyphMetrics.fontHeight;
+  // Set the primary cursor's height.
+  cursorInfo.primaryCursorHeight = cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight;
 
 
-  // Set the position.
-  cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + currentPosition.x + ( isCurrentRightToLeft ? glyphMetrics.advance : interGlyphAdvance );
+  // Set the primary cursor's position.
+  cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + primaryPosition.x + glyphAdvance;
   cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
 
   cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
 
-  if( isLastPosition )
+  // Calculate the secondary cursor.
+
+  if( cursorInfo.isSecondaryCursor )
   {
   {
-    // The position of the cursor after the last character needs special
-    // care depending on its direction and the direction of the paragraph.
+    // Set the secondary cursor's height.
+    cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
 
 
-    if( cursorInfo.isSecondaryCursor )
+    CharacterIndex index = characterIndex;
+    if( !isLastPosition )
     {
     {
-      // 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 );
+      index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? nextCharacterIndex : characterIndex;
+    }
 
 
-      const Vector2& position = *( mVisualModel->mGlyphPositions.Begin() + glyphIndex );
+    const GlyphIndex secondaryGlyphIndex = *( charactersToGlyphBuffer + index );
+    const Length secondaryNumberOfGlyphs = *( glyphsPerCharacterBuffer + index );
 
 
-      // Get the metrics for the group of glyphs.
-      GlyphMetrics glyphMetrics;
-      GetGlyphsMetrics( glyphIndex,
-                        numberOfGlyphs,
-                        glyphMetrics,
-                        mVisualModel,
-                        mFontClient );
+    const Vector2& secondaryPosition = *( glyphPositionsBuffer + secondaryGlyphIndex );
 
 
-      cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + position.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
+    GetGlyphsMetrics( secondaryGlyphIndex,
+                      secondaryNumberOfGlyphs,
+                      glyphMetrics,
+                      glyphInfoBuffer,
+                      mMetrics );
 
 
-      cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
-    }
-    else
-    {
-      if( !isCurrentRightToLeft )
-      {
-        cursorInfo.primaryPosition.x += glyphMetrics.advance;
-      }
-      else
-      {
-        cursorInfo.primaryPosition.x -= glyphMetrics.advance;
-      }
-    }
+    // Set the secondary cursor's position.
+    cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + secondaryPosition.x + ( isCurrentRightToLeft ? 0.f : glyphMetrics.advance );
+    cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
   }
 
   }
 
-  // Set the alternative cursor position.
-  if( cursorInfo.isSecondaryCursor )
+  if( LayoutEngine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
   {
   {
-    // 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 );
+    // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
 
 
-    // Get the metrics for the group of glyphs.
-    GlyphMetrics glyphMetrics;
-    GetGlyphsMetrics( previousGlyphIndex,
-                      numberOfGlyphs,
-                      glyphMetrics,
-                      mVisualModel,
-                      mFontClient );
-
-    // Set the cursor position and height.
-    cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + previousPosition.x + ( ( ( isLastPosition && !isCurrentRightToLeft ) ||
-                                                                                       ( !isLastPosition && isCurrentRightToLeft )    ) ? glyphMetrics.advance : 0.f );
-
-    cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
+    // 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;
+    }
   }
 }
 
   }
 }
 
@@ -997,25 +2284,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 );
     }
   }
 
     }
   }
 
@@ -1031,7 +2320,7 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex( CharacterIndex index )
   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 )
@@ -1041,121 +2330,55 @@ 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;
+  const Vector2 offset = mEventData->mScrollPosition + ( IsShowingRealText() ? mAlignmentOffset : Vector2::ZERO );
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
 
 
-    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;
-      }
-    }
+  // 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 );
 
 
-    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 grab handle position.
+  mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+                                       cursorPosition.x,
+                                       cursorInfo.lineOffset + offset.y,
+                                       cursorInfo.lineHeight );
 
 
-    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
-                                         lineHeight,
-                                         lineHeight );
-  }
-  else
+  if( cursorInfo.isSecondaryCursor )
   {
   {
-    CursorInfo cursorInfo;
-    GetCursorPosition( mEventData->mPrimaryCursorPosition,
-                       cursorInfo );
-
-    const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
-    const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
-
-    // Sets the cursor position.
-    mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
-                                         cursorInfo.primaryCursorHeight,
-                                         cursorInfo.lineHeight );
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Primary cursor position: %f,%f\n", cursorPosition.x, cursorPosition.y );
-
-    // Sets the grab handle position.
-    mEventData->mDecorator->SetPosition( GRAB_HANDLE,
-                                         cursorPosition.x,
-                                         cursorPosition.y,
+    mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+                                         cursorInfo.secondaryPosition.x + offset.x,
+                                         cursorInfo.secondaryPosition.y + offset.y,
+                                         cursorInfo.secondaryCursorHeight,
                                          cursorInfo.lineHeight );
                                          cursorInfo.lineHeight );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
+  }
 
 
+  // Set which cursors are active according the state.
+  if( EventData::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 ) )
@@ -1163,29 +2386,28 @@ void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
     return;
   }
 
     return;
   }
 
-  const bool leftSelectionHandle = LEFT_SELECTION_HANDLE == handleType;
-  const CharacterIndex index = leftSelectionHandle ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
-
-  CursorInfo cursorInfo;
-  GetCursorPosition( index,
-                     cursorInfo );
-
   const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
   const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
 
   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 + offset.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 )
 {
   // Clamp between -space & 0 (and the text alignment).
 }
 
 void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
-  if( actualSize.width > mControlSize.width )
+
+  if( actualSize.width > mVisualModel->mControlSize.width )
   {
   {
-    const float space = ( actualSize.width - mControlSize.width ) + mAlignmentOffset.x;
+    const float space = ( actualSize.width - mVisualModel->mControlSize.width ) + mAlignmentOffset.x;
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
 
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
     mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
 
@@ -1200,9 +2422,9 @@ void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
 void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
 void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
 {
   // Clamp between -space & 0 (and the text alignment).
-  if( actualSize.height > mControlSize.height )
+  if( actualSize.height > mVisualModel->mControlSize.height )
   {
   {
-    const float space = ( actualSize.height - mControlSize.height ) + mAlignmentOffset.y;
+    const float space = ( actualSize.height - mVisualModel->mControlSize.height ) + mAlignmentOffset.y;
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
 
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
     mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
 
@@ -1214,37 +2436,36 @@ void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
   }
 }
 
   }
 }
 
-void Controller::Impl::ScrollToMakeCursorVisible()
+void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position )
 {
 {
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
+  // position is in actor's coords.
+  const float positionEnd = position.x + ( mEventData->mDecorator ? mEventData->mDecorator->GetCursorWidth() : 0.f );
 
 
-  const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+  // Transform the position to decorator coords.
+  const float alignment = IsShowingRealText() ? mAlignmentOffset.x : 0.f;
+  const float offset = mEventData->mScrollPosition.x + alignment;
+  const float decoratorPositionBegin = position.x + offset;
+  const float decoratorPositionEnd = positionEnd + offset;
 
 
-  Vector2 offset;
-  bool updateDecorator = false;
-  if( primaryCursorPosition.x < 0.f )
+  if( decoratorPositionBegin < 0.f )
   {
   {
-    offset.x = -primaryCursorPosition.x;
-    mEventData->mScrollPosition.x += offset.x;
-    updateDecorator = true;
+    mEventData->mScrollPosition.x = -position.x - alignment;
   }
   }
-  else if( primaryCursorPosition.x > mControlSize.width )
+  else if( decoratorPositionEnd > mVisualModel->mControlSize.width )
   {
   {
-    offset.x = mControlSize.width - primaryCursorPosition.x;
-    mEventData->mScrollPosition.x += offset.x;
-    updateDecorator = true;
+    mEventData->mScrollPosition.x = mVisualModel->mControlSize.width - positionEnd - alignment;
   }
   }
+}
 
 
-  if( updateDecorator && mEventData->mDecorator )
-  {
-    mEventData->mDecorator->UpdatePositions( offset );
-  }
+void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
+{
+  // Get the current cursor position in decorator coords.
+  const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+  // Calculate the offset to match the cursor position before the character was deleted.
+  mEventData->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x - mAlignmentOffset.x;
 
 
-  // TODO : calculate the vertical scroll.
+  ClampHorizontalScroll( mVisualModel->GetLayoutSize() );
 }
 
 void Controller::Impl::RequestRelayout()
 }
 
 void Controller::Impl::RequestRelayout()