Merge "DALi Version 1.1.41" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
index 37110dc..8175be4 100644 (file)
@@ -40,7 +40,6 @@ namespace
 #endif
 
 const float MAX_FLOAT = std::numeric_limits<float>::max();
-const unsigned int POINTS_PER_INCH = 72;
 
 const std::string EMPTY_STRING("");
 
@@ -132,6 +131,68 @@ bool Controller::IsMarkupProcessorEnabled() const
   return mImpl->mMarkupProcessorEnabled;
 }
 
+void Controller::SetAutoScrollEnabled( bool enable )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable)?"true":"false", ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX)?"true":"false", this );
+
+  if ( mImpl->mLayoutEngine.GetLayout() == LayoutEngine::SINGLE_LINE_BOX )
+  {
+    if ( enable )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n" );
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               LAYOUT                    |
+                                                               ALIGN                     |
+                                                               UPDATE_ACTUAL_SIZE        |
+                                                               UPDATE_DIRECTION          |
+                                                               REORDER );
+
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               LAYOUT                    |
+                                                               ALIGN                     |
+                                                               UPDATE_ACTUAL_SIZE        |
+                                                               REORDER );
+    }
+
+    mImpl->mAutoScrollEnabled = enable;
+    mImpl->RequestRelayout();
+  }
+  else
+  {
+    DALI_LOG_WARNING( "Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored" );
+    mImpl->mAutoScrollEnabled = false;
+  }
+}
+
+bool Controller::IsAutoScrollEnabled() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", (mImpl->mAutoScrollEnabled)?"true":"false" );
+
+  return mImpl->mAutoScrollEnabled;
+}
+
+CharacterDirection Controller::GetAutoScrollDirection() const
+{
+  return mImpl->mAutoScrollDirectionRTL;
+}
+
+float Controller::GetAutoScrollLineAlignment() const
+{
+  float offset = 0.f;
+
+  if( mImpl->mVisualModel &&
+      ( 0u != mImpl->mVisualModel->mLines.Count() ) )
+  {
+    offset = ( *mImpl->mVisualModel->mLines.Begin() ).alignmentOffset;
+  }
+
+  return offset;
+}
+
 void Controller::SetText( const std::string& text )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
@@ -230,9 +291,6 @@ void Controller::SetText( const std::string& text )
     mImpl->mEventData->mEventQueue.clear();
   }
 
-  // Notify IMF as text changed
-  NotifyImfManager();
-
   // Do this last since it provides callbacks into application code
   mImpl->mControlInterface.TextChanged();
 }
@@ -241,12 +299,8 @@ void Controller::GetText( std::string& text ) const
 {
   if( !mImpl->IsShowingPlaceholderText() )
   {
-    Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
-
-    if( 0u != utf32Characters.Count() )
-    {
-      Utf32ToUtf8( &utf32Characters[0], utf32Characters.Count(), text );
-    }
+    // Retrieves the text string.
+    mImpl->GetText( 0u, text );
   }
   else
   {
@@ -254,16 +308,6 @@ void Controller::GetText( std::string& text ) const
   }
 }
 
-unsigned int Controller::GetLogicalCursorPosition() const
-{
-  if( NULL != mImpl->mEventData )
-  {
-    return mImpl->mEventData->mPrimaryCursorPosition;
-  }
-
-  return 0u;
-}
-
 void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text )
 {
   if( NULL != mImpl->mEventData )
@@ -446,15 +490,6 @@ void Controller::SetDefaultPointSize( float pointSize )
   mImpl->mFontDefaults->mDefaultPointSize = pointSize;
   mImpl->mFontDefaults->sizeDefined = true;
 
-  unsigned int horizontalDpi( 0u );
-  unsigned int verticalDpi( 0u );
-  mImpl->mFontClient.GetDpi( horizontalDpi, verticalDpi );
-
-  // Adjust the metrics if the fixed-size font should be down-scaled
-  int maxEmojiSize( pointSize/POINTS_PER_INCH * verticalDpi );
-  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetDefaultPointSize %p setting MaxEmojiSize %d\n", this, maxEmojiSize );
-  mImpl->mMetrics->SetMaxEmojiSize( maxEmojiSize );
-
   // Clear the font-specific data
   ClearFontData();
 
@@ -473,7 +508,7 @@ float Controller::GetDefaultPointSize() const
 
 void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange");
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange");
 
   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
   {
@@ -565,6 +600,8 @@ bool Controller::RemoveText( int cursorOffset,
       // Cursor position retreat
       oldCursorIndex = cursorIndex;
 
+      mImpl->mEventData->mScrollAfterDelete = true;
+
       DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters );
       removed = true;
     }
@@ -621,6 +658,26 @@ const Vector4& Controller::GetShadowColor() const
   return mImpl->mVisualModel->GetShadowColor();
 }
 
