Corrects the position.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
index 5594c01..e13c842 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 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.
 
 // EXTERNAL INCLUDES
 #include <limits>
+#include <cmath>
 #include <dali/integration-api/debug.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
+#include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
@@ -49,9 +50,15 @@ namespace
 #endif
 
 const float MAX_FLOAT = std::numeric_limits<float>::max();
-const bool RTL = true;
-const float CURSOR_WIDTH = 1.f;
-const float LINE_SPACING= 0.f;
+const CharacterDirection LTR = false;
+const CharacterDirection RTL = !LTR;
+const float LINE_SPACING = 0.f;
+const float MIN_LINE_SIZE = 0.f;
+
+inline bool isEmptyLineAtLast( const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line )
+{
+  return ( (*line).characterRun.numberOfCharacters == 0 && line + 1u == lines.End() );
+}
 
 } //namespace
 
@@ -61,17 +68,18 @@ const float LINE_SPACING= 0.f;
 struct LineLayout
 {
   LineLayout()
-  : glyphIndex( 0u ),
-    characterIndex( 0u ),
-    numberOfGlyphs( 0u ),
-    numberOfCharacters( 0u ),
-    length( 0.f ),
-    extraBearing( 0.f ),
-    extraWidth( 0.f ),
-    wsLengthEndOfLine( 0.f ),
-    ascender( 0.f ),
-    descender( MAX_FLOAT ),
-    lineSpacing( 0.f )
+  : glyphIndex{ 0u },
+    characterIndex{ 0u },
+    numberOfGlyphs{ 0u },
+    numberOfCharacters{ 0u },
+    ascender{ -MAX_FLOAT },
+    descender{ MAX_FLOAT },
+    lineSpacing{ 0.f },
+    penX{ 0.f },
+    previousAdvance{ 0.f },
+    length{ 0.f },
+    whiteSpaceLengthEndOfLine{ 0.f },
+    direction{ LTR }
   {}
 
   ~LineLayout()
@@ -83,34 +91,48 @@ struct LineLayout
     characterIndex = 0u;
     numberOfGlyphs = 0u;
     numberOfCharacters = 0u;
-    length = 0.f;
-    extraBearing = 0.f;
-    extraWidth = 0.f;
-    wsLengthEndOfLine = 0.f;
-    ascender = 0.f;
+    ascender = -MAX_FLOAT;
     descender = MAX_FLOAT;
+    direction = LTR;
+  }
+
+  GlyphIndex         glyphIndex;                ///< Index of the first glyph to be laid-out.
+  CharacterIndex     characterIndex;            ///< Index of the first character to be laid-out.
+  Length             numberOfGlyphs;            ///< The number of glyph which fit in one line.
+  Length             numberOfCharacters;        ///< The number of characters which fit in one line.
+  float              ascender;                  ///< The maximum ascender of all fonts in the line.
+  float              descender;                 ///< The minimum descender of all fonts in the line.
+  float              lineSpacing;               ///< The line spacing
+  float              penX;                      ///< The origin of the current glyph ( is the start point plus the accumulation of all advances ).
+  float              previousAdvance;           ///< The advance of the previous glyph.
+  float              length;                    ///< The current length of the line.
+  float              whiteSpaceLengthEndOfLine; ///< The length of the white spaces at the end of the line.
+  CharacterDirection direction;
+};
+
+struct LayoutBidiParameters
+{
+  void Clear()
+  {
+    paragraphDirection = LTR;
+    bidiParagraphIndex = 0u;
+    bidiLineIndex = 0u;
+    isBidirectional = false;
   }
 
-  GlyphIndex     glyphIndex;         ///< Index of the first glyph to be laid-out.
-  CharacterIndex characterIndex;     ///< Index of the first character to be laid-out.
-  Length         numberOfGlyphs;     ///< The number of glyph which fit in one line.
-  Length         numberOfCharacters; ///< The number of characters which fit in one line.
-  float          length;             ///< The addition of the advance metric of all the glyphs which fit in one line.
-  float          extraBearing;       ///< The extra width to be added to the line's length when the bearing of the first glyph is negative.
-  float          extraWidth;         ///< The extra width to be added to the line's length when the bearing + width of the last glyph is greater than the advance.
-  float          wsLengthEndOfLine;  ///< The length of the white spaces at the end of the line.
-  float          ascender;           ///< The maximum ascender of all fonts in the line.
-  float          descender;          ///< The minimum descender of all fonts in the line.
-  float          lineSpacing;        ///< The line spacing
+  CharacterDirection paragraphDirection = LTR;   ///< The paragraph's direction.
+  BidirectionalRunIndex bidiParagraphIndex = 0u; ///< Index to the paragraph's bidi info.
+  BidirectionalLineRunIndex bidiLineIndex = 0u;  ///< Index where to insert the next bidi line info.
+  bool isBidirectional = false;                  ///< Whether the text is bidirectional.
 };
 
 struct Engine::Impl
 {
   Impl()
-  : mLayout( Layout::Engine::SINGLE_LINE_BOX ),
-    mCursorWidth( CURSOR_WIDTH ),
-    mDefaultLineSpacing( LINE_SPACING ),
-    mPreviousCharacterExtraWidth( 0.0f )
+  : mLayout{ Layout::Engine::SINGLE_LINE_BOX },
+    mCursorWidth{ 0.f },
+    mDefaultLineSpacing{ LINE_SPACING },
+    mDefaultLineSize{ MIN_LINE_SIZE }
   {
   }
 
@@ -142,8 +164,12 @@ struct Engine::Impl
     // Sets the minimum descender.
     lineLayout.descender = std::min( lineLayout.descender, fontMetrics.descender );
 
-    // set the line spacing
-    lineLayout.lineSpacing = mDefaultLineSpacing;
+    // Sets the line size
+    lineLayout.lineSpacing = mDefaultLineSize - ( lineLayout.ascender + -lineLayout.descender );
+    lineLayout.lineSpacing = lineLayout.lineSpacing < 0.f ? 0.f : lineLayout.lineSpacing;
+
+    // Add the line spacing
+    lineLayout.lineSpacing += mDefaultLineSpacing;
   }
 
   /**
@@ -157,18 +183,12 @@ struct Engine::Impl
   {
     lineLayout.numberOfCharacters += tmpLineLayout.numberOfCharacters;
     lineLayout.numberOfGlyphs += tmpLineLayout.numberOfGlyphs;
-    lineLayout.length += tmpLineLayout.length;
 
-    if( 0.f < tmpLineLayout.length )
-    {
-      lineLayout.length += lineLayout.wsLengthEndOfLine;
+    lineLayout.penX = tmpLineLayout.penX;
+    lineLayout.previousAdvance = tmpLineLayout.previousAdvance;
 
-    lineLayout.wsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine;
-    }
-    else
-    {
-      lineLayout.wsLengthEndOfLine += tmpLineLayout.wsLengthEndOfLine;
-    }
+    lineLayout.length = tmpLineLayout.length;
+    lineLayout.whiteSpaceLengthEndOfLine = tmpLineLayout.whiteSpaceLengthEndOfLine;
 
     // Sets the maximum ascender.
     lineLayout.ascender = std::max( lineLayout.ascender, tmpLineLayout.ascender );
@@ -177,35 +197,261 @@ struct Engine::Impl
     lineLayout.descender = std::min( lineLayout.descender, tmpLineLayout.descender );
   }
 
+  void LayoutRightToLeft( const Parameters& parameters,
+                          const BidirectionalLineInfoRun& bidirectionalLineInfo,
+                          float& length,
+                          float& whiteSpaceLengthEndOfLine )
+  {
+    const Character* const textBuffer = parameters.textModel->mLogicalModel->mText.Begin();
+    const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+    const GlyphInfo* const glyphsBuffer = parameters.textModel->mVisualModel->mGlyphs.Begin();
+    const GlyphIndex* const charactersToGlyphsBuffer = parameters.textModel->mVisualModel->mCharactersToGlyph.Begin();
+
+    const float outlineWidth = static_cast<float>( parameters.textModel->GetOutlineWidth() );
+    const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+
+    CharacterIndex characterLogicalIndex = 0u;
+    CharacterIndex characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+
+    if( RTL == bidirectionalLineInfo.direction )
+    {
+      while( TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) ) )
+      {
+        const GlyphInfo& glyphInfo = *( glyphsBuffer + *( charactersToGlyphsBuffer + characterVisualIndex ) );
+
+        whiteSpaceLengthEndOfLine += glyphInfo.advance;
+
+        ++characterLogicalIndex;
+        characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+      }
+    }
+
+    const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+
+    // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
+    const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                   lastGlyphOfParagraphPlusOne,
+                                                                   charactersPerGlyphBuffer );
+
+    GlyphMetrics glyphMetrics;
+    GetGlyphsMetrics( glyphIndex,
+                      numberOfGLyphsInGroup,
+                      glyphMetrics,
+                      glyphsBuffer,
+                      mMetrics );
+
+    float penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
+
+    // Traverses the characters of the right to left paragraph.
+    for( ; characterLogicalIndex < bidirectionalLineInfo.characterRun.numberOfCharacters; )
+    {
+      // Convert the character in the logical order into the character in the visual order.
+      const CharacterIndex characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *( bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex );
+      const bool isWhiteSpace = TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) );
+
+      const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+
+      // Check whether this glyph comes from a character that is shaped in multiple glyphs.
+      const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                     lastGlyphOfParagraphPlusOne,
+                                                                     charactersPerGlyphBuffer );
+
+      characterLogicalIndex += *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( glyphIndex,
+                        numberOfGLyphsInGroup,
+                        glyphMetrics,
+                        glyphsBuffer,
+                        mMetrics );
+
+      if( isWhiteSpace )
+      {
+        if( RTL == bidirectionalLineInfo.direction )
+        {
+          length += glyphMetrics.advance;
+        }
+        else
+        {
+          whiteSpaceLengthEndOfLine += glyphMetrics.advance;
+        }
+        penX += glyphMetrics.advance;
+      }
+      else
+      {
+        if( LTR == bidirectionalLineInfo.direction )
+        {
+          whiteSpaceLengthEndOfLine = 0.f;
+        }
+        length = std::max( length, penX + glyphMetrics.xBearing + glyphMetrics.width );
+        penX += ( glyphMetrics.advance + parameters.interGlyphExtraAdvance );
+      }
+    }
+  }
+
+  void ReorderBiDiLayout( const Parameters& parameters,
+                          LayoutBidiParameters& bidiParameters,
+                          const LineLayout& currentLineLayout,
+                          LineLayout& lineLayout,
+                          bool breakInCharacters )
+  {
+    const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+
+    // The last glyph to be laid-out.
+    const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+
+    const Vector<BidirectionalParagraphInfoRun>& bidirectionalParagraphsInfo = parameters.textModel->mLogicalModel->mBidirectionalParagraphInfo;
+
+    const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo = bidirectionalParagraphsInfo[bidiParameters.bidiParagraphIndex];
+    if( ( lineLayout.characterIndex >= bidirectionalParagraphInfo.characterRun.characterIndex ) &&
+        ( lineLayout.characterIndex < bidirectionalParagraphInfo.characterRun.characterIndex + bidirectionalParagraphInfo.characterRun.numberOfCharacters ) )
+    {
+      Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = parameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+      // Sets the visual to logical map tables needed to reorder the text.
+      ReorderLine( bidirectionalParagraphInfo,
+                   bidirectionalLinesInfo,
+                   bidiParameters.bidiLineIndex,
+                   lineLayout.characterIndex,
+                   lineLayout.numberOfCharacters,
+                   bidiParameters.paragraphDirection );
+
+      // Recalculate the length of the line and update the layout.
+      const BidirectionalLineInfoRun& bidirectionalLineInfo = *( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+      if( !bidirectionalLineInfo.isIdentity )
+      {
+        float length = 0.f;
+        float whiteSpaceLengthEndOfLine = 0.f;
+        LayoutRightToLeft( parameters,
+                           bidirectionalLineInfo,
+                           length,
+                           whiteSpaceLengthEndOfLine );
+
+        lineLayout.whiteSpaceLengthEndOfLine = whiteSpaceLengthEndOfLine;
+        if( !Equals( length, lineLayout.length ) )
+        {
+          const bool isMultiline = mLayout == MULTI_LINE_BOX;
+
+          if( isMultiline && ( length > parameters.boundingBox.width ) )
+          {
+            if( breakInCharacters || ( isMultiline && ( 0u == currentLineLayout.numberOfGlyphs ) ) )
+            {
+              // The word doesn't fit in one line. It has to be split by character.
+
+              // Remove the last laid out glyph(s) as they doesn't fit.
+              for( GlyphIndex glyphIndex = lineLayout.glyphIndex + lineLayout.numberOfGlyphs - 1u; glyphIndex >= lineLayout.glyphIndex; )
+              {
+                const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                               lastGlyphOfParagraphPlusOne,
+                                                                               charactersPerGlyphBuffer );
+
+                const Length numberOfCharacters = *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+
+                lineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
+                lineLayout.numberOfCharacters -= numberOfCharacters;
+
+                AdjustLayout( parameters,
+                              bidiParameters,
+                              bidirectionalParagraphInfo,
+                              lineLayout );
+
+                if( lineLayout.length < parameters.boundingBox.width )
+                {
+                  break;
+                }
+
+                if( glyphIndex < numberOfGLyphsInGroup )
+                {
+                  // avoids go under zero for an unsigned int.
+                  break;
+                }
+
+                glyphIndex -= numberOfGLyphsInGroup;
+              }
+            }
+            else
+            {
+              lineLayout  = currentLineLayout;
+
+              AdjustLayout( parameters,
+                            bidiParameters,
+                            bidirectionalParagraphInfo,
+                            lineLayout );
+            }
+          }
+          else
+          {
+            lineLayout.length = std::max( length, lineLayout.length );
+          }
+        }
+      }
+    }
+  }
+
+  void AdjustLayout( const Parameters& parameters,
+                     LayoutBidiParameters& bidiParameters,
+                     const BidirectionalParagraphInfoRun& bidirectionalParagraphInfo,
+                     LineLayout& lineLayout )
+  {
+    Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = parameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+    // Remove current reordered line.
+    bidirectionalLinesInfo.Erase( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+    // Re-build the conversion table without the removed glyphs.
+    ReorderLine( bidirectionalParagraphInfo,
+                 bidirectionalLinesInfo,
+                 bidiParameters.bidiLineIndex,
+                 lineLayout.characterIndex,
+                 lineLayout.numberOfCharacters,
+                 bidiParameters.paragraphDirection );
+
+    const BidirectionalLineInfoRun& bidirectionalLineInfo = *( bidirectionalLinesInfo.Begin() + bidiParameters.bidiLineIndex );
+
+    float length = 0.f;
+    float whiteSpaceLengthEndOfLine = 0.f;
+    LayoutRightToLeft( parameters,
+                       bidirectionalLineInfo,
+                       length,
+                       whiteSpaceLengthEndOfLine );
+
+    lineLayout.length = length;
+    lineLayout.whiteSpaceLengthEndOfLine = whiteSpaceLengthEndOfLine;
+  }
+
   /**
    * Retrieves the line layout for a given box width.
    *
-   * @note This method lais out text as it were left to right. At this point is not possible to reorder the line
-   *       because the number of characters of the line is not known (one of the responsabilities of this method
-   *       is calculate that). Due to glyph's 'x' bearing, width and advance, when right to left or mixed right to left
-   *       and left to right text is laid-out, it can be small differences in the line length. One solution is to
-   *       reorder and re-lay out the text after this method and add or remove one extra glyph if needed. However,
-   *       this method calculates which are the first and last glyphs of the line (the ones that causes the
-   *       differences). This is a good point to check if there is problems with the text exceeding the boundaries
-   *       of the control when there is right to left text.
+   * @note This method starts to layout text as if it was left to right. However, it might be differences in the length
+   *       of the line if it's a bidirectional one. If the paragraph is bidirectional, this method will call a function
+   *       to reorder the line and recalculate its length.
    *
+
    * @param[in] parameters The layout parameters.
+   * @param[] bidiParameters Bidirectional info for the current line.
    * @param[out] lineLayout The line layout.
-   * @param[in,out] paragraphDirection in: the current paragraph's direction, out: the next paragraph's direction. Is set after a must break.
    * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ).
    */
   void GetLineLayoutForBox( const Parameters& parameters,
+                            LayoutBidiParameters& bidiParameters,
                             LineLayout& lineLayout,
-                            CharacterDirection& paragraphDirection,
                             bool completelyFill )
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n" );
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  initial glyph index : %d\n", lineLayout.glyphIndex );
-    // Stores temporary line layout which has not been added to the final line layout.
-    LineLayout tmpLineLayout;
+
+    const Character* const textBuffer = parameters.textModel->mLogicalModel->mText.Begin();
+    const Length* const charactersPerGlyphBuffer = parameters.textModel->mVisualModel->mCharactersPerGlyph.Begin();
+    const GlyphInfo* const glyphsBuffer = parameters.textModel->mVisualModel->mGlyphs.Begin();
+    const CharacterIndex* const glyphsToCharactersBuffer = parameters.textModel->mVisualModel->mGlyphsToCharacters.Begin();
+    const LineBreakInfo* const lineBreakInfoBuffer = parameters.textModel->mLogicalModel->mLineBreakInfo.Begin();
+
+    const float outlineWidth = static_cast<float>( parameters.textModel->GetOutlineWidth() );
+    const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
 
     const bool isMultiline = mLayout == MULTI_LINE_BOX;
