GetLineCount() after GetTextDirection() returns wrong value.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
index 6580790..139fbfd 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <limits>
+#include <cmath>
 #include <memory.h>
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/integration-api/debug.h>
@@ -61,13 +62,25 @@ const char * const PLACEHOLDER_FONT_STYLE = "fontStyle";
 const char * const PLACEHOLDER_POINT_SIZE = "pointSize";
 const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
 const char * const PLACEHOLDER_ELLIPSIS = "ellipsis";
+const unsigned int MAX_TEXT_LENGTH = 1024u * 32u;
 
 float ConvertToEven( float value )
 {
   int intValue(static_cast<int>( value ));
-  return static_cast<float>(intValue % 2 == 0) ? intValue : (intValue + 1);
+  return static_cast<float>( intValue + ( intValue & 1 ) );
 }
 
+int ConvertPixelToPint( float pixel )
+{
+  unsigned int horizontalDpi = 0u;
+  unsigned int verticalDpi = 0u;
+  Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+  fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+  return ( pixel * 72.f ) / static_cast< float >( horizontalDpi );
+}
+
+
 } // namespace
 
 namespace Dali
@@ -138,7 +151,7 @@ ControllerPtr Controller::New( ControlInterface* controlInterface,
 
 // public : Configure the text controller.
 
-void Controller::EnableTextInput( DecoratorPtr decorator )
+void Controller::EnableTextInput( DecoratorPtr decorator, InputMethodContext& inputMethodContext )
 {
   if( !decorator )
   {
@@ -151,7 +164,7 @@ void Controller::EnableTextInput( DecoratorPtr decorator )
 
   if( NULL == mImpl->mEventData )
   {
-    mImpl->mEventData = new EventData( decorator );
+    mImpl->mEventData = new EventData( decorator, inputMethodContext );
   }
 }
 
@@ -168,7 +181,14 @@ void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
 
 void Controller::SetMarkupProcessorEnabled( bool enable )
 {
-  mImpl->mMarkupProcessorEnabled = enable;
+  if( enable != mImpl->mMarkupProcessorEnabled )
+  {
+    //If Text was already set, call the SetText again for enabling or disabling markup
+    mImpl->mMarkupProcessorEnabled = enable;
+    std::string text;
+    GetText( text );
+    SetText( text );
+  }
 }
 
 bool Controller::IsMarkupProcessorEnabled() const
@@ -302,7 +322,7 @@ bool Controller::IsSmoothHandlePanEnabled() const
 
 void Controller::SetMaximumNumberOfCharacters( Length maxCharacters )
 {
-  mImpl->mMaximumNumberOfCharacters = maxCharacters;
+  mImpl->mMaximumNumberOfCharacters = std::min( maxCharacters, MAX_TEXT_LENGTH );
 }
 
 int Controller::GetMaximumNumberOfCharacters()
@@ -354,6 +374,9 @@ void Controller::SetMultiLineEnabled( bool enable )
     mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | layoutOperations );
 
+    // Need to recalculate natural size
+    mImpl->mRecalculateNaturalSize = true;
+
     mImpl->RequestRelayout();
   }
 }
@@ -373,6 +396,18 @@ void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignme
     // Set the flag to redo the alignment operation.
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
 
+    if( mImpl->mEventData )
+    {
+      mImpl->mEventData->mUpdateAlignment = true;
+
+      // Update the cursor if it's in editing mode
+      if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+      {
+        mImpl->ChangeState( EventData::EDITING );
+        mImpl->mEventData->mUpdateCursorPosition = true;
+      }
+    }
+
     mImpl->RequestRelayout();
   }
 }
@@ -400,6 +435,37 @@ VerticalAlignment::Type Controller::GetVerticalAlignment() const
   return mImpl->mModel->mVerticalAlignment;
 }
 
