Merge "Added IGNORE_SPACES_AFTER_TEXT property" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
index 0b9e39d..061707a 100644 (file)
@@ -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;
   }
 
   /**
@@ -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,68 +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;
 
-    const GlyphIndex lastGlyphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
     for( GlyphIndex glyphIndex = lineLayout.glyphIndex;
-         glyphIndex < lastGlyphPlusOne;
-         ++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 );
@@ -273,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.
@@ -298,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
           {
@@ -311,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
@@ -324,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 )
@@ -343,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
             {
@@ -351,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 );
             }
           }
         }
@@ -361,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.
@@ -374,7 +418,7 @@ struct LayoutEngine::Impl
           if( tmpLineLayout.numberOfGlyphs > 0u )
           {
             tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
-            --tmpLineLayout.numberOfGlyphs;
+            tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
             tmpLineLayout.length = previousTmpLineLength;
             tmpExtraBearing = previousTmpExtraBearing;
             tmpExtraWidth = previousTmpExtraWidth;
@@ -414,13 +458,14 @@ 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;
+        oneWordLaidOut = isWordLaidOut;
         DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  One word laid-out\n" );
 
         // Current glyph is the last one of the current word.
@@ -431,6 +476,7 @@ struct LayoutEngine::Impl
       }
 
       previousCharacterDirection = characterDirection;
+      glyphIndex += numberOfGLyphsInGroup;
     }
 
     lineLayout.extraBearing = tmpExtraBearing;
@@ -439,36 +485,9 @@ struct LayoutEngine::Impl
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
   }
 
-  /**
-   * @brief Calculates the vertical offset to add to the new laid-out glyphs.
-   *
-   * @pre @p lineIndex must be between 0 and the number of lines (both inclusive).
-   *
-   * @param[in] lines The previously laid-out lines.
-   * @param[in] lineIndex Index to the line where the new laid-out lines are inserted.
-   *
-   * @return The vertical offset of the lines starting from the beginning to the line @p lineIndex.
-   */
-  float SetParagraphOffset( const Vector<LineRun>& lines,
-                            LineIndex lineIndex )
-  {
-    float offset = 0.f;
-
-    for( Vector<LineRun>::ConstIterator it = lines.Begin(),
-           endIt = lines.Begin() + lineIndex;
-         it != endIt;
-         ++it )
-    {
-      const LineRun& line = *it;
-
-      offset += line.ascender + -line.descender;
-    }
-
-    return offset;
-  }
-
   void SetGlyphPositions( const GlyphInfo* const glyphsBuffer,
                           Length numberOfGlyphs,
+                          float outlineWidth,
                           Vector2* glyphPositionsBuffer )
   {
     // Traverse the glyphs and set the positions.
@@ -478,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 )
     {
@@ -538,7 +558,7 @@ struct LayoutEngine::Impl
    *
    * return Whether the line is ellipsized.
    */
-  bool EllipsisLine( const LayoutParameters& layoutParameters,
+  bool EllipsisLine( const Parameters& layoutParameters,
                      const LineLayout& layout,
                      Size& layoutSize,
                      LineRun* linesBuffer,
@@ -565,7 +585,7 @@ struct LayoutEngine::Impl
         // Get the last line and layout it again with the 'completelyFill' flag to true.
         lineRun = linesBuffer + ( numberOfLines - 1u );
 
-        penY -= layout.ascender - lineRun->descender;
+        penY -= layout.ascender - lineRun->descender + lineRun->lineSpacing;
 
         ellipsisLayout.glyphIndex = lineRun->glyphRun.glyphIndex;
       }
@@ -596,10 +616,14 @@ struct LayoutEngine::Impl
       lineRun->ellipsis = true;
 
       layoutSize.width = layoutParameters.boundingBox.width;
-      layoutSize.height += ( lineRun->ascender + -lineRun->descender );
+      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 );
     }
 
@@ -617,7 +641,7 @@ struct LayoutEngine::Impl
    * @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 LayoutParameters& layoutParameters,
+  void UpdateTextLayout( const Parameters& layoutParameters,
                          const LineLayout& layout,
                          Size& layoutSize,
                          LineRun* linesBuffer,
@@ -632,6 +656,8 @@ struct LayoutEngine::Impl
     lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs;
     lineRun.characterRun.characterIndex = layout.characterIndex;
     lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters;
+    lineRun.lineSpacing = mDefaultLineSpacing;
+
     if( isLastLine && !layoutParameters.isLastNewParagraph )
     {
       const float width = layout.extraBearing + layout.length + layout.extraWidth + layout.wsLengthEndOfLine;
@@ -662,7 +688,7 @@ struct LayoutEngine::Impl
       layoutSize.width = lineRun.width;
     }
 
-    layoutSize.height += ( lineRun.ascender + -lineRun.descender );
+    layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
   }
 
   /**
@@ -675,7 +701,7 @@ struct LayoutEngine::Impl
    * @param[in,out] linesBuffer Pointer to the line's buffer.
    * @param[in,out] numberOfLines The number of laid-out lines.
    */