-    const bool isWordLaidOut = parameters.lineWrapMode == Text::LineWrap::WORD;
+    const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD;
 
     // The last glyph to be laid-out.
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
@@ -217,26 +463,27 @@ struct Engine::Impl
     // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
     const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( lineLayout.glyphIndex,
                                                                    lastGlyphOfParagraphPlusOne,
-                                                                   parameters.charactersPerGlyphBuffer );
+                                                                   charactersPerGlyphBuffer );
 
     GlyphMetrics glyphMetrics;
     GetGlyphsMetrics( lineLayout.glyphIndex,
                       numberOfGLyphsInGroup,
                       glyphMetrics,
-                      parameters.glyphsBuffer,
+                      glyphsBuffer,
                       mMetrics );
 
     // Set the direction of the first character of the line.
-    lineLayout.characterIndex = *( parameters.glyphsToCharactersBuffer + lineLayout.glyphIndex );
-    const CharacterDirection firstCharacterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + lineLayout.characterIndex );
-    CharacterDirection previousCharacterDirection = firstCharacterDirection;
+    lineLayout.characterIndex = *( glyphsToCharactersBuffer + lineLayout.glyphIndex );
 
-    const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
-    float tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+    // Stores temporary line layout which has not been added to the final line layout.
+    LineLayout tmpLineLayout;
 
