[dali_2.3.22] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
index 077b598..e78a544 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -28,7 +28,9 @@
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/layouts/layout-engine-helper-functions.h>
 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 
 namespace Dali
 {
@@ -36,6 +38,20 @@ namespace Toolkit
 {
 namespace Text
 {
+float GetLineHeight(const LineRun lineRun, bool isLastLine)
+{
+  // The line height is the addition of the line ascender, the line descender and the line spacing.
+  // However, the line descender has a negative value, hence the subtraction.
+  // In case this is the only/last line then line spacing should be ignored.
+  float lineHeight = lineRun.ascender - lineRun.descender;
+
+  if(!isLastLine || lineRun.lineSpacing > 0)
+  {
+    lineHeight += lineRun.lineSpacing;
+  }
+  return lineHeight;
+}
+
 namespace Layout
 {
 namespace
@@ -44,12 +60,13 @@ namespace
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
 #endif
 
-const float              MAX_FLOAT      = std::numeric_limits<float>::max();
-const CharacterDirection LTR            = false;
-const CharacterDirection RTL            = !LTR;
-const float              LINE_SPACING   = 0.f;
-const float              MIN_LINE_SIZE  = 0.f;
-const Character          HYPHEN_UNICODE = 0x002D;
+const float              MAX_FLOAT          = std::numeric_limits<float>::max();
+const CharacterDirection LTR                = false;
+const CharacterDirection RTL                = !LTR;
+const float              LINE_SPACING       = 0.f;
+const float              MIN_LINE_SIZE      = 0.f;
+const Character          HYPHEN_UNICODE     = 0x002D;
+const float              RELATIVE_LINE_SIZE = 1.f;
 
 inline bool isEmptyLineAtLast(const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line)
 {
@@ -80,7 +97,8 @@ struct LineLayout
     glyphIndexInSecondHalfLine{0u},
     characterIndexInSecondHalfLine{0u},
     numberOfGlyphsInSecondHalfLine{0u},
-    numberOfCharactersInSecondHalfLine{0u}
+    numberOfCharactersInSecondHalfLine{0u},
+    relativeLineSize{1.0f}
 
   {
   }
@@ -103,6 +121,7 @@ struct LineLayout
     characterIndexInSecondHalfLine     = 0u;
     numberOfGlyphsInSecondHalfLine     = 0u;
     numberOfCharactersInSecondHalfLine = 0u;
+    relativeLineSize                   = 1.0f;
   }
 
   GlyphIndex         glyphIndex;                ///< Index of the first glyph to be laid-out.
@@ -123,6 +142,8 @@ struct LineLayout
   CharacterIndex characterIndexInSecondHalfLine;     ///< Index of the first character to be laid-out for the second half of line.
   Length         numberOfGlyphsInSecondHalfLine;     ///< The number of glyph which fit in one line for the second half of line.
   Length         numberOfCharactersInSecondHalfLine; ///< The number of characters which fit in one line for the second half of line.
+
+  float relativeLineSize; ///< The relative line size to be applied for this line.
 };
 
 struct LayoutBidiParameters
@@ -147,11 +168,56 @@ struct Engine::Impl
   : mLayout{Layout::Engine::SINGLE_LINE_BOX},
     mCursorWidth{0.f},
     mDefaultLineSpacing{LINE_SPACING},
-    mDefaultLineSize{MIN_LINE_SIZE}
+    mDefaultLineSize{MIN_LINE_SIZE},
+    mRelativeLineSize{RELATIVE_LINE_SIZE}
   {
   }
 
   /**
+   * @brief get the line spacing.
+   *
+   * @param[in] textSize The text size.
+   * @param[in] relativeLineSize The relative line size to be applied.
+   * @return the line spacing value.
+   */
+  float GetLineSpacing(float textSize, float relativeLineSize)
+  {
+    float lineSpacing;
+    float relTextSize;
+
+    // Sets the line size
+    lineSpacing = mDefaultLineSize - textSize;
+    lineSpacing = lineSpacing < 0.f ? 0.f : lineSpacing;
+
+    // Add the line spacing
+    lineSpacing += mDefaultLineSpacing;
+
+    //subtract line spcaing if relativeLineSize < 1 & larger than min height
+    relTextSize = textSize * relativeLineSize;
+    if(relTextSize > mDefaultLineSize)
+    {
+      if(relativeLineSize < 1)
+      {
+        //subtract the difference (always will be positive)
+        lineSpacing -= (textSize - relTextSize);
+      }
+      else
+      {
+        //reverse the addition in the top.
+        if(mDefaultLineSize > textSize)
+        {
+          lineSpacing -= mDefaultLineSize - textSize;
+        }
+
+        //add difference instead
+        lineSpacing += relTextSize - textSize;
+      }
+    }
+
+    return lineSpacing;
+  }
+
+  /**
    * @brief Updates the line ascender and descender with the metrics of a new font.
    *
    * @param[in] glyphMetrics The metrics of the new font.
@@ -179,12 +245,7 @@ struct Engine::Impl
     // Sets the minimum descender.
     lineLayout.descender = std::min(lineLayout.descender, fontMetrics.descender);
 
-    // Sets the line size
-    lineLayout.lineSpacing = mDefaultLineSize - (lineLayout.ascender + -lineLayout.descender);
-    lineLayout.lineSpacing = lineLayout.lineSpacing < 0.f ? 0.f : lineLayout.lineSpacing;
-
-    // Add the line spacing
-    lineLayout.lineSpacing += mDefaultLineSpacing;
+    lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender, lineLayout.relativeLineSize);
   }
 
   /**
@@ -244,10 +305,16 @@ struct Engine::Impl
 
     const float      outlineWidth                = static_cast<float>(parameters.textModel->GetOutlineWidth());
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
+    const float      modelCharacterSpacing       = parameters.textModel->mVisualModel->GetCharacterSpacing();
+
+    // Get the character-spacing runs.
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = parameters.textModel->mVisualModel->GetCharacterSpacingGlyphRuns();
 
     CharacterIndex characterLogicalIndex = 0u;
     CharacterIndex characterVisualIndex  = 0u;
 
+    float calculatedAdvance = 0.f;
+
     // If there are characters in the second half of Line then the first visual index mapped from visualToLogicalMapSecondHalf
     // Otherwise maps the first visual index from visualToLogicalMap.
     // This is to initialize the first visual index.
@@ -272,7 +339,9 @@ struct Engine::Impl
         {
           const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
 
-          whiteSpaceLengthEndOfLine += glyphInfo.advance;
+          const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+          calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
+          whiteSpaceLengthEndOfLine += calculatedAdvance;
 
           ++characterLogicalIndex;
           characterVisualIndex = bidirectionalLineInfo.characterRunForSecondHalfLine.characterIndex + *(bidirectionalLineInfo.visualToLogicalMapSecondHalf + characterLogicalIndex);
@@ -293,7 +362,9 @@ struct Engine::Impl
         {
           const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
 
-          whiteSpaceLengthEndOfLine += glyphInfo.advance;
+          const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+          calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
+          whiteSpaceLengthEndOfLine += calculatedAdvance;
 
           ++characterLogicalIndex;
           characterVisualIndex = bidirectionalLineInfo.characterRun.characterIndex + *(bidirectionalLineInfo.visualToLogicalMap + characterLogicalIndex);
@@ -310,11 +381,14 @@ struct Engine::Impl
                                                                   charactersPerGlyphBuffer);
 
     GlyphMetrics glyphMetrics;
+    const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+    calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
     GetGlyphsMetrics(glyphIndex,
                      numberOfGLyphsInGroup,
                      glyphMetrics,
                      glyphsBuffer,
-                     mMetrics);
+                     mMetrics,
+                     calculatedAdvance);
 
     float penX = -glyphMetrics.xBearing + mCursorWidth + outlineWidth;
 
@@ -339,11 +413,14 @@ struct Engine::Impl
         characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
 
         GlyphMetrics glyphMetrics;
+        const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+        calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
         GetGlyphsMetrics(glyphIndex,
                          numberOfGLyphsInGroup,
                          glyphMetrics,
                          glyphsBuffer,
-                         mMetrics);
+                         mMetrics,
+                         calculatedAdvance);
 
         if(isWhiteSpace)
         {
@@ -372,7 +449,16 @@ struct Engine::Impl
           {
             whiteSpaceLengthEndOfLine = 0.f;
           }
-          length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+
+          if(parameters.textModel->mRemoveBackInset)
+          {
+            length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+          }
+          else
+          {
+            length = std::max(length, penX + glyphMetrics.advance);
+          }
+
           penX += (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
         }
       }
@@ -399,11 +485,14 @@ struct Engine::Impl
       characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
 
       GlyphMetrics glyphMetrics;
+      const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+      calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
       GetGlyphsMetrics(glyphIndex,
                        numberOfGLyphsInGroup,
                        glyphMetrics,
                        glyphsBuffer,
-                       mMetrics);
+                       mMetrics,
+                       calculatedAdvance);
 
       if(isWhiteSpace)
       {
@@ -432,7 +521,15 @@ struct Engine::Impl
         {
           whiteSpaceLengthEndOfLine = 0.f;
         }
-        length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+
+        if(parameters.textModel->mRemoveBackInset)
+        {
+          length = std::max(length, penX + glyphMetrics.xBearing + glyphMetrics.width);
+        }
+        else
+        {
+          length = std::max(length, penX + glyphMetrics.advance);
+        }
         penX += (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
       }
     }
@@ -587,6 +684,7 @@ struct Engine::Impl
    * @param[out] lineLayout The line layout.
    * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ).
    * @param[in] ellipsisPosition Where is the location the text elide
+   * @param[in] hiddenInputEnabled Whether the hidden input is enabled.
    */
   void GetLineLayoutForBox(const Parameters&                 parameters,
                            LayoutBidiParameters&             bidiParameters,
@@ -594,7 +692,8 @@ struct Engine::Impl
                            bool                              completelyFill,
                            DevelText::EllipsisPosition::Type ellipsisPosition,
                            bool                              enforceEllipsisInSingleLine,
-                           bool                              elideTextEnabled)
+                           bool                              elideTextEnabled,
+                           bool                              hiddenInputEnabled)
   {
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n");
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  initial glyph index : %d\n", lineLayout.glyphIndex);
@@ -633,13 +732,24 @@ struct Engine::Impl
     float widthFirstHalf = ((ellipsisPosition != DevelText::EllipsisPosition::MIDDLE) ? targetWidth : targetWidth - std::floor(targetWidth / 2));
 
     bool isSecondHalf = false;
+    // Character Spacing
+    const float             modelCharacterSpacing     = parameters.textModel->mVisualModel->GetCharacterSpacing();
+    float                   calculatedAdvance         = 0.f;
+    Vector<CharacterIndex>& glyphToCharacterMap       = parameters.textModel->mVisualModel->mGlyphsToCharacters;
+    const CharacterIndex*   glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+
+    // Get the character-spacing runs.
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = parameters.textModel->mVisualModel->GetCharacterSpacingGlyphRuns();
 
     GlyphMetrics glyphMetrics;
+    const float  characterSpacing = GetGlyphCharacterSpacing(lineLayout.glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+    calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance);
     GetGlyphsMetrics(lineLayout.glyphIndex,
                      numberOfGLyphsInGroup,
                      glyphMetrics,
                      glyphsBuffer,
-                     mMetrics);
+                     mMetrics,
+                     calculatedAdvance);
 
     // Set the direction of the first character of the line.
     lineLayout.characterIndex = *(glyphsToCharactersBuffer + lineLayout.glyphIndex);
@@ -652,7 +762,14 @@ struct Engine::Impl
     // 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.penX = mCursorWidth + outlineWidth;
+    if(parameters.textModel->mRemoveFrontInset)
+    {
+      tmpLineLayout.penX -= glyphMetrics.xBearing;
+    }
+
+    tmpLineLayout.relativeLineSize = lineLayout.relativeLineSize;
 
     // Calculate the line height if there is no characters.
     FontId lastFontId = glyphMetrics.fontId;
@@ -674,11 +791,14 @@ struct Engine::Impl
                                                                     charactersPerGlyphBuffer);
 
       GlyphMetrics glyphMetrics;
+      const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
+      calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
       GetGlyphsMetrics(glyphIndex,
                        numberOfGLyphsInGroup,
                        glyphMetrics,
                        glyphsBuffer,
-                       mMetrics);
+                       mMetrics,
+                       calculatedAdvance);
 
       const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup == totalNumberOfGlyphs;
 
