Further refactoring of text-controller-impl
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
index b0aa82e..6554a2c 100644 (file)
@@ -21,7 +21,6 @@
 // EXTERNAL INCLUDES
 #include <dali/public-api/rendering/renderer.h>
 #include <dali/integration-api/debug.h>
-#include <limits>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/text/text-control-interface.h>
 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
 #include <dali-toolkit/internal/text/text-run-container.h>
-#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-selection-handle-controller.h>
 
 using namespace Dali;
 
 namespace
 {
 
-/**
- * @brief Struct used to calculate the selection box.
- */
-struct SelectionBoxInfo
-{
-  float lineOffset;
-  float lineHeight;
-  float minX;
-  float maxX;
-};
-
 #if defined(DEBUG_ENABLED)
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
 #endif
 
-const float MAX_FLOAT = std::numeric_limits<float>::max();
-const float MIN_FLOAT = std::numeric_limits<float>::min();
-const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
-
 #define MAKE_SHADER(A)#A
 
 const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
@@ -165,228 +149,9 @@ EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodCon
 {
 }
 
-EventData::~EventData()
-{}
-
 bool Controller::Impl::ProcessInputEvents()
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::ProcessInputEvents\n" );
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents no event data\n" );
-    return false;
-  }
-
-  if( mEventData->mDecorator )
-  {
-    for( std::vector<Event>::iterator iter = mEventData->mEventQueue.begin();
-         iter != mEventData->mEventQueue.end();
-         ++iter )
-    {
-      switch( iter->type )
-      {
-        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;
-        }
-        case Event::SELECT_NONE:
-        {
-          OnSelectNoneEvent();
-          break;
-        }
-      }
-    }
-  }
-
-  if( mEventData->mUpdateCursorPosition ||
-      mEventData->mUpdateHighlightBox )
-  {
-    NotifyInputMethodContext();
-  }
-
-  // The cursor must also be repositioned after inserts into the model
-  if( mEventData->mUpdateCursorPosition )
-  {
-    // Updates the cursor position and scrolls the text to make it visible.
-    CursorInfo cursorInfo;
-    // Calculate the cursor position from the new cursor index.
-    GetCursorPosition( mEventData->mPrimaryCursorPosition,
-                       cursorInfo );
-
-    if( NULL != mEditableControlInterface )
-    {
-      mEditableControlInterface->CaretMoved( mEventData->mPrimaryCursorPosition );
-    }
-
-    if( mEventData->mUpdateCursorHookPosition )
-    {
-      // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'.
-      mEventData->mCursorHookPositionX = cursorInfo.primaryPosition.x;
-      mEventData->mUpdateCursorHookPosition = false;
-    }
-
-    // Scroll first the text after delete ...
-    if( mEventData->mScrollAfterDelete )
-    {
-      ScrollTextToMatchCursor( cursorInfo );
-    }
-
-    // ... then, text can be scrolled to make the cursor visible.
-    if( mEventData->mScrollAfterUpdatePosition )
-    {
-      const Vector2 currentCursorPosition( cursorInfo.primaryPosition.x, cursorInfo.lineOffset );
-      ScrollToMakePositionVisible( currentCursorPosition, cursorInfo.lineHeight );
-    }
-    mEventData->mScrollAfterUpdatePosition = false;
-    mEventData->mScrollAfterDelete = false;
-
-    UpdateCursorPosition( cursorInfo );
-
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateCursorPosition = false;
-    mEventData->mUpdateGrabHandlePosition = false;
-  }
-  else
-  {
-    CursorInfo leftHandleInfo;
-    CursorInfo rightHandleInfo;
-
-    if( mEventData->mUpdateHighlightBox )
-    {
-      GetCursorPosition( mEventData->mLeftSelectionPosition,
-                         leftHandleInfo );
-
-      GetCursorPosition( mEventData->mRightSelectionPosition,
-                         rightHandleInfo );
-
-      if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
-      {
-        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 );
-        }
-      }
-    }
-
-    if( mEventData->mUpdateLeftSelectionPosition )
-    {
-      UpdateSelectionHandle( LEFT_SELECTION_HANDLE,
-                             leftHandleInfo );
-
-      SetPopupButtons();
-      mEventData->mDecoratorUpdated = true;
-      mEventData->mUpdateLeftSelectionPosition = false;
-    }
-
-    if( mEventData->mUpdateRightSelectionPosition )
-    {
-      UpdateSelectionHandle( RIGHT_SELECTION_HANDLE,
-                             rightHandleInfo );
-
-      SetPopupButtons();
-      mEventData->mDecoratorUpdated = true;
-      mEventData->mUpdateRightSelectionPosition = false;
-    }
-
-    if( mEventData->mUpdateHighlightBox )
-    {
-      RepositionSelectionHandles();
-
-      mEventData->mUpdateLeftSelectionPosition = false;
-      mEventData->mUpdateRightSelectionPosition = false;
-      mEventData->mUpdateHighlightBox = false;
-      mEventData->mIsLeftHandleSelected = false;
-      mEventData->mIsRightHandleSelected = false;
-    }
-
-    mEventData->mScrollAfterUpdatePosition = false;
-  }
-
-  if( mEventData->mUpdateInputStyle )
-  {
-    // Keep a copy of the current input style.
-    InputStyle currentInputStyle;
-    currentInputStyle.Copy( mEventData->mInputStyle );
-
-    // 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.
-    mModel->mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
-
-    // Compare if the input style has changed.
-    const bool hasInputStyleChanged = !currentInputStyle.Equal( mEventData->mInputStyle );
-
-    if( hasInputStyleChanged )
-    {
-      const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mEventData->mInputStyle );
-      // Queue the input style changed signal.
-      mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask );
-    }
-
-    mEventData->mUpdateInputStyle = false;
-  }
-
-  mEventData->mEventQueue.clear();
-
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
-
-  const bool decoratorUpdated = mEventData->mDecoratorUpdated;
-  mEventData->mDecoratorUpdated = false;
-
-  return decoratorUpdated;
+  return ControllerImplEventHandler::ProcessInputEvents(*this);
 }
 
 void Controller::Impl::NotifyInputMethodContext()
