[Tizen] Fix some decorative line style issues in text 31/319231/1
authorBowon Ryu <bowon.ryu@samsung.com>
Tue, 4 Feb 2025 01:16:12 +0000 (10:16 +0900)
committerBowon Ryu <bowon.ryu@samsung.com>
Thu, 6 Feb 2025 04:29:59 +0000 (13:29 +0900)
- fixed strikethrough rendering issue for editable text
- fixed an issue where the decorative line style of editable text was not rendered again when updated.
- clean up the decorative line related code of the atlas renderer
- fixed double underline issue in text label

Change-Id: I667155525c526dc36297b316b356028d61d24e76
Signed-off-by: Bowon Ryu <bowon.ryu@samsung.com>
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.h
dali-toolkit/internal/controls/text-controls/text-editor-property-handler.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-field-property-handler.cpp
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/rendering/text-typesetter-impl.cpp

index 1a130c923bba5259767b9c0793a67d7aa589671c..3691e3671cd972884a967d2cc1a4358e8ebe2ee0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -771,7 +771,7 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
     EmitTextChangedSignal();
   }
 
-  const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
+  Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
 
   if((Text::Controller::NONE_UPDATED != updateTextType) ||
      !mRenderer)
@@ -789,6 +789,12 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
       mRenderer = Backend::Get().NewRenderer(mRenderingBackend);
     }
 
+    if(mRenderRequired)
+    {
+      updateTextType = static_cast<Text::Controller::UpdateTextType>(updateTextType | Text::Controller::MODEL_UPDATED);
+      mRenderRequired = false;
+    }
+
     RenderText(updateTextType);
   }
 
@@ -1410,7 +1416,8 @@ TextEditor::TextEditor(ControlBehaviour additionalBehaviour)
   mOldPosition(0u),
   mOldSelectionStart(0u),
   mOldSelectionEnd(0u),
-  mSelectionStarted(false)
+  mSelectionStarted(false),
+  mRenderRequired(false)
 {
 }
 
index 982a159208543b2cc5f5481ddfc16a3d69d473f0..c349327064de426b6c7009794247c93f80dd3174 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_EDITOR_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -651,6 +651,7 @@ private: // Data
   uint32_t mOldSelectionEnd;
 
   bool mSelectionStarted : 1; ///< If true, emits SelectionStartedSignal at the end of OnRelayout().
+  bool mRenderRequired   : 1; ///< If true, text rendering required.
 
   struct PropertyHandler;
 