+void Controller::SetDefaultShadowProperties( const std::string& shadowProperties )
+{
+  if( NULL == mImpl->mShadowDefaults )
+  {
+    mImpl->mShadowDefaults = new ShadowDefaults();
+  }
+
+  mImpl->mShadowDefaults->properties = shadowProperties;
+}
+
+const std::string& Controller::GetDefaultShadowProperties() const
+{
+  if( NULL != mImpl->mShadowDefaults )
+  {
+    return mImpl->mShadowDefaults->properties;
+  }
+
+  return EMPTY_STRING;
+}
+
 void Controller::SetUnderlineColor( const Vector4& color )
 {
   mImpl->mVisualModel->SetUnderlineColor( color );
@@ -657,6 +714,77 @@ float Controller::GetUnderlineHeight() const
   return mImpl->mVisualModel->GetUnderlineHeight();
 }
 
+void Controller::SetDefaultUnderlineProperties( const std::string& underlineProperties )
+{
+  if( NULL == mImpl->mUnderlineDefaults )
+  {
+    mImpl->mUnderlineDefaults = new UnderlineDefaults();
+  }
+
+  mImpl->mUnderlineDefaults->properties = underlineProperties;
+}
+
+const std::string& Controller::GetDefaultUnderlineProperties() const
+{
+  if( NULL != mImpl->mUnderlineDefaults )
+  {
+    return mImpl->mUnderlineDefaults->properties;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
+{
+  if( NULL == mImpl->mEmbossDefaults )
+  {
+    mImpl->mEmbossDefaults = new EmbossDefaults();
+  }
+
+  mImpl->mEmbossDefaults->properties = embossProperties;
+}
+
+const std::string& Controller::GetDefaultEmbossProperties() const
+{
+  if( NULL != mImpl->mEmbossDefaults )
+  {
+    return mImpl->mEmbossDefaults->properties;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
+{
+  if( NULL == mImpl->mOutlineDefaults )
+  {
+    mImpl->mOutlineDefaults = new OutlineDefaults();
+  }
+
+  mImpl->mOutlineDefaults->properties = outlineProperties;
+}
+
+const std::string& Controller::GetDefaultOutlineProperties() const
+{
+  if( NULL != mImpl->mOutlineDefaults )
+  {
+    return mImpl->mOutlineDefaults->properties;
+  }
+
+  return EMPTY_STRING;
+}
+
+void Controller::SetDefaultLineSpacing( float lineSpacing )
+{
+  //TODO finish implementation
+  mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
+}
+
+float Controller::GetDefaultLineSpacing() const
+{
+  return mImpl->mLayoutEngine.GetDefaultLineSpacing();
+}
+
 void Controller::SetInputColor( const Vector4& color )
 {
   if( NULL != mImpl->mEventData )
@@ -993,6 +1121,96 @@ float Controller::GetInputFontPointSize() const
   return GetDefaultPointSize();
 }
 
+void Controller::SetInputLineSpacing( float lineSpacing )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
+  }
+}
+
+float Controller::GetInputLineSpacing() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.lineSpacing;
+  }
+
+  return 0.f;
+}
+
+void Controller::SetInputShadowProperties( const std::string& shadowProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
+  }
+}
+
+const std::string& Controller::GetInputShadowProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.shadowProperties;
+  }
+
+  return GetDefaultShadowProperties();
+}
+
+void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
+  }
+}
+
+const std::string& Controller::GetInputUnderlineProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.underlineProperties;
+  }
+
+  return GetDefaultUnderlineProperties();
+}
+
+void Controller::SetInputEmbossProperties( const std::string& embossProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
+  }
+}
+
+const std::string& Controller::GetInputEmbossProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.embossProperties;
+  }
+
+  return GetDefaultEmbossProperties();
+}
+
+void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
+{
+  if( NULL != mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
+  }
+}
+
+const std::string& Controller::GetInputOutlineProperties() const
+{
+  if( NULL != mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.outlineProperties;
+  }
+
+  return GetDefaultOutlineProperties();
+}
+
 void Controller::SetEnableCursorBlink( bool enable )
 {
   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
@@ -1021,17 +1239,7 @@ bool Controller::GetEnableCursorBlink() const
 
 const Vector2& Controller::GetScrollPosition() const
 {
-  if( NULL != mImpl->mEventData )
-  {
-    return mImpl->mEventData->mScrollPosition;
-  }
-
-  return Vector2::ZERO;
-}
-
-const Vector2& Controller::GetAlignmentOffset() const
-{
-  return mImpl->mAlignmentOffset;
+  return mImpl->mScrollPosition;
 }
 
 Vector3 Controller::GetNaturalSize()
@@ -1063,8 +1271,8 @@ Vector3 Controller::GetNaturalSize()
     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
     mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
 
-    // Store the actual control's width.
-    const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
+    // Store the actual control's size to restore later.
+    const Size actualControlSize = mImpl->mVisualModel->mControlSize;
 
     DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
                 static_cast<OperationsMask>( onlyOnceOperations |
@@ -1089,8 +1297,8 @@ Vector3 Controller::GetNaturalSize()
     // Clear the update info. This info will be set the next time the text is updated.
     mImpl->mTextUpdateInfo.Clear();
 
-    // Restore the actual control's width.
-    mImpl->mVisualModel->mControlSize.width = actualControlWidth;
+    // Restore the actual control's size.
+    mImpl->mVisualModel->mControlSize = actualControlSize;
 
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
   }
@@ -1173,7 +1381,7 @@ float Controller::GetHeightForWidth( float width )
 
 bool Controller::Relayout( const Size& size )
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f\n", this, size.width, size.height );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, (mImpl->mAutoScrollEnabled)?"true":"false"  );
 
   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
   {
@@ -1235,15 +1443,18 @@ bool Controller::Relayout( const Size& size )
   // Whether the text control is editable
   const bool isEditable = NULL != mImpl->mEventData;
 
-  // Keep the current offset and alignment as it will be used to update the decorator's positions (if the size changes).
+  // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
   Vector2 offset;
   if( newSize && isEditable )
   {
-    offset = mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition;
+    offset = mImpl->mScrollPosition;
   }
 
-  // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
-  CalculateTextAlignment( size );
+  if( !isEditable || !IsMultiLineEnabled() )
+  {
+    // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
+    CalculateVerticalOffset( size );
+  }
 
   if( isEditable )
   {
@@ -1253,7 +1464,7 @@ bool Controller::Relayout( const Size& size )
       mImpl->ClampHorizontalScroll( layoutSize );
 
       // Update the decorator's positions is needed if there is a new size.
-      mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mAlignmentOffset + mImpl->mEventData->mScrollPosition - offset );
+      mImpl->mEventData->mDecorator->UpdatePositions( mImpl->mScrollPosition - offset );
     }
 
     // Move the cursor, grab handle etc.
@@ -1357,7 +1568,7 @@ void Controller::ResetScrollPosition()
   if( NULL != mImpl->mEventData )
   {
     // Reset the scroll position.
-    mImpl->mEventData->mScrollPosition = Vector2::ZERO;
+    mImpl->mScrollPosition = Vector2::ZERO;
     mImpl->mEventData->mScrollAfterUpdatePosition = true;
   }
 }
