Merge "If the height is small even if scrolling is enabled, it should be elide."...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
old mode 100644 (file)
new mode 100755 (executable)
index 54a957c..f97a8ea
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
 #include <dali/devel-api/text-abstraction/font-client.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
 #include <dali-toolkit/internal/text/bidirectional-line-info-run.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>
 
 namespace Dali
 {
@@ -36,6 +38,9 @@ namespace Toolkit
 namespace Text
 {
 
+namespace Layout
+{
+
 namespace
 {
 
@@ -46,6 +51,7 @@ namespace
 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;
 
 } //namespace
 
@@ -64,7 +70,8 @@ struct LineLayout
     extraWidth( 0.f ),
     wsLengthEndOfLine( 0.f ),
     ascender( 0.f ),
-    descender( MAX_FLOAT )
+    descender( MAX_FLOAT ),
+    lineSpacing( 0.f )
   {}
 
   ~LineLayout()
@@ -94,16 +101,16 @@ struct LineLayout
   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
 };
 
-struct LayoutEngine::Impl
+struct Engine::Impl
 {
   Impl()
-  : mLayout( LayoutEngine::SINGLE_LINE_BOX ),
-    mHorizontalAlignment( LayoutEngine::HORIZONTAL_ALIGN_BEGIN ),
-    mVerticalAlignment( LayoutEngine::VERTICAL_ALIGN_TOP ),
+  : mLayout( Layout::Engine::SINGLE_LINE_BOX ),
     mCursorWidth( CURSOR_WIDTH ),
-    mEllipsisEnabled( false )
+    mDefaultLineSpacing( LINE_SPACING ),
+    mPreviousCharacterExtraWidth( 0.0f )
   {
   }
 
@@ -129,6 +136,9 @@ struct LayoutEngine::Impl
     {
       lineLayout.descender = fontMetrics.descender;
     }
+
+    // set the line spacing
+    lineLayout.lineSpacing = mDefaultLineSpacing;
   }
 
   /**
@@ -172,7 +182,7 @@ struct LayoutEngine::Impl
    * @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
+   *       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
@@ -183,7 +193,7 @@ struct LayoutEngine::Impl
    * @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 LayoutParameters& parameters,
+  void GetLineLayoutForBox( const Parameters& parameters,
                             LineLayout& lineLayout,
                             CharacterDirection& paragraphDirection,
                             bool completelyFill )
@@ -194,67 +204,88 @@ struct LayoutEngine::Impl
     LineLayout tmpLineLayout;
 
     const bool isMultiline = mLayout == MULTI_LINE_BOX;
-    const GlyphIndex lastGlyphIndex = parameters.totalNumberOfGlyphs - 1u;
+    const bool isWordLaidOut = parameters.lineWrapMode == Text::LineWrap::WORD;
+
+    // The last glyph to be laid-out.
+    const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
 
     // If the first glyph has a negative bearing its absolute value needs to be added to the line length.
     // In the case the line starts with a right to left character, if the width is longer than the advance,
     // the difference needs to be added to the line length.
-    const GlyphInfo& glyphInfo = *( parameters.glyphsBuffer + lineLayout.glyphIndex );
+
+    // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
+    const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( lineLayout.glyphIndex,
+                                                                   lastGlyphOfParagraphPlusOne,
+                                                                   parameters.charactersPerGlyphBuffer );
+
+    GlyphMetrics glyphMetrics;
+    GetGlyphsMetrics( lineLayout.glyphIndex,
+                      numberOfGLyphsInGroup,
+                      glyphMetrics,
+                      parameters.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;
 
-    const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+    const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
     float tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
 
-    float tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+    float tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
 
     tmpLineLayout.length += mCursorWidth; // Added to give some space to the cursor.
 
     // Calculate the line height if there is no characters.
-    FontId lastFontId = glyphInfo.fontId;
+    FontId lastFontId = glyphMetrics.fontId;
     UpdateLineHeight( lastFontId, tmpLineLayout );
 
     bool oneWordLaidOut = false;
 
     for( GlyphIndex glyphIndex = lineLayout.glyphIndex;
-         glyphIndex < parameters.totalNumberOfGlyphs;
-         ++glyphIndex )
+         glyphIndex < lastGlyphOfParagraphPlusOne; )
     {
       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  glyph index : %d\n", glyphIndex );
-      const bool isLastGlyph = glyphIndex == lastGlyphIndex;
 
-      // Get the glyph info.
-      const GlyphInfo& glyphInfo = *( parameters.glyphsBuffer + glyphIndex );
+      // Check whether this glyph comes from a character that is shaped in multiple glyphs.
+      const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
+                                                                     lastGlyphOfParagraphPlusOne,
+                                                                     parameters.charactersPerGlyphBuffer );
+
+      GlyphMetrics glyphMetrics;
+      GetGlyphsMetrics( glyphIndex,
+                        numberOfGLyphsInGroup,
+                        glyphMetrics,
+                        parameters.glyphsBuffer,
+                        mMetrics );
+
+      const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup  == parameters.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 != glyphInfo.fontId )
+      if( lastFontId != glyphMetrics.fontId )
       {
-        UpdateLineHeight( glyphInfo.fontId, tmpLineLayout );
-        lastFontId = glyphInfo.fontId;
+        UpdateLineHeight( glyphMetrics.fontId, 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 );
+      const Length charactersPerGlyph = *( parameters.charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
+      const bool hasCharacters = charactersPerGlyph > 0u;
       const CharacterIndex characterFirstIndex = *( parameters.glyphsToCharactersBuffer + glyphIndex );
-      const CharacterIndex characterLastIndex = characterFirstIndex + ( ( 1u > charactersPerGlyph ) ? 0u : charactersPerGlyph - 1u );
+      const CharacterIndex characterLastIndex = characterFirstIndex + ( hasCharacters ? charactersPerGlyph - 1u : 0u );
 
       // Get the line break info for the current character.
-      const LineBreakInfo lineBreakInfo = *( parameters.lineBreakInfoBuffer + characterLastIndex );
-
-      // Get the word break info for the current character.
-      const WordBreakInfo wordBreakInfo = *( parameters.wordBreakInfoBuffer + characterLastIndex );
+      const LineBreakInfo lineBreakInfo = hasCharacters ? *( parameters.lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
 
       // Increase the number of characters.
       tmpLineLayout.numberOfCharacters += charactersPerGlyph;
 
       // Increase the number of glyphs.
-      tmpLineLayout.numberOfGlyphs++;
+      tmpLineLayout.numberOfGlyphs += numberOfGLyphsInGroup;
 
       // Check whether is a white space.
       const Character character = *( parameters.textBuffer + characterFirstIndex );
@@ -272,12 +303,12 @@ struct LayoutEngine::Impl
       if( isWhiteSpace )
       {
         // Add the length to the length of white spaces at the end of the line.
-        tmpLineLayout.wsLengthEndOfLine += glyphInfo.advance; // The advance is used as the width is always zero for the white spaces.
+        tmpLineLayout.wsLengthEndOfLine += 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 + glyphInfo.advance;
+        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.
@@ -297,7 +328,7 @@ struct LayoutEngine::Impl
             // |     Rll|
             //
 
-            tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+            tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
           }
           else // LTR
           {
@@ -310,8 +341,9 @@ struct LayoutEngine::Impl
             // |rrL     |
             //
 
-            const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+            const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
             tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+            tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
           }
         }
         else
@@ -323,15 +355,16 @@ struct LayoutEngine::Impl
               //  -->
               // |lllR    |
 
-              const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+              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 > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+              tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
             }
           }
           else if( characterDirection == firstCharacterDirection )
@@ -342,7 +375,7 @@ struct LayoutEngine::Impl
               // |llllllrr|
               // |Rr      |
 
-              tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
+              tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
             }
             else // LTR
             {
@@ -350,8 +383,9 @@ struct LayoutEngine::Impl
               // |llllrrrr|
               // |     llL|
 
-              const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
+              const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
               tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
+              tmpExtraWidth = std::max( mPreviousCharacterExtraWidth - glyphMetrics.advance, tmpExtraWidth );
             }
           }
         }
@@ -360,8 +394,19 @@ struct LayoutEngine::Impl
         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 ) && !isWhiteSpace &&
+      if( ( completelyFill || isMultiline )  && !(parameters.ignoreSpaceAfterText && isWhiteSpace) &&
           ( tmpExtraBearing + lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpExtraWidth > parameters.boundingBox.width ) )
       {
         // Current word does not fit in the box's width.
@@ -369,11 +414,11 @@ struct LayoutEngine::Impl
         {
           DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Break the word by character\n" );
 
-          // The word's with doesn't fit in the control's with. It needs to be split by character.
+          // The word doesn't fit in the control's width. It needs to be split by character.
           if( tmpLineLayout.numberOfGlyphs > 0u )
           {
             tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
-            --tmpLineLayout.numberOfGlyphs;
+            tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
             tmpLineLayout.length = previousTmpLineLength;
             tmpExtraBearing = previousTmpExtraBearing;
             tmpExtraWidth = previousTmpExtraWidth;
@@ -413,14 +458,15 @@ struct LayoutEngine::Impl
 
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
+
         return;
       }
 
       if( isMultiline &&
-          ( TextAbstraction::WORD_BREAK == wordBreakInfo ) )
+          ( TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo ) )
       {
-        oneWordLaidOut = true;
-        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  One word laid out\n" );
+        oneWordLaidOut = isWordLaidOut;
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  One word laid-out\n" );
 
         // Current glyph is the last one of the current word.
         // Add the temporal layout to the current one.
@@ -430,6 +476,7 @@ struct LayoutEngine::Impl
       }
 
       previousCharacterDirection = characterDirection;
+      glyphIndex += numberOfGLyphsInGroup;
     }
 
     lineLayout.extraBearing = tmpExtraBearing;
@@ -440,7 +487,7 @@ struct LayoutEngine::Impl
 
   void SetGlyphPositions( const GlyphInfo* const glyphsBuffer,
                           Length numberOfGlyphs,
-                          float penY,
+                          float outlineWidth,
                           Vector2* glyphPositionsBuffer )
   {
     // Traverse the glyphs and set the positions.
@@ -450,7 +497,8 @@ struct LayoutEngine::Impl
     // so the penX position needs to be moved to the right.
 
     const GlyphInfo& glyph = *glyphsBuffer;
-    float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing : 0.f;
+    float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing + outlineWidth : outlineWidth;
+
 
     for( GlyphIndex i = 0u; i < numberOfGlyphs; ++i )
     {
@@ -458,25 +506,387 @@ struct LayoutEngine::Impl
       Vector2& position = *( glyphPositionsBuffer + i );
 
       position.x = penX + glyph.xBearing;
-      position.y = penY - glyph.yBearing;
+      position.y = -glyph.yBearing;
 
       penX += glyph.advance;
     }
   }
 
-  bool LayoutText( const LayoutParameters& layoutParameters,
+  /**
+   * @brief Resizes the line buffer.
+   *
+   * @param[in,out] lines The vector of lines. Used when the layout is created from scratch.
+   * @param[in,out] newLines The vector of lines used instead of @p lines when the layout is updated.
+   * @param[in,out] linesCapacity The capacity of the vector (either lines or newLines).
+   * @param[in] updateCurrentBuffer Whether the layout is updated.
+   *
+   * @return Pointer to either lines or newLines.
+   */
+  LineRun* ResizeLinesBuffer( Vector<LineRun>& lines,
+                              Vector<LineRun>& newLines,
+                              Length& linesCapacity,
+                              bool updateCurrentBuffer )
+  {
+    LineRun* linesBuffer = NULL;
+    // Reserve more space for the next lines.
+    linesCapacity *= 2u;
+    if( updateCurrentBuffer )
+    {
+      newLines.Resize( linesCapacity );
+      linesBuffer = newLines.Begin();
+    }
+    else
+    {
+      lines.Resize( linesCapacity );
+      linesBuffer = lines.Begin();
+    }
+
+    return linesBuffer;
+  }
+
+  /**
+   * Ellipsis a line if it exceeds the width's of the bounding box.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in] layout The line layout.
+   * @param[in,out] layoutSize The text's layout size.
+   * @param[in,out] linesBuffer Pointer to the line's buffer.
+   * @param[in,out] glyphPositionsBuffer Pointer to the position's buffer.
+   * @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.
+   */
+  bool EllipsisLine( const Parameters& layoutParameters,
+                     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 ) :
+                                                ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
+                                                  ( ( mLayout == SINGLE_LINE_BOX ) &&
+                                                  ( layout.extraBearing + layout.length + layout.extraWidth > 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;
+      LineLayout ellipsisLayout;
+      if( 0u != numberOfLines )
+      {
+        // Get the last line and layout it again with the 'completelyFill' flag to true.
+        lineRun = linesBuffer + ( numberOfLines - 1u );
+
+        penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
+
+        ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
+      }
+      else
+      {
+        // At least there is space reserved for one line.
+        lineRun = linesBuffer;
+
+        lineRun->glyphRun.glyphIndex = 0u;
+        ellipsisLayout.glyphIndex = 0u;
+
+        ++numberOfLines;
+      }
+
+      GetLineLayoutForBox( layoutParameters,
+                           ellipsisLayout,
+                           currentParagraphDirection,
+                           true );
+
+      lineRun->glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
+      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->ascender = ellipsisLayout.ascender;
+      lineRun->descender = ellipsisLayout.descender;
+      lineRun->direction = !RTL;
+      lineRun->ellipsis = true;
+
+      layoutSize.width = layoutParameters.boundingBox.width;
+      if( layoutSize.height < Math::MACHINE_EPSILON_1000 )
+      {
+        layoutSize.height += ( lineRun->ascender + -lineRun->descender ) + lineRun->lineSpacing;
+      }
+
+      SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
+                         ellipsisLayout.numberOfGlyphs,
+                         layoutParameters.outlineWidth,
+                         glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
+    }
+
+    return ellipsis;
+  }
+
+  /**
+   * @brief Updates the text layout with a new laid-out line.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in] layout The line layout.
+   * @param[in,out] layoutSize The text's layout size.
+   * @param[in,out] linesBuffer Pointer to the line's buffer.
+   * @param[in] index Index to the vector of glyphs.
+   * @param[in,out] numberOfLines The number of laid-out lines.
+   * @param[in] isLastLine Whether the laid-out line is the last one.
+   */
+  void UpdateTextLayout( const Parameters& layoutParameters,
+                         const LineLayout& layout,
+                         Size& layoutSize,
+                         LineRun* linesBuffer,
+                         GlyphIndex index,
+                         Length& numberOfLines,
+                         bool isLastLine )
+  {
+    LineRun& lineRun = *( linesBuffer + numberOfLines );
+    ++numberOfLines;
+
+    lineRun.glyphRun.glyphIndex = index;
+    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.extraLength = 0.f;
+    }
+    else
+    {
+      lineRun.width = layout.extraBearing + layout.length + layout.extraWidth;
+      lineRun.extraLength = ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f;
+    }
+    lineRun.ascender = layout.ascender;
+    lineRun.descender = layout.descender;
+    lineRun.direction = !RTL;
+    lineRun.ellipsis = false;
+
+    // Update the actual size.
+    if( lineRun.width > layoutSize.width )
+    {
+      layoutSize.width = lineRun.width;
+    }
+
+    layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
+  }
+
+  /**
+   * @brief Updates the text layout with the last laid-out line.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in] characterIndex The character index of the line.
+   * @param[in] glyphIndex The glyph index of the line.
+   * @param[in,out] layoutSize The text's layout size.
+   * @param[in,out] linesBuffer Pointer to the line's buffer.
+   * @param[in,out] numberOfLines The number of laid-out lines.
+   */
+  void UpdateTextLayout( const Parameters& layoutParameters,
+                         CharacterIndex characterIndex,
+                         GlyphIndex glyphIndex,
+                         Size& layoutSize,
+                         LineRun* linesBuffer,
+                         Length& numberOfLines )
+  {
+    // 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 );
+
+    Text::FontMetrics fontMetrics;
+    mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
+
+    LineRun& lineRun = *( linesBuffer + numberOfLines );
+    ++numberOfLines;
+
+    lineRun.glyphRun.glyphIndex = glyphIndex;
+    lineRun.glyphRun.numberOfGlyphs = 0u;
+    lineRun.characterRun.characterIndex = characterIndex;
+    lineRun.characterRun.numberOfCharacters = 0u;
+    lineRun.width = 0.f;
+    lineRun.ascender = fontMetrics.ascender;
+    lineRun.descender = fontMetrics.descender;
+    lineRun.extraLength = 0.f;
+    lineRun.alignmentOffset = 0.f;
+    lineRun.direction = !RTL;
+    lineRun.ellipsis = false;
+    lineRun.lineSpacing = mDefaultLineSpacing;
+
+    layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
+  }
+
+  /**
+   * @brief Updates the text's layout size adding the size of the previously laid-out lines.
+   *
+   * @param[in] lines The vector of lines (before the new laid-out lines are inserted).
+   * @param[in,out] layoutSize The text's layout size.
+   */
+  void UpdateLayoutSize( const Vector<LineRun>& lines,
+                         Size& layoutSize )
+  {
+    for( Vector<LineRun>::ConstIterator it = lines.Begin(),
+           endIt = lines.End();
+         it != endIt;
+         ++it )
+    {
+      const LineRun& line = *it;
+
+      if( line.width > layoutSize.width )
+      {
+        layoutSize.width = line.width;
+      }
+
+      layoutSize.height += ( line.ascender + -line.descender ) + line.lineSpacing;
+    }
+  }
+
+  /**
+   * @brief Updates the indices of the character and glyph runs of the lines before the new lines are inserted.
+   *
+   * @param[in] layoutParameters The parameters needed to layout the text.
+   * @param[in,out] lines The vector of lines (before the new laid-out lines are inserted).
+   * @param[in] characterOffset The offset to be added to the runs of characters.
+   * @param[in] glyphOffset The offset to be added to the runs of glyphs.
+   */
+  void UpdateLineIndexOffsets( const Parameters& layoutParameters,
+                               Vector<LineRun>& lines,
+                               Length characterOffset,
+                               Length glyphOffset )
+  {
+    // Update the glyph and character runs.
+    for( Vector<LineRun>::Iterator it = lines.Begin() + layoutParameters.startLineIndex,
+           endIt = lines.End();
+         it != endIt;
+         ++it )
+    {
+      LineRun& line = *it;
+
+      line.glyphRun.glyphIndex = glyphOffset;
+      line.characterRun.characterIndex = characterOffset;
+
+      glyphOffset += line.glyphRun.numberOfGlyphs;
+      characterOffset += line.characterRun.numberOfCharacters;
+    }
+  }
+
+  bool LayoutText( const Parameters& layoutParameters,
                    Vector<Vector2>& glyphPositions,
                    Vector<LineRun>& lines,
-                   Size& actualSize )
+                   Size& layoutSize,
+                   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 );
 