@@ -730,17 +850,28 @@ struct Engine::Impl
       const float previousTmpLength                    = tmpLineLayout.length;
       const float previousTmpWhiteSpaceLengthEndOfLine = tmpLineLayout.whiteSpaceLengthEndOfLine;
 
-      if(isWhiteSpace)
+      // The calculated text size is used in atlas renderer.
+      // When the text is all white space, partial render issue occurs because the width is 0.
+      // To avoid issue, do not remove the white space size in hidden input mode.
+      if(isWhiteSpace && !hiddenInputEnabled)
       {
         // Add the length to the length of white spaces at the end of the line.
-        tmpLineLayout.whiteSpaceLengthEndOfLine += glyphMetrics.advance; // The advance is used as the width is always zero for the white spaces.
+        tmpLineLayout.whiteSpaceLengthEndOfLine += glyphMetrics.advance;
+        // The advance is used as the width is always zero for the white spaces.
       }
       else
       {
         tmpLineLayout.penX += tmpLineLayout.previousAdvance + tmpLineLayout.whiteSpaceLengthEndOfLine;
         tmpLineLayout.previousAdvance = (glyphMetrics.advance + parameters.interGlyphExtraAdvance);
 
-        tmpLineLayout.length = std::max(tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.xBearing + glyphMetrics.width);
+        if(parameters.textModel->mRemoveBackInset)
+        {
+          tmpLineLayout.length = std::max(tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.xBearing + glyphMetrics.width);
+        }
+        else
+        {
+          tmpLineLayout.length = std::max(tmpLineLayout.length, tmpLineLayout.penX + glyphMetrics.advance);
+        }
 
         // Clear the white space length at the end of the line.
         tmpLineLayout.whiteSpaceLengthEndOfLine = 0.f;
@@ -771,11 +902,14 @@ struct Engine::Impl
         while(tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth && glyphIndexToRemove < glyphIndex)
         {
           GlyphMetrics glyphMetrics;
+          const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndexToRemove, characterSpacingGlyphRuns, modelCharacterSpacing);
+          calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance);
           GetGlyphsMetrics(glyphIndexToRemove,
                            numberOfGLyphsInGroup,
                            glyphMetrics,
                            glyphsBuffer,
-                           mMetrics);
+                           mMetrics,
+                           calculatedAdvance);
 
           const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup(glyphIndexToRemove,
                                                                         lastGlyphOfParagraphPlusOne,
@@ -807,7 +941,7 @@ struct Engine::Impl
             tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
           }
 