-    float tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
+    // Initialize the start point.
 
-    tmpLineLayout.length += mCursorWidth; // Added to give some space to the cursor.
+    // The initial start point is zero. However it needs a correction according the 'x' bearing of the first glyph.
+    // i.e. if the bearing of the first glyph is negative it may exceed the boundaries of the text area.
+    // It needs to add as well space for the cursor if the text is in edit mode and extra space in case the text is outlined.
+    tmpLineLayout.penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
 
     // Calculate the line height if there is no characters.
     FontId lastFontId = glyphMetrics.fontId;
@@ -252,16 +499,16 @@ struct Engine::Impl
       // Check whether this glyph comes from a character that is shaped in multiple glyphs.
       const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
                                                                      lastGlyphOfParagraphPlusOne,
-                                                                     parameters.charactersPerGlyphBuffer );
+                                                                     charactersPerGlyphBuffer );
 
       GlyphMetrics glyphMetrics;
       GetGlyphsMetrics( glyphIndex,
                         numberOfGLyphsInGroup,
                         glyphMetrics,
-                        parameters.glyphsBuffer,
+                        glyphsBuffer,
                         mMetrics );
 
-      const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup  == parameters.totalNumberOfGlyphs;
+      const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup  == totalNumberOfGlyphs;
 
       // Check if the font of the current glyph is the same of the previous one.
       // If it's different the ascender and descender need to be updated.
