[dali_2.2.19] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-view.cpp
index fdccbe1..469a318 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
@@ -25,6 +25,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/character-spacing-helper-functions.h>
 
 namespace Dali
 {
@@ -107,7 +108,7 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
 {
   Length                  numberOfLaidOutGlyphs       = 0u;
   Length                  numberOfActualLaidOutGlyphs = 0u;
-  const float             characterSpacing            = mImpl->mVisualModel->GetCharacterSpacing();
+  const float             modelCharacterSpacing       = mImpl->mVisualModel->GetCharacterSpacing();
   Vector<CharacterIndex>& glyphToCharacterMap         = mImpl->mVisualModel->mGlyphsToCharacters;
   const CharacterIndex*   glyphToCharacterMapBuffer   = glyphToCharacterMap.Begin();
   float                   calculatedAdvance           = 0.f;
@@ -115,12 +116,15 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
 
   if(mImpl->mVisualModel)
   {
+    // Get the character-spacing runs.
+    const Vector<CharacterSpacingGlyphRun>& characterSpacingGlyphRuns = mImpl->mVisualModel->GetCharacterSpacingGlyphRuns();
+
     bool                              textElided       = false;
     DevelText::EllipsisPosition::Type ellipsisPosition = GetEllipsisPosition();
 
     //Reset indices of ElidedGlyphs
     mImpl->mVisualModel->SetStartIndexOfElidedGlyphs(0u);
-    mImpl->mVisualModel->SetEndIndexOfElidedGlyphs(numberOfGlyphs);
+    mImpl->mVisualModel->SetEndIndexOfElidedGlyphs(numberOfGlyphs - 1u); // Initialization is the last index of Glyphs
     mImpl->mVisualModel->SetFirstMiddleIndexOfElidedGlyphs(0u);
     mImpl->mVisualModel->SetSecondMiddleIndexOfElidedGlyphs(0u);
 
@@ -356,7 +360,8 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
                 firstPenSet = true;
               }
 
-              calculatedAdvance = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + indexOfEllipsis))), characterSpacing, glyphToRemove.advance);
+              const float characterSpacing = GetGlyphCharacterSpacing(indexOfEllipsis, characterSpacingGlyphRuns, modelCharacterSpacing);
+              calculatedAdvance            = GetCalculatedAdvance(*(textBuffer + (*(glyphToCharacterMapBuffer + indexOfEllipsis))), characterSpacing, glyphToRemove.advance);
               removedGlypsWidth += std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width));
 
               // Calculate the width of the ellipsis glyph and check if it fits.
@@ -371,10 +376,73 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
                 glyphInfo = ellipsisGlyph;
 
                 // Change the 'x' and 'y' position of the ellipsis glyph.
-
                 if(position.x > firstPenX)
                 {
-                  position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+                  if(isTailMode)
+                  {
+                    // To handle case of the mixed languages (LTR then RTL) with
+                    // EllipsisPosition::END and the LayoutDirection::RIGHT_TO_LEFT
+                    float nextXPositions = ellipsisLine->width;
+                    if(indexOfEllipsis + 1u < numberOfGlyphs)
+                    {
+                      Vector2& positionOfNextGlyph = *(glyphPositions + indexOfEllipsis + 1u);
+                      nextXPositions               = positionOfNextGlyph.x;
+                    }
+
+                    if(position.x > nextXPositions) // RTL language
+                    {
+                      if((indexOfEllipsis > 0u) && ((position.x - nextXPositions) > removedGlypsWidth))
+                      {
+                        // To handle mixed directions
+                        // Re-calculates the first penX which will be used if rtl text is elided.
+                        firstPenX = position.x - glyphToRemove.xBearing;
+                        if(firstPenX < -ellipsisGlyph.xBearing)
+                        {
+                          // Avoids to exceed the bounding box when rtl text is elided.
+                          firstPenX = -ellipsisGlyph.xBearing;
+                        }
+                        //Reset the width of removed glyphs
+                        removedGlypsWidth = std::min(calculatedAdvance, (glyphToRemove.xBearing + glyphToRemove.width)) - ellipsisGlyph.xBearing;
+
+                        --indexOfEllipsis;
+                        continue;
+                      }
+                      else
+                      {
+                        // To handle the case of RTL language with EllipsisPosition::END
+                        position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+                      }
+                    }
+                  }
+                  else
+                  {
+                    // To handle the case of LTR language with EllipsisPosition::START
+                    position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+                  }
+                }
+                else
+                {
+                  if(!isTailMode)
+                  {
+                    // To handle case of the mixed languages (RTL then LTR) with
+                    // EllipsisPosition::START and the LayoutDirection::RIGHT_TO_LEFT
+                    float nextXPositions = ellipsisLine->width;
+                    if(indexOfEllipsis + 1u < numberOfGlyphs)
+                    {
+                      Vector2& positionOfNextGlyph = *(glyphPositions + indexOfEllipsis + 1u);
+                      nextXPositions               = positionOfNextGlyph.x;
+                    }
+
+                    if(position.x < nextXPositions) // LTR language
+                    {
+                      position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth;
+
+                      if((position.x + ellipsisGlyphWidth + ellipsisGlyph.xBearing) > nextXPositions)
+                      {
+                        position.x -= (position.x + ellipsisGlyphWidth + ellipsisGlyph.xBearing) - nextXPositions;
+                      }
+                    }
+                  }
                 }
 
                 position.x += ellipsisGlyph.xBearing;
