Merge "Use RegisterUniqueProperty for some more renderers" into devel/master
authorDavid Steele <david.steele@samsung.com>
Tue, 22 Feb 2022 18:00:19 +0000 (18:00 +0000)
committerGerrit Code Review <gerrit@review>
Tue, 22 Feb 2022 18:00:19 +0000 (18:00 +0000)
46 files changed:
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
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder-impl.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-scene-holder.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h
automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
dali-toolkit/internal/text/markup-processor-attribute-helper-functions.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-font.cpp
dali-toolkit/internal/text/markup-processor-helper-functions.cpp
dali-toolkit/internal/text/markup-processor-helper-functions.h
dali-toolkit/internal/text/markup-processor-underline.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-underline.h [new file with mode: 0644]
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 [new file with mode: 0644]
dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/styles/underline-helper-functions.cpp [new file with mode: 0644]
dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h [new file with mode: 0644]
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/rendering/view-model.h
dali-toolkit/internal/text/text-controller-impl-model-updater.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-effects-style.cpp
dali-toolkit/internal/text/text-effects-style.h
dali-toolkit/internal/text/text-model-interface.h
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h
dali-toolkit/internal/text/underline-style-properties.h [new file with mode: 0644]
dali-toolkit/internal/text/underlined-character-run.h
dali-toolkit/internal/text/underlined-glyph-run.h [new file with mode: 0644]
dali-toolkit/internal/text/visual-model-impl.cpp
dali-toolkit/internal/text/visual-model-impl.h
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index 0c55d97..46abf15 100644 (file)
@@ -94,18 +94,255 @@ int UtcDaliTextEditorMarkupUnderline(void)
 
   DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
 
-  Vector<GlyphRun> underlineRuns;
+  Vector<UnderlinedGlyphRun> underlineRuns;
   underlineRuns.Resize(numberOfUnderlineRuns);
   textEditorImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
 
   //ABC are underlined
-  DALI_TEST_EQUALS(underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[1u].glyphRun.glyphIndex, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[2u].glyphRun.glyphIndex, 2u, TEST_LOCATION);
 
   //GH are underlined
-  DALI_TEST_EQUALS(underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[3u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[4u].glyphRun.glyphIndex, 6u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorMarkupUnderlineAttributes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupUnderlineAttributes ");
+
+  TextEditor textEditor = TextEditor::New();
+
+  application.GetScene().Add(textEditor);
+
+  std::string testText =
+    "start<u>ABC1</u>then"
+    "<u type='solid'>ABC2</u>then"
+    "<u type='dashed'>ABC3</u>then"
+    "<u type='double'>ABC4</u>then"
+    "<u color='green'>ABC5</u>then"
+    "<u height='5.0f'>ABC6</u>then"
+    "<u type='dashed' dash-gap='3.0f'>ABC7</u>then"
+    "<u type='dashed' dash-width='4.0f'>ABC8</u>then"
+    "<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>ABC9</u>end"
+
+    ;
+
+  textEditor.SetProperty(TextEditor::Property::TEXT, testText);
+  textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t NUMBER_OF_CASES                  = 9u;
+  uint32_t       expectedNumberOfUnderlinedGlyphs = 36u;
+
+  Toolkit::Internal::TextEditor& textEditorImpl        = GetImpl(textEditor);
+  const Text::Length             numberOfUnderlineRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+  DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
+
+  Vector<UnderlinedGlyphRun> underlineRuns;
+  underlineRuns.Resize(numberOfUnderlineRuns);
+  textEditorImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+  struct DataOfCase
+  {
+    std::string              title;
+    uint32_t                 startIndex;
+    uint32_t                 endIndex;
+    GlyphIndex               startGlyphIndex;
+    GlyphIndex               endGlyphIndex;
+    UnderlineStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //<u>ABC1</u>
+      {"<u>ABC1</u>",
+       0u,
+       3u,
+       5u,
+       8u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         false,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='solid'>ABC2</u>
+      {"<u type='solid'>ABC2</u>",
+       4u,
+       7u,
+       13u,
+       16u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='dashed'>ABC3</u>
+      {"<u type='dashed'>ABC3</u>",
+       8u,
+       11u,
+       21u,
+       24u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='double'>ABC4</u>
+      {"<u type='double'>ABC4</u>",
+       12u,
+       15u,
+       29u,
+       32u,
+       {
+         Text::Underline::DOUBLE,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u color='green'>ABC5</u>
+      {"<u color='green'>ABC5</u>",
+       16u,
+       19u,
+       37u,
+       40u,
+       {
+         Text::Underline::SOLID,
+         Color::GREEN,
+         0u,
+         1u,
+         2u,
+         false,
+         true,
+         false,
+         false,
+         false,
+       }},
+
+      //<u height='5.0f'>ABC6</u>
+      {"<u height='5.0f'>ABC6</u>",
+       20u,
+       23u,
+       45u,
+       48u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         5u,
+         1u,
+         2u,
+         false,
+         false,
+         true,
+         false,
+         false,
+       }},
+
+      //<u type='dashed' dash-gap='3.0f'>ABC7</u>
+      {"<u type='dashed' dash-gap='3.0f'>ABC7</u>",
+       24u,
+       27u,
+       53u,
+       56u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         3u,
+         2u,
+         true,
+         false,
+         false,
+         true,
+         false,
+       }},
+
+      //<u type='dashed' dash-width='4.0f'>ABC8</u>
+      {"<u type='dashed' dash-width='4.0f'>ABC8</u>",
+       28u,
+       31u,
+       61u,
+       64u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         1u,
+         4u,
+         true,
+         false,
+         false,
+         false,
+         true,
+       }},
+
+      //<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>
+      {"<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>",
+       32u,
+       35u,
+       69u,
+       72u,
+       {
+         Text::Underline::DASHED,
+         Color::BLUE,
+         4u,
+         2u,
+         3u,
+         true,
+         true,
+         true,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < NUMBER_OF_CASES; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(underlineRuns[data[i].startIndex].glyphRun.glyphIndex, data[i].startGlyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(underlineRuns[data[i].endIndex].glyphRun.glyphIndex, data[i].endGlyphIndex, TEST_LOCATION);
+
+    DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].startIndex].properties);
+    DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].endIndex].properties);
+  }
 
   END_TEST;
 }
@@ -376,3 +613,28 @@ int UtcDaliTextEditorMarkupStrikethrough(void)
 
   END_TEST;
 }
+
+int UtcDaliTextEditorMarkupStrikethroughNoEndTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupStrikethroughNoEndTag ");
+
+  TextEditor textEditor = TextEditor::New();
+
+  application.GetScene().Add(textEditor);
+
+  textEditor.SetProperty(TextEditor::Property::TEXT, "<s>ABC");
+  textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfStrikethroughGlyphs = 0u;
+
+  Toolkit::Internal::TextEditor& textEditorImpl            = GetImpl(textEditor);
+  Text::Length                   numberOfStrikethroughRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index 57fb32b..77366b6 100644 (file)
@@ -176,18 +176,255 @@ int UtcDaliTextFieldMarkupUnderline(void)
 
   DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
 
-  Vector<GlyphRun> underlineRuns;
+  Vector<UnderlinedGlyphRun> underlineRuns;
   underlineRuns.Resize(numberOfUnderlineRuns);
   textFieldImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
 
   //ABC are underlined
-  DALI_TEST_EQUALS(underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[1u].glyphRun.glyphIndex, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[2u].glyphRun.glyphIndex, 2u, TEST_LOCATION);
 
   //GH are underlined
-  DALI_TEST_EQUALS(underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[3u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[4u].glyphRun.glyphIndex, 6u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldMarkupUnderlineAttributes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupUnderlineAttributes ");
+
+  TextField textField = TextField::New();
+
+  application.GetScene().Add(textField);
+
+  std::string testText =
+    "start<u>ABC1</u>then"
+    "<u type='solid'>ABC2</u>then"
+    "<u type='dashed'>ABC3</u>then"
+    "<u type='double'>ABC4</u>then"
+    "<u color='green'>ABC5</u>then"
+    "<u height='5.0f'>ABC6</u>then"
+    "<u type='dashed' dash-gap='3.0f'>ABC7</u>then"
+    "<u type='dashed' dash-width='4.0f'>ABC8</u>then"
+    "<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>ABC9</u>end"
+
+    ;
+
+  textField.SetProperty(TextField::Property::TEXT, testText);
+  textField.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t NUMBER_OF_CASES                  = 9u;
+  uint32_t       expectedNumberOfUnderlinedGlyphs = 36u;
+
+  Toolkit::Internal::TextField& textFieldImpl         = GetImpl(textField);
+  const Text::Length            numberOfUnderlineRuns = textFieldImpl.GetTextController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+  DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
+
+  Vector<UnderlinedGlyphRun> underlineRuns;
+  underlineRuns.Resize(numberOfUnderlineRuns);
+  textFieldImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+  struct DataOfCase
+  {
+    std::string              title;
+    uint32_t                 startIndex;
+    uint32_t                 endIndex;
+    GlyphIndex               startGlyphIndex;
+    GlyphIndex               endGlyphIndex;
+    UnderlineStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //<u>ABC1</u>
+      {"<u>ABC1</u>",
+       0u,
+       3u,
+       5u,
+       8u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         false,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='solid'>ABC2</u>
+      {"<u type='solid'>ABC2</u>",
+       4u,
+       7u,
+       13u,
+       16u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='dashed'>ABC3</u>
+      {"<u type='dashed'>ABC3</u>",
+       8u,
+       11u,
+       21u,
+       24u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='double'>ABC4</u>
+      {"<u type='double'>ABC4</u>",
+       12u,
+       15u,
+       29u,
+       32u,
+       {
+         Text::Underline::DOUBLE,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u color='green'>ABC5</u>
+      {"<u color='green'>ABC5</u>",
+       16u,
+       19u,
+       37u,
+       40u,
+       {
+         Text::Underline::SOLID,
+         Color::GREEN,
+         0u,
+         1u,
+         2u,
+         false,
+         true,
+         false,
+         false,
+         false,
+       }},
+
+      //<u height='5.0f'>ABC6</u>
+      {"<u height='5.0f'>ABC6</u>",
+       20u,
+       23u,
+       45u,
+       48u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         5u,
+         1u,
+         2u,
+         false,
+         false,
+         true,
+         false,
+         false,
+       }},
+
+      //<u type='dashed' dash-gap='3.0f'>ABC7</u>
+      {"<u type='dashed' dash-gap='3.0f'>ABC7</u>",
+       24u,
+       27u,
+       53u,
+       56u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         3u,
+         2u,
+         true,
+         false,
+         false,
+         true,
+         false,
+       }},
+
+      //<u type='dashed' dash-width='4.0f'>ABC8</u>
+      {"<u type='dashed' dash-width='4.0f'>ABC8</u>",
+       28u,
+       31u,
+       61u,
+       64u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         1u,
+         4u,
+         true,
+         false,
+         false,
+         false,
+         true,
+       }},
+
+      //<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>
+      {"<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>",
+       32u,
+       35u,
+       69u,
+       72u,
+       {
+         Text::Underline::DASHED,
+         Color::BLUE,
+         4u,
+         2u,
+         3u,
+         true,
+         true,
+         true,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < NUMBER_OF_CASES; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(underlineRuns[data[i].startIndex].glyphRun.glyphIndex, data[i].startGlyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(underlineRuns[data[i].endIndex].glyphRun.glyphIndex, data[i].endGlyphIndex, TEST_LOCATION);
+
+    DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].startIndex].properties);
+    DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].endIndex].properties);
+  }
 
   END_TEST;
 }
@@ -450,3 +687,28 @@ int UtcDaliTextFieldMarkupStrikethrough(void)
 
   END_TEST;
 }
+
+int UtcDaliTextFieldMarkupStrikethroughNoEndTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupStrikethroughNoEndTag ");
+
+  TextField textField = TextField::New();
+
+  application.GetScene().Add(textField);
+
+  textField.SetProperty(TextField::Property::TEXT, "<s>ABC");
+  textField.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfStrikethroughGlyphs = 0u;
+
+  Toolkit::Internal::TextField& textFieldImpl             = GetImpl(textField);
+  Text::Length                  numberOfStrikethroughRuns = textFieldImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index ba067f6..b1c380a 100644 (file)
@@ -15,6 +15,7 @@
  *
  */
 
+#include <bits/stdint-uintn.h>
 #include <stdlib.h>
 #include <iostream>
 
@@ -53,18 +54,255 @@ int UtcDaliTextLabelMarkupUnderline(void)
 
   DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
 
-  Vector<GlyphRun> underlineRuns;
+  Vector<UnderlinedGlyphRun> underlineRuns;
   underlineRuns.Resize(numberOfUnderlineRuns);
   textLabelImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
 
   //ABC are underlined
-  DALI_TEST_EQUALS(underlineRuns[0u].glyphIndex, 0u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[1u].glyphIndex, 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[2u].glyphIndex, 2u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[1u].glyphRun.glyphIndex, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[2u].glyphRun.glyphIndex, 2u, TEST_LOCATION);
 
   //GH are underlined