+    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.
+      if( layoutParameters.isLastNewParagraph )
+      {
+        Length numberOfLines = lines.Count();
+        if( 0u != numberOfLines )
+        {
+          const LineRun& lastLine = *( lines.End() - 1u );
+
+          if( 0u != lastLine.characterRun.numberOfCharacters )
+          {
+            // Need to add a new line with no characters but with height to increase the layoutSize.height
+            LineRun newLine;
+            Initialize( newLine );
+            lines.PushBack( newLine );
+
+            UpdateTextLayout( layoutParameters,
+                              lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters,
+                              lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs,
+                              layoutSize,
+                              lines.Begin(),
+                              numberOfLines );
+          }
+        }
+      }
+
+      // Calculates the layout size.
+      UpdateLayoutSize( lines,
+                        layoutSize );
+
+      // Nothing else do if there are no glyphs to layout.
+      return false;
+    }
+
+    const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
+
+    // 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.
+    if( 0u != lines.Count() )
+    {
+      Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
+
+      if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
+          ( lastGlyphPlusOne == layoutParameters.totalNumberOfGlyphs ) )
+      {
+        lines.Remove( lastLine );
+      }
+    }
+
     // Set the first paragraph's direction.
     CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
 
-    float penY = 0.f;
-    for( GlyphIndex index = 0u; index < layoutParameters.totalNumberOfGlyphs; )
+    // Whether the layout is being updated or set from scratch.
+    const bool updateCurrentBuffer = layoutParameters.numberOfGlyphs < layoutParameters.totalNumberOfGlyphs;
+
+    Vector2* glyphPositionsBuffer = NULL;
+    Vector<Vector2> newGlyphPositions;
+
+    LineRun* linesBuffer = NULL;
+    Vector<LineRun> newLines;
+
+    // Estimate the number of lines.
+    Length linesCapacity = std::max( 1u, layoutParameters.estimatedNumberOfLines );
+    Length numberOfLines = 0u;
+
+    if( updateCurrentBuffer )
+    {
+      newGlyphPositions.Resize( layoutParameters.numberOfGlyphs );
+      glyphPositionsBuffer = newGlyphPositions.Begin();
+
+      newLines.Resize( linesCapacity );
+      linesBuffer = newLines.Begin();
+    }
+    else
+    {
+      glyphPositionsBuffer = glyphPositions.Begin();
+
+      lines.Resize( linesCapacity );
+      linesBuffer = lines.Begin();
+    }
+
+    float penY = CalculateLineOffset( lines,
+                                      layoutParameters.startLineIndex );
+
+    for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
     {
       CharacterDirection currentParagraphDirection = paragraphDirection;
 
@@ -498,6 +908,8 @@ struct LayoutEngine::Impl
       {
         // The width is too small and no characters are laid-out.
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n" );
+
+        lines.Resize( numberOfLines );
         return false;
       }
 
@@ -506,171 +918,162 @@ struct LayoutEngine::Impl
       penY += layout.ascender;
 
       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  pen y %f\n", penY );
-      if( mEllipsisEnabled &&
-          ( ( penY - layout.descender > layoutParameters.boundingBox.height ) ||
-            ( ( mLayout == SINGLE_LINE_BOX ) &&
-              ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) ) )
-      {
-        // 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.
-
-        const Length numberOfLines = lines.Count();
 
-        LineRun lineRun;
-        LineLayout ellipsisLayout;
-        if( 0u != numberOfLines )
-        {
-          // Get the last line and layout it again with the 'completelyFill' flag to true.
-          lineRun = *( lines.Begin() + ( numberOfLines - 1u ) );
-
-          penY -= layout.ascender - lineRun.descender;
-
-          ellipsisLayout.glyphIndex = lineRun.glyphRun.glyphIndex;
-        }
-        else
-        {
-          lineRun.glyphRun.glyphIndex = 0u;
-          ellipsisLayout.glyphIndex = 0u;
-        }
-
-        GetLineLayoutForBox( layoutParameters,
-                             ellipsisLayout,
-                             currentParagraphDirection,
-                             true );
-
-        lineRun.glyphRun.numberOfGlyphs = ellipsisLayout.numberOfGlyphs;
-        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.ascender = ellipsisLayout.ascender;
-        lineRun.descender = ellipsisLayout.descender;
-        lineRun.direction = !RTL;
-        lineRun.ellipsis = true;
-
-        actualSize.width = layoutParameters.boundingBox.width;
-        actualSize.height += ( lineRun.ascender + -lineRun.descender );
-
-        SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun.glyphRun.glyphIndex,
-                           ellipsisLayout.numberOfGlyphs,
-                           penY,
-                           glyphPositions.Begin() + lineRun.glyphRun.glyphIndex );
-
-        if( 0u != numberOfLines )
-        {
-          // Set the last line with the ellipsis layout.
-          *( lines.Begin() + ( numberOfLines - 1u ) ) = lineRun;
-        }
-        else
-        {
-          // Push the line.
-          lines.PushBack( lineRun );
-        }
+      bool ellipsis = false;
+      if( elideTextEnabled )
+      {
+        // Does the ellipsis of the last line.
+        ellipsis = EllipsisLine( layoutParameters,
+                                 layout,
+                                 layoutSize,
+                                 linesBuffer,
+                                 glyphPositionsBuffer,
+                                 numberOfLines,
+                                 penY,
+                                 currentParagraphDirection,
+                                 isAutoScrollEnabled );
+      }
 
+      if( ellipsis )
+      {
+        // No more lines to layout.
         break;
       }
       else
       {
+        // Whether the last line has been laid-out.
         const bool isLastLine = index + layout.numberOfGlyphs == layoutParameters.totalNumberOfGlyphs;
 
-        LineRun lineRun;
-        lineRun.glyphRun.glyphIndex = index;
-        lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
-        lineRun.characterRun.characterIndex = layout.characterIndex;
-        lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
-        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.extraLength = 0.f;
-        }
-        else
+        if( numberOfLines == linesCapacity )
         {
-          lineRun.width = layout.extraBearing + layout.length + layout.extraWidth;
-          lineRun.extraLength = ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f;
+          // Reserve more space for the next lines.
+          linesBuffer = ResizeLinesBuffer( lines,
+                                           newLines,
+                                           linesCapacity,
+                                           updateCurrentBuffer );
         }
-        lineRun.ascender = layout.ascender;
-        lineRun.descender = layout.descender;
-        lineRun.direction = !RTL;
-        lineRun.ellipsis = false;
 
-        lines.PushBack( lineRun );
+        // Updates the current text's layout with the line's layout.
+        UpdateTextLayout( layoutParameters,
+                          layout,
+                          layoutSize,
+                          linesBuffer,
+                          index,
+                          numberOfLines,
+                          isLastLine );
+
+        const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
 
-        // Update the actual size.
-        if( lineRun.width > actualSize.width )
+        if( ( nextIndex == layoutParameters.totalNumberOfGlyphs ) &&
+            layoutParameters.isLastNewParagraph &&
+            ( mLayout == MULTI_LINE_BOX ) )
         {
-          actualSize.width = lineRun.width;
-        }
+          // The last character of the text is a new paragraph character.
+          // An extra line with no characters is added to increase the text's height
+          // in order to place the cursor.
+
+          if( numberOfLines == linesCapacity )
+          {
+            // Reserve more space for the next lines.
+            linesBuffer = ResizeLinesBuffer( lines,
+                                             newLines,
+                                             linesCapacity,
+                                             updateCurrentBuffer );
+          }
 
-        actualSize.height += ( lineRun.ascender + -lineRun.descender );
+          UpdateTextLayout( layoutParameters,
+                            layout.characterIndex + layout.numberOfCharacters,
+                            index + layout.numberOfGlyphs,
+                            layoutSize,
+                            linesBuffer,
+                            numberOfLines );
+        } // whether to add a last line.
 