-          if(isRemovedGlyphWhiteSpace)
+          if(isRemovedGlyphWhiteSpace && !hiddenInputEnabled)
           {
             tmpLineLayout.penX -= glyphMetrics.advance;
             tmpLineLayout.length -= glyphMetrics.advance;
@@ -1000,35 +1134,36 @@ struct Engine::Impl
     // If it has a negative x bearing, it will exceed the boundaries of the actor,
     // so the penX position needs to be moved to the right.
     const GlyphInfo& glyph = *(glyphsBuffer + startIndexForGlyph);
-    float            penX  = -glyph.xBearing + mCursorWidth + outlineWidth; //
+    float            penX  = mCursorWidth + outlineWidth; //
 
-    for(GlyphIndex i = 0u; i < numberOfGlyphs; ++i)
+    if(layoutParameters.textModel->mRemoveFrontInset)
     {
-      const GlyphInfo& glyph    = *(glyphsBuffer + startIndexForGlyph + i);
-      Vector2&         position = *(glyphPositionsBuffer + startIndexForGlyphPositions + i);
-
-      position.x = penX + glyph.xBearing;
-      position.y = -glyph.yBearing;
-
-      penX += (glyph.advance + interGlyphExtraAdvance);
+      penX -= glyph.xBearing;
     }
 
+    CalculateGlyphPositionsLTR(layoutParameters.textModel->mVisualModel,
+                               layoutParameters.textModel->mLogicalModel,
+                               interGlyphExtraAdvance,
+                               numberOfGlyphs,
+                               startIndexForGlyph, // startIndexForGlyph is the index of the first glyph in the line
+                               startIndexForGlyphPositions,
+                               glyphPositionsBuffer,
+                               penX);
+
     if(layout.isSplitToTwoHalves)
     {
       const GlyphIndex startIndexForGlyphInSecondHalf         = layout.glyphIndexInSecondHalfLine;
       const Length     numberOfGlyphsInSecondHalfLine         = layout.numberOfGlyphsInSecondHalfLine;
       const GlyphIndex startIndexForGlyphPositionsnSecondHalf = layout.glyphIndexInSecondHalfLine - layoutParameters.startGlyphIndex;
 
-      for(GlyphIndex i = 0u; i < numberOfGlyphsInSecondHalfLine; ++i)
-      {
-        const GlyphInfo& glyph    = *(glyphsBuffer + startIndexForGlyphInSecondHalf + i);
-        Vector2&         position = *(glyphPositionsBuffer + startIndexForGlyphPositionsnSecondHalf + i);
-
-        position.x = penX + glyph.xBearing;
-        position.y = -glyph.yBearing;
-
-        penX += (glyph.advance + interGlyphExtraAdvance);
-      }
+      CalculateGlyphPositionsLTR(layoutParameters.textModel->mVisualModel,
+                                 layoutParameters.textModel->mLogicalModel,
+                                 interGlyphExtraAdvance,
+                                 numberOfGlyphsInSecondHalfLine,
+                                 startIndexForGlyphInSecondHalf, // startIndexForGlyph is the index of the first glyph in the line
+                                 startIndexForGlyphPositionsnSecondHalf,
+                                 glyphPositionsBuffer,
+                                 penX);
     }
   }
 