@@ -274,13 +521,13 @@ struct Engine::Impl
       // Get the character indices for the current glyph. The last character index is needed
       // because there are glyphs formed by more than one character but their break info is
       // given only for the last character.
-      const Length charactersPerGlyph = *( parameters.charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+      const Length charactersPerGlyph = *( charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
       const bool hasCharacters = charactersPerGlyph > 0u;
-      const CharacterIndex characterFirstIndex = *( parameters.glyphsToCharactersBuffer + glyphIndex );
+      const CharacterIndex characterFirstIndex = *( glyphsToCharactersBuffer + glyphIndex );
       const CharacterIndex characterLastIndex = characterFirstIndex + ( hasCharacters ? charactersPerGlyph - 1u : 0u );
 
       // Get the line break info for the current character.
-      const LineBreakInfo lineBreakInfo = hasCharacters ? *( parameters.lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
+      const LineBreakInfo lineBreakInfo = hasCharacters ? *( lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
 
       // Increase the number of characters.
       tmpLineLayout.numberOfCharacters += charactersPerGlyph;
@@ -289,126 +536,36 @@ struct Engine::Impl
       tmpLineLayout.numberOfGlyphs += numberOfGLyphsInGroup;
 
       // Check whether is a white space.
-      const Character character = *( parameters.textBuffer + characterFirstIndex );
+      const Character character = *( textBuffer + characterFirstIndex );
       const bool isWhiteSpace = TextAbstraction::IsWhiteSpace( character );
 
-      // Used to restore the temporal line layout when a single word does not fit in the control's width and is split by character.
-      const float previousTmpLineLength = tmpLineLayout.length;
-      const float previousTmpExtraBearing = tmpExtraBearing;
-      const float previousTmpExtraWidth = tmpExtraWidth;
+      // Calculate the length of the line.
 
-      // Get the character's direction.
-      const CharacterDirection characterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + characterFirstIndex );
+      // Used to restore the temporal line layout when a single word does not fit in the control's width and is split by character.
+      const float previousTmpPenX = tmpLineLayout.penX;
+      const float previousTmpAdvance = tmpLineLayout.previousAdvance;
+      const float previousTmpLength = tmpLineLayout.length;
+      const float previousTmpWhiteSpaceLengthEndOfLine = tmpLineLayout.whiteSpaceLengthEndOfLine;
 
-      // Increase the accumulated length.
       if( isWhiteSpace )
       {
         // Add the length to the length of white spaces at the end of the line.
-        tmpLineLayout.wsLengthEndOfLine += glyphMetrics.advance; // The advance is used as the width is always zero for the white spaces.
+        tmpLineLayout.whiteSpaceLengthEndOfLine += glyphMetrics.advance; // The advance is used as the width is always zero for the white spaces.
       }
       else
       {
-        // Add as well any previous white space length.
-        tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine + glyphMetrics.advance;
+        tmpLineLayout.penX += tmpLineLayout.previousAdvance + tmpLineLayout.whiteSpaceLengthEndOfLine;
+        tmpLineLayout.previousAdvance = ( glyphMetrics.advance + parameters.interGlyphExtraAdvance );
 
-        // An extra space may be added to the line for the first and last glyph of the line.
-        // If the bearing of the first glyph is negative, its positive value needs to be added.
-        // If the bearing plus the width of the last glyph is greater than the advance, the difference
-        // needs to be added.
-
-        if( characterDirection == paragraphDirection )
-        {
-          if( RTL == characterDirection )
-          {
-            //       <--
-            // |   Rrrrr|
-            // or
-            // |  Rllrrr|
-            // or
-            // |lllrrrrr|
-            // |     Rll|
-            //
-
-            tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
-          }
-          else // LTR
-          {
-            //  -->
-            // |lllL    |
-            // or
-            // |llrrL   |
-            // or
-            // |lllllrrr|
-            // |rrL     |
-            //
-
-            const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
-            tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
-            tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
-          }
-        }
-        else
-        {
-          if( characterDirection != previousCharacterDirection )
-          {
-            if( RTL == characterDirection )
-            {
-              //  -->
-              // |lllR    |
-
-              const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
-              tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
-              tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
-            }
-            else // LTR
-            {
-              //       <--
-              // |   Lrrrr|
-
-              tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
-            }
-          }
-          else if( characterDirection == firstCharacterDirection )
-          {
-            if( RTL == characterDirection )
-            {
-              //  -->
-              // |llllllrr|
-              // |Rr      |
-
-              tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
-            }
-            else // LTR
-            {
-              //       <--
-              // |llllrrrr|
-              // |     llL|
-
-              const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
-              tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
-              tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
-            }
-          }
-        }
+        tmpLineLayout.length = std::max( tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.xBearing + glyphMetrics.width );
 
         // Clear the white space length at the end of the line.
-        tmpLineLayout.wsLengthEndOfLine = 0.f;
+        tmpLineLayout.whiteSpaceLengthEndOfLine = 0.f;
       }
 
-      // If calculation is end but wsLengthEndOfLine is exist, it means end of text is space.
-      // Merge remained length.
-      if ( !parameters.ignoreSpaceAfterText && glyphIndex == lastGlyphOfParagraphPlusOne-1 && tmpLineLayout.wsLengthEndOfLine > 0 )
-      {
-        tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine;
-        tmpLineLayout.wsLengthEndOfLine = 0u;
-      }
-
-      // Save the current extra width to compare with the next one
-      mPreviousCharacterExtraWidth = tmpExtraWidth;
-
       // Check if the accumulated length fits in the width of the box.
-      if( ( completelyFill || isMultiline )  && !(parameters.ignoreSpaceAfterText && isWhiteSpace) &&
-          ( tmpExtraBearing + lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpExtraWidth > parameters.boundingBox.width ) )
+      if( ( completelyFill || isMultiline ) && !isWhiteSpace &&
+          ( tmpLineLayout.length > parameters.boundingBox.width ) )
       {
         // Current word does not fit in the box's width.
         if( !oneWordLaidOut || completelyFill )
@@ -420,9 +577,11 @@ struct Engine::Impl
           {
             tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
             tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
-            tmpLineLayout.length = previousTmpLineLength;
-            tmpExtraBearing = previousTmpExtraBearing;
-            tmpExtraWidth = previousTmpExtraWidth;
+
+            tmpLineLayout.penX = previousTmpPenX;
+            tmpLineLayout.previousAdvance = previousTmpAdvance;
+            tmpLineLayout.length = previousTmpLength;
+            tmpLineLayout.whiteSpaceLengthEndOfLine = previousTmpWhiteSpaceLengthEndOfLine;
           }
 
           // Add part of the word to the line layout.
@@ -433,30 +592,39 @@ struct Engine::Impl
           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Current word does not fit.\n" );
         }
 
-        lineLayout.extraBearing = tmpExtraBearing;
-        lineLayout.extraWidth = tmpExtraWidth;
-
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox.\n" );
 
+        // Reorder the RTL line.
+        if( bidiParameters.isBidirectional )
+        {
+          ReorderBiDiLayout( parameters,
+                             bidiParameters,
+                             lineLayout,
+                             lineLayout,
+                             true );
+        }
+
         return;
       }
 
       if( ( isMultiline || isLastGlyph ) &&
           ( TextAbstraction::LINE_MUST_BREAK == lineBreakInfo ) )
       {
+        LineLayout currentLineLayout = lineLayout;
+
         // Must break the line. Update the line layout and return.
         MergeLineLayout( lineLayout, tmpLineLayout );
 
-        // Set the next paragraph's direction.
-        if( !isLastGlyph &&
-            ( NULL != parameters.characterDirectionBuffer ) )
+       // Reorder the RTL line.
+        if( bidiParameters.isBidirectional )
         {
-          paragraphDirection = *( parameters.characterDirectionBuffer + 1u + characterLastIndex );
+          ReorderBiDiLayout( parameters,
+                             bidiParameters,
+                             currentLineLayout,
+                             lineLayout,
+                             false );
         }
 
-        lineLayout.extraBearing = tmpExtraBearing;
-        lineLayout.extraWidth = tmpExtraWidth;
-
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
 
@@ -476,19 +644,16 @@ struct Engine::Impl
         tmpLineLayout.Clear();
       }
 
-      previousCharacterDirection = characterDirection;
       glyphIndex += numberOfGLyphsInGroup;
     }
 
-    lineLayout.extraBearing = tmpExtraBearing;
-    lineLayout.extraWidth = tmpExtraWidth;
-
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
   }
 
   void SetGlyphPositions( const GlyphInfo* const glyphsBuffer,
                           Length numberOfGlyphs,
                           float outlineWidth,
+                          float interGlyphExtraAdvance,
                           Vector2* glyphPositionsBuffer )
   {
     // Traverse the glyphs and set the positions.
@@ -498,8 +663,7 @@ struct Engine::Impl
     // so the penX position needs to be moved to the right.
 
     const GlyphInfo& glyph = *glyphsBuffer;
-    float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing + outlineWidth : outlineWidth;
-
+    float penX = -glyph.xBearing + mCursorWidth + outlineWidth;
 
     for( GlyphIndex i = 0u; i < numberOfGlyphs; ++i )
     {
@@ -509,7 +673,70 @@ struct Engine::Impl
       position.x = penX + glyph.xBearing;
       position.y = -glyph.yBearing;
 
+      penX += ( glyph.advance + interGlyphExtraAdvance );
+    }
+  }
+
+  void SetGlyphPositions( const Parameters& layoutParameters,
+                          Vector2* glyphPositionsBuffer,
+                          LayoutBidiParameters& layoutBidiParameters,
+                          const LineLayout& layout )
+  {
+    const Character* const textBuffer = layoutParameters.textModel->mLogicalModel->mText.Begin();
+    const BidirectionalLineInfoRun& bidiLine = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo[layoutBidiParameters.bidiLineIndex];
+    const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+    const GlyphIndex* const charactersToGlyphsBuffer = layoutParameters.textModel->mVisualModel->mCharactersToGlyph.Begin();
+    const Length* const glyphsPerCharacterBuffer = layoutParameters.textModel->mVisualModel->mGlyphsPerCharacter.Begin();
+
+    CharacterIndex characterLogicalIndex = 0u;
+    CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+
+    float penX = 0.f;
+    while( TextAbstraction::IsWhiteSpace( *( textBuffer + characterVisualIndex ) ) )
+    {
+      const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+      const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+
+      Vector2& position = *( glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex );
+      position.x = penX;
+      position.y = -glyph.yBearing;
+
       penX += glyph.advance;
+
+      ++characterLogicalIndex;
+      characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+    }
+
+    const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex );
+    const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+
+    penX += -glyph.xBearing;
+
+    // Traverses the characters of the right to left paragraph.
+    for( ; characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
+         ++characterLogicalIndex )
+    {
+      // Convert the character in the logical order into the character in the visual order.
+      const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
+
+      // Get the number of glyphs of the character.
+      const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterVisualIndex );
+
+      for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
+      {
+        // Convert the character in the visual order into the glyph in the visual order.
+        const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex ) + index;
+
+        DALI_ASSERT_DEBUG( glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count() );
+
+        const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
+        Vector2& position = *( glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex );
+
+        position.x = penX + glyph.xBearing;
+        position.y = -glyph.yBearing;
+
+       penX += ( glyph.advance + layoutParameters.interGlyphExtraAdvance );
+      }
     }
   }
 