+        // Sets the positions of the glyphs.
         SetGlyphPositions( layoutParameters.glyphsBuffer + index,
                            layout.numberOfGlyphs,
-                           penY,
-                           glyphPositions.Begin() + index );
+                           layoutParameters.outlineWidth,
+                           glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
 
-        penY += -layout.descender;
+        // Updates the vertical pen's position.
+        penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
 
         // Increase the glyph index.
-        index += layout.numberOfGlyphs;
+        index = nextIndex;
+      } // no ellipsis
+    } // end for() traversing glyphs.
 
-        if( isLastLine &&
-            layoutParameters.isLastNewParagraph &&
-            ( mLayout == MULTI_LINE_BOX ) )
-        {
-          // Need to add a new line with no characters but with height to increase the actualSize.height
-          const GlyphInfo& glyphInfo = *( layoutParameters.glyphsBuffer + layoutParameters.totalNumberOfGlyphs - 1u );
-
-          Text::FontMetrics fontMetrics;
-          mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics );
-
-          LineRun lineRun;
-          lineRun.glyphRun.glyphIndex = 0u;
-          lineRun.glyphRun.numberOfGlyphs = 0u;
-          lineRun.characterRun.characterIndex = 0u;
-          lineRun.characterRun.numberOfCharacters = 0u;
-          lineRun.width = 0.f;
-          lineRun.ascender = fontMetrics.ascender;
-          lineRun.descender = fontMetrics.descender;
-          lineRun.extraLength = 0.f;
-          lineRun.alignmentOffset = 0.f;
-          lineRun.direction = !RTL;
-          lineRun.ellipsis = false;
-
-          actualSize.height += ( lineRun.ascender + -lineRun.descender );
-
-          lines.PushBack( lineRun );
-        }
+    if( updateCurrentBuffer )
+    {
+      glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
+                             newGlyphPositions.Begin(),
+                             newGlyphPositions.End() );
+      glyphPositions.Resize( layoutParameters.totalNumberOfGlyphs );
+
+      newLines.Resize( numberOfLines );
+
+      // Current text's layout size adds only the newly laid-out lines.
+      // Updates the layout size with the previously laid-out lines.
+      UpdateLayoutSize( lines,
+                        layoutSize );
+
+      if( 0u != newLines.Count() )
+      {
+        const LineRun& lastLine = *( newLines.End() - 1u );
+
+        const Length characterOffset = lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters;
+        const Length glyphOffset = lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs;
+
+        // Update the indices of the runs before the new laid-out lines are inserted.
+        UpdateLineIndexOffsets( layoutParameters,
+                                lines,
+                                characterOffset,
+                                glyphOffset );
+
+        // Insert the lines.
+        lines.Insert( lines.Begin() + layoutParameters.startLineIndex,
+                      newLines.Begin(),
+                      newLines.End() );
       }