+bool Controller::IsIgnoreSpacesAfterText() const
+{
+  return mImpl->mModel->mIgnoreSpacesAfterText;
+}
+
+void Controller::SetIgnoreSpacesAfterText( bool ignore )
+{
+  mImpl->mModel->mIgnoreSpacesAfterText = ignore;
+}
+
+bool Controller::IsMatchSystemLanguageDirection() const
+{
+  return mImpl->mModel->mMatchSystemLanguageDirection;
+}
+
+void Controller::SetMatchSystemLanguageDirection( bool match )
+{
+  mImpl->mModel->mMatchSystemLanguageDirection = match;
+}
+
+void Controller::SetLayoutDirection( Dali::LayoutDirection::Type layoutDirection )
+{
+  mImpl->mLayoutDirection = layoutDirection;
+}
+
+bool Controller::IsShowingRealText() const
+{
+  return mImpl->IsShowingRealText();
+}
+
+
 void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
 {
   if( lineWrapMode != mImpl->mModel->mLineWrapMode )
@@ -438,6 +504,92 @@ bool Controller::IsTextElideEnabled() const
   return mImpl->mModel->mElideEnabled;
 }
 
+void Controller::SetTextFitEnabled(bool enabled)
+{
+  mImpl->mTextFitEnabled = enabled;
+}
+
+bool Controller::IsTextFitEnabled() const
+{
+  return mImpl->mTextFitEnabled;
+}
+
+void Controller::SetTextFitMinSize( float minSize, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitMinSize = minSize;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitMinSize = ConvertPixelToPint( minSize );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitMinSize() const
+{
+  return mImpl->mTextFitMinSize;
+}
+
+void Controller::SetTextFitMaxSize( float maxSize, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitMaxSize = maxSize;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitMaxSize = ConvertPixelToPint( maxSize );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitMaxSize() const
+{
+  return mImpl->mTextFitMaxSize;
+}
+
+void Controller::SetTextFitStepSize( float step, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitStepSize = step;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitStepSize = ConvertPixelToPint( step );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitStepSize() const
+{
+  return mImpl->mTextFitStepSize;
+}
+
+void Controller::SetTextFitContentSize(Vector2 size)
+{
+  mImpl->mTextFitContentSize = size;
+}
+
+Vector2 Controller::GetTextFitContentSize() const
+{
+  return mImpl->mTextFitContentSize;
+}
+
 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
 {
   mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
@@ -476,6 +628,26 @@ bool Controller::IsShiftSelectionEnabled() const
   return mImpl->mEventData->mShiftSelectionFlag;
 }
 
+void Controller::SetGrabHandleEnabled( bool enabled )
+{
+  mImpl->mEventData->mGrabHandleEnabled = enabled;
+}
+
+bool Controller::IsGrabHandleEnabled() const
+{
+  return mImpl->mEventData->mGrabHandleEnabled;
+}
+
+void Controller::SetGrabHandlePopupEnabled(bool enabled)
+{
+  mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
+}
+
+bool Controller::IsGrabHandlePopupEnabled() const
+{
+  return mImpl->mEventData->mGrabHandlePopupEnabled;
+}
+
 // public : Update
 
 void Controller::SetText( const std::string& text )
@@ -483,7 +655,7 @@ void Controller::SetText( const std::string& text )
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" );
 
   // Reset keyboard as text changed
-  mImpl->ResetImfManager();
+  mImpl->ResetInputMethodContext();
 
   // Remove the previously set text and style.
   ResetText();
@@ -510,7 +682,8 @@ void Controller::SetText( const std::string& text )
     mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor );
 
     MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns,
-                                         mImpl->mModel->mLogicalModel->mFontDescriptionRuns );
+                                         mImpl->mModel->mLogicalModel->mFontDescriptionRuns,
+                                         mImpl->mModel->mLogicalModel->mEmbeddedItems );
 
     Length textSize = 0u;
     const uint8_t* utf8 = NULL;
@@ -530,6 +703,13 @@ void Controller::SetText( const std::string& text )
       utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
     }
 
+    // Limit the text size. If the text size is too large, crash or deadlock will occur.
+    if( textSize > MAX_TEXT_LENGTH )
+    {
+      DALI_LOG_WARNING( "The text size is too large(%d), limit the length to 32,768u\n", textSize );
+      textSize = MAX_TEXT_LENGTH;
+    }
+
     //  Convert text into UTF-32
     Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
     utf32Characters.Resize( textSize );
@@ -1075,6 +1255,10 @@ void Controller::SetDefaultColor( const Vector4& color )
   {
     mImpl->mModel->mVisualModel->SetTextColor( color );
 
+    mImpl->mModel->mLogicalModel->mColorRuns.Clear();
+
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
+
     mImpl->RequestRelayout();
   }
 }