index 984be66512afcf629baee190a268a3af2713728a..708e803a630cd4a7c77cec5cc7e58692e299f9e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -372,6 +372,7 @@ void TextEditor::PropertyHandler::SetProperty(Toolkit::TextEditor textEditor, Pr
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
@@ -390,6 +391,7 @@ void TextEditor::PropertyHandler::SetProperty(Toolkit::TextEditor textEditor, Pr
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
@@ -426,6 +428,7 @@ void TextEditor::PropertyHandler::SetProperty(Toolkit::TextEditor textEditor, Pr
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
@@ -714,6 +717,7 @@ void TextEditor::PropertyHandler::SetProperty(Toolkit::TextEditor textEditor, Pr
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
index cfdbb8763dcc41b4f7b943f2e0142ce7702c515d..68c3555fde4d15d22ee22c09c3642299567958f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -682,7 +682,7 @@ void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
     EmitTextChangedSignal();
   }
 
-  const Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
+  Text::Controller::UpdateTextType updateTextType = mController->Relayout(contentSize, layoutDirection);
 
   if((Text::Controller::NONE_UPDATED != updateTextType) ||
      !mRenderer)
@@ -700,6 +700,12 @@ void TextField::OnRelayout(const Vector2& size, RelayoutContainer& container)
       mRenderer = Backend::Get().NewRenderer(mRenderingBackend);
     }
 
+    if(mRenderRequired)
+    {
+      updateTextType = static_cast<Text::Controller::UpdateTextType>(updateTextType | Text::Controller::MODEL_UPDATED);
+      mRenderRequired = false;
+    }
+
     RenderText(updateTextType);
   }
 
@@ -1177,7 +1183,8 @@ TextField::TextField(ControlBehaviour additionalBehaviour)
   mOldPosition(0u),
   mOldSelectionStart(0u),
   mOldSelectionEnd(0u),
-  mSelectionStarted(false)
+  mSelectionStarted(false),
+  mRenderRequired(false)
 {
 }
 
index ed1a00833ca5f5cf02e60fe81660cd0d99d2d8e0..59abb6767ff946626ae73ae1c02d1c5c1bad8378 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_FIELD_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -591,6 +591,7 @@ private: // Data
   uint32_t mOldSelectionEnd;
 
   bool mSelectionStarted : 1; ///< If true, emits SelectionStartedSignal at the end of OnRelayout().
+  bool mRenderRequired   : 1; ///< If true, text rendering required.
 
 protected:
   struct PropertyHandler;
index 91b6f2523d2986953461cac67a74c57734d16fbf..79242396158691888e365e369071660210b37bd6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -437,6 +437,7 @@ void TextField::PropertyHandler::SetProperty(Toolkit::TextField textField, Prope
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
@@ -455,6 +456,7 @@ void TextField::PropertyHandler::SetProperty(Toolkit::TextField textField, Prope
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
@@ -491,6 +493,7 @@ void TextField::PropertyHandler::SetProperty(Toolkit::TextField textField, Prope
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
@@ -680,6 +683,7 @@ void TextField::PropertyHandler::SetProperty(Toolkit::TextField textField, Prope
       if(update)
       {
         impl.mRenderer.Reset();
+        impl.mRenderRequired = true;
       }
       break;
     }
index 787bcfa48dc3f0a897c70f1a2878fc10cb368de4..91cee528f693f510d668d4766869e2fdcd81525c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -82,27 +82,23 @@ struct AtlasRenderer::Impl
   struct Extent
   {
     Extent()
-    : mBaseLine(0.0f),
+    : mMeshRecordIndex(0u),
+      mBaseLine(0.0f),
       mLeft(0.0f),
       mRight(0.0f),
-      mUnderlinePosition(0.0f),
-      mLineThickness(0.0f),
-      mMeshRecordIndex(0u),
-      mUnderlineChunkId(0u),
-      mStrikethroughPosition(0.0f),
-      mStrikethroughChunkId(0u)
+      mLineChunkId(0u),
+      mLinePosition(0.0f),
+      mLineThickness(0.0f)
     {
     }
 
+    uint32_t mMeshRecordIndex;
     float    mBaseLine;
     float    mLeft;
     float    mRight;
-    float    mUnderlinePosition;
+    uint32_t mLineChunkId;
+    float    mLinePosition;
     float    mLineThickness;
-    uint32_t mMeshRecordIndex;
-    uint32_t mUnderlineChunkId;
-    float    mStrikethroughPosition;
-    uint32_t mStrikethroughChunkId;
   };
 
   struct MaxBlockSize
@@ -296,15 +292,19 @@ struct AtlasRenderer::Impl
                     const Vector4&           color,
                     uint16_t                 outline,
                     AtlasManager::AtlasSlot& slot,
-                    bool                     decorationlineGlyph,
-                    float                    currentUnderlinePosition,
-                    float                    currentlineThickness,
                     std::vector<MeshRecord>& meshContainer,
                     Vector<TextCacheEntry>&  newTextCache,
-                    Vector<Extent>&          extents,
-                    uint32_t                 underlineChunkId,
                     bool                     isGlyphCached,
-                    uint32_t                 strikethroughChunkId)
+                    float                    fontMetricsAscender,
+                    bool                     underlineEnabled,
+                    uint32_t                 underlineChunkId,
+                    float                    underlinePosition,
+                    float                    underlineThickness,
+                    Vector<Extent>&          underlineExtents,
+                    bool                     strikethroughEnabled,
+                    uint32_t                 strikethroughChunkId,
+                    float                    strikethroughThickness,
+                    Vector<Extent>&          strikethroughExtents)
   {
     // Generate mesh data for this quad, plugging in our supplied position
     AtlasManager::Mesh2D newMesh;
@@ -337,20 +337,23 @@ struct AtlasRenderer::Impl
 
     // Since Free Type font doesn't contain the strikethrough-position property,
     // strikethrough position will be calculated by moving the underline position upwards by half the value of the line height.
-    float strikethroughStartingYPosition = (position.y + glyph.yBearing + currentUnderlinePosition) - ((glyph.height) * HALF);
+    const float baseLine              = position.y + glyph.yBearing;
+    const float strikethroughPosition = (baseLine + underlinePosition) - (fontMetricsAscender * HALF);
 
-    // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
-    StitchTextMesh(meshContainer,
+    StitchTextMesh(slot,
+                   meshContainer,
                    newMesh,
-                   extents,
-                   position.y + glyph.yBearing,
-                   decorationlineGlyph,
-                   currentUnderlinePosition,
-                   currentlineThickness,
-                   slot,
+                   baseLine,
+                   underlineEnabled,
                    underlineChunkId,
-                   strikethroughStartingYPosition,
-                   strikethroughChunkId);
+                   underlinePosition,
+                   underlineThickness,
+                   underlineExtents,
+                   strikethroughEnabled,
+                   strikethroughChunkId,
+                   strikethroughPosition,
+                   strikethroughThickness,
+                   strikethroughExtents);
   }
 
   void CreateActors(const std::vector<MeshRecord>& meshContainer,
@@ -439,7 +442,7 @@ struct AtlasRenderer::Impl
 
     std::vector<MeshRecord> meshContainer;
     std::vector<MeshRecord> meshContainerOutline;
-    Vector<Extent>          extents;
+    Vector<Extent>          underlineExtents;
     Vector<Extent>          strikethroughExtents;
     mDepth = depth;
 
@@ -506,6 +509,7 @@ struct AtlasRenderer::Impl
     FontId lastFontId                  = 0;
     Style  style                       = STYLE_NORMAL;
     float  currentUnderlinePosition    = ZERO;
+    float  currentFontMetricsAscender  = ZERO;
     bool   thereAreUnderlinedGlyphs    = false;
     bool   thereAreStrikethroughGlyphs = false;
 
@@ -601,7 +605,8 @@ struct AtlasRenderer::Impl
             if(isGlyphStrikethrough || isGlyphUnderlined)
             {
               //The currentUnderlinePosition will be used for both Underline and/or Strikethrough
-              currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(lastDecorativeLinesFontMetrics);
+              currentUnderlinePosition   = FetchUnderlinePositionFromFontMetrics(lastDecorativeLinesFontMetrics);
+              currentFontMetricsAscender = lastDecorativeLinesFontMetrics.ascender;
             }
           }
 
@@ -675,57 +680,51 @@ struct AtlasRenderer::Impl
           {
             underlineChunkId++;
             mapUnderlineChunkIdWithProperties.insert(std::pair<uint32_t, UnderlineStyleProperties>(underlineChunkId, currentUnderlineProperties));
+            if(currentUnderlineProperties.height < 1.0f)
+            {
+              maxUnderlineHeight = 1.0f;
+            }
           }
 
           //Keep status of underlined for previous glyph to check consecutive indices
           isPreUnderlined        = isGlyphUnderlined;
           preUnderlineProperties = currentUnderlineProperties;
 
-          GenerateMesh(glyph,
-                       positionPlusOutlineOffset,
-                       color,
-                       NO_OUTLINE,
-                       slot,
-                       isGlyphUnderlined,
-                       currentUnderlinePosition,
-                       maxUnderlineHeight,
-                       meshContainer,
-                       newTextCache,
-                       extents,
-                       underlineChunkId,
-                       false,
-                       0u);
-
-          if(isGlyphStrikethrough)
+          //The new strikethrough chunk. Add new id if they are not consecutive indices (this is for Markup case)
+          // Examples: "Hello <s>World</s> Hello <s>World</s>", "<s>World</s> Hello <s>World</s>", "<s>   World</s> Hello <s>World</s>"
+          if((!isPreStrikethrough && isGlyphStrikethrough) || (isGlyphStrikethrough && (preStrikethroughProperties != currentStrikethroughProperties)))
           {
-            //The new strikethrough chunk. Add new id if they are not consecutive indices (this is for Markup case)
-            // Examples: "Hello <s>World</s> Hello <s>World</s>", "<s>World</s> Hello <s>World</s>", "<s>   World</s> Hello <s>World</s>"
-            if((!isPreStrikethrough) || (preStrikethroughProperties != currentStrikethroughProperties))
+            strikethroughChunkId++;
+            mapStrikethroughChunkIdWithProperties.insert(std::pair<uint32_t, StrikethroughStyleProperties>(strikethroughChunkId, currentStrikethroughProperties));
+            if(currentStrikethroughProperties.height < 1.0f)
             {
-              strikethroughChunkId++;
-              mapStrikethroughChunkIdWithProperties.insert(std::pair<uint32_t, StrikethroughStyleProperties>(strikethroughChunkId, currentStrikethroughProperties));
+              maxStrikethroughHeight = 1.0f;
             }
-
-            GenerateMesh(glyph,
-                         positionPlusOutlineOffset,
-                         color,
-                         NO_OUTLINE,
-                         slot,
-                         isGlyphStrikethrough,
-                         0.0f,
-                         maxStrikethroughHeight,
-                         meshContainer,
-                         newTextCache,
-                         strikethroughExtents,
-                         0u,
-                         true,
-                         strikethroughChunkId);
           }
 
           //Keep status of Strikethrough for previous glyph to check consecutive indices
           isPreStrikethrough         = isGlyphStrikethrough;
           preStrikethroughProperties = currentStrikethroughProperties;
 
+          GenerateMesh(glyph,
+                       positionPlusOutlineOffset,
+                       color,
+                       NO_OUTLINE,
+                       slot,
+                       meshContainer,
+                       newTextCache,
+                       false,
+                       currentFontMetricsAscender,
+                       isGlyphUnderlined,
+                       underlineChunkId,
+                       currentUnderlinePosition,
+                       maxUnderlineHeight,
+                       underlineExtents,
+                       isGlyphStrikethrough,
+                       strikethroughChunkId,
+                       maxStrikethroughHeight,
+                       strikethroughExtents);
+
           lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId.
         }
 
@@ -736,15 +735,19 @@ struct AtlasRenderer::Impl
                        outlineColor,
                        outlineWidth,
                        slotOutline,
-                       false,
-                       currentUnderlinePosition,
-                       maxUnderlineHeight,
                        meshContainerOutline,
                        newTextCache,
-                       extents,
+                       false,
+                       currentFontMetricsAscender,
+                       false,
                        0u,
+                       currentUnderlinePosition,
+                       maxUnderlineHeight,
+                       underlineExtents,
                        false,
-                       0u);
+                       0u,
+                       maxStrikethroughHeight,
+                       strikethroughExtents);
         }
       }
 
