Handled nested tags in strikethrough 18/272318/4
authorssabah <s.sabah@samsung.com>
Mon, 14 Mar 2022 12:05:12 +0000 (15:05 +0300)
committershrouq Sabah <s.sabah@samsung.com>
Wed, 23 Mar 2022 06:47:06 +0000 (06:47 +0000)
The inner tag inherit the attributes of the outer tag and override them when defined in the inner tag
Example:
"<s height='5.0f' color='blue'> outer tag before  <s color='green'> inner tag </s> outer tag after </s>"
"outer tag before" and  "outer tag after" have height = 5.0f and color = 'blue'
"inner tag" has height = 5.0f and color = 'green'

This patch should be preceded by the patch below:
https://review.tizen.org/gerrit/c/platform/core/uifw/dali-toolkit/+/272264

Change-Id: I7426507b14c73f09aca67b9a22173e8ee5c0db29

automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp
dali-toolkit/internal/text/markup-processor-strikethrough.cpp
dali-toolkit/internal/text/markup-processor-strikethrough.h
dali-toolkit/internal/text/markup-processor.cpp
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp
dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/strikethrough-style-properties.h

index ade6b11..d19326f 100644 (file)
@@ -600,6 +600,78 @@ int UtcDaliTextEditorMarkupNestedUnderlineTags(void)
   END_TEST;
 }
 
