Resolve incorrect position for Ellipsis when mixed LTR & RTL languages and set layout...
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / rendering / view-model.cpp
index 0557e09..9cfba93 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -23,6 +23,7 @@
 #include <memory.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 #include <dali-toolkit/internal/text/line-run.h>
 
 namespace Dali
@@ -249,12 +250,27 @@ float ViewModel::GetUnderlineHeight() const
   return mModel->GetUnderlineHeight();
 }
 
+Text::Underline::Type ViewModel::GetUnderlineType() const
+{
+  return mModel->GetUnderlineType();
+}
+
+float ViewModel::GetDashedUnderlineWidth() const
+{
+  return mModel->GetDashedUnderlineWidth();
+}
+
+float ViewModel::GetDashedUnderlineGap() const
+{
+  return mModel->GetDashedUnderlineGap();
+}
+
 Length ViewModel::GetNumberOfUnderlineRuns() const
 {
   return mModel->GetNumberOfUnderlineRuns();
 }
 
-void ViewModel::GetUnderlineRuns(GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const
+void ViewModel::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const
 {
   mModel->GetUnderlineRuns(underlineRuns, index, numberOfRuns);
 }
@@ -299,13 +315,33 @@ Length ViewModel::GetHyphensCount() const
   return mModel->GetHyphensCount();
 }
 
+const float ViewModel::GetCharacterSpacing() const
+{
+  return mModel->GetCharacterSpacing();
+}
+
+const Character* ViewModel::GetTextBuffer() const
+{
+  return mModel->GetTextBuffer();
+}
+
+const Vector<CharacterIndex>& ViewModel::GetGlyphsToCharacters() const
+{
+  return mModel->GetGlyphsToCharacters();
+}
+
 void ViewModel::ElideGlyphs()
 {
   mIsTextElided             = false;
   mStartIndexOfElidedGlyphs = mFirstMiddleIndexOfElidedGlyphs = mSecondMiddleIndexOfElidedGlyphs = 0;
   mEndIndexOfElidedGlyphs                                                                        = mModel->GetNumberOfGlyphs() - 1u;
 
-  auto ellipsisPosition = GetEllipsisPosition();
+  auto                          ellipsisPosition          = GetEllipsisPosition();
+  auto                          characterSpacing          = GetCharacterSpacing();
+  const Character*              textBuffer                = GetTextBuffer();
+  const Vector<CharacterIndex>& glyphToCharacterMap       = GetGlyphsToCharacters();
+  const CharacterIndex*         glyphToCharacterMapBuffer = glyphToCharacterMap.Begin();
+  float                         calculatedAdvance         = 0.f;
 
   if(IsTextElideEnabled())
   {
@@ -469,7 +505,8 @@ void ViewModel::ElideGlyphs()
                 firstPenSet = true;
               }
 
-              removedGlypsWidth += std::min(glyphToRemove.advance, (glyphToRemove.xBearing + glyphToRemove.width));
+              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.
               const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing;
@@ -487,7 +524,71 @@ void ViewModel::ElideGlyphs()
                 // 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 = *(elidedPositionsBuffer + 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 = *(elidedPositionsBuffer + 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;
@@ -598,6 +699,36 @@ bool ViewModel::IsStrikethroughEnabled() const
   return mModel->IsStrikethroughEnabled();
 }
 
+Length ViewModel::GetNumberOfStrikethroughRuns() const
+{
+  return mModel->GetNumberOfStrikethroughRuns();
+}
+
+void ViewModel::GetStrikethroughRuns(StrikethroughGlyphRun* strikethroughRuns, StrikethroughRunIndex index, Length numberOfRuns) const
+{
+  mModel->GetStrikethroughRuns(strikethroughRuns, index, numberOfRuns);
+}
+
+Length ViewModel::GetNumberOfBoundedParagraphRuns() const
+{
+  return mModel->GetNumberOfBoundedParagraphRuns();
+}
+
+const Vector<BoundedParagraphRun>& ViewModel::GetBoundedParagraphRuns() const
+{
+  return mModel->GetBoundedParagraphRuns();
+}
+
+Length ViewModel::GetNumberOfCharacterSpacingGlyphRuns() const
+{
+  return mModel->GetNumberOfCharacterSpacingGlyphRuns();
+}
+
+const Vector<CharacterSpacingGlyphRun>& ViewModel::GetCharacterSpacingGlyphRuns() const
+{
+  return mModel->GetCharacterSpacingGlyphRuns();
+}
+
 } // namespace Text
 
 } // namespace Toolkit