-    } // end for() traversing glyphs.
+    }
+    else
+    {
+      lines.Resize( numberOfLines );
+    }
 
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" );
 
     return true;
   }
 
-  void ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
+  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 : 0.f;
+      float penX = ( 0.f > glyph.xBearing ) ? -glyph.xBearing - layoutParameters.outlineWidth : -layoutParameters.outlineWidth;
 
       Vector2* glyphPositionsBuffer = glyphPositions.Begin();
 
@@ -702,218 +1105,251 @@ struct LayoutEngine::Impl
     }
   }
 
-  void Align( const Size& layoutSize,
-              Vector<LineRun>& lines )
+  void Align( const Size& size,
+              CharacterIndex startIndex,
+              Length numberOfCharacters,
+              Text::HorizontalAlignment::Type horizontalAlignment,
+              Vector<LineRun>& lines,
+              float& alignmentOffset,
+              Dali::LayoutDirection::Type layoutDirection,
+              bool matchSystemLanguageDirection )
   {
-    // Traverse all lines and align the glyphs.
+    const CharacterIndex lastCharacterPlusOne = startIndex + numberOfCharacters;
 
+    alignmentOffset = MAX_FLOAT;
+    // Traverse all lines and align the glyphs.
     for( Vector<LineRun>::Iterator it = lines.Begin(), endIt = lines.End();
          it != endIt;
          ++it )
     {
       LineRun& line = *it;
-      const bool isLastLine = lines.End() == it + 1u;
 
-      // Calculate the alignment offset accordingly with the align option,
-      // the box width, line length, and the paragraphs direction.
-      CalculateHorizontalAlignment( layoutSize.width,
+      if( line.characterRun.characterIndex < startIndex )
+      {
+        // Do not align lines which have already been aligned.
+        continue;
+      }
+
+      if( line.characterRun.characterIndex >= lastCharacterPlusOne )
+      {
+        // Do not align lines beyond the last laid-out character.
+        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,
+                                    horizontalAlignment,
                                     line,
-                                    isLastLine );
+                                    layoutDirection,
+                                    matchSystemLanguageDirection );
+
+      // Updates the alignment offset.
+      alignmentOffset = std::min( alignmentOffset, line.alignmentOffset );
     }
   }
 
   void CalculateHorizontalAlignment( float boxWidth,
+                                     HorizontalAlignment::Type horizontalAlignment,
                                      LineRun& line,
-                                     bool isLastLine )
+                                     Dali::LayoutDirection::Type layoutDirection,
+                                     bool matchSystemLanguageDirection )
   {
     line.alignmentOffset = 0.f;
-    const 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 alignment = mHorizontalAlignment;
-    if( isRTL &&
-        ( HORIZONTAL_ALIGN_CENTER != alignment ) )
+    // match align for system language direction
+    if( matchSystemLanguageDirection )
     {
-      if( HORIZONTAL_ALIGN_BEGIN == alignment )
-      {
-        alignment = HORIZONTAL_ALIGN_END;
-      }
-      else
-      {
-        alignment = HORIZONTAL_ALIGN_BEGIN;
-      }
+      // Swap the alignment type if the line is right to left.
+      isLayoutRTL = layoutDirection == LayoutDirection::RIGHT_TO_LEFT;
     }
-
-    switch( alignment )
+    // Calculate the horizontal line offset.
+    switch( horizontalAlignment )
     {
-      case HORIZONTAL_ALIGN_BEGIN:
+      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( isLastLine )
+          if( isLineRTL )
           {
-            line.alignmentOffset += std::min( line.extraLength, boxWidth - lineLength );
+            // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+            line.alignmentOffset -= line.extraLength;
           }
         }
         break;
       }