@@ -959,7 +724,7 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 
       // Get the default font's description.
       TextAbstraction::FontDescription defaultFontDescription;
-      TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+      TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
 
       if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
       {
@@ -967,7 +732,7 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
         defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
         if( mEventData->mPlaceholderFont->sizeDefined )
         {
-          defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
+          defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * mFontSizeScale * 64u;
         }
       }
       else if( NULL != mFontDefaults )
@@ -981,7 +746,7 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
         }
         else
         {
-          defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
+          defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * 64u;
         }
       }
 
@@ -1332,11 +1097,11 @@ float Controller::Impl::GetDefaultFontLineHeight()
   if( NULL == mFontDefaults )
   {
     TextAbstraction::FontDescription fontDescription;
-    defaultFontId = mFontClient.GetFontId( fontDescription );
+    defaultFontId = mFontClient.GetFontId( fontDescription, TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale );
   }
   else
   {
-    defaultFontId = mFontDefaults->GetFontId( mFontClient );
+    defaultFontId = mFontDefaults->GetFontId( mFontClient, mFontDefaults->mDefaultPointSize * mFontSizeScale );
   }
 
   Text::FontMetrics fontMetrics;
@@ -1345,46 +1110,6 @@ float Controller::Impl::GetDefaultFontLineHeight()
   return( fontMetrics.ascender - fontMetrics.descender );
 }
 
-void Controller::Impl::OnCursorKeyEvent( const Event& event )
-{
-  ControllerImplEventHandler::OnCursorKeyEvent(*this, event);
-}
-
-void Controller::Impl::OnTapEvent( const Event& event )
-{
-  ControllerImplEventHandler::OnTapEvent(*this, event);
-}
-
-void Controller::Impl::OnPanEvent( const Event& event )
-{
-  ControllerImplEventHandler::OnPanEvent(*this, event);
-}
-
-void Controller::Impl::OnLongPressEvent( const Event& event )
-{
-  ControllerImplEventHandler::OnLongPressEvent(*this, event);
-}
-
-void Controller::Impl::OnHandleEvent( const Event& event )
-{
-  ControllerImplEventHandler::OnHandleEvent(*this, event);
-}
-
-void Controller::Impl::OnSelectEvent( const Event& event )
-{
-  ControllerImplEventHandler::OnSelectEvent(*this, event);
-}
-
-void Controller::Impl::OnSelectAllEvent()
-{
-  ControllerImplEventHandler::OnSelectAllEvent(*this);
-}
-
-void Controller::Impl::OnSelectNoneEvent()
-{
-  ControllerImplEventHandler::OnSelectNoneEvent(*this);
-}
-
 void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint32_t *pEnd)
 {
   if( nullptr == mEventData )
@@ -1422,6 +1147,38 @@ void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint3
   }
 }
 
+CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
+{
+  if( nullptr == mEventData )
+  {
+    return 0;
+  }
+  return mEventData->mPrimaryCursorPosition;
+}
+
+bool Controller::Impl::SetPrimaryCursorPosition( CharacterIndex index )
+{
+  if( nullptr == mEventData )
+  {
+    // Nothing to do if there is no text.
+    return false;
+  }
+
+  if( mEventData->mPrimaryCursorPosition == index )
+  {
+    // Nothing for same cursor position.
+    return false;
+  }
+
+  uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+  mEventData->mPrimaryCursorPosition = std::min(index, length);
+  ChangeState( EventData::EDITING );
+  mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+  mEventData->mUpdateCursorPosition = true;
+  ScrollTextToMatchCursor();
+  return true;
+}
+
 Uint32Pair Controller::Impl::GetTextSelectionRange() const
 {
   Uint32Pair range;
@@ -1582,477 +1339,11 @@ void Controller::Impl::RequestGetTextFromClipboard()
 
 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.
-    // So, deactive Highlight box.
-    mEventData->mDecorator->SetHighlightActive( false );
-    return;
-  }
-
-  mEventData->mDecorator->ClearHighlights();
-
-  const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
-  const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
-  const GlyphInfo* const glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
-  const Vector2* const positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
-  const Length* const charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
-  const CharacterIndex* const glyphToCharacterBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
-  const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mModel->mLogicalModel->mCharacterDirections.Count() ) ? mModel->mLogicalModel->mCharacterDirections.Begin() : NULL;
-
-  const bool isLastCharacter = selectionEnd >= mModel->mLogicalModel->mText.Count();
-  const CharacterDirection startDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + selectionStart ) );
-  const CharacterDirection endDirection = ( ( NULL == modelCharacterDirectionsBuffer ) ? false : *( modelCharacterDirectionsBuffer + ( selectionEnd - ( isLastCharacter ? 1u : 0u ) ) ) );
-
-  // Swap the indices if the start is greater than the end.
-  const bool indicesSwapped = selectionStart > selectionEnd;
-
-  // Tell the decorator to flip the selection handles if needed.
-  mEventData->mDecorator->SetSelectionHandleFlipState( indicesSwapped, startDirection, endDirection );
-
-  if( indicesSwapped )
-  {
-    std::swap( selectionStart, selectionEnd );
-  }
-
-  // Get the indices to the first and last selected glyphs.
-  const CharacterIndex selectionEndMinusOne = selectionEnd - 1u;
-  const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
-  const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + selectionEndMinusOne );
-  const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + selectionEndMinusOne ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
-
-  // Get the lines where the glyphs are laid-out.
-  const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
-
-  LineIndex lineIndex = 0u;
-  Length numberOfLines = 0u;
-  mModel->mVisualModel->GetNumberOfLines( glyphStart,
-                                          1u + glyphEnd - glyphStart,
-                                          lineIndex,
-                                          numberOfLines );
-  const LineIndex firstLineIndex = lineIndex;
-
-  // Create the structure to store some selection box info.
-  Vector<SelectionBoxInfo> selectionBoxLinesInfo;
-  selectionBoxLinesInfo.Resize( numberOfLines );
-
-  SelectionBoxInfo* selectionBoxInfo = selectionBoxLinesInfo.Begin();
-  selectionBoxInfo->minX = MAX_FLOAT;
-  selectionBoxInfo->maxX = MIN_FLOAT;
-
-  // Keep the min and max 'x' position to calculate the size and position of the highlighed text.
-  float minHighlightX = std::numeric_limits<float>::max();
-  float maxHighlightX = std::numeric_limits<float>::min();
-  Size highLightSize;
-  Vector2 highLightPosition; // The highlight position in decorator's coords.
-
-  // Retrieve the first line and get the line's vertical offset, the line's height and the index to the last glyph.
-
-  // The line's vertical offset of all the lines before the line where the first glyph is laid-out.
-  selectionBoxInfo->lineOffset = CalculateLineOffset( mModel->mVisualModel->mLines,
-                                                      firstLineIndex );
-
-  // Transform to decorator's (control) coords.
-  selectionBoxInfo->lineOffset += mModel->mScrollPosition.y;
-
-  lineRun += firstLineIndex;
-
-  // The line height is the addition of the line ascender and the line descender.
-  // However, the line descender has a negative value, hence the subtraction.
-  selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
-
-  GlyphIndex lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
-
-  // 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( mModel->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( mModel->mLogicalModel->GetScript( selectionEndMinusOne ) );
-
-  // The number of quads of the selection box.
-  const unsigned int numberOfQuads = 1u + ( glyphEnd - glyphStart ) + ( ( numberOfLines > 1u ) ? 2u * numberOfLines : 0u );
-  mEventData->mDecorator->ResizeHighlightQuads( numberOfQuads );
-
-  // Count the actual number of quads.
-  unsigned int actualNumberOfQuads = 0u;
-  Vector4 quad;
-
-  // 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 );
-
-      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + glyphAdvance * static_cast<float>( isCurrentRightToLeft ? ( numberOfCharactersStart - interGlyphIndex - numberOfCharacters ) : interGlyphIndex );
-      quad.y = selectionBoxInfo->lineOffset;
-      quad.z = quad.x + static_cast<float>( numberOfCharacters ) * glyphAdvance;
-      quad.w = selectionBoxInfo->lineOffset + selectionBoxInfo->lineHeight;
-
-      // Store the min and max 'x' for each line.
-      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
-      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
-
-      mEventData->mDecorator->AddHighlight( actualNumberOfQuads, quad );
-      ++actualNumberOfQuads;
-
-      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;
-
-      quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x + ( isCurrentRightToLeft ? ( glyphAdvance * static_cast<float>( numberOfCharacters ) ) : 0.f );
-      quad.y = selectionBoxInfo->lineOffset;
-      quad.z = quad.x + static_cast<float>( interGlyphIndex ) * glyphAdvance;
-      quad.w = quad.y + selectionBoxInfo->lineHeight;
-
-      // Store the min and max 'x' for each line.
-      selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
-      selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
-
-      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
-      ++actualNumberOfQuads;
-
-      splitEndGlyph = false;
-      continue;
-    }
-
-    quad.x = lineRun->alignmentOffset + position.x - glyph.xBearing + mModel->mScrollPosition.x;
-    quad.y = selectionBoxInfo->lineOffset;
-    quad.z = quad.x + glyph.advance;
-    quad.w = quad.y + selectionBoxInfo->lineHeight;
-
-    // Store the min and max 'x' for each line.
-    selectionBoxInfo->minX = std::min( selectionBoxInfo->minX, quad.x );
-    selectionBoxInfo->maxX = std::max( selectionBoxInfo->maxX, quad.z );
-
-    mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                          quad );
-    ++actualNumberOfQuads;
-
-    // Whether to retrieve the next line.
-    if( index == lastGlyphOfLine )
-    {
-      ++lineIndex;
-      if( lineIndex < firstLineIndex + numberOfLines )
-      {
-        // Retrieve the next line.
-        ++lineRun;
-
-        // Get the last glyph of the new line.
-        lastGlyphOfLine = lineRun->glyphRun.glyphIndex + lineRun->glyphRun.numberOfGlyphs - 1u;
-
-        // Keep the offset and height of the current selection box.
-        const float currentLineOffset = selectionBoxInfo->lineOffset;
-        const float currentLineHeight = selectionBoxInfo->lineHeight;
-
-        // Get the selection box info for the next line.
-        ++selectionBoxInfo;
-
-        selectionBoxInfo->minX = MAX_FLOAT;
-        selectionBoxInfo->maxX = MIN_FLOAT;
-
-        // Update the line's vertical offset.
-        selectionBoxInfo->lineOffset = currentLineOffset + currentLineHeight;
-
-        // The line height is the addition of the line ascender and the line descender.
-        // However, the line descender has a negative value, hence the subtraction.
-        selectionBoxInfo->lineHeight = lineRun->ascender - lineRun->descender;
-      }
-    }
-  }
-
-  // Traverses all the lines and updates the min and max 'x' positions and the total height.
-  // The final width is calculated after 'boxifying' the selection.
-  for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin(),
-         endIt = selectionBoxLinesInfo.End();
-       it != endIt;
-       ++it )
-  {
-    const SelectionBoxInfo& info = *it;
-
-    // Update the size of the highlighted text.
-    highLightSize.height += info.lineHeight;
-    minHighlightX = std::min( minHighlightX, info.minX );
-    maxHighlightX = std::max( maxHighlightX, info.maxX );
-  }
-
-  // Add extra geometry to 'boxify' the selection.
-
-  if( 1u < numberOfLines )
-  {
-    // Boxify the first line.
-    lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex;
-    const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
-
-    bool boxifyBegin = ( LTR != lineRun->direction ) && ( LTR != startDirection );
-    bool boxifyEnd = ( LTR == lineRun->direction ) && ( LTR == startDirection );
-
-    if( boxifyBegin )
-    {
-      quad.x = 0.f;
-      quad.y = firstSelectionBoxLineInfo.lineOffset;
-      quad.z = firstSelectionBoxLineInfo.minX;
-      quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
-
-      // Boxify at the beginning of the line.
-      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
-      ++actualNumberOfQuads;
-
-      // Update the size of the highlighted text.
-      minHighlightX = 0.f;
-    }
-
-    if( boxifyEnd )
-    {
-      quad.x = firstSelectionBoxLineInfo.maxX;
-      quad.y = firstSelectionBoxLineInfo.lineOffset;
-      quad.z = mModel->mVisualModel->mControlSize.width;
-      quad.w = firstSelectionBoxLineInfo.lineOffset + firstSelectionBoxLineInfo.lineHeight;
-
-      // Boxify at the end of the line.
-      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
-      ++actualNumberOfQuads;
-
-      // Update the size of the highlighted text.
-      maxHighlightX = mModel->mVisualModel->mControlSize.width;
-    }
-
-    // Boxify the central lines.
-    if( 2u < numberOfLines )
-    {
-      for( Vector<SelectionBoxInfo>::ConstIterator it = selectionBoxLinesInfo.Begin() + 1u,
-             endIt = selectionBoxLinesInfo.End() - 1u;
-           it != endIt;
-           ++it )
-      {
-        const SelectionBoxInfo& info = *it;
-
-        quad.x = 0.f;
-        quad.y = info.lineOffset;
-        quad.z = info.minX;
-        quad.w = info.lineOffset + info.lineHeight;
-
-        mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                              quad );
-        ++actualNumberOfQuads;
-
-        quad.x = info.maxX;
-        quad.y = info.lineOffset;
-        quad.z = mModel->mVisualModel->mControlSize.width;
-        quad.w = info.lineOffset + info.lineHeight;
-
-        mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                              quad );
-        ++actualNumberOfQuads;
-      }
-
-      // Update the size of the highlighted text.
-      minHighlightX = 0.f;
-      maxHighlightX = mModel->mVisualModel->mControlSize.width;
-    }
-
-    // Boxify the last line.
-    lineRun = mModel->mVisualModel->mLines.Begin() + firstLineIndex + numberOfLines - 1u;
-    const SelectionBoxInfo& lastSelectionBoxLineInfo = *( selectionBoxLinesInfo.End() - 1u );
-
-    boxifyBegin = ( LTR == lineRun->direction ) && ( LTR == endDirection );
-    boxifyEnd = ( LTR != lineRun->direction ) && ( LTR != endDirection );
-
-    if( boxifyBegin )
-    {
-      quad.x = 0.f;
-      quad.y = lastSelectionBoxLineInfo.lineOffset;
-      quad.z = lastSelectionBoxLineInfo.minX;
-      quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
-
-      // Boxify at the beginning of the line.
-      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
-      ++actualNumberOfQuads;
-
-      // Update the size of the highlighted text.
-      minHighlightX = 0.f;
-    }
-
-    if( boxifyEnd )
-    {
-      quad.x = lastSelectionBoxLineInfo.maxX;
-      quad.y = lastSelectionBoxLineInfo.lineOffset;
-      quad.z = mModel->mVisualModel->mControlSize.width;
-      quad.w = lastSelectionBoxLineInfo.lineOffset + lastSelectionBoxLineInfo.lineHeight;
-
-      // Boxify at the end of the line.
-      mEventData->mDecorator->AddHighlight( actualNumberOfQuads,
-                                            quad );
-      ++actualNumberOfQuads;
-
-      // Update the size of the highlighted text.
-      maxHighlightX = mModel->mVisualModel->mControlSize.width;
-    }
-  }
-
-  // Set the actual number of quads.
-  mEventData->mDecorator->ResizeHighlightQuads( actualNumberOfQuads );
-
-  // Sets the highlight's size and position. In decorator's coords.
-  // The highlight's height has been calculated above (before 'boxifying' the highlight).
-  highLightSize.width = maxHighlightX - minHighlightX;
-
-  highLightPosition.x = minHighlightX;
-  const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
-  highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
-
-  mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
-
-  if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
-  {
-    CursorInfo primaryCursorInfo;
-    GetCursorPosition( mEventData->mLeftSelectionPosition,
-                       primaryCursorInfo );
-
-    const Vector2 primaryPosition = primaryCursorInfo.primaryPosition + mModel->mScrollPosition;
-
-    mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,
-                                         primaryPosition.x,
-                                         primaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
-                                         primaryCursorInfo.lineHeight );
-
-    CursorInfo secondaryCursorInfo;
-    GetCursorPosition( mEventData->mRightSelectionPosition,
-                       secondaryCursorInfo );
-
-    const Vector2 secondaryPosition = secondaryCursorInfo.primaryPosition + mModel->mScrollPosition;
-
-    mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE,
-                                         secondaryPosition.x,
-                                         secondaryCursorInfo.lineOffset + mModel->mScrollPosition.y,
-                                         secondaryCursorInfo.lineHeight );
-  }
-
-  // Set the flag to update the decorator.
-  mEventData->mDecoratorUpdated = true;
+  SelectionHandleController::Reposition(*this);
 }
-
 void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
 {
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  if( IsShowingPlaceholderText() )
-  {
-    // Nothing to do if there is the place-holder text.
-    return;
-  }
-
-  const Length numberOfGlyphs = mModel->mVisualModel->mGlyphs.Count();
-  const Length numberOfLines  = mModel->mVisualModel->mLines.Count();
-  if( ( 0 == numberOfGlyphs ) ||
-      ( 0 == numberOfLines ) )
-  {
-    // Nothing to do if there is no text.
-    return;
-  }
-
-  // Find which word was selected
-  CharacterIndex selectionStart( 0 );
-  CharacterIndex selectionEnd( 0 );
-  CharacterIndex noTextHitIndex( 0 );
-  const bool characterHit = FindSelectionIndices( mModel->mVisualModel,
-                                                  mModel->mLogicalModel,
-                                                  mMetrics,
-                                                  visualX,
-                                                  visualY,
-                                                  selectionStart,
-                                                  selectionEnd,
-                                                  noTextHitIndex );
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
-
-  if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
-  {
-    ChangeState( EventData::SELECTING );
-
-    mEventData->mLeftSelectionPosition = selectionStart;
-    mEventData->mRightSelectionPosition = selectionEnd;
-
-    mEventData->mUpdateLeftSelectionPosition = true;
-    mEventData->mUpdateRightSelectionPosition = true;
-    mEventData->mUpdateHighlightBox = true;
-
-    // It may happen an InputMethodContext commit event arrives before the selection event
-    // if the InputMethodContext is in pre-edit state. The commit event will set the
-    // mEventData->mUpdateCursorPosition flag to true. If it's not set back
-    // to false, the highlight box won't be updated.
-    mEventData->mUpdateCursorPosition = false;
-
-    mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
-
-    // 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 = std::max( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
-  }
-  else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
-  {
-    // Nothing to select. i.e. a white space, out of bounds
-    ChangeState( EventData::EDITING_WITH_POPUP );
-
-    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->mScrollAfterUpdatePosition = true;
-    mEventData->mUpdateInputStyle = true;
-  }
+  SelectionHandleController::Reposition(*this, visualX, visualY, action);
 }
 
 void Controller::Impl::SetPopupButtons()
@@ -2550,24 +1841,7 @@ void Controller::Impl::UpdateCursorPosition( const CursorInfo& cursorInfo )
 void Controller::Impl::UpdateSelectionHandle( HandleType handleType,
                                               const CursorInfo& cursorInfo )
 {
-  if( ( LEFT_SELECTION_HANDLE != handleType ) &&
-      ( RIGHT_SELECTION_HANDLE != handleType ) )
-  {
-    return;
-  }
-
-  const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
-
-  // Sets the handle's position.
-  mEventData->mDecorator->SetPosition( handleType,
-                                       cursorPosition.x,
-                                       cursorInfo.lineOffset + mModel->mScrollPosition.y,
-                                       cursorInfo.lineHeight );
-
-  // If selection handle at start of the text and other at end of the text then all text is selected.
-  const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
-  const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
-  mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mModel->mLogicalModel->mText.Count() );
+  SelectionHandleController::Update(*this, handleType, cursorInfo);
 }
 
 void Controller::Impl::ClampHorizontalScroll( const Vector2& layoutSize )
@@ -2675,6 +1949,13 @@ void Controller::Impl::ScrollTextToMatchCursor( const CursorInfo& cursorInfo )
   ScrollToMakePositionVisible( cursorInfo.primaryPosition, cursorInfo.lineHeight );
 }
 
+void Controller::Impl::ScrollTextToMatchCursor()
+{
+  CursorInfo cursorInfo;
+  GetCursorPosition( mEventData->mPrimaryCursorPosition, cursorInfo );
+  ScrollTextToMatchCursor(cursorInfo);
+}
+
 void Controller::Impl::RequestRelayout()
 {
   if( NULL != mControlInterface )