@@ -761,7 +764,7 @@ struct AtlasRenderer::Impl
     if(thereAreUnderlinedGlyphs)
     {
       // Check to see if any of the text needs an underline
-      GenerateUnderlines(meshContainer, extents, viewUnderlineProperties, mapUnderlineChunkIdWithProperties);
+      GenerateUnderlines(meshContainer, underlineExtents, viewUnderlineProperties, mapUnderlineChunkIdWithProperties);
     }
 
     if(thereAreStrikethroughGlyphs)
@@ -903,17 +906,20 @@ struct AtlasRenderer::Impl
     return actor;
   }
 
-  void StitchTextMesh(std::vector<MeshRecord>& meshContainer,
+  void StitchTextMesh(AtlasManager::AtlasSlot& slot,
+                      std::vector<MeshRecord>& meshContainer,
                       AtlasManager::Mesh2D&    newMesh,
-                      Vector<Extent>&          extents,
                       float                    baseLine,
-                      bool                     decorationlineGlyph,
-                      float                    underlinePosition,
-                      float                    lineThickness,
-                      AtlasManager::AtlasSlot& slot,
+                      bool                     underlineEnabled,
                       uint32_t                 underlineChunkId,
+                      float                    underlinePosition,
+                      float                    underlineThickness,
+                      Vector<Extent>&          underlineExtents,
+                      bool                     strikethroughEnabled,
+                      uint32_t                 strikethroughChunkId,
                       float                    strikethroughPosition,
-                      uint32_t                 strikethroughChunkId)
+                      float                    strikethroughThickness,
+                      Vector<Extent>&          strikethroughExtents)
   {
     if(slot.mImageId)
     {
@@ -932,19 +938,29 @@ struct AtlasRenderer::Impl
           // Append the mesh to the existing mesh and adjust any extents
           Toolkit::Internal::AtlasMeshFactory::AppendMesh(mIt->mMesh, newMesh);
 
-          if(decorationlineGlyph)
+          if(underlineEnabled)
           {
-            AdjustExtents(extents,
+            AdjustExtents(underlineExtents,
                           meshContainer,
                           index,
+                          baseLine,
                           left,
                           right,
-                          baseLine,
-                          underlinePosition,
-                          lineThickness,
                           underlineChunkId,
+                          underlinePosition,
+                          underlineThickness);
+          }
+          if(strikethroughEnabled)
+          {
+            AdjustExtents(strikethroughExtents,
+                          meshContainer,
+                          index,
+                          baseLine,
+                          left,
+                          right,
+                          strikethroughChunkId,
                           strikethroughPosition,
-                          strikethroughChunkId);
+                          strikethroughThickness);
           }
 
           return;
@@ -957,20 +973,30 @@ struct AtlasRenderer::Impl
       meshRecord.mMesh    = newMesh;
       meshContainer.push_back(meshRecord);
 
-      if(decorationlineGlyph)
+      if(underlineEnabled)
       {
         // Adjust extents for this new meshrecord
-        AdjustExtents(extents,
+        AdjustExtents(underlineExtents,
                       meshContainer,
                       meshContainer.size() - 1u,
+                      baseLine,
                       left,
                       right,
-                      baseLine,
-                      underlinePosition,
-                      lineThickness,
                       underlineChunkId,
+                      underlinePosition,
+                      underlineThickness);
+      }
+      if(strikethroughEnabled)
+      {
+        AdjustExtents(strikethroughExtents,
+                      meshContainer,
+                      meshContainer.size() - 1u,
+                      baseLine,
+                      left,
+                      right,
+                      strikethroughChunkId,
                       strikethroughPosition,
-                      strikethroughChunkId);
+                      strikethroughThickness);
       }
     }
   }
