Text cleaning.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
index 0c3d9df..f4e11bf 100755 (executable)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <limits>
+#include <cmath>
 #include <dali/integration-api/debug.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
 
@@ -49,10 +50,15 @@ namespace
 #endif
 
 const float MAX_FLOAT = std::numeric_limits<float>::max();
-const bool RTL = true;
-const float CURSOR_WIDTH = 1.f;
+const CharacterDirection LTR = false;
+const CharacterDirection RTL = !LTR;
 const float LINE_SPACING= 0.f;
 
+inline bool isEmptyLineAtLast( const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line )
+{
+  return ( (*line).characterRun.numberOfCharacters == 0 && line + 1u == lines.End() );
+}
+
 } //namespace
 
 /**
@@ -65,13 +71,13 @@ 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 ),
-    lineSpacing( 0.f )
+    lineSpacing( 0.f ),
+    penX( 0.f ),
+    previousAdvance( 0.f ),
+    length( 0.f ),
+    wsLengthEndOfLine( 0.f )
   {}
 
   ~LineLayout()
@@ -83,10 +89,6 @@ struct LineLayout
     characterIndex = 0u;
     numberOfGlyphs = 0u;
     numberOfCharacters = 0u;
-    length = 0.f;
-    extraBearing = 0.f;
-    extraWidth = 0.f;
-    wsLengthEndOfLine = 0.f;
     ascender = 0.f;
     descender = MAX_FLOAT;
   }
@@ -95,48 +97,52 @@ struct LineLayout
   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
+  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          wsLengthEndOfLine;  ///< The length of the white spaces at the end of the line.
 };
 
 struct Engine::Impl
 {
   Impl()
   : mLayout( Layout::Engine::SINGLE_LINE_BOX ),
-    mCursorWidth( CURSOR_WIDTH ),
-    mDefaultLineSpacing( LINE_SPACING ),
-    mPreviousCharacterExtraWidth( 0.0f )
+    mCursorWidth( 0.f ),
+    mDefaultLineSpacing( LINE_SPACING )
   {
   }
 
   /**
    * @brief Updates the line ascender and descender with the metrics of a new font.
    *
-   * @param[in] fontId The id of the new font.
+   * @param[in] glyphMetrics The metrics of the new font.
    * @param[in,out] lineLayout The line layout.
    */
-  void UpdateLineHeight( FontId fontId, LineLayout& lineLayout )
+  void UpdateLineHeight( const GlyphMetrics& glyphMetrics, LineLayout& lineLayout )
   {
     Text::FontMetrics fontMetrics;
-    mMetrics->GetFontMetrics( fontId, fontMetrics );
-
-    // Sets the maximum ascender.
-    if( fontMetrics.ascender > lineLayout.ascender )
+    if( 0u != glyphMetrics.fontId )
     {
-      lineLayout.ascender = fontMetrics.ascender;
+      mMetrics->GetFontMetrics( glyphMetrics.fontId, fontMetrics );
     }
-
-    // Sets the minimum descender.
-    if( fontMetrics.descender < lineLayout.descender )
+    else
     {
-      lineLayout.descender = fontMetrics.descender;
+      fontMetrics.ascender = glyphMetrics.fontHeight;
+      fontMetrics.descender = 0.f;
+      fontMetrics.height = fontMetrics.ascender;
+      fontMetrics.underlinePosition = 0.f;
+      fontMetrics.underlineThickness = 1.f;
     }
 
+    // Sets the maximum ascender.
+    lineLayout.ascender = std::max( lineLayout.ascender, fontMetrics.ascender );
+
+    // Sets the minimum descender.
+    lineLayout.descender = std::min( lineLayout.descender, fontMetrics.descender );
+
     // set the line spacing
     lineLayout.lineSpacing = mDefaultLineSpacing;
   }
@@ -152,28 +158,18 @@ 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.wsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine;
 
-    if( tmpLineLayout.ascender > lineLayout.ascender )
-    {
-      lineLayout.ascender = tmpLineLayout.ascender;
-    }
+    // Sets the maximum ascender.
+    lineLayout.ascender = std::max( lineLayout.ascender, tmpLineLayout.ascender );
 