-      case HORIZONTAL_ALIGN_CENTER:
+      case HorizontalAlignment::CENTER:
       {
-        if( isLastLine && !isRTL )
-        {
-          lineLength += line.extraLength;
-          if( lineLength > boxWidth )
-          {
-            lineLength = boxWidth;
-            line.alignmentOffset = 0.f;
-            break;
-          }
-        }
-
         line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
 
-        if( isRTL )
+        if( isLineRTL )
         {
           line.alignmentOffset -= line.extraLength;
-
-          if( isLastLine )
-          {
-            line.alignmentOffset += 0.5f * std::min( line.extraLength, boxWidth - lineLength );
-          }
         }
 
         line.alignmentOffset = floorf( line.alignmentOffset ); // try to avoid pixel alignment.
         break;
       }
-      case HORIZONTAL_ALIGN_END:
+      case HorizontalAlignment::END:
       {
-        if( isLastLine && !isRTL )
+        if( isLayoutRTL )
         {
-          lineLength += line.extraLength;
-          if( lineLength > boxWidth )
+          line.alignmentOffset = 0.f;
+
+          if( isLineRTL )
           {
-            line.alignmentOffset = 0.f;
-            break;
+            // 'Remove' the white spaces at the end of the line (which are at the beginning in visual order)
+            line.alignmentOffset -= line.extraLength;
           }
         }
-
-        if( isRTL )
+        else
         {
-          lineLength += line.extraLength;
-        }
+          if( isLineRTL )
+          {
+            lineLength += line.extraLength;
+          }
 
-        line.alignmentOffset = boxWidth - lineLength;
+          line.alignmentOffset = boxWidth - lineLength;
+        }
         break;
       }
     }
   }
 
