[dali_2.1.16] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
index a85f5f6..3fcc82c 100644 (file)
@@ -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
 {
@@ -59,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)
 {
@@ -162,11 +164,55 @@ 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.
+   * @return the line spacing value.
+   */
+  float GetLineSpacing(float textSize)
+  {
+    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 * mRelativeLineSize;
+    if(relTextSize > mDefaultLineSize)
+    {
+      if(mRelativeLineSize < 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.
@@ -194,12 +240,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);
   }
 
   /**
@@ -259,7 +300,10 @@ struct Engine::Impl
 
     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;
@@ -290,7 +334,8 @@ struct Engine::Impl
         {
           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;
@@ -312,7 +357,8 @@ struct Engine::Impl
         {
           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;
@@ -330,7 +376,8 @@ struct Engine::Impl
                                                                   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,
@@ -361,7 +408,8 @@ struct Engine::Impl
         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,
@@ -423,7 +471,8 @@ struct Engine::Impl
       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,
@@ -660,13 +709,17 @@ struct Engine::Impl
 
     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,
@@ -707,7 +760,8 @@ struct Engine::Impl
                                                                     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,
@@ -807,7 +861,8 @@ struct Engine::Impl
         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,
@@ -1266,6 +1321,15 @@ struct Engine::Impl
       {
         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;
 
@@ -1360,10 +1424,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);
 
     // Update the actual size.
     if(lineRun.width > layoutSize.width)
@@ -1417,10 +1478,7 @@ 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;
-
-    lineRun.lineSpacing += mDefaultLineSpacing;
+    lineRun.lineSpacing = GetLineSpacing(lineRun.ascender + -lineRun.descender);
 
     layoutSize.height += GetLineHeight(lineRun, true);
   }
@@ -1819,14 +1877,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);
 
         // Increase the glyph index.
         index = nextIndex;
@@ -2085,6 +2136,7 @@ struct Engine::Impl
   float mDefaultLineSize;
 
   IntrusivePtr<Metrics> mMetrics;
+  float                 mRelativeLineSize;
 };
 
 Engine::Engine()
@@ -2176,6 +2228,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