@@ -1037,11 +1172,9 @@ struct Engine::Impl
                          LayoutBidiParameters& layoutBidiParameters,
                          const LineLayout&     layout)
   {
-    const Character* const          textBuffer               = layoutParameters.textModel->mLogicalModel->mText.Begin();
     const BidirectionalLineInfoRun& bidiLine                 = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo[layoutBidiParameters.bidiLineIndex];
     const GlyphInfo* const          glyphsBuffer             = layoutParameters.textModel->mVisualModel->mGlyphs.Begin();
     const GlyphIndex* const         charactersToGlyphsBuffer = layoutParameters.textModel->mVisualModel->mCharactersToGlyph.Begin();
-    const Length* const             glyphsPerCharacterBuffer = layoutParameters.textModel->mVisualModel->mGlyphsPerCharacter.Begin();
 
     CharacterIndex characterLogicalIndex = 0u;
     CharacterIndex characterVisualIndex  = bidiLine.characterRunForSecondHalfLine.characterIndex + *(bidiLine.visualToLogicalMapSecondHalf + characterLogicalIndex);
@@ -1051,20 +1184,14 @@ struct Engine::Impl
 
     if(layout.isSplitToTwoHalves)
     {
-      while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
-      {
-        const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
-        const GlyphInfo& glyph      = *(glyphsBuffer + glyphIndex);
-
-        Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
-        position.x        = penX;
-        position.y        = -glyph.yBearing;
-
-        penX += glyph.advance;
-
-        ++characterLogicalIndex;
-        characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
-      }
+      CalculateGlyphPositionsRTL(layoutParameters.textModel->mVisualModel,
+                                 layoutParameters.textModel->mLogicalModel,
+                                 layoutBidiParameters.bidiLineIndex,
+                                 layoutParameters.startGlyphIndex,
+                                 glyphPositionsBuffer,
+                                 characterVisualIndex,
+                                 characterLogicalIndex,
+                                 penX);
     }
 
     if(characterLogicalIndex == bidiLine.characterRunForSecondHalfLine.numberOfCharacters)
@@ -1073,20 +1200,14 @@ struct Engine::Impl
       characterLogicalIndex = 0u;
       characterVisualIndex  = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
 
-      while(TextAbstraction::IsWhiteSpace(*(textBuffer + characterVisualIndex)))
-      {
-        const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
-        const GlyphInfo& glyph      = *(glyphsBuffer + glyphIndex);
-
-        Vector2& position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
-        position.x        = penX;
-        position.y        = -glyph.yBearing;
-
-        penX += glyph.advance;
-
-        ++characterLogicalIndex;
-        characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
-      }
+      CalculateGlyphPositionsRTL(layoutParameters.textModel->mVisualModel,
+                                 layoutParameters.textModel->mLogicalModel,
+                                 layoutBidiParameters.bidiLineIndex,
+                                 layoutParameters.startGlyphIndex,
+                                 glyphPositionsBuffer,
+                                 characterVisualIndex,
+                                 characterLogicalIndex,
+                                 penX);
     }
 
     const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex);