@@ -481,6 +549,12 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
             {
               Length numberOfSecondHalfGlyphs = numberOfLaidOutGlyphs - firstMiddleIndexOfElidedGlyphs + 1u;
 
+              // Make sure that out-of-boundary does not occur.
+              if(secondMiddleIndexOfElidedGlyphs + numberOfSecondHalfGlyphs > numberOfGlyphs)
+              {
+                numberOfSecondHalfGlyphs = numberOfGlyphs - secondMiddleIndexOfElidedGlyphs;
+              }
+
               //Copy elided glyphs after the ellipsis glyph.
               memcpy(glyphs + firstMiddleIndexOfElidedGlyphs + 1u, glyphs + secondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(GlyphInfo));
               memcpy(glyphPositions + firstMiddleIndexOfElidedGlyphs + 1u, glyphPositions + secondMiddleIndexOfElidedGlyphs, numberOfSecondHalfGlyphs * sizeof(Vector2));
@@ -507,7 +581,7 @@ Length View::GetGlyphs(GlyphInfo* glyphs,
   return numberOfLaidOutGlyphs;
 }
 
-const Vector4* const View::GetColors() const
+const Vector4* View::GetColors() const
 {
   if(mImpl->mVisualModel)
   {
@@ -517,7 +591,7 @@ const Vector4* const View::GetColors() const
   return NULL;
 }
 
-const ColorIndex* const View::GetColorIndices() const
+const ColorIndex* View::GetColorIndices() const
 {
   if(mImpl->mVisualModel)
   {
@@ -527,7 +601,7 @@ const ColorIndex* const View::GetColorIndices() const
   return NULL;
 }
 
-const Vector4* const View::GetBackgroundColors() const
+const Vector4* View::GetBackgroundColors() const
 {
   if(mImpl->mVisualModel)
   {
@@ -537,7 +611,7 @@ const Vector4* const View::GetBackgroundColors() const
   return nullptr;
 }
 
-const ColorIndex* const View::GetBackgroundColorIndices() const
+const ColorIndex* View::GetBackgroundColorIndices() const
 {
   if(mImpl->mVisualModel)
   {
@@ -547,7 +621,7 @@ const ColorIndex* const View::GetBackgroundColorIndices() const
   return nullptr;
 }
 
-bool const View::IsMarkupBackgroundColorSet() const
+bool View::IsMarkupBackgroundColorSet() const
 {
   if(mImpl->mVisualModel)
   {
@@ -602,6 +676,11 @@ bool View::IsUnderlineEnabled() const
   return false;
 }
 
+bool View::IsMarkupUnderlineSet() const
+{
+  return (GetNumberOfUnderlineRuns() > 0u);
+}
+
 const GlyphInfo* View::GetHyphens() const
 {
   if(mImpl->mVisualModel)
@@ -797,6 +876,11 @@ bool View::IsStrikethroughEnabled() const
   return (mImpl->mVisualModel) ? mImpl->mVisualModel->IsStrikethroughEnabled() : false;
 }
 
+bool View::IsMarkupStrikethroughSet() const
+{
+  return (GetNumberOfStrikethroughRuns() > 0u);
+}
+
 float View::GetStrikethroughHeight() const
 {
   return (mImpl->mVisualModel) ? mImpl->mVisualModel->GetStrikethroughHeight() : 0.0f;
@@ -839,14 +923,14 @@ const Vector<BoundedParagraphRun>& View::GetBoundedParagraphRuns() const
   return mImpl->mLogicalModel->GetBoundedParagraphRuns();
 }
 
-const float View::GetCharacterSpacing() const
+float View::GetCharacterSpacing() const
 {
-  return (mImpl->mVisualModel) ? mImpl->mVisualModel->GetCharacterSpacing() : 0.f;
+  return mImpl->mVisualModel->GetCharacterSpacing();
 }
 
 const Character* View::GetTextBuffer() const
 {
-  return (mImpl->mVisualModel) ? mImpl->mLogicalModel->mText.Begin() : nullptr;
+  return mImpl->mLogicalModel->mText.Begin();
 }
 
 const Vector<CharacterIndex>& View::GetGlyphsToCharacters() const