@@ -978,14 +1004,13 @@ struct AtlasRenderer::Impl
   void AdjustExtents(Vector<Extent>&          extents,
                      std::vector<MeshRecord>& meshRecords,
                      uint32_t                 index,
+                     float                    baseLine,
                      float                    left,
                      float                    right,
-                     float                    baseLine,
-                     float                    underlinePosition,
-                     float                    lineThickness,
-                     uint32_t                 underlineChunkId,
-                     float                    strikethroughPosition,
-                     uint32_t                 strikethroughChunkId)
+                     uint32_t                 lineChunkId,
+                     float                    linePosition,
+                     float                    lineThickness)
+
   {
     bool foundExtent = false;
     for(Vector<Extent>::Iterator eIt    = extents.Begin(),
@@ -993,7 +1018,7 @@ struct AtlasRenderer::Impl
         eIt != eEndIt;
         ++eIt)
     {
-      if(Equals(baseLine, eIt->mBaseLine) && underlineChunkId == eIt->mUnderlineChunkId && strikethroughChunkId == eIt->mStrikethroughChunkId)
+      if(Equals(baseLine, eIt->mBaseLine) && lineChunkId == eIt->mLineChunkId)
       {
         foundExtent = true;
         if(left < eIt->mLeft)
@@ -1005,9 +1030,9 @@ struct AtlasRenderer::Impl
           eIt->mRight = right;
         }
 
-        if(underlinePosition > eIt->mUnderlinePosition)
+        if(linePosition > eIt->mLinePosition)
         {
-          eIt->mUnderlinePosition = underlinePosition;
+          eIt->mLinePosition = linePosition;
         }
         if(lineThickness > eIt->mLineThickness)
         {
@@ -1018,15 +1043,13 @@ struct AtlasRenderer::Impl
     if(!foundExtent)
     {
       Extent extent;
-      extent.mLeft                  = left;
-      extent.mRight                 = right;
-      extent.mBaseLine              = baseLine;
-      extent.mUnderlinePosition     = underlinePosition;
-      extent.mMeshRecordIndex       = index;
-      extent.mUnderlineChunkId      = underlineChunkId;
-      extent.mLineThickness         = lineThickness;
-      extent.mStrikethroughPosition = strikethroughPosition;
-      extent.mStrikethroughChunkId  = strikethroughChunkId;
+      extent.mMeshRecordIndex = index;
+      extent.mBaseLine        = baseLine;
+      extent.mLeft            = left;
+      extent.mRight           = right;
+      extent.mLineChunkId     = lineChunkId;
+      extent.mLinePosition    = linePosition;
+      extent.mLineThickness   = lineThickness;
       extents.PushBack(extent);
     }
   }
@@ -1074,8 +1097,6 @@ struct AtlasRenderer::Impl
                           const UnderlineStyleProperties&                     viewUnderlineProperties,
                           const std::map<uint32_t, UnderlineStyleProperties>& mapUnderlineChunkIdWithProperties)
   {
-    AtlasManager::Mesh2D newMesh;
-    unsigned short       faceIndex = 0;
 
     for(Vector<Extent>::ConstIterator eIt    = extents.Begin(),
                                       eEndIt = extents.End();
@@ -1086,7 +1107,7 @@ struct AtlasRenderer::Impl
       uint32_t               index = eIt->mMeshRecordIndex;
       Vector2                uv    = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId);
 
-      auto pairUnderlineChunkIdWithProperties = mapUnderlineChunkIdWithProperties.find(eIt->mUnderlineChunkId);
+      auto pairUnderlineChunkIdWithProperties = mapUnderlineChunkIdWithProperties.find(eIt->mLineChunkId);
 
       const UnderlineStyleProperties underlineProperties = (pairUnderlineChunkIdWithProperties == mapUnderlineChunkIdWithProperties.end())
                                                              ? viewUnderlineProperties
@@ -1101,11 +1122,14 @@ struct AtlasRenderer::Impl
       float u           = HALF / uv.x;
       float v           = HALF / uv.y;
       float thickness   = eIt->mLineThickness;
-      float ShiftLineBy = (underlineType == Text::Underline::Type::DOUBLE) ? (thickness * ONE_AND_A_HALF) : (thickness * HALF);
-      float baseLine    = eIt->mBaseLine + eIt->mUnderlinePosition - ShiftLineBy;
+      float ShiftLineBy = (underlineType == Text::Underline::Type::DOUBLE) ? floor(thickness * ONE_AND_A_HALF) : floor(thickness * HALF);
+      float baseLine    = eIt->mBaseLine + eIt->mLinePosition - ShiftLineBy;
       float tlx         = eIt->mLeft;
       float brx         = eIt->mRight;
 
+      AtlasManager::Mesh2D newMesh;
+      unsigned short       faceIndex = 0;
+
       if(underlineType == Text::Underline::Type::DASHED)
       {
         float dashTlx = tlx;
@@ -1156,8 +1180,6 @@ struct AtlasRenderer::Impl
           newMesh.mIndices.PushBack(faceIndex + 1u);
 
           faceIndex += 4;
-
-          Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
         }
       }
       else
@@ -1198,8 +1220,6 @@ struct AtlasRenderer::Impl
         newMesh.mIndices.PushBack(faceIndex + 1u);
         faceIndex += 4;
 
-        Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
-
         if(underlineType == Text::Underline::Type::DOUBLE)
         {
           baseLine += 2 * thickness;
@@ -1243,10 +1263,9 @@ struct AtlasRenderer::Impl
           newMesh.mIndices.PushBack(faceIndex + 1u);
 
           faceIndex += 4;
-
-          Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
         }
       }