@@ -1097,59 +1218,28 @@ struct Engine::Impl
     // Traverses the characters of the right to left paragraph.
     if(layout.isSplitToTwoHalves && !extendedToSecondHalf)
     {
-      for(; characterLogicalIndex < bidiLine.characterRunForSecondHalfLine.numberOfCharacters;
-          ++characterLogicalIndex)
-      {
-        // Convert the character in the logical order into the character in the visual order.
-        const CharacterIndex characterVisualIndex = bidiLine.characterRunForSecondHalfLine.characterIndex + *(bidiLine.visualToLogicalMapSecondHalf + characterLogicalIndex);
-
-        // Get the number of glyphs of the character.
-        const Length numberOfGlyphs = *(glyphsPerCharacterBuffer + characterVisualIndex);
-
-        for(GlyphIndex index = 0u; index < numberOfGlyphs; ++index)
-        {
-          // Convert the character in the visual order into the glyph in the visual order.
-          const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex) + index;
-
-          DALI_ASSERT_DEBUG(glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count());
-
-          const GlyphInfo& glyph    = *(glyphsBuffer + glyphIndex);
-          Vector2&         position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
-
-          position.x = penX + glyph.xBearing;
-          position.y = -glyph.yBearing;
-
-          penX += (glyph.advance + layoutParameters.interGlyphExtraAdvance);
-        }
-      }
+      TraversesCharactersForGlyphPositionsRTL(layoutParameters.textModel->mVisualModel,
+                                              layoutParameters.textModel->mLogicalModel->mText.Begin(),
+                                              layoutParameters.startGlyphIndex,
+                                              layoutParameters.interGlyphExtraAdvance,
+                                              bidiLine.characterRunForSecondHalfLine,
+                                              bidiLine.visualToLogicalMapSecondHalf,
+                                              glyphPositionsBuffer,
+                                              characterLogicalIndex,
+                                              penX);
     }
 
     characterLogicalIndex = extendedToSecondHalf ? characterLogicalIndex : 0u;
