Fixed for single line text updates
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
index c54ca22..532afed 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -55,7 +55,6 @@ struct SelectionBoxInfo
 const float MAX_FLOAT = std::numeric_limits<float>::max();
 const float MIN_FLOAT = std::numeric_limits<float>::min();
 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
 const float MAX_FLOAT = std::numeric_limits<float>::max();
 const float MIN_FLOAT = std::numeric_limits<float>::min();
 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
-const uint32_t STAR = 0x2A;
 
 } // namespace
 
 
 } // namespace
 
@@ -71,6 +70,8 @@ namespace Text
 EventData::EventData( DecoratorPtr decorator )
 : mDecorator( decorator ),
   mImfManager(),
 EventData::EventData( DecoratorPtr decorator )
 : mDecorator( decorator ),
   mImfManager(),
+  mPlaceholderFont( NULL ),
+  mPlaceholderText(),
   mPlaceholderTextActive(),
   mPlaceholderTextInactive(),
   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
   mPlaceholderTextActive(),
   mPlaceholderTextInactive(),
   mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
@@ -84,6 +85,8 @@ EventData::EventData( DecoratorPtr decorator )
   mPreEditStartPosition( 0u ),
   mPreEditLength( 0u ),
   mCursorHookPositionX( 0.f ),
   mPreEditStartPosition( 0u ),
   mPreEditLength( 0u ),
   mCursorHookPositionX( 0.f ),
+  mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
+  mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
   mIsShowingPlaceholderText( false ),
   mPreEditFlag( false ),
   mDecoratorUpdated( false ),
   mIsShowingPlaceholderText( false ),
   mPreEditFlag( false ),
   mDecoratorUpdated( false ),
@@ -97,12 +100,14 @@ EventData::EventData( DecoratorPtr decorator )
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
   mIsLeftHandleSelected( false ),
   mUpdateLeftSelectionPosition( false ),
   mUpdateRightSelectionPosition( false ),
   mIsLeftHandleSelected( false ),
+  mIsRightHandleSelected( false ),
   mUpdateHighlightBox( false ),
   mScrollAfterUpdatePosition( false ),
   mScrollAfterDelete( false ),
   mAllTextSelected( false ),
   mUpdateInputStyle( false ),
   mUpdateHighlightBox( false ),
   mScrollAfterUpdatePosition( false ),
   mScrollAfterDelete( false ),
   mAllTextSelected( false ),
   mUpdateInputStyle( false ),
-  mPasswordInput( false )
+  mPasswordInput( false ),
+  mIsPlaceholderPixelSize( false )
 {
   mImfManager = ImfManager::Get();
 }
 {
   mImfManager = ImfManager::Get();
 }
@@ -227,10 +232,25 @@ bool Controller::Impl::ProcessInputEvents()
 
       if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
       {
 
       if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
       {
-        CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
+        if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
+        {
+          CursorInfo& infoLeft = leftHandleInfo;
+
+          const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
+          ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
+
+          CursorInfo& infoRight = rightHandleInfo;
+
+          const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
+          ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
+        }
+        else
+        {
+          CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
 
 
-        const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
-        ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
+          const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
+          ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
+        }
       }
     }
 
       }
     }
 
@@ -261,6 +281,8 @@ bool Controller::Impl::ProcessInputEvents()
       mEventData->mUpdateLeftSelectionPosition = false;
       mEventData->mUpdateRightSelectionPosition = false;
       mEventData->mUpdateHighlightBox = false;
       mEventData->mUpdateLeftSelectionPosition = false;
       mEventData->mUpdateRightSelectionPosition = false;
       mEventData->mUpdateHighlightBox = false;
+      mEventData->mIsLeftHandleSelected = false;
+      mEventData->mIsRightHandleSelected = false;
     }
 
     mEventData->mScrollAfterUpdatePosition = false;
     }
 
     mEventData->mScrollAfterUpdatePosition = false;
@@ -769,24 +791,16 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     return false;
   }
 
     return false;
   }
 