@@ -1195,18 +1379,42 @@ const Vector4& Controller::GetOutlineColor() const
   return mImpl->mModel->mVisualModel->GetOutlineColor();
 }
 
-void Controller::SetOutlineWidth( unsigned int width )
+void Controller::SetOutlineWidth( uint16_t width )
 {
   mImpl->mModel->mVisualModel->SetOutlineWidth( width );
 
   mImpl->RequestRelayout();
 }
 
-unsigned int Controller::GetOutlineWidth() const
+uint16_t Controller::GetOutlineWidth() const
 {
   return mImpl->mModel->mVisualModel->GetOutlineWidth();
 }
 
+void Controller::SetBackgroundColor( const Vector4& color )
+{
+  mImpl->mModel->mVisualModel->SetBackgroundColor( color );
+
+  mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetBackgroundColor() const
+{
+  return mImpl->mModel->mVisualModel->GetBackgroundColor();
+}
+
+void Controller::SetBackgroundEnabled( bool enabled )
+{
+  mImpl->mModel->mVisualModel->SetBackgroundEnabled( enabled );
+
+  mImpl->RequestRelayout();
+}
+
+bool Controller::IsBackgroundEnabled() const
+{
+  return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
+}
+
 void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
 {
   if( NULL == mImpl->mEmbossDefaults )
@@ -1249,7 +1457,7 @@ const std::string& Controller::GetDefaultOutlineProperties() const
 
 bool Controller::SetDefaultLineSpacing( float lineSpacing )
 {
-  if( std::abs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000 )
+  if( std::fabs( lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing() ) > Math::MACHINE_EPSILON_1000 )
   {
     mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
     mImpl->mRecalculateNaturalSize = true;
@@ -1270,7 +1478,7 @@ void Controller::SetInputColor( const Vector4& color )
     mImpl->mEventData->mInputStyle.textColor = color;
     mImpl->mEventData->mInputStyle.isDefaultColor = false;
 
-    if( EventData::SELECTING == mImpl->mEventData->mState )
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
     {
       const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
 
@@ -1317,7 +1525,7 @@ void Controller::SetInputFontFamily( const std::string& fontFamily )
     mImpl->mEventData->mInputStyle.familyName = fontFamily;
     mImpl->mEventData->mInputStyle.isFamilyDefined = true;
 
-    if( EventData::SELECTING == mImpl->mEventData->mState )
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
     {
       CharacterIndex startOfSelectedText = 0u;
       Length lengthOfSelectedText = 0u;
@@ -1376,7 +1584,7 @@ void Controller::SetInputFontWeight( FontWeight weight )
     mImpl->mEventData->mInputStyle.weight = weight;
     mImpl->mEventData->mInputStyle.isWeightDefined = true;
 
-    if( EventData::SELECTING == mImpl->mEventData->mState )
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
     {
       CharacterIndex startOfSelectedText = 0u;
       Length lengthOfSelectedText = 0u;
@@ -1442,7 +1650,7 @@ void Controller::SetInputFontWidth( FontWidth width )
     mImpl->mEventData->mInputStyle.width = width;
     mImpl->mEventData->mInputStyle.isWidthDefined = true;
 
-    if( EventData::SELECTING == mImpl->mEventData->mState )
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
     {
       CharacterIndex startOfSelectedText = 0u;
       Length lengthOfSelectedText = 0u;
@@ -1508,7 +1716,7 @@ void Controller::SetInputFontSlant( FontSlant slant )
     mImpl->mEventData->mInputStyle.slant = slant;
     mImpl->mEventData->mInputStyle.isSlantDefined = true;
 
-    if( EventData::SELECTING == mImpl->mEventData->mState )
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
     {
       CharacterIndex startOfSelectedText = 0u;
       Length lengthOfSelectedText = 0u;
@@ -1574,7 +1782,7 @@ void Controller::SetInputFontPointSize( float size )
     mImpl->mEventData->mInputStyle.size = size;
     mImpl->mEventData->mInputStyle.isSizeDefined = true;
 
-    if( EventData::SELECTING == mImpl->mEventData->mState )
+    if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState )
     {
       CharacterIndex startOfSelectedText = 0u;
       Length lengthOfSelectedText = 0u;
@@ -1897,6 +2105,98 @@ Vector3 Controller::GetNaturalSize()
   return naturalSize;
 }
 
+bool Controller::CheckForTextFit( float pointSize, Size& layoutSize )
+{
+  Size textSize;
+  mImpl->mFontDefaults->mFitPointSize = pointSize;
+  mImpl->mFontDefaults->sizeDefined = true;
+  ClearFontData();
+
+  // Operations that can be done only once until the text changes.
+  const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
+                                                                              GET_SCRIPTS |
+                                                                           VALIDATE_FONTS |
+                                                                          GET_LINE_BREAKS |
+                                                                          GET_WORD_BREAKS |
+                                                                                BIDI_INFO |
+                                                                                SHAPE_TEXT|
+                                                                         GET_GLYPH_METRICS );
+
+  mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+  mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+
+  // Make sure the model is up-to-date before layouting
+  mImpl->UpdateModel( onlyOnceOperations );
+
+  DoRelayout( Size( layoutSize.width, MAX_FLOAT ),
+              static_cast<OperationsMask>( onlyOnceOperations | LAYOUT),
+              textSize);
+
+  // Clear the update info. This info will be set the next time the text is updated.
+  mImpl->mTextUpdateInfo.Clear();
+  mImpl->mTextUpdateInfo.mClearAll = true;
+
+  if( textSize.width > layoutSize.width || textSize.height > layoutSize.height )
+  {
+    return false;
+  }
+  return true;
+}
+
+void Controller::FitPointSizeforLayout( Size layoutSize )
+{
+  const OperationsMask operations  = mImpl->mOperationsPending;
+  if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
+  {
+    bool actualellipsis = mImpl->mModel->mElideEnabled;
+    float minPointSize = mImpl->mTextFitMinSize;
+    float maxPointSize = mImpl->mTextFitMaxSize;
+    float pointInterval = mImpl->mTextFitStepSize;
+
+    mImpl->mModel->mElideEnabled = false;
+    Vector<float> pointSizeArray;
+
+    // check zero value
+    if( pointInterval < 1.f )
+    {
+      mImpl->mTextFitStepSize = pointInterval = 1.0f;
+    }
+
+    pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) );
+
+    for( float i = minPointSize; i < maxPointSize; i += pointInterval )
+    {
+      pointSizeArray.PushBack( i );
+    }
+
+    pointSizeArray.PushBack( maxPointSize );
+
+    int bestSizeIndex = 0;
+    int min = bestSizeIndex + 1;
+    int max = pointSizeArray.Size() - 1;
+    while( min <= max )
+    {
+      int destI = ( min + max ) / 2;
+
+      if( CheckForTextFit( pointSizeArray[destI], layoutSize ) )
+      {
+        bestSizeIndex = min;
+        min = destI + 1;
+      }
+      else
+      {
+        max = destI - 1;
+        bestSizeIndex = max;
+      }
+    }
+
+    mImpl->mModel->mElideEnabled = actualellipsis;
+    mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
+    mImpl->mFontDefaults->sizeDefined = true;
+    ClearFontData();
+  }
+}
+
 float Controller::GetHeightForWidth( float width )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
@@ -1949,6 +2249,7 @@ float Controller::GetHeightForWidth( float width )
 
     // Clear the update info. This info will be set the next time the text is updated.
     mImpl->mTextUpdateInfo.Clear();
+    mImpl->mTextUpdateInfo.mClearAll = true;
 
     // Restore the actual control's width.
     mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
@@ -2130,12 +2431,14 @@ Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
   if ( mImpl->mUpdateTextDirection )
   {
     // Operations that can be done only once until the text changes.
-    const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( GET_SCRIPTS       |
+    const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32  |
+                                                                           GET_SCRIPTS       |
                                                                            VALIDATE_FONTS    |
                                                                            GET_LINE_BREAKS   |
                                                                            GET_WORD_BREAKS   |
                                                                            BIDI_INFO         |
-                                                                           SHAPE_TEXT        );
+                                                                           SHAPE_TEXT        |
+                                                                           GET_GLYPH_METRICS );
 
     // Set the update info to relayout the whole text.
     mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
@@ -2150,9 +2453,15 @@ Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
                                              LAYOUT | REORDER | UPDATE_DIRECTION ),
                 naturalSize.GetVectorXY() );
 
+    // Do not do again the only once operations.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
+
     // Clear the update info. This info will be set the next time the text is updated.
     mImpl->mTextUpdateInfo.Clear();
 
+    // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+
     mImpl->mUpdateTextDirection = false;
   }
 
@@ -2171,7 +2480,7 @@ void Controller::SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlign
 
 // public : Relayout.
 
-Controller::UpdateTextType Controller::Relayout( const Size& size )
+Controller::UpdateTextType Controller::Relayout( const Size& size, Dali::LayoutDirection::Type layoutDirection )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ?"true":"false"  );
 
@@ -2244,6 +2553,22 @@ Controller::UpdateTextType Controller::Relayout( const Size& size )
     mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
   }
 
