Merge changes I26f3edb0,Iba714851 into new_text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
index 47b0115..d86d4f5 100644 (file)
@@ -44,7 +44,6 @@ namespace
 {
 
 const float MAX_FLOAT = std::numeric_limits<float>::max();
 {
 
 const float MAX_FLOAT = std::numeric_limits<float>::max();
-const std::string EMPTY_STRING;
 
 enum ModifyType
 {
 
 enum ModifyType
 {
@@ -70,6 +69,31 @@ namespace Toolkit
 namespace Text
 {
 
 namespace Text
 {
 
+struct Controller::FontDefaults
+{
+  FontDefaults()
+  : mDefaultPointSize(0.0f),
+    mFontId(0u)
+  {
+  }
+
+  FontId GetFontId( TextAbstraction::FontClient& fontClient )
+  {
+    if( !mFontId )
+    {
+      Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
+      mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
+    }
+
+    return mFontId;
+  }
+
+  std::string mDefaultFontFamily;
+  std::string mDefaultFontStyle;
+  float mDefaultPointSize;
+  FontId mFontId;
+};
+
 struct Controller::TextInput
 {
   // Used to queue input events until DoRelayout()
 struct Controller::TextInput
 {
   // Used to queue input events until DoRelayout()
@@ -105,37 +129,86 @@ struct Controller::TextInput
     Param p3;
   };
 
     Param p3;
   };
 
+  struct CursorInfo
+  {
+    CursorInfo()
+    : primaryPosition(),
+      secondaryPosition(),
+      lineHeight( 0.f ),
+      primaryCursorHeight( 0.f ),
+      secondaryCursorHeight( 0.f ),
+      isSecondaryCursor( false )
+    {}
+
+    ~CursorInfo()
+    {}
+
+    Vector2 primaryPosition;       ///< The primary cursor's position.
+    Vector2 secondaryPosition;     ///< The secondary cursor's position.
+    float   lineHeight;            ///< The height of the line where the cursor is placed.
+    float   primaryCursorHeight;   ///< The primary cursor's height.
+    float   secondaryCursorHeight; ///< The secondary cursor's height.
+    bool    isSecondaryCursor;     ///< Whether the secondary cursor is valid.
+  };
+
+  /**
+   * @brief Some characters can be shaped in more than one glyph.
+   * This struct is used to retrieve metrics from these group of glyphs.
+   */
+  struct GlyphMetrics
+  {
+    GlyphMetrics()
+    : fontHeight( 0.f ),
+      advance( 0.f ),
+      ascender( 0.f ),
+      xBearing( 0.f )
+    {}
+
+    ~GlyphMetrics()
+    {}
+
+    float fontHeight; ///< The font's height of that glyphs.
+    float advance;    ///< The sum of all the advances of all the glyphs.
+    float ascender;   ///< The font's ascender.
+    float xBearing;   ///< The x bearing of the first glyph.
+  };
+
   enum State
   {
     INACTIVE,
     SELECTING,
   enum State
   {
     INACTIVE,
     SELECTING,
-    EDITING
+    EDITING,
+    EDITING_WITH_POPUP
   };
 
   TextInput( LogicalModelPtr logicalModel,
              VisualModelPtr visualModel,
   };
 
   TextInput( LogicalModelPtr logicalModel,
              VisualModelPtr visualModel,
-             DecoratorPtr decorator )
+             DecoratorPtr decorator,
+             FontDefaults* fontDefaults,
+             TextAbstraction::FontClient& fontClient )
   : mLogicalModel( logicalModel ),
     mVisualModel( visualModel ),
     mDecorator( decorator ),
   : mLogicalModel( logicalModel ),
     mVisualModel( visualModel ),
     mDecorator( decorator ),
+    mFontDefaults( fontDefaults ),
+    mFontClient( fontClient ),
     mState( INACTIVE ),
     mPrimaryCursorPosition( 0u ),
     mSecondaryCursorPosition( 0u ),
     mDecoratorUpdated( false ),
     mCursorBlinkEnabled( true ),
     mState( INACTIVE ),
     mPrimaryCursorPosition( 0u ),
     mSecondaryCursorPosition( 0u ),
     mDecoratorUpdated( false ),
     mCursorBlinkEnabled( true ),
-    mGrabHandleEnabled( false ),
-    mGrabHandlePopupEnabled( false ),
-    mSelectionEnabled( false ),
+    mGrabHandleEnabled( true ),
+    mGrabHandlePopupEnabled( true ),
+    mSelectionEnabled( true ),
     mHorizontalScrollingEnabled( true ),
     mVerticalScrollingEnabled( false ),
     mUpdateCursorPosition( false )
     mHorizontalScrollingEnabled( true ),
     mVerticalScrollingEnabled( false ),
     mUpdateCursorPosition( false )
-  {
-  }
+  {}
 
   /**
    * @brief Helper to move the cursor, grab handle etc.
    */
 
   /**
    * @brief Helper to move the cursor, grab handle etc.
    */
-  bool ProcessInputEvents( const Vector2& controlSize )
+  bool ProcessInputEvents( const Vector2& controlSize,
+                           const Vector2& alignmentOffset )
   {
     mDecoratorUpdated = false;
 
   {
     mDecoratorUpdated = false;
 
@@ -162,12 +235,12 @@ struct Controller::TextInput
           }
           case TAP_EVENT:
           {
           }
           case TAP_EVENT:
           {
-            OnTapEvent( *iter );
+            OnTapEvent( *iter, alignmentOffset );
             break;
           }
           case PAN_EVENT:
           {
             break;
           }
           case PAN_EVENT:
           {
-            OnPanEvent( *iter, controlSize );
+            OnPanEvent( *iter, controlSize, alignmentOffset );
             break;
           }
           case GRAB_HANDLE_EVENT:
             break;
           }
           case GRAB_HANDLE_EVENT:
@@ -209,11 +282,17 @@ struct Controller::TextInput
 
     if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
     {
 
     if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
     {
-      // TODO
+      if( mPrimaryCursorPosition > 0u )
+      {
+        mPrimaryCursorPosition = CalculateNewCursorIndex( mPrimaryCursorPosition - 1u );
+      }
     }
     else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
     {
     }
     else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
     {
-      // TODO
+      if( mLogicalModel->GetNumberOfCharacters() > mPrimaryCursorPosition )
+      {
+        mPrimaryCursorPosition = CalculateNewCursorIndex( mPrimaryCursorPosition );
+      }
     }
     else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
     {
     }
     else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
     {
@@ -223,6 +302,8 @@ struct Controller::TextInput
     {
       // TODO
     }
     {
       // TODO
     }
+
+    UpdateCursorPosition();
   }
 
   void HandleCursorKey( int keyCode )
   }
 
   void HandleCursorKey( int keyCode )
@@ -230,7 +311,8 @@ struct Controller::TextInput
     // TODO
   }
 
     // TODO
   }
 
-  void OnTapEvent( const Event& event )
+  void OnTapEvent( const Event& event,
+                   const Vector2& alignmentOffset  )
   {
     unsigned int tapCount = event.p1.mUint;
 
   {
     unsigned int tapCount = event.p1.mUint;
 
@@ -238,23 +320,26 @@ struct Controller::TextInput
     {
       ChangeState( EDITING );
 
     {
       ChangeState( EDITING );
 
-      float xPosition = event.p2.mFloat;
-      float yPosition = event.p3.mFloat;
-      float height(0.0f);
-      GetClosestCursorPosition( mPrimaryCursorPosition, xPosition, yPosition, height );
-      mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
-      mUpdateCursorPosition = false;
+      float xPosition = event.p2.mFloat - alignmentOffset.x;
+      float yPosition = event.p3.mFloat - alignmentOffset.y;
 
 
-      mDecoratorUpdated = true;
+      mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
+                                                      yPosition );
+
+      UpdateCursorPosition();
     }
     else if( mSelectionEnabled &&
              2u == tapCount )
     {
       ChangeState( SELECTING );
     }
     else if( mSelectionEnabled &&
              2u == tapCount )
     {
       ChangeState( SELECTING );
+
+      RepositionSelectionHandles( event.p2.mFloat, event.p3.mFloat );
     }
     }
 }
+ }
 
 
-  void OnPanEvent( const Event& event, const Vector2& controlSize )
+  void OnPanEvent( const Event& event,
+                   const Vector2& controlSize,
+                   const Vector2& alignmentOffset )
   {
     int state = event.p1.mInt;
 
   {
     int state = event.p1.mInt;
 
@@ -265,28 +350,43 @@ struct Controller::TextInput
 
       if( mHorizontalScrollingEnabled )
       {
 
       if( mHorizontalScrollingEnabled )
       {
-        float displacementX = event.p2.mFloat;
+        const float displacementX = event.p2.mFloat;
         mScrollPosition.x += displacementX;
 
         mScrollPosition.x += displacementX;
 
-        // Clamp between -space & 0
-        float contentWidth = actualSize.width;
-        float space = (contentWidth > controlSize.width) ? contentWidth - controlSize.width : 0.0f;
-        mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x;
-        mScrollPosition.x = ( mScrollPosition.x > 0 )      ?      0 : mScrollPosition.x;
+        // Clamp between -space & 0 (and the text alignment).
+        const float contentWidth = actualSize.width;
+        if( contentWidth > controlSize.width )
+        {
+          const float space = ( contentWidth - controlSize.width ) + alignmentOffset.x;
+          mScrollPosition.x = ( mScrollPosition.x < -space ) ? -space : mScrollPosition.x;
+          mScrollPosition.x = ( mScrollPosition.x > -alignmentOffset.x ) ? -alignmentOffset.x : mScrollPosition.x;
 
 
-        mDecoratorUpdated = true;
+          mDecoratorUpdated = true;
+        }
+        else
+        {
+          mScrollPosition.x = 0.f;
+        }
       }
       }
+
       if( mVerticalScrollingEnabled )
       {
       if( mVerticalScrollingEnabled )
       {
-        float displacementY = event.p3.mFloat;
+        const float displacementY = event.p3.mFloat;
         mScrollPosition.y += displacementY;
 
         mScrollPosition.y += displacementY;
 
-        // Clamp between -space & 0
-        float space = (actualSize.height > controlSize.height) ? actualSize.height - controlSize.height : 0.0f;
-        mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y;
-        mScrollPosition.y = ( mScrollPosition.y > 0 )      ?      0 : mScrollPosition.y;
+        // Clamp between -space & 0 (and the text alignment).
+        if( actualSize.height > controlSize.height )
+        {
+          const float space = ( actualSize.height - controlSize.height ) + alignmentOffset.y;
+          mScrollPosition.y = ( mScrollPosition.y < -space ) ? -space : mScrollPosition.y;
+          mScrollPosition.y = ( mScrollPosition.y > -alignmentOffset.y ) ? -alignmentOffset.y : mScrollPosition.y;
 
 
-        mDecoratorUpdated = true;
+          mDecoratorUpdated = true;
+        }
+        else
+        {
+          mScrollPosition.y = 0.f;
+        }
       }
     }
   }
       }
     }
   }
@@ -297,20 +397,53 @@ struct Controller::TextInput
 
     if( GRAB_HANDLE_PRESSED == state )
     {
 
     if( GRAB_HANDLE_PRESSED == state )
     {
-      float xPosition = event.p2.mFloat;
-      float yPosition = event.p3.mFloat;
-      float height(0.0f);
+      float xPosition = event.p2.mFloat + mScrollPosition.x;
+      float yPosition = event.p3.mFloat + mScrollPosition.y;
 
 
-      GetClosestCursorPosition( mPrimaryCursorPosition, xPosition, yPosition, height );
+      mPrimaryCursorPosition = GetClosestCursorIndex( xPosition,
+                                                      yPosition );
 
 
-      mDecorator->SetPosition( PRIMARY_CURSOR, xPosition, yPosition, height );
-      mDecorator->HidePopup();
-      mDecoratorUpdated = true;
+      UpdateCursorPosition();
+
+      //mDecorator->HidePopup();
+      ChangeState ( EDITING );
     }
     else if ( mGrabHandlePopupEnabled &&
               GRAB_HANDLE_RELEASED == state )
     {
     }
     else if ( mGrabHandlePopupEnabled &&
               GRAB_HANDLE_RELEASED == state )
     {
-      mDecorator->ShowPopup();
+      //mDecorator->ShowPopup();
+      ChangeState ( EDITING_WITH_POPUP );
+      mDecoratorUpdated = true;
+    }
+  }
+
+  void RepositionSelectionHandles( float visualX, float visualY )
+  {
+    // TODO - Find which word was selected
+
+    const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
+    const Vector<Vector2>::SizeType glyphCount = glyphs.Count();
+
+    const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
+    const Vector<Vector2>::SizeType positionCount = positions.Count();
+
+    // Guard against glyphs which did not fit inside the layout
+    const Vector<Vector2>::SizeType count = (positionCount < glyphCount) ? positionCount : glyphCount;
+
+    if( count )
+    {
+      float primaryX   = positions[0].x;
+      float secondaryX = positions[count-1].x + glyphs[count-1].width;
+
+      // TODO - multi-line selection
+      const Vector<LineRun>& lines = mVisualModel->mLines;
+      float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
+
+      mDecorator->SetPosition( PRIMARY_SELECTION_HANDLE,   primaryX,   0.0f, height );
+      mDecorator->SetPosition( SECONDARY_SELECTION_HANDLE, secondaryX, 0.0f, height );
+
+      mDecorator->ClearHighlights();
+      mDecorator->AddHighlight( primaryX, 0.0f, secondaryX, height );
     }
   }
 
     }
   }
 