@@ -1385,13 +1596,6 @@ void Controller::TextInsertedEvent()
 
   // Apply modifications to the model; TODO - Optimize this
   mImpl->mOperationsPending = ALL_OPERATIONS;
-
-  // Queue a cursor reposition event; this must wait until after DoRelayout()
-  if( EventData::IsEditingState( mImpl->mEventData->mState ) )
-  {
-    mImpl->mEventData->mUpdateCursorPosition = true;
-    mImpl->mEventData->mScrollAfterUpdatePosition = true;
-  }
 }
 
 void Controller::TextDeletedEvent()
@@ -1408,13 +1612,6 @@ void Controller::TextDeletedEvent()
 
   // Apply modifications to the model; TODO - Optimize this
   mImpl->mOperationsPending = ALL_OPERATIONS;
-
-  // Queue a cursor reposition event; this must wait until after DoRelayout()
-  mImpl->mEventData->mUpdateCursorPosition = true;
-  if( 0u != mImpl->mLogicalModel->mText.Count() )
-  {
-    mImpl->mEventData->mScrollAfterDelete = true;
-  }
 }
 
 bool Controller::DoRelayout( const Size& size,
@@ -1430,8 +1627,10 @@ bool Controller::DoRelayout( const Size& size,
   const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
   const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
 
-  if( LAYOUT & operations )
+  if( NO_OPERATION != ( LAYOUT & operations ) )
   {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
+
     // Some vectors with data needed to layout and reorder may be void
     // after the first time the text has been laid out.
     // Fill the vectors again.
@@ -1449,7 +1648,7 @@ bool Controller::DoRelayout( const Size& size,
 
     if( 0u == totalNumberOfGlyphs )
     {
-      if( UPDATE_ACTUAL_SIZE & operations )
+      if( NO_OPERATION != ( UPDATE_ACTUAL_SIZE & operations ) )
       {
         mImpl->mVisualModel->SetLayoutSize( Size::ZERO );
       }
@@ -1500,10 +1699,16 @@ bool Controller::DoRelayout( const Size& size,
                                                    mImpl->mVisualModel->mLines,
                                                    layoutSize );
 
+
     if( viewUpdated )
     {
+      if ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) )
+      {
+        mImpl->mAutoScrollDirectionRTL = false;
+      }
+
       // Reorder the lines
-      if( REORDER & operations )
+      if( NO_OPERATION != ( REORDER & operations ) )
       {
         Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mImpl->mLogicalModel->mBidirectionalParagraphInfo;
         Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = mImpl->mLogicalModel->mBidirectionalLineInfo;
@@ -1526,25 +1731,25 @@ bool Controller::DoRelayout( const Size& size,
           layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin();
           layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
 
-          // TODO: update the conversion map instead creating it from scratch.
-          //       Note this tables store indices to characters, so update the table means modify all the indices of the text after the last updated character.
-          //       It's better to refactor this. Store this table per line and don't update the indices.
-          //       For the cursor position probably is better to use the function instead creating a table.
-          // Set the bidirectional info into the model.
-          mImpl->mLogicalModel->SetVisualToLogicalMap( 0u,
-                                                       mImpl->mLogicalModel->mText.Count() );
-
           // Re-layout the text. Reorder those lines with right to left characters.
           mImpl->mLayoutEngine.ReLayoutRightToLeftLines( layoutParameters,
                                                          startIndex,
                                                          requestedNumberOfCharacters,
                                                          glyphPositions );
 
+          if ( ( NO_OPERATION != ( UPDATE_DIRECTION & operations ) ) && ( numberOfLines > 0 ) )
+          {
+            const LineRun* const firstline = mImpl->mVisualModel->mLines.Begin();
+            if ( firstline )
+            {
+              mImpl->mAutoScrollDirectionRTL = firstline->direction;
+            }
+          }
         }
       } // REORDER
 
       // Sets the actual size.
-      if( UPDATE_ACTUAL_SIZE & operations )
+      if( NO_OPERATION != ( UPDATE_ACTUAL_SIZE & operations ) )
       {
         mImpl->mVisualModel->SetLayoutSize( layoutSize );
       }
@@ -1558,7 +1763,7 @@ bool Controller::DoRelayout( const Size& size,
     layoutSize = mImpl->mVisualModel->GetLayoutSize();
   }
 
-  if( ALIGN & operations )
+  if( NO_OPERATION != ( ALIGN & operations ) )
   {
     // The laid-out lines.
     Vector<LineRun>& lines = mImpl->mVisualModel->mLines;
@@ -1570,7 +1775,11 @@ bool Controller::DoRelayout( const Size& size,
 
     viewUpdated = true;
   }
-
+#if defined(DEBUG_ENABLED)
+  std::string currentText;
+  GetText( currentText );
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mAutoScrollDirectionRTL[%s] [%s]\n", this, (mImpl->mAutoScrollDirectionRTL)?"true":"false",  currentText.c_str() );
+#endif
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", ( viewUpdated ? "true" : "false" ) );
   return viewUpdated;
 }
@@ -1638,7 +1847,7 @@ LayoutEngine::VerticalAlignment Controller::GetVerticalAlignment() const
   return mImpl->mLayoutEngine.GetVerticalAlignment();
 }
 
-void Controller::CalculateTextAlignment( const Size& controlSize )
+void Controller::CalculateVerticalOffset( const Size& controlSize )
 {
   Size layoutSize = mImpl->mVisualModel->GetLayoutSize();
 
@@ -1648,71 +1857,21 @@ void Controller::CalculateTextAlignment( const Size& controlSize )
     layoutSize.height = mImpl->GetDefaultFontLineHeight();
   }
 
-  if( LayoutEngine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() )
-  {
-    // Get the direction of the first character.
-    const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
-
-    // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
-    LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
-    if( firstParagraphDirection )
-    {
-      switch( horizontalAlignment )
-      {
-        case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
-        {
-          horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
-          break;
-        }
-        case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
-        {
-          // Nothing to do.
-          break;
-        }
-        case LayoutEngine::HORIZONTAL_ALIGN_END:
-        {
-          horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
-          break;
-        }
-      }
-    }
-
-    switch( horizontalAlignment )
-    {
-      case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
-      {
-        mImpl->mAlignmentOffset.x = 0.f;
-        break;
-      }
-      case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
-      {
-        mImpl->mAlignmentOffset.x = floorf( 0.5f * ( controlSize.width - layoutSize.width ) ); // try to avoid pixel alignment.
-        break;
-      }
-      case LayoutEngine::HORIZONTAL_ALIGN_END:
-      {
-        mImpl->mAlignmentOffset.x = controlSize.width - layoutSize.width;
-        break;
-      }
-    }
-  }
-
-  const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
-  switch( verticalAlignment )
+  switch( mImpl->mLayoutEngine.GetVerticalAlignment() )
   {
     case LayoutEngine::VERTICAL_ALIGN_TOP:
     {
-      mImpl->mAlignmentOffset.y = 0.f;
+      mImpl->mScrollPosition.y = 0.f;
       break;
     }
     case LayoutEngine::VERTICAL_ALIGN_CENTER:
     {
-      mImpl->mAlignmentOffset.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
+      mImpl->mScrollPosition.y = floorf( 0.5f * ( controlSize.height - layoutSize.height ) ); // try to avoid pixel alignment.
       break;
     }
     case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
     {
-      mImpl->mAlignmentOffset.y = controlSize.height - layoutSize.height;
+      mImpl->mScrollPosition.y = controlSize.height - layoutSize.height;
       break;
     }
   }
@@ -1832,9 +1991,13 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       textChanged = true;
     }
 
-    if( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
-        ( mImpl->mEventData->mState != EventData::INACTIVE ) )
+    if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
+         ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
+         ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) )
     {
+      // Should not change the state if the key is the shift send by the imf manager.
+      // Otherwise, when the state is SELECTING the text controller can't send the right
+      // surrounding info to the imf.
       mImpl->ChangeState( EventData::EDITING );
     }
 