+  if( mImpl->mModel->mMatchSystemLanguageDirection  && mImpl->mLayoutDirection != layoutDirection )
+  {
+    // Clear the update info. This info will be set the next time the text is updated.
+    mImpl->mTextUpdateInfo.mClearAll = true;
+    // Apply modifications to the model
+    // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                             GET_GLYPH_METRICS         |
+                                                             SHAPE_TEXT                |
+                                                             UPDATE_DIRECTION          |
+                                                             LAYOUT                    |
+                                                             BIDI_INFO                 |
+                                                             REORDER );
+    mImpl->mLayoutDirection = layoutDirection;
+  }
+
   // Make sure the model is up-to-date before layouting.
   ProcessModifyEvents();
   bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
@@ -2254,6 +2579,7 @@ Controller::UpdateTextType Controller::Relayout( const Size& size )
                         mImpl->mOperationsPending,
                         layoutSize ) || updated;
 
+
   if( updated )
   {
     updateTextType = MODEL_UPDATED;
@@ -2355,8 +2681,9 @@ void Controller::KeyboardFocusGainEvent()
       mImpl->ChangeState( EventData::EDITING );
       mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered.
       mImpl->mEventData->mUpdateInputStyle = true;
+      mImpl->mEventData->mScrollAfterUpdatePosition = true;
     }