-  LayoutEngine::Layout mLayout;
-  LayoutEngine::HorizontalAlignment mHorizontalAlignment;
-  LayoutEngine::VerticalAlignment mVerticalAlignment;
+  void Initialize( LineRun& line )
+  {
+    line.glyphRun.glyphIndex = 0u;
+    line.glyphRun.numberOfGlyphs = 0u;
+    line.characterRun.characterIndex = 0u;
+    line.characterRun.numberOfCharacters = 0u;
+    line.width = 0.f;
+    line.ascender = 0.f;
+    line.descender = 0.f;
+    line.extraLength = 0.f;
+    line.alignmentOffset = 0.f;
+    line.direction = !RTL;
+    line.ellipsis = false;
+    line.lineSpacing = mDefaultLineSpacing;
+  }
+
+  Type mLayout;
   float mCursorWidth;
+  float mDefaultLineSpacing;
+  float mPreviousCharacterExtraWidth;
 
   IntrusivePtr<Metrics> mMetrics;
-
-  bool mEllipsisEnabled:1;
 };
 
-LayoutEngine::LayoutEngine()
+Engine::Engine()
 : mImpl( NULL )
 {
-  mImpl = new LayoutEngine::Impl();
+  mImpl = new Engine::Impl();
 }
 
-LayoutEngine::~LayoutEngine()
+Engine::~Engine()
 {
   delete mImpl;
 }
 