-    for(; characterLogicalIndex < bidiLine.characterRun.numberOfCharacters;
-        ++characterLogicalIndex)
-    {
-      // Convert the character in the logical order into the character in the visual order.
-      const CharacterIndex characterVisualIndex = bidiLine.characterRun.characterIndex + *(bidiLine.visualToLogicalMap + characterLogicalIndex);
-
-      // Get the number of glyphs of the character.
-      const Length numberOfGlyphs = *(glyphsPerCharacterBuffer + characterVisualIndex);
-
-      for(GlyphIndex index = 0u; index < numberOfGlyphs; ++index)
-      {
-        // Convert the character in the visual order into the glyph in the visual order.
-        const GlyphIndex glyphIndex = *(charactersToGlyphsBuffer + characterVisualIndex) + index;
-
-        DALI_ASSERT_DEBUG(glyphIndex < layoutParameters.textModel->mVisualModel->mGlyphs.Count());
-
-        const GlyphInfo& glyph    = *(glyphsBuffer + glyphIndex);
-        Vector2&         position = *(glyphPositionsBuffer + glyphIndex - layoutParameters.startGlyphIndex);
 
-        position.x = penX + glyph.xBearing;
-        position.y = -glyph.yBearing;
-
-        penX += (glyph.advance + layoutParameters.interGlyphExtraAdvance);
-      }
-    }
+    TraversesCharactersForGlyphPositionsRTL(layoutParameters.textModel->mVisualModel,
+                                            layoutParameters.textModel->mLogicalModel->mText.Begin(),
+                                            layoutParameters.startGlyphIndex,
+                                            layoutParameters.interGlyphExtraAdvance,
+                                            bidiLine.characterRun,
+                                            bidiLine.visualToLogicalMap,
+                                            glyphPositionsBuffer,
+                                            characterLogicalIndex,
+                                            penX);
   }
 
   /**
@@ -1196,6 +1286,7 @@ struct Engine::Impl
    * @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
+   * @param[in] isHiddenInputEnabled Whether the hidden input is enabled.
    * @param[in] ellipsisPosition Where is the location the text elide
    *
    * return Whether the line is ellipsized.
@@ -1209,21 +1300,31 @@ struct Engine::Impl
                     Length&                           numberOfLines,
                     float                             penY,
                     bool&                             isAutoScrollEnabled,
+                    bool                              isAutoScrollMaxTextureExceeded,
+                    bool                              isHiddenInputEnabled,
                     DevelText::EllipsisPosition::Type ellipsisPosition,
                     bool                              enforceEllipsisInSingleLine)
   {
-    const bool ellipsis    = enforceEllipsisInSingleLine || (isAutoScrollEnabled ? (penY - layout.descender > layoutParameters.boundingBox.height) : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width))));
+    const bool ellipsis    = enforceEllipsisInSingleLine || (isAutoScrollEnabled ? isAutoScrollMaxTextureExceeded : ((penY - layout.descender > layoutParameters.boundingBox.height) || ((mLayout == SINGLE_LINE_BOX) && (layout.length > layoutParameters.boundingBox.width))));
     const bool isMultiline = !enforceEllipsisInSingleLine && (mLayout == MULTI_LINE_BOX);
     if(ellipsis && (ellipsisPosition == DevelText::EllipsisPosition::END || !isMultiline))
     {
-      isAutoScrollEnabled = false;
-      // Do not layout more lines if ellipsis is enabled.
+      if(penY - layout.descender > layoutParameters.boundingBox.height)
+      {
+        // Even if auto scroll is enabled and text is bigger than max texture size,
+        // if the the height is small, auto scroll should not work.
+        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 = nullptr;
       LineLayout ellipsisLayout;
+
+      ellipsisLayout.relativeLineSize = layout.relativeLineSize;
+
       if(0u != numberOfLines)
       {
         // Get the last line and layout it again with the 'completelyFill' flag to true.
@@ -1250,7 +1351,8 @@ struct Engine::Impl
                           true,
                           ellipsisPosition,
                           enforceEllipsisInSingleLine,
-                          true);
+                          true,
+                          isHiddenInputEnabled);
 
       if(ellipsisPosition == DevelText::EllipsisPosition::START && !isMultiline)
       {
@@ -1275,7 +1377,16 @@ struct Engine::Impl
       layoutSize.width = layoutParameters.boundingBox.width;
       if(layoutSize.height < Math::MACHINE_EPSILON_1000)
       {
-        layoutSize.height += (lineRun->ascender + -lineRun->descender) + lineRun->lineSpacing;
+        layoutSize.height += GetLineHeight(*lineRun, true);
+      }
+      else
+      {
+        //when we apply ellipsis, the last line should not take negative linespacing into account for layoutSize.height calculation
+        //usually we don't includ it in normal cases using GetLineHeight()
+        if(lineRun->lineSpacing < 0)
+        {
+          layoutSize.height -= lineRun->lineSpacing;
+        }
       }
 
       const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
@@ -1371,10 +1482,7 @@ struct Engine::Impl
     lineRun.direction = layout.direction;
     lineRun.ellipsis  = false;
 
-    lineRun.lineSpacing = mDefaultLineSize - (lineRun.ascender + -lineRun.descender);
-    lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing;
-
-    lineRun.lineSpacing += mDefaultLineSpacing;
+    lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, layout.relativeLineSize);
 
     // Update the actual size.
     if(lineRun.width > layoutSize.width)
@@ -1382,7 +1490,7 @@ struct Engine::Impl
       layoutSize.width = lineRun.width;
     }
 
-    layoutSize.height += (lineRun.ascender + -lineRun.descender) + lineRun.lineSpacing;
+    layoutSize.height += GetLineHeight(lineRun, isLastLine);
   }
 
   /**
@@ -1404,6 +1512,12 @@ struct Engine::Impl
   {
     const Vector<GlyphInfo>& glyphs = layoutParameters.textModel->mVisualModel->mGlyphs;
 
+    if(glyphs.Size() == 0u)
+    {
+      // Do nothing.
+      return;
+    }
+
     // Need to add a new line with no characters but with height to increase the layoutSize.height
     const GlyphInfo& glyphInfo = glyphs[glyphs.Count() - 1u];
 
@@ -1428,12 +1542,13 @@ struct Engine::Impl
     lineRun.direction                       = LTR;
     lineRun.ellipsis                        = false;
 
-    lineRun.lineSpacing = mDefaultLineSize - (lineRun.ascender + -lineRun.descender);
-    lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing;
+    BoundedParagraphRun currentParagraphRun;
+    LineLayout          tempLineLayout;
+    (GetBoundedParagraph(layoutParameters.textModel->GetBoundedParagraphRuns(), characterIndex, currentParagraphRun) ? SetRelativeLineSize(&currentParagraphRun, tempLineLayout) : SetRelativeLineSize(nullptr, tempLineLayout));
 
-    lineRun.lineSpacing += mDefaultLineSpacing;
+    lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, tempLineLayout.relativeLineSize);
 
-    layoutSize.height += (lineRun.ascender + -lineRun.descender) + lineRun.lineSpacing;
+    layoutSize.height += GetLineHeight(lineRun, true);
   }
 
   /**
@@ -1450,14 +1565,15 @@ struct Engine::Impl
         it != endIt;
         ++it)
     {
-      const LineRun& line = *it;
+      const LineRun& line       = *it;
+      bool           isLastLine = (it + 1 == endIt);
 
       if(line.width > layoutSize.width)
       {
         layoutSize.width = line.width;
       }
 
-      layoutSize.height += (line.ascender + -line.descender) + line.lineSpacing;
+      layoutSize.height += GetLineHeight(line, isLastLine);
     }
   }
 
@@ -1490,10 +1606,57 @@ struct Engine::Impl
     }
   }
 
+  /**
+   * @brief Sets the relative line size for the LineLayout
+   *
+   * @param[in] currentParagraphRun Contains the bounded paragraph for this line layout.
+   * @param[in,out] lineLayout The line layout to be updated.
+   */
+  void SetRelativeLineSize(BoundedParagraphRun* currentParagraphRun, LineLayout& lineLayout)
+  {
+    lineLayout.relativeLineSize = mRelativeLineSize;
+
+    if(currentParagraphRun != nullptr && currentParagraphRun->relativeLineSizeDefined)
+    {
+      lineLayout.relativeLineSize = currentParagraphRun->relativeLineSize;
+    }
+  }
+
+  /**
+   * @brief Get the bounded paragraph for the characterIndex if exists.
+   *
+   * @param[in] boundedParagraphRuns The bounded paragraph list to search in.
+   * @param[in] characterIndex The character index to get bounded paragraph for.
+   * @param[out] currentParagraphRun Contains the bounded paragraph if found for the characterIndex.
+   *
+   * @return returns true if a bounded paragraph was found.
+   */
+  bool GetBoundedParagraph(const Vector<BoundedParagraphRun> boundedParagraphRuns, CharacterIndex characterIndex, BoundedParagraphRun& currentParagraphRun)
+  {
+    for(Vector<BoundedParagraphRun>::Iterator it    = boundedParagraphRuns.Begin(),
+                                              endIt = boundedParagraphRuns.End();
+        it != endIt;
+        ++it)
+    {
+      BoundedParagraphRun& tempParagraphRun = *it;
+
+      if(characterIndex >= tempParagraphRun.characterRun.characterIndex &&
+         characterIndex < (tempParagraphRun.characterRun.characterIndex + tempParagraphRun.characterRun.numberOfCharacters))
+      {
+        currentParagraphRun = tempParagraphRun;
+        return true;
+      }
+    }
+
+    return false;
+  }
+
   bool LayoutText(Parameters&                       layoutParameters,
                   Size&                             layoutSize,
                   bool                              elideTextEnabled,
                   bool&                             isAutoScrollEnabled,
+                  bool                              isAutoScrollMaxTextureExceeded,
+                  bool                              isHiddenInputEnabled,
                   DevelText::EllipsisPosition::Type ellipsisPosition)
   {
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
@@ -1508,7 +1671,8 @@ struct Engine::Impl
     layoutParameters.textModel->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(0u);
     layoutParameters.textModel->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(0u);
 
-    Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
+    Vector<LineRun>&                   lines                = layoutParameters.textModel->mVisualModel->mLines;
+    const Vector<BoundedParagraphRun>& boundedParagraphRuns = layoutParameters.textModel->GetBoundedParagraphRuns();
 
     if(0u == layoutParameters.numberOfGlyphs)
     {
@@ -1568,7 +1732,7 @@ struct Engine::Impl
     // Retrieve BiDi info.
     const bool hasBidiParagraphs = !layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo.Empty();
 
-    const CharacterIndex* const                  glyphsToCharactersBuffer    = hasBidiParagraphs ? layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin() : nullptr;
+    const CharacterIndex* const                  glyphsToCharactersBuffer    = layoutParameters.textModel->mVisualModel->mGlyphsToCharacters.Begin();
     const Vector<BidirectionalParagraphInfoRun>& bidirectionalParagraphsInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalParagraphInfo;
     const Vector<BidirectionalLineInfoRun>&      bidirectionalLinesInfo      = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
 
@@ -1672,13 +1836,18 @@ struct Engine::Impl
       LineLayout layout;
       layout.direction  = layoutBidiParameters.paragraphDirection;
       layout.glyphIndex = index;
+
+      BoundedParagraphRun currentParagraphRun;
+      (GetBoundedParagraph(boundedParagraphRuns, *(glyphsToCharactersBuffer + index), currentParagraphRun) ? SetRelativeLineSize(&currentParagraphRun, layout) : SetRelativeLineSize(nullptr, layout));
+
       GetLineLayoutForBox(layoutParameters,
                           layoutBidiParameters,
                           layout,
                           false,
                           ellipsisPosition,
                           false,
-                          elideTextEnabled);
+                          elideTextEnabled,
+                          isHiddenInputEnabled);
 
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex);
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "       character index %d\n", layout.characterIndex);
@@ -1686,6 +1855,14 @@ struct Engine::Impl
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  number of characters %d\n", layout.numberOfCharacters);
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "                length %f\n", layout.length);
 