-    mImpl->NotifyImfMultiLineStatus();
+    mImpl->NotifyInputMethodContextMultiLineStatus();
     if( mImpl->IsShowingPlaceholderText() )
     {
       // Show alternative placeholder-text when editing
@@ -2432,13 +2759,24 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines();
 
       // Logic to determine whether this text control will lose focus or not.
-      if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition ) ||
-          ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition) ||
+      if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) ||
+          ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) ||
           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) ||
           ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) ||
           ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) ||
           ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) )
       {
+        // Release the active highlight.
+        if( mImpl->mEventData->mState == EventData::SELECTING )
+        {
+          mImpl->ChangeState( EventData::EDITING );
+
+          // Update selection position.
+          mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
+          mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition;
+          mImpl->mEventData->mUpdateCursorPosition = true;
+          mImpl->RequestRelayout();
+        }
         return false;
       }
 
@@ -2502,9 +2840,9 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
 
       // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text.
     }
-    else if( Dali::DALI_KEY_SHIFT_LEFT == keyCode )
+    else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) )
     {
-      // DALI_KEY_SHIFT_LEFT is the key code for the Left Shift. It's sent (by the imf?) when the predictive text is enabled
+      // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled
       // and a character is typed after the type of a upper case latin character.
 
       // Do nothing.
@@ -2520,26 +2858,32 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
     {
       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() );
 
-      // IMF manager is no longer handling key-events
-      mImpl->ClearPreEditFlag();
+      if( !keyString.empty() )
+      {
+        // InputMethodContext is no longer handling key-events
+        mImpl->ClearPreEditFlag();
 
-      InsertText( keyString, COMMIT );
-      textChanged = true;
+        InsertText( keyString, COMMIT );
+
+        textChanged = true;
+
+        // Will request for relayout.
+        relayoutNeeded = true;
+      }
 
-      // Will request for relayout.
-      relayoutNeeded = true;
     }
 
     if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) &&
          ( mImpl->mEventData->mState != EventData::INACTIVE ) &&
          ( !isNullKey ) &&
          ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) &&