-  Vector<Character> utf32CharactersStar;
-  const Length characterCount = mModel->mLogicalModel->mText.Count();
-  const bool isPasswordInput = ( mEventData != NULL && mEventData->mPasswordInput &&
-        !mEventData->mIsShowingPlaceholderText && characterCount > 0 );
-
-  if (isPasswordInput)
+  Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
+  Vector<Character> displayCharacters;
+  bool useHiddenText = false;
+  if ( mHiddenInput && mEventData != NULL && !mEventData->mIsShowingPlaceholderText)
   {
   {
-    utf32CharactersStar.Resize( characterCount );
-
-    uint32_t* begin = utf32CharactersStar.Begin();
-    uint32_t* end = begin + characterCount;
-    while ( begin < end )
-    {
-      *begin++ = STAR;
-    }
+    mHiddenInput->Substitute( srcCharacters,displayCharacters );
+    useHiddenText = true;
   }
 
   }
 
-  Vector<Character>& utf32Characters = isPasswordInput ? utf32CharactersStar : mModel->mLogicalModel->mText;
+  Vector<Character>& utf32Characters = useHiddenText ? displayCharacters : srcCharacters;
   const Length numberOfCharacters = utf32Characters.Count();
 
   // Index to the first character of the first paragraph to be updated.
   const Length numberOfCharacters = utf32Characters.Count();
 
   // Index to the first character of the first paragraph to be updated.
@@ -872,8 +886,19 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
       // Get the default font's description.
       TextAbstraction::FontDescription defaultFontDescription;
       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
       // Get the default font's description.
       TextAbstraction::FontDescription defaultFontDescription;
       TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
-      if( NULL != mFontDefaults )
+
+      if( IsShowingPlaceholderText() && ( NULL != mEventData->mPlaceholderFont ) )
+      {
+        // If the placeholder font is set specifically, only placeholder font is changed.
+        defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
+        if( mEventData->mPlaceholderFont->sizeDefined )
+        {
+          defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
+        }
+      }
+      else if( NULL != mFontDefaults )
       {
       {
+        // Set the normal font and the placeholder font.
         defaultFontDescription = mFontDefaults->mFontDescription;
         defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
       }
         defaultFontDescription = mFontDefaults->mFontDescription;
         defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
       }
@@ -1151,29 +1176,30 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
     }
 
     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
     }
 
     const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
+    const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex );
 
 
-    if( lineIndex > 0u )
-    {
-      // Retrieve the cursor position info.
-      CursorInfo cursorInfo;
-      GetCursorPosition( mEventData->mPrimaryCursorPosition,
-                         cursorInfo );
+    // Retrieve the cursor position info.
+    CursorInfo cursorInfo;
+    GetCursorPosition( mEventData->mPrimaryCursorPosition,
+                       cursorInfo );
 
 
-      // Get the line above.
-      const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + ( lineIndex - 1u ) );
+    // Get the line above.
+    const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + previousLineIndex );
 
 
-      // Get the next hit 'y' point.
-      const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
+    // Get the next hit 'y' point.
+    const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
 
 
-      // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
-      mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                                        mModel->mLogicalModel,
-                                                                        mMetrics,
-                                                                        mEventData->mCursorHookPositionX,
-                                                                        hitPointY );
-    }
+    // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+    bool matchedCharacter = false;
+    mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
+                                                                      mModel->mLogicalModel,
+                                                                      mMetrics,
+                                                                      mEventData->mCursorHookPositionX,
+                                                                      hitPointY,
+                                                                      CharacterHitTest::TAP,
+                                                                      matchedCharacter );
   }
   }
-  else if(   Dali::DALI_KEY_CURSOR_DOWN == keyCode )
+  else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode )
   {
     // Get first the line index of the current cursor position index.
     CharacterIndex characterIndex = 0u;
   {
     // Get first the line index of the current cursor position index.
     CharacterIndex characterIndex = 0u;
@@ -1199,11 +1225,14 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
       const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
 
       // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
       const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
 
       // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+      bool matchedCharacter = false;
       mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                         mModel->mLogicalModel,
                                                                         mMetrics,
                                                                         mEventData->mCursorHookPositionX,
       mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                         mModel->mLogicalModel,
                                                                         mMetrics,
                                                                         mEventData->mCursorHookPositionX,
-                                                                        hitPointY );
+                                                                        hitPointY,
+                                                                        CharacterHitTest::TAP,
+                                                                        matchedCharacter );
     }
   }
 
     }
   }
 