+      CharacterIndex lastCharacterInParagraph = currentParagraphRun.characterRun.characterIndex + currentParagraphRun.characterRun.numberOfCharacters - 1;
+
+      //check if this is the last line in paragraph, if false we should use the default relative line size (the one set using the property)
+      if(lastCharacterInParagraph >= layout.characterIndex && lastCharacterInParagraph < layout.characterIndex + layout.numberOfCharacters)
+      {
+        layout.relativeLineSize = mRelativeLineSize;
+      }
+
       if(0u == layout.numberOfGlyphs + layout.numberOfGlyphsInSecondHalfLine)
       {
         // The width is too small and no characters are laid-out.
@@ -1720,6 +1897,8 @@ struct Engine::Impl
                                 numberOfLines,
                                 penY,
                                 isAutoScrollEnabled,
+                                isAutoScrollMaxTextureExceeded,
+                                isHiddenInputEnabled,
                                 ellipsisPosition,
                                 false);
       }
@@ -1738,6 +1917,8 @@ struct Engine::Impl
                                   numberOfLines,
                                   penY,
                                   isAutoScrollEnabled,
+                                  isAutoScrollMaxTextureExceeded,
+                                  isHiddenInputEnabled,
                                   ellipsisPosition,
                                   true);
         }
@@ -1829,14 +2010,7 @@ struct Engine::Impl
         }
 
         // Updates the vertical pen's position.