@@ -528,7 +755,7 @@ struct Engine::Impl
                               Length& linesCapacity,
                               bool updateCurrentBuffer )
   {
-    LineRun* linesBuffer = NULL;
+    LineRun* linesBuffer = nullptr;
     // Reserve more space for the next lines.
     linesCapacity *= 2u;
     if( updateCurrentBuffer )
@@ -561,13 +788,13 @@ struct Engine::Impl
    * return Whether the line is ellipsized.
    */
   bool EllipsisLine( const Parameters& layoutParameters,
+                     LayoutBidiParameters& layoutBidiParameters,
                      const LineLayout& layout,
                      Size& layoutSize,
                      LineRun* linesBuffer,
                      Vector2* glyphPositionsBuffer,
                      Length& numberOfLines,
                      float penY,
-                     CharacterDirection currentParagraphDirection,
                      bool& isAutoScrollEnabled )
   {
     const bool ellipsis = isAutoScrollEnabled ? ( penY - layout.descender > layoutParameters.boundingBox.height ) :
@@ -583,7 +810,7 @@ struct Engine::Impl
       // The last line needs to be completely filled with characters.
       // Part of a word may be used.
 
-      LineRun* lineRun = NULL;
+      LineRun* lineRun = nullptr;
       LineLayout ellipsisLayout;
       if( 0u != numberOfLines )
       {
@@ -606,18 +833,17 @@ struct Engine::Impl
       }
 
       GetLineLayoutForBox( layoutParameters,
+                           layoutBidiParameters,
                            ellipsisLayout,
-                           currentParagraphDirection,
                            true );
 
       lineRun->glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
       lineRun->characterRun.characterIndex = ellipsisLayout.characterIndex;
       lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
       lineRun->width = ellipsisLayout.length;
-      lineRun->extraLength =  std::ceil( ( ellipsisLayout.wsLengthEndOfLine > 0.f ) ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.extraWidth : 0.f );
+      lineRun->extraLength = std::ceil( ellipsisLayout.whiteSpaceLengthEndOfLine );
       lineRun->ascender = ellipsisLayout.ascender;
       lineRun->descender = ellipsisLayout.descender;
-      lineRun->direction = !RTL;
       lineRun->ellipsis = true;
 
       layoutSize.width = layoutParameters.boundingBox.width;
@@ -626,10 +852,50 @@ struct Engine::Impl
         layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
       }
 
-      SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
-                         ellipsisLayout.numberOfGlyphs,
-                         layoutParameters.outlineWidth,
-                         glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
+      const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+      const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
+      const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+      if( layoutBidiParameters.isBidirectional )
+      {
+        layoutBidiParameters.bidiLineIndex = 0u;
+        for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLinesInfo.Begin(),
+               endIt = bidirectionalLinesInfo.End();
+             it != endIt;
+             ++it, ++layoutBidiParameters.bidiLineIndex )
+        {
+          const BidirectionalLineInfoRun& run = *it;
+
+          if( ellipsisLayout.characterIndex == run.characterRun.characterIndex )
+          {
+            // Found where to insert the bidi line info.
+            break;
+          }
+        }
+      }
+
+      const BidirectionalLineInfoRun* const bidirectionalLineInfo = ( layoutBidiParameters.isBidirectional && !bidirectionalLinesInfo.Empty() ) ? &bidirectionalLinesInfo[layoutBidiParameters.bidiLineIndex] : nullptr;
+
+      if( ( nullptr != bidirectionalLineInfo ) &&
+          !bidirectionalLineInfo->isIdentity &&
+          ( ellipsisLayout.characterIndex == bidirectionalLineInfo->characterRun.characterIndex ) )
+      {
+        lineRun->direction = RTL;
+        SetGlyphPositions( layoutParameters,
+                           glyphPositionsBuffer,
+                           layoutBidiParameters,
+                           ellipsisLayout );
+      }
+      else
+      {
+        lineRun->direction = LTR;
+        SetGlyphPositions( glyphsBuffer + lineRun->glyphRun.glyphIndex,
+                           ellipsisLayout.numberOfGlyphs,
+                           outlineWidth,
+                           layoutParameters.interGlyphExtraAdvance,
+                           glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
+      }
     }
 
     return ellipsis;