@@ -1229,11 +1258,15 @@ void Controller::Impl::OnTapEvent( const Event& event )
         // Keep the tap 'x' position. Used to move the cursor.
         mEventData->mCursorHookPositionX = xPosition;
 
         // Keep the tap 'x' position. Used to move the cursor.
         mEventData->mCursorHookPositionX = xPosition;
 
+        // Whether to touch point hits on a glyph.
+        bool matchedCharacter = false;
         mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                           mModel->mLogicalModel,
                                                                           mMetrics,
                                                                           xPosition,
         mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                           mModel->mLogicalModel,
                                                                           mMetrics,
                                                                           xPosition,
-                                                                          yPosition );
+                                                                          yPosition,
+                                                                          CharacterHitTest::TAP,
+                                                                          matchedCharacter );
 
         // When the cursor position is changing, delay cursor blinking
         mEventData->mDecorator->DelayCursorBlink();
 
         // When the cursor position is changing, delay cursor blinking
         mEventData->mDecorator->DelayCursorBlink();
@@ -1255,6 +1288,20 @@ void Controller::Impl::OnTapEvent( const Event& event )
         mEventData->mImfManager.NotifyCursorPosition();
       }
     }
         mEventData->mImfManager.NotifyCursorPosition();
       }
     }
+    else if( 2u == tapCount )
+    {
+      if( mEventData->mSelectionEnabled )
+      {
+        // Convert from control's coords to text's coords.
+        const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+        const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+        // Calculates the logical position from the x,y coords.
+        RepositionSelectionHandles( xPosition,
+                                    yPosition,
+                                    mEventData->mDoubleTapAction );
+      }
+    }
   }
 }
 
   }
 }
 
@@ -1325,12 +1372,26 @@ void Controller::Impl::OnLongPressEvent( const Event& event )
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
 
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
 
-  if( EventData::EDITING == mEventData->mState )
+  if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
   {
   {
-    ChangeState ( EventData::EDITING_WITH_POPUP );
+    ChangeState( EventData::EDITING_WITH_POPUP );
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateInputStyle = true;
   }
     mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateInputStyle = true;
   }
+  else
+  {
+    if( mEventData->mSelectionEnabled )
+    {
+      // Convert from control's coords to text's coords.
+      const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
+      const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+
+      // Calculates the logical position from the x,y coords.
+      RepositionSelectionHandles( xPosition,
+                                  yPosition,
+                                  mEventData->mLongPressAction );
+    }
+  }
 }
 
 void Controller::Impl::OnHandleEvent( const Event& event )
 }
 
 void Controller::Impl::OnHandleEvent( const Event& event )
@@ -1352,11 +1413,14 @@ void Controller::Impl::OnHandleEvent( const Event& event )
     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
 
     // Need to calculate the handle's new position.
     const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
 
     // Need to calculate the handle's new position.
+    bool matchedCharacter = false;
     const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                           mModel->mLogicalModel,
                                                                           mMetrics,
                                                                           xPosition,
     const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                           mModel->mLogicalModel,
                                                                           mMetrics,
                                                                           xPosition,
-                                                                          yPosition );
+                                                                          yPosition,
+                                                                          CharacterHitTest::SCROLL,
+                                                                          matchedCharacter );
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
@@ -1393,6 +1457,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
       // Will define the order to scroll the text to match the handle position.
       mEventData->mIsLeftHandleSelected = true;
 
       // Will define the order to scroll the text to match the handle position.
       mEventData->mIsLeftHandleSelected = true;