@@ -1869,16 +2032,13 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   // TODO: At the moment the underline runs are only for pre-edit.
   mImpl->mVisualModel->mUnderlineRuns.Clear();
 
-  Vector<Character> utf32Characters;
-  Length characterCount( 0u );
+  // Keep the current number of characters.
+  const Length currentNumberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
 
-  // Remove the previous IMF pre-edit (predicitive text)
-  if( mImpl->mEventData->mPreEditFlag &&
-      ( 0u != mImpl->mEventData->mPreEditLength ) )
+  // Remove the previous IMF pre-edit.
+  if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
   {
-    const CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
-
-    removedPrevious = RemoveText( -static_cast<int>( offset ),
+    removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
                                   mImpl->mEventData->mPreEditLength,
                                   DONT_UPDATE_INPUT_STYLE );
 
@@ -1887,10 +2047,13 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   }
   else
   {
-    // Remove the previous Selection
+    // Remove the previous Selection.
     removedPrevious = RemoveSelectedText();
   }
 
+  Vector<Character> utf32Characters;
+  Length characterCount = 0u;
+
   if( !text.empty() )
   {
     //  Convert text into UTF-32
@@ -2055,6 +2218,8 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition );
   }
 
+  const Length numberOfCharacters = mImpl->IsShowingRealText() ? mImpl->mLogicalModel->mText.Count() : 0u;
+
   if( ( 0u == mImpl->mLogicalModel->mText.Count() ) &&
       mImpl->IsPlaceholderAvailable() )
   {
@@ -2068,6 +2233,16 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   {
     // Queue an inserted event
     mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED );
+
+    mImpl->mEventData->mUpdateCursorPosition = true;
+    if( numberOfCharacters < currentNumberOfCharacters )
+    {
+      mImpl->mEventData->mScrollAfterDelete = true;
+    }
+    else
+    {
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
+    }
   }
 
   if( maxLengthReached )