-    if( tmpLineLayout.descender < lineLayout.descender )
-    {
-      lineLayout.descender = tmpLineLayout.descender;
-    }
+    // Sets the minimum descender.
+    lineLayout.descender = std::min( lineLayout.descender, tmpLineLayout.descender );
   }
 
   /**
@@ -200,11 +196,21 @@ struct Engine::Impl
   {
     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 bool hasBidiParagraphs = !parameters.textModel->mLogicalModel->mBidirectionalParagraphInfo.Empty();
+    const CharacterDirection* const characterDirectionBuffer = hasBidiParagraphs ? parameters.textModel->mLogicalModel->mCharacterDirections.Begin() : nullptr;
+
+    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;
@@ -216,30 +222,34 @@ 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 );
+
+    // Stores temporary line layout which has not been added to the final line layout.
+    LineLayout tmpLineLayout;
 
-    const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
-    float tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+    // Initialize the start point.
 
-    float tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
+    // 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;
 
-    tmpLineLayout.length += mCursorWidth; // Added to give some space to the cursor.
+    // Initialize the advance of the previous glyph.
+    tmpLineLayout.previousAdvance = 0.f;
 
     // Calculate the line height if there is no characters.
     FontId lastFontId = glyphMetrics.fontId;
-    UpdateLineHeight( lastFontId, tmpLineLayout );
+    UpdateLineHeight( glyphMetrics, tmpLineLayout );
 
     bool oneWordLaidOut = false;
 
@@ -251,35 +261,35 @@ 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.
       if( lastFontId != glyphMetrics.fontId )
       {
-        UpdateLineHeight( glyphMetrics.fontId, tmpLineLayout );
+        UpdateLineHeight( glyphMetrics, tmpLineLayout );
         lastFontId = glyphMetrics.fontId;
       }
 
       // 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;
@@ -288,18 +298,17 @@ 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 previousTmpWsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine;
 
-      // Increase the accumulated length.
       if( isWhiteSpace )
       {
         // Add the length to the length of white spaces at the end of the line.
@@ -307,107 +316,17 @@ struct Engine::Impl
       }
       else
       {
-        // Add as well any previous white space length.
-        tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine + glyphMetrics.advance;
-
-        // 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.penX += tmpLineLayout.previousAdvance + tmpLineLayout.wsLengthEndOfLine;
+        tmpLineLayout.previousAdvance = ( glyphMetrics.advance + parameters.interGlyphExtraAdvance );
+        tmpLineLayout.length = tmpLineLayout.penX + glyphMetrics.xBearing + glyphMetrics.width;
 
         // Clear the white space length at the end of the line.
         tmpLineLayout.wsLengthEndOfLine = 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 )
@@ -419,9 +338,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.wsLengthEndOfLine = previousTmpWsLengthEndOfLine;
           }
 
           // Add part of the word to the line layout.
@@ -432,9 +353,6 @@ 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" );
 
         return;
@@ -448,14 +366,11 @@ struct Engine::Impl
 
         // Set the next paragraph's direction.
         if( !isLastGlyph &&
-            ( NULL != parameters.characterDirectionBuffer ) )
+            ( nullptr != characterDirectionBuffer ) )
         {
-          paragraphDirection = *( parameters.characterDirectionBuffer + 1u + characterLastIndex );
+          paragraphDirection = *( characterDirectionBuffer + 1u + characterLastIndex );
         }
 
-        lineLayout.extraBearing = tmpExtraBearing;
-        lineLayout.extraWidth = tmpExtraWidth;
-
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
 
@@ -475,19 +390,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.
@@ -497,18 +409,17 @@ 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 )
     {
       const GlyphInfo& glyph = *( glyphsBuffer + i );
       Vector2& position = *( glyphPositionsBuffer + i );
 
-      position.x = penX + glyph.xBearing;
+      position.x = std::roundf( penX + glyph.xBearing );
       position.y = -glyph.yBearing;
 
-      penX += glyph.advance;
+      penX += ( glyph.advance + interGlyphExtraAdvance );
     }
   }
 
@@ -527,7 +438,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 )
@@ -555,6 +466,7 @@ struct Engine::Impl
    * @param[in,out] numberOfLines The number of laid-out lines.
    * @param[in] penY The vertical layout position.
    * @param[in] currentParagraphDirection The current paragraph's direction.
+   * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
    *
    * return Whether the line is ellipsized.
    */
@@ -565,20 +477,23 @@ struct Engine::Impl
                      Vector2* glyphPositionsBuffer,
                      Length& numberOfLines,
                      float penY,