+         ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) &&
          ( Dali::DALI_KEY_VOLUME_UP != keyCode ) &&
          ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) )
     {
-      // Should not change the state if the key is the shift send by the imf manager.
+      // Should not change the state if the key is the shift send by the InputMethodContext.
       // Otherwise, when the state is SELECTING the text controller can't send the right
-      // surrounding info to the imf.
+      // surrounding info to the InputMethodContext.
       mImpl->ChangeState( EventData::EDITING );
 
       // Will request for relayout.
@@ -2636,7 +2980,7 @@ void Controller::TapEvent( unsigned int tapCount, float x, float y )
   }
 
   // Reset keyboard as tap event has occurred.
-  mImpl->ResetImfManager();
+  mImpl->ResetInputMethodContext();
 }
 
 void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
@@ -2686,8 +3030,8 @@ void Controller::LongPressEvent( Gesture::State state, float x, float y  )
     }
     else if( !mImpl->IsClipboardVisible() )
     {
-      // Reset the imf manager to commit the pre-edit before selecting the text.
-      mImpl->ResetImfManager();
+      // Reset the InputMethodContext to commit the pre-edit before selecting the text.
+      mImpl->ResetInputMethodContext();
 
       Event event( Event::LONG_PRESS_EVENT );
       event.p1.mInt = state;
@@ -2702,35 +3046,61 @@ void Controller::LongPressEvent( Gesture::State state, float x, float y  )
   }
 }
 
-ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, const ImfManager::ImfEventData& imfEvent )
+void Controller::SelectEvent( float x, float y, bool selectAll )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
+
+  if( NULL != mImpl->mEventData )
+  {
+    if( selectAll )
+    {
+      Event event( Event::SELECT_ALL );
+      mImpl->mEventData->mEventQueue.push_back( event );
+    }
+    else
+    {
+      Event event( Event::SELECT );
+      event.p2.mFloat = x;
+      event.p3.mFloat = y;
+      mImpl->mEventData->mEventQueue.push_back( event );
+    }
+
+    mImpl->mEventData->mCheckScrollAmount = true;
+    mImpl->mEventData->mIsLeftHandleSelected = true;
+    mImpl->mEventData->mIsRightHandleSelected = true;
+    mImpl->RequestRelayout();
+  }
+}
+
+InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent )
 {
   // Whether the text needs to be relaid-out.
   bool requestRelayout = false;
 
-  // Whether to retrieve the text and cursor position to be sent to the IMF manager.
+  // Whether to retrieve the text and cursor position to be sent to the InputMethodContext.
   bool retrieveText = false;
   bool retrieveCursor = false;
 
-  switch( imfEvent.eventName )
+  switch( inputMethodContextEvent.eventName )
   {
-    case ImfManager::COMMIT:
+    case InputMethodContext::COMMIT:
     {
-      InsertText( imfEvent.predictiveString, Text::Controller::COMMIT );
+      InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT );
       requestRelayout = true;
       retrieveCursor = true;
       break;
     }
-    case ImfManager::PREEDIT:
+    case InputMethodContext::PRE_EDIT:
     {
-      InsertText( imfEvent.predictiveString, Text::Controller::PRE_EDIT );
+      InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT );
       requestRelayout = true;
       retrieveCursor = true;
       break;
     }
-    case ImfManager::DELETESURROUNDING:
+    case InputMethodContext::DELETE_SURROUNDING:
     {
-      const bool textDeleted = RemoveText( imfEvent.cursorOffset,
-                                           imfEvent.numberOfChars,
+      const bool textDeleted = RemoveText( inputMethodContextEvent.cursorOffset,
+                                           inputMethodContextEvent.numberOfChars,
                                            DONT_UPDATE_INPUT_STYLE );
 
       if( textDeleted )
@@ -2751,20 +3121,20 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
       }
       break;
     }
-    case ImfManager::GETSURROUNDING:
+    case InputMethodContext::GET_SURROUNDING:
     {
       retrieveText = true;
       retrieveCursor = true;
       break;
     }
-    case ImfManager::PRIVATECOMMAND:
+    case InputMethodContext::PRIVATE_COMMAND:
     {
       // PRIVATECOMMAND event is just for getting the private command message
       retrieveText = true;
       retrieveCursor = true;
       break;
     }
-    case ImfManager::VOID:
+    case InputMethodContext::VOID:
     {
       // do nothing
       break;
@@ -2812,7 +3182,7 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
     }
   }
 