@@ -661,36 +927,24 @@ struct Engine::Impl
     lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
     lineRun.characterRun.characterIndex = layout.characterIndex;
     lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
-    lineRun.lineSpacing = mDefaultLineSpacing;
-
-    if( isLastLine && !layoutParameters.isLastNewParagraph )
-    {
-      const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
-      if( MULTI_LINE_BOX == mLayout )
-      {
-        lineRun.width = ( width > layoutParameters.boundingBox.width ) ? layoutParameters.boundingBox.width : width;
-      }
-      else
-      {
-        lineRun.width = width;
-      }
+    lineRun.width = layout.length;
+    lineRun.extraLength = std::ceil( layout.whiteSpaceLengthEndOfLine );
 
-      lineRun.extraLength = 0.f;
-    }
-    else
-    {
-      lineRun.width = layout.extraBearing + layout.length + layout.extraWidth;
-      lineRun.extraLength = std::ceil( ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f );
-    }
 
     // Rounds upward to avoid a non integer size.
     lineRun.width = std::ceil( lineRun.width );
 
     lineRun.ascender = layout.ascender;
     lineRun.descender = layout.descender;
-    lineRun.direction = !RTL;
+    lineRun.direction = layout.direction;
     lineRun.ellipsis = false;
 
+    lineRun.lineSpacing = mDefaultLineSize - ( lineRun.ascender + -lineRun.descender );
+    lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing;
+
+    lineRun.lineSpacing += mDefaultLineSpacing;
+
+
     // Update the actual size.
     if( lineRun.width > layoutSize.width )
     {
@@ -717,8 +971,10 @@ struct Engine::Impl
                          LineRun* linesBuffer,
                          Length& numberOfLines )
   {
+    const Vector<GlyphInfo>& glyphs = layoutParameters.textModel->mVisualModel->mGlyphs;
+
     // Need to add a new line with no characters but with height to increase the layoutSize.height
-    const GlyphInfo& glyphInfo = *( layoutParameters.glyphsBuffer + layoutParameters.totalNumberOfGlyphs - 1u );
+    const GlyphInfo& glyphInfo = glyphs[glyphs.Count() - 1u];
 
     Text::FontMetrics fontMetrics;
     if( 0u != glyphInfo.fontId )
@@ -738,9 +994,13 @@ struct Engine::Impl
     lineRun.descender = fontMetrics.descender;
     lineRun.extraLength = 0.f;
     lineRun.alignmentOffset = 0.f;
-    lineRun.direction = !RTL;
+    lineRun.direction = LTR;
     lineRun.ellipsis = false;
-    lineRun.lineSpacing = mDefaultLineSpacing;
+
+    lineRun.lineSpacing = mDefaultLineSize - ( lineRun.ascender + -lineRun.descender );
+    lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing;
+
+    lineRun.lineSpacing += mDefaultLineSpacing;
 
     layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
   }
@@ -799,9 +1059,7 @@ struct Engine::Impl
     }
   }
 
-  bool LayoutText( const Parameters& layoutParameters,
-                   Vector<Vector2>& glyphPositions,
-                   Vector<LineRun>& lines,
+  bool LayoutText( Parameters& layoutParameters,
                    Size& layoutSize,
                    bool elideTextEnabled,
                    bool& isAutoScrollEnabled )
@@ -809,6 +1067,8 @@ struct Engine::Impl
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->LayoutText\n" );
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height );
 
+    Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
+
     if( 0u == layoutParameters.numberOfGlyphs )
     {
       // Add an extra line if the last character is a new paragraph character and the last line doesn't have zero characters.
@@ -848,6 +1108,8 @@ struct Engine::Impl
     }
 
     const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
+    const Length totalNumberOfGlyphs = layoutParameters.textModel->mVisualModel->mGlyphs.Count();
+    Vector<Vector2>& glyphPositions = layoutParameters.textModel->mVisualModel->mGlyphPositions;
 
     // In a previous layout, an extra line with no characters may have been added if the text ended with a new paragraph character.
     // This extra line needs to be removed.
@@ -856,22 +1118,29 @@ struct Engine::Impl
       Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
 
       if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
-          ( lastGlyphPlusOne == layoutParameters.totalNumberOfGlyphs ) )
+          ( lastGlyphPlusOne == totalNumberOfGlyphs ) )
       {
         lines.Remove( lastLine );
       }
     }
 