-void LayoutEngine::SetMetrics( MetricsPtr& metrics )
+void Engine::SetMetrics( MetricsPtr& metrics )
 {
   mImpl->mMetrics = metrics;
 }
 
-void LayoutEngine::SetLayout( Layout layout )
+void Engine::SetLayout( Type layout )
 {
   mImpl->mLayout = layout;
 }
 
-unsigned int LayoutEngine::GetLayout() const
+Engine::Type Engine::GetLayout() const
 {
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetLayout[%d]\n", mImpl->mLayout);
   return mImpl->mLayout;
 }
 
-void LayoutEngine::SetTextEllipsisEnabled( bool enabled )
-{
-  mImpl->mEllipsisEnabled = enabled;
-}
-
-bool LayoutEngine::GetTextEllipsisEnabled() const
-{
-  return mImpl->mEllipsisEnabled;
-}
-
-void LayoutEngine::SetHorizontalAlignment( HorizontalAlignment alignment )
-{
-  mImpl->mHorizontalAlignment = alignment;
-}
-
-LayoutEngine::HorizontalAlignment LayoutEngine::GetHorizontalAlignment() const
-{
-  return mImpl->mHorizontalAlignment;
-}
-
-void LayoutEngine::SetVerticalAlignment( VerticalAlignment alignment )
-{
-  mImpl->mVerticalAlignment = alignment;
-}
-
-LayoutEngine::VerticalAlignment LayoutEngine::GetVerticalAlignment() const
-{
-  return mImpl->mVerticalAlignment;
-}
-
-void LayoutEngine::SetCursorWidth( int width )
+void Engine::SetCursorWidth( int width )
 {
   mImpl->mCursorWidth = static_cast<float>( width );
 }
 