-  ImfManager::ImfCallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
+  InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false );
 
   if( requestRelayout &&
       ( NULL != mImpl->mEditableControlInterface ) )
@@ -2831,7 +3201,7 @@ void Controller::PasteClipboardItemEvent()
   std::string stringToPaste( notifier.GetContent() );
 
   // Commit the current pre-edit text; the contents of the clipboard should be appended
-  mImpl->ResetImfManager();
+  mImpl->ResetInputMethodContext();
 
   // Temporary disable hiding clipboard
   mImpl->SetClipboardHideEnable( false );
@@ -3023,7 +3393,7 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   // TODO: At the moment the underline runs are only for pre-edit.
   mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
 
-  // Remove the previous IMF pre-edit.
+  // Remove the previous InputMethodContext pre-edit.
   if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) )
   {
     removedPrevious = RemoveText( -static_cast<int>( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ),
@@ -3070,10 +3440,10 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
 
     mImpl->ChangeState( EventData::EDITING );
 
-    // Handle the IMF (predicitive text) state changes
+    // Handle the InputMethodContext (predicitive text) state changes
     if( COMMIT == type )
     {
-      // IMF manager is no longer handling key-events
+      // InputMethodContext is no longer handling key-events
       mImpl->ClearPreEditFlag();
     }
     else // PRE_EDIT
@@ -3115,14 +3485,14 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
     mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style );
 
     // Whether to add a new text color run.
-    const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
+    const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor ) && !mImpl->mEventData->mInputStyle.isDefaultColor;
 
     // Whether to add a new font run.
-    const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
-    const bool addFontWeightRun = style.weight != mImpl->mEventData->mInputStyle.weight;
-    const bool addFontWidthRun = style.width != mImpl->mEventData->mInputStyle.width;
-    const bool addFontSlantRun = style.slant != mImpl->mEventData->mInputStyle.slant;
-    const bool addFontSizeRun = style.size != mImpl->mEventData->mInputStyle.size;
+    const bool addFontNameRun = ( style.familyName != mImpl->mEventData->mInputStyle.familyName ) && mImpl->mEventData->mInputStyle.isFamilyDefined;
+    const bool addFontWeightRun = ( style.weight != mImpl->mEventData->mInputStyle.weight ) && mImpl->mEventData->mInputStyle.isWeightDefined;
+    const bool addFontWidthRun = ( style.width != mImpl->mEventData->mInputStyle.width ) && mImpl->mEventData->mInputStyle.isWidthDefined;
+    const bool addFontSlantRun = ( style.slant != mImpl->mEventData->mInputStyle.slant ) && mImpl->mEventData->mInputStyle.isSlantDefined;
+    const bool addFontSizeRun = ( style.size != mImpl->mEventData->mInputStyle.size ) && mImpl->mEventData->mInputStyle.isSizeDefined ;
 
     // Add style runs.
     if( addColorRun )
@@ -3247,7 +3617,7 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() );
 