+      mEventData->mIsRightHandleSelected = false;
     }
     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
     }
     else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
     {
@@ -1413,6 +1478,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
       // Will define the order to scroll the text to match the handle position.
       mEventData->mIsLeftHandleSelected = false;
 
       // Will define the order to scroll the text to match the handle position.
       mEventData->mIsLeftHandleSelected = false;
+      mEventData->mIsRightHandleSelected = true;
     }
   } // end ( HANDLE_PRESSED == state )
   else if( ( HANDLE_RELEASED == state ) ||
     }
   } // end ( HANDLE_PRESSED == state )
   else if( ( HANDLE_RELEASED == state ) ||
@@ -1425,11 +1491,14 @@ void Controller::Impl::OnHandleEvent( const Event& event )
       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
 
       const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
       const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
 
+      bool matchedCharacter = false;
       handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                     mModel->mLogicalModel,
                                                     mMetrics,
                                                     xPosition,
       handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                     mModel->mLogicalModel,
                                                     mMetrics,
                                                     xPosition,
-                                                    yPosition );
+                                                    yPosition,
+                                                    CharacterHitTest::SCROLL,
+                                                    matchedCharacter );
     }
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
     }
 
     if( Event::GRAB_HANDLE_EVENT == event.type )
@@ -1541,11 +1610,14 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
       // Get the new handle position.
       // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
 
       // Get the new handle position.
       // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
+      bool matchedCharacter = false;
       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                          mModel->mLogicalModel,
                                                                          mMetrics,
                                                                          position.x - mModel->mScrollPosition.x,
       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                          mModel->mLogicalModel,
                                                                          mMetrics,
                                                                          position.x - mModel->mScrollPosition.x,
-                                                                         position.y - mModel->mScrollPosition.y );
+                                                                         position.y - mModel->mScrollPosition.y,
+                                                                         CharacterHitTest::SCROLL,
+                                                                         matchedCharacter );
 
       if( mEventData->mPrimaryCursorPosition != handlePosition )
       {
 
       if( mEventData->mPrimaryCursorPosition != handlePosition )
       {
@@ -1582,11 +1654,14 @@ void Controller::Impl::OnHandleEvent( const Event& event )
 
       // Get the new handle position.
       // The selection handle's position is in decorator's coords. Need to transform to text's coords.
 
       // Get the new handle position.
       // The selection handle's position is in decorator's coords. Need to transform to text's coords.
+      bool matchedCharacter = false;
       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                          mModel->mLogicalModel,
                                                                          mMetrics,
                                                                          position.x - mModel->mScrollPosition.x,
       const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
                                                                          mModel->mLogicalModel,
                                                                          mMetrics,
                                                                          position.x - mModel->mScrollPosition.x,
-                                                                         position.y - mModel->mScrollPosition.y );
+                                                                         position.y - mModel->mScrollPosition.y,
+                                                                         CharacterHitTest::SCROLL,
+                                                                         matchedCharacter );
 
       if( leftSelectionHandleEvent )
       {
 
       if( leftSelectionHandleEvent )
       {
@@ -1639,7 +1714,8 @@ void Controller::Impl::OnSelectEvent( const Event& event )
 
     // Calculates the logical position from the x,y coords.
     RepositionSelectionHandles( xPosition,
 
     // Calculates the logical position from the x,y coords.
     RepositionSelectionHandles( xPosition,
-                                yPosition );
+                                yPosition,
+                                Controller::NoTextTap::HIGHLIGHT );
   }
 }
 
   }
 }
 
@@ -1713,8 +1789,18 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete
       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
 
       // Mark the paragraphs to be updated.
       mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
 
       // Mark the paragraphs to be updated.
-      mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
-      mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
+      {
+        mTextUpdateInfo.mCharacterIndex = 0;
+        mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+        mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
+        mTextUpdateInfo.mClearAll = true;
+      }
+      else
+      {
+        mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+        mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      }
 
       // Delete text between handles
       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
 
       // Delete text between handles
       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
@@ -2170,7 +2256,7 @@ void Controller::Impl::RepositionSelectionHandles()
   mEventData->mDecoratorUpdated = true;
 }
 
   mEventData->mDecoratorUpdated = true;
 }
 
