Merge "Support paragraph attribute: relative line height" into devel/master
authorBowon Ryu <bowon.ryu@samsung.com>
Fri, 1 Apr 2022 10:04:30 +0000 (10:04 +0000)
committerGerrit Code Review <gerrit@review>
Fri, 1 Apr 2022 10:04:30 +0000 (10:04 +0000)
1  2 
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
dali-toolkit/internal/text/layouts/layout-engine.cpp

@@@ -20,8 -20,6 +20,8 @@@
  #include <dali-toolkit/devel-api/controls/text-controls/text-editor-devel.h>
  #include <dali-toolkit/devel-api/text/rendering-backend.h>
  #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 +
 +#include <dali/devel-api/actors/actor-devel.h>
  #include <dali/devel-api/adaptor-framework/clipboard.h>
  #include <dali/devel-api/adaptor-framework/key-devel.h>
  #include <dali/devel-api/text-abstraction/font-client.h>
@@@ -3632,9 -3630,6 +3632,9 @@@ int UtcDaliTextEditorEnableEditing(void
    application.SendNotification();
    application.Render();
  
 +  textEditor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, true);
 +  DALI_TEST_EQUALS(textEditor.GetProperty(DevelActor::Property::USER_INTERACTION_ENABLED).Get<bool>(), true, TEST_LOCATION);
 +
    textEditor.SetKeyInputFocus();
    textEditor.SetProperty(DevelTextEditor::Property::ENABLE_EDITING, false);
    application.ProcessEvent(GenerateKey("D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
    DALI_TEST_EQUALS(textEditor.GetProperty(TextEditor::Property::TEXT).Get<std::string>(), "D", TEST_LOCATION);
    DALI_TEST_EQUALS(textEditor.GetProperty(DevelTextEditor::Property::ENABLE_EDITING).Get<bool>(), true, TEST_LOCATION);
  
 +  // Check the user interaction enabled and for coverage
 +  DevelTextEditor::SelectWholeText(textEditor);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  textEditor.SetKeyInputFocus();
 +  textEditor.SetProperty(DevelActor::Property::USER_INTERACTION_ENABLED, false);
 +  application.ProcessEvent(GenerateKey("D", "", "D", KEY_D_CODE, 0, 0, Integration::KeyEvent::DOWN, "D", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  DALI_TEST_EQUALS(textEditor.GetProperty(TextEditor::Property::TEXT).Get<std::string>(), "D", TEST_LOCATION);
 +  DALI_TEST_EQUALS(textEditor.GetProperty(DevelActor::Property::USER_INTERACTION_ENABLED).Get<bool>(), false, TEST_LOCATION);
 +
    END_TEST;
  }
  
@@@ -5788,6 -5765,55 +5788,55 @@@ int UtcDaliToolkitTextEditorUnderlineTy
    END_TEST;
  }
  
+ int UtcDaliToolkitTextEditorMarkupRelativeLineHeight(void)
+ {
+   ToolkitTestApplication application;
+   tet_infoline(" UtcDaliToolkitTextEditorMarkupRelativeLineHeight");
+   TextEditor editor = TextEditor::New();
+   editor.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+   editor.SetProperty(TextEditor::Property::POINT_SIZE, 10);
+   editor.SetProperty(TextEditor::Property::TEXT, "line 1\nline 2\nline 3\nline 4\nline 5");
+   editor.SetProperty(DevelTextEditor::Property::RELATIVE_LINE_SIZE, 1.0f);
+   editor.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+   editor.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
+   TextEditor editorSingleLineParagraph = TextEditor::New();
+   editorSingleLineParagraph.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+   editorSingleLineParagraph.SetProperty(TextEditor::Property::POINT_SIZE, 10);
+   editorSingleLineParagraph.SetProperty(TextEditor::Property::TEXT, "<p>line 1</p><p rel-line-height=0.5>line 2</p>line 3<p rel-line-height=3>line 4</p>line 5");
+   editorSingleLineParagraph.SetProperty(DevelTextEditor::Property::RELATIVE_LINE_SIZE, 1.0f);
+   editorSingleLineParagraph.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+   editorSingleLineParagraph.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
+   TextEditor editorMultiLineParagraph = TextEditor::New();
+   editorMultiLineParagraph.SetProperty(Actor::Property::SIZE, Vector2(200.0f, 300.f));
+   editorMultiLineParagraph.SetProperty(TextEditor::Property::POINT_SIZE, 10);
+   editorMultiLineParagraph.SetProperty(TextEditor::Property::TEXT, "<p>line 1</p><p rel-line-height=0.5>line\n2</p>line 3<p rel-line-height=3>line\n4</p>line 5");
+   editorMultiLineParagraph.SetProperty(DevelTextEditor::Property::RELATIVE_LINE_SIZE, 1.0f);
+   editorMultiLineParagraph.SetProperty(DevelTextEditor::Property::ELLIPSIS, false);
+   editorMultiLineParagraph.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
+   application.GetScene().Add(editor);
+   application.GetScene().Add(editorSingleLineParagraph);
+   application.GetScene().Add(editorMultiLineParagraph);
+   application.SendNotification();
+   application.Render();
+   Vector3 naturalSize               = editor.GetNaturalSize();
+   Vector3 relativeSingleNaturalSize = editorSingleLineParagraph.GetNaturalSize();
+   Vector3 relativeMultiNaturalSize  = editorMultiLineParagraph.GetNaturalSize();
+   float lineSize = naturalSize.y / 5.0f; //total size/number of lines
+   //no effect of relative line size for paragraph with single line
+   DALI_TEST_EQUALS(naturalSize.y, relativeSingleNaturalSize.y, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+   DALI_TEST_EQUALS(lineSize*8.5f, relativeMultiNaturalSize.y, Math::MACHINE_EPSILON_1000, TEST_LOCATION);
+   END_TEST;
+ }
  int UtcDaliToolkitTextEditorRelativeLineHeight(void)
  {
    ToolkitTestApplication application;
@@@ -5947,83 -5973,4 +5996,83 @@@ int UtcDaliToolkitTexteditorParagraphTa
    application.Render();
  
    END_TEST;
 +}
 +
 +//Handle Emoji clustering for cursor handling
 +int utcDaliTextEditorClusteredEmojiDeletionBackSpaceKey(void)
 +{
 +  ToolkitTestApplication application;
 +  tet_infoline(" utcDaliTextEditorClusteredEmojiDeletionBackSpaceKey ");
 +  TextEditor textEditor = TextEditor::New();
 +  DALI_TEST_CHECK(textEditor);
 +
 +  application.GetScene().Add(textEditor);
 +
 +  // Avoid a crash when core load gl resources.
 +  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
 +
 +  textEditor.SetProperty(TextEditor::Property::TEXT, "ABC&#x1F468;&#x200D;&#x1F469;&#x200D;&#x1F467;&#x200D;&#x1F466;XY");
 +  textEditor.SetProperty(Dali::Toolkit::TextEditor::Property::ENABLE_MARKUP, true);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Set currsor
 +  textEditor.SetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION, 10);
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Set focus and remove Emoji
 +  textEditor.SetKeyInputFocus();
 +  application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +
 +  //Check the changed text and cursor position
 +  DALI_TEST_EQUALS(textEditor.GetProperty(TextEditor::Property::TEXT).Get<std::string>(), "ABCXY", TEST_LOCATION);
 +  DALI_TEST_EQUALS(textEditor.GetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION).Get<int>(), 3, TEST_LOCATION);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  END_TEST;
 +}
 +
 +int utcDaliTextEditorClusteredEmojiDeletionDeleteKey(void)
 +{
 +  ToolkitTestApplication application;
 +  tet_infoline(" utcDaliTextEditorClusteredEmojiDeletionDeleteKey ");
 +  TextEditor textEditor = TextEditor::New();
 +  DALI_TEST_CHECK(textEditor);
 +
 +  application.GetScene().Add(textEditor);
 +
 +  // Avoid a crash when core load gl resources.
 +  application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
 +
 +  textEditor.SetProperty(TextEditor::Property::TEXT, "ABC&#x1F468;&#x200D;&#x1F469;&#x200D;&#x1F467;&#x200D;&#x1F466;XY");
 +  textEditor.SetProperty(Dali::Toolkit::TextEditor::Property::ENABLE_MARKUP, true);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Set currsor
 +  textEditor.SetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION, 3);
 +  application.SendNotification();
 +  application.Render();
 +
 +  // Set focus and remove Emoji
 +  textEditor.SetKeyInputFocus();
 +  application.ProcessEvent(GenerateKey("", "", "", Dali::DevelKey::DALI_KEY_DELETE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
 +
 +  //Check the changed text and cursor position
 +  DALI_TEST_EQUALS(textEditor.GetProperty(TextEditor::Property::TEXT).Get<std::string>(), "ABCXY", TEST_LOCATION);
 +  DALI_TEST_EQUALS(textEditor.GetProperty(DevelTextEditor::Property::PRIMARY_CURSOR_POSITION).Get<int>(), 3, TEST_LOCATION);
 +
 +  // Render and notify
 +  application.SendNotification();
 +  application.Render();
 +
 +  END_TEST;
  }
@@@ -30,7 -30,6 +30,7 @@@
  #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
  {
@@@ -97,7 -96,8 +97,8 @@@ struct LineLayou
      glyphIndexInSecondHalfLine{0u},
      characterIndexInSecondHalfLine{0u},
      numberOfGlyphsInSecondHalfLine{0u},
-     numberOfCharactersInSecondHalfLine{0u}
+     numberOfCharactersInSecondHalfLine{0u},
+     relativeLineSize{1.0f}
  
    {
    }
      characterIndexInSecondHalfLine     = 0u;
      numberOfGlyphsInSecondHalfLine     = 0u;
      numberOfCharactersInSecondHalfLine = 0u;
+     relativeLineSize                   = 1.0f;
    }
  
    GlyphIndex         glyphIndex;                ///< Index of the first glyph to be laid-out.
    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
@@@ -173,9 -176,10 +177,10 @@@ struct Engine::Imp
     * @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 GetLineSpacing(float textSize, float relativeLineSize)
    {
      float lineSpacing;
      float relTextSize;
      lineSpacing += mDefaultLineSpacing;
  
      //subtract line spcaing if relativeLineSize < 1 & larger than min height
-     relTextSize = textSize * mRelativeLineSize;
+     relTextSize = textSize * relativeLineSize;
      if(relTextSize > mDefaultLineSize)
      {
-       if(mRelativeLineSize < 1)
+       if(relativeLineSize < 1)
        {
          //subtract the difference (always will be positive)
          lineSpacing -= (textSize - relTextSize);
      // Sets the minimum descender.
      lineLayout.descender = std::min(lineLayout.descender, fontMetrics.descender);
  
-     lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender);
+     lineLayout.lineSpacing = GetLineSpacing(lineLayout.ascender + -lineLayout.descender, lineLayout.relativeLineSize);
    }
  
    /**
  
      const float      outlineWidth                = static_cast<float>(parameters.textModel->GetOutlineWidth());
      const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
 -    const float      characterSpacing            = parameters.textModel->mVisualModel->GetCharacterSpacing();
 +    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;
          {
            const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
  
 -          calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
 +          const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
 +          calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
            whiteSpaceLengthEndOfLine += calculatedAdvance;
  
            ++characterLogicalIndex;
          {
            const GlyphInfo& glyphInfo = *(glyphsBuffer + *(charactersToGlyphsBuffer + characterVisualIndex));
  
 -          calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
 +          const float characterSpacing = GetGlyphCharacterSpacing(characterVisualIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
 +          calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, glyphInfo.advance);
            whiteSpaceLengthEndOfLine += calculatedAdvance;
  
            ++characterLogicalIndex;
                                                                    charactersPerGlyphBuffer);
  
      GlyphMetrics glyphMetrics;
 -    calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
 +    const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
 +    calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
      GetGlyphsMetrics(glyphIndex,
                       numberOfGLyphsInGroup,
                       glyphMetrics,
          characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
  
          GlyphMetrics glyphMetrics;
 -        calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
 +        const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
 +        calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
          GetGlyphsMetrics(glyphIndex,
                           numberOfGLyphsInGroup,
                           glyphMetrics,
        characterLogicalIndex += *(charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u);
  
        GlyphMetrics glyphMetrics;
 -      calculatedAdvance = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
 +      const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
 +      calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + characterVisualIndex), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
        GetGlyphsMetrics(glyphIndex,
                         numberOfGLyphsInGroup,
                         glyphMetrics,
  
      bool isSecondHalf = false;
      // Character Spacing
 -    const float             characterSpacing          = parameters.textModel->mVisualModel->GetCharacterSpacing();
 +    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;
 -    calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance);
 +    const float  characterSpacing = GetGlyphCharacterSpacing(lineLayout.glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
 +    calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + lineLayout.glyphIndex))), characterSpacing, (*(glyphsBuffer + lineLayout.glyphIndex)).advance);
      GetGlyphsMetrics(lineLayout.glyphIndex,
                       numberOfGLyphsInGroup,
                       glyphMetrics,
      // 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.relativeLineSize = lineLayout.relativeLineSize;
      // Calculate the line height if there is no characters.
      FontId lastFontId = glyphMetrics.fontId;
      UpdateLineHeight(glyphMetrics, tmpLineLayout);
                                                                      charactersPerGlyphBuffer);
  
        GlyphMetrics glyphMetrics;
 -      calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
 +      const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndex, characterSpacingGlyphRuns, modelCharacterSpacing);
 +      calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndex))), characterSpacing, (*(glyphsBuffer + glyphIndex)).advance);
        GetGlyphsMetrics(glyphIndex,
                         numberOfGLyphsInGroup,
                         glyphMetrics,
          while(tmpLineLayout.length + tmpLineLayout.whiteSpaceLengthEndOfLine > targetWidth && glyphIndexToRemove < glyphIndex)
          {
            GlyphMetrics glyphMetrics;
 -          calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance);
 +          const float  characterSpacing = GetGlyphCharacterSpacing(glyphIndexToRemove, characterSpacingGlyphRuns, modelCharacterSpacing);
 +          calculatedAdvance             = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + glyphIndexToRemove))), characterSpacing, (*(glyphsBuffer + glyphIndexToRemove)).advance);
            GetGlyphsMetrics(glyphIndexToRemove,
                             numberOfGLyphsInGroup,
                             glyphMetrics,
  
        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.
      lineRun.direction = layout.direction;
      lineRun.ellipsis  = false;
  
-     lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender);
+     lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, layout.relativeLineSize);
  
      // Update the actual size.
      if(lineRun.width > layoutSize.width)
      lineRun.direction                       = LTR;
      lineRun.ellipsis                        = false;
  
-     lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender);
+     BoundedParagraphRun currentParagraphRun;
+     LineLayout          tempLineLayout;
+     (GetBoundedParagraph(layoutParameters.textModel->GetBoundedParagraphRuns(), characterIndex, currentParagraphRun) ? SetRelativeLineSize(&currentParagraphRun, tempLineLayout) : SetRelativeLineSize(nullptr, tempLineLayout));
+     lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender, tempLineLayout.relativeLineSize);
  
      layoutSize.height += GetLineHeight(lineRun, true);
    }
      }
    }
  
+   /**
+    * @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,
      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)
      {
      // 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;
  
        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,
        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.
          }
  
          // Updates the vertical pen's position.
-         penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender);
+         penY += -layout.descender + layout.lineSpacing + GetLineSpacing(layout.ascender + -layout.descender, layout.relativeLineSize);
  
          // Increase the glyph index.
          index = nextIndex;