@@ -326,7 +459,7 @@ struct Controller::TextInput
         mDecorator->StopCursorBlink();
         mDecorator->SetGrabHandleActive( false );
         mDecorator->SetSelectionActive( false );
         mDecorator->StopCursorBlink();
         mDecorator->SetGrabHandleActive( false );
         mDecorator->SetSelectionActive( false );
-        mDecorator->HidePopup();
+        mDecorator->SetPopupActive( false );
         mDecoratorUpdated = true;
       }
       else if ( SELECTING == mState )
         mDecoratorUpdated = true;
       }
       else if ( SELECTING == mState )
@@ -348,37 +481,74 @@ struct Controller::TextInput
         {
           mDecorator->SetGrabHandleActive( true );
         }
         {
           mDecorator->SetGrabHandleActive( true );
         }
+        if( mGrabHandlePopupEnabled )
+        {
+          mDecorator->SetPopupActive( false );
+        }
+        mDecorator->SetSelectionActive( false );
+        mDecoratorUpdated = true;
+      }
+      else if( EDITING_WITH_POPUP == mState )
+      {
+        mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+        if( mCursorBlinkEnabled )
+        {
+          mDecorator->StartCursorBlink();
+        }
+        if( mGrabHandleEnabled )
+        {
+          mDecorator->SetGrabHandleActive( true );
+        }
+        if( mGrabHandlePopupEnabled )
+        {
+          mDecorator->SetPopupActive( true );
+        }
         mDecorator->SetSelectionActive( false );
         mDecoratorUpdated = true;
       }
     }
   }
 
         mDecorator->SetSelectionActive( false );
         mDecoratorUpdated = true;
       }
     }
   }
 