@@ -2113,10 +2288,10 @@ void Controller::TapEvent( unsigned int tapCount, float x, float y )
       // This is to avoid unnecessary relayouts when tapping an empty text-field
       bool relayoutNeeded( false );
 
-      if( ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) ||
+      if( ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) ||
           ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) )
       {
-        mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE);  // If Popup shown hide it here so can be shown again if required.
+        mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE );  // If Popup shown hide it here so can be shown again if required.
       }
 
       if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != mImpl->mEventData->mState ) )
@@ -2343,8 +2518,13 @@ void Controller::PasteClipboardItemEvent()
   // Commit the current pre-edit text; the contents of the clipboard should be appended
   mImpl->ResetImfManager();
 
+  // Temporary disable hiding clipboard
+  mImpl->SetClipboardHideEnable( false );
+
   // Paste
   PasteText( stringToPaste );
+
+  mImpl->SetClipboardHideEnable( true );
 }
 
 void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button )
@@ -2361,12 +2541,6 @@ void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Butt
       mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text
       mImpl->mOperationsPending = ALL_OPERATIONS;
 
-      // This is to reset the virtual keyboard to Upper-case
-      if( 0u == mImpl->mLogicalModel->mText.Count() )
-      {
-        NotifyImfManager();
-      }
-
       if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
           !mImpl->IsPlaceholderAvailable() )
       {
@@ -2375,8 +2549,11 @@ void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Butt
       else
       {
         ShowPlaceholderText();
-        mImpl->mEventData->mUpdateCursorPosition = true;
       }
+
+      mImpl->mEventData->mUpdateCursorPosition = true;
+      mImpl->mEventData->mScrollAfterDelete = true;
+
       mImpl->RequestRelayout();
       mImpl->mControlInterface.TextChanged();
       break;
@@ -2426,35 +2603,36 @@ void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Butt
 
 ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
 {
-  bool update = false;
+  // Whether the text needs to be relaid-out.
   bool requestRelayout = false;
 
-  std::string text;
-  unsigned int cursorPosition = 0u;
+  // Whether to retrieve the text and cursor position to be sent to the IMF manager.
+  bool retrieveText = false;
+  bool retrieveCursor = false;
 
   switch( imfEvent.eventName )
   {
     case ImfManager::COMMIT:
     {
       InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
-      update = true;
       requestRelayout = true;
+      retrieveCursor = true;
       break;
     }
     case ImfManager::PREEDIT:
     {
       InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
-      update = true;
       requestRelayout = true;
+      retrieveCursor = true;
       break;
     }
     case ImfManager::DELETESURROUNDING:
     {
-      update = RemoveText( imfEvent.cursorOffset,
-                           imfEvent.numberOfChars,
-                           DONT_UPDATE_INPUT_STYLE );
+      const bool textDeleted = RemoveText( imfEvent.cursorOffset,
+                                           imfEvent.numberOfChars,
+                                           DONT_UPDATE_INPUT_STYLE );
 
-      if( update )
+      if( textDeleted )
       {
         if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
             !mImpl->IsPlaceholderAvailable() )
@@ -2464,19 +2642,19 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
         else
         {
           ShowPlaceholderText();
-          mImpl->mEventData->mUpdateCursorPosition = true;
         }
+        mImpl->mEventData->mUpdateCursorPosition = true;
+        mImpl->mEventData->mScrollAfterDelete = true;
+
+        requestRelayout = true;
+        retrieveCursor = true;
       }
-      requestRelayout = true;
       break;
     }
     case ImfManager::GETSURROUNDING:
     {
-      GetText( text );
-      cursorPosition = GetLogicalCursorPosition();
-
-      imfManager.SetSurroundingText( text );
-      imfManager.SetCursorPosition( cursorPosition );
+      retrieveText = true;
+      retrieveCursor = true;
       break;
     }
     case ImfManager::VOID:
@@ -2486,12 +2664,6 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
     }
   } // end switch
 