-                     CharacterDirection currentParagraphDirection )
+                     CharacterDirection currentParagraphDirection,
+                     bool& isAutoScrollEnabled )
   {
-    const bool ellipsis = ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
-                            ( ( mLayout == SINGLE_LINE_BOX ) &&
-                              ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) );
+    const bool ellipsis = isAutoScrollEnabled ? ( penY - layout.descender > layoutParameters.boundingBox.height ) :
+                                                ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
+                                                  ( ( mLayout == SINGLE_LINE_BOX ) &&
+                                                    ( layout.length > layoutParameters.boundingBox.width ) ) );
 
     if( ellipsis )
     {
+      isAutoScrollEnabled = false;
       // Do not layout more lines if ellipsis is enabled.
 
       // 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 )
       {
@@ -609,10 +524,10 @@ struct Engine::Impl
       lineRun->characterRun.characterIndex = ellipsisLayout.characterIndex;
       lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters;
       lineRun->width = ellipsisLayout.length;
-      lineRun->extraLength =  ( ellipsisLayout.wsLengthEndOfLine > 0.f ) ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.extraWidth : 0.f;
+      lineRun->extraLength = std::ceil( ellipsisLayout.wsLengthEndOfLine );
       lineRun->ascender = ellipsisLayout.ascender;
       lineRun->descender = ellipsisLayout.descender;
-      lineRun->direction = !RTL;
+      lineRun->direction = LTR;
       lineRun->ellipsis = true;
 
       layoutSize.width = layoutParameters.boundingBox.width;
@@ -621,9 +536,13 @@ struct Engine::Impl
         layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
       }
 
-      SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
+      const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+      const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
+      SetGlyphPositions( glyphsBuffer + lineRun->glyphRun.glyphIndex,
                          ellipsisLayout.numberOfGlyphs,
-                         layoutParameters.outlineWidth,
+                         outlineWidth,
+                         layoutParameters.interGlyphExtraAdvance,
                          glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
     }
 
@@ -660,7 +579,7 @@ struct Engine::Impl
 
     if( isLastLine && !layoutParameters.isLastNewParagraph )
     {
-      const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
+      const float width = layout.length + layout.wsLengthEndOfLine;
       if( MULTI_LINE_BOX == mLayout )
       {
         lineRun.width = ( width > layoutParameters.boundingBox.width ) ? layoutParameters.boundingBox.width : width;
@@ -674,12 +593,16 @@ struct Engine::Impl
     }
     else
     {
-      lineRun.width = layout.extraBearing + layout.length + layout.extraWidth;
-      lineRun.extraLength = ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f;
+      lineRun.width = layout.length;
+      lineRun.extraLength = std::ceil( layout.wsLengthEndOfLine );
     }
+
+    // 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 = LTR;
     lineRun.ellipsis = false;
 
     // Update the actual size.
@@ -708,11 +631,16 @@ 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;
-    mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
+    if( 0u != glyphInfo.fontId )
+    {
+      mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
+    }
 
     LineRun& lineRun = *( linesBuffer + numberOfLines );
     ++numberOfLines;
@@ -726,7 +654,7 @@ 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;
 
@@ -791,7 +719,8 @@ struct Engine::Impl
                    Vector<Vector2>& glyphPositions,
                    Vector<LineRun>& lines,
                    Size& layoutSize,
-                   bool elideTextEnabled )
+                   bool elideTextEnabled,
+                   bool& isAutoScrollEnabled )
   {
     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 );
@@ -827,11 +756,15 @@ struct Engine::Impl
       UpdateLayoutSize( lines,
                         layoutSize );
 
+      // Rounds upward to avoid a non integer size.
+      layoutSize.height = std::ceil( layoutSize.height );
+
       // Nothing else do if there are no glyphs to layout.
       return false;
     }
 
     const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
+    const Length totalNumberOfGlyphs = layoutParameters.textModel->mVisualModel->mGlyphs.Count();
 
     // 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.
@@ -840,22 +773,27 @@ struct Engine::Impl
       Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
 
       if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
-          ( lastGlyphPlusOne == layoutParameters.totalNumberOfGlyphs ) )
+          ( lastGlyphPlusOne == totalNumberOfGlyphs ) )
       {
         lines.Remove( lastLine );
       }
     }
 
+    // Retrieve BiDi info.
+    const bool hasBidiParagraphs = !layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo.Empty();
+
+    const CharacterDirection* const characterDirectionBuffer = hasBidiParagraphs ? layoutParameters.textModel->mLogicalModel->mCharacterDirections.Begin() : nullptr;
+
     // Set the first paragraph's direction.