-int LayoutEngine::GetCursorWidth() const
+int Engine::GetCursorWidth() const
 {
   return static_cast<int>( mImpl->mCursorWidth );
 }
 
-bool LayoutEngine::LayoutText( const LayoutParameters& layoutParameters,
-                               Vector<Vector2>& glyphPositions,
-                               Vector<LineRun>& lines,
-                               Size& actualSize )
+bool Engine::LayoutText( const Parameters& layoutParameters,
+                         Vector<Vector2>& glyphPositions,
+                         Vector<LineRun>& lines,
+                         Size& layoutSize,
+                         bool elideTextEnabled,
+                         bool& isAutoScrollEnabled )
 {
   return mImpl->LayoutText( layoutParameters,
                             glyphPositions,
                             lines,
-                            actualSize );
+                            layoutSize,
+                            elideTextEnabled,
+                            isAutoScrollEnabled );
 }
 
-void LayoutEngine::ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
-                                             Vector<Vector2>& glyphPositions )
+void Engine::ReLayoutRightToLeftLines( const Parameters& layoutParameters,
+                                       CharacterIndex startIndex,
+                                       Length numberOfCharacters,
+                                       Vector<Vector2>& glyphPositions )
 {
   mImpl->ReLayoutRightToLeftLines( layoutParameters,
+                                   startIndex,
+                                   numberOfCharacters,
                                    glyphPositions );
 }
 
-void LayoutEngine::Align( const Size& layoutSize,
-                          Vector<LineRun>& lines )
+void Engine::Align( const Size& size,
+                    CharacterIndex startIndex,
+                    Length numberOfCharacters,
+                    Text::HorizontalAlignment::Type horizontalAlignment,
+                    Vector<LineRun>& lines,
+                    float& alignmentOffset,
+                    Dali::LayoutDirection::Type layoutDirection,
+                    bool matchSystemLanguageDirection )
+{
+  mImpl->Align( size,
+                startIndex,
+                numberOfCharacters,
+                horizontalAlignment,
+                lines,
+                alignmentOffset,
+                layoutDirection,
+                matchSystemLanguageDirection );
+}
+
+void Engine::SetDefaultLineSpacing( float lineSpacing )
 {
-  mImpl->Align( layoutSize,
-                lines );
+  mImpl->mDefaultLineSpacing = lineSpacing;
 }
 
+float Engine::GetDefaultLineSpacing() const
+{
+  return mImpl->mDefaultLineSpacing;
+}
+
+} // namespace Layout
+
 } // namespace Text
 
 } // namespace Toolkit