-    mImpl->ResetImfManager();
+    mImpl->ResetInputMethodContext();
 
     if( NULL != mImpl->mEditableControlInterface )
     {
@@ -3420,6 +3790,22 @@ bool Controller::DoRelayout( const Size& size,
 
     const CharacterIndex lastIndex = startIndex + ( ( requestedNumberOfCharacters > 0u ) ? requestedNumberOfCharacters - 1u : 0u );
     const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
+
+    // Make sure the index is not out of bound
+    if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
+         requestedNumberOfCharacters > charactersToGlyph.Count() ||
+         ( lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
+    {
+      std::string currentText;
+      GetText( currentText );
+
+      DALI_LOG_ERROR( "Controller::DoRelayout: Attempting to access invalid buffer\n" );
+      DALI_LOG_ERROR( "Current text is: %s\n", currentText.c_str() );
+      DALI_LOG_ERROR( "startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
+
+      return false;
+    }
+
     const Length numberOfGlyphs = ( requestedNumberOfCharacters > 0u ) ? *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex : 0u;
     const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
 
@@ -3445,8 +3831,7 @@ bool Controller::DoRelayout( const Size& size,
     const float outlineWidth = static_cast<float>( mImpl->mModel->GetOutlineWidth() );
 
     // Set the layout parameters.
-    const Vector2 sizeOffset = Vector2(outlineWidth * 2.0f, outlineWidth * 2.0f); // The outline should be fit into the bounding box
-    Layout::Parameters layoutParameters( size - sizeOffset,
+    Layout::Parameters layoutParameters( size,
                                          textBuffer,
                                          lineBreakInfo.Begin(),
                                          wordBreakInfo.Begin(),
@@ -3459,7 +3844,9 @@ bool Controller::DoRelayout( const Size& size,
                                          totalNumberOfGlyphs,
                                          mImpl->mModel->mHorizontalAlignment,
                                          mImpl->mModel->mLineWrapMode,
-                                         outlineWidth );
+                                         outlineWidth,
+                                         mImpl->mModel->mIgnoreSpacesAfterText,
+                                         mImpl->mModel->mMatchSystemLanguageDirection );
 
     // Resize the vector of positions to have the same size than the vector of glyphs.
     Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
@@ -3498,12 +3885,15 @@ bool Controller::DoRelayout( const Size& size,
     }
 
     // Update the visual model.
+    bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
     Size newLayoutSize;
     viewUpdated = mImpl->mLayoutEngine.LayoutText( layoutParameters,
                                                    glyphPositions,
                                                    mImpl->mModel->mVisualModel->mLines,
                                                    newLayoutSize,
-                                                   elideTextEnabled );
+                                                   elideTextEnabled,
+                                                   isAutoScrollEnabled );
+    mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
 
     viewUpdated = viewUpdated || ( newLayoutSize != layoutSize );
 
@@ -3570,14 +3960,28 @@ bool Controller::DoRelayout( const Size& size,
     // The laid-out lines.
     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
 
+    CharacterIndex alignStartIndex = startIndex;
+    Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
+
+    // the whole text needs to be full aligned.
+    // If you do not do a full aligned, only the last line of the multiline input is aligned.
+    if(  mImpl->mEventData && mImpl->mEventData->mUpdateAlignment )
+    {
+      alignStartIndex = 0u;
+      alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+      mImpl->mEventData->mUpdateAlignment = false;
+    }
+
     // Need to align with the control's size as the text may contain lines
     // starting either with left to right text or right to left.
     mImpl->mLayoutEngine.Align( size,
-                                startIndex,
-                                requestedNumberOfCharacters,
+                                alignStartIndex,
+                                alignRequestedNumberOfCharacters,
                                 mImpl->mModel->mHorizontalAlignment,
                                 lines,
-                                mImpl->mModel->mAlignmentOffset );
+                                mImpl->mModel->mAlignmentOffset,
+                                mImpl->mLayoutDirection,
+                                mImpl->mModel->mMatchSystemLanguageDirection );
 
     viewUpdated = true;
   }
@@ -3728,32 +4132,6 @@ void Controller::TextDeletedEvent()
   mImpl->mOperationsPending = ALL_OPERATIONS;
 }
 
-void Controller::SelectEvent( float x, float y, bool selectAll )
-{
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" );
-
-  if( NULL != mImpl->mEventData )
-  {
-    if( selectAll )
-    {
-      Event event( Event::SELECT_ALL );
-      mImpl->mEventData->mEventQueue.push_back( event );
-    }
-    else
-    {
-      Event event( Event::SELECT );
-      event.p2.mFloat = x;
-      event.p3.mFloat = y;
-      mImpl->mEventData->mEventQueue.push_back( event );
-    }
-
-    mImpl->mEventData->mCheckScrollAmount = true;
-    mImpl->mEventData->mIsLeftHandleSelected = true;
-    mImpl->mEventData->mIsRightHandleSelected = true;
-    mImpl->RequestRelayout();
-  }
-}
-
 bool Controller::DeleteEvent( int keyCode )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode );
@@ -3765,7 +4143,7 @@ bool Controller::DeleteEvent( int keyCode )
     return removed;
   }
 
-  // IMF manager is no longer handling key-events
+  // InputMethodContext is no longer handling key-events
   mImpl->ClearPreEditFlag();
 
   if( EventData::SELECTING == mImpl->mEventData->mState )
@@ -3812,6 +4190,9 @@ void Controller::ResetText()
   // Reset buffers.
   mImpl->mModel->mLogicalModel->mText.Clear();
 
+  // Reset the embedded images buffer.
+  mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
+
   // We have cleared everything including the placeholder-text
   mImpl->PlaceholderCleared();