-    CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
+    CharacterDirection paragraphDirection = ( nullptr != characterDirectionBuffer ) ? *characterDirectionBuffer : LTR;
 
     // 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.
@@ -878,9 +816,14 @@ struct Engine::Impl
       linesBuffer = lines.Begin();
     }
 
+
+    const GlyphInfo* const glyphsBuffer = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
+    const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
     float penY = CalculateLineOffset( lines,
                                       layoutParameters.startLineIndex );
 
+
     for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
     {
       CharacterDirection currentParagraphDirection = paragraphDirection;
@@ -905,6 +848,10 @@ struct Engine::Impl
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n" );
 
         lines.Resize( numberOfLines );
+
+        // Rounds upward to avoid a non integer size.
+        layoutSize.height = std::ceil( layoutSize.height );
+
         return false;
       }
 
@@ -925,7 +872,8 @@ struct Engine::Impl
                                  glyphPositionsBuffer,
                                  numberOfLines,
                                  penY,
-                                 currentParagraphDirection );
+                                 currentParagraphDirection,
+                                 isAutoScrollEnabled );
       }
 
       if( ellipsis )
@@ -936,7 +884,7 @@ 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 )
         {
@@ -958,7 +906,7 @@ struct Engine::Impl
 
         const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
 
-        if( ( nextIndex == layoutParameters.totalNumberOfGlyphs ) &&
+        if( ( nextIndex == totalNumberOfGlyphs ) &&
             layoutParameters.isLastNewParagraph &&
             ( mLayout == MULTI_LINE_BOX ) )
         {
@@ -984,9 +932,10 @@ struct Engine::Impl
         } // whether to add a last line.
 
         // Sets the positions of the glyphs.
-        SetGlyphPositions( layoutParameters.glyphsBuffer + index,
+        SetGlyphPositions( glyphsBuffer + index,
                            layout.numberOfGlyphs,
-                           layoutParameters.outlineWidth,
+                           outlineWidth,
+                           layoutParameters.interGlyphExtraAdvance,
                            glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
 
         // Updates the vertical pen's position.
@@ -1002,7 +951,7 @@ struct Engine::Impl
       glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
                              newGlyphPositions.Begin(),
                              newGlyphPositions.End() );
-      glyphPositions.Resize( layoutParameters.totalNumberOfGlyphs );
+      glyphPositions.Resize( totalNumberOfGlyphs );
 
       newLines.Resize( numberOfLines );
 
@@ -1035,6 +984,9 @@ struct Engine::Impl
       lines.Resize( numberOfLines );
     }
 
+    // Rounds upward to avoid a non integer size.
+    layoutSize.height = std::ceil( layoutSize.height );
+
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
 
     return true;
@@ -1045,6 +997,11 @@ struct Engine::Impl
                                  Length numberOfCharacters,
                                  Vector<Vector2>& glyphPositions )
   {
+    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();
+    const float outlineWidth = static_cast<float>( layoutParameters.textModel->GetOutlineWidth() );
+
     const CharacterIndex lastCharacterIndex = startIndex + numberOfCharacters;
 
     // Traverses the paragraphs with right to left characters.
@@ -1065,9 +1022,9 @@ struct Engine::Impl
       }
 
       const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *bidiLine.visualToLogicalMap;
-      const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) );
+      const GlyphInfo& glyph = *( glyphsBuffer + *( charactersToGlyphsBuffer + characterVisualIndex ) );
 
-      float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing - layoutParameters.outlineWidth : -layoutParameters.outlineWidth;
+      float penX = -glyph.xBearing + outlineWidth + mCursorWidth;
 
       Vector2* glyphPositionsBuffer = glyphPositions.Begin();
 
@@ -1080,20 +1037,20 @@ struct Engine::Impl
         const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *( bidiLine.visualToLogicalMap + characterLogicalIndex );
 
         // Get the number of glyphs of the character.
-        const Length numberOfGlyphs = *( layoutParameters.glyphsPerCharacterBuffer + characterVisualIndex );
+        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 = *( layoutParameters.charactersToGlyphsBuffer + characterVisualIndex ) + index;
+          const GlyphIndex glyphIndex = *( charactersToGlyphsBuffer + characterVisualIndex ) + index;
 
-          DALI_ASSERT_DEBUG( 0u <= glyphIndex && glyphIndex < layoutParameters.totalNumberOfGlyphs );
+          DALI_ASSERT_DEBUG( 0u <= glyphIndex && glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count() );
 