+      Toolkit::Internal::AtlasMeshFactory::AppendMesh(meshRecords[index].mMesh, newMesh);
     }
   }
 
@@ -1255,8 +1274,6 @@ struct AtlasRenderer::Impl
                              const StrikethroughStyleProperties&                     viewStrikethroughProperties,
                              const std::map<uint32_t, StrikethroughStyleProperties>& mapStrikethroughChunkIdWithProperties)
   {
-    AtlasManager::Mesh2D newMesh;
-    unsigned short       faceIndex = 0;
     for(Vector<Extent>::ConstIterator eIt    = extents.Begin(),
                                       eEndIt = extents.End();
         eIt != eEndIt;
@@ -1266,7 +1283,7 @@ struct AtlasRenderer::Impl
       uint32_t               index = eIt->mMeshRecordIndex;
       Vector2                uv    = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId);
 
-      auto pairStrikethroughChunkIdWithProperties = mapStrikethroughChunkIdWithProperties.find(eIt->mStrikethroughChunkId);
+      auto pairStrikethroughChunkIdWithProperties = mapStrikethroughChunkIdWithProperties.find(eIt->mLineChunkId);
 
       const StrikethroughStyleProperties strikethroughProperties = (pairStrikethroughChunkIdWithProperties == mapStrikethroughChunkIdWithProperties.end())
                                                                      ? viewStrikethroughProperties
@@ -1280,7 +1297,10 @@ struct AtlasRenderer::Impl
       float thickness             = eIt->mLineThickness;
       float tlx                   = eIt->mLeft;
       float brx                   = eIt->mRight;
-      float strikethroughPosition = eIt->mStrikethroughPosition;
+      float strikethroughPosition = eIt->mLinePosition;
+
+      AtlasManager::Mesh2D newMesh;
+      unsigned short       faceIndex = 0;
 
       vert.mPosition.x  = tlx;
       vert.mPosition.y  = strikethroughPosition;
index fcf2c56fbb30b494541ea165b877152acadb2b9e..14ecdabb94132189341618e4049c8928250043ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -501,7 +501,7 @@ void DrawUnderline(
       const uint32_t secondYRangeMax        = static_cast<uint32_t>(std::max(0, std::min(static_cast<int32_t>(bufferHeight), secondUnderlineYOffset + static_cast<int32_t>(maxUnderlineHeight))));
 
       // Rewind bitmapBuffer pointer, and skip secondYRangeMin line.
-      bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer()) + yRangeMin * glyphData.width;
+      bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer()) + secondYRangeMin * glyphData.width;
 
       for(uint32_t y = secondYRangeMin; y < secondYRangeMax; y++)
       {
@@ -566,7 +566,7 @@ void DrawUnderline(
       const uint32_t secondYRangeMax        = static_cast<uint32_t>(std::max(0, std::min(static_cast<int32_t>(bufferHeight), secondUnderlineYOffset + static_cast<int32_t>(maxUnderlineHeight))));
 
       // Rewind bitmapBuffer pointer, and skip secondYRangeMin line.
-      bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer()) + yRangeMin * glyphData.width;
+      bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer()) + secondYRangeMin * glyphData.width;
 
       for(uint32_t y = secondYRangeMin; y < secondYRangeMax; y++)
       {