-  LineIndex GetClosestLine( float y )
+  LineIndex GetClosestLine( float y ) const
   {
   {
-    LineIndex lineIndex( 0u );
+    float totalHeight = 0.f;
+    LineIndex lineIndex = 0u;
 
     const Vector<LineRun>& lines = mVisualModel->mLines;
 
     const Vector<LineRun>& lines = mVisualModel->mLines;
-    for( float totalHeight = 0; lineIndex < lines.Count(); ++lineIndex )
+    for( LineIndex endLine = lines.Count();
+         lineIndex < endLine;
+         ++lineIndex )
     {
     {
-      totalHeight += lines[lineIndex].lineSize.height;
+      const LineRun& lineRun = lines[lineIndex];
+      totalHeight += lineRun.ascender + -lineRun.descender;
       if( y < totalHeight )
       {
       if( y < totalHeight )
       {
-        break;
+        return lineIndex;
       }
     }
 
       }
     }
 
-    return lineIndex;
+    return lineIndex-1;
   }
 
   }
 
-  void GetClosestCursorPosition( CharacterIndex& logical, float& visualX, float& visualY, float& height )
+  /**
+   * @brief Retrieves the cursor's logical position for a given touch point x,y
+   *
+   * @param[in] visualX The touch point x.
+   * @param[in] visualY The touch point y.
+   *
+   * @return The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
+   */
+  CharacterIndex GetClosestCursorIndex( float visualX,
+                                        float visualY ) const
   {
   {
-    Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
-    Length numberOfLines  = mVisualModel->mLines.Count();
+    CharacterIndex logicalIndex = 0u;
+
+    const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
+    const Length numberOfLines  = mVisualModel->mLines.Count();
     if( 0 == numberOfGlyphs ||
         0 == numberOfLines )
     {
     if( 0 == numberOfGlyphs ||
         0 == numberOfLines )
     {
-      return;
+      return logicalIndex;
     }
 
     // Transform to visual model coords
     }
 
     // Transform to visual model coords
@@ -386,115 +556,380 @@ struct Controller::TextInput
     visualY -= mScrollPosition.y;
 
     // Find which line is closest
     visualY -= mScrollPosition.y;
 
     // Find which line is closest
-    LineIndex lineIndex( GetClosestLine( visualY ) );
-
-    const Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
-    const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+    const LineIndex lineIndex = GetClosestLine( visualY );
+    const LineRun& line = mVisualModel->mLines[lineIndex];
 
 
+    // Get the positions of the glyphs.
     const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
     const Vector2* const positionsBuffer = positions.Begin();
 
     const Vector<Vector2>& positions = mVisualModel->mGlyphPositions;
     const Vector2* const positionsBuffer = positions.Begin();
 
-    unsigned int closestGlyph = 0;
-    bool leftOfGlyph( false ); // which side of the glyph?
-    float closestDistance = MAX_FLOAT;
+    // Get the visual to logical conversion tables.
+    const CharacterIndex* const visualToLogicalBuffer = ( 0u != mLogicalModel->mVisualToLogicalMap.Count() ) ? mLogicalModel->mVisualToLogicalMap.Begin() : NULL;
+    const CharacterIndex* const visualToLogicalCursorBuffer = mLogicalModel->mVisualToLogicalCursorMap.Begin();
 
 
-    const LineRun& line = mVisualModel->mLines[lineIndex];
-    GlyphIndex startGlyph = line.glyphIndex;
-    GlyphIndex endGlyph   = line.glyphIndex + line.numberOfGlyphs;
-    DALI_ASSERT_DEBUG( endGlyph <= glyphs.Count() && "Invalid line info" );
+    // Get the character to glyph conversion table.
+    const GlyphIndex* const charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
 
 
-    for( GlyphIndex i = startGlyph; i < endGlyph; ++i )
+    // Get the glyphs per character table.
+    const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+
+    // If the vector is void, there is no right to left characters.
+    const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
+
+    const CharacterIndex startCharacter = line.characterRun.characterIndex;
+    const CharacterIndex endCharacter   = line.characterRun.characterIndex + line.characterRun.numberOfCharacters;
+    DALI_ASSERT_DEBUG( endCharacter <= mLogicalModel->mText.Count() && "Invalid line info" );
+
+    // Whether there is a hit on a glyph.
+    bool matched = false;
+
+    // Traverses glyphs in visual order. To do that use the visual to logical conversion table.
+    CharacterIndex visualIndex = startCharacter;
+    for( ; !matched && ( visualIndex < endCharacter ); ++visualIndex )
     {
     {
-      const GlyphInfo& glyphInfo = *( glyphsBuffer + i );
-      const Vector2& position = *( positionsBuffer + i );
-      float glyphX = position.x + glyphInfo.width*0.5f;
-      float glyphY = position.y + glyphInfo.height*0.5f;
+      // The character in logical order.
+      const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
+
+      // The first glyph for that character in logical order.
+      const GlyphIndex glyphLogicalOrderIndex = *( charactersToGlyphBuffer + characterLogicalOrderIndex );
+
+      // The number of glyphs for that character
+      const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
 
 
-      float distanceToGlyph = fabsf( glyphX - visualX ) + fabsf( glyphY - visualY );
+      // Get the metrics for the group of glyphs.
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( glyphLogicalOrderIndex,
+                        numberOfGlyphs,
+                        glyphMetrics );
 
 
-      if( distanceToGlyph < closestDistance )
+      const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
+
+      const float glyphX = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
+
+      if( visualX < glyphX )
       {
       {
-        closestDistance = distanceToGlyph;
-        closestGlyph = i;
-        leftOfGlyph = ( visualX < glyphX );
+        matched = true;
+        break;
       }
     }
 
       }
     }
 
-    // Calculate the logical position
-    logical = mVisualModel->GetCharacterIndex( closestGlyph );
+    // Return the logical position of the cursor in characters.
 
 
-    // Returns the visual position of the glyph
-    visualX = positions[closestGlyph].x;
-    if( !leftOfGlyph )
+    if( !matched )
     {
     {
-      visualX += glyphs[closestGlyph].width;
-
-      //if( LTR ) TODO
-        ++logical;
+      visualIndex = endCharacter;
     }
     }
-    else// if ( RTL ) TODO
-    {
-      //++logical;
-    }
-    visualY = 0.0f;
 
 
-    height = line.lineSize.height;
+    return hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
   }
 
   }
 
-  void UpdateCursorPosition()
+  /**
+   * @brief Calculates the cursor's position for a given character index in the logical order.
+   *
+   * It retrieves as well the line's height and the cursor's height and
+   * if there is a valid alternative cursor, its position and height.
+   *
+   * @param[in] logical The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
+   * @param[out] cursorInfo The line's height, the cursor's height, the cursor's position and whether there is an alternative cursor.
+   */
+  void GetCursorPosition( CharacterIndex logical,
+                          CursorInfo& cursorInfo ) const
   {
   {
-    if( 0 == mVisualModel->mGlyphs.Count() )
+    // TODO: Check for multiline with \n, etc...
+
+    // Check if the logical position is the first or the last one of the text.
+    const bool isFirstPosition = 0u == logical;
+    const bool isLastPosition = mLogicalModel->GetNumberOfCharacters() == logical;
+
+    if( isFirstPosition && isLastPosition )
     {
     {
+      // There is zero characters. Get the default font.
+
+      FontId defaultFontId = 0u;
+      if( NULL == mFontDefaults )
+      {
+        defaultFontId = mFontClient.GetFontId( String::EMPTY,
+                                               String::EMPTY );
+      }
+      else
+      {
+        defaultFontId = mFontDefaults->GetFontId( mFontClient );
+      }
+
+      Text::FontMetrics fontMetrics;
+      mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
+
+      cursorInfo.lineHeight = fontMetrics.ascender - fontMetrics.descender;
+      cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
+
+      cursorInfo.primaryPosition.x = 0.f;
+      cursorInfo.primaryPosition.y = 0.f;
+
+      // Nothing else to do.
       return;
     }
 
       return;
     }
 
-    // FIXME GetGlyphIndex() is behaving strangely
-#if 0
-    GlyphIndex cursorGlyph = mVisualModel->GetGlyphIndex( mPrimaryCursorPosition );
-#else
-    GlyphIndex cursorGlyph( 0u );
-    for( cursorGlyph = 0; cursorGlyph < mVisualModel->mGlyphs.Count(); ++cursorGlyph )
+    // Get the previous logical index.
+    const CharacterIndex previousLogical = isFirstPosition ? 0u : logical - 1u;
+
+    // Decrease the logical index if it's the last one.
+    if( isLastPosition )
     {
     {
-      if( mPrimaryCursorPosition == mVisualModel->GetCharacterIndex( cursorGlyph ) )
-      {
-        break;
-      }
+      --logical;
+    }
+
+    // Get the direction of the character and the previous one.
+    const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
+
+    CharacterDirection isCurrentRightToLeft = false;
+    CharacterDirection isPreviousRightToLeft = false;
+    if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
+    {
+      isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + logical );
+      isPreviousRightToLeft = *( modelCharacterDirectionsBuffer + previousLogical );
+    }
+
+    // Get the line where the character is laid-out.
+    const LineRun* modelLines = mVisualModel->mLines.Begin();
+
+    const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( logical );
+    const LineRun& line = *( modelLines + lineIndex );
+
+    // Get the paragraph's direction.
+    const CharacterDirection isRightToLeftParagraph = line.direction;
+
+    // Check whether there is an alternative position:
+
+    cursorInfo.isSecondaryCursor = ( isCurrentRightToLeft != isPreviousRightToLeft ) ||
+                                   ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
+
+    // Set the line height.
+    cursorInfo.lineHeight = line.ascender + -line.descender;
+
+    // Convert the cursor position into the glyph position.
+    CharacterIndex characterIndex = logical;
+    if( cursorInfo.isSecondaryCursor &&
+        ( isRightToLeftParagraph != isCurrentRightToLeft ) )
+    {
+      characterIndex = previousLogical;
     }
     }
-#endif
 
 
-    float visualX( 0.0f );
-    float visualY( 0.0f );
-    LineIndex lineIndex( 0u );
-    const Vector<LineRun>& lineRuns = mVisualModel->mLines;
+    const GlyphIndex currentGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
+    const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
+    const Length numberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() +currentGlyphIndex );
+
+    // Get the metrics for the group of glyphs.
+    GlyphMetrics glyphMetrics;
+    GetGlyphsMetrics( currentGlyphIndex,
+                      numberOfGlyphs,
+                      glyphMetrics );
 
 
-    if( cursorGlyph > 0 )
+    float interGlyphAdvance = 0.f;
+    if( !isLastPosition &&
+        ( numberOfCharacters > 1u ) )
     {
     {
-      --cursorGlyph;
+      const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + currentGlyphIndex );
+      interGlyphAdvance = static_cast<float>( characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( numberOfCharacters );
+    }
 
 
-      visualX = mVisualModel->mGlyphPositions[ cursorGlyph ].x;
-      //if( LTR ) TODO
-        visualX += mVisualModel->mGlyphs[ cursorGlyph ].width;
+    // Get the glyph position and x bearing.
+    const Vector2& currentPosition = *( mVisualModel->mGlyphPositions.Begin() + currentGlyphIndex );
 
 
-      // Find the line height
-      for( GlyphIndex lastGlyph = 0; lineIndex < lineRuns.Count(); ++lineIndex )
+    // Set the cursor's height.
+    cursorInfo.primaryCursorHeight = glyphMetrics.fontHeight;
+
+    // Set the position.
+    cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + currentPosition.x + ( isCurrentRightToLeft ? glyphMetrics.advance : interGlyphAdvance );
+    cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
+
+    if( isLastPosition )
+    {
+      // The position of the cursor after the last character needs special
+      // care depending on its direction and the direction of the paragraph.
+
+      if( cursorInfo.isSecondaryCursor )
       {
       {
-        lastGlyph = (lineRuns[lineIndex].glyphIndex + lineRuns[lineIndex].numberOfGlyphs);
-        if( cursorGlyph < lastGlyph )
+        // Need to find the first character after the last character with the paragraph's direction.
+        // i.e l0 l1 l2 r0 r1 should find r0.
+
+        // TODO: check for more than one line!
+        characterIndex = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
+        characterIndex = mLogicalModel->GetLogicalCharacterIndex( characterIndex );
+
+        const GlyphIndex glyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
+        const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
+
+        const Vector2& position = *( mVisualModel->mGlyphPositions.Begin() + glyphIndex );
+
+        // Get the metrics for the group of glyphs.
+        GlyphMetrics glyphMetrics;
+        GetGlyphsMetrics( glyphIndex,
+                          numberOfGlyphs,
+                          glyphMetrics );
+
+        cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + position.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
+
+        cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
+      }
+      else
+      {
+        if( !isCurrentRightToLeft )
+        {
+          cursorInfo.primaryPosition.x += glyphMetrics.advance;
+        }
+        else
         {
         {
-          break;
+          cursorInfo.primaryPosition.x -= glyphMetrics.advance;
         }
       }
     }
 
         }
       }
     }
 
-    mDecorator->SetPosition( PRIMARY_CURSOR, visualX, visualY, lineRuns[lineIndex].lineSize.height );
-    mDecoratorUpdated = true;
+    // Set the alternative cursor position.
+    if( cursorInfo.isSecondaryCursor )
+    {
+      // Convert the cursor position into the glyph position.
+      const CharacterIndex previousCharacterIndex = ( ( isRightToLeftParagraph != isCurrentRightToLeft ) ? logical : previousLogical );
+      const GlyphIndex previousGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + previousCharacterIndex );
+      const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + previousCharacterIndex );
+
+      // Get the glyph position.
+      const Vector2& previousPosition = *( mVisualModel->mGlyphPositions.Begin() + previousGlyphIndex );
+
+      // Get the metrics for the group of glyphs.
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( previousGlyphIndex,
+                        numberOfGlyphs,
+                        glyphMetrics );
+
+      // Set the cursor position and height.
+      cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + previousPosition.x + ( ( ( isLastPosition && !isCurrentRightToLeft ) ||
+                                                                                         ( !isLastPosition && isCurrentRightToLeft )    ) ? glyphMetrics.advance : 0.f );
+
+      cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
+
+      cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
+
+      // Update the primary cursor height as well.
+      cursorInfo.primaryCursorHeight *= 0.5f;
+    }
   }
 
   }
 
-  LogicalModelPtr mLogicalModel;
-  VisualModelPtr  mVisualModel;
-  DecoratorPtr    mDecorator;
+  /**
+   * @brief Get some glyph's metrics of a group of glyphs formed as a result of shaping one character.
+   *
+   * @param[in] glyphIndex The index to the first glyph.
+   * @param[in] numberOfGlyphs The number of glyphs.
+   * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
+   */
+  void GetGlyphsMetrics( GlyphIndex glyphIndex,
+                         Length numberOfGlyphs,
+                         GlyphMetrics& glyphMetrics ) const
+  {
+    const GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
+
+    const GlyphInfo& firstGlyph = *( glyphsBuffer + glyphIndex );
+
+    Text::FontMetrics fontMetrics;
+    mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics );
 
 
-  std::string mPlaceholderText;
+    glyphMetrics.fontHeight = fontMetrics.height;
+    glyphMetrics.advance = firstGlyph.advance;
+    glyphMetrics.ascender = fontMetrics.ascender;
+    glyphMetrics.xBearing = firstGlyph.xBearing;
+
+    for( unsigned int i = 1u; i < numberOfGlyphs; ++i )
+    {
+      const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i );
+
+      glyphMetrics.advance += glyphInfo.advance;
+    }
+  }
+
+  /**
+   * @brief Calculates the new cursor index.
+   *
+   * It takes into account that in some scripts multiple characters can form a glyph and all of them
+   * need to be jumped with one key event.
+   *
+   * @param[in] index The initial new index.
+   *
+   * @return The new cursor index.
+   */
+  CharacterIndex CalculateNewCursorIndex( CharacterIndex index ) const
+  {
+    CharacterIndex cursorIndex = mPrimaryCursorPosition;
+
+    const Script script = mLogicalModel->GetScript( index );
+    const GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+    const Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+
+    Length numberOfCharacters = 0u;
+    if( TextAbstraction::LATIN == script )
+    {
+      // Prevents to jump the whole Latin ligatures like fi, ff, ...
+      numberOfCharacters = 1u;
+    }
+    else
+    {
+      GlyphIndex glyphIndex = *( charactersToGlyphBuffer + index );
+      numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
+
+      while( 0u == numberOfCharacters )
+      {
+        numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex );
+        ++glyphIndex;
+      }
+    }
+
+    if( index < mPrimaryCursorPosition )
+    {
+      cursorIndex -= numberOfCharacters;
+    }
+    else
+    {
+      cursorIndex += numberOfCharacters;
+    }
+
+    return cursorIndex;
+  }
+
+  void UpdateCursorPosition()
+  {
+    CursorInfo cursorInfo;
+
+    GetCursorPosition( mPrimaryCursorPosition,
+                       cursorInfo );
+
+    mDecorator->SetPosition( PRIMARY_CURSOR,
+                             cursorInfo.primaryPosition.x,
+                             cursorInfo.primaryPosition.y,
+                             cursorInfo.primaryCursorHeight,
+                             cursorInfo.lineHeight );
+
+    if( cursorInfo.isSecondaryCursor )
+    {
+      mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
+      mDecorator->SetPosition( SECONDARY_CURSOR,
+                               cursorInfo.secondaryPosition.x,
+                               cursorInfo.secondaryPosition.y,
+                               cursorInfo.secondaryCursorHeight,
+                               cursorInfo.lineHeight );
+    }
+    else
+    {
+      mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+    }
+
+    mUpdateCursorPosition = false;
+    mDecoratorUpdated = true;
+  }
+
+  LogicalModelPtr              mLogicalModel;
+  VisualModelPtr               mVisualModel;
+  DecoratorPtr                 mDecorator;
+  FontDefaults*                mFontDefaults;
+  TextAbstraction::FontClient& mFontClient;
+  std::string                  mPlaceholderText;
 
   /**
    * This is used to delay handling events until after the model has been updated.
 
   /**
    * This is used to delay handling events until after the model has been updated.
@@ -523,31 +958,6 @@ struct Controller::TextInput
   bool mUpdateCursorPosition       : 1; ///< True if the visual position of the cursor must be recalculated
 };
 
   bool mUpdateCursorPosition       : 1; ///< True if the visual position of the cursor must be recalculated
 };
 
-struct Controller::FontDefaults
-{
-  FontDefaults()
-  : mDefaultPointSize(0.0f),
-    mFontId(0u)
-  {
-  }
-
-  FontId GetFontId( TextAbstraction::FontClient& fontClient )
-  {
-    if( !mFontId )
-    {
-      Dali::TextAbstraction::PointSize26Dot6 pointSize = mDefaultPointSize*64;
-      mFontId = fontClient.GetFontId( mDefaultFontFamily, mDefaultFontStyle, pointSize );
-    }
-
-    return mFontId;
-  }
-
-  std::string mDefaultFontFamily;
-  std::string mDefaultFontStyle;
-  float mDefaultPointSize;
-  FontId mFontId;
-};
-
 struct Controller::Impl
 {
   Impl( ControlInterface& controlInterface )
 struct Controller::Impl
 {
   Impl( ControlInterface& controlInterface )
@@ -561,6 +971,7 @@ struct Controller::Impl
     mLayoutEngine(),
     mModifyEvents(),
     mControlSize(),
     mLayoutEngine(),
     mModifyEvents(),
     mControlSize(),
+    mAlignmentOffset(),
     mOperationsPending( NO_OPERATION ),
     mRecalculateNaturalSize( true )
   {
     mOperationsPending( NO_OPERATION ),
     mRecalculateNaturalSize( true )
   {
@@ -570,6 +981,13 @@ struct Controller::Impl
     mFontClient = TextAbstraction::FontClient::Get();
 
     mView.SetVisualModel( mVisualModel );
     mFontClient = TextAbstraction::FontClient::Get();
 
     mView.SetVisualModel( mVisualModel );
+
+    // Set the text properties to default
+    mVisualModel->SetTextColor( Color::WHITE );
+    mVisualModel->SetShadowOffset( Vector2::ZERO );
+    mVisualModel->SetShadowColor( Vector4::ZERO );
+    mVisualModel->SetUnderlineEnabled( false );
+    mVisualModel->SetUnderlineHeight( 0.0f );
   }
 
   ~Impl()
   }
 
   ~Impl()
@@ -587,6 +1005,7 @@ struct Controller::Impl
   LayoutEngine mLayoutEngine;              ///< The layout engine.
   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
   Size mControlSize;                       ///< The size of the control.
   LayoutEngine mLayoutEngine;              ///< The layout engine.
   std::vector<ModifyEvent> mModifyEvents;  ///< Temporary stores the text set until the next relayout.
   Size mControlSize;                       ///< The size of the control.
+  Vector2 mAlignmentOffset;                ///< Vertical and horizontal offset of the whole text inside the control due to alignment.
   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
   bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
 };
   OperationsMask mOperationsPending;       ///< Operations pending to be done to layout the text.
   bool mRecalculateNaturalSize:1;          ///< Whether the natural size needs to be recalculated.
 };
@@ -656,6 +1075,19 @@ void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
+
+  // Clear the font-specific data
+  mImpl->mLogicalModel->mFontRuns.Clear();
+  mImpl->mVisualModel->mGlyphs.Clear();
+  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+  mImpl->mVisualModel->mCharactersToGlyph.Clear();
+  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+  mImpl->mVisualModel->mGlyphPositions.Clear();
+  mImpl->mVisualModel->mLines.Clear();
+  mImpl->mVisualModel->ClearCaches();
+
+  RequestRelayout();
 }
 
 const std::string& Controller::GetDefaultFontFamily() const
 }
 
 const std::string& Controller::GetDefaultFontFamily() const
@@ -665,7 +1097,7 @@ const std::string& Controller::GetDefaultFontFamily() const
     return mImpl->mFontDefaults->mDefaultFontFamily;
   }
 
     return mImpl->mFontDefaults->mDefaultFontFamily;
   }
 
-  return EMPTY_STRING;
+  return String::EMPTY;;
 }
 
 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
 }
 
 void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
@@ -679,6 +1111,19 @@ void Controller::SetDefaultFontStyle( const std::string& defaultFontStyle )
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
+
+  // Clear the font-specific data
+  mImpl->mLogicalModel->mFontRuns.Clear();
+  mImpl->mVisualModel->mGlyphs.Clear();
+  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+  mImpl->mVisualModel->mCharactersToGlyph.Clear();
+  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+  mImpl->mVisualModel->mGlyphPositions.Clear();
+  mImpl->mVisualModel->mLines.Clear();
+  mImpl->mVisualModel->ClearCaches();
+
+  RequestRelayout();
 }
 
 const std::string& Controller::GetDefaultFontStyle() const
 }
 
 const std::string& Controller::GetDefaultFontStyle() const
@@ -688,7 +1133,7 @@ const std::string& Controller::GetDefaultFontStyle() const
     return mImpl->mFontDefaults->mDefaultFontStyle;
   }
 
     return mImpl->mFontDefaults->mDefaultFontStyle;
   }
 
-  return EMPTY_STRING;
+  return String::EMPTY;
 }
 
 void Controller::SetDefaultPointSize( float pointSize )
 }
 
 void Controller::SetDefaultPointSize( float pointSize )
@@ -702,6 +1147,19 @@ void Controller::SetDefaultPointSize( float pointSize )
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
   mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   mImpl->mOperationsPending = ALL_OPERATIONS;
   mImpl->mRecalculateNaturalSize = true;
+
+  // Clear the font-specific data
+  mImpl->mLogicalModel->mFontRuns.Clear();
+  mImpl->mVisualModel->mGlyphs.Clear();
+  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+  mImpl->mVisualModel->mCharactersToGlyph.Clear();
+  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+  mImpl->mVisualModel->mGlyphPositions.Clear();
+  mImpl->mVisualModel->mLines.Clear();
+  mImpl->mVisualModel->ClearCaches();
+
+  RequestRelayout();
 }
 
 float Controller::GetDefaultPointSize() const
 }
 
 float Controller::GetDefaultPointSize() const
@@ -714,7 +1172,7 @@ float Controller::GetDefaultPointSize() const
   return 0.0f;
 }
 
   return 0.0f;
 }
 
-void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
+void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters ) const
 {
   if( mImpl->mFontDefaults )
   {
 {
   if( mImpl->mFontDefaults )
   {
@@ -728,11 +1186,75 @@ void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharact
   }
 }
 
   }
 }
 
+const Vector4& Controller::GetTextColor() const
+{
+  return mImpl->mVisualModel->GetTextColor();
+}
+
+const Vector2& Controller::GetShadowOffset() const
+{
+  return mImpl->mVisualModel->GetShadowOffset();
+}
+
+const Vector4& Controller::GetShadowColor() const
+{
+  return mImpl->mVisualModel->GetShadowColor();
+}
+
+const Vector4& Controller::GetUnderlineColor() const
+{
+  return mImpl->mVisualModel->GetUnderlineColor();
+}
+
+bool Controller::IsUnderlineEnabled() const
+{
+  return mImpl->mVisualModel->IsUnderlineEnabled();
+}
+
+float Controller::GetUnderlineHeight() const
+{
+  return mImpl->mVisualModel->GetUnderlineHeight();
+}
+
+void Controller::SetTextColor( const Vector4& textColor )
+{
+  mImpl->mVisualModel->SetTextColor( textColor );
+}
+
+void Controller::SetShadowOffset( const Vector2& shadowOffset )
+{
+  mImpl->mVisualModel->SetShadowOffset( shadowOffset );
+}
+
+void Controller::SetShadowColor( const Vector4& shadowColor )
+{
+  mImpl->mVisualModel->SetShadowColor( shadowColor );
+}
+
+void Controller::SetUnderlineColor( const Vector4& color )
+{
+  mImpl->mVisualModel->SetUnderlineColor( color );
+}
+
+void Controller::SetUnderlineEnabled( bool enabled )
+{
+  mImpl->mVisualModel->SetUnderlineEnabled( enabled );
+}
+
+void Controller::SetUnderlineHeight( float height )
+{
+  mImpl->mVisualModel->SetUnderlineHeight( height );
+}
+
 void Controller::EnableTextInput( DecoratorPtr decorator )
 {
   if( !mImpl->mTextInput )
   {
 void Controller::EnableTextInput( DecoratorPtr decorator )
 {
   if( !mImpl->mTextInput )
   {
-    mImpl->mTextInput = new TextInput( mImpl->mLogicalModel, mImpl->mVisualModel, decorator );
+    mImpl->mTextInput = new TextInput( mImpl->mLogicalModel,
+                                       mImpl->mVisualModel,
+                                       decorator,
+                                       mImpl->mFontDefaults,
+                                       mImpl->mFontClient );
   }
 }
 
   }
 }
 
@@ -772,6 +1294,11 @@ const Vector2& Controller::GetScrollPosition() const
   return Vector2::ZERO;
 }
 
   return Vector2::ZERO;
 }
 
+const Vector2& Controller::GetAlignmentOffset() const
+{
+  return mImpl->mAlignmentOffset;
+}
+
 Vector3 Controller::GetNaturalSize()
 {
   Vector3 naturalSize;
 Vector3 Controller::GetNaturalSize()
 {
   Vector3 naturalSize;
@@ -867,7 +1394,7 @@ float Controller::GetHeightForWidth( float width )
   return layoutSize.height;
 }
 
   return layoutSize.height;
 }
 
-bool Controller::Relayout( const Vector2& size )
+bool Controller::Relayout( const Size& size )
 {
   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
   {
 {
   if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
   {
@@ -906,10 +1433,13 @@ bool Controller::Relayout( const Vector2& size )
   // Do not re-do any operation until something changes.
   mImpl->mOperationsPending = NO_OPERATION;
 
   // Do not re-do any operation until something changes.
   mImpl->mOperationsPending = NO_OPERATION;
 
+  // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
+  CalculateTextAlignment( size );
+
   if( mImpl->mTextInput )
   {
     // Move the cursor, grab handle etc.
   if( mImpl->mTextInput )
   {
     // Move the cursor, grab handle etc.
-    updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize ) || updated;
+    updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize, mImpl->mAlignmentOffset ) || updated;
   }
 
   return updated;
   }
 
   return updated;
@@ -951,6 +1481,7 @@ void Controller::ReplaceTextEvent( const std::string& text )
   mImpl->mLogicalModel->mLineBreakInfo.Clear();
   mImpl->mLogicalModel->mWordBreakInfo.Clear();
   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
   mImpl->mLogicalModel->mLineBreakInfo.Clear();
   mImpl->mLogicalModel->mWordBreakInfo.Clear();
   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+  mImpl->mLogicalModel->mCharacterDirections.Clear();
   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
@@ -961,6 +1492,7 @@ void Controller::ReplaceTextEvent( const std::string& text )
   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
   mImpl->mVisualModel->mGlyphPositions.Clear();
   mImpl->mVisualModel->mLines.Clear();
   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
   mImpl->mVisualModel->mGlyphPositions.Clear();
   mImpl->mVisualModel->mLines.Clear();
+  mImpl->mVisualModel->ClearCaches();
 
   //  Convert text into UTF-32
   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
 
   //  Convert text into UTF-32
   Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
@@ -1003,6 +1535,7 @@ void Controller::InsertTextEvent( const std::string& text )
   mImpl->mLogicalModel->mLineBreakInfo.Clear();
   mImpl->mLogicalModel->mWordBreakInfo.Clear();
   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
   mImpl->mLogicalModel->mLineBreakInfo.Clear();
   mImpl->mLogicalModel->mWordBreakInfo.Clear();
   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+  mImpl->mLogicalModel->mCharacterDirections.Clear();
   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
@@ -1013,6 +1546,7 @@ void Controller::InsertTextEvent( const std::string& text )
   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
   mImpl->mVisualModel->mGlyphPositions.Clear();
   mImpl->mVisualModel->mLines.Clear();
   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
   mImpl->mVisualModel->mGlyphPositions.Clear();
   mImpl->mVisualModel->mLines.Clear();
+  mImpl->mVisualModel->ClearCaches();
 
   //  Convert text into UTF-32
   Vector<Character> utf32Characters;
 
   //  Convert text into UTF-32
   Vector<Character> utf32Characters;
@@ -1067,6 +1601,7 @@ void Controller::DeleteTextEvent()
   mImpl->mLogicalModel->mLineBreakInfo.Clear();
   mImpl->mLogicalModel->mWordBreakInfo.Clear();
   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
   mImpl->mLogicalModel->mLineBreakInfo.Clear();
   mImpl->mLogicalModel->mWordBreakInfo.Clear();
   mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+  mImpl->mLogicalModel->mCharacterDirections.Clear();
   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
   mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
   mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
   mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
@@ -1077,6 +1612,7 @@ void Controller::DeleteTextEvent()
   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
   mImpl->mVisualModel->mGlyphPositions.Clear();
   mImpl->mVisualModel->mLines.Clear();
   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
   mImpl->mVisualModel->mGlyphPositions.Clear();
   mImpl->mVisualModel->mLines.Clear();
+  mImpl->mVisualModel->ClearCaches();
 
   // Delte at current cursor position
   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
 
   // Delte at current cursor position
   Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
@@ -1208,8 +1744,21 @@ void Controller::UpdateModel( OperationsMask operationsRequired )
       // TODO: consider if the mirrored string can be stored as well.
 
       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
       // TODO: consider if the mirrored string can be stored as well.
 
       textMirrored = GetMirroredText( utf32Characters, mirroredUtf32Characters );
+
+      // Only set the character directions if there is right to left characters.
+      Vector<CharacterDirection>& directions = mImpl->mLogicalModel->mCharacterDirections;
+      directions.Resize( numberOfCharacters );
+
+      GetCharactersDirection( bidirectionalInfo,
+                              directions );
     }
     }
-  }
+    else
+    {
+      // There is no right to left characters. Clear the directions vector.
+      mImpl->mLogicalModel->mCharacterDirections.Clear();
+    }
+
+   }
 
   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
 
   Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
   Vector<CharacterIndex>& glyphsToCharactersMap = mImpl->mVisualModel->mGlyphsToCharacters;
@@ -1225,6 +1774,10 @@ void Controller::UpdateModel( OperationsMask operationsRequired )
                glyphs,
                glyphsToCharactersMap,
                charactersPerGlyph );
                glyphs,
                glyphsToCharactersMap,
                charactersPerGlyph );
+
+    // Create the 'number of glyphs' per character and the glyph to character conversion tables.
+    mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
+    mImpl->mVisualModel->CreateCharacterToGlyphTable( numberOfCharacters );
   }
 
   const Length numberOfGlyphs = glyphs.Count();
   }
 
   const Length numberOfGlyphs = glyphs.Count();
@@ -1233,16 +1786,9 @@ void Controller::UpdateModel( OperationsMask operationsRequired )
   {
     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
   }
   {
     mImpl->mFontClient.GetGlyphMetrics( glyphs.Begin(), numberOfGlyphs );
   }
-
-  if( 0u != numberOfGlyphs )
-  {
-    // Create the glyph to character conversion table and the 'number of glyphs' per character.
-    mImpl->mVisualModel->CreateCharacterToGlyphTable(numberOfCharacters );
-    mImpl->mVisualModel->CreateGlyphsPerCharacterTable( numberOfCharacters );
-  }
 }
 
 }
 
-bool Controller::DoRelayout( const Vector2& size,
+bool Controller::DoRelayout( const Size& size,
                              OperationsMask operationsRequired,
                              Size& layoutSize )
 {
                              OperationsMask operationsRequired,
                              Size& layoutSize )
 {
@@ -1259,6 +1805,12 @@ bool Controller::DoRelayout( const Vector2& size,
 
     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
 
 
     Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs();
 
+    if( 0u == numberOfGlyphs )
+    {
+      // Nothing else to do if there is no glyphs.
+      return true;
+    }
+
     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
     Vector<LineBreakInfo>& lineBreakInfo = mImpl->mLogicalModel->mLineBreakInfo;
     Vector<WordBreakInfo>& wordBreakInfo = mImpl->mLogicalModel->mWordBreakInfo;
     Vector<GlyphInfo>& glyphs = mImpl->mVisualModel->mGlyphs;
@@ -1352,6 +1904,7 @@ bool Controller::DoRelayout( const Vector2& size,
       if( ALIGN & operations )
       {
         mImpl->mLayoutEngine.Align( layoutParameters,
       if( ALIGN & operations )
       {
         mImpl->mLayoutEngine.Align( layoutParameters,
+                                    layoutSize,
                                     lines,
                                     glyphPositions );
       }
                                     lines,
                                     glyphPositions );
       }
@@ -1371,6 +1924,70 @@ bool Controller::DoRelayout( const Vector2& size,
   return viewUpdated;
 }
 
   return viewUpdated;
 }
 
+void Controller::CalculateTextAlignment( const Size& size )
+{
+  // Get the direction of the first character.
+  const CharacterDirection firstParagraphDirection = mImpl->mLogicalModel->GetCharacterDirection( 0u );
+
+  const Size& actualSize = mImpl->mVisualModel->GetActualSize();
+
+  // If the first paragraph is right to left swap ALIGN_BEGIN and ALIGN_END;
+  LayoutEngine::HorizontalAlignment horizontalAlignment = mImpl->mLayoutEngine.GetHorizontalAlignment();
+  if( firstParagraphDirection &&
+      ( LayoutEngine::HORIZONTAL_ALIGN_CENTER != horizontalAlignment ) )
+  {
+    if( LayoutEngine::HORIZONTAL_ALIGN_BEGIN == horizontalAlignment )
+    {
+      horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_END;
+    }
+    else
+    {
+      horizontalAlignment = LayoutEngine::HORIZONTAL_ALIGN_BEGIN;
+    }
+  }
+
+  switch( horizontalAlignment )
+  {
+    case LayoutEngine::HORIZONTAL_ALIGN_BEGIN:
+    {
+      mImpl->mAlignmentOffset.x = 0.f;
+      break;
+    }
+    case LayoutEngine::HORIZONTAL_ALIGN_CENTER:
+    {
+      const int intOffset = static_cast<int>( 0.5f * ( size.width - actualSize.width ) ); // try to avoid pixel alignment.
+      mImpl->mAlignmentOffset.x = static_cast<float>( intOffset );
+      break;
+    }
+    case LayoutEngine::HORIZONTAL_ALIGN_END:
+    {
+      mImpl->mAlignmentOffset.x = size.width - actualSize.width;
+      break;
+    }
+  }
+
+  const LayoutEngine::VerticalAlignment verticalAlignment = mImpl->mLayoutEngine.GetVerticalAlignment();
+  switch( verticalAlignment )
+  {
+    case LayoutEngine::VERTICAL_ALIGN_TOP:
+    {
+      mImpl->mAlignmentOffset.y = 0.f;
+      break;
+    }
+    case LayoutEngine::VERTICAL_ALIGN_CENTER:
+    {
+      const int intOffset = static_cast<int>( 0.5f * ( size.height - actualSize.height ) ); // try to avoid pixel alignment.
+      mImpl->mAlignmentOffset.y = static_cast<float>( intOffset );
+      break;
+    }
+    case LayoutEngine::VERTICAL_ALIGN_BOTTOM:
+    {
+      mImpl->mAlignmentOffset.y = size.height - actualSize.height;
+      break;
+    }
+  }
+}
+
 View& Controller::GetView()
 {
   return mImpl->mView;
 View& Controller::GetView()
 {
   return mImpl->mView;
@@ -1453,6 +2070,8 @@ bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent )
       mImpl->mModifyEvents.push_back( event );
     }
 
       mImpl->mModifyEvents.push_back( event );
     }
 
+    mImpl->mTextInput->ChangeState( TextInput::EDITING ); // todo Confirm this is the best place to change the state of
+
     RequestRelayout();
   }
 
     RequestRelayout();
   }