-        penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing;
-        // If there is a defaultLineSize, updates the pen's position.
-        if(mDefaultLineSize > 0.f)
-        {
-          float lineSpacing = mDefaultLineSize - (layout.ascender + -layout.descender);
-          lineSpacing       = lineSpacing < 0.f ? 0.f : lineSpacing;
-          penY += lineSpacing;
-        }
+        penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender, layout.relativeLineSize);
 
         // Increase the glyph index.
         index = nextIndex;
@@ -1861,7 +2035,6 @@ struct Engine::Impl
             linesBuffer[lineIndex].ellipsis = false;
           }
           numberOfLines--;
-          lineIndex++;
         }
         linesBuffer[0u].ellipsis = true;
       }
@@ -1881,7 +2054,7 @@ struct Engine::Impl
             linesBuffer[lineIndex].ellipsis = false;
           }
           numberOfLines--;
-          ellipsisLineIndex = middleLineIndex > 0u ? middleLineIndex - 1u : 0u;
+          ellipsisLineIndex = middleLineIndex - 1u;
           middleLineIndex   = (numberOfLines) / 2u;
         }
 
@@ -2071,18 +2244,23 @@ struct Engine::Impl
 
   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                       = LTR;
-    line.ellipsis                        = false;
-    line.lineSpacing                     = mDefaultLineSpacing;
+    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                                        = LTR;
+    line.ellipsis                                         = false;
+    line.lineSpacing                                      = mDefaultLineSpacing;
+    line.isSplitToTwoHalves                               = false;
+    line.glyphRunSecondHalf.glyphIndex                    = 0u;
+    line.glyphRunSecondHalf.numberOfGlyphs                = 0u;
+    line.characterRunForSecondHalfLine.characterIndex     = 0u;
+    line.characterRunForSecondHalfLine.numberOfCharacters = 0u;
   }
 
   Type  mLayout;
@@ -2091,6 +2269,7 @@ struct Engine::Impl
   float mDefaultLineSize;
 
   IntrusivePtr<Metrics> mMetrics;
+  float                 mRelativeLineSize;
 };
 
 Engine::Engine()
@@ -2134,12 +2313,16 @@ bool Engine::LayoutText(Parameters&                       layoutParameters,
                         Size&                             layoutSize,
                         bool                              elideTextEnabled,
                         bool&                             isAutoScrollEnabled,
+                        bool                              isAutoScrollMaxTextureExceeded,
+                        bool                              isHiddenInputEnabled,
                         DevelText::EllipsisPosition::Type ellipsisPosition)
 {
   return mImpl->LayoutText(layoutParameters,
                            layoutSize,
                            elideTextEnabled,
                            isAutoScrollEnabled,
+                           isAutoScrollMaxTextureExceeded,
+                           isHiddenInputEnabled,
                            ellipsisPosition);
 }
 
@@ -2182,6 +2365,16 @@ float Engine::GetDefaultLineSize() const
   return mImpl->mDefaultLineSize;
 }
 
+void Engine::SetRelativeLineSize(float relativeLineSize)
+{
+  mImpl->mRelativeLineSize = relativeLineSize;
+}
+
+float Engine::GetRelativeLineSize() const
+{
+  return mImpl->mRelativeLineSize;
+}
+
 } // namespace Layout
 
 } // namespace Text