-          const GlyphInfo& glyph = *( layoutParameters.glyphsBuffer + glyphIndex );
+          const GlyphInfo& glyph = *( glyphsBuffer + glyphIndex );
           Vector2& position = *( glyphPositionsBuffer + glyphIndex );
 
-          position.x = penX + glyph.xBearing;
-          penX += glyph.advance;
+          position.x = std::round( penX + glyph.xBearing );
+          penX += ( glyph.advance + layoutParameters.interGlyphExtraAdvance );
         }
       }
     }
@@ -1124,12 +1081,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,
@@ -1150,51 +1113,41 @@ struct Engine::Impl
                                      bool matchSystemLanguageDirection )
   {
     line.alignmentOffset = 0.f;
-    bool isRTL = RTL == line.direction;
+    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;
     float lineLength = line.width;
-    HorizontalAlignment::Type alignment = horizontalAlignment;
 
     // match align for system language direction
     if( matchSystemLanguageDirection )
     {
-      isRTL = layoutDirection == LayoutDirection::RIGHT_TO_LEFT;
+      // Swap the alignment type if the line is right to left.
+      isLayoutRTL = layoutDirection == LayoutDirection::RIGHT_TO_LEFT;
     }
-
-    // Swap the alignment type if the line is right to left.
-    if( isRTL )
-    {
-      switch( alignment )
-      {
-        case HorizontalAlignment::BEGIN:
-        {
-          alignment = HorizontalAlignment::END;
-          break;
-        }
-        case HorizontalAlignment::CENTER:
-        {
-          // Nothing to do.
-          break;
-        }
-        case HorizontalAlignment::END:
-        {
-          alignment = HorizontalAlignment::BEGIN;
-          break;
-        }
-      }
-
-    }
-
     // Calculate the horizontal line offset.
-    switch( alignment )
+    switch( horizontalAlignment )
     {
       case HorizontalAlignment::BEGIN:
       {
-        line.alignmentOffset = 0.f;
+        if( isLayoutRTL )
+        {
+          if( isLineRTL )
+          {
+            lineLength += line.extraLength;
+          }
 
-        if( isRTL )
+          line.alignmentOffset = boxWidth - lineLength;
+        }
+        else
         {
-          // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
-          line.alignmentOffset -= line.extraLength;
+          line.alignmentOffset = 0.f;
+
+          if( isLineRTL )
+          {
+            // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+            line.alignmentOffset -= line.extraLength;
+          }
         }
         break;
       }
@@ -1202,22 +1155,35 @@ struct Engine::Impl
       {
         line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
 
-        if( isRTL )
+        if( isLineRTL )
         {
           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:
       {
-        if( isRTL )
+        if( isLayoutRTL )
         {
-          lineLength += line.extraLength;
+          line.alignmentOffset = 0.f;
+
+          if( isLineRTL )
+          {
+            // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+            line.alignmentOffset -= line.extraLength;
+          }
         }
+        else
+        {
+          if( isLineRTL )
+          {
+            lineLength += line.extraLength;
+          }
 
-        line.alignmentOffset = boxWidth - lineLength;
+          line.alignmentOffset = boxWidth - lineLength;
+        }
         break;
       }
     }
@@ -1234,7 +1200,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;
   }
@@ -1242,13 +1208,12 @@ struct Engine::Impl
   Type mLayout;
   float mCursorWidth;
   float mDefaultLineSpacing;
-  float mPreviousCharacterExtraWidth;
 
   IntrusivePtr<Metrics> mMetrics;
 };
 
 Engine::Engine()
-: mImpl( NULL )
+: mImpl( nullptr )
 {
   mImpl = new Engine::Impl();
 }
@@ -1288,13 +1253,15 @@ bool Engine::LayoutText( const Parameters& layoutParameters,
                          Vector<Vector2>& glyphPositions,
                          Vector<LineRun>& lines,
                          Size& layoutSize,
-                         bool elideTextEnabled )
+                         bool elideTextEnabled,
+                         bool& isAutoScrollEnabled )
 {
   return mImpl->LayoutText( layoutParameters,
                             glyphPositions,
                             lines,
                             layoutSize,
-                            elideTextEnabled );
+                            elideTextEnabled,
+                            isAutoScrollEnabled );
 }
 
 void Engine::ReLayoutRightToLeftLines( const Parameters& layoutParameters,