-  void UpdateTextLayout( const LayoutParameters& layoutParameters,
+  void UpdateTextLayout( const Parameters& layoutParameters,
                          CharacterIndex characterIndex,
                          GlyphIndex glyphIndex,
                          Size& layoutSize,
@@ -702,8 +728,9 @@ struct LayoutEngine::Impl
     lineRun.alignmentOffset = 0.f;
     lineRun.direction = !RTL;
     lineRun.ellipsis = false;
+    lineRun.lineSpacing = mDefaultLineSpacing;
 
-    layoutSize.height += ( lineRun.ascender + -lineRun.descender );
+    layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing;
   }
 
   /**
@@ -727,7 +754,7 @@ struct LayoutEngine::Impl
         layoutSize.width = line.width;
       }
 
-      layoutSize.height += ( line.ascender + -line.descender );
+      layoutSize.height += ( line.ascender + -line.descender ) + line.lineSpacing;
     }
   }
 
@@ -739,7 +766,7 @@ struct LayoutEngine::Impl
    * @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 LayoutParameters& layoutParameters,
+  void UpdateLineIndexOffsets( const Parameters& layoutParameters,
                                Vector<LineRun>& lines,
                                Length characterOffset,
                                Length glyphOffset )
@@ -760,10 +787,11 @@ struct LayoutEngine::Impl
     }
   }
 
-  bool LayoutText( const LayoutParameters& layoutParameters,
+  bool LayoutText( const Parameters& layoutParameters,
                    Vector<Vector2>& glyphPositions,
                    Vector<LineRun>& lines,
-                   Size& layoutSize )
+                   Size& layoutSize,
+                   bool elideTextEnabled )
   {
     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 );
@@ -782,6 +810,7 @@ struct LayoutEngine::Impl
           {
             // 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,
@@ -794,6 +823,10 @@ struct LayoutEngine::Impl
         }
       }
 
+      // Calculates the layout size.
+      UpdateLayoutSize( lines,
+                        layoutSize );
+
       // Nothing else do if there are no glyphs to layout.
       return false;
     }
@@ -826,7 +859,7 @@ struct LayoutEngine::Impl
     Vector<LineRun> newLines;
 
     // Estimate the number of lines.
-    Length linesCapacity = layoutParameters.estimatedNumberOfLines;
+    Length linesCapacity = std::max( 1u, layoutParameters.estimatedNumberOfLines );
     Length numberOfLines = 0u;
 
     if( updateCurrentBuffer )
@@ -845,8 +878,8 @@ struct LayoutEngine::Impl
       linesBuffer = lines.Begin();
     }
 
-    float penY = SetParagraphOffset( lines,
-                                     layoutParameters.startLineIndex );
+    float penY = CalculateLineOffset( lines,
+                                      layoutParameters.startLineIndex );
 
     for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
     {
@@ -882,7 +915,7 @@ struct LayoutEngine::Impl
       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  pen y %f\n", penY );
 
       bool ellipsis = false;
-      if( mEllipsisEnabled )
+      if( elideTextEnabled )
       {
         // Does the ellipsis of the last line.
         ellipsis = EllipsisLine( layoutParameters,
@@ -953,10 +986,11 @@ struct LayoutEngine::Impl
         // Sets the positions of the glyphs.
         SetGlyphPositions( layoutParameters.glyphsBuffer + index,
                            layout.numberOfGlyphs,
+                           layoutParameters.outlineWidth,
                            glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
 
         // Updates the vertical pen's position.
-        penY += -layout.descender;
+        penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
 
         // Increase the glyph index.
         index = nextIndex;
@@ -1006,7 +1040,7 @@ struct LayoutEngine::Impl
     return true;
   }
 
-  void ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
+  void ReLayoutRightToLeftLines( const Parameters& layoutParameters,
                                  CharacterIndex startIndex,
                                  Length numberOfCharacters,
                                  Vector<Vector2>& glyphPositions )
@@ -1033,7 +1067,7 @@ struct LayoutEngine::Impl
       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();
 
@@ -1068,10 +1102,13 @@ struct LayoutEngine::Impl
   void Align( const Size& size,
               CharacterIndex startIndex,
               Length numberOfCharacters,
-              Vector<LineRun>& lines )
+              Text::HorizontalAlignment::Type horizontalAlignment,
+              Vector<LineRun>& lines,
+              float& alignmentOffset )
   {
     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;
@@ -1094,36 +1131,41 @@ struct LayoutEngine::Impl
       // 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 );
+
+      // Updates the alignment offset.
+      alignmentOffset = std::min( alignmentOffset, line.alignmentOffset );
     }
   }
 
   void CalculateHorizontalAlignment( float boxWidth,
+                                     HorizontalAlignment::Type horizontalAlignment,
                                      LineRun& line )
   {
     line.alignmentOffset = 0.f;
     const bool isRTL = RTL == line.direction;
     float lineLength = line.width;
 
-    HorizontalAlignment alignment = mHorizontalAlignment;
+    HorizontalAlignment::Type alignment = horizontalAlignment;
     if( isRTL )
     {
       // Swap the alignment type if the line is right to left.
       switch( alignment )
       {
-        case HORIZONTAL_ALIGN_BEGIN:
+        case HorizontalAlignment::BEGIN:
         {
-          alignment = HORIZONTAL_ALIGN_END;
+          alignment = HorizontalAlignment::END;
           break;
         }
-        case HORIZONTAL_ALIGN_CENTER:
+        case HorizontalAlignment::CENTER:
         {
           // Nothing to do.
           break;
         }
-        case HORIZONTAL_ALIGN_END:
+        case HorizontalAlignment::END:
         {
-          alignment = HORIZONTAL_ALIGN_BEGIN;
+          alignment = HorizontalAlignment::BEGIN;
           break;
         }
       }
@@ -1132,7 +1174,7 @@ struct LayoutEngine::Impl
     // Calculate the horizontal line offset.
     switch( alignment )
     {
-      case HORIZONTAL_ALIGN_BEGIN:
+      case HorizontalAlignment::BEGIN:
       {
         line.alignmentOffset = 0.f;
 
@@ -1143,7 +1185,7 @@ struct LayoutEngine::Impl
         }
         break;
       }
-      case HORIZONTAL_ALIGN_CENTER:
+      case HorizontalAlignment::CENTER:
       {
         line.alignmentOffset = 0.5f * ( boxWidth - lineLength );
 
@@ -1155,7 +1197,7 @@ struct LayoutEngine::Impl
         line.alignmentOffset = floorf( line.alignmentOffset ); // try to avoid pixel alignment.
         break;
       }
-      case HORIZONTAL_ALIGN_END:
+      case HorizontalAlignment::END:
       {
         if( isRTL )
         {
@@ -1168,97 +1210,84 @@ struct LayoutEngine::Impl
     }
   }
 
-  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;
 }
 
-LayoutEngine::Layout 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& layoutSize )
+bool Engine::LayoutText( const Parameters& layoutParameters,
+                         Vector<Vector2>& glyphPositions,
+                         Vector<LineRun>& lines,
+                         Size& layoutSize,
+                         bool elideTextEnabled )
 {
   return mImpl->LayoutText( layoutParameters,
                             glyphPositions,
                             lines,
-                            layoutSize );
+                            layoutSize,
+                            elideTextEnabled );
 }
 
-void LayoutEngine::ReLayoutRightToLeftLines( const LayoutParameters& layoutParameters,
-                                             CharacterIndex startIndex,
-                                             Length numberOfCharacters,
-                                             Vector<Vector2>& glyphPositions )
+void Engine::ReLayoutRightToLeftLines( const Parameters& layoutParameters,
+                                       CharacterIndex startIndex,
+                                       Length numberOfCharacters,
+                                       Vector<Vector2>& glyphPositions )
 {
   mImpl->ReLayoutRightToLeftLines( layoutParameters,
                                    startIndex,
@@ -1266,17 +1295,33 @@ void LayoutEngine::ReLayoutRightToLeftLines( const LayoutParameters& layoutParam
                                    glyphPositions );
 }
 
-void LayoutEngine::Align( const Size& size,
-                          CharacterIndex startIndex,
-                          Length numberOfCharacters,
-                          Vector<LineRun>& lines )
+void Engine::Align( const Size& size,
+                    CharacterIndex startIndex,
+                    Length numberOfCharacters,
+                    Text::HorizontalAlignment::Type horizontalAlignment,
+                    Vector<LineRun>& lines,
+                    float& alignmentOffset )
 {
   mImpl->Align( size,
                 startIndex,
                 numberOfCharacters,
-                lines );
+                horizontalAlignment,
+                lines,
+                alignmentOffset );
+}
+
+void Engine::SetDefaultLineSpacing( float lineSpacing )
+{
+  mImpl->mDefaultLineSpacing = lineSpacing;
 }
 
+float Engine::GetDefaultLineSpacing() const
+{
+  return mImpl->mDefaultLineSpacing;
+}
+
+} // namespace Layout
+
 } // namespace Text
 
 } // namespace Toolkit