+int UtcDaliTextEditorMarkupNestedStrikethroughTags(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupNestedStrikethroughTags ");
+
+  TextEditor textEditor = TextEditor::New();
+
+  application.GetScene().Add(textEditor);
+
+  std::string testText = "start<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>end";
+
+  textEditor.SetProperty(TextEditor::Property::TEXT, testText);
+  textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 2u;
+
+  Toolkit::Internal::TextEditor& textEditorImpl            = GetImpl(textEditor);
+  const Text::Length             numberOfStrikethroughRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textEditorImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //Outter
+      {"<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>",
+       5u,
+       8u,
+       {
+         Color::GREEN,
+         5.0f,
+         true,
+         true,
+       }},
+
+      //Inner
+      {"<s color='blue' >XYZ</s>",
+       7u,
+       3u,
+       {
+         Color::BLUE,
+         5.0f,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliTextEditorMarkupStrikethroughAttributes(void)
 {
   ToolkitTestApplication application;
index da74a7a..02aa540 100644 (file)
@@ -684,6 +684,78 @@ int UtcDaliTextFieldMarkupNestedUnderlineTags(void)
   END_TEST;
 }
 
+int UtcDaliTextFieldMarkupNestedStrikethroughTags(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupNestedStrikethroughTags ");
+
+  TextField textField = TextField::New();
+
+  application.GetScene().Add(textField);
+
+  std::string testText = "start<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>end";
+
+  textField.SetProperty(TextField::Property::TEXT, testText);
+  textField.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 2u;
+
+  Toolkit::Internal::TextField& textFieldImpl             = GetImpl(textField);
+  const Text::Length            numberOfStrikethroughRuns = textFieldImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textFieldImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //Outter
+      {"<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>",
+       5u,
+       8u,
+       {
+         Color::GREEN,
+         5.0f,
+         true,
+         true,
+       }},
+
+      //Inner
+      {"<s color='blue' >XYZ</s>",
+       7u,
+       3u,
+       {
+         Color::BLUE,
+         5.0f,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliTextFieldMarkupStrikethroughAttributes(void)
 {
   ToolkitTestApplication application;
index 6c07302..1ac00b5 100644 (file)
@@ -561,6 +561,78 @@ int UtcDaliTextLabelMarkupNestedUnderlineTags(void)
   END_TEST;
 }
 
+int UtcDaliTextLabelMarkupNestedStrikethroughTags(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupNestedStrikethroughTags ");
+
+  TextLabel textLabel = TextLabel::New();
+
+  application.GetScene().Add(textLabel);
+
+  std::string testText = "start<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>end";
+
+  textLabel.SetProperty(TextLabel::Property::TEXT, testText);
+  textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 2u;
+
+  Toolkit::Internal::TextLabel& textLabelImpl             = GetImpl(textLabel);
+  const Text::Length            numberOfStrikethroughRuns = textLabelImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textLabelImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //Outter
+      {"<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>",
+       5u,
+       8u,
+       {
+         Color::GREEN,
+         5.0f,
+         true,
+         true,
+       }},
+
+      //Inner
+      {"<s color='blue' >XYZ</s>",
+       7u,
+       3u,
+       {
+         Color::BLUE,
+         5.0f,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliTextLabelMarkupStrikethroughAttributes(void)
 {
   ToolkitTestApplication application;
index 622a624..2f0ea5d 100644 (file)
@@ -71,6 +71,44 @@ void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& striketh
   }
 }
 
+void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns)
+{
+  // Handle nested tags
+  // The inner tag inherit the attributes of the outer tag and override them when defined in the inner tag.
+  // Example:
+  // <s height='5.0f' color='blue'> outer tag before  <s color='green'> inner tag </s> outer tag after </s>
+  // "outer tag before" and  "outer tag after" have height = 5.0f and color = 'blue'
+  // "inner tag" has height = 5.0f and color = 'green'
+
+  if(strikethroughCharacterRuns.Count() > 0u)
+  {
+    Vector<StrikethroughCharacterRun>::ConstIterator preIt = strikethroughCharacterRuns.Begin();
+
+    Vector<StrikethroughCharacterRun>::Iterator      it    = strikethroughCharacterRuns.Begin() + 1;
+    Vector<StrikethroughCharacterRun>::ConstIterator endIt = strikethroughCharacterRuns.End();
+
+    while(it != endIt)
+    {
+      const StrikethroughCharacterRun& run                = *it;
+      const CharacterIndex&            characterIndex     = run.characterRun.characterIndex;
+      const Length&                    numberOfCharacters = run.characterRun.numberOfCharacters;
+
+      const StrikethroughCharacterRun& preRun                = *preIt;
+      const CharacterIndex&            preCharacterIndex     = preRun.characterRun.characterIndex;
+      const Length&                    preNumberOfCharacters = preRun.characterRun.numberOfCharacters;
+
+      if((preCharacterIndex <= characterIndex) &&
+         ((characterIndex + numberOfCharacters) <= (preCharacterIndex + preNumberOfCharacters)))
+      {
+        it->properties.CopyIfNotDefined(preIt->properties);
+      }
+
+      it++;
+      preIt++;
+    }
+  }
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index d18966d..fca6d34 100644 (file)
  *
  */
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/strikethrough-character-run.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -52,6 +58,13 @@ void ProcessHeightAttribute(const Attribute& attribute, StrikethroughCharacterRu
  */
 void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun);
 
+/**
+ * @brief Override the run's attributes which contained in the previous run. This is to handle the nested tags.
+ *
+ * @param[in,out] strikethroughCharacterRun The list of strikethrough character run
+ */
+void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRun);
+
 } // namespace Text
 
 } // namespace Toolkit
index 830d629..9c26b39 100644 (file)
@@ -1179,6 +1179,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
 
   // Handle the nested tags
   OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
+  OverrideNestedStrikethroughCharacterRuns(markupProcessData.strikethroughCharacterRuns);
 }
 
 } // namespace Text
index d9c4c86..e30564e 100644 (file)
@@ -554,8 +554,8 @@ struct AtlasRenderer::Impl
 
       Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End();
       const bool                                   isGlyphStrikethrough           = strikethroughEnabled || IsGlyphStrikethrough(i, strikethroughRuns, currentStrikethroughGlyphRunIt);
-      const StrikethroughStyleProperties           currentStrikethroughProperties = GetCurrentStrikethroughProperties(isGlyphStrikethrough, strikethroughRuns, currentStrikethroughGlyphRunIt, viewStrikethroughProperties);
-      float                                        currentStrikethroughHeight     = GetCurrentStrikethroughHeight(strikethroughRuns, currentStrikethroughGlyphRunIt, viewStrikethroughProperties.height);
+      const StrikethroughStyleProperties           currentStrikethroughProperties = GetCurrentStrikethroughProperties(i, isGlyphStrikethrough, strikethroughRuns, currentStrikethroughGlyphRunIt, viewStrikethroughProperties);
+      float                                        currentStrikethroughHeight     = currentStrikethroughProperties.height;
       thereAreStrikethroughGlyphs                                                 = thereAreStrikethroughGlyphs || isGlyphStrikethrough;
 
       // No operation for white space
index b28f90f..76b8ce3 100644 (file)
@@ -45,27 +45,34 @@ bool IsGlyphStrikethrough(GlyphIndex                                    index,
   return false;
 }
 
-float GetCurrentStrikethroughHeight(const Vector<StrikethroughGlyphRun>&         strikethroughRuns,
-                                    Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt,
-                                    const float                                  strikethroughHeight)
+StrikethroughStyleProperties GetCurrentStrikethroughProperties(GlyphIndex                                    index,
+                                                               const bool&                                   isGlyphStrikethrough,
+                                                               const Vector<StrikethroughGlyphRun>&          strikethroughRuns,
+                                                               Vector<StrikethroughGlyphRun>::ConstIterator& currentStrikethroughGlyphRunIt,
+                                                               const StrikethroughStyleProperties&           commonStrikethroughProperties)
 {
-  if(currentStrikethroughGlyphRunIt == strikethroughRuns.End())
+  StrikethroughStyleProperties currentStrikethroughStyleProperties = commonStrikethroughProperties;
+
+  if(isGlyphStrikethrough && (currentStrikethroughGlyphRunIt != strikethroughRuns.End()))
   {
-    return strikethroughHeight;
-  }
+    // Retrieve the latest run to handle the nested case.
+    for(Vector<StrikethroughGlyphRun>::ConstIterator it    = currentStrikethroughGlyphRunIt + 1,
+                                                     endIt = strikethroughRuns.End();
+        it != endIt;
+        ++it)
+    {
+      const StrikethroughGlyphRun& run = *it;
 
-  const StrikethroughGlyphRun& strikethroughGlyphRun = *currentStrikethroughGlyphRunIt;
-  return (strikethroughGlyphRun.properties.heightDefined ? strikethroughGlyphRun.properties.height : strikethroughHeight);
-}
+      if((run.glyphRun.glyphIndex <= index) && (index < (run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs)))
+      {
+        currentStrikethroughGlyphRunIt = it;
+      }
+    }
 
-StrikethroughStyleProperties GetCurrentStrikethroughProperties(const bool&                                  isGlyphStrikethrough,
-                                                               const Vector<StrikethroughGlyphRun>&         strikethroughRuns,
-                                                               Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt,
-                                                               const StrikethroughStyleProperties&          commonStrikethroughProperties)
-{
-  return (isGlyphStrikethrough && (currentStrikethroughGlyphRunIt != strikethroughRuns.End()))
-           ? currentStrikethroughGlyphRunIt->properties
-           : commonStrikethroughProperties;
+    currentStrikethroughStyleProperties.OverrideByDefinedProperties(currentStrikethroughGlyphRunIt->properties);
+  }
+
+  return currentStrikethroughStyleProperties;
 }
 
 /// Helper method to fetch the strikethrough metrics for the specified font glyph
index c5c5141..d9c86e4 100644 (file)
@@ -46,21 +46,9 @@ bool IsGlyphStrikethrough(GlyphIndex                                    index,
                           Vector<StrikethroughGlyphRun>::ConstIterator& currentStrikethroughGlyphRunIt);
 
 /**
- * @brief Check the current strikethrough glyph run iterator if not empty and its height is defined then return ts height. Otherwise return the common strikethrough height.
- *
- * @param[in] strikethroughRuns the strikethrough runs.
- * @param[in] currentStrikethroughGlyphRunIt the iterator of current strikethrough glyph run.
- * @param[in] strikethroughHeight the common strikethrough height.
- *
- * @return the determined strikethrough height
- */
-float GetCurrentStrikethroughHeight(const Vector<StrikethroughGlyphRun>&         strikethroughRuns,
-                                    Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt,
-                                    const float                                  strikethroughHeight);
-
-/**
  * @brief Check the current strikethrough glyph run iterator if not empty and isGlyphStrikethrough is true then return its StrikethroughProperties. Otherwise return the common strikethrough properties.
  *
+ * @param[in] index the index of glyph.
  * @param[in] isGlyphStrikethrough whether the glyph is strikethrough.
  * @param[in] strikethroughRuns the strikethrough runs.
  * @param[in] currentStrikethroughGlyphRunIt the iterator of current strikethrough glyph run.
@@ -68,10 +56,11 @@ float GetCurrentStrikethroughHeight(const Vector<StrikethroughGlyphRun>&
  *
  * @return the determined strikethrough properties
  */
-StrikethroughStyleProperties GetCurrentStrikethroughProperties(const bool&                                  isGlyphStrikethrough,
-                                                               const Vector<StrikethroughGlyphRun>&         strikethroughRuns,
-                                                               Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt,
-                                                               const StrikethroughStyleProperties&          commonStrikethroughProperties);
+StrikethroughStyleProperties GetCurrentStrikethroughProperties(GlyphIndex                                    index,
+                                                               const bool&                                   isGlyphStrikethrough,
+                                                               const Vector<StrikethroughGlyphRun>&          strikethroughRuns,
+                                                               Vector<StrikethroughGlyphRun>::ConstIterator& currentStrikethroughGlyphRunIt,
+                                                               const StrikethroughStyleProperties&           commonStrikethroughProperties);
 
 /**
  * @brief Calculate the current strikethrough height and update maximum strikethrough height
index afb279e..9d58934 100644 (file)
@@ -991,8 +991,8 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
 
       Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End();
       const bool                                   strikethroughGlyph             = strikethroughEnabled || IsGlyphStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughGlyphRunIt);
-      currentStrikethroughProperties                                              = GetCurrentStrikethroughProperties(strikethroughGlyph, strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties);
-      currentStrikethroughHeight                                                  = GetCurrentStrikethroughHeight(strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties.height);
+      currentStrikethroughProperties                                              = GetCurrentStrikethroughProperties(glyphIndex, strikethroughGlyph, strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties);
+      currentStrikethroughHeight                                                  = currentStrikethroughProperties.height;
       thereAreStrikethroughGlyphs                                                 = thereAreStrikethroughGlyphs || strikethroughGlyph;
 
       // Are we still using the same fontId as previous
index a92f4c2..79597c9 100644 (file)
@@ -76,6 +76,46 @@ struct StrikethroughStyleProperties
     return ((!heightDefined && !other.heightDefined) || ((heightDefined && other.heightDefined) && (height == other.height)));
   }
 
+  StrikethroughStyleProperties& CopyIfNotDefined(const StrikethroughStyleProperties& other)
+  {
+    //Copy only the defined properties in other and not defined in this from other to this
+
+    if(!heightDefined && other.heightDefined)
+    {
+      height        = other.height;
+      heightDefined = true;
+    }
+
+    if(!colorDefined && other.colorDefined)
+    {
+      color        = other.color;
+      colorDefined = true;
+    }
+
+    // to chain this method
+    return *this;
+  }
+
+  StrikethroughStyleProperties& OverrideByDefinedProperties(const StrikethroughStyleProperties& other)
+  {
+    //Copy only the defined properties in other from other to this
+
+    if(other.heightDefined)
+    {
+      height        = other.height;
+      heightDefined = true;
+    }
+
+    if(other.colorDefined)
+    {
+      color        = other.color;
+      colorDefined = true;
+    }
+
+    // to chain this method
+    return *this;
+  }
+
   //Attributes
   Vector4 color;  ///< The color of strikethrough.
   float   height; ///< The height of strikethrough.