-    // Set the first paragraph's direction.
-    CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
+    // Retrieve BiDi info.
+    const bool hasBidiParagraphs = !layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo.Empty();
+
+    const CharacterIndex* const glyphsToCharactersBuffer = hasBidiParagraphs ? layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin() : nullptr;
+    const Vector<BidirectionalParagraphInfoRun>& bidirectionalParagraphsInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo;
+    const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
+
+    // Set the layout bidirectional paramters.
+    LayoutBidiParameters layoutBidiParameters;
 
     // Whether the layout is being updated or set from scratch.
-    const bool updateCurrentBuffer = layoutParameters.numberOfGlyphs < layoutParameters.totalNumberOfGlyphs;
+    const bool updateCurrentBuffer = layoutParameters.numberOfGlyphs < totalNumberOfGlyphs;
 
-    Vector2* glyphPositionsBuffer = NULL;
+    Vector2* glyphPositionsBuffer = nullptr;
     Vector<Vector2> newGlyphPositions;
 
-    LineRun* linesBuffer = NULL;
+    LineRun* linesBuffer = nullptr;
     Vector<LineRun> newLines;
 
     // Estimate the number of lines.
@@ -896,17 +1165,74 @@ struct Engine::Impl
 
     float penY = CalculateLineOffset( lines,
                                       layoutParameters.startLineIndex );
-
     for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
     {
-      CharacterDirection currentParagraphDirection = paragraphDirection;
+      layoutBidiParameters.Clear();
+
+      if( hasBidiParagraphs )
+      {
+        const CharacterIndex startCharacterIndex = *( glyphsToCharactersBuffer + index );
+
+        for( Vector<BidirectionalParagraphInfoRun>::ConstIterator it = bidirectionalParagraphsInfo.Begin(),
+               endIt = bidirectionalParagraphsInfo.End();
+             it != endIt;
+             ++it, ++layoutBidiParameters.bidiParagraphIndex )
+        {
+          const BidirectionalParagraphInfoRun& run = *it;
+
+          const CharacterIndex lastCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters;
+
+          if( lastCharacterIndex <= startCharacterIndex )
+          {
+            // Do not process, the paragraph has already been processed.
+            continue;
+          }
+
+          if( startCharacterIndex >= run.characterRun.characterIndex && startCharacterIndex < lastCharacterIndex )
+          {
+            layoutBidiParameters.paragraphDirection = run.direction;
+            layoutBidiParameters.isBidirectional = true;
+          }
+
+          // Has already been found.
+          break;
+        }
+
+        if( layoutBidiParameters.isBidirectional )
+        {
+          for( Vector<BidirectionalLineInfoRun>::ConstIterator it = bidirectionalLinesInfo.Begin(),
+                 endIt = bidirectionalLinesInfo.End();
+               it != endIt;
+               ++it, ++layoutBidiParameters.bidiLineIndex )
+          {
+            const BidirectionalLineInfoRun& run = *it;
+
+            const CharacterIndex lastCharacterIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters;
+
+            if( lastCharacterIndex <= startCharacterIndex )
+            {
+              // skip
+              continue;
+            }
+
+            if( startCharacterIndex < lastCharacterIndex )
+            {
+              // Found where to insert the bidi line info.
+              break;
+            }
+          }
+        }
+      }
+
+      CharacterDirection currentParagraphDirection = layoutBidiParameters.paragraphDirection;
 
       // Get the layout for the line.
       LineLayout layout;
+      layout.direction = layoutBidiParameters.paragraphDirection;
       layout.glyphIndex = index;
       GetLineLayoutForBox( layoutParameters,
+                           layoutBidiParameters,
                            layout,
-                           paragraphDirection,
                            false );
 
       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex );
@@ -937,15 +1263,17 @@ struct Engine::Impl
       bool ellipsis = false;
       if( elideTextEnabled )
       {
+        layoutBidiParameters.paragraphDirection = currentParagraphDirection;
+
         // Does the ellipsis of the last line.
         ellipsis = EllipsisLine( layoutParameters,
+                                 layoutBidiParameters,
                                  layout,
                                  layoutSize,
                                  linesBuffer,
                                  glyphPositionsBuffer,
                                  numberOfLines,
                                  penY,
-                                 currentParagraphDirection,
                                  isAutoScrollEnabled );
       }
 
@@ -957,10 +1285,11 @@ struct Engine::Impl
       else
       {
         // Whether the last line has been laid-out.
-        const bool isLastLine = index + layout.numberOfGlyphs == layoutParameters.totalNumberOfGlyphs;
+        const bool isLastLine = index + layout.numberOfGlyphs == totalNumberOfGlyphs;
 
         if( numberOfLines == linesCapacity )
         {
+
           // Reserve more space for the next lines.
           linesBuffer = ResizeLinesBuffer( lines,
                                            newLines,
@@ -979,7 +1308,7 @@ struct Engine::Impl
 
         const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
 
-        if( ( nextIndex == layoutParameters.totalNumberOfGlyphs ) &&
+        if( ( nextIndex == totalNumberOfGlyphs ) &&
             layoutParameters.isLastNewParagraph &&
             ( mLayout == MULTI_LINE_BOX ) )
         {
@@ -1004,11 +1333,30 @@ struct Engine::Impl
                             numberOfLines );
         } // whether to add a last line.
 
-        // Sets the positions of the glyphs.
-        SetGlyphPositions( layoutParameters.glyphsBuffer + index,
-                           layout.numberOfGlyphs,
-                           layoutParameters.outlineWidth,
-                           glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
+        const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+        const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
+        const BidirectionalLineInfoRun* const bidirectionalLineInfo = ( layoutBidiParameters.isBidirectional && !bidirectionalLinesInfo.Empty() ) ? &bidirectionalLinesInfo[layoutBidiParameters.bidiLineIndex] : nullptr;
+
+        if( ( nullptr != bidirectionalLineInfo ) &&
+            !bidirectionalLineInfo->isIdentity &&
+            ( layout.characterIndex == bidirectionalLineInfo->characterRun.characterIndex ) )
+        {
+          SetGlyphPositions( layoutParameters,
+                             glyphPositionsBuffer,
+                             layoutBidiParameters,
+                             layout );
+        }
+        else
+        {
+
+          // Sets the positions of the glyphs.
+          SetGlyphPositions( glyphsBuffer + index,
+                             layout.numberOfGlyphs,
+                             outlineWidth,
+                             layoutParameters.interGlyphExtraAdvance,
+                             glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
+        }
 
         // Updates the vertical pen's position.
         penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
@@ -1023,7 +1371,7 @@ struct Engine::Impl
       glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
                              newGlyphPositions.Begin(),
                              newGlyphPositions.End() );
-      glyphPositions.Resize( layoutParameters.totalNumberOfGlyphs );
+      glyphPositions.Resize( totalNumberOfGlyphs );
 
       newLines.Resize( numberOfLines );
 
@@ -1064,65 +1412,6 @@ struct Engine::Impl
     return true;
   }
 
-  void ReLayoutRightToLeftLines( const Parameters& layoutParameters,
-                                 CharacterIndex startIndex,
-                                 Length numberOfCharacters,
-                                 Vector<Vector2>& glyphPositions )
-  {
-    const CharacterIndex lastCharacterIndex = startIndex + numberOfCharacters;
-
-    // Traverses the paragraphs with right to left characters.
-    for( LineIndex lineIndex = 0u; lineIndex < layoutParameters.numberOfBidirectionalInfoRuns; ++lineIndex )
-    {
-      const BidirectionalLineInfoRun& bidiLine = *( layoutParameters.lineBidirectionalInfoRunsBuffer + lineIndex );
-
-      if( startIndex >= bidiLine.characterRun.characterIndex + bidiLine.characterRun.numberOfCharacters )
-      {
-        // Do not reorder the line if it has been already reordered.
-        continue;
-      }
-
-      if( bidiLine.characterRun.characterIndex >= lastCharacterIndex )
-      {
-        // Do not reorder the lines after the last requested character.
-        break;
-      }
-
-      const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *bidiLine.visualToLogicalMap;
-      const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
-
-      float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing - layoutParameters.outlineWidth : -layoutParameters.outlineWidth;
-
-      Vector2* glyphPositionsBuffer = glyphPositions.Begin();
-
-      // Traverses the characters of the right to left paragraph.
-      for( CharacterIndex characterLogicalIndex = 0u;
-           characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
-           ++characterLogicalIndex )
-      {
-        // Convert the character in the logical order into the character in the visual order.
-        const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
-
-        // Get the number of glyphs of the character.
-        const Length numberOfGlyphs = *( layoutParameters.glyphsPerCharacterBuffer + characterVisualIndex );
-
-        for( GlyphIndex index = 0u; index < numberOfGlyphs; ++index )
-        {
-          // Convert the character in the visual order into the glyph in the visual order.
-          const GlyphIndex glyphIndex = *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) + index;
-
-          DALI_ASSERT_DEBUG( 0u <= glyphIndex && glyphIndex < layoutParameters.totalNumberOfGlyphs );
-
-          const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + glyphIndex );
-          Vector2& position = *( glyphPositionsBuffer + glyphIndex );
-
-          position.x = penX + glyph.xBearing;
-          penX += glyph.advance;
-        }
-      }
-    }
-  }
-
   void Align( const Size& size,
               CharacterIndex startIndex,
               Length numberOfCharacters,
@@ -1148,12 +1437,18 @@ struct Engine::Impl
         continue;
       }
 
-      if( line.characterRun.characterIndex >= lastCharacterPlusOne )
+      if( line.characterRun.characterIndex > lastCharacterPlusOne )
       {
         // Do not align lines beyond the last laid-out character.
         break;
       }
 
+      if( line.characterRun.characterIndex == lastCharacterPlusOne && !isEmptyLineAtLast( lines, it ) )
+      {
+        // Do not align lines beyond the last laid-out character unless the line is last and empty.
+        break;
+      }
+
       // Calculate the line's alignment offset accordingly with the align option,
       // the box width, line length, and the paragraph's direction.
       CalculateHorizontalAlignment( size.width,
@@ -1175,6 +1470,7 @@ struct Engine::Impl
   {
     line.alignmentOffset = 0.f;
     const bool isLineRTL = RTL == line.direction;
+
     // Whether to swap the alignment.
     // Swap if the line is RTL and is not required to match the direction of the system's language or if it's required to match the direction of the system's language and it's RTL.
     bool isLayoutRTL = isLineRTL;
@@ -1221,7 +1517,7 @@ struct Engine::Impl
           line.alignmentOffset -= line.extraLength;
         }
 
-        line.alignmentOffset = floorf( line.alignmentOffset ); // try to avoid pixel alignment.
+        line.alignmentOffset = std::floor( line.alignmentOffset ); // floor() avoids pixel alignment issues.
         break;
       }
       case HorizontalAlignment::END:
@@ -1261,7 +1557,7 @@ struct Engine::Impl
     line.descender = 0.f;
     line.extraLength = 0.f;
     line.alignmentOffset = 0.f;
-    line.direction = !RTL;
+    line.direction = LTR;
     line.ellipsis = false;
     line.lineSpacing = mDefaultLineSpacing;
   }
@@ -1269,13 +1565,13 @@ struct Engine::Impl
   Type mLayout;
   float mCursorWidth;
   float mDefaultLineSpacing;
-  float mPreviousCharacterExtraWidth;
+  float mDefaultLineSize;
 
   IntrusivePtr<Metrics> mMetrics;
 };
 
 Engine::Engine()
-: mImpl( NULL )
+: mImpl{ nullptr }
 {
   mImpl = new Engine::Impl();
 }
@@ -1311,32 +1607,17 @@ int Engine::GetCursorWidth() const
   return static_cast<int>( mImpl->mCursorWidth );
 }
 
-bool Engine::LayoutText( const Parameters& layoutParameters,
-                         Vector<Vector2>& glyphPositions,
-                         Vector<LineRun>& lines,
+bool Engine::LayoutText( Parameters& layoutParameters,
                          Size& layoutSize,
                          bool elideTextEnabled,
                          bool& isAutoScrollEnabled )
 {
   return mImpl->LayoutText( layoutParameters,
-                            glyphPositions,
-                            lines,
                             layoutSize,
                             elideTextEnabled,
                             isAutoScrollEnabled );
 }
 
-void Engine::ReLayoutRightToLeftLines( const Parameters& layoutParameters,
-                                       CharacterIndex startIndex,
-                                       Length numberOfCharacters,
-                                       Vector<Vector2>& glyphPositions )
-{
-  mImpl->ReLayoutRightToLeftLines( layoutParameters,
-                                   startIndex,
-                                   numberOfCharacters,
-                                   glyphPositions );
-}
-
 void Engine::Align( const Size& size,
                     CharacterIndex startIndex,
                     Length numberOfCharacters,
@@ -1366,6 +1647,16 @@ float Engine::GetDefaultLineSpacing() const
   return mImpl->mDefaultLineSpacing;
 }
 
+void Engine::SetDefaultLineSize( float lineSize )
+{
+  mImpl->mDefaultLineSize = lineSize;
+}
+
+float Engine::GetDefaultLineSize() const
+{
+  return mImpl->mDefaultLineSize;
+}
+
 } // namespace Layout
 
 } // namespace Text