-void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
+void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
 {
   if( NULL == mEventData )
   {
 {
   if( NULL == mEventData )
   {
@@ -2196,16 +2282,18 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY
   // Find which word was selected
   CharacterIndex selectionStart( 0 );
   CharacterIndex selectionEnd( 0 );
   // Find which word was selected
   CharacterIndex selectionStart( 0 );
   CharacterIndex selectionEnd( 0 );
-  const bool indicesFound = FindSelectionIndices( mModel->mVisualModel,
+  CharacterIndex noTextHitIndex( 0 );
+  const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
                                                   mModel->mLogicalModel,
                                                   mMetrics,
                                                   visualX,
                                                   visualY,
                                                   selectionStart,
                                                   mModel->mLogicalModel,
                                                   mMetrics,
                                                   visualX,
                                                   visualY,
                                                   selectionStart,
-                                                  selectionEnd );
+                                                  selectionEnd,
+                                                  noTextHitIndex );
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
 
-  if( indicesFound )
+  if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
   {
     ChangeState( EventData::SELECTING );
 
   {
     ChangeState( EventData::SELECTING );
 
@@ -2224,12 +2312,22 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY
 
     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
   }
 
     mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
   }
-  else
+  else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
   {
     // Nothing to select. i.e. a white space, out of bounds
   {
     // Nothing to select. i.e. a white space, out of bounds
-    ChangeState( EventData::EDITING );
+    ChangeState( EventData::EDITING_WITH_POPUP );
 
 
-    mEventData->mPrimaryCursorPosition = selectionEnd;
+    mEventData->mPrimaryCursorPosition = noTextHitIndex;
+
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mUpdateGrabHandlePosition = true;
+    mEventData->mScrollAfterUpdatePosition = true;
+    mEventData->mUpdateInputStyle = true;
+  }
+  else if( Controller::NoTextTap::NO_ACTION == action )
+  {
+    // Nothing to select. i.e. a white space, out of bounds
+    mEventData->mPrimaryCursorPosition = noTextHitIndex;
 
     mEventData->mUpdateCursorPosition = true;
     mEventData->mUpdateGrabHandlePosition = true;
 
     mEventData->mUpdateCursorPosition = true;
     mEventData->mUpdateGrabHandlePosition = true;
@@ -2533,13 +2631,18 @@ void Controller::Impl::GetCursorPosition( CharacterIndex logical,
     return;
   }
 
     return;
   }
 
-  Text::GetCursorPosition( mModel->mVisualModel,
-                           mModel->mLogicalModel,
-                           mMetrics,
-                           logical,
+  const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
+  GetCursorPositionParameters parameters;
+  parameters.visualModel = mModel->mVisualModel;
+  parameters.logicalModel = mModel->mLogicalModel;
+  parameters.metrics = mMetrics;
+  parameters.logical = logical;
+  parameters.isMultiline = isMultiLine;
+
+  Text::GetCursorPosition( parameters,
                            cursorInfo );
 
                            cursorInfo );
 
-  if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
+  if( isMultiLine )
   {
     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
 
   {
     // If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
 
@@ -2620,6 +2723,8 @@ void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
 
   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
 
 
   const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
 
+  mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
+
   // Sets the cursor position.
   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
                                        cursorPosition.x,
   // Sets the cursor position.
   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
                                        cursorPosition.x,
@@ -2755,13 +2860,16 @@ void Controller::Impl::ScrollToMakePositionVisible( const Vector2& position, flo
     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
   }
 
     mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
   }
 
-  if( decoratorPositionBeginY < 0.f )
-  {
-    mModel->mScrollPosition.y = -position.y;
-  }
-  else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
+  if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
   {
   {
-    mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
+    if( decoratorPositionBeginY < 0.f )
+    {
+      mModel->mScrollPosition.y = -position.y;
+    }
+    else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
+    {
+      mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
+    }
   }
 }
 
   }
 }
 
@@ -2770,9 +2878,20 @@ void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
   // Get the current cursor position in decorator coords.
   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
 
   // Get the current cursor position in decorator coords.
   const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
 
+  const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition  );
+
+
+
   // Calculate the offset to match the cursor position before the character was deleted.
   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
   // Calculate the offset to match the cursor position before the character was deleted.
   mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
-  mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset;
+
+  //If text control has more than two lines and current line index is not last, calculate scrollpositionY
+  if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
+  {
+    const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
+    mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
+  }
+
 
   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );
 
   ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
   ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );