(TextController/ScrollView) Reduced LOC
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
index 417eaed..8a1dd76 100644 (file)
 #include <dali-toolkit/internal/text/text-controller-impl.h>
 
 // EXTERNAL INCLUDES
+#include <cmath>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
-#include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/color-segmentation.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/hyphenator.h>
-#include <dali-toolkit/internal/text/multi-language-support.h>
-#include <dali-toolkit/internal/text/segmentation.h>
-#include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
+#include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
+#include <dali-toolkit/internal/text/text-editable-control-interface.h>
+#include <dali-toolkit/internal/text/text-enumerations-impl.h>
 #include <dali-toolkit/internal/text/text-run-container.h>
 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
 
-#include <dali-toolkit/internal/text/text-enumerations-impl.h>
-
 using namespace Dali;
 
 namespace
@@ -60,24 +58,323 @@ struct BackgroundMesh
   Vector<unsigned short>   mIndices;  ///< container of indices
 };
 
-const Dali::Vector4 LIGHT_BLUE(0.75f, 0.96f, 1.f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB4(0.58f, 0.87f, 0.96f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB5(0.83f, 0.94f, 0.98f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB6(1.f, 0.5f, 0.5f, 1.f);
-const Dali::Vector4 BACKGROUND_SUB7(1.f, 0.8f, 0.8f, 1.f);
-
 } // namespace
 
-namespace Dali
+namespace Dali::Toolkit::Text
 {
-namespace Toolkit
+
+namespace
+{
+
+void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const fontDefaults, const Vector4& textColor)
 {
-namespace Text
+  // Sets the default text's color.
+  inputStyle.textColor      = textColor;
+  inputStyle.isDefaultColor = true;
+
+  inputStyle.familyName.clear();
+  inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
+  inputStyle.width  = TextAbstraction::FontWidth::NORMAL;
+  inputStyle.slant  = TextAbstraction::FontSlant::NORMAL;
+  inputStyle.size   = 0.f;
+
+  inputStyle.lineSpacing = 0.f;
+
+  inputStyle.underlineProperties.clear();
+  inputStyle.shadowProperties.clear();
+  inputStyle.embossProperties.clear();
+  inputStyle.outlineProperties.clear();
+
+  inputStyle.isFamilyDefined = false;
+  inputStyle.isWeightDefined = false;
+  inputStyle.isWidthDefined  = false;
+  inputStyle.isSlantDefined  = false;
+  inputStyle.isSizeDefined   = false;
+
+  inputStyle.isLineSpacingDefined = false;
+
+  inputStyle.isUnderlineDefined = false;
+  inputStyle.isShadowDefined    = false;
+  inputStyle.isEmbossDefined    = false;
+  inputStyle.isOutlineDefined   = false;
+
+  // Sets the default font's family name, weight, width, slant and size.
+  if(fontDefaults)
+  {
+    if(fontDefaults->familyDefined)
+    {
+      inputStyle.familyName      = fontDefaults->mFontDescription.family;
+      inputStyle.isFamilyDefined = true;
+    }
+
+    if(fontDefaults->weightDefined)
+    {
+      inputStyle.weight          = fontDefaults->mFontDescription.weight;
+      inputStyle.isWeightDefined = true;
+    }
+
+    if(fontDefaults->widthDefined)
+    {
+      inputStyle.width          = fontDefaults->mFontDescription.width;
+      inputStyle.isWidthDefined = true;
+    }
+
+    if(fontDefaults->slantDefined)
+    {
+      inputStyle.slant          = fontDefaults->mFontDescription.slant;
+      inputStyle.isSlantDefined = true;
+    }
+
+    if(fontDefaults->sizeDefined)
+    {
+      inputStyle.size          = fontDefaults->mDefaultPointSize;
+      inputStyle.isSizeDefined = true;
+    }
+  }
+}
+
+void ChangeTextControllerState(Controller::Impl& impl, EventData::State newState)
 {
+  EventData* eventData = impl.mEventData;
+
+  if(nullptr == eventData)
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  DecoratorPtr& decorator = eventData->mDecorator;
+  if(!decorator)
+  {
+    // Nothing to do if there is no decorator.
+    return;
+  }
+
+  DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", eventData->mState, newState);
+
+  if(eventData->mState != newState)
+  {
+    eventData->mPreviousState = eventData->mState;
+    eventData->mState         = newState;
+
+    switch(eventData->mState)
+    {
+      case EventData::INACTIVE:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        decorator->SetPopupActive(false);
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::INTERRUPTED:
+      {
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        decorator->SetPopupActive(false);
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::SELECTING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
+        }
+        decorator->SetHighlightActive(true);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          impl.SetPopupButtons();
+          decorator->SetPopupActive(true);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::EDITING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        // Grab handle is not shown until a tap is received whilst EDITING
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_POPUP:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        if(eventData->mSelectionEnabled)
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+          decorator->SetHighlightActive(false);
+        }
+        else if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          impl.SetPopupButtons();
+          decorator->SetPopupActive(true);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_GRAB_HANDLE:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        // Grab handle is not shown until a tap is received whilst EDITING
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::SELECTION_HANDLE_PANNING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
+        }
+        decorator->SetHighlightActive(true);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::GRAB_HANDLE_PANNING:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::EDITING_WITH_PASTE_POPUP:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          impl.SetPopupButtons();
+          decorator->SetPopupActive(true);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::TEXT_PANNING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        if(eventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
+            decorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+          decorator->SetHighlightActive(true);
+        }
+
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+    }
+  }
+}
+
+} // unnamed Namespace
+
 EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
 : mDecorator(decorator),
   mInputMethodContext(inputMethodContext),
-  mPlaceholderFont(NULL),
+  mPlaceholderFont(nullptr),
   mPlaceholderTextActive(),
   mPlaceholderTextInactive(),
   mPlaceholderTextColor(0.8f, 0.8f, 0.8f, 0.8f), // This color has been published in the Public API (placeholder-properties.h).
@@ -211,6 +508,19 @@ void Controller::Impl::GetText(CharacterIndex index, std::string& text) const
   }
 }
 
+Dali::LayoutDirection::Type Controller::Impl::GetLayoutDirection(Dali::Actor& actor) const
+{
+  if(mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE ||
+     (mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mIsLayoutDirectionChanged))
+  {
+    return static_cast<Dali::LayoutDirection::Type>(DevelWindow::Get(actor).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+  }
+  else
+  {
+    return static_cast<Dali::LayoutDirection::Type>(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+  }
+}
+
 void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
 {
   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
@@ -296,854 +606,19 @@ void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
   mTextUpdateInfo.mStartGlyphIndex             = *(mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex);
 }
 
-void Controller::Impl::ClearFullModelData(OperationsMask operations)
-{
-  if(NO_OPERATION != (GET_LINE_BREAKS & operations))
-  {
-    mModel->mLogicalModel->mLineBreakInfo.Clear();
-    mModel->mLogicalModel->mParagraphInfo.Clear();
-  }
-
-  if(NO_OPERATION != (GET_SCRIPTS & operations))
-  {
-    mModel->mLogicalModel->mScriptRuns.Clear();
-  }
-
-  if(NO_OPERATION != (VALIDATE_FONTS & operations))
-  {
-    mModel->mLogicalModel->mFontRuns.Clear();
-  }
-
-  if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
-  {
-    if(NO_OPERATION != (BIDI_INFO & operations))
-    {
-      mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
-      mModel->mLogicalModel->mCharacterDirections.Clear();
-    }
-
-    if(NO_OPERATION != (REORDER & operations))
-    {
-      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
-      for(Vector<BidirectionalLineInfoRun>::Iterator it    = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
-                                                     endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
-          it != endIt;
-          ++it)
-      {
-        BidirectionalLineInfoRun& bidiLineInfo = *it;
-
-        free(bidiLineInfo.visualToLogicalMap);
-        bidiLineInfo.visualToLogicalMap = NULL;
-      }
-      mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
-    }
-  }
-
-  if(NO_OPERATION != (SHAPE_TEXT & operations))
-  {
-    mModel->mVisualModel->mGlyphs.Clear();
-    mModel->mVisualModel->mGlyphsToCharacters.Clear();
-    mModel->mVisualModel->mCharactersToGlyph.Clear();
-    mModel->mVisualModel->mCharactersPerGlyph.Clear();
-    mModel->mVisualModel->mGlyphsPerCharacter.Clear();
-    mModel->mVisualModel->mGlyphPositions.Clear();
-  }
-
-  if(NO_OPERATION != (LAYOUT & operations))
-  {
-    mModel->mVisualModel->mLines.Clear();
-  }
-
-  if(NO_OPERATION != (COLOR & operations))
-  {
-    mModel->mVisualModel->mColorIndices.Clear();
-    mModel->mVisualModel->mBackgroundColorIndices.Clear();
-  }
-}
-
-void Controller::Impl::ClearCharacterModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
-{
-  const CharacterIndex endIndexPlusOne = endIndex + 1u;
-
-  if(NO_OPERATION != (GET_LINE_BREAKS & operations))
-  {
-    // Clear the line break info.
-    LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
-
-    mModel->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex,
-                                                lineBreakInfoBuffer + endIndexPlusOne);
-
-    // Clear the paragraphs.
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mLogicalModel->mParagraphInfo);
-  }
-
-  if(NO_OPERATION != (GET_SCRIPTS & operations))
-  {
-    // Clear the scripts.
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mLogicalModel->mScriptRuns);
-  }
-
-  if(NO_OPERATION != (VALIDATE_FONTS & operations))
-  {
-    // Clear the fonts.
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mLogicalModel->mFontRuns);
-  }
-
-  if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
-  {
-    if(NO_OPERATION != (BIDI_INFO & operations))
-    {
-      // Clear the bidirectional paragraph info.
-      ClearCharacterRuns(startIndex,
-                         endIndex,
-                         mModel->mLogicalModel->mBidirectionalParagraphInfo);
-
-      // Clear the character's directions.
-      CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
-
-      mModel->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex,
-                                                        characterDirectionsBuffer + endIndexPlusOne);
-    }
-
-    if(NO_OPERATION != (REORDER & operations))
-    {
-      uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
-      uint32_t endRemoveIndex   = startRemoveIndex;
-      ClearCharacterRuns(startIndex,
-                         endIndex,
-                         mModel->mLogicalModel->mBidirectionalLineInfo,
-                         startRemoveIndex,
-                         endRemoveIndex);
-
-      BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
-
-      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
-      for(Vector<BidirectionalLineInfoRun>::Iterator it    = bidirectionalLineInfoBuffer + startRemoveIndex,
-                                                     endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
-          it != endIt;
-          ++it)
-      {
-        BidirectionalLineInfoRun& bidiLineInfo = *it;
-
-        free(bidiLineInfo.visualToLogicalMap);
-        bidiLineInfo.visualToLogicalMap = NULL;
-      }
-
-      mModel->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex,
-                                                          bidirectionalLineInfoBuffer + endRemoveIndex);
-    }
-  }
-}
-
-void Controller::Impl::ClearGlyphModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
-{
-  const CharacterIndex endIndexPlusOne           = endIndex + 1u;
-  const Length         numberOfCharactersRemoved = endIndexPlusOne - startIndex;
-
-  // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
-  GlyphIndex* charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
-  Length*     glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
-
-  const GlyphIndex endGlyphIndexPlusOne  = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex);
-  const Length     numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
-
-  if(NO_OPERATION != (SHAPE_TEXT & operations))
-  {
-    // Update the character to glyph indices.
-    for(Vector<GlyphIndex>::Iterator it    = charactersToGlyphBuffer + endIndexPlusOne,
-                                     endIt = charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
-        it != endIt;
-        ++it)
-    {
-      CharacterIndex& index = *it;
-      index -= numberOfGlyphsRemoved;
-    }
-
-    // Clear the character to glyph conversion table.
-    mModel->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex,
-                                                   charactersToGlyphBuffer + endIndexPlusOne);
-
-    // Clear the glyphs per character table.
-    mModel->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex,
-                                                    glyphsPerCharacterBuffer + endIndexPlusOne);
-
-    // Clear the glyphs buffer.
-    GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
-    mModel->mVisualModel->mGlyphs.Erase(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                        glyphsBuffer + endGlyphIndexPlusOne);
-
-    CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
-
-    // Update the glyph to character indices.
-    for(Vector<CharacterIndex>::Iterator it    = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
-                                         endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
-        it != endIt;
-        ++it)
-    {
-      CharacterIndex& index = *it;
-      index -= numberOfCharactersRemoved;
-    }
-
-    // Clear the glyphs to characters buffer.
-    mModel->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                    glyphsToCharactersBuffer + endGlyphIndexPlusOne);
-
-    // Clear the characters per glyph buffer.
-    Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
-    mModel->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                    charactersPerGlyphBuffer + endGlyphIndexPlusOne);
-
-    // Clear the positions buffer.
-    Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
-    mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                positionsBuffer + endGlyphIndexPlusOne);
-  }
-
-  if(NO_OPERATION != (LAYOUT & operations))
-  {
-    // Clear the lines.
-    uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
-    uint32_t endRemoveIndex   = startRemoveIndex;
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mVisualModel->mLines,
-                       startRemoveIndex,
-                       endRemoveIndex);
-
-    // Will update the glyph runs.
-    startRemoveIndex = mModel->mVisualModel->mLines.Count();
-    endRemoveIndex   = startRemoveIndex;
-    ClearGlyphRuns(mTextUpdateInfo.mStartGlyphIndex,
-                   endGlyphIndexPlusOne - 1u,
-                   mModel->mVisualModel->mLines,
-                   startRemoveIndex,
-                   endRemoveIndex);
-
-    // Set the line index from where to insert the new laid-out lines.
-    mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
-
-    LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
-    mModel->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
-                                       linesBuffer + endRemoveIndex);
-  }
-
-  if(NO_OPERATION != (COLOR & operations))
-  {
-    if(0u != mModel->mVisualModel->mColorIndices.Count())
-    {
-      ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
-      mModel->mVisualModel->mColorIndices.Erase(colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                colorIndexBuffer + endGlyphIndexPlusOne);
-    }
-
-    if(0u != mModel->mVisualModel->mBackgroundColorIndices.Count())
-    {
-      ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
-      mModel->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                          backgroundColorIndexBuffer + endGlyphIndexPlusOne);
-    }
-  }
-}
-
 void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
 {
-  if(mTextUpdateInfo.mClearAll ||
-     ((0u == startIndex) &&
-      (mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
-  {
-    ClearFullModelData(operations);
-  }
-  else
-  {
-    // Clear the model data related with characters.
-    ClearCharacterModelData(startIndex, endIndex, operations);
-
-    // Clear the model data related with glyphs.
-    ClearGlyphModelData(startIndex, endIndex, operations);
-  }
-
-  // The estimated number of lines. Used to avoid reallocations when layouting.
-  mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
-
-  mModel->mVisualModel->ClearCaches();
+  ControllerImplDataClearer::ClearModelData(*this, startIndex, endIndex, operations);
 }
 
 bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel\n");
-
-  // Calculate the operations to be done.
-  const OperationsMask operations = static_cast<OperationsMask>(mOperationsPending & operationsRequired);
-
-  if(NO_OPERATION == operations)
-  {
-    // Nothing to do if no operations are pending and required.
-    return false;
-  }
-
-  Vector<Character>& srcCharacters = mModel->mLogicalModel->mText;
-  Vector<Character>  displayCharacters;
-  bool               useHiddenText = false;
-  if(mHiddenInput && mEventData != nullptr && !mEventData->mIsShowingPlaceholderText)
-  {
-    mHiddenInput->Substitute(srcCharacters, displayCharacters);
-    useHiddenText = true;
-  }
-
-  Vector<Character>& utf32Characters    = useHiddenText ? displayCharacters : srcCharacters;
-  const Length       numberOfCharacters = utf32Characters.Count();
-
-  // Index to the first character of the first paragraph to be updated.
-  CharacterIndex startIndex = 0u;
-  // Number of characters of the paragraphs to be removed.
-  Length paragraphCharacters = 0u;
-
-  CalculateTextUpdateIndices(paragraphCharacters);
-
-  // Check whether the indices for updating the text is valid
-  if(numberOfCharacters > 0u &&
-     (mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
-      mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters))
-  {
-    std::string currentText;
-    Utf32ToUtf8(mModel->mLogicalModel->mText.Begin(), numberOfCharacters, currentText);
-
-    DALI_LOG_ERROR("Controller::Impl::UpdateModel: mTextUpdateInfo has invalid indices\n");
-    DALI_LOG_ERROR("Number of characters: %d, current text is: %s\n", numberOfCharacters, currentText.c_str());
-
-    // Dump mTextUpdateInfo
-    DALI_LOG_ERROR("Dump mTextUpdateInfo:\n");
-    DALI_LOG_ERROR("     mTextUpdateInfo.mCharacterIndex = %u\n", mTextUpdateInfo.mCharacterIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToRemove = %u\n", mTextUpdateInfo.mNumberOfCharactersToRemove);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mNumberOfCharactersToAdd = %u\n", mTextUpdateInfo.mNumberOfCharactersToAdd);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mPreviousNumberOfCharacters = %u\n", mTextUpdateInfo.mPreviousNumberOfCharacters);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mParagraphCharacterIndex = %u\n", mTextUpdateInfo.mParagraphCharacterIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mRequestedNumberOfCharacters = %u\n", mTextUpdateInfo.mRequestedNumberOfCharacters);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mStartGlyphIndex = %u\n", mTextUpdateInfo.mStartGlyphIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mStartLineIndex = %u\n", mTextUpdateInfo.mStartLineIndex);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mEstimatedNumberOfLines = %u\n", mTextUpdateInfo.mEstimatedNumberOfLines);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mClearAll = %d\n", mTextUpdateInfo.mClearAll);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mFullRelayoutNeeded = %d\n", mTextUpdateInfo.mFullRelayoutNeeded);
-    DALI_LOG_ERROR("     mTextUpdateInfo.mIsLastCharacterNewParagraph = %d\n", mTextUpdateInfo.mIsLastCharacterNewParagraph);
-
-    return false;
-  }
-
-  startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
-
-  if(mTextUpdateInfo.mClearAll ||
-     (0u != paragraphCharacters))
-  {
-    ClearModelData(startIndex, startIndex + ((paragraphCharacters > 0u) ? paragraphCharacters - 1u : 0u), operations);
-  }
-
-  mTextUpdateInfo.mClearAll = false;
-
-  // Whether the model is updated.
-  bool updated = false;
-
-  Vector<LineBreakInfo>& lineBreakInfo               = mModel->mLogicalModel->mLineBreakInfo;
-  const Length           requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
-
-  if(NO_OPERATION != (GET_LINE_BREAKS & operations))
-  {
-    // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
-    // calculate the bidirectional info for each 'paragraph'.
-    // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines
-    // is not shaped together).
-    lineBreakInfo.Resize(numberOfCharacters, TextAbstraction::LINE_NO_BREAK);
-
-    SetLineBreakInfo(utf32Characters,
-                     startIndex,
-                     requestedNumberOfCharacters,
-                     lineBreakInfo);
-
-    if(mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
-       mModel->mLineWrapMode == ((Text::LineWrap::Mode)DevelText::LineWrap::MIXED))
-    {
-      CharacterIndex end                 = startIndex + requestedNumberOfCharacters;
-      LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
-
-      for(CharacterIndex index = startIndex; index < end; index++)
-      {
-        CharacterIndex wordEnd = index;
-        while((*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_ALLOW_BREAK) && (*(lineBreakInfoBuffer + wordEnd) != TextAbstraction::LINE_MUST_BREAK))
-        {
-          wordEnd++;
-        }
-
-        if((wordEnd + 1) == end) // add last char
-        {
-          wordEnd++;
-        }
-
-        Vector<bool> hyphens = GetWordHyphens(utf32Characters.Begin() + index, wordEnd - index, nullptr);
-
-        for(CharacterIndex i = 0; i < (wordEnd - index); i++)
-        {
-          if(hyphens[i])
-          {
-            *(lineBreakInfoBuffer + index + i) = TextAbstraction::LINE_HYPHENATION_BREAK;
-          }
-        }
-
-        index = wordEnd;
-      }
-    }
-
-    // Create the paragraph info.
-    mModel->mLogicalModel->CreateParagraphInfo(startIndex,
-                                               requestedNumberOfCharacters);
-    updated = true;
-  }
-
-  const bool getScripts    = NO_OPERATION != (GET_SCRIPTS & operations);
-  const bool validateFonts = NO_OPERATION != (VALIDATE_FONTS & operations);
-
-  Vector<ScriptRun>& scripts    = mModel->mLogicalModel->mScriptRuns;
-  Vector<FontRun>&   validFonts = mModel->mLogicalModel->mFontRuns;
-
-  if(getScripts || validateFonts)
-  {
-    // Validates the fonts assigned by the application or assigns default ones.
-    // It makes sure all the characters are going to be rendered by the correct font.
-    MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get();
-
-    if(getScripts)
-    {
-      // Retrieves the scripts used in the text.
-      multilanguageSupport.SetScripts(utf32Characters,
-                                      startIndex,
-                                      requestedNumberOfCharacters,
-                                      scripts);
-    }
-
-    if(validateFonts)
-    {
-      // Validate the fonts set through the mark-up string.
-      Vector<FontDescriptionRun>& fontDescriptionRuns = mModel->mLogicalModel->mFontDescriptionRuns;
-
-      // Get the default font's description.
-      TextAbstraction::FontDescription defaultFontDescription;
-      TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE * mFontSizeScale;
-
-      //Get the number of points per one unit of point-size
-      uint32_t numberOfPointsPerOneUnitOfPointSize = mFontClient.GetNumberOfPointsPerOneUnitOfPointSize();
-
-      if(IsShowingPlaceholderText() && mEventData && (nullptr != 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 * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
-        }
-      }
-      else if(nullptr != mFontDefaults)
-      {
-        // Set the normal font and the placeholder font.
-        defaultFontDescription = mFontDefaults->mFontDescription;
-
-        if(mTextFitEnabled)
-        {
-          defaultPointSize = mFontDefaults->mFitPointSize * numberOfPointsPerOneUnitOfPointSize;
-        }
-        else
-        {
-          defaultPointSize = mFontDefaults->mDefaultPointSize * mFontSizeScale * numberOfPointsPerOneUnitOfPointSize;
-        }
-      }
-
-      // Validates the fonts. If there is a character with no assigned font it sets a default one.
-      // After this call, fonts are validated.
-      multilanguageSupport.ValidateFonts(utf32Characters,
-                                         scripts,
-                                         fontDescriptionRuns,
-                                         defaultFontDescription,
-                                         defaultPointSize,
-                                         startIndex,
-                                         requestedNumberOfCharacters,
-                                         validFonts);
-    }
-    updated = true;
-  }
-
-  Vector<Character> mirroredUtf32Characters;
-  bool              textMirrored       = false;
-  const Length      numberOfParagraphs = mModel->mLogicalModel->mParagraphInfo.Count();
-  if(NO_OPERATION != (BIDI_INFO & operations))
-  {
-    Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mModel->mLogicalModel->mBidirectionalParagraphInfo;
-    bidirectionalInfo.Reserve(numberOfParagraphs);
-
-    // Calculates the bidirectional info for the whole paragraph if it contains right to left scripts.
-    SetBidirectionalInfo(utf32Characters,
-                         scripts,
-                         lineBreakInfo,
-                         startIndex,
-                         requestedNumberOfCharacters,
-                         bidirectionalInfo,
-                         mModel->mMatchSystemLanguageDirection,
-                         mLayoutDirection);
-
-    if(0u != bidirectionalInfo.Count())
-    {
-      // Only set the character directions if there is right to left characters.
-      Vector<CharacterDirection>& directions = mModel->mLogicalModel->mCharacterDirections;
-      GetCharactersDirection(bidirectionalInfo,
-                             numberOfCharacters,
-                             startIndex,
-                             requestedNumberOfCharacters,
-                             directions);
-
-      // This paragraph has right to left text. Some characters may need to be mirrored.
-      // TODO: consider if the mirrored string can be stored as well.
-
-      textMirrored = GetMirroredText(utf32Characters,
-                                     directions,
-                                     bidirectionalInfo,
-                                     startIndex,
-                                     requestedNumberOfCharacters,
-                                     mirroredUtf32Characters);
-    }
-    else
-    {
-      // There is no right to left characters. Clear the directions vector.
-      mModel->mLogicalModel->mCharacterDirections.Clear();
-    }
-    updated = true;
-  }
-
-  Vector<GlyphInfo>&      glyphs                = mModel->mVisualModel->mGlyphs;
-  Vector<CharacterIndex>& glyphsToCharactersMap = mModel->mVisualModel->mGlyphsToCharacters;
-  Vector<Length>&         charactersPerGlyph    = mModel->mVisualModel->mCharactersPerGlyph;
-  Vector<GlyphIndex>      newParagraphGlyphs;
-  newParagraphGlyphs.Reserve(numberOfParagraphs);
-
-  const Length currentNumberOfGlyphs = glyphs.Count();
-  if(NO_OPERATION != (SHAPE_TEXT & operations))
-  {
-    const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
-    // Shapes the text.
-    ShapeText(textToShape,
-              lineBreakInfo,
-              scripts,
-              validFonts,
-              startIndex,
-              mTextUpdateInfo.mStartGlyphIndex,
-              requestedNumberOfCharacters,
-              glyphs,
-              glyphsToCharactersMap,
-              charactersPerGlyph,
-              newParagraphGlyphs);
-
-    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-    mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
-    mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
-
-   updated = true;
-  }
-
-  const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
-
-  if(NO_OPERATION != (GET_GLYPH_METRICS & operations))
-  {
-    GlyphInfo* glyphsBuffer = glyphs.Begin();
-    mMetrics->GetGlyphMetrics(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs);
-
-    // Update the width and advance of all new paragraph characters.
-    for(Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it)
-    {
-      const GlyphIndex index = *it;
-      GlyphInfo&       glyph = *(glyphsBuffer + index);
-
-      glyph.xBearing = 0.f;
-      glyph.width    = 0.f;
-      glyph.advance  = 0.f;
-    }
-    updated = true;
-  }
-
-  if((nullptr != mEventData) &&
-     mEventData->mPreEditFlag &&
-     (0u != mModel->mVisualModel->mCharactersToGlyph.Count()))
-  {
-    Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
-    mEventData->mInputMethodContext.GetPreeditStyle(attrs);
-    Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
-
-    // Check the type of preedit and run it.
-    for(Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++)
-    {
-      Dali::InputMethodContext::PreeditAttributeData attrData = *it;
-      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex);
-      type = attrData.preeditType;
-
-      // Check the number of commit characters for the start position.
-      unsigned int numberOfCommit  = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
-      Length       numberOfIndices = attrData.endIndex - attrData.startIndex;
-
-      switch(type)
-      {
-        case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
-        {
-          // Add the underline for the pre-edit text.
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::REVERSE:
-        {
-          Vector4  textColor = mModel->mVisualModel->GetTextColor();
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = textColor;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          Vector4          backgroundColor = mModel->mVisualModel->GetBackgroundColor();
-          Vector<ColorRun> colorRuns;
-          colorRuns.Resize(1u);
-          ColorRun& colorRun                       = *(colorRuns.Begin());
-          colorRun.color                           = backgroundColor;
-          colorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          colorRun.characterRun.numberOfCharacters = numberOfIndices;
-
-          mModel->mLogicalModel->mColorRuns.PushBack(colorRun);
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
-        {
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = LIGHT_BLUE;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
-        {
-          // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB4;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
-        {
-          // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB5;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
-        {
-          // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB6;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
-        {
-          // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
-          ColorRun backgroundColorRun;
-          backgroundColorRun.characterRun.characterIndex     = attrData.startIndex + numberOfCommit;
-          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
-          backgroundColorRun.color                           = BACKGROUND_SUB7;
-          mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
-
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
-
-          //Mark-up processor case
-          if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-          {
-            CopyUnderlinedFromLogicalToVisualModels(false);
-          }
-          break;
-        }
-        case Dali::InputMethodContext::PreeditStyle::NONE:
-        default:
-        {
-          break;
-        }
-      }
-    }
-    attrs.Clear();
-    updated = true;
-  }
-
-  if(NO_OPERATION != (COLOR & operations))
-  {
-    // Set the color runs in glyphs.
-    SetColorSegmentationInfo(mModel->mLogicalModel->mColorRuns,
-                             mModel->mVisualModel->mCharactersToGlyph,
-                             mModel->mVisualModel->mGlyphsPerCharacter,
-                             startIndex,
-                             mTextUpdateInfo.mStartGlyphIndex,
-                             requestedNumberOfCharacters,
-                             mModel->mVisualModel->mColors,
-                             mModel->mVisualModel->mColorIndices);
-
-    // Set the background color runs in glyphs.
-    SetColorSegmentationInfo(mModel->mLogicalModel->mBackgroundColorRuns,
-                             mModel->mVisualModel->mCharactersToGlyph,
-                             mModel->mVisualModel->mGlyphsPerCharacter,
-                             startIndex,
-                             mTextUpdateInfo.mStartGlyphIndex,
-                             requestedNumberOfCharacters,
-                             mModel->mVisualModel->mBackgroundColors,
-                             mModel->mVisualModel->mBackgroundColorIndices);
-
-    updated = true;
-  }
-
-  if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
-      ! ((nullptr != mEventData) &&
-         mEventData->mPreEditFlag &&
-         (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
-  {
-    //Mark-up processor case
-    if(mModel->mVisualModel->IsMarkupProcessorEnabled())
-    {
-      CopyUnderlinedFromLogicalToVisualModels(true);
-    }
-
-    updated = true;
-  }
-
-
-  // The estimated number of lines. Used to avoid reallocations when layouting.
-  mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
-
-  // Set the previous number of characters for the next time the text is updated.
-  mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
-
-  return updated;
+  return ControllerImplModelUpdater::Update(*this, operationsRequired);
 }
 
 void Controller::Impl::RetrieveDefaultInputStyle(InputStyle& inputStyle)
 {
-  // Sets the default text's color.
-  inputStyle.textColor      = mTextColor;
-  inputStyle.isDefaultColor = true;
-
-  inputStyle.familyName.clear();
-  inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
-  inputStyle.width  = TextAbstraction::FontWidth::NORMAL;
-  inputStyle.slant  = TextAbstraction::FontSlant::NORMAL;
-  inputStyle.size   = 0.f;
-
-  inputStyle.lineSpacing = 0.f;
-
-  inputStyle.underlineProperties.clear();
-  inputStyle.shadowProperties.clear();
-  inputStyle.embossProperties.clear();
-  inputStyle.outlineProperties.clear();
-
-  inputStyle.isFamilyDefined = false;
-  inputStyle.isWeightDefined = false;
-  inputStyle.isWidthDefined  = false;
-  inputStyle.isSlantDefined  = false;
-  inputStyle.isSizeDefined   = false;
-
-  inputStyle.isLineSpacingDefined = false;
-
-  inputStyle.isUnderlineDefined = false;
-  inputStyle.isShadowDefined    = false;
-  inputStyle.isEmbossDefined    = false;
-  inputStyle.isOutlineDefined   = false;
-
-  // Sets the default font's family name, weight, width, slant and size.
-  if(mFontDefaults)
-  {
-    if(mFontDefaults->familyDefined)
-    {
-      inputStyle.familyName      = mFontDefaults->mFontDescription.family;
-      inputStyle.isFamilyDefined = true;
-    }
-
-    if(mFontDefaults->weightDefined)
-    {
-      inputStyle.weight          = mFontDefaults->mFontDescription.weight;
-      inputStyle.isWeightDefined = true;
-    }
-
-    if(mFontDefaults->widthDefined)
-    {
-      inputStyle.width          = mFontDefaults->mFontDescription.width;
-      inputStyle.isWidthDefined = true;
-    }
-
-    if(mFontDefaults->slantDefined)
-    {
-      inputStyle.slant          = mFontDefaults->mFontDescription.slant;
-      inputStyle.isSlantDefined = true;
-    }
-
-    if(mFontDefaults->sizeDefined)
-    {
-      inputStyle.size          = mFontDefaults->mDefaultPointSize;
-      inputStyle.isSizeDefined = true;
-    }
-  }
+  SetDefaultInputStyle(inputStyle, mFontDefaults, mTextColor);
 }
 
 float Controller::Impl::GetDefaultFontLineHeight()
@@ -1165,6 +640,32 @@ float Controller::Impl::GetDefaultFontLineHeight()
   return (fontMetrics.ascender - fontMetrics.descender);
 }
 
+bool Controller::Impl::SetDefaultLineSpacing(float lineSpacing)
+{
+  if(std::fabs(lineSpacing - mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
+  {
+    mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
+    mRecalculateNaturalSize = true;
+
+    RelayoutForNewLineSize();
+    return true;
+  }
+  return false;
+}
+
+bool Controller::Impl::SetDefaultLineSize(float lineSize)
+{
+  if(std::fabs(lineSize - mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
+  {
+    mLayoutEngine.SetDefaultLineSize(lineSize);
+    mRecalculateNaturalSize = true;
+
+    RelayoutForNewLineSize();
+    return true;
+  }
+  return false;
+}
+
 void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd)
 {
   if(nullptr == mEventData)
@@ -1175,7 +676,9 @@ void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint3
 
   if(mEventData->mSelectionEnabled && (pStart || pEnd))
   {
-    uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+    uint32_t length   = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+    uint32_t oldStart = mEventData->mLeftSelectionPosition;
+    uint32_t oldEnd   = mEventData->mRightSelectionPosition;
 
     if(pStart)
     {
@@ -1199,6 +702,11 @@ void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint3
       mEventData->mUpdateLeftSelectionPosition  = true;
       mEventData->mUpdateRightSelectionPosition = true;
     }
+
+    if(mSelectableControlInterface != nullptr)
+    {
+      mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+    }
   }
 }
 
@@ -1211,7 +719,7 @@ CharacterIndex Controller::Impl::GetPrimaryCursorPosition() const
   return mEventData->mPrimaryCursorPosition;
 }
 
-bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index)
+bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index, bool focused)
 {
   if(nullptr == mEventData)
   {
@@ -1219,18 +727,38 @@ bool Controller::Impl::SetPrimaryCursorPosition(CharacterIndex index)
     return false;
   }
 
-  if(mEventData->mPrimaryCursorPosition == index)
+  if(mEventData->mPrimaryCursorPosition == index && mEventData->mState != EventData::SELECTING)
   {
     // Nothing for same cursor position.
     return false;
   }
 
   uint32_t length                    = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
+  uint32_t oldCursorPos              = mEventData->mPrimaryCursorPosition;
   mEventData->mPrimaryCursorPosition = std::min(index, length);
-  ChangeState(EventData::EDITING);
-  mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
-  mEventData->mUpdateCursorPosition                                        = true;
-  ScrollTextToMatchCursor();
+  // If there is no focus, only the value is updated.
+  if(focused)
+  {
+    bool     wasInSelectingState = mEventData->mState == EventData::SELECTING;
+    uint32_t oldStart            = mEventData->mLeftSelectionPosition;
+    uint32_t oldEnd              = mEventData->mRightSelectionPosition;
+    ChangeState(EventData::EDITING);
+    mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+    mEventData->mUpdateCursorPosition                                        = true;
+
+    if(mSelectableControlInterface != nullptr && wasInSelectingState)
+    {
+      mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
+    }
+
+    ScrollTextToMatchCursor();
+  }
+
+  if(nullptr != mEditableControlInterface)
+  {
+    mEditableControlInterface->CursorPositionChanged(oldCursorPos, mEventData->mPrimaryCursorPosition);
+  }
+
   return true;
 }
 
@@ -1252,11 +780,31 @@ bool Controller::Impl::IsEditable() const
   return mEventData && mEventData->mEditingEnabled;
 }
 
-void Controller::Impl::SetEditable(bool editable)
+void Controller::Impl::SetEditable(bool editable)
+{
+  if(mEventData)
+  {
+    mEventData->mEditingEnabled = editable;
+
+    if(mEventData->mDecorator)
+    {
+      mEventData->mDecorator->SetEditable(editable);
+    }
+  }
+}
+
+void Controller::Impl::UpdateAfterFontChange(const std::string& newDefaultFont)
 {
-  if(mEventData)
+  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
+
+  if(!mFontDefaults->familyDefined) // If user defined font then should not update when system font changes
   {
-    mEventData->mEditingEnabled = editable;
+    DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str());
+    mFontDefaults->mFontDescription.family = newDefaultFont;
+
+    ClearFontData();
+
+    RequestRelayout();
   }
 }
 
@@ -1339,9 +887,17 @@ void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteA
 
 void Controller::Impl::SetSelection(int start, int end)
 {
+  uint32_t oldStart = mEventData->mLeftSelectionPosition;
+  uint32_t oldEnd   = mEventData->mRightSelectionPosition;
+
   mEventData->mLeftSelectionPosition  = start;
   mEventData->mRightSelectionPosition = end;
   mEventData->mUpdateCursorPosition   = true;
+
+  if(mSelectableControlInterface != nullptr)
+  {
+    mSelectableControlInterface->SelectionChanged(oldStart, oldEnd, start, end);
+  }
 }
 
 std::pair<int, int> Controller::Impl::GetSelectionIndexes() const
@@ -1469,222 +1025,7 @@ void Controller::Impl::SetPopupButtons()
 
 void Controller::Impl::ChangeState(EventData::State newState)
 {
-  if(nullptr == mEventData)
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState);
-
-  if(mEventData->mState != newState)
-  {
-    mEventData->mPreviousState = mEventData->mState;
-    mEventData->mState         = newState;
-
-    switch(mEventData->mState)
-    {
-      case EventData::INACTIVE:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        mEventData->mDecorator->SetPopupActive(false);
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::INTERRUPTED:
-      {
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        mEventData->mDecorator->SetPopupActive(false);
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::SELECTING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHighlightActive(true);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          SetPopupButtons();
-          mEventData->mDecorator->SetPopupActive(true);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        // Grab handle is not shown until a tap is received whilst EDITING
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING_WITH_POPUP:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        if(mEventData->mSelectionEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHighlightActive(false);
-        }
-        else if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          SetPopupButtons();
-          mEventData->mDecorator->SetPopupActive(true);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING_WITH_GRAB_HANDLE:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        // Grab handle is not shown until a tap is received whilst EDITING
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::SELECTION_HANDLE_PANNING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHighlightActive(true);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::GRAB_HANDLE_PANNING:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING_WITH_PASTE_POPUP:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          SetPopupButtons();
-          mEventData->mDecorator->SetPopupActive(true);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::TEXT_PANNING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        if(mEventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
-           mEventData->mDecorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHighlightActive(true);
-        }
-
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-    }
-  }
+  ChangeTextControllerState(*this, newState);
 }
 
 void Controller::Impl::GetCursorPosition(CharacterIndex logical,
@@ -1703,7 +1044,7 @@ void Controller::Impl::GetCursorPosition(CharacterIndex logical,
     cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
 
     bool isRTL = false;
-    if(mModel->mMatchSystemLanguageDirection)
+    if(mModel->mMatchLayoutDirection != DevelText::MatchLayoutDirection::CONTENTS)
     {
       isRTL = mLayoutDirection == LayoutDirection::RIGHT_TO_LEFT;
     }
@@ -2018,8 +1359,7 @@ void Controller::Impl::RequestRelayout()
 
 Actor Controller::Impl::CreateBackgroundActor()
 {
-  // NOTE: Currently we only support background color for one line left-to-right text,
-  //       so the following calculation is based on one line left-to-right text only!
+  // NOTE: Currently we only support background color for left-to-right text.
 
   Actor actor;
 
@@ -2053,15 +1393,19 @@ Actor Controller::Impl::CreateBackgroundActor()
 
     const Vector2 textSize = mView.GetLayoutSize();
 
-    const float offsetX = textSize.width * 0.5f;
+    const float offsetX = alignmentOffset + textSize.width * 0.5f;
     const float offsetY = textSize.height * 0.5f;
 
     const Vector4* const    backgroundColorsBuffer       = mView.GetBackgroundColors();
     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
     const Vector4&          defaultBackgroundColor       = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
 
-    Vector4  quad;
-    uint32_t numberOfQuads = 0u;
+    Vector4   quad;
+    uint32_t  numberOfQuads = 0u;
+    Length    yLineOffset   = 0;
+    Length    prevLineIndex = 0;
+    LineIndex lineIndex;
+    Length    numberOfLines;
 
     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
     {
@@ -2069,8 +1413,18 @@ Actor Controller::Impl::CreateBackgroundActor()
 
       // Get the background color of the character.
       // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
-      const ColorIndex backgroundColorIndex = (nullptr == backgroundColorsBuffer) ? 0u : *(backgroundColorIndicesBuffer + i);
-      const Vector4&   backgroundColor      = (0u == backgroundColorIndex) ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
+      const bool       isMarkupBackground       = mView.IsMarkupBackgroundColorSet();
+      const ColorIndex backgroundColorIndex     = isMarkupBackground ? *(backgroundColorIndicesBuffer + i) : 0u;
+      const bool       isDefaultBackgroundColor = (0u == backgroundColorIndex);
+      const Vector4&   backgroundColor          = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
+
+      mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
+      Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
+
+      if(lineIndex != prevLineIndex)
+      {
+        yLineOffset += lineHeight;
+      }
 
       // Only create quads for glyphs with a background color
       if(backgroundColor != Color::TRANSPARENT)
@@ -2080,30 +1434,30 @@ Actor Controller::Impl::CreateBackgroundActor()
         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
         {
           quad.x = position.x;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
-          quad.w = textSize.height;
+          quad.w = lineHeight;
         }
-        else if(i == 0u) // The first glyph in the whole text
+        else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
         {
           quad.x = position.x;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x - glyph.xBearing + glyph.advance;
-          quad.w = textSize.height;
+          quad.w = quad.y + lineHeight;
         }
         else if(i == glyphSize - 1u) // The last glyph in the whole text
         {
           quad.x = position.x - glyph.xBearing;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
-          quad.w = textSize.height;
+          quad.w = quad.y + lineHeight;
         }
         else // The glyph in the middle of the text
         {
           quad.x = position.x - glyph.xBearing;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x + glyph.advance;
-          quad.w = textSize.height;
+          quad.w = quad.y + lineHeight;
         }
 
         BackgroundVertex vertex;
@@ -2142,6 +1496,11 @@ Actor Controller::Impl::CreateBackgroundActor()
 
         numberOfQuads++;
       }
+
+      if(lineIndex != prevLineIndex)
+      {
+        prevLineIndex = lineIndex;
+      }
     }
 
     // Only create the background actor if there are glyphs with background color
@@ -2180,34 +1539,303 @@ Actor Controller::Impl::CreateBackgroundActor()
   return actor;
 }
 
+void Controller::Impl::RelayoutForNewLineSize()
+{
+  // relayout all characters
+  mTextUpdateInfo.mCharacterIndex             = 0;
+  mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+  mTextUpdateInfo.mNumberOfCharactersToAdd    = mModel->mLogicalModel->mText.Count();
+  mOperationsPending                          = static_cast<OperationsMask>(mOperationsPending | LAYOUT);
+
+  //remove selection
+  if(mEventData && mEventData->mState == EventData::SELECTING)
+  {
+    ChangeState(EventData::EDITING);
+  }
+
+  RequestRelayout();
+}
+
+bool Controller::Impl::IsInputStyleChangedSignalsQueueEmpty()
+{
+  return (NULL == mEventData) || (0u == mEventData->mInputStyleChangedQueue.Count());
+}
+
+void Controller::Impl::ProcessInputStyleChangedSignals()
+{
+  if(mEventData)
+  {
+    if(mEditableControlInterface)
+    {
+      // Emit the input style changed signal for each mask
+      std::for_each(mEventData->mInputStyleChangedQueue.begin(),
+                    mEventData->mInputStyleChangedQueue.end(),
+                    [&](const auto mask) { mEditableControlInterface->InputStyleChanged(mask); } );
+    }
+
+    mEventData->mInputStyleChangedQueue.Clear();
+  }
+}
+
+void Controller::Impl::ScrollBy(Vector2 scroll)
+{
+  if(mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
+  {
+    const Vector2& layoutSize    = mModel->mVisualModel->GetLayoutSize();
+    const Vector2  currentScroll = mModel->mScrollPosition;
+
+    scroll.x = -scroll.x;
+    scroll.y = -scroll.y;
+
+    if(fabs(scroll.x) > Math::MACHINE_EPSILON_0)
+    {
+      mModel->mScrollPosition.x += scroll.x;
+      ClampHorizontalScroll(layoutSize);
+    }
+
+    if(fabs(scroll.y) > Math::MACHINE_EPSILON_0)
+    {
+      mModel->mScrollPosition.y += scroll.y;
+      ClampVerticalScroll(layoutSize);
+    }
+
+    if(mModel->mScrollPosition != currentScroll)
+    {
+      mEventData->mDecorator->UpdatePositions(mModel->mScrollPosition - currentScroll);
+      RequestRelayout();
+    }
+  }
+}
+
+float Controller::Impl::GetHorizontalScrollPosition()
+{
+  // Scroll values are negative internally so we convert them to positive numbers
+  return mEventData ? -mModel->mScrollPosition.x : 0.0f;
+}
+
+float Controller::Impl::GetVerticalScrollPosition()
+{
+  // Scroll values are negative internally so we convert them to positive numbers
+  return mEventData ? -mModel->mScrollPosition.y : 0.0f;
+}
+
 void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
 {
-    //Underlined character runs for markup-processor
-    const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
-    const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
-    const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
+  //Underlined character runs for markup-processor
+  const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
+  const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
+  const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
+
+  if(shouldClearPreUnderlineRuns)
+  {
+    mModel->mVisualModel->mUnderlineRuns.Clear();
+  }
 
-    if(shouldClearPreUnderlineRuns)
+  for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+  {
+    CharacterIndex characterIndex     = it->characterRun.characterIndex;
+    Length         numberOfCharacters = it->characterRun.numberOfCharacters;
+    for(Length index = 0u; index < numberOfCharacters; index++)
     {
-        mModel->mVisualModel->mUnderlineRuns.Clear();
+      GlyphRun underlineGlyphRun;
+      underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
+      underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+      mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
     }
+  }
+}
+
+void Controller::Impl::SetAutoScrollEnabled(bool enable)
+{
+  if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
+  {
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+                                                     LAYOUT |
+                                                     ALIGN |
+                                                     UPDATE_LAYOUT_SIZE |
+                                                     REORDER);
 
-    for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+    if(enable)
     {
-        CharacterIndex characterIndex = it->characterRun.characterIndex;
-        Length numberOfCharacters = it->characterRun.numberOfCharacters;
-        for(Length index=0u; index<numberOfCharacters; index++)
-        {
-          GlyphRun underlineGlyphRun;
-          underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
-          underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
-        }
+      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
+      mOperationsPending = static_cast<OperationsMask>(mOperationsPending | UPDATE_DIRECTION);
+    }
+    else
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
+    }
+
+    mIsAutoScrollEnabled = enable;
+    RequestRelayout();
+  }
+  else
+  {
+    DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
+    mIsAutoScrollEnabled = false;
+  }
+}
+
+void Controller::Impl::SetEnableCursorBlink(bool enable)
+{
+  DALI_ASSERT_DEBUG(NULL != mEventData && "TextInput disabled");
+
+  if(mEventData)
+  {
+    mEventData->mCursorBlinkEnabled = enable;
+
+    if(!enable && mEventData->mDecorator)
+    {
+      mEventData->mDecorator->StopCursorBlink();
+    }
+  }
+}
+
+void Controller::Impl::SetMultiLineEnabled(bool enable)
+{
+  const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
+
+  if(layout != mLayoutEngine.GetLayout())
+  {
+    // Set the layout type.
+    mLayoutEngine.SetLayout(layout);
+
+    // Set the flags to redo the layout operations
+    const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
+                                                                        UPDATE_LAYOUT_SIZE |
+                                                                        ALIGN |
+                                                                        REORDER);
+
+    mTextUpdateInfo.mFullRelayoutNeeded = true;
+    mOperationsPending                  = static_cast<OperationsMask>(mOperationsPending | layoutOperations);
+
+    // Need to recalculate natural size
+    mRecalculateNaturalSize = true;
+
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
+{
+  if(alignment != mModel->mHorizontalAlignment)
+  {
+    // Set the alignment.
+    mModel->mHorizontalAlignment = alignment;
+
+    // Set the flag to redo the alignment operation.
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
+
+    if(mEventData)
+    {
+      mEventData->mUpdateAlignment = true;
+
+      // Update the cursor if it's in editing mode
+      if(EventData::IsEditingState(mEventData->mState))
+      {
+        ChangeState(EventData::EDITING);
+        mEventData->mUpdateCursorPosition = true;
+      }
+    }
+
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetVerticalAlignment(VerticalAlignment::Type alignment)
+{
+  if(alignment != mModel->mVerticalAlignment)
+  {
+    // Set the alignment.
+    mModel->mVerticalAlignment = alignment;
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
+{
+  if(lineWrapMode != mModel->mLineWrapMode)
+  {
+    // Update Text layout for applying wrap mode
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+                                                     ALIGN |
+                                                     LAYOUT |
+                                                     UPDATE_LAYOUT_SIZE |
+                                                     REORDER);
+
+    if((mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+       (mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
+    {
+      mOperationsPending = static_cast<OperationsMask>(mOperationsPending | GET_LINE_BREAKS);
     }
+
+    // Set the text wrap mode.
+    mModel->mLineWrapMode = lineWrapMode;
+
+    mTextUpdateInfo.mCharacterIndex             = 0u;
+    mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+    mTextUpdateInfo.mNumberOfCharactersToAdd    = mModel->mLogicalModel->mText.Count();
+
+    // Request relayout
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetDefaultColor(const Vector4& color)
+{
+  mTextColor = color;
+
+  if(!IsShowingPlaceholderText())
+  {
+    mModel->mVisualModel->SetTextColor(color);
+    mModel->mLogicalModel->mColorRuns.Clear();
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending | COLOR);
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::ClearFontData()
+{
+  if(mFontDefaults)
+  {
+    mFontDefaults->mFontId = 0u; // Remove old font ID
+  }
+
+  // Set flags to update the model.
+  mTextUpdateInfo.mCharacterIndex             = 0u;
+  mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+  mTextUpdateInfo.mNumberOfCharactersToAdd    = mModel->mLogicalModel->mText.Count();
+
+  mTextUpdateInfo.mClearAll           = true;
+  mTextUpdateInfo.mFullRelayoutNeeded = true;
+  mRecalculateNaturalSize             = true;
+
+  mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+                                                   VALIDATE_FONTS |
+                                                   SHAPE_TEXT |
+                                                   BIDI_INFO |
+                                                   GET_GLYPH_METRICS |
+                                                   LAYOUT |
+                                                   UPDATE_LAYOUT_SIZE |
+                                                   REORDER |
+                                                   ALIGN);
 }
 
-} // namespace Text
+void Controller::Impl::ClearStyleData()
+{
+  mModel->mLogicalModel->mColorRuns.Clear();
+  mModel->mLogicalModel->ClearFontDescriptionRuns();
+}
 
-} // namespace Toolkit
 
-} // namespace Dali
+void Controller::Impl::ResetScrollPosition()
+{
+  if(mEventData)
+  {
+    // Reset the scroll position.
+    mModel->mScrollPosition                = Vector2::ZERO;
+    mEventData->mScrollAfterUpdatePosition = true;
+  }
+}
+
+} // namespace Dali::Toolkit::Text