-  if( ImfManager::GETSURROUNDING != imfEvent.eventName )
-  {
-    GetText( text );
-    cursorPosition = GetLogicalCursorPosition();
-  }
-
   if( requestRelayout )
   {
     mImpl->mOperationsPending = ALL_OPERATIONS;
@@ -2501,7 +2673,32 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
     mImpl->mControlInterface.TextChanged();
   }
 
-  ImfManager::ImfCallbackData callbackData( update, cursorPosition, text, false );
+  std::string text;
+  CharacterIndex cursorPosition = 0u;
+  Length numberOfWhiteSpaces = 0u;
+
+  if( retrieveCursor )
+  {
+    numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u );
+
+    cursorPosition = mImpl->GetLogicalCursorPosition();
+
+    if( cursorPosition < numberOfWhiteSpaces )
+    {
+      cursorPosition = 0u;
+    }
+    else
+    {
+      cursorPosition -= numberOfWhiteSpaces;
+    }
+  }
+
+  if( retrieveText )
+  {
+    mImpl->GetText( numberOfWhiteSpaces, text );
+  }
+
+  ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
 
   return callbackData;
 }
@@ -2539,11 +2736,6 @@ bool Controller::BackspaceKeyEvent()
 
   if( removed )
   {
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p DALI_KEY_BACKSPACE RemovedText\n", this );
-    // Notifiy the IMF manager after text changed
-    // Automatic  Upper-case and restarting prediction on an existing word require this.
-    NotifyImfManager();
-
     if( ( 0u != mImpl->mLogicalModel->mText.Count() ) ||
         !mImpl->IsPlaceholderAvailable() )
     {
@@ -2552,30 +2744,14 @@ bool Controller::BackspaceKeyEvent()
     else
     {
       ShowPlaceholderText();
-      mImpl->mEventData->mUpdateCursorPosition = true;
     }
+    mImpl->mEventData->mUpdateCursorPosition = true;
+    mImpl->mEventData->mScrollAfterDelete = true;
   }
 
   return removed;
 }
 
-void Controller::NotifyImfManager()
-{
-  if( NULL != mImpl->mEventData )
-  {
-    if( mImpl->mEventData->mImfManager )
-    {
-      // Notifying IMF of a cursor change triggers a surrounding text request so updating it now.
-      std::string text;
-      GetText( text );
-      mImpl->mEventData->mImfManager.SetSurroundingText( text );
-
-      mImpl->mEventData->mImfManager.SetCursorPosition( GetLogicalCursorPosition() );
-      mImpl->mEventData->mImfManager.NotifyCursorPosition();
-    }
-  }
-}
-
 void Controller::ShowPlaceholderText()
 {
   if( mImpl->IsPlaceholderAvailable() )