-  DALI_TEST_EQUALS(underlineRuns[3u].glyphIndex, 5u, TEST_LOCATION);
-  DALI_TEST_EQUALS(underlineRuns[4u].glyphIndex, 6u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[3u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
+  DALI_TEST_EQUALS(underlineRuns[4u].glyphRun.glyphIndex, 6u, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliTextLabelMarkupUnderlineAttributes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupUnderlineAttributes ");
+
+  TextLabel textLabel = TextLabel::New();
+
+  application.GetScene().Add(textLabel);
+
+  std::string testText =
+    "start<u>ABC1</u>then"
+    "<u type='solid'>ABC2</u>then"
+    "<u type='dashed'>ABC3</u>then"
+    "<u type='double'>ABC4</u>then"
+    "<u color='green'>ABC5</u>then"
+    "<u height='5.0f'>ABC6</u>then"
+    "<u type='dashed' dash-gap='3.0f'>ABC7</u>then"
+    "<u type='dashed' dash-width='4.0f'>ABC8</u>then"
+    "<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>ABC9</u>end"
+
+    ;
+
+  textLabel.SetProperty(TextLabel::Property::TEXT, testText);
+  textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t NUMBER_OF_CASES                  = 9u;
+  uint32_t       expectedNumberOfUnderlinedGlyphs = 36u;
+
+  Toolkit::Internal::TextLabel& textLabelImpl         = GetImpl(textLabel);
+  const Text::Length            numberOfUnderlineRuns = textLabelImpl.GetTextController()->GetTextModel()->GetNumberOfUnderlineRuns();
+
+  DALI_TEST_EQUALS(numberOfUnderlineRuns, expectedNumberOfUnderlinedGlyphs, TEST_LOCATION);
+
+  Vector<UnderlinedGlyphRun> underlineRuns;
+  underlineRuns.Resize(numberOfUnderlineRuns);
+  textLabelImpl.GetTextController()->GetTextModel()->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
+
+  struct DataOfCase
+  {
+    std::string              title;
+    uint32_t                 startIndex;
+    uint32_t                 endIndex;
+    GlyphIndex               startGlyphIndex;
+    GlyphIndex               endGlyphIndex;
+    UnderlineStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //<u>ABC1</u>
+      {"<u>ABC1</u>",
+       0u,
+       3u,
+       5u,
+       8u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         false,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='solid'>ABC2</u>
+      {"<u type='solid'>ABC2</u>",
+       4u,
+       7u,
+       13u,
+       16u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='dashed'>ABC3</u>
+      {"<u type='dashed'>ABC3</u>",
+       8u,
+       11u,
+       21u,
+       24u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u type='double'>ABC4</u>
+      {"<u type='double'>ABC4</u>",
+       12u,
+       15u,
+       29u,
+       32u,
+       {
+         Text::Underline::DOUBLE,
+         Color::BLACK,
+         0u,
+         1u,
+         2u,
+         true,
+         false,
+         false,
+         false,
+         false,
+       }},
+
+      //<u color='green'>ABC5</u>
+      {"<u color='green'>ABC5</u>",
+       16u,
+       19u,
+       37u,
+       40u,
+       {
+         Text::Underline::SOLID,
+         Color::GREEN,
+         0u,
+         1u,
+         2u,
+         false,
+         true,
+         false,
+         false,
+         false,
+       }},
+
+      //<u height='5.0f'>ABC6</u>
+      {"<u height='5.0f'>ABC6</u>",
+       20u,
+       23u,
+       45u,
+       48u,
+       {
+         Text::Underline::SOLID,
+         Color::BLACK,
+         5u,
+         1u,
+         2u,
+         false,
+         false,
+         true,
+         false,
+         false,
+       }},
+
+      //<u type='dashed' dash-gap='3.0f'>ABC7</u>
+      {"<u type='dashed' dash-gap='3.0f'>ABC7</u>",
+       24u,
+       27u,
+       53u,
+       56u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         3u,
+         2u,
+         true,
+         false,
+         false,
+         true,
+         false,
+       }},
+
+      //<u type='dashed' dash-width='4.0f'>ABC8</u>
+      {"<u type='dashed' dash-width='4.0f'>ABC8</u>",
+       28u,
+       31u,
+       61u,
+       64u,
+       {
+         Text::Underline::DASHED,
+         Color::BLACK,
+         0u,
+         1u,
+         4u,
+         true,
+         false,
+         false,
+         false,
+         true,
+       }},
+
+      //<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>
+      {"<u color='blue' type='dashed' height='4.0f' dash-gap='2.0f' dash-width='3.0f'>",
+       32u,
+       35u,
+       69u,
+       72u,
+       {
+         Text::Underline::DASHED,
+         Color::BLUE,
+         4u,
+         2u,
+         3u,
+         true,
+         true,
+         true,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < NUMBER_OF_CASES; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(underlineRuns[data[i].startIndex].glyphRun.glyphIndex, data[i].startGlyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(underlineRuns[data[i].endIndex].glyphRun.glyphIndex, data[i].endGlyphIndex, TEST_LOCATION);
+
+    DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].startIndex].properties);
+    DALI_TEST_CHECK(data[i].properties == underlineRuns[data[i].endIndex].properties);
+  }
 
   END_TEST;
 }
@@ -262,3 +500,28 @@ int UtcDaliTextLabelMarkupStrikethrough(void)
 
   END_TEST;
 }
+
+int UtcDaliTextLabelMarkupStrikethroughNoEndTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupStrikethroughNoEndTag ");
+
+  TextLabel textLabel = TextLabel::New();
+
+  application.GetScene().Add(textLabel);
+
+  textLabel.SetProperty(TextLabel::Property::TEXT, "<s>ABC");
+  textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  uint32_t expectedNumberOfStrikethroughGlyphs = 0u;
+
+  Toolkit::Internal::TextLabel& textLabelImpl             = GetImpl(textLabel);
+  Text::Length                  numberOfStrikethroughRuns = textLabelImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughGlyphs, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index fb67a4b..8075dbe 100644 (file)
@@ -119,6 +119,8 @@ public:
 
   Dali::Integration::SceneHolder::WheelEventSignalType& WheelEventSignal();
 
+  Dali::Integration::SceneHolder::WheelEventGeneratedSignalType& WheelEventGeneratedSignal();
+
   Integration::Scene GetScene();
 
   Dali::RenderSurfaceInterface& GetRenderSurface();
index e18809a..8bcb3c0 100644 (file)
@@ -115,6 +115,11 @@ Dali::Integration::SceneHolder::WheelEventSignalType& SceneHolder::WheelEventSig
   return mScene.WheelEventSignal();
 }
 
+Dali::Integration::SceneHolder::WheelEventGeneratedSignalType& SceneHolder::WheelEventGeneratedSignal()
+{
+  return mScene.WheelEventGeneratedSignal();
+}
+
 Integration::Scene SceneHolder::GetScene()
 {
   return mScene;
@@ -235,6 +240,11 @@ SceneHolder::WheelEventSignalType& SceneHolder::WheelEventSignal()
   return GetImplementation( *this ).WheelEventSignal();
 }
 
+SceneHolder::WheelEventGeneratedSignalType& SceneHolder::WheelEventGeneratedSignal()
+{
+  return GetImplementation( *this ).WheelEventGeneratedSignal();
+}
+
 } // Integration
 
 } // Dali
index b8cc1bc..9fc2763 100644 (file)
@@ -272,6 +272,11 @@ WheelEventSignalType& WheelEventSignal( Window window )
   return GetImplementation( window ).WheelEventSignal();
 }
 
+WheelEventGeneratedSignalType& WheelEventGeneratedSignal( Window window )
+{
+  return GetImplementation( window ).WheelEventGeneratedSignal();
+}
+
 VisibilityChangedSignalType& VisibilityChangedSignal( Window window )
 {
   return GetImplementation( window ).mVisibilityChangedSignal;
index d102f6a..0d4e219 100644 (file)
@@ -95,6 +95,7 @@ namespace DevelWindow
 typedef Signal< void () > EventProcessingFinishedSignalType;
 typedef Signal< bool (const KeyEvent&) > KeyEventGeneratedSignalType;
 typedef Signal< void (const WheelEvent&) > WheelEventSignalType;
+typedef Signal< bool (const WheelEvent&) > WheelEventGeneratedSignalType;
 typedef Signal< void ( Window, bool ) > VisibilityChangedSignalType;
 
 Dali::Window Get( Actor actor );
@@ -107,6 +108,7 @@ void AddFramePresentedCallback( Window window, std::unique_ptr< CallbackBase > c
 EventProcessingFinishedSignalType& EventProcessingFinishedSignal( Window window );
 KeyEventGeneratedSignalType& KeyEventGeneratedSignal( Dali::Window window );
 WheelEventSignalType& WheelEventSignal( Window window );
+WheelEventGeneratedSignalType& WheelEventGeneratedSignal( Dali::Window window );
 VisibilityChangedSignalType& VisibilityChangedSignal( Window window );
 }
 
index 6d0e8af..4780331 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/devel-api/actors/actor-devel.h>
 #include <dali/integration-api/events/key-event-integ.h>
 #include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h>
@@ -247,6 +248,34 @@ public:
   bool mIsCalled;
 };
 
+class WheelEventCallback : public Dali::ConnectionTracker
+{
+public:
+  /**
+   * Constructor
+   * @param[in]  returnValue  Set return value of WheelEvent callback.
+   * */
+  WheelEventCallback( bool consumed )
+  : mConsumed( consumed ),
+    mIsCalled( false )
+  {
+  }
+
+  bool Callback( Actor actor, const WheelEvent& wheelEvent )
+  {
+    mIsCalled = true;
+    return mConsumed;
+  }
+
+  void Callback( const WheelEvent& wheelEvent )
+  {
+    mIsCalled = true;
+  }
+
+  bool mConsumed;
+  bool mIsCalled;
+};
+
 // Used to connect to signals via the ConnectSignal Handle method
 struct CallbackFunctor
 {
@@ -2036,4 +2065,46 @@ int UtcDaliKeyboardFocusManagerWithKeyboardFocusableChildren(void)
   DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
 
   END_TEST;
+}
+
+int UtcDaliKeyboardFocusManagerCheckWheelEvent(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliKeyboardFocusManagerCheckWheelEvent" );
+  Dali::Integration::Scene scene = application.GetScene();
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK( ! manager.GetCurrentFocusActor() );
+
+  // Create the first actor and add it to the stage
+  Actor parent = Actor::New();
+  parent.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+
+  Actor child = Actor::New();
+  child.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+
+  parent.Add(child);
+  scene.Add(parent);
+
+  WheelEventCallback childCallback( false );
+  child.WheelEventSignal().Connect( &childCallback, &WheelEventCallback::Callback );
+
+  WheelEventCallback parentCallback( true );
+  parent.WheelEventSignal().Connect( &parentCallback, &WheelEventCallback::Callback );
+
+  WheelEventCallback sceneCallback( false );
+  scene.WheelEventSignal().Connect( &sceneCallback, &WheelEventCallback::Callback );
+
+  manager.SetCurrentFocusActor( child );
+
+  // Emit custom wheel event is comming to KeyboardFocusManager
+  Integration::WheelEvent event(Integration::WheelEvent::CUSTOM_WHEEL, 0, 0u, Vector2(0.0f, 0.0f), 1, 1000u);
+  application.ProcessEvent(event);
+
+  DALI_TEST_CHECK( childCallback.mIsCalled );
+  DALI_TEST_CHECK( parentCallback.mIsCalled );
+  DALI_TEST_CHECK( !sceneCallback.mIsCalled );
+
+  END_TEST;
 }
\ No newline at end of file
index e57fa31..c65b61e 100644 (file)
@@ -149,7 +149,9 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/markup-processor-background.cpp
    ${toolkit_src_dir}/text/markup-processor-span.cpp
    ${toolkit_src_dir}/text/markup-processor-strikethrough.cpp
+   ${toolkit_src_dir}/text/markup-processor-underline.cpp
    ${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
+   ${toolkit_src_dir}/text/markup-processor-attribute-helper-functions.cpp
    ${toolkit_src_dir}/text/multi-language-support.cpp
    ${toolkit_src_dir}/text/hidden-text.cpp
    ${toolkit_src_dir}/text/input-filter.cpp
@@ -196,6 +198,8 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/rendering/text-backend-impl.cpp
    ${toolkit_src_dir}/text/rendering/text-typesetter.cpp
    ${toolkit_src_dir}/text/rendering/view-model.cpp
+   ${toolkit_src_dir}/text/rendering/styles/underline-helper-functions.cpp
+   ${toolkit_src_dir}/text/rendering/styles/strikethrough-helper-functions
    ${toolkit_src_dir}/transition/fade-transition-impl.cpp
    ${toolkit_src_dir}/transition/slide-transition-impl.cpp
    ${toolkit_src_dir}/transition/scale-transition-impl.cpp
index cc80372..4afb39a 100644 (file)
@@ -145,6 +145,7 @@ void KeyboardFocusManager::OnAdaptorInit()
     {
       (*iter).KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent);
       (*iter).TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
+      (*iter).WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
       Dali::Window window = DevelWindow::DownCast(*iter);
       if(window)
       {
@@ -161,6 +162,7 @@ void KeyboardFocusManager::OnSceneHolderCreated(Dali::Integration::SceneHolder&
 {
   sceneHolder.KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent);
   sceneHolder.TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
+  sceneHolder.WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
   Dali::Window window = DevelWindow::DownCast(sceneHolder);
   if(window)
   {
@@ -1008,6 +1010,49 @@ void KeyboardFocusManager::OnTouch(const TouchEvent& touch)
   }
 }
 
+bool KeyboardFocusManager::OnWheelEvent(const WheelEvent& event)
+{
+  bool consumed = false;
+  Actor actor = GetCurrentFocusActor();
+  if(actor)
+  {
+    // Notify the actor about the wheel event
+    consumed = EmitWheelSignals(actor, event);
+  }
+  return consumed;
+}
+
+bool KeyboardFocusManager::EmitWheelSignals(Actor actor, const WheelEvent& event)
+{
+  bool consumed = false;
+
+  if(actor)
+  {
+    Dali::Actor oldParent(actor.GetParent());
+
+    // Only do the conversion and emit the signal if the actor's wheel signal has connections.
+    if(!actor.WheelEventSignal().Empty())
+    {
+      // Emit the signal to the parent
+      consumed = actor.WheelEventSignal().Emit(actor, event);
+    }
+    // if actor doesn't consume WheelEvent, give WheelEvent to its parent.
+    if(!consumed)
+    {
+      // The actor may have been removed/reparented during the signal callbacks.
+      Dali::Actor parent = actor.GetParent();
+
+      if(parent &&
+         (parent == oldParent))
+      {
+        consumed = EmitWheelSignals(parent, event);
+      }
+    }
+  }
+
+  return consumed;
+}
+
 void KeyboardFocusManager::OnWindowFocusChanged(Window window, bool focusIn)
 {
   if(focusIn && mCurrentFocusedWindow.GetHandle() != window.GetRootLayer())
index 8212a79..783e3f5 100644 (file)
@@ -292,6 +292,12 @@ private:
   void OnTouch(const TouchEvent& touch);
 
   /**
+   * Callback for the wheel event when the custom wheel event occurs.
+   * @param[in] wheel The WheelEvent information
+   */
+  bool OnWheelEvent(const WheelEvent& wheel);
+
+  /**
    * Called when the window focus is changed.
    * @param[in] window The window whose focus is changed
    * @param[in] focusIn Whether the focus is in/out
@@ -303,6 +309,14 @@ private:
    */
   Actor GetFocusActorFromCurrentWindow();
 
+  /**
+   * Recursively deliver events to the control and its parents, until the event is consumed or the stage is reached.
+   * @param[in]  actor  The actor got WheelEvent.
+   * @param[in]  event  The WheelEvent.
+   * @return True if WheelEvent is consumed.
+   */
+  bool EmitWheelSignals(Actor actor, const WheelEvent& event);
+
 private:
   // Undefined
   KeyboardFocusManager(const KeyboardFocusManager&);
index f1fd1f5..4516662 100644 (file)
@@ -471,6 +471,11 @@ void LogicalModel::ClearFontDescriptionRuns()
   FreeFontFamilyNames(mFontDescriptionRuns);
 }
 
+void LogicalModel::ClearStrikethroughRuns()
+{
+  mStrikethroughCharacterRuns.Clear();
+}
+
 void LogicalModel::CreateParagraphInfo(CharacterIndex startIndex,
                                        Length         numberOfCharacters)
 {
index 1bed342..08c636d 100644 (file)
@@ -153,6 +153,11 @@ public:
    */
   void ClearFontDescriptionRuns();
 
+  /**
+   * @brief Clears the strikethrough runs.
+   */
+  void ClearStrikethroughRuns();
+
   // Paragraphs
 
   /**
diff --git a/dali-toolkit/internal/text/markup-processor-attribute-helper-functions.cpp b/dali-toolkit/internal/text/markup-processor-attribute-helper-functions.cpp
new file mode 100644 (file)
index 0000000..da00996
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+void CopyAttributeValueFromBuffer(const Attribute& attribute, const Length maxLengthAttributeValue, char* value)
+{
+  const Length length = attribute.valueLength > maxLengthAttributeValue ? maxLengthAttributeValue : attribute.valueLength;
+  memcpy(value, attribute.valueBuffer, length);
+  value[length] = 0;
+}
+
+float ProcessFloatAttribute(const Attribute& attribute)
+{
+  return StringToFloat(attribute.valueBuffer);
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h b/dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h
new file mode 100644 (file)
index 0000000..52771b5
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
+
+/*
+ * Copyright (c) 2021 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <functional>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Attribute;
+
+/**
+ * @brief Copy the value from attribute buffer to value.
+ *
+ * @param[in] attribute the value of attribute.
+ * @param[in] maxLengthAttributeValue the maximum length of any of the possible value for attribute
+ * @param[out] value the value container.
+ *
+ */
+void CopyAttributeValueFromBuffer(const Attribute& attribute, const Length maxLengthAttributeValue, char* value);
+
+/**
+ * @brief Process the float attribute value from buffer.
+ *
+ * @param[in] attribute the float attribute.
+ *
+ * @return The float value.
+ */
+float ProcessFloatAttribute(const Attribute& attribute);
+
+/**
+ * @brief Process the Enumeration attribute value from buffer.
+ *
+ * @param[in] attribute the Enumeration attribute.
+ * @param[in] maxLengthAttributeValue the maximum length of any of the possible value for attribute
+ * @param[in] funcStringToEnum the function converts string value to enum value
+ * @param[out] enumValue the enum value
+ *
+ * @return      True if the enum value was processed successfully
+ *
+ */
+template<typename T>
+bool ProcessEnumerationAttribute(const Attribute&                    attribute,
+                                 const Length                        maxLengthAttributeValue,
+                                 std::function<T(const char* const)> funcStringToEnum,
+                                 T&                                  enumValue)
+{
+  char* value = new char[maxLengthAttributeValue + 1u];
+
+  CopyAttributeValueFromBuffer(attribute, maxLengthAttributeValue, value);
+
+  enumValue = funcStringToEnum(value); // @TODO: the functions that process Enum value should be refactored to return bool from Scripting::GetEnumeration
+
+  delete[] value;
+
+  return true;
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_ATTRIBUTE_HELPER_FUNCTIONS_H
index df8b6ec..0c469b8 100644 (file)
@@ -24,6 +24,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/font-description-run.h>
+#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
 #include <dali-toolkit/internal/text/text-font-style.h>
 
@@ -68,35 +69,23 @@ void ProcessFontFamily(const Attribute& attribute, FontDescriptionRun& fontRun)
 void ProcessFontSize(const Attribute& attribute, FontDescriptionRun& fontRun)
 {
   // 64.f is used to convert from point size to 26.6 pixel format.
-  fontRun.size        = static_cast<PointSize26Dot6>(StringToFloat(attribute.valueBuffer) * PIXEL_FORMAT_64_FACTOR);
+  fontRun.size        = static_cast<PointSize26Dot6>(ProcessFloatAttribute(attribute) * PIXEL_FORMAT_64_FACTOR);
   fontRun.sizeDefined = true;
 }
 
 void ProcessFontWeight(const Attribute& attribute, FontDescriptionRun& fontRun)
 {
-  char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
-  processFontAttributeValue(value, attribute);
-
-  fontRun.weight        = StringToWeight(value);
-  fontRun.weightDefined = true;
+  fontRun.weightDefined = ProcessEnumerationAttribute<FontWeight>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToWeight, fontRun.weight);
 }
 
 void ProcessFontWidth(const Attribute& attribute, FontDescriptionRun& fontRun)
 {
-  char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
-  processFontAttributeValue(value, attribute);
-
-  fontRun.width        = StringToWidth(value);
-  fontRun.widthDefined = true;
+  fontRun.widthDefined = ProcessEnumerationAttribute<FontWidth>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToWidth, fontRun.width);
 }
 
 void ProcessFontSlant(const Attribute& attribute, FontDescriptionRun& fontRun)
 {
-  char value[MAX_FONT_ATTRIBUTE_SIZE + 1u];
-  processFontAttributeValue(value, attribute);
-
-  fontRun.slant        = StringToSlant(value);
-  fontRun.slantDefined = true;
+  fontRun.slantDefined = ProcessEnumerationAttribute<FontSlant>(attribute, MAX_FONT_ATTRIBUTE_SIZE, &StringToSlant, fontRun.slant);
 }
 
 void ProcessFontTag(const Tag& tag, FontDescriptionRun& fontRun)
index ce8bcee..e4cb1c4 100644 (file)
@@ -38,6 +38,8 @@ const char FIRST_UPPER_CASE = 0x41; // ASCII value of the one after the first up
 const char LAST_UPPER_CASE  = 0x5b; // ASCII value of the one after the last upper case character (Z).
 const char TO_LOWER_CASE    = 32;   // Value to add to a upper case character to transform it into a lower case.
 
+const unsigned int MAX_FLOAT_ATTRIBUTE_SIZE = 17u; ///< The maximum length of any of the possible float values.  +99999.999999999f  (sign, five digits, dot, nine digits, f)
+
 const char        WEB_COLOR_TOKEN('#');
 const char* const HEX_COLOR_TOKEN("0x");
 const char* const ALPHA_ONE("FF");
index d7a6596..a28c1cb 100644 (file)
@@ -193,6 +193,15 @@ void Vector2ToString(const Vector2& value, std::string& vector2Str);
  */
 void UnderlineTypeStringToTypeValue(const char* const typeStr, Length length, Text::Underline::Type& retType);
 
+/**
+ * @brief Converts a string into a float value.
+ *
+ * @param[in] floatStr A float packed inside a string.
+ *
+ * @return The float value.
+ */
+float StringToFloat(const char* const floatStr);
+
 } // namespace Text
 
 } // namespace Toolkit
diff --git a/dali-toolkit/internal/text/markup-processor-underline.cpp b/dali-toolkit/internal/text/markup-processor-underline.cpp
new file mode 100644 (file)
index 0000000..063f3fe
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-underline.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/markup-processor-attribute-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/text-effects-style.h>
+#include <dali-toolkit/internal/text/underlined-character-run.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const std::string XHTML_COLOR_ATTRIBUTE("color");
+const std::string XHTML_HEIGHT_ATTRIBUTE("height");
+const std::string XHTML_TYPE_ATTRIBUTE("type");
+const std::string XHTML_DASH_GAP_ATTRIBUTE("dash-gap");
+const std::string XHTML_DASH_WIDTH_ATTRIBUTE("dash-width");
+
+const unsigned int MAX_TYPE_ATTRIBUTE_SIZE = 7u; ///< The maximum length of any of the possible 'type' values.
+
+} // namespace
+
+void ProcessTypeAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+  underlinedCharacterRun.properties.typeDefined = ProcessEnumerationAttribute<Text::Underline::Type>(attribute,
+                                                                                                     MAX_TYPE_ATTRIBUTE_SIZE,
+                                                                                                     &StringToUnderlineType,
+                                                                                                     underlinedCharacterRun.properties.type);
+}
+
+void ProcessDashGapAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+  underlinedCharacterRun.properties.dashGap        = ProcessFloatAttribute(attribute);
+  underlinedCharacterRun.properties.dashGapDefined = true;
+}
+
+void ProcessDashWidthAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+  underlinedCharacterRun.properties.dashWidth        = ProcessFloatAttribute(attribute);
+  underlinedCharacterRun.properties.dashWidthDefined = true;
+}
+void ProcessHeightAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+  underlinedCharacterRun.properties.height        = ProcessFloatAttribute(attribute);
+  underlinedCharacterRun.properties.heightDefined = true;
+}
+
+void ProcessColorAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+  ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, underlinedCharacterRun.properties.color);
+  underlinedCharacterRun.properties.colorDefined = true;
+}
+
+void ProcessUnderlineTag(const Tag& tag, UnderlinedCharacterRun& underlinedCharacterRun)
+{
+  for(Vector<Attribute>::ConstIterator it    = tag.attributes.Begin(),
+                                       endIt = tag.attributes.End();
+      it != endIt;
+      ++it)
+  {
+    const Attribute& attribute(*it);
+
+    if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessColorAttribute(attribute, underlinedCharacterRun);
+    }
+    else if(TokenComparison(XHTML_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessHeightAttribute(attribute, underlinedCharacterRun);
+    }
+    else if(TokenComparison(XHTML_TYPE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessTypeAttribute(attribute, underlinedCharacterRun);
+    }
+    else if(TokenComparison(XHTML_DASH_GAP_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessDashGapAttribute(attribute, underlinedCharacterRun);
+    }
+    else if(TokenComparison(XHTML_DASH_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-underline.h b/dali-toolkit/internal/text/markup-processor-underline.h
new file mode 100644 (file)
index 0000000..f210718
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Tag;
+struct Attribute;
+struct UnderlinedCharacterRun;
+
+/**
+ * @brief Fill the underlined character run with the type attribute value.
+ *
+ * @param[in] attribute the type attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessTypeAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the dash-gap attribute value.
+ *
+ * @param[in] attribute the dash-gap attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessDashGapAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the dash-width attribute value.
+ *
+ * @param[in] attribute the dash-width attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessDashWidthAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the height attribute value.
+ *
+ * @param[in] attribute the height attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessHeightAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Fill the underlined character run with the color attribute value.
+ *
+ * @param[in] attribute the color attribute.
+ * @param[out] underlinedCharacterRun The underlined character run
+ */
+void ProcessColorAttribute(const Attribute& attribute, UnderlinedCharacterRun& underlinedCharacterRun);
+
+/**
+ * @brief Retrieves the underline run info from the tag and sets it to the underline run.
+ *
+ * @param[in] tag The underline tag and its attributes.
+ * @param[in,out] underlinedCharacterRun The underlined character run
+ */
+void ProcessUnderlineTag(const Tag& tag, UnderlinedCharacterRun& underlinedCharacterRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_UNDERLINE_H
index 7ed1f61..17aae96 100644 (file)
@@ -33,6 +33,7 @@
 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
 #include <dali-toolkit/internal/text/markup-processor-span.h>
 #include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
+#include <dali-toolkit/internal/text/markup-processor-underline.h>
 #include <dali-toolkit/internal/text/xhtml-entities.h>
 
 namespace Dali
@@ -940,7 +941,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
       else if(TokenComparison(XHTML_U_TAG, tag.buffer, tag.length))
       {
         ProcessTagForRun<UnderlinedCharacterRun>(
-          markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) {});
+          markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) { ProcessUnderlineTag(tag, run); });
       } // <u></u>
       else if(TokenComparison(XHTML_B_TAG, tag.buffer, tag.length))
       {
index 9946d49..9eb2fd6 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/animation/constraints.h>
 #include <dali/public-api/rendering/geometry.h>
 #include <dali/public-api/rendering/renderer.h>
+#include <map>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
@@ -32,6 +33,8 @@
 #include <dali-toolkit/internal/text/glyph-run.h>
 #include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
 #include <dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.h>
+#include <dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h>
+#include <dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h>
 #include <dali-toolkit/internal/text/text-view.h>
 
 using namespace Dali;
@@ -158,28 +161,10 @@ struct AtlasRenderer::Impl
     mQuadVertexFormat["aColor"]    = Property::VECTOR4;
   }
 
-  bool IsGlyphUnderlined(GlyphIndex              index,
-                         const Vector<GlyphRun>& underlineRuns)
-  {
-    for(Vector<GlyphRun>::ConstIterator it    = underlineRuns.Begin(),
-                                        endIt = underlineRuns.End();
-        it != endIt;
-        ++it)
-    {
-      const GlyphRun& run = *it;
-
-      if((run.glyphIndex <= index) && (index < run.glyphIndex + run.numberOfGlyphs))
-      {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  bool doGlyphHaveStrikethrough(GlyphIndex                           index,
-                                const Vector<StrikethroughGlyphRun>& strikethroughRuns,
-                                Vector4&                             strikethroughColor)
+  bool
+  doGlyphHaveStrikethrough(GlyphIndex                           index,
+                           const Vector<StrikethroughGlyphRun>& strikethroughRuns,
+                           Vector4&                             strikethroughColor)
   {
     for(Vector<StrikethroughGlyphRun>::ConstIterator it    = strikethroughRuns.Begin(),
                                                      endIt = strikethroughRuns.End();
@@ -456,27 +441,22 @@ struct AtlasRenderer::Impl
     Vector<Extent>          strikethroughExtents;
     mDepth = depth;
 
-    const Vector2&              textSize(view.GetLayoutSize());
-    const Vector2               halfTextSize(textSize * 0.5f);
-    const Vector2&              shadowOffset(view.GetShadowOffset());
-    const Vector4&              shadowColor(view.GetShadowColor());
-    const bool                  underlineEnabled = view.IsUnderlineEnabled();
-    const Vector4&              underlineColor(view.GetUnderlineColor());
-    const float                 underlineHeight      = view.GetUnderlineHeight();
-    const Text::Underline::Type underlineType        = view.GetUnderlineType();
-    const float                 dashedUnderlineWidth = view.GetDashedUnderlineWidth();
-    const float                 dashedUnderlineGap   = view.GetDashedUnderlineGap();
-    const uint16_t              outlineWidth         = view.GetOutlineWidth();
-    const Vector4&              outlineColor(view.GetOutlineColor());
-    const bool                  isOutline            = 0u != outlineWidth;
-    const GlyphInfo*            hyphens              = view.GetHyphens();
-    const Length*               hyphenIndices        = view.GetHyphenIndices();
-    const Length                hyphensCount         = view.GetHyphensCount();
-    const bool                  strikethroughEnabled = view.IsStrikethroughEnabled();
-    const Vector4&              strikethroughColor(view.GetStrikethroughColor());
-    const float                 strikethroughHeight = view.GetStrikethroughHeight();
-    Vector4                     currentStrikethroughColor;
-    const float                 characterSpacing(view.GetCharacterSpacing());
+    const Vector2&   textSize(view.GetLayoutSize());
+    const Vector2    halfTextSize(textSize * 0.5f);
+    const Vector2&   shadowOffset(view.GetShadowOffset());
+    const Vector4&   shadowColor(view.GetShadowColor());
+    const bool       underlineEnabled = view.IsUnderlineEnabled();
+    const uint16_t   outlineWidth     = view.GetOutlineWidth();
+    const Vector4&   outlineColor(view.GetOutlineColor());
+    const bool       isOutline            = 0u != outlineWidth;
+    const GlyphInfo* hyphens              = view.GetHyphens();
+    const Length*    hyphenIndices        = view.GetHyphenIndices();
+    const Length     hyphensCount         = view.GetHyphensCount();
+    const bool       strikethroughEnabled = view.IsStrikethroughEnabled();
+    const Vector4&   strikethroughColor(view.GetStrikethroughColor());
+    const float      strikethroughHeight = view.GetStrikethroughHeight();
+    Vector4          currentStrikethroughColor;
+    const float      characterSpacing(view.GetCharacterSpacing());
 
     // Elided text info. Indices according to elided text.
     const auto startIndexOfGlyphs              = view.GetStartIndexOfElidedGlyphs();
@@ -485,14 +465,31 @@ struct AtlasRenderer::Impl
 
     const bool useDefaultColor = (NULL == colorsBuffer);
 
+    // Get a handle of the font client. Used to retrieve the bitmaps of the glyphs.
+    TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
     // Get the underline runs.
-    const Length     numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
-    Vector<GlyphRun> underlineRuns;
+    const Length               numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
+    Vector<UnderlinedGlyphRun> underlineRuns;
     underlineRuns.Resize(numberOfUnderlineRuns);
     view.GetUnderlineRuns(underlineRuns.Begin(),
                           0u,
                           numberOfUnderlineRuns);
 
+    // Aggregate underline-style-properties from view
+    const UnderlineStyleProperties viewUnderlineProperties{view.GetUnderlineType(),
+                                                           view.GetUnderlineColor(),
+                                                           view.GetUnderlineHeight(),
+                                                           view.GetDashedUnderlineGap(),
+                                                           view.GetDashedUnderlineWidth(),
+                                                           true,
+                                                           true,
+                                                           true,
+                                                           true,
+                                                           true};
+
+    float maxUnderlineHeight = viewUnderlineProperties.height;
+
     // Get the strikethrough runs.
     const Length                  numberOfStrikethroughRuns = view.GetNumberOfStrikethroughRuns();
     Vector<StrikethroughGlyphRun> strikethroughRuns;
@@ -502,12 +499,11 @@ struct AtlasRenderer::Impl
     bool thereAreUnderlinedGlyphs = false;
     bool strikethroughGlyphsExist = false;
 
-    float  currentUnderlinePosition      = ZERO;
-    float  currentUnderlineThickness     = underlineHeight;
-    float  currentStrikethroughThickness = strikethroughHeight;
-    FontId lastFontId                    = 0;
-    FontId lastUnderlinedFontId          = 0;
-    Style  style                         = STYLE_NORMAL;
+    float  currentUnderlinePosition   = ZERO;
+    float  currentStrikethroughHeight = strikethroughHeight;
+    float  maxStrikethroughHeight     = currentStrikethroughHeight;
+    FontId lastFontId                 = 0;
+    Style  style                      = STYLE_NORMAL;
 
     if(fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1)
     {
@@ -524,8 +520,10 @@ struct AtlasRenderer::Impl
     uint32_t               hyphenIndex = 0;
 
     //For septated underlined chunks. (this is for Markup case)
-    uint32_t underlineChunkId = 0u;    // give id for each chunk.
-    bool     isPreUnderlined  = false; // status of underlined for previous glyph.
+    uint32_t                                     underlineChunkId = 0u;                            // give id for each chunk.
+    bool                                         isPreUnderlined  = false;                         // status of underlined for previous glyph.
+    std::map<uint32_t, UnderlineStyleProperties> mapUnderlineChunkIdWithProperties;                // mapping underlineChunkId with UnderlineStyleProperties to get properties of underlined chunk
+    UnderlineStyleProperties                     preUnderlineProperties = viewUnderlineProperties; // the previous UnderlineStyleProperties
 
     uint32_t                      strikethroughChunkId      = 0u;    // give id for each chunk.
     bool                          isPrevGlyphStrikethrough  = false; // status of strikethrough for previous glyph.
@@ -544,6 +542,12 @@ struct AtlasRenderer::Impl
       }
     }
 
+    //To keep the last fontMetrics of lastDecorativeLinesFontId
+    FontId      lastDecorativeLinesFontId = 0; // DecorativeLines like Undeline and Strikethrough
+    FontMetrics lastDecorativeLinesFontMetrics;
+    fontClient.GetFontMetrics(lastDecorativeLinesFontId, lastDecorativeLinesFontMetrics);
+
+    // Iteration on glyphs
     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
     {
       GlyphInfo glyph;
@@ -558,8 +562,11 @@ struct AtlasRenderer::Impl
         glyph = *(glyphsBuffer + i);
       }
 
-      const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined(i, underlineRuns);
-      thereAreUnderlinedGlyphs     = thereAreUnderlinedGlyphs || isGlyphUnderlined;
+      Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt = underlineRuns.End();
+      const bool                                isGlyphUnderlined           = underlineEnabled || IsGlyphUnderlined(i, underlineRuns, currentUnderlinedGlyphRunIt);
+      const UnderlineStyleProperties            currentUnderlineProperties  = GetCurrentUnderlineProperties(isGlyphUnderlined, underlineRuns, currentUnderlinedGlyphRunIt, viewUnderlineProperties);
+      float                                     currentUnderlineHeight      = GetCurrentUnderlineHeight(underlineRuns, currentUnderlinedGlyphRunIt, viewUnderlineProperties.height);
+      thereAreUnderlinedGlyphs                                              = thereAreUnderlinedGlyphs || isGlyphUnderlined;
 
       currentStrikethroughColor       = strikethroughColor;
       const bool isStrikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(i, strikethroughRuns, currentStrikethroughColor);
@@ -568,58 +575,42 @@ struct AtlasRenderer::Impl
       // No operation for white space
       if(glyph.width && glyph.height)
       {
-        // Are we still using the same fontId as previous
-        if((isGlyphUnderlined || isStrikethroughGlyph) && (glyph.fontId != lastUnderlinedFontId))
+        // Check and update decorative-lines informations
+        if((isGlyphUnderlined || isStrikethroughGlyph) &&
+           ((glyph.fontId != lastDecorativeLinesFontId) || !(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties))))
         {
-          // We need to fetch fresh font underline metrics
-          FontMetrics fontMetrics;
-          mFontClient.GetFontMetrics(glyph.fontId, fontMetrics);
-          currentUnderlinePosition = ceil(fabsf(fontMetrics.underlinePosition));
-          const float descender    = ceil(fabsf(fontMetrics.descender));
-
-          if(fabsf(underlineHeight) < Math::MACHINE_EPSILON_1000)
+          bool isDecorativeLinesFontIdUpdated = false;
+          // Are we still using the same fontId as previous
+          if(glyph.fontId != lastDecorativeLinesFontId)
           {
-            currentUnderlineThickness = fontMetrics.underlineThickness;
+            // We need to fetch fresh font metrics
+            lastDecorativeLinesFontId      = glyph.fontId;
+            isDecorativeLinesFontIdUpdated = true;
+            fontClient.GetFontMetrics(lastDecorativeLinesFontId, lastDecorativeLinesFontMetrics);
 
-            // Ensure underline will be at least a pixel high
-            if(currentUnderlineThickness < ONE)
+            if(isStrikethroughGlyph || isGlyphUnderlined)
             {
-              currentUnderlineThickness = ONE;
-            }
-            else
-            {
-              currentUnderlineThickness = ceil(currentUnderlineThickness);
+              //The currentUnderlinePosition will be used for both Underline and/or Strikethrough
+              currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(lastDecorativeLinesFontMetrics);
             }
           }
 
-          if(fabsf(strikethroughHeight) < Math::MACHINE_EPSILON_1000)
+          if(isGlyphUnderlined && (isDecorativeLinesFontIdUpdated || !(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties))))
           {
-            // Ensure strikethrough will be at least a pixel high
-            if(currentStrikethroughThickness < ONE)
-            {
-              currentStrikethroughThickness = ONE;
-            }
-            else
+            //If the Underline Height is changed then we need to recalculate height.
+            if(!(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties)))
             {
-              currentStrikethroughThickness = ceil(currentStrikethroughThickness);
+              maxUnderlineHeight = currentUnderlineHeight;
             }
-          }
 
-          // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
-          if(currentUnderlinePosition > descender)
-          {
-            currentUnderlinePosition = descender;
+            CalcualteUnderlineHeight(lastDecorativeLinesFontMetrics, currentUnderlineHeight, maxUnderlineHeight);
           }
 
-          if(fabsf(currentUnderlinePosition) < Math::MACHINE_EPSILON_1000)
+          if(isDecorativeLinesFontIdUpdated && isStrikethroughGlyph)
           {
-            // Move offset down by one ( EFL behavior )
-            currentUnderlinePosition = ONE;
+            CalcualteStrikethroughHeight(currentStrikethroughHeight, maxStrikethroughHeight);
           }
-
-          lastUnderlinedFontId = glyph.fontId;
-
-        } // underline
+        } // decorative-lines
 
         AtlasGlyphManager::GlyphStyle style;
         style.isItalic = glyph.isItalicRequired;
@@ -662,6 +653,18 @@ struct AtlasRenderer::Impl
           const ColorIndex colorIndex = useDefaultColor ? 0u : *(colorIndicesBuffer + i);
           const Vector4&   color      = (useDefaultColor || (0u == colorIndex)) ? defaultColor : *(colorsBuffer + colorIndex - 1u);
 
+          //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case)
+          // Examples: "Hello <u>World</u> Hello <u>World</u>", "<u>World</u> Hello <u>World</u>", "<u>   World</u> Hello <u>World</u>"
+          if(isPreUnderlined && (!isGlyphUnderlined || (preUnderlineProperties != currentUnderlineProperties)))
+          {
+            mapUnderlineChunkIdWithProperties.insert(std::pair<uint32_t, UnderlineStyleProperties>(underlineChunkId, preUnderlineProperties));
+            underlineChunkId++;
+          }
+
+          //Keep status of underlined for previous glyph to check consecutive indices
+          isPreUnderlined        = isGlyphUnderlined;
+          preUnderlineProperties = currentUnderlineProperties;
+
           GenerateMesh(glyph,
                        positionPlusOutlineOffset,
                        color,
@@ -669,7 +672,7 @@ struct AtlasRenderer::Impl
                        slot,
                        isGlyphUnderlined,
                        currentUnderlinePosition,
-                       currentUnderlineThickness,
+                       maxUnderlineHeight,
                        meshContainer,
                        newTextCache,
                        extents,
@@ -686,7 +689,7 @@ struct AtlasRenderer::Impl
                          slot,
                          strikethroughGlyphsExist,
                          0.0f,
-                         currentStrikethroughThickness,
+                         maxStrikethroughHeight,
                          meshContainer,
                          newTextCache,
                          strikethroughExtents,
@@ -707,7 +710,7 @@ struct AtlasRenderer::Impl
                        slotOutline,
                        false,
                        currentUnderlinePosition,
-                       currentUnderlineThickness,
+                       maxUnderlineHeight,
                        meshContainerOutline,
                        newTextCache,
                        extents,
@@ -716,15 +719,6 @@ struct AtlasRenderer::Impl
                        0u);
         }
 
-        //The new underlined chunk. Add new id if they are not consecutive indices (this is for Markup case)
-        // Examples: "Hello <u>World</u> Hello <u>World</u>", "<u>World</u> Hello <u>World</u>", "<u>   World</u> Hello <u>World</u>"
-        if(isPreUnderlined && (isPreUnderlined != isGlyphUnderlined))
-        {
-          underlineChunkId++;
-        }
-        //Keep status of underlined for previous glyph to check consecutive indices
-        isPreUnderlined = isGlyphUnderlined;
-
         if(isPrevGlyphStrikethrough && !isStrikethroughGlyph)
         {
           strikethroughChunkId++;
@@ -746,7 +740,7 @@ struct AtlasRenderer::Impl
     if(thereAreUnderlinedGlyphs)
     {
       // Check to see if any of the text needs an underline
-      GenerateUnderlines(meshContainer, extents, underlineColor, underlineType, dashedUnderlineWidth, dashedUnderlineGap);
+      GenerateUnderlines(meshContainer, extents, viewUnderlineProperties, mapUnderlineChunkIdWithProperties);
     }
 
     if(strikethroughGlyphsExist)
@@ -1051,15 +1045,14 @@ struct AtlasRenderer::Impl
     }
   }
 
-  void GenerateUnderlines(std::vector<MeshRecord>&     meshRecords,
-                          Vector<Extent>&              extents,
-                          const Vector4&               underlineColor,
-                          const Text::Underline::Type& underlineType,
-                          const float&                 dashedUnderlineWidth,
-                          const float&                 dashedUnderlineGap)
+  void GenerateUnderlines(std::vector<MeshRecord>&                            meshRecords,
+                          Vector<Extent>&                                     extents,
+                          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();
         eIt != eEndIt;
@@ -1069,6 +1062,17 @@ struct AtlasRenderer::Impl
       uint32_t               index = eIt->mMeshRecordIndex;
       Vector2                uv    = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId);
 
+      auto pairUnderlineChunkIdWithProperties = mapUnderlineChunkIdWithProperties.find(eIt->mUnderlineChunkId);
+
+      const UnderlineStyleProperties underlineProperties = (pairUnderlineChunkIdWithProperties == mapUnderlineChunkIdWithProperties.end())
+                                                             ? viewUnderlineProperties
+                                                             : pairUnderlineChunkIdWithProperties->second;
+
+      const Vector4&               underlineColor       = underlineProperties.colorDefined ? underlineProperties.color : viewUnderlineProperties.color;
+      const Text::Underline::Type& underlineType        = underlineProperties.typeDefined ? underlineProperties.type : viewUnderlineProperties.type;
+      const float&                 dashedUnderlineGap   = underlineProperties.dashGapDefined ? underlineProperties.dashGap : viewUnderlineProperties.dashGap;
+      const float&                 dashedUnderlineWidth = underlineProperties.dashWidthDefined ? underlineProperties.dashWidth : viewUnderlineProperties.dashWidth;
+
       // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
       float u           = HALF / uv.x;
       float v           = HALF / uv.y;
@@ -1082,9 +1086,7 @@ struct AtlasRenderer::Impl
       {
         float dashTlx = tlx;
         float dashBrx = tlx;
-        faceIndex     = 0;
 
-        AtlasManager::Mesh2D newMesh;
         while((dashTlx >= tlx) && (dashTlx < brx) && ((dashTlx + dashedUnderlineWidth) <= brx))
         {
           dashBrx = dashTlx + dashedUnderlineWidth;
diff --git a/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp b/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp
new file mode 100644 (file)
index 0000000..c87fe88
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/// Helper method to fetch the underline metrics for the specified font glyph
+void CalcualteStrikethroughHeight(float& currentStrikethroughHeight, float& maxStrikethroughHeight)
+{
+  //Height of strikethrough represents the thickness of line.
+
+  // Ensure strikethrough will be at least a pixel high
+  if(currentStrikethroughHeight < 1.0f)
+  {
+    currentStrikethroughHeight = 1.0f;
+  }
+  else
+  {
+    currentStrikethroughHeight = ceil(currentStrikethroughHeight);
+  }
+
+  // The strikethrough height should be the max strikethrough height of all glyphs of the line.
+  if(currentStrikethroughHeight > maxStrikethroughHeight)
+  {
+    maxStrikethroughHeight = currentStrikethroughHeight;
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h b/dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h
new file mode 100644 (file)
index 0000000..b3df7ef
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef DALI_TOOLKIT_TEXT_RENDERING_STYLES_STRIKETHROUGH_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_RENDERING_STYLES_STRIKETHROUGH_HELPER_FUNCTIONS_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Calculate the current underline height and update maximum underline height
+ *
+ * @param[inout] currentStrikethroughHeight the current strikethrough height.
+ * @param[inout] maxStrikethroughHeight the maximum strikethrough height.
+ *
+ */
+void CalcualteStrikethroughHeight(float& currentStrikethroughHeight, float& maxStrikethroughHeight);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_RENDERING_STYLES_STRIKETHROUGH_HELPER_FUNCTIONS_H
\ No newline at end of file
diff --git a/dali-toolkit/internal/text/rendering/styles/underline-helper-functions.cpp b/dali-toolkit/internal/text/rendering/styles/underline-helper-functions.cpp
new file mode 100644 (file)
index 0000000..6720b91
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+bool IsGlyphUnderlined(GlyphIndex                                 index,
+                       const Vector<UnderlinedGlyphRun>&          underlineRuns,
+                       Vector<UnderlinedGlyphRun>::ConstIterator& currentUnderlinedGlyphRunIt)
+{
+  for(Vector<UnderlinedGlyphRun>::ConstIterator it    = underlineRuns.Begin(),
+                                                endIt = underlineRuns.End();
+      it != endIt;
+      ++it)
+  {
+    const UnderlinedGlyphRun& run = *it;
+
+    if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs))
+    {
+      currentUnderlinedGlyphRunIt = it;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+float GetCurrentUnderlineHeight(const Vector<UnderlinedGlyphRun>&         underlineRuns,
+                                Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt,
+                                const float                               underlineHeight)
+{
+  if(currentUnderlinedGlyphRunIt == underlineRuns.End())
+  {
+    return underlineHeight;
+  }
+
+  const UnderlinedGlyphRun& underlinedGlyphRun = *currentUnderlinedGlyphRunIt;
+  return (underlinedGlyphRun.properties.heightDefined ? underlinedGlyphRun.properties.height : underlineHeight);
+}
+
+UnderlineStyleProperties GetCurrentUnderlineProperties(const bool&                               isGlyphUnderlined,
+                                                       const Vector<UnderlinedGlyphRun>&         underlineRuns,
+                                                       Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt,
+                                                       const UnderlineStyleProperties&           commonUnderlineProperties)
+{
+  return (isGlyphUnderlined && (currentUnderlinedGlyphRunIt != underlineRuns.End()))
+           ? currentUnderlinedGlyphRunIt->properties
+           : commonUnderlineProperties;
+}
+
+float FetchUnderlinePositionFromFontMetrics(const FontMetrics& fontMetrics)
+{
+  //Helper method to fetch the underline metrics for the specified font glyph
+  const float descender         = ceil(fabsf(fontMetrics.descender));
+  float       underlinePosition = ceil(fabsf(fontMetrics.underlinePosition));
+
+  // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
+  if(underlinePosition > descender)
+  {
+    underlinePosition = descender;
+  }
+
+  if(fabsf(underlinePosition) < Math::MACHINE_EPSILON_1000)
+  {
+    // Move offset down by one ( EFL behavior )
+    underlinePosition = 1.0f;
+  }
+
+  return underlinePosition;
+}
+
+void CalcualteUnderlineHeight(const FontMetrics& fontMetrics, float& currentUnderlineHeight, float& maxUnderlineHeight)
+{
+  //Helper method to fetch the underline metrics for the specified font glyph
+  //Height of underline represents the thickness of line.
+  if(fabsf(currentUnderlineHeight) < Math::MACHINE_EPSILON_1000)
+  {
+    currentUnderlineHeight = fontMetrics.underlineThickness;
+
+    // Ensure underline will be at least a pixel high
+    if(currentUnderlineHeight < 1.0f)
+    {
+      currentUnderlineHeight = 1.0f;
+    }
+    else
+    {
+      currentUnderlineHeight = ceil(currentUnderlineHeight);
+    }
+  }
+
+  // The underline height should be the max underline height of all glyphs of the line.
+  if(currentUnderlineHeight > maxUnderlineHeight)
+  {
+    maxUnderlineHeight = currentUnderlineHeight;
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h b/dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h
new file mode 100644 (file)
index 0000000..825b05c
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef DALI_TOOLKIT_TEXT_RENDERING_STYLES_UNDERLINE_HELPER_FUNCTIONS_H
+#define DALI_TOOLKIT_TEXT_RENDERING_STYLES_UNDERLINE_HELPER_FUNCTIONS_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Whether the glyph at index is underlined or not. If true then return iterator to the run containes index.
+ *
+ * @param[in] index the index of glyph.
+ * @param[in] underlineRuns the underline runs.
+ * @param[out] currentUnderlinedGlyphRunIt the iterator of current underlined glyph run.
+ *
+ * @return true if glyph at index is underlined
+ */
+bool IsGlyphUnderlined(GlyphIndex                                 index,
+                       const Vector<UnderlinedGlyphRun>&          underlineRuns,
+                       Vector<UnderlinedGlyphRun>::ConstIterator& currentUnderlinedGlyphRunIt);
+
+/**
+ * @brief Check the current underlined glyph run iterator if not empty and its height is defined then return ts height. Otherwise return the common underline height.
+ *
+ * @param[in] underlineRuns the underline runs.
+ * @param[in] currentUnderlinedGlyphRunIt the iterator of current underlined glyph run.
+ * @param[in] underlineHeight the common underline height.
+ *
+ * @return the determined underline height
+ */
+float GetCurrentUnderlineHeight(const Vector<UnderlinedGlyphRun>&         underlineRuns,
+                                Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt,
+                                const float                               underlineHeight);
+
+/**
+ * @brief Check the current underlined glyph run iterator if not empty and isGlyphUnderlined is true then return its UnderlineProperties. Otherwise return the common underline properties.
+ *
+ * @param[in] isGlyphUnderlined whether the glyph is underlined.
+ * @param[in] underlineRuns the underline runs.
+ * @param[in] currentUnderlinedGlyphRunIt the iterator of current underlined glyph run.
+ * @param[in] commonUnderlineProperties the common underline properties.
+ *
+ * @return the determined underline properties
+ */
+UnderlineStyleProperties GetCurrentUnderlineProperties(const bool&                               isGlyphUnderlined,
+                                                       const Vector<UnderlinedGlyphRun>&         underlineRuns,
+                                                       Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt,
+                                                       const UnderlineStyleProperties&           commonUnderlineProperties);
+
+/**
+ * @brief Fetch and calculate underline Position using font-metrics
+ *
+ * @param[in] fontMetrics the font metrics of glyph.
+ *
+ * @return the underline position
+ */
+float FetchUnderlinePositionFromFontMetrics(const FontMetrics& fontMetrics);
+
+/**
+ * @brief Calculate the current underline height using font-metrics and update maximum underline height
+ *
+ * @param[in] fontMetrics the font metrics of glyph.
+ * @param[inout] currentUnderlineHeight the current underline height.
+ * @param[inout] maxUnderlineHeight the maximum underline height.
+ *
+ */
+void CalcualteUnderlineHeight(const FontMetrics& fontMetrics, float& currentUnderlineHeight, float& maxUnderlineHeight);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_RENDERING_STYLES_UNDERLINE_HELPER_FUNCTIONS_H
\ No newline at end of file
index 96088b5..790e247 100644 (file)
@@ -26,6 +26,8 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h>
+#include <dali-toolkit/internal/text/rendering/styles/underline-helper-functions.h>
 #include <dali-toolkit/internal/text/rendering/view-model.h>
 
 namespace Dali
@@ -37,6 +39,7 @@ namespace Text
 namespace
 {
 const float HALF(0.5f);
+const float ONE_AND_A_HALF(1.5f);
 /**
  * @brief Data struct used to set the buffer of the glyph's bitmap into the final bitmap's buffer.
  */
@@ -257,25 +260,6 @@ void TypesetGlyph(GlyphData&           data,
   }
 }
 
-bool IsGlyphUnderlined(GlyphIndex              index,
-                       const Vector<GlyphRun>& underlineRuns)
-{
-  for(Vector<GlyphRun>::ConstIterator it    = underlineRuns.Begin(),
-                                      endIt = underlineRuns.End();
-      it != endIt;
-      ++it)
-  {
-    const GlyphRun& run = *it;
-
-    if((run.glyphIndex <= index) && (index < run.glyphIndex + run.numberOfGlyphs))
-    {
-      return true;
-    }
-  }
-
-  return false;
-}
-
 bool doGlyphHaveStrikethrough(GlyphIndex                           index,
                               const Vector<StrikethroughGlyphRun>& strikethroughRuns,
                               Vector4&                             strikethroughColor)
@@ -301,79 +285,6 @@ bool doGlyphHaveStrikethrough(GlyphIndex                           index,
   return false;
 }
 
-/// Helper method to fetch the underline metrics for the specified font glyph
-void FetchFontDecorationlinesMetrics(
-  TextAbstraction::FontClient& fontClient,
-  const GlyphInfo* const       glyphInfo,
-  float&                       currentUnderlinePosition,
-  const float                  underlineHeight,
-  float&                       currentUnderlineThickness,
-  float&                       maxUnderlineThickness,
-  FontId&                      lastlinedFontId,
-  const float                  strikethroughHeight,
-  float&                       currentStrikethroughThickness,
-  float&                       maxStrikethroughThickness)
-{
-  FontMetrics fontMetrics;
-  fontClient.GetFontMetrics(glyphInfo->fontId, fontMetrics);
-  currentUnderlinePosition = ceil(fabsf(fontMetrics.underlinePosition));
-  const float descender    = ceil(fabsf(fontMetrics.descender));
-
-  if(fabsf(underlineHeight) < Math::MACHINE_EPSILON_1000)
-  {
-    currentUnderlineThickness = fontMetrics.underlineThickness;
-
-    // Ensure underline will be at least a pixel high
-    if(currentUnderlineThickness < 1.0f)
-    {
-      currentUnderlineThickness = 1.0f;
-    }
-    else
-    {
-      currentUnderlineThickness = ceil(currentUnderlineThickness);
-    }
-  }
-
-  if(fabsf(strikethroughHeight) < Math::MACHINE_EPSILON_1000)
-  {
-    // Ensure strikethrough will be at least a pixel high
-    if(currentStrikethroughThickness < 1.0f)
-    {
-      currentStrikethroughThickness = 1.0f;
-    }
-    else
-    {
-      currentStrikethroughThickness = ceil(currentStrikethroughThickness);
-    }
-  }
-
-  // The underline thickness should be the max underline thickness of all glyphs of the line.
-  if(currentUnderlineThickness > maxUnderlineThickness)
-  {
-    maxUnderlineThickness = currentUnderlineThickness;
-  }
-
-  // The strikethrough thickness should be the max strikethrough thickness of all glyphs of the line.
-  if(currentStrikethroughThickness > maxStrikethroughThickness)
-  {
-    maxStrikethroughThickness = currentStrikethroughThickness;
-  }
-
-  // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font
-  if(currentUnderlinePosition > descender)
-  {
-    currentUnderlinePosition = descender;
-  }
-
-  if(fabsf(currentUnderlinePosition) < Math::MACHINE_EPSILON_1000)
-  {
-    // Move offset down by one ( EFL behavior )
-    currentUnderlinePosition = 1.0f;
-  }
-
-  lastlinedFontId = glyphInfo->fontId;
-}
-
 /// Draws the specified color to the pixel buffer
 void WriteColorToPixelBuffer(
   GlyphData&         glyphData,
@@ -398,24 +309,27 @@ void WriteColorToPixelBuffer(
 
 /// Draws the specified underline color to the buffer
 void DrawUnderline(
-  const Vector4&              underlineColor,
-  const unsigned int          bufferWidth,
-  const unsigned int          bufferHeight,
-  GlyphData&                  glyphData,
-  const float                 baseline,
-  const float                 currentUnderlinePosition,
-  const float                 maxUnderlineThickness,
-  const float                 lineExtentLeft,
-  const float                 lineExtentRight,
-  const Text::Underline::Type underlineType,
-  const float                 dashedUnderlineWidth,
-  const float                 dashedUnderlineGap,
-  const LineRun&              line)
+  const unsigned int              bufferWidth,
+  const unsigned int              bufferHeight,
+  GlyphData&                      glyphData,
+  const float                     baseline,
+  const float                     currentUnderlinePosition,
+  const float                     maxUnderlineHeight,
+  const float                     lineExtentLeft,
+  const float                     lineExtentRight,
+  const UnderlineStyleProperties& commonUnderlineProperties,
+  const UnderlineStyleProperties& currentUnderlineProperties,
+  const LineRun&                  line)
 {
+  const Vector4&              underlineColor       = currentUnderlineProperties.colorDefined ? currentUnderlineProperties.color : commonUnderlineProperties.color;
+  const Text::Underline::Type underlineType        = currentUnderlineProperties.typeDefined ? currentUnderlineProperties.type : commonUnderlineProperties.type;
+  const float                 dashedUnderlineWidth = currentUnderlineProperties.dashWidthDefined ? currentUnderlineProperties.dashWidth : commonUnderlineProperties.dashWidth;
+  const float                 dashedUnderlineGap   = currentUnderlineProperties.dashGapDefined ? currentUnderlineProperties.dashGap : commonUnderlineProperties.dashGap;
+
   int       underlineYOffset = glyphData.verticalOffset + baseline + currentUnderlinePosition;
   uint32_t* bitmapBuffer     = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer());
 
-  for(unsigned int y = underlineYOffset; y < underlineYOffset + maxUnderlineThickness; y++)
+  for(unsigned int y = underlineYOffset; y < underlineYOffset + maxUnderlineHeight; y++)
   {
     if(y > bufferHeight - 1)
     {
@@ -466,8 +380,8 @@ void DrawUnderline(
   }
   if(underlineType == Text::Underline::DOUBLE)
   {
-    int secondUnderlineYOffset = glyphData.verticalOffset - line.descender - maxUnderlineThickness;
-    for(unsigned int y = secondUnderlineYOffset; y < secondUnderlineYOffset + maxUnderlineThickness; y++)
+    int secondUnderlineYOffset = underlineYOffset - ONE_AND_A_HALF * maxUnderlineHeight;
+    for(unsigned int y = secondUnderlineYOffset; y < secondUnderlineYOffset + maxUnderlineHeight; y++)
     {
       if(y > bufferHeight - 1)
       {
@@ -639,14 +553,14 @@ void DrawStrikethrough(
   GlyphData&         glyphData,
   const float        baseline,
   const LineRun&     line,
-  const float        maxStrikethroughThickness,
+  const float        maxStrikethroughHeight,
   const float        lineExtentLeft,
   const float        lineExtentRight,
   float              strikethroughStartingYPosition)
 {
   uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer());
 
-  for(unsigned int y = strikethroughStartingYPosition; y < strikethroughStartingYPosition + maxStrikethroughThickness; y++)
+  for(unsigned int y = strikethroughStartingYPosition; y < strikethroughStartingYPosition + maxStrikethroughHeight; y++)
   {
     if(y > bufferHeight - 1)
     {
@@ -987,20 +901,27 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       }
     }
 
-    const bool                  underlineEnabled     = mModel->IsUnderlineEnabled();
-    const Vector4&              underlineColor       = mModel->GetUnderlineColor();
-    const float                 underlineHeight      = mModel->GetUnderlineHeight();
-    const Text::Underline::Type underlineType        = mModel->GetUnderlineType();
-    const float                 dashedUnderlineWidth = mModel->GetDashedUnderlineWidth();
-    const float                 dashedUnderlineGap   = mModel->GetDashedUnderlineGap();
-    const bool                  strikethroughEnabled = mModel->IsStrikethroughEnabled();
-    const Vector4&              strikethroughColor   = mModel->GetStrikethroughColor();
-    const float                 strikethroughHeight  = mModel->GetStrikethroughHeight();
-    const float                 characterSpacing     = mModel->GetCharacterSpacing();
+    const bool     underlineEnabled     = mModel->IsUnderlineEnabled();
+    const bool     strikethroughEnabled = mModel->IsStrikethroughEnabled();
+    const Vector4& strikethroughColor   = mModel->GetStrikethroughColor();
+    const float    strikethroughHeight  = mModel->GetStrikethroughHeight();
+    const float    characterSpacing     = mModel->GetCharacterSpacing();
+
+    // Aggregate underline-style-properties from mModel
+    const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(),
+                                                            mModel->GetUnderlineColor(),
+                                                            mModel->GetUnderlineHeight(),
+                                                            mModel->GetDashedUnderlineGap(),
+                                                            mModel->GetDashedUnderlineWidth(),
+                                                            true,
+                                                            true,
+                                                            true,
+                                                            true,
+                                                            true};
 
     // Get the underline runs.
-    const Length     numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
-    Vector<GlyphRun> underlineRuns;
+    const Length               numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
+    Vector<UnderlinedGlyphRun> underlineRuns;
     underlineRuns.Resize(numberOfUnderlineRuns);
     mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
 
@@ -1013,14 +934,16 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
     bool thereAreUnderlinedGlyphs = false;
     bool strikethroughGlyphsExist = false;
 
-    float currentUnderlinePosition       = 0.0f;
-    float currentUnderlineThickness      = underlineHeight;
-    float maxUnderlineThickness          = currentUnderlineThickness;
-    float currentStrikethroughThickness  = strikethroughHeight;
-    float maxStrikethroughThickness      = currentStrikethroughThickness;
+    float currentUnderlinePosition   = 0.0f;
+    float currentUnderlineHeight     = modelUnderlineProperties.height;
+    float maxUnderlineHeight         = currentUnderlineHeight;
+    auto  currentUnderlineProperties = modelUnderlineProperties;
+
+    float currentStrikethroughHeight     = strikethroughHeight;
+    float maxStrikethroughHeight         = currentStrikethroughHeight;
     float strikethroughStartingYPosition = 0.0f;
 
-    FontId lastUnderlinedFontId = 0;
+    FontId lastFontId = 0;
 
     float lineExtentLeft  = bufferWidth;
     float lineExtentRight = 0.0f;
@@ -1079,19 +1002,39 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
         continue;
       }
 
-      const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined(glyphIndex, underlineRuns);
-      thereAreUnderlinedGlyphs  = thereAreUnderlinedGlyphs || underlineGlyph;
+      Vector<UnderlinedGlyphRun>::ConstIterator currentUnderlinedGlyphRunIt = underlineRuns.End();
+      const bool                                underlineGlyph              = underlineEnabled || IsGlyphUnderlined(glyphIndex, underlineRuns, currentUnderlinedGlyphRunIt);
+      currentUnderlineProperties                                            = GetCurrentUnderlineProperties(underlineGlyph, underlineRuns, currentUnderlinedGlyphRunIt, modelUnderlineProperties);
+      currentUnderlineHeight                                                = GetCurrentUnderlineHeight(underlineRuns, currentUnderlinedGlyphRunIt, modelUnderlineProperties.height);
+      thereAreUnderlinedGlyphs                                              = thereAreUnderlinedGlyphs || underlineGlyph;
 
       currentStrikethroughColor     = strikethroughColor;
       const bool strikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughColor);
       strikethroughGlyphsExist      = strikethroughGlyphsExist || strikethroughGlyph;
 
       // Are we still using the same fontId as previous
-      if((strikethroughGlyph || underlineGlyph) && (glyphInfo->fontId != lastUnderlinedFontId))
+      if((glyphInfo->fontId != lastFontId) && (strikethroughGlyph || underlineGlyph))
       {
         // We need to fetch fresh font underline metrics
-        FetchFontDecorationlinesMetrics(fontClient, glyphInfo, currentUnderlinePosition, underlineHeight, currentUnderlineThickness, maxUnderlineThickness, lastUnderlinedFontId, strikethroughHeight, currentStrikethroughThickness, maxStrikethroughThickness);
-      } // underline
+        FontMetrics fontMetrics;
+        fontClient.GetFontMetrics(glyphInfo->fontId, fontMetrics);
+
+        //The currentUnderlinePosition will be used for both Underline and/or Strikethrough
+        currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(fontMetrics);
+
+        if(underlineGlyph)
+        {
+          CalcualteUnderlineHeight(fontMetrics, currentUnderlineHeight, maxUnderlineHeight);
+        }
+
+        if(strikethroughGlyph)
+        {
+          CalcualteStrikethroughHeight(currentStrikethroughHeight, maxStrikethroughHeight);
+        }
+
+        // Update lastFontId because fontId is changed
+        lastFontId = glyphInfo->fontId; // Prevents searching for existing blocksizes when string of the same fontId.
+      }
 
       // Retrieves the glyph's position.
       Vector2 position = *(positionBuffer + elidedGlyphIndex);
@@ -1210,7 +1153,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
     // Draw the underline from the leftmost glyph to the rightmost glyph
     if(thereAreUnderlinedGlyphs && style == Typesetter::STYLE_UNDERLINE)
     {
-      DrawUnderline(underlineColor, bufferWidth, bufferHeight, glyphData, baseline, currentUnderlinePosition, maxUnderlineThickness, lineExtentLeft, lineExtentRight, underlineType, dashedUnderlineWidth, dashedUnderlineGap, line);
+      DrawUnderline(bufferWidth, bufferHeight, glyphData, baseline, currentUnderlinePosition, maxUnderlineHeight, lineExtentLeft, lineExtentRight, modelUnderlineProperties, currentUnderlineProperties, line);
     }
 
     // Draw the background color from the leftmost glyph to the rightmost glyph
@@ -1224,7 +1167,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
     {
       //TODO : The currently implemented strikethrough creates a strikethrough on the line level. We need to create different strikethroughs the case of glyphs with different sizes.
       strikethroughStartingYPosition = (glyphData.verticalOffset + baseline + currentUnderlinePosition) - ((line.ascender) * HALF); // 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.
-      DrawStrikethrough(currentStrikethroughColor, bufferWidth, bufferHeight, glyphData, baseline, line, maxStrikethroughThickness, lineExtentLeft, lineExtentRight, strikethroughStartingYPosition);
+      DrawStrikethrough(currentStrikethroughColor, bufferWidth, bufferHeight, glyphData, baseline, line, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, strikethroughStartingYPosition);
     }
 
     // Increases the vertical offset with the line's descender.
@@ -1300,27 +1243,30 @@ Devel::PixelBuffer Typesetter::ApplyUnderlineMarkupImageBuffer(Devel::PixelBuffe
 {
   // Underline-tags (this is for Markup case)
   // Get the underline runs.
-  const Length     numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
-  Vector<GlyphRun> underlineRuns;
+  const Length               numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
+  Vector<UnderlinedGlyphRun> underlineRuns;
   underlineRuns.Resize(numberOfUnderlineRuns);
   mModel->GetUnderlineRuns(underlineRuns.Begin(), 0u, numberOfUnderlineRuns);
 
   // Iterate on the consecutive underlined glyph run and connect them into one chunk of underlined characters.
-  Vector<GlyphRun>::ConstIterator itGlyphRun    = underlineRuns.Begin();
-  Vector<GlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
-  GlyphIndex                      startGlyphIndex, endGlyphIndex;
+  Vector<UnderlinedGlyphRun>::ConstIterator itGlyphRun    = underlineRuns.Begin();
+  Vector<UnderlinedGlyphRun>::ConstIterator endItGlyphRun = underlineRuns.End();
+  GlyphIndex                                startGlyphIndex, endGlyphIndex;
 
   //The outer loop to iterate on the separated chunks of underlined glyph runs
   while(itGlyphRun != endItGlyphRun)
   {
-    startGlyphIndex = itGlyphRun->glyphIndex;
+    const UnderlineStyleProperties& firstUnderlineStyleProperties = itGlyphRun->properties;
+
+    startGlyphIndex = itGlyphRun->glyphRun.glyphIndex;
     endGlyphIndex   = startGlyphIndex;
     //The inner loop to make a connected underline for the consecutive characters
     do
     {
-      endGlyphIndex += itGlyphRun->numberOfGlyphs;
+      endGlyphIndex += itGlyphRun->glyphRun.numberOfGlyphs;
       itGlyphRun++;
-    } while(itGlyphRun != endItGlyphRun && itGlyphRun->glyphIndex == endGlyphIndex);
+    } while(itGlyphRun != endItGlyphRun && itGlyphRun->glyphRun.glyphIndex == endGlyphIndex &&
+            (firstUnderlineStyleProperties == itGlyphRun->properties));
 
     endGlyphIndex--;
 
index 5e014df..47aed00 100644 (file)
@@ -23,8 +23,8 @@
 #include <memory.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/line-run.h>
 #include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/line-run.h>
 
 namespace Dali
 {
@@ -270,7 +270,7 @@ 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);
 }
index c3ee530..ef8ba87 100644 (file)
@@ -233,7 +233,7 @@ public:
   /**
    * @copydoc ModelInterface::GetUnderlineRuns()
    */
-  void GetUnderlineRuns(GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
+  void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
 
   /**
    * @copydoc ModelInterface::GetOutlineColor()
index 2d1e28d..e6ec978 100644 (file)
@@ -374,9 +374,9 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
         case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
         {
           // Add the underline for the pre-edit text.
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
+          UnderlinedGlyphRun underlineRun;
+          underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
 
           //Mark-up processor case
@@ -451,9 +451,9 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
           backgroundColorRun.color                           = BACKGROUND_SUB4;
           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
 
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
+          UnderlinedGlyphRun underlineRun;
+          underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
 
           //Mark-up processor case
@@ -472,9 +472,9 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
           backgroundColorRun.color                           = BACKGROUND_SUB5;
           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
 
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
+          UnderlinedGlyphRun underlineRun;
+          underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
 
           //Mark-up processor case
@@ -493,9 +493,9 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
           backgroundColorRun.color                           = BACKGROUND_SUB6;
           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
 
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
+          UnderlinedGlyphRun underlineRun;
+          underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
 
           //Mark-up processor case
@@ -514,9 +514,9 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
           backgroundColorRun.color                           = BACKGROUND_SUB7;
           impl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack(backgroundColorRun);
 
-          GlyphRun underlineRun;
-          underlineRun.glyphIndex     = attrData.startIndex + numberOfCommit;
-          underlineRun.numberOfGlyphs = numberOfIndices;
+          UnderlinedGlyphRun underlineRun;
+          underlineRun.glyphRun.glyphIndex     = attrData.startIndex + numberOfCommit;
+          underlineRun.glyphRun.numberOfGlyphs = numberOfIndices;
           impl.mModel->mVisualModel->mUnderlineRuns.PushBack(underlineRun);
 
           //Mark-up processor case
index db6fde1..294b534 100644 (file)
@@ -39,6 +39,7 @@
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
 #include <dali-toolkit/internal/text/text-run-container.h>
 #include <dali-toolkit/internal/text/text-selection-handle-controller.h>
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
 
 using namespace Dali;
 
@@ -1620,9 +1621,22 @@ void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearP
     Length         numberOfCharacters = it->characterRun.numberOfCharacters;
     for(Length index = 0u; index < numberOfCharacters; index++)
     {
-      GlyphRun underlineGlyphRun;
-      underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
-      underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+      UnderlinedGlyphRun underlineGlyphRun;
+      underlineGlyphRun.glyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
+      underlineGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+
+      //Copy properties (attributes)
+      underlineGlyphRun.properties.type             = it->properties.type;
+      underlineGlyphRun.properties.color            = it->properties.color;
+      underlineGlyphRun.properties.height           = it->properties.height;
+      underlineGlyphRun.properties.dashGap          = it->properties.dashGap;
+      underlineGlyphRun.properties.dashWidth        = it->properties.dashWidth;
+      underlineGlyphRun.properties.typeDefined      = it->properties.typeDefined;
+      underlineGlyphRun.properties.colorDefined     = it->properties.colorDefined;
+      underlineGlyphRun.properties.heightDefined    = it->properties.heightDefined;
+      underlineGlyphRun.properties.dashGapDefined   = it->properties.dashGapDefined;
+      underlineGlyphRun.properties.dashWidthDefined = it->properties.dashWidthDefined;
+
       mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
     }
   }
@@ -1639,8 +1653,14 @@ void Controller::Impl::CopyStrikethroughFromLogicalToVisualModels()
 
   for(Vector<StrikethroughCharacterRun>::ConstIterator it = strikethroughCharacterRuns.Begin(), endIt = strikethroughCharacterRuns.End(); it != endIt; ++it)
   {
-    CharacterIndex        characterIndex     = it->characterRun.characterIndex;
-    Length                numberOfCharacters = it->characterRun.numberOfCharacters;
+    CharacterIndex characterIndex     = it->characterRun.characterIndex;
+    Length         numberOfCharacters = it->characterRun.numberOfCharacters;
+
+    if(numberOfCharacters == 0)
+    {
+      continue;
+    }
+
     StrikethroughGlyphRun strikethroughGlyphRun;
     strikethroughGlyphRun.color                   = it->color;
     strikethroughGlyphRun.isColorSet              = it->isColorSet;
@@ -1836,6 +1856,7 @@ void Controller::Impl::ClearStyleData()
 {
   mModel->mLogicalModel->mColorRuns.Clear();
   mModel->mLogicalModel->ClearFontDescriptionRuns();
+  mModel->mLogicalModel->ClearStrikethroughRuns();
 }
 
 void Controller::Impl::ResetScrollPosition()
index 8d552d4..90c570a 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.
@@ -22,7 +22,6 @@
 #include <dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
 #include <dali-toolkit/internal/text/property-string-parser.h>
-#include <dali-toolkit/public-api/text/text-enumerations.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
 
 namespace Dali
@@ -355,8 +354,8 @@ bool SetUnderlineProperties(ControllerPtr controller, const Property::Value& val
       {
         const Property::Map& propertiesMap = value.Get<Property::Map>();
 
-        bool                  enabled       = false;
-        bool                  colorDefined  = false;
+        bool                  enabled      = false;
+        bool                  colorDefined = false;
         Vector4               color;
         bool                  heightDefined = false;
         float                 height        = 0.f;
@@ -976,11 +975,11 @@ bool SetStrikethroughProperties(ControllerPtr controller, const Property::Value&
             Text::ParsePropertyString(propertyString, parsedStringMap);
 
             empty = ParseStrikethroughProperties(parsedStringMap,
-                                             enabled,
-                                             colorDefined,
-                                             color,
-                                             heightDefined,
-                                             height);
+                                                 enabled,
+                                                 colorDefined,
+                                                 color,
+                                                 heightDefined,
+                                                 height);
 
             controller->StrikethroughSetByString(!empty);
           }
@@ -1057,7 +1056,7 @@ void GetStrikethroughProperties(ControllerPtr controller, Property::Value& value
         if(controller->IsStrikethroughSetByString())
         {
           std::string       strikethroughProperties = "{\"enable\":";
-          const std::string enabledStr          = enabled ? "true" : "false";
+          const std::string enabledStr              = enabled ? "true" : "false";
           strikethroughProperties += "\"" + enabledStr + "\",";
 
           std::string colorStr;
@@ -1092,6 +1091,17 @@ void GetStrikethroughProperties(ControllerPtr controller, Property::Value& value
   }
 }
 
+Underline::Type StringToUnderlineType(const char* const underlineTypeStr)
+{
+  Underline::Type underlineType = Text::Underline::SOLID;
+  Scripting::GetEnumeration<Underline::Type>(underlineTypeStr,
+                                             UNDERLINE_TYPE_STRING_TABLE,
+                                             UNDERLINE_TYPE_STRING_TABLE_COUNT,
+                                             underlineType);
+
+  return underlineType;
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index a1b7bea..d87e810 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_EFFECTS_STYLE_H
 
 /*
- * 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.
@@ -20,6 +20,8 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+#include <dali/devel-api/scripting/scripting.h>
 
 namespace Dali
 {
@@ -27,6 +29,12 @@ namespace Toolkit
 {
 namespace Text
 {
+const Scripting::StringEnum UNDERLINE_TYPE_STRING_TABLE[] =
+  {
+    {"solid", Text::Underline::SOLID},
+    {"dashed", Text::Underline::DASHED},
+    {"double", Text::Underline::DOUBLE}};
+const unsigned int UNDERLINE_TYPE_STRING_TABLE_COUNT = sizeof(UNDERLINE_TYPE_STRING_TABLE) / sizeof(UNDERLINE_TYPE_STRING_TABLE[0]);
 namespace EffectStyle
 {
 enum Type
@@ -116,11 +124,11 @@ bool ParseBackgroundProperties(const Property::Map& backgroundProperties,
  * @param[out] height The strikethrough's height.
  */
 bool ParseStrikethroughProperties(const Property::Map& strikethroughProperties,
-                              bool&                enabled,
-                              bool&                colorDefined,
-                              Vector4&             color,
-                              bool&                heightDefined,
-                              float&               height);
+                                  bool&                enabled,
+                                  bool&                colorDefined,
+                                  Vector4&             color,
+                                  bool&                heightDefined,
+                                  float&               height);
 
 /**
  * @brief Sets the underline properties.
@@ -242,6 +250,15 @@ bool SetBackgroundProperties(ControllerPtr controller, const Property::Value& va
  */
 void GetBackgroundProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type);
 
+/**
+ * @brief Converts a underline type string into @e Underline::Type
+ *
+ * @param[in] underlineTypeStr The underline type string. Must end with '\0'.
+ *
+ * @return The @e Underline::Type value corresponding to the string.
+ */
+Underline::Type StringToUnderlineType(const char* const underlineTypeStr);
+
 } // namespace Text
 
 } // namespace Toolkit
index 7d51b16..f9d993a 100644 (file)
@@ -27,6 +27,7 @@
 #include <dali-toolkit/internal/text/script-run.h>
 #include <dali-toolkit/internal/text/strikethrough-glyph-run.h>
 #include <dali-toolkit/internal/text/text-definitions.h>
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 
 namespace Dali
@@ -300,7 +301,7 @@ public:
    * @param[in] index Index of the first underline run to be copied.
    * @param[in] numberOfRuns Number of underline runs to be copied.
    */
-  virtual void GetUnderlineRuns(GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const = 0;
+  virtual void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const = 0;
 
   /**
    * @brief Retrieve the outline color.
index e19618e..7ce74ca 100644 (file)
@@ -212,7 +212,7 @@ Length Model::GetNumberOfUnderlineRuns() const
   return mVisualModel->GetNumberOfUnderlineRuns();
 }
 
-void Model::GetUnderlineRuns(GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const
+void Model::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const
 {
   mVisualModel->GetUnderlineRuns(underlineRuns, index, numberOfRuns);
 }
index 4f7b9e3..7077c85 100644 (file)
@@ -230,7 +230,7 @@ public:
   /**
    * @copydoc ModelInterface::GetUnderlineRuns()
    */
-  void GetUnderlineRuns(GlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
+  void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns, UnderlineRunIndex index, Length numberOfRuns) const override;
 
   /**
    * @copydoc ModelInterface::GetOutlineColor()
index da6b4e1..2dda239 100644 (file)
@@ -24,6 +24,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
 #include <dali-toolkit/internal/text/text-definitions.h>
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 
 namespace Dali
@@ -233,9 +234,9 @@ public:
    * @param[in] index Index of the first underline run to be copied.
    * @param[in] numberOfRuns Number of underline runs to be copied.
    */
-  virtual void GetUnderlineRuns(GlyphRun*         underlineRuns,
-                                UnderlineRunIndex index,
-                                Length            numberOfRuns) const = 0;
+  virtual void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
+                                UnderlineRunIndex   index,
+                                Length              numberOfRuns) const = 0;
 
   /**
    * @brief Retrieve the outline color.
index b4644e7..137ded2 100644 (file)
@@ -680,9 +680,9 @@ Length View::GetNumberOfUnderlineRuns() const
   return 0u;
 }
 
-void View::GetUnderlineRuns(GlyphRun*         underlineRuns,
-                            UnderlineRunIndex index,
-                            Length            numberOfRuns) const
+void View::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
+                            UnderlineRunIndex   index,
+                            Length              numberOfRuns) const
 {
   if(mImpl->mVisualModel)
   {
index f673e0e..8eeb882 100644 (file)
@@ -176,9 +176,9 @@ public:
   /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineRuns()
    */
-  virtual void GetUnderlineRuns(GlyphRun*         underlineRuns,
-                                UnderlineRunIndex index,
-                                Length            numberOfRuns) const;
+  virtual void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
+                                UnderlineRunIndex   index,
+                                Length              numberOfRuns) const;
 
   /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineColor()
diff --git a/dali-toolkit/internal/text/underline-style-properties.h b/dali-toolkit/internal/text/underline-style-properties.h
new file mode 100644 (file)
index 0000000..14016c4
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_TOOLKIT_TEXT_UNDERLINE_STYLE_PROPERTIES_H
+#define DALI_TOOLKIT_TEXT_UNDERLINE_STYLE_PROPERTIES_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+
+#include <dali-toolkit/public-api/text/text-enumerations.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Properties of underline style.
+ */
+struct UnderlineStyleProperties
+{
+  // Constructors
+
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  UnderlineStyleProperties()
+  : type{Text::Underline::SOLID},
+    color{Color::BLACK},
+    height{0u},
+    dashGap{1u},
+    dashWidth{2u},
+    typeDefined{false},
+    colorDefined{false},
+    heightDefined{false},
+    dashGapDefined{false},
+    dashWidthDefined{false}
+  {
+  }
+
+  UnderlineStyleProperties(Text::Underline::Type type,
+                           Vector4               color,
+                           float                 height,
+                           float                 dashGap,
+                           float                 dashWidth,
+                           bool                  typeDefined,
+                           bool                  colorDefined,
+                           bool                  heightDefined,
+                           bool                  dashGapDefined,
+                           bool                  dashWidthDefined)
+  : type{type},
+    color{color},
+    height{height},
+    dashGap{dashGap},
+    dashWidth{dashWidth},
+    typeDefined{typeDefined},
+    colorDefined{colorDefined},
+    heightDefined{heightDefined},
+    dashGapDefined{dashGapDefined},
+    dashWidthDefined{dashWidthDefined}
+  {
+  }
+
+  // Overloading operators
+
+  bool operator==(const UnderlineStyleProperties& other) const
+  {
+    //The property is similar when both are not defined or when both are defined and have the same value.
+    return ((!typeDefined && !other.typeDefined) || ((typeDefined && other.typeDefined) && (type == other.type))) &&
+           ((!colorDefined && !other.colorDefined) || ((colorDefined && other.colorDefined) && (color == other.color))) &&
+           ((!heightDefined && !other.heightDefined) || ((heightDefined && other.heightDefined) && (height == other.height))) &&
+           ((!dashGapDefined && !other.dashGapDefined) || ((dashGapDefined && other.dashGapDefined) && (dashGap == other.dashGap))) &&
+           ((!dashWidthDefined && !other.dashWidthDefined) || ((dashWidthDefined && other.dashWidthDefined) && (dashWidth == other.dashWidth)));
+  }
+
+  bool operator!=(const UnderlineStyleProperties& other) const
+  {
+    return !(*this == other);
+  }
+
+  bool IsHeightEqualTo(const UnderlineStyleProperties& other) const
+  {
+    return ((!heightDefined && !other.heightDefined) || ((heightDefined && other.heightDefined) && (height == other.height)));
+  }
+
+  //Attributes
+  Text::Underline::Type type;      ///< The type of underline.
+  Vector4               color;     ///< The color of underline.
+  float                 height;    ///< The height of underline.
+  float                 dashGap;   ///< The dash-gap of underline.
+  float                 dashWidth; ///< The height of underline.
+
+  bool typeDefined : 1;      ///< Whether the type is defined.
+  bool colorDefined : 1;     ///< Whether the color is defined.
+  bool heightDefined : 1;    ///< Whether the height is defined.
+  bool dashGapDefined : 1;   ///< Whether the dash-gap is defined.
+  bool dashWidthDefined : 1; ///< Whether the dash-width is defined.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UNDERLINE_STYLE_PROPERTIES_H
index 99d5967..4024dff 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_UNDERLINED_CHARACTER_RUN_H
 
 /*
- * 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,7 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/character-run.h>
-#include <dali-toolkit/internal/text/glyph-run.h>
+#include <dali-toolkit/internal/text/underline-style-properties.h>
 
 namespace Dali
 {
@@ -36,10 +36,17 @@ namespace Text
  */
 struct UnderlinedCharacterRun
 {
-  CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
-  //TODO: add properties like color, height and style
-  //Vector4      color;       ///< The color of underline.
-  //float        height;      ///< The height of underline.
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  UnderlinedCharacterRun()
+  : characterRun{},
+    properties{}
+  {
+  }
+
+  CharacterRun             characterRun; ///< The initial character index and the number of characters of the run.
+  UnderlineStyleProperties properties;   /// The properties of underline style
 };
 
 } // namespace Text
diff --git a/dali-toolkit/internal/text/underlined-glyph-run.h b/dali-toolkit/internal/text/underlined-glyph-run.h
new file mode 100644 (file)
index 0000000..4c5ed7a
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef DALI_TOOLKIT_TEXT_UNDERLINED_GLYPH_RUN_H
+#define DALI_TOOLKIT_TEXT_UNDERLINED_GLYPH_RUN_H
+
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/glyph-run.h>
+#include <dali-toolkit/internal/text/underline-style-properties.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Run of underlined glyphs with same properties.
+ */
+struct UnderlinedGlyphRun
+{
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  UnderlinedGlyphRun()
+  : glyphRun{},
+    properties{}
+  {
+  }
+
+  GlyphRun                 glyphRun;   ///< The initial glyph index and the number of glyphs in the run.
+  UnderlineStyleProperties properties; /// The properties of underline style
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_UNDERLINED_GLYPH_RUN_H
index 3fa3975..ce0fb7c 100644 (file)
@@ -305,13 +305,13 @@ LineIndex VisualModel::GetLineOfCharacter(CharacterIndex characterIndex)
   return index;
 }
 
-void VisualModel::GetUnderlineRuns(GlyphRun*         underlineRuns,
-                                   UnderlineRunIndex index,
-                                   Length            numberOfRuns) const
+void VisualModel::GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
+                                   UnderlineRunIndex   index,
+                                   Length              numberOfRuns) const
 {
   memcpy(underlineRuns,
          mUnderlineRuns.Begin() + index,
-         numberOfRuns * sizeof(GlyphRun));
+         numberOfRuns * sizeof(UnderlinedGlyphRun));
 }
 
 void VisualModel::SetNaturalSize(const Vector2& size)
index ebddb35..4bae17c 100644 (file)
@@ -29,6 +29,7 @@
 #include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/line-run.h>
 #include <dali-toolkit/internal/text/strikethrough-glyph-run.h>
+#include <dali-toolkit/internal/text/underlined-glyph-run.h>
 #include <dali-toolkit/public-api/text/text-enumerations.h>
 
 // DEVEL INCLUDES
@@ -172,9 +173,9 @@ public:
    * @param[in] index Index of the first underline run to be copied.
    * @param[in] numberOfRuns Number of underline runs to be copied.
    */
-  void GetUnderlineRuns(GlyphRun*         underlineRuns,
-                        UnderlineRunIndex index,
-                        Length            numberOfRuns) const;
+  void GetUnderlineRuns(UnderlinedGlyphRun* underlineRuns,
+                        UnderlineRunIndex   index,
+                        Length              numberOfRuns) const;
 
   // Size interface
 
@@ -621,7 +622,7 @@ public:
   Vector<Length>                mGlyphsPerCharacter;     ///< For each character, the number of glyphs that are shaped.
   Vector<Vector2>               mGlyphPositions;         ///< For each glyph, the position.
   Vector<LineRun>               mLines;                  ///< The laid out lines.
-  Vector<GlyphRun>              mUnderlineRuns;          ///< Runs of glyphs that are underlined.
+  Vector<UnderlinedGlyphRun>    mUnderlineRuns;          ///< Runs of glyphs that are underlined.
   Vector<Vector4>               mColors;                 ///< Colors of the glyphs.
   Vector<ColorIndex>            mColorIndices;           ///< Indices to the vector of colors for each glyphs.
   Vector<Vector4>               mBackgroundColors;       ///< Background colors of the glyphs.
index d574d6c..6a5256d 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 9;
+const unsigned int TOOLKIT_MICRO_VERSION = 10;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 7376644..6360436 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.1.9
+Version:    2.1.10
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT