[dali_2.1.15] Merge branch 'devel/master' 56/272856/1
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 25 Mar 2022 10:57:53 +0000 (10:57 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 25 Mar 2022 10:57:53 +0000 (10:57 +0000)
Change-Id: I5e189a1613ab9a3e3a78fc921aad31796fd361d7

38 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/test-graphics-command-buffer.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-graphics-controller.cpp
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
automated-tests/src/dali-toolkit/utc-Dali-KeyboardFocusManager.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/devel-api/controls/control-devel.h
dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.cpp
dali-toolkit/devel-api/focus-manager/keyboard-focus-manager-devel.h
dali-toolkit/internal/controls/control/control-data-impl.cpp
dali-toolkit/internal/controls/control/control-data-impl.h
dali-toolkit/internal/controls/text-controls/common-text-utils.cpp
dali-toolkit/internal/controls/text-controls/common-text-utils.h
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp
dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.h
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/markup-processor-span.cpp
dali-toolkit/internal/text/markup-processor-span.h
dali-toolkit/internal/text/markup-processor-strikethrough.cpp
dali-toolkit/internal/text/markup-processor-strikethrough.h
dali-toolkit/internal/text/markup-processor.cpp
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.cpp
dali-toolkit/internal/text/rendering/styles/strikethrough-helper-functions.h
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/strikethrough-character-run.h
dali-toolkit/internal/text/strikethrough-glyph-run.h
dali-toolkit/internal/text/strikethrough-style-properties.h [new file with mode: 0644]
dali-toolkit/internal/text/text-controller-background-actor.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/public-api/controls/control.h
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index c75f754..d19326f 100644 (file)
@@ -600,6 +600,244 @@ int UtcDaliTextEditorMarkupNestedUnderlineTags(void)
   END_TEST;
 }
 
+int UtcDaliTextEditorMarkupNestedStrikethroughTags(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupNestedStrikethroughTags ");
+
+  TextEditor textEditor = TextEditor::New();
+
+  application.GetScene().Add(textEditor);
+
+  std::string testText = "start<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>end";
+
+  textEditor.SetProperty(TextEditor::Property::TEXT, testText);
+  textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 2u;
+
+  Toolkit::Internal::TextEditor& textEditorImpl            = GetImpl(textEditor);
+  const Text::Length             numberOfStrikethroughRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textEditorImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //Outter
+      {"<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>",
+       5u,
+       8u,
+       {
+         Color::GREEN,
+         5.0f,
+         true,
+         true,
+       }},
+
+      //Inner
+      {"<s color='blue' >XYZ</s>",
+       7u,
+       3u,
+       {
+         Color::BLUE,
+         5.0f,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorMarkupStrikethroughAttributes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupStrikethroughAttributes ");
+
+  TextEditor textEditor = TextEditor::New();
+
+  application.GetScene().Add(textEditor);
+
+  std::string testText =
+    "start<s>ABC1</s>then"
+    "<s color='green'>ABC2</s>then"
+    "<s height='5.0f'>ABC3</s>then"
+    "<s color='blue' height='4.0f' >ABC4</s>end";
+
+  textEditor.SetProperty(TextEditor::Property::TEXT, testText);
+  textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 4u;
+
+  Toolkit::Internal::TextEditor& textEditorImpl            = GetImpl(textEditor);
+  const Text::Length             numberOfStrikethroughRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textEditorImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+
+      {"<s>ABC1</s>",
+       5u,
+       4u,
+       {Color::BLACK,
+        0.0f,
+        false,
+        false}},
+
+      {"<s color='green'>ABC2</s>",
+       13u,
+       4u,
+       {Color::GREEN,
+        0.0f,
+        true,
+        false}},
+
+      {"<s height='5.0f'>ABC3</s>",
+       21u,
+       4u,
+       {Color::BLACK,
+        5.0f,
+        false,
+        true}},
+
+      {"<s color='blue' height='4.0f' >ABC4</s>",
+       29u,
+       4u,
+       {Color::BLUE,
+        4.0f,
+        true,
+        true}},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTextEditorMarkupSpanStrikethrough(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextEditorMarkupSpanStrikethrough ");
+
+  TextEditor textEditor = TextEditor::New();
+
+  application.GetScene().Add(textEditor);
+
+  std::string testText =
+    "start<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red'>ABC1</span>then"
+    "<span s-color='blue'>ABC2</span>then"
+    "<span s-height='2.0f'>ABC3</span>then"
+    "<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red' s-color='green' s-height='5.0f'>ABC4</span>end";
+
+  textEditor.SetProperty(TextEditor::Property::TEXT, testText);
+  textEditor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 3u;
+
+  Toolkit::Internal::TextEditor& textEditorImpl            = GetImpl(textEditor);
+  const Text::Length             numberOfStrikethroughRuns = textEditorImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textEditorImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+
+      {"<span s-color='blue'>ABC2</span>then",
+       13u,
+       4u,
+       {Color::BLUE,
+        0.0f,
+        true,
+        false}},
+
+      {"<span s-height='2.0f'>ABC3</span>then",
+       21u,
+       4u,
+       {Color::BLACK,
+        2.0f,
+        false,
+        true}},
+
+      {"<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red' s-color='green' s-height='5.0f'>ABC4</span>",
+       29u,
+       4u,
+       {Color::GREEN,
+        5.0f,
+        true,
+        true}},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliTextEditorFontPointSizeLargerThanAtlas(void)
 {
   ToolkitTestApplication application;
@@ -689,6 +927,37 @@ int UtcDaliTextEditorBackgroundTag(void)
   END_TEST;
 }
 
+int UtcDaliTextEditorSpanBackgroundTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorSpanBackgroundTag\n");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK(editor);
+
+  editor.SetProperty(TextEditor ::Property::ENABLE_MARKUP, true);
+  editor.SetProperty(TextEditor::Property::TEXT, "H<span background-color='red'>e</span> Worl<span background-color='yellow'>d</span>");
+  application.GetScene().Add(editor);
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextEditor& editorImpl                   = GetImpl(editor);
+  const ColorIndex* const        backgroundColorIndicesBuffer = editorImpl.GetTextController()->GetTextModel()->GetBackgroundColorIndices();
+
+  DALI_TEST_CHECK(backgroundColorIndicesBuffer);
+
+  //default color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[0], 0u, TEST_LOCATION);
+
+  //red color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[1], 1u, TEST_LOCATION);
+
+  //yellow color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[7], 2u, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliTextEditorTextWithSpan(void)
 {
   ToolkitTestApplication application;
@@ -857,12 +1126,12 @@ int UtcDaliTextEditorMarkupStrikethrough(void)
   //ABC have strikethrough
   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION);
-  DALI_TEST_CHECK(!strikethroughRuns[0u].isColorSet);
+  DALI_TEST_CHECK(!strikethroughRuns[0u].properties.colorDefined);
 
   //GH have strikethrough
   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.numberOfGlyphs, 2u, TEST_LOCATION);
-  DALI_TEST_CHECK(strikethroughRuns[1u].isColorSet);
+  DALI_TEST_CHECK(strikethroughRuns[1u].properties.colorDefined);
 
   END_TEST;
 }
index b73142a..02aa540 100644 (file)
@@ -684,6 +684,244 @@ int UtcDaliTextFieldMarkupNestedUnderlineTags(void)
   END_TEST;
 }
 
+int UtcDaliTextFieldMarkupNestedStrikethroughTags(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupNestedStrikethroughTags ");
+
+  TextField textField = TextField::New();
+
+  application.GetScene().Add(textField);
+
+  std::string testText = "start<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>end";
+
+  textField.SetProperty(TextField::Property::TEXT, testText);
+  textField.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 2u;
+
+  Toolkit::Internal::TextField& textFieldImpl             = GetImpl(textField);
+  const Text::Length            numberOfStrikethroughRuns = textFieldImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textFieldImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //Outter
+      {"<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>",
+       5u,
+       8u,
+       {
+         Color::GREEN,
+         5.0f,
+         true,
+         true,
+       }},
+
+      //Inner
+      {"<s color='blue' >XYZ</s>",
+       7u,
+       3u,
+       {
+         Color::BLUE,
+         5.0f,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldMarkupStrikethroughAttributes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupStrikethroughAttributes ");
+
+  TextField textField = TextField::New();
+
+  application.GetScene().Add(textField);
+
+  std::string testText =
+    "start<s>ABC1</s>then"
+    "<s color='green'>ABC2</s>then"
+    "<s height='5.0f'>ABC3</s>then"
+    "<s color='blue' height='4.0f' >ABC4</s>end";
+
+  textField.SetProperty(TextField::Property::TEXT, testText);
+  textField.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 4u;
+
+  Toolkit::Internal::TextField& textFieldImpl             = GetImpl(textField);
+  const Text::Length            numberOfStrikethroughRuns = textFieldImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textFieldImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+
+      {"<s>ABC1</s>",
+       5u,
+       4u,
+       {Color::BLACK,
+        0.0f,
+        false,
+        false}},
+
+      {"<s color='green'>ABC2</s>",
+       13u,
+       4u,
+       {Color::GREEN,
+        0.0f,
+        true,
+        false}},
+
+      {"<s height='5.0f'>ABC3</s>",
+       21u,
+       4u,
+       {Color::BLACK,
+        5.0f,
+        false,
+        true}},
+
+      {"<s color='blue' height='4.0f' >ABC4</s>",
+       29u,
+       4u,
+       {Color::BLUE,
+        4.0f,
+        true,
+        true}},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTextFieldMarkupSpanStrikethrough(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextFieldMarkupSpanStrikethrough ");
+
+  TextField textField = TextField::New();
+
+  application.GetScene().Add(textField);
+
+  std::string testText =
+    "start<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red'>ABC1</span>then"
+    "<span s-color='blue'>ABC2</span>then"
+    "<span s-height='2.0f'>ABC3</span>then"
+    "<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red' s-color='green' s-height='5.0f'>ABC4</span>end";
+
+  textField.SetProperty(TextField::Property::TEXT, testText);
+  textField.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 3u;
+
+  Toolkit::Internal::TextField& textFieldImpl             = GetImpl(textField);
+  const Text::Length            numberOfStrikethroughRuns = textFieldImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textFieldImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+
+      {"<span s-color='blue'>ABC2</span>then",
+       13u,
+       4u,
+       {Color::BLUE,
+        0.0f,
+        true,
+        false}},
+
+      {"<span s-height='2.0f'>ABC3</span>then",
+       21u,
+       4u,
+       {Color::BLACK,
+        2.0f,
+        false,
+        true}},
+
+      {"<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red' s-color='green' s-height='5.0f'>ABC4</span>",
+       29u,
+       4u,
+       {Color::GREEN,
+        5.0f,
+        true,
+        true}},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliTextFieldFontPointSizeLargerThanAtlas(void)
 {
   ToolkitTestApplication application;
@@ -773,6 +1011,37 @@ int UtcDaliTextFieldBackgroundTag(void)
   END_TEST;
 }
 
+int UtcDaliTextFieldSpanBackgroundTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldSpanBackgroundTag\n");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK(field);
+
+  field.SetProperty(TextField ::Property::ENABLE_MARKUP, true);
+  field.SetProperty(TextField::Property::TEXT, "H<span background-color='red'>e</span> Worl<span background-color='yellow'>d</span>");
+  application.GetScene().Add(field);
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextField& fieldImpl                    = GetImpl(field);
+  const ColorIndex* const       backgroundColorIndicesBuffer = fieldImpl.GetTextController()->GetTextModel()->GetBackgroundColorIndices();
+
+  DALI_TEST_CHECK(backgroundColorIndicesBuffer);
+
+  //default color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[0], 0u, TEST_LOCATION);
+
+  //red color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[1], 1u, TEST_LOCATION);
+
+  //yellow color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[7], 2u, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliToolkitTextFieldEllipsisInternalAPIs(void)
 {
   ToolkitTestApplication application;
@@ -933,12 +1202,12 @@ int UtcDaliTextFieldMarkupStrikethrough(void)
   //ABC have strikethrough
   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION);
-  DALI_TEST_CHECK(!strikethroughRuns[0u].isColorSet);
+  DALI_TEST_CHECK(!strikethroughRuns[0u].properties.colorDefined);
 
   //GH have strikethrough
   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.numberOfGlyphs, 2u, TEST_LOCATION);
-  DALI_TEST_CHECK(strikethroughRuns[1u].isColorSet);
+  DALI_TEST_CHECK(strikethroughRuns[1u].properties.colorDefined);
 
   END_TEST;
 }
index dd460f2..1ac00b5 100644 (file)
@@ -561,6 +561,244 @@ int UtcDaliTextLabelMarkupNestedUnderlineTags(void)
   END_TEST;
 }
 
+int UtcDaliTextLabelMarkupNestedStrikethroughTags(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupNestedStrikethroughTags ");
+
+  TextLabel textLabel = TextLabel::New();
+
+  application.GetScene().Add(textLabel);
+
+  std::string testText = "start<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>end";
+
+  textLabel.SetProperty(TextLabel::Property::TEXT, testText);
+  textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 2u;
+
+  Toolkit::Internal::TextLabel& textLabelImpl             = GetImpl(textLabel);
+  const Text::Length            numberOfStrikethroughRuns = textLabelImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textLabelImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+      //Outter
+      {"<s height='5.0f' color='green' >AB<s color='blue' >XYZ</s>CDE</s>",
+       5u,
+       8u,
+       {
+         Color::GREEN,
+         5.0f,
+         true,
+         true,
+       }},
+
+      //Inner
+      {"<s color='blue' >XYZ</s>",
+       7u,
+       3u,
+       {
+         Color::BLUE,
+         5.0f,
+         true,
+         true,
+       }},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTextLabelMarkupStrikethroughAttributes(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupStrikethroughAttributes ");
+
+  TextLabel textLabel = TextLabel::New();
+
+  application.GetScene().Add(textLabel);
+
+  std::string testText =
+    "start<s>ABC1</s>then"
+    "<s color='green'>ABC2</s>then"
+    "<s height='5.0f'>ABC3</s>then"
+    "<s color='blue' height='4.0f' >ABC4</s>end";
+
+  textLabel.SetProperty(TextLabel::Property::TEXT, testText);
+  textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 4u;
+
+  Toolkit::Internal::TextLabel& textLabelImpl             = GetImpl(textLabel);
+  const Text::Length            numberOfStrikethroughRuns = textLabelImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textLabelImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+
+      {"<s>ABC1</s>",
+       5u,
+       4u,
+       {Color::BLACK,
+        0.0f,
+        false,
+        false}},
+
+      {"<s color='green'>ABC2</s>",
+       13u,
+       4u,
+       {Color::GREEN,
+        0.0f,
+        true,
+        false}},
+
+      {"<s height='5.0f'>ABC3</s>",
+       21u,
+       4u,
+       {Color::BLACK,
+        5.0f,
+        false,
+        true}},
+
+      {"<s color='blue' height='4.0f' >ABC4</s>",
+       29u,
+       4u,
+       {Color::BLUE,
+        4.0f,
+        true,
+        true}},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTextLabelMarkupSpanStrikethrough(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliTextLabelMarkupSpanStrikethrough ");
+
+  TextLabel textLabel = TextLabel::New();
+
+  application.GetScene().Add(textLabel);
+
+  std::string testText =
+    "start<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red'>ABC1</span>then"
+    "<span s-color='blue'>ABC2</span>then"
+    "<span s-height='2.0f'>ABC3</span>then"
+    "<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red' s-color='green' s-height='5.0f'>ABC4</span>end";
+
+  textLabel.SetProperty(TextLabel::Property::TEXT, testText);
+  textLabel.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+
+  application.SendNotification();
+  application.Render();
+
+  const uint32_t expectedNumberOfStrikethroughRuns = 3u;
+
+  Toolkit::Internal::TextLabel& textLabelImpl             = GetImpl(textLabel);
+  const Text::Length            numberOfStrikethroughRuns = textLabelImpl.GetTextController()->GetTextModel()->GetNumberOfStrikethroughRuns();
+
+  DALI_TEST_EQUALS(numberOfStrikethroughRuns, expectedNumberOfStrikethroughRuns, TEST_LOCATION);
+
+  Vector<StrikethroughGlyphRun> strikethroughRuns;
+  strikethroughRuns.Resize(numberOfStrikethroughRuns);
+  textLabelImpl.GetTextController()->GetTextModel()->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
+
+  struct DataOfCase
+  {
+    std::string                  title;
+    GlyphIndex                   glyphIndex;
+    Length                       numberOfGlyphs;
+    StrikethroughStyleProperties properties;
+  };
+  DataOfCase data[] =
+    {
+
+      {"<span s-color='blue'>ABC2</span>then",
+       13u,
+       4u,
+       {Color::BLUE,
+        0.0f,
+        true,
+        false}},
+
+      {"<span s-height='2.0f'>ABC3</span>then",
+       21u,
+       4u,
+       {Color::BLACK,
+        2.0f,
+        false,
+        true}},
+
+      {"<span font-size='45' font-family='DejaVu Sans' font-width='condensed' font-slant='italic' text-color='red' s-color='green' s-height='5.0f'>ABC4</span>",
+       29u,
+       4u,
+       {Color::GREEN,
+        5.0f,
+        true,
+        true}},
+
+    };
+
+  for(uint32_t i = 0; i < expectedNumberOfStrikethroughRuns; i++)
+  {
+    tet_infoline(data[i].title.c_str());
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.glyphIndex, data[i].glyphIndex, TEST_LOCATION);
+    DALI_TEST_EQUALS(strikethroughRuns[i].glyphRun.numberOfGlyphs, data[i].numberOfGlyphs, TEST_LOCATION);
+    DALI_TEST_CHECK(data[i].properties == strikethroughRuns[i].properties);
+  }
+
+  END_TEST;
+}
+
 int UtcDaliTextLabelBackgroundTag(void)
 {
   ToolkitTestApplication application;
@@ -592,6 +830,37 @@ int UtcDaliTextLabelBackgroundTag(void)
   END_TEST;
 }
 
+int UtcDaliTextLabelSpanBackgroundTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextLabelSpanBackgroundTag\n");
+
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK(label);
+
+  label.SetProperty(TextLabel ::Property::ENABLE_MARKUP, true);
+  label.SetProperty(TextLabel::Property::TEXT, "H<span background-color='red'>e</span> Worl<span background-color='yellow'>d</span>");
+  application.GetScene().Add(label);
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextLabel& labelImpl                    = GetImpl(label);
+  const ColorIndex* const       backgroundColorIndicesBuffer = labelImpl.GetTextController()->GetTextModel()->GetBackgroundColorIndices();
+
+  DALI_TEST_CHECK(backgroundColorIndicesBuffer);
+
+  //default color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[0], 0u, TEST_LOCATION);
+
+  //red color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[1], 1u, TEST_LOCATION);
+
+  //yellow color
+  DALI_TEST_EQUALS(backgroundColorIndicesBuffer[7], 2u, TEST_LOCATION);
+
+  END_TEST;
+}
+
 int UtcDaliToolkitTextlabelEllipsisInternalAPIs(void)
 {
   ToolkitTestApplication application;
@@ -739,18 +1008,18 @@ int UtcDaliTextLabelMarkupStrikethrough(void)
   //ABC have strikethrough
   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.glyphIndex, 0u, TEST_LOCATION);
   DALI_TEST_EQUALS(strikethroughRuns[0u].glyphRun.numberOfGlyphs, 3u, TEST_LOCATION);
-  DALI_TEST_CHECK(strikethroughRuns[0u].isColorSet);
-  DALI_TEST_EQUALS(strikethroughRuns[0u].color.r, 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(strikethroughRuns[0u].color.g, 0u, TEST_LOCATION);
-  DALI_TEST_EQUALS(strikethroughRuns[0u].color.b, 0u, TEST_LOCATION);
+  DALI_TEST_CHECK(strikethroughRuns[0u].properties.colorDefined);
+  DALI_TEST_EQUALS(strikethroughRuns[0u].properties.color.r, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(strikethroughRuns[0u].properties.color.g, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS(strikethroughRuns[0u].properties.color.b, 0u, TEST_LOCATION);
 
   //GH have strikethrough
   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.glyphIndex, 5u, TEST_LOCATION);
   DALI_TEST_EQUALS(strikethroughRuns[1u].glyphRun.numberOfGlyphs, 2u, TEST_LOCATION);
-  DALI_TEST_CHECK(strikethroughRuns[1u].isColorSet);
-  DALI_TEST_EQUALS(strikethroughRuns[1u].color.r, 0u, TEST_LOCATION);
-  DALI_TEST_EQUALS(strikethroughRuns[1u].color.g, 1u, TEST_LOCATION);
-  DALI_TEST_EQUALS(strikethroughRuns[1u].color.b, 0u, TEST_LOCATION);
+  DALI_TEST_CHECK(strikethroughRuns[1u].properties.colorDefined);
+  DALI_TEST_EQUALS(strikethroughRuns[1u].properties.color.r, 0u, TEST_LOCATION);
+  DALI_TEST_EQUALS(strikethroughRuns[1u].properties.color.g, 1u, TEST_LOCATION);
+  DALI_TEST_EQUALS(strikethroughRuns[1u].properties.color.b, 0u, TEST_LOCATION);
 
   END_TEST;
 }
index 96b0021..407dade 100644 (file)
@@ -65,6 +65,7 @@ enum class CommandType
   SET_DEPTH_COMPARE_OP    = 1 << 24,
   SET_DEPTH_TEST_ENABLE   = 1 << 25,
   SET_DEPTH_WRITE_ENABLE  = 1 << 26,
+  DRAW_NATIVE             = 1 << 27,
 };
 
 std::ostream& operator<<(std::ostream& os, Graphics::StencilOp op);
@@ -123,7 +124,8 @@ struct DrawCallDescriptor
   {
     DRAW,
     DRAW_INDEXED,
-    DRAW_INDEXED_INDIRECT
+    DRAW_INDEXED_INDIRECT,
+    DRAW_NATIVE
   };
 
   Type type{}; ///< Type of the draw call
@@ -166,6 +168,11 @@ struct DrawCallDescriptor
       uint32_t                  drawCount;
       uint32_t                  stride;
     } drawIndexedIndirect;
+
+    struct
+    {
+      Graphics::DrawNativeInfo drawNativeInfo;
+    } drawNative;
   };
 };
 
@@ -265,6 +272,12 @@ struct Command
         data.bindUniformBuffers = rhs.data.bindUniformBuffers;
         break;
       }
+      case CommandType::DRAW_NATIVE:
+      {
+        data.draw.type       = rhs.data.draw.type;
+        data.draw.drawNative = rhs.data.draw.drawNative;
+        break;
+      }
       case CommandType::DRAW:
       {
         data.draw.type = rhs.data.draw.type;
@@ -418,6 +431,12 @@ struct Command
         data.bindPipeline = rhs.data.bindPipeline;
         break;
       }
+      case CommandType::DRAW_NATIVE:
+      {
+        data.draw.type       = rhs.data.draw.type;
+        data.draw.drawNative = rhs.data.draw.drawNative;
+        break;
+      }
       case CommandType::DRAW:
       {
         data.draw.type = rhs.data.draw.type;
@@ -800,6 +819,16 @@ public:
     mCallStack.PushCall("ExecuteCommandBuffers", "");
   }
 
+  void DrawNative(const Graphics::DrawNativeInfo* drawInfo)
+  {
+    mCommands.emplace_back();
+    mCommands.back().type         = CommandType::DRAW_NATIVE;
+    auto& cmd                     = mCommands.back().data.draw;
+    cmd.type                      = DrawCallDescriptor::Type::DRAW_NATIVE;
+    cmd.drawNative.drawNativeInfo = *drawInfo;
+    mCallStack.PushCall("DrawNative", "");
+  }
+
   void Draw(
     uint32_t vertexCount,
     uint32_t instanceCount,
index bedce18..6a8eab4 100644 (file)
@@ -693,6 +693,12 @@ void TestGraphicsController::ProcessCommandBuffer(TestGraphicsCommandBuffer& com
         BindPipeline(currentPipeline);
         break;
       }
+      case CommandType::DRAW_NATIVE:
+      {
+        auto info = &cmd.data.draw.drawNative.drawNativeInfo;
+        CallbackBase::ExecuteReturn<bool>(*info->callback, info->userData);
+        break;
+      }
       case CommandType::DRAW:
       {
         if(currentPipeline)
index 9f02d5f..6745fea 100644 (file)
@@ -269,6 +269,8 @@ int UtcDaliControlNavigationProperties(void)
   DALI_TEST_EQUALS(-1, control.GetProperty(DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID).Get<int>(), TEST_LOCATION);
   DALI_TEST_EQUALS(-1, control.GetProperty(DevelControl::Property::UP_FOCUSABLE_ACTOR_ID).Get<int>(), TEST_LOCATION);
   DALI_TEST_EQUALS(-1, control.GetProperty(DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID).Get<int>(), TEST_LOCATION);
+  DALI_TEST_EQUALS(-1, control.GetProperty( DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION);
+  DALI_TEST_EQUALS(-1, control.GetProperty( DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION);
 
   control.SetProperty(DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, 1);
   DALI_TEST_EQUALS(1, control.GetProperty(DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID).Get<int>(), TEST_LOCATION);
@@ -287,6 +289,10 @@ int UtcDaliControlNavigationProperties(void)
   DALI_TEST_EQUALS(17, control.GetProperty(DevelControl::Property::UP_FOCUSABLE_ACTOR_ID).Get<int>(), TEST_LOCATION);
   control.SetProperty(DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, 18);
   DALI_TEST_EQUALS(18, control.GetProperty(DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID).Get<int>(), TEST_LOCATION);
+  control.SetProperty(DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID, 19);
+  DALI_TEST_EQUALS(19, control.GetProperty( DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION);
+  control.SetProperty(DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID, 20);
+  DALI_TEST_EQUALS(20, control.GetProperty( DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID ).Get< int >(), TEST_LOCATION);
 
   END_TEST;
 }
index 785b509..7b08e1a 100644 (file)
@@ -55,11 +55,12 @@ public:
   : mInterfaceVerified(interfaceVerified),
     mCurrentFocusedActor(),
     mProposedActorToFocus(),
-    mDirection(Control::KeyboardFocus::LEFT)
+    mDirection(Control::KeyboardFocus::LEFT),
+    mDeviceName("")
   {
   }
 
-  Actor GetNextFocusableActor(Actor currentFocusedActor, Actor proposedActorToFocus, Control::KeyboardFocus::Direction direction)
+  Actor GetNextFocusableActor(Actor currentFocusedActor, Actor proposedActorToFocus, Control::KeyboardFocus::Direction direction, const std::string& deviceName)
   {
     tet_infoline("Verifying CustomAlgorithm()");
 
@@ -68,6 +69,7 @@ public:
     mCurrentFocusedActor  = currentFocusedActor;
     mProposedActorToFocus = proposedActorToFocus;
     mDirection            = direction;
+    mDeviceName           = deviceName;
 
     return mProposedActorToFocus;
   }
@@ -78,12 +80,14 @@ public:
     mCurrentFocusedActor  = Actor();
     mProposedActorToFocus = Actor();
     mDirection            = Control::KeyboardFocus::LEFT;
+    mDeviceName           = "";
   }
 
   bool&                             mInterfaceVerified;
   Actor                             mCurrentFocusedActor;
   Actor                             mProposedActorToFocus;
   Control::KeyboardFocus::Direction mDirection;
+  std::string mDeviceName;
 };
 
 // Functors to test whether PreFocusChange signal is emitted when the keyboard focus is about to change
@@ -578,17 +582,19 @@ int UtcDaliKeyboardFocusManagerCustomAlgorithmMoveFocus(void)
   preFocusChangeCallback.Reset();
 
   bool            customAlgorithmInterfaceVerified = false;
+  std::string     deviceName                       = "deviceName";
   CustomAlgorithm customAlgorithm(customAlgorithmInterfaceVerified);
   Toolkit::DevelKeyboardFocusManager::SetCustomAlgorithm(manager, customAlgorithm);
 
   // Move the focus towards right
-  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+  DALI_TEST_CHECK(Toolkit::DevelKeyboardFocusManager::MoveFocus(manager, Control::KeyboardFocus::RIGHT, deviceName) == false);
 
   // Because no layout control in the stage and the first actor is focused, it should invoke CustomAlgorithm
   DALI_TEST_CHECK(customAlgorithm.mInterfaceVerified);
   DALI_TEST_CHECK(customAlgorithm.mCurrentFocusedActor == Actor());
   DALI_TEST_CHECK(customAlgorithm.mProposedActorToFocus == Actor());
   DALI_TEST_CHECK(customAlgorithm.mDirection == Control::KeyboardFocus::RIGHT);
+  DALI_TEST_EQUALS(customAlgorithm.mDeviceName, deviceName, TEST_LOCATION );
   customAlgorithm.Reset();
 
   // Check that the focus is set on the first actor
@@ -600,13 +606,14 @@ int UtcDaliKeyboardFocusManagerCustomAlgorithmMoveFocus(void)
   focusChangedCallback.Reset();
 
   // Move the focus towards right
-  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::RIGHT) == false);
+  DALI_TEST_CHECK(Toolkit::DevelKeyboardFocusManager::MoveFocus(manager, Control::KeyboardFocus::RIGHT, deviceName) == false);
 
   // Because no layout control in the stage and the first actor is focused, it should invoke CustomAlgorithm
   DALI_TEST_CHECK(customAlgorithm.mInterfaceVerified);
   DALI_TEST_CHECK(customAlgorithm.mCurrentFocusedActor == first);
   DALI_TEST_CHECK(customAlgorithm.mProposedActorToFocus == Actor());
   DALI_TEST_CHECK(customAlgorithm.mDirection == Control::KeyboardFocus::RIGHT);
+  DALI_TEST_EQUALS(customAlgorithm.mDeviceName, deviceName, TEST_LOCATION );
   customAlgorithm.Reset();
 
   // Check that the focus is set on the second actor
@@ -618,13 +625,14 @@ int UtcDaliKeyboardFocusManagerCustomAlgorithmMoveFocus(void)
   focusChangedCallback.Reset();
 
   // Move the focus towards up
-  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::UP) == false);
+  DALI_TEST_CHECK(Toolkit::DevelKeyboardFocusManager::MoveFocus(manager, Control::KeyboardFocus::UP, deviceName) == false);
 
   // Because no layout control in the stage and no actor is focused, it should invoke CustomAlgorithm
   DALI_TEST_CHECK(customAlgorithm.mInterfaceVerified);
   DALI_TEST_CHECK(customAlgorithm.mCurrentFocusedActor == second);
   DALI_TEST_CHECK(customAlgorithm.mProposedActorToFocus == Actor());
   DALI_TEST_CHECK(customAlgorithm.mDirection == Control::KeyboardFocus::UP);
+  DALI_TEST_EQUALS(customAlgorithm.mDeviceName, deviceName, TEST_LOCATION );
   customAlgorithm.Reset();
   DALI_TEST_CHECK(!focusChangedCallback.mSignalVerified);
 
@@ -670,12 +678,16 @@ int UtcDaliKeyboardFocusManagerFocusablePropertiesMoveFocus(void)
   button1.SetProperty(Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetProperty<int>(Actor::Property::ID)));
   button1.SetProperty(Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetProperty<int>(Actor::Property::ID)));
   button1.SetProperty(Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetProperty<int>(Actor::Property::ID)));
+  button1.SetProperty(Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetProperty< int >( Actor::Property::ID)));
+  button1.SetProperty(Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::Value((int)button2.GetProperty< int >( Actor::Property::ID)));
 
   // set the navigation properties of button2
   button2.SetProperty(Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetProperty<int>(Actor::Property::ID)));
   button2.SetProperty(Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetProperty<int>(Actor::Property::ID)));
   button2.SetProperty(Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetProperty<int>(Actor::Property::ID)));
   button2.SetProperty(Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetProperty<int>(Actor::Property::ID)));
+  button2.SetProperty(Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetProperty< int >( Actor::Property::ID)));
+  button2.SetProperty(Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::Value((int)button1.GetProperty< int >( Actor::Property::ID)));
 
   // Move the focus towards left
   DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::LEFT) == true);
@@ -717,6 +729,26 @@ int UtcDaliKeyboardFocusManagerFocusablePropertiesMoveFocus(void)
   DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
   focusChangedCallback.Reset();
 
+  // Move the focus towards clockwise
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::CLOCKWISE) == true);
+
+  // Confirm whether focus is moved to button2
+  DALI_TEST_EQUALS(button2.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button1);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button2);
+  focusChangedCallback.Reset();
+
+  // Move the focus towards clockwise
+  DALI_TEST_CHECK(manager.MoveFocus(Control::KeyboardFocus::COUNTER_CLOCKWISE) == true);
+
+  // Confirm whether focus is moved to button1
+  DALI_TEST_EQUALS(button1.GetProperty<int>(DevelControl::Property::STATE), (int)DevelControl::FOCUSED, TEST_LOCATION );
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == button2);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == button1);
+  focusChangedCallback.Reset();
+
   // Create a 1x1 table view and try to move focus inside it
   TableView tableView = TableView::New(1, 1);
   application.GetScene().Add(tableView);
@@ -2117,3 +2149,64 @@ int UtcDaliKeyboardFocusManagerCheckWheelEvent(void)
 
   END_TEST;
 }
+
+int UtcDaliKeyboardFocusManagerChangeFocusDirectionByCustomWheelEvent(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliKeyboardFocusManagerChangeFocusDirectionByCustomWheelEvent");
+  Dali::Integration::Scene scene = application.GetScene();
+
+  KeyboardFocusManager manager = KeyboardFocusManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  bool focusChangedSignalVerified = false;
+  FocusChangedCallback focusChangedCallback(focusChangedSignalVerified);
+  manager.FocusChangedSignal().Connect( &focusChangedCallback, &FocusChangedCallback::Callback );
+
+  Integration::WheelEvent clockwiseEvent(Integration::WheelEvent::CUSTOM_WHEEL, 0, 0u, Vector2(0.0f, 0.0f), 1, 1000u);
+  Integration::WheelEvent counterClockwiseEvent(Integration::WheelEvent::CUSTOM_WHEEL, 0, 0u, Vector2(0.0f, 0.0f), -1, 1100u);
+
+  // Create the first button
+  PushButton first = PushButton::New();
+  first.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+  scene.Add(first);
+
+  // Create the second button
+  PushButton second = PushButton::New();
+  second.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true);
+  scene.Add(second);
+
+   // set the navigation properties
+  first.SetProperty(Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::Value((int)second.GetProperty< int >( Actor::Property::ID )));
+  second.SetProperty(Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::Value((int)first.GetProperty< int >( Actor::Property::ID )));
+
+  // Set the focus to the first actor
+  DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == Actor());
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Send the clockwise wheel event to move the focus towards clockwise
+  application.ProcessEvent(clockwiseEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == first);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == second);
+  focusChangedCallback.Reset();
+
+  // Send the counter clockwise wheel event to move the focus towards count clockwise
+  application.ProcessEvent(counterClockwiseEvent);
+  DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first);
+  DALI_TEST_CHECK(focusChangedCallback.mSignalVerified);
+  DALI_TEST_CHECK(focusChangedCallback.mOriginalFocusedActor == second);
+  DALI_TEST_CHECK(focusChangedCallback.mCurrentFocusedActor == first);
+  focusChangedCallback.Reset();
+
+  // Clear the focus
+  manager.ClearFocus();
+
+  END_TEST;
+}
index 0524d55..9d9567b 100644 (file)
@@ -5857,6 +5857,36 @@ int UtcDaliTextEditorTextSizeNegativeLineSpacing(void)
   END_TEST;
 }
 
+int UtcDaliTextEditorNegativeLineSpacingWithEllipsis(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorNegativeLineSpacingWithEllipsis");
+
+  TextEditor editor = TextEditor::New();
+
+  float lineSpacing = -20.f;
+
+  editor.SetProperty(Actor::Property::SIZE, Vector2(480.0f, 100.f));
+  editor.SetProperty(TextEditor::Property::POINT_SIZE, 11.0f);
+  editor.SetProperty(DevelTextEditor::Property::LINE_SPACING, lineSpacing);
+  editor.SetProperty(TextEditor::Property::TEXT, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
+  editor.SetProperty(DevelTextEditor::Property::ELLIPSIS, true);
+
+  application.GetScene().Add(editor);
+  application.SendNotification();
+  application.Render();
+
+  Vector<Vector2> sizeList = DevelTextEditor::GetTextSize(editor, 0, 123);
+
+  int lineCount = sizeList.Size();
+  DALI_TEST_EQUALS(4, lineCount, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
 int UtcDaliToolkitTexteditorParagraphTag(void)
 {
   ToolkitTestApplication application;
index e12ce04..bbd3d77 100644 (file)
@@ -2725,6 +2725,37 @@ int UtcDaliTextTextLabelSizeNegativeLineSpacing(void)
   END_TEST;
 }
 
+int UtcDaliTextLabelNegativeLineSpacingWithEllipsis(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextLabelNegativeLineSpacingWithEllipsis");
+
+  TextLabel label = TextLabel::New();
+
+  float lineSpacing = -20.f;
+
+  label.SetProperty(Actor::Property::SIZE, Vector2(480.0f, 100.f));
+  label.SetProperty(TextLabel::Property::POINT_SIZE, 11.0f);
+  label.SetProperty(DevelTextLabel::Property::LINE_SPACING, lineSpacing);
+  label.SetProperty(TextLabel::Property::MULTI_LINE, true);
+  label.SetProperty(TextLabel::Property::TEXT, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
+  label.SetProperty(TextLabel::Property::ELLIPSIS, true);
+
+  application.GetScene().Add(label);
+  application.SendNotification();
+  application.Render();
+
+  Vector<Vector2> sizeList = DevelTextLabel::GetTextSize(label, 0, 123);
+
+  int lineCount = sizeList.Size();
+  DALI_TEST_EQUALS(4, lineCount, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  END_TEST;
+}
+
 int UtcDaliToolkitTextlabelParagraphTag(void)
 {
   ToolkitTestApplication application;
index 895e404..42384a1 100644 (file)
@@ -201,6 +201,20 @@ enum
    * @note The representative Accessible object will not appear in the AT-SPI tree.
    */
   ACCESSIBILITY_HIDDEN,
+
+  /**
+   * @brief The actor ID of the clockwise focusable control.
+   * @details Name "clockwiseFocusableActorId", type Property::INTEGER.
+   *
+   */
+  CLOCKWISE_FOCUSABLE_ACTOR_ID,
+
+  /**
+   * @brief The actor ID of the conter-clockwise focusable control.
+   * @details Name "counterClockwiseFocusableActorId", type Property::INTEGER.
+   *
+   */
+  COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID,
 };
 
 } // namespace Property
index f320269..a3ed473 100644 (file)
@@ -50,6 +50,11 @@ bool IsDefaultAlgorithmEnabled(KeyboardFocusManager keyboardFocusManager)
   return GetImpl(keyboardFocusManager).IsDefaultAlgorithmEnabled();
 }
 
+bool MoveFocus(KeyboardFocusManager keyboardFocusManager, Control::KeyboardFocus::Direction direction, const std::string& deviceName)
+{
+  return GetImpl(keyboardFocusManager).MoveFocus(direction, deviceName);
+}
+
 } // namespace DevelKeyboardFocusManager
 
 } // namespace Toolkit
index 192c296..b830445 100644 (file)
@@ -54,9 +54,11 @@ public:
    * @param[in] current The current focused actor
    * @param[in] proposed The proposed focused actor
    * @param[in] direction The direction of focus movement
+   * @param[in] deviceName The name of the device where the key event occurred.
    * @return A handle to the next focusable actor
    */
-  virtual Actor GetNextFocusableActor(Actor current, Actor proposed, Control::KeyboardFocus::Direction direction) = 0;
+  virtual Actor GetNextFocusableActor(Actor current, Actor proposed, Control::KeyboardFocus::Direction direction, const std::string& deviceName = "") = 0;
+
 };
 
 /**
@@ -100,6 +102,20 @@ DALI_TOOLKIT_API void EnableDefaultAlgorithm(KeyboardFocusManager keyboardFocusM
  */
 DALI_TOOLKIT_API bool IsDefaultAlgorithmEnabled(KeyboardFocusManager keyboardFocusManager);
 
+/**
+ * @brief Moves the focus to the next focusable actor in the focus
+ * chain in the given direction (according to the focus traversal
+ * order).
+ *
+ * @param[in] keyboardFocusManager The instance of KeyboardFocusManager
+ * @param direction The direction of focus movement
+ * @param deviceName The device name
+ * @return true if the movement was successful
+ * @pre The KeyboardFocusManager has been initialized.
+ */
+DALI_TOOLKIT_API bool MoveFocus(KeyboardFocusManager keyboardFocusManager, Control::KeyboardFocus::Direction direction, const std::string& deviceName);
+
+
 } // namespace DevelKeyboardFocusManager
 
 } // namespace Toolkit
index c1618f3..b49f9d0 100644 (file)
@@ -483,6 +483,8 @@ const PropertyRegistration Control::Impl::PROPERTY_20(typeRegistration, "accessi
 const PropertyRegistration Control::Impl::PROPERTY_21(typeRegistration, "accessibilityAttributes",        Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES,         Property::MAP,     &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 const PropertyRegistration Control::Impl::PROPERTY_22(typeRegistration, "dispatchKeyEvents",              Toolkit::DevelControl::Property::DISPATCH_KEY_EVENTS,              Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 const PropertyRegistration Control::Impl::PROPERTY_23(typeRegistration, "accessibilityHidden",            Toolkit::DevelControl::Property::ACCESSIBILITY_HIDDEN,             Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_24(typeRegistration, "clockwiseFocusableActorId",      Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID,     Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
+const PropertyRegistration Control::Impl::PROPERTY_25(typeRegistration, "counterClockwiseFocusableActorId", Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty);
 
 // clang-format on
 
@@ -494,6 +496,8 @@ Control::Impl::Impl(Control& controlImpl)
   mRightFocusableActorId(-1),
   mUpFocusableActorId(-1),
   mDownFocusableActorId(-1),
+  mClockwiseFocusableActorId(-1),
+  mCounterClockwiseFocusableActorId(-1),
   mStyleName(""),
   mBackgroundColor(Color::TRANSPARENT),
   mStartingPinchScale(nullptr),
@@ -1367,6 +1371,24 @@ void Control::Impl::SetProperty(BaseObject* object, Property::Index index, const
         }
         break;
       }
+      case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if(value.Get(focusId))
+        {
+          controlImpl.mImpl->mClockwiseFocusableActorId = focusId;
+        }
+        break;
+      }
+      case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID:
+      {
+        int focusId;
+        if(value.Get(focusId))
+        {
+          controlImpl.mImpl->mCounterClockwiseFocusableActorId = focusId;
+        }
+        break;
+      }
     }
   }
 }
@@ -1527,6 +1549,18 @@ Property::Value Control::Impl::GetProperty(BaseObject* object, Property::Index i
         value = controlImpl.mImpl->mAccessibilityHidden;
         break;
       }
+
+      case Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mClockwiseFocusableActorId;
+        break;
+      }
+
+      case Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID:
+      {
+        value = controlImpl.mImpl->mCounterClockwiseFocusableActorId;
+        break;
+      }
     }
   }
 
index 13ee7de..2354a94 100644 (file)
@@ -500,6 +500,8 @@ public:
   int mRightFocusableActorId; ///< Actor ID of Right focusable control.
   int mUpFocusableActorId;    ///< Actor ID of Up focusable control.
   int mDownFocusableActorId;  ///< Actor ID of Down focusable control.
+  int mClockwiseFocusableActorId;  ///< Actor ID of Clockwise focusable control.
+  int mCounterClockwiseFocusableActorId;  ///< Actor ID of Counter clockwise focusable control.
 
   RegisteredVisualContainer                 mVisuals; ///< Stores visuals needed by the control, non trivial type so std::vector used.
   std::string                               mStyleName;
@@ -582,6 +584,8 @@ public:
   static const PropertyRegistration PROPERTY_21;
   static const PropertyRegistration PROPERTY_22;
   static const PropertyRegistration PROPERTY_23;
+  static const PropertyRegistration PROPERTY_24;
+  static const PropertyRegistration PROPERTY_25;
 
 private:
   // Accessibility - notification for highlighted object to check if it is showing.
index 833b81b..c1f4179 100644 (file)
@@ -55,6 +55,7 @@ void CommonTextUtils::RenderText(
   float&                            alignmentOffset,
   Actor&                            renderableActor,
   Actor&                            backgroundActor,
+  Actor&                            cursorLayerActor,
   Toolkit::Control&                 stencil,
   std::vector<Actor>&               clippingDecorationActors,
   std::vector<Toolkit::TextAnchor>& anchorActors,
@@ -152,6 +153,12 @@ void CommonTextUtils::RenderText(
         backgroundActor.LowerToBottom();
       }
     }
+
+    if(cursorLayerActor)
+    {
+      cursorLayerActor.RaiseToTop();
+    }
+
     SynchronizeTextAnchorsInParent(textActor, controller, anchorActors);
   }
 }
index f6a9a2f..a0d0ad4 100644 (file)
@@ -60,6 +60,7 @@ public:
     float&                           alignmentOffset,
     Actor&                           renderableActor,
     Actor&                           backgroundActor,
+    Actor&                           cursorLayerActor,
     Toolkit::Control&                stencil,
     std::vector<Actor>&              clippingDecorationActors,
     std::vector<Toolkit::TextAnchor>& anchorActors,
index d3c0154..d6bae90 100644 (file)
@@ -776,7 +776,7 @@ void TextEditor::OnRelayout(const Vector2& size, RelayoutContainer& container)
 
 void TextEditor::RenderText(Text::Controller::UpdateTextType updateTextType)
 {
-  CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, mAnchorActors, updateTextType);
+  CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mCursorLayer, mStencil, mClippingDecorationActors, mAnchorActors, updateTextType);
   if(mRenderableActor)
   {
     ApplyScrollPosition();
index b1ea8e7..3cbd0b9 100644 (file)
@@ -716,7 +716,7 @@ Text::ControllerPtr TextField::GetTextController()
 
 void TextField::RenderText(Text::Controller::UpdateTextType updateTextType)
 {
-  CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mStencil, mClippingDecorationActors, mAnchorActors, updateTextType);
+  CommonTextUtils::RenderText(Self(), mRenderer, mController, mDecorator, mAlignmentOffset, mRenderableActor, mBackgroundActor, mCursorLayer, mStencil, mClippingDecorationActors, mAnchorActors, updateTextType);
 }
 
 void TextField::OnKeyInputFocusGained()
index 74e89dc..977e2e0 100644 (file)
@@ -29,6 +29,7 @@
 #include <dali/public-api/animation/constraints.h>
 #include <dali/public-api/events/key-event.h>
 #include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/events/wheel-event.h>
 #include <dali/public-api/object/property-map.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
@@ -145,7 +146,8 @@ void KeyboardFocusManager::OnAdaptorInit()
     {
       (*iter).KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent);
       (*iter).TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
-      (*iter).WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
+      (*iter).WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnCustomWheelEvent);
+      (*iter).WheelEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
       Dali::Window window = DevelWindow::DownCast(*iter);
       if(window)
       {
@@ -162,7 +164,8 @@ void KeyboardFocusManager::OnSceneHolderCreated(Dali::Integration::SceneHolder&
 {
   sceneHolder.KeyEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnKeyEvent);
   sceneHolder.TouchedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnTouch);
-  sceneHolder.WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
+  sceneHolder.WheelEventGeneratedSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnCustomWheelEvent);
+  sceneHolder.WheelEventSignal().Connect(mSlotDelegate, &KeyboardFocusManager::OnWheelEvent);
   Dali::Window window = DevelWindow::DownCast(sceneHolder);
   if(window)
   {
@@ -420,7 +423,7 @@ Toolkit::Control KeyboardFocusManager::GetParentLayoutControl(Actor actor) const
   return Toolkit::Control::DownCast(parent);
 }
 
-bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction)
+bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction, const std::string& deviceName)
 {
   Actor currentFocusActor = GetCurrentFocusActor();
 
@@ -470,6 +473,16 @@ bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction
           index = Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID;
           break;
         }
+        case Toolkit::Control::KeyboardFocus::CLOCKWISE:
+        {
+          index = Toolkit::DevelControl::Property::CLOCKWISE_FOCUSABLE_ACTOR_ID;
+          break;
+        }
+        case Toolkit::Control::KeyboardFocus::COUNTER_CLOCKWISE:
+        {
+          index = Toolkit::DevelControl::Property::COUNTER_CLOCKWISE_FOCUSABLE_ACTOR_ID;
+          break;
+        }
         default:
           break;
       }
@@ -506,7 +519,7 @@ bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction
       if(mCustomAlgorithmInterface)
       {
         mIsWaitingKeyboardFocusChangeCommit = true;
-        nextFocusableActor                  = mCustomAlgorithmInterface->GetNextFocusableActor(currentFocusActor, Actor(), direction);
+        nextFocusableActor                  = mCustomAlgorithmInterface->GetNextFocusableActor(currentFocusActor, Actor(), direction, deviceName);
         mIsWaitingKeyboardFocusChangeCommit = false;
       }
       else if(!mPreFocusChangeSignal.Empty())
@@ -785,7 +798,8 @@ Actor KeyboardFocusManager::GetFocusIndicatorActor()
 
 void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
 {
-  std::string keyName = event.GetKeyName();
+  const std::string& keyName = event.GetKeyName();
+  const std::string& deviceName = event.GetDeviceName();
 
   if(mIsFocusIndicatorShown == UNKNOWN)
   {
@@ -806,7 +820,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
       else
       {
         // Move the focus towards left
-        MoveFocus(Toolkit::Control::KeyboardFocus::LEFT);
+        MoveFocus(Toolkit::Control::KeyboardFocus::LEFT, deviceName);
       }
 
       isFocusStartableKey = true;
@@ -821,7 +835,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
       else
       {
         // Move the focus towards right
-        MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
+        MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT, deviceName);
       }
 
       isFocusStartableKey = true;
@@ -836,7 +850,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
       else
       {
         // Move the focus towards up
-        MoveFocus(Toolkit::Control::KeyboardFocus::UP);
+        MoveFocus(Toolkit::Control::KeyboardFocus::UP, deviceName);
       }
 
       isFocusStartableKey = true;
@@ -851,7 +865,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
       else
       {
         // Move the focus towards down
-        MoveFocus(Toolkit::Control::KeyboardFocus::DOWN);
+        MoveFocus(Toolkit::Control::KeyboardFocus::DOWN, deviceName);
       }
 
       isFocusStartableKey = true;
@@ -866,7 +880,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
       else
       {
         // Move the focus towards the previous page
-        MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_UP);
+        MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_UP, deviceName);
       }
 
       isFocusStartableKey = true;
@@ -881,7 +895,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
       else
       {
         // Move the focus towards the next page
-        MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_DOWN);
+        MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_DOWN, deviceName);
       }
 
       isFocusStartableKey = true;
@@ -900,7 +914,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
         if(!DoMoveFocusToNextFocusGroup(!event.IsShiftModifier()))
         {
           // If the focus group is not changed, Move the focus towards forward, "Shift-Tap" key moves the focus towards backward.
-          MoveFocus(event.IsShiftModifier() ? Toolkit::Control::KeyboardFocus::BACKWARD : Toolkit::Control::KeyboardFocus::FORWARD);
+          MoveFocus(event.IsShiftModifier() ? Toolkit::Control::KeyboardFocus::BACKWARD : Toolkit::Control::KeyboardFocus::FORWARD, deviceName);
         }
       }
 
@@ -973,7 +987,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
     {
       // No actor is focused but keyboard focus is activated by the key press
       // Let's try to move the initial focus
-      MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
+      MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT, deviceName);
     }
   }
 }
@@ -1006,19 +1020,29 @@ void KeyboardFocusManager::OnTouch(const TouchEvent& touch)
   }
 }
 
-bool KeyboardFocusManager::OnWheelEvent(const WheelEvent& event)
+void KeyboardFocusManager::OnWheelEvent(const WheelEvent& event)
+{
+  if(event.GetType() == Dali::WheelEvent::CUSTOM_WHEEL)
+  {
+    Toolkit::Control::KeyboardFocus::Direction direction = (event.GetDelta() > 0) ? Toolkit::Control::KeyboardFocus::CLOCKWISE : Toolkit::Control::KeyboardFocus::COUNTER_CLOCKWISE;
+    // Move the focus
+    MoveFocus(direction);
+  }
+}
+
+bool KeyboardFocusManager::OnCustomWheelEvent(const WheelEvent& event)
 {
   bool consumed = false;
   Actor actor = GetCurrentFocusActor();
   if(actor)
   {
     // Notify the actor about the wheel event
-    consumed = EmitWheelSignals(actor, event);
+    consumed = EmitCustomWheelSignals(actor, event);
   }
   return consumed;
 }
 
-bool KeyboardFocusManager::EmitWheelSignals(Actor actor, const WheelEvent& event)
+bool KeyboardFocusManager::EmitCustomWheelSignals(Actor actor, const WheelEvent& event)
 {
   bool consumed = false;
 
@@ -1041,7 +1065,7 @@ bool KeyboardFocusManager::EmitWheelSignals(Actor actor, const WheelEvent& event
       if(parent &&
          (parent == oldParent))
       {
-        consumed = EmitWheelSignals(parent, event);
+        consumed = EmitCustomWheelSignals(parent, event);
       }
     }
   }
index 783e3f5..3b09623 100644 (file)
@@ -90,7 +90,7 @@ public:
   /**
    * @copydoc Toolkit::KeyboardFocusManager::MoveFocus
    */
-  bool MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction);
+  bool MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction, const std::string& deviceName = "");
 
   /**
    * @copydoc Toolkit::KeyboardFocusManager::ClearFocus
@@ -295,7 +295,13 @@ private:
    * Callback for the wheel event when the custom wheel event occurs.
    * @param[in] wheel The WheelEvent information
    */
-  bool OnWheelEvent(const WheelEvent& wheel);
+  bool OnCustomWheelEvent(const WheelEvent& wheel);
+
+  /**
+   * Callback for the wheel event when the wheel event occurs.
+   * @param[in] wheel The WheelEvent information
+   */
+  void OnWheelEvent(const WheelEvent& wheel);
 
   /**
    * Called when the window focus is changed.
@@ -315,7 +321,7 @@ private:
    * @param[in]  event  The WheelEvent.
    * @return True if WheelEvent is consumed.
    */
-  bool EmitWheelSignals(Actor actor, const WheelEvent& event);
+  bool EmitCustomWheelSignals(Actor actor, const WheelEvent& event);
 
 private:
   // Undefined
index 53030e2..aff78c6 100644 (file)
@@ -1306,6 +1306,15 @@ struct Engine::Impl
       {
         layoutSize.height += GetLineHeight(*lineRun, true);
       }
+      else
+      {
+        //when we apply ellipsis, the last line should not take negative linespacing into account for layoutSize.height calculation
+        //usually we don't includ it in normal cases using GetLineHeight()
+        if(lineRun->lineSpacing < 0)
+        {
+          layoutSize.height -= lineRun->lineSpacing;
+        }
+      }
 
       const Vector<BidirectionalLineInfoRun>& bidirectionalLinesInfo = layoutParameters.textModel->mLogicalModel->mBidirectionalLineInfo;
 
index d7bf5eb..1b3cdc2 100644 (file)
@@ -26,6 +26,7 @@
 #include <dali-toolkit/internal/text/font-description-run.h>
 #include <dali-toolkit/internal/text/markup-processor-font.h>
 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+#include <dali-toolkit/internal/text/markup-processor-strikethrough.h>
 #include <dali-toolkit/internal/text/markup-processor-underline.h>
 
 namespace Dali
@@ -43,6 +44,7 @@ const std::string XHTML_WIDTH_ATTRIBUTE("font-width");
 const std::string XHTML_SLANT_ATTRIBUTE("font-slant");
 
 const std::string XHTML_COLOR_ATTRIBUTE("text-color");
+const std::string XHTML_BACKGROUND_COLOR_ATTRIBUTE("background-color");
 
 //the underlined character's attributes
 const std::string XHTML_UNDERLINE_COLOR_ATTRIBUTE("u-color");
@@ -50,15 +52,25 @@ const std::string XHTML_UNDERLINE_HEIGHT_ATTRIBUTE("u-height");
 const std::string XHTML_UNDERLINE_TYPE_ATTRIBUTE("u-type");
 const std::string XHTML_UNDERLINE_DASH_GAP_ATTRIBUTE("u-dash-gap");
 const std::string XHTML_UNDERLINE_DASH_WIDTH_ATTRIBUTE("u-dash-width");
+
+//the strikethroughed character's attributes
+const std::string XHTML_STRIKETHROUGH_COLOR_ATTRIBUTE("s-color");
+const std::string XHTML_STRIKETHROUGH_HEIGHT_ATTRIBUTE("s-height");
+
 } // namespace
 
-void ProcessSpanTag(const Tag&              tag,
-                    ColorRun&               colorRun,
-                    FontDescriptionRun&     fontRun,
-                    UnderlinedCharacterRun& underlinedCharacterRun,
-                    bool&                   isColorDefined,
-                    bool&                   isFontDefined,
-                    bool&                   isUnderlinedCharacterDefined)
+void ProcessSpanTag(const Tag&                 tag,
+                    ColorRun&                  colorRun,
+                    FontDescriptionRun&        fontRun,
+                    UnderlinedCharacterRun&    underlinedCharacterRun,
+                    ColorRun&                  backgroundColorRun,
+                    StrikethroughCharacterRun& strikethroughRun,
+                    bool&                      isColorDefined,
+                    bool&                      isFontDefined,
+                    bool&                      isUnderlinedCharacterDefined,
+                    bool&                      isBackgroundColorDefined,
+                    bool&                      isStrikethroughDefined)
+
 {
   for(Vector<Attribute>::ConstIterator it    = tag.attributes.Begin(),
                                        endIt = tag.attributes.End();
@@ -72,6 +84,11 @@ void ProcessSpanTag(const Tag&              tag,
       isColorDefined = true;
       ProcessColor(attribute, colorRun);
     }
+    else if(TokenComparison(XHTML_BACKGROUND_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      isBackgroundColorDefined = true;
+      ProcessColor(attribute, backgroundColorRun);
+    }
     else if(TokenComparison(XHTML_FAMILY_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
     {
       isFontDefined = true;
@@ -122,6 +139,16 @@ void ProcessSpanTag(const Tag&              tag,
       isUnderlinedCharacterDefined = true;
       ProcessDashWidthAttribute(attribute, underlinedCharacterRun);
     }
+    else if(TokenComparison(XHTML_STRIKETHROUGH_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      isStrikethroughDefined = true;
+      ProcessColorAttribute(attribute, strikethroughRun);
+    }
+    else if(TokenComparison(XHTML_STRIKETHROUGH_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      isStrikethroughDefined = true;
+      ProcessHeightAttribute(attribute, strikethroughRun);
+    }
   }
 }
 
index f5c49f6..6c29554 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_SPAN_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.
@@ -34,17 +34,25 @@ struct MarkupProcessData;
  * @param[out] colorRun the color run to be filled.
  * @param[out] fontRun the font run to be filled.
  * @param[out] underlinedCharacterRun the underlined character run to be filled.
+ * @param[out] backgroundColorRun the background color run to be filled.
+ * @param[out] strikethroughRun the strikethrough run to be filled.
  * @param[out] isColorDefined if the span has color defined.
  * @param[out] isFontDefined if the span has font defined.
  * @param[out] isUnderlinedCharacterDefined if the span has underlined-character defined.
+ * @param[out] isBackgroundColorDefined if the span has background color defined.
+ * @param[out] isStrikethroughDefined if the span has strikethrough defined.
  */
-void ProcessSpanTag(const Tag&              tag,
-                    ColorRun&               colorRun,
-                    FontDescriptionRun&     fontRun,
-                    UnderlinedCharacterRun& underlinedCharacterRun,
-                    bool&                   isColorDefined,
-                    bool&                   isFontDefined,
-                    bool&                   isUnderlinedCharacterDefined);
+void ProcessSpanTag(const Tag&                 tag,
+                    ColorRun&                  colorRun,
+                    FontDescriptionRun&        fontRun,
+                    UnderlinedCharacterRun&    underlinedCharacterRun,
+                    ColorRun&                  backgroundColorRun,
+                    StrikethroughCharacterRun& strikethroughRun,
+                    bool&                      isColorDefined,
+                    bool&                      isFontDefined,
+                    bool&                      isUnderlinedCharacterDefined,
+                    bool&                      isBackgroundColorDefined,
+                    bool&                      isStrikethroughDefined);
 
 } // namespace Text
 
index 9282121..2f0ea5d 100644 (file)
@@ -22,6 +22,7 @@
 #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/strikethrough-character-run.h>
 
@@ -34,6 +35,20 @@ namespace Text
 namespace
 {
 const std::string XHTML_COLOR_ATTRIBUTE("color");
+const std::string XHTML_HEIGHT_ATTRIBUTE("height");
+} // namespace
+
+void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun)
+
+{
+  ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, strikethroughRun.properties.color);
+  strikethroughRun.properties.colorDefined = true;
+}
+
+void ProcessHeightAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun)
+{
+  strikethroughRun.properties.height        = ProcessFloatAttribute(attribute);
+  strikethroughRun.properties.heightDefined = true;
 }
 
 void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun)
@@ -44,10 +59,52 @@ void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& striketh
       ++it)
   {
     const Attribute& attribute(*it);
+
     if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
     {
-      strikethroughRun.isColorSet = true;
-      ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, strikethroughRun.color);
+      ProcessColorAttribute(attribute, strikethroughRun);
+    }
+    else if(TokenComparison(XHTML_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ProcessHeightAttribute(attribute, strikethroughRun);
+    }
+  }
+}
+
+void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns)
+{
+  // Handle nested tags
+  // The inner tag inherit the attributes of the outer tag and override them when defined in the inner tag.
+  // Example:
+  // <s height='5.0f' color='blue'> outer tag before  <s color='green'> inner tag </s> outer tag after </s>
+  // "outer tag before" and  "outer tag after" have height = 5.0f and color = 'blue'
+  // "inner tag" has height = 5.0f and color = 'green'
+
+  if(strikethroughCharacterRuns.Count() > 0u)
+  {
+    Vector<StrikethroughCharacterRun>::ConstIterator preIt = strikethroughCharacterRuns.Begin();
+
+    Vector<StrikethroughCharacterRun>::Iterator      it    = strikethroughCharacterRuns.Begin() + 1;
+    Vector<StrikethroughCharacterRun>::ConstIterator endIt = strikethroughCharacterRuns.End();
+
+    while(it != endIt)
+    {
+      const StrikethroughCharacterRun& run                = *it;
+      const CharacterIndex&            characterIndex     = run.characterRun.characterIndex;
+      const Length&                    numberOfCharacters = run.characterRun.numberOfCharacters;
+
+      const StrikethroughCharacterRun& preRun                = *preIt;
+      const CharacterIndex&            preCharacterIndex     = preRun.characterRun.characterIndex;
+      const Length&                    preNumberOfCharacters = preRun.characterRun.numberOfCharacters;
+
+      if((preCharacterIndex <= characterIndex) &&
+         ((characterIndex + numberOfCharacters) <= (preCharacterIndex + preNumberOfCharacters)))
+      {
+        it->properties.CopyIfNotDefined(preIt->properties);
+      }
+
+      it++;
+      preIt++;
     }
   }
 }
index 6c0a520..fca6d34 100644 (file)
  *
  */
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/strikethrough-character-run.h>
+
 namespace Dali
 {
 namespace Toolkit
@@ -25,9 +31,26 @@ namespace Toolkit
 namespace Text
 {
 struct Tag;
+struct Attribute;
 struct StrikethroughCharacterRun;
 
 /**
+ * @brief Fill the strikethrough character run with the color attribute value.
+ *
+ * @param[in] attribute the color attribute.
+ * @param[out] strikethroughCharacterRun The strikethrough character run
+ */
+void ProcessColorAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughCharacterRun);
+
+/**
+ * @brief Fill the strikethrough character run with the height attribute value.
+ *
+ * @param[in] attribute the height attribute.
+ * @param[out] strikethroughRun The strikethrough character run
+ */
+void ProcessHeightAttribute(const Attribute& attribute, StrikethroughCharacterRun& strikethroughRun);
+
+/**
  * @brief Retrieves the strikethrough run info from the tag and sets it to the strikethrough run.
  *
  * @param[in] tag The strikethrough tag and its attributes.
@@ -35,6 +58,13 @@ struct StrikethroughCharacterRun;
  */
 void ProcessStrikethroughTag(const Tag& tag, StrikethroughCharacterRun& strikethroughRun);
 
+/**
+ * @brief Override the run's attributes which contained in the previous run. This is to handle the nested tags.
+ *
+ * @param[in,out] strikethroughCharacterRun The list of strikethrough character run
+ */
+void OverrideNestedStrikethroughCharacterRuns(Vector<StrikethroughCharacterRun>& strikethroughCharacterRun);
+
 } // namespace Text
 
 } // namespace Toolkit
index 197dff1..9c26b39 100644 (file)
@@ -83,7 +83,7 @@ const char NEW_LINE    = 0x0A; // ASCII value of the newline.
 // Range 3 0x10000u < XHTML_DECIMAL_ENTITY_RANGE <= 0x10FFFFu
 const unsigned long XHTML_DECIMAL_ENTITY_RANGE[] = {0x0u, 0xD7FFu, 0xE000u, 0xFFFDu, 0x10000u, 0x10FFFFu};
 
-const unsigned int MAX_NUM_OF_ATTRIBUTES = 11u; ///< The span tag has the 'font-family', 'font-size' 'font-weight', 'font-width', 'font-slant','text-color', 'u-color', 'u-height','u-type','u-dash-gap'and 'u-dash-width' attrubutes.
+const unsigned int MAX_NUM_OF_ATTRIBUTES = 13u; ///< The span tag has the 'font-family', 'font-size' 'font-weight', 'font-width', 'font-slant','text-color', 'u-color', 'u-height','u-type','u-dash-gap', 'u-dash-width', 's-color' and 's-height' attrubutes.
 const unsigned int DEFAULT_VECTOR_SIZE   = 16u; ///< Default size of run vectors.
 
 #if defined(DEBUG_ENABLED)
@@ -141,9 +141,14 @@ struct Span
   RunIndex colorRunIndex;
   RunIndex fontRunIndex;
   RunIndex underlinedCharacterRunIndex;
-  bool     isColorDefined;
-  bool     isFontDefined;
-  bool     isUnderlinedCharacterDefined;
+  RunIndex backgroundColorRunIndex;
+  RunIndex strikethroughCharacterRunIndex;
+
+  bool isColorDefined;
+  bool isFontDefined;
+  bool isUnderlinedCharacterDefined;
+  bool isBackgroundColorDefined;
+  bool isStrikethroughDefined;
 };
 
 /**
@@ -203,6 +208,12 @@ void Initialize(Span& span)
   span.isFontDefined                = false;
   span.underlinedCharacterRunIndex  = 0u;
   span.isUnderlinedCharacterDefined = false;
+  span.backgroundColorRunIndex      = 0u;
+  span.isBackgroundColorDefined     = false;
+
+  //strikethrough
+  span.strikethroughCharacterRunIndex = 0u;
+  span.isStrikethroughDefined         = false;
 }
 
 /**
@@ -214,7 +225,7 @@ void Initialize(StrikethroughCharacterRun& strikethroughCharacterRun)
 {
   strikethroughCharacterRun.characterRun.characterIndex     = 0u;
   strikethroughCharacterRun.characterRun.numberOfCharacters = 0u;
-  strikethroughCharacterRun.isColorSet                      = false;
+  strikethroughCharacterRun.properties.colorDefined         = false;
 }
 
 /**
@@ -714,25 +725,33 @@ void ProcessAnchorTag(
  * @brief Processes span tag for the color-run & font-run.
  *
  * @param[in] spanTag The tag we are currently processing
- * @param[in/out] spanStack The spans stack
- * @param[int/out] colorRuns The container containing all the color runs
- * @param[int/out] fontRuns The container containing all the font description runs
- * @param[in/out] colorRunIndex The color run index
- * @param[in/out] fontRunIndex The font run index
+ * @param[inout] spanStack The spans stack
+ * @param[inout] colorRuns The container containing all the color runs
+ * @param[inout] fontRuns The container containing all the font description runs
+ * @param[inout] underlinedCharacterRuns The container containing all the underlined character runs
+ * @param[inout] strikethroughCharacterRuns The container containing all the strikethroughed character runs
+ * @param[inout] colorRunIndex The color run index
+ * @param[inout] fontRunIndex The font run index
+ * @param[inout] underlinedCharacterRunIndex The underlined character run index
+ * @param[inout] strikethroughCharacterRunIndex The strikethroughed character run index
  * @param[in] characterIndex The current character index
  * @param[in] tagReference The tagReference we should increment/decrement
  */
 void ProcessSpanForRun(
-  const Tag&                      spanTag,
-  StyleStack<Span>&               spanStack,
-  Vector<ColorRun>&               colorRuns,
-  Vector<FontDescriptionRun>&     fontRuns,
-  Vector<UnderlinedCharacterRun>& underlinedCharacterRuns,
-  RunIndex&                       colorRunIndex,
-  RunIndex&                       fontRunIndex,
-  RunIndex&                       underlinedCharacterRunIndex,
-  const CharacterIndex            characterIndex,
-  int&                            tagReference)
+  const Tag&                         spanTag,
+  StyleStack<Span>&                  spanStack,
+  Vector<ColorRun>&                  colorRuns,
+  Vector<FontDescriptionRun>&        fontRuns,
+  Vector<UnderlinedCharacterRun>&    underlinedCharacterRuns,
+  Vector<ColorRun>&                  backgroundColorRuns,
+  Vector<StrikethroughCharacterRun>& strikethroughCharacterRuns,
+  RunIndex&                          colorRunIndex,
+  RunIndex&                          fontRunIndex,
+  RunIndex&                          underlinedCharacterRunIndex,
+  RunIndex&                          backgroundColorRunIndex,
+  RunIndex&                          strikethroughCharacterRunIndex,
+  const CharacterIndex               characterIndex,
+  int&                               tagReference)
 {
   if(!spanTag.isEndTag)
   {
@@ -746,19 +765,39 @@ void ProcessSpanForRun(
     UnderlinedCharacterRun underlinedCharacterRun;
     Initialize(underlinedCharacterRun);
 
+    ColorRun backgroundColorRun;
+    Initialize(backgroundColorRun);
+
+    StrikethroughCharacterRun strikethroughCharacterRun;
+    Initialize(strikethroughCharacterRun);
+
     Span span;
     Initialize(span);
 
     // Fill the run with the parameters.
-    colorRun.characterRun.characterIndex               = characterIndex;
-    fontRun.characterRun.characterIndex                = characterIndex;
-    underlinedCharacterRun.characterRun.characterIndex = characterIndex;
-
-    span.colorRunIndex               = colorRunIndex;
-    span.fontRunIndex                = fontRunIndex;
-    span.underlinedCharacterRunIndex = underlinedCharacterRunIndex;
-
-    ProcessSpanTag(spanTag, colorRun, fontRun, underlinedCharacterRun, span.isColorDefined, span.isFontDefined, span.isUnderlinedCharacterDefined);
+    colorRun.characterRun.characterIndex                  = characterIndex;
+    fontRun.characterRun.characterIndex                   = characterIndex;
+    underlinedCharacterRun.characterRun.characterIndex    = characterIndex;
+    backgroundColorRun.characterRun.characterIndex        = characterIndex;
+    strikethroughCharacterRun.characterRun.characterIndex = characterIndex;
+
+    span.colorRunIndex                  = colorRunIndex;
+    span.fontRunIndex                   = fontRunIndex;
+    span.underlinedCharacterRunIndex    = underlinedCharacterRunIndex;
+    span.backgroundColorRunIndex        = backgroundColorRunIndex;
+    span.strikethroughCharacterRunIndex = strikethroughCharacterRunIndex;
+
+    ProcessSpanTag(spanTag,
+                   colorRun,
+                   fontRun,
+                   underlinedCharacterRun,
+                   backgroundColorRun,
+                   strikethroughCharacterRun,
+                   span.isColorDefined,
+                   span.isFontDefined,
+                   span.isUnderlinedCharacterDefined,
+                   span.isBackgroundColorDefined,
+                   span.isStrikethroughDefined);
 
     // Push the span into the stack.
     spanStack.Push(span);
@@ -785,6 +824,20 @@ void ProcessSpanForRun(
       ++underlinedCharacterRunIndex;
     }
 
+    if(span.isBackgroundColorDefined)
+    {
+      // Push the run in the logical model.
+      backgroundColorRuns.PushBack(backgroundColorRun);
+      ++backgroundColorRunIndex;
+    }
+
+    if(span.isStrikethroughDefined)
+    {
+      // Push the run in the logical model.
+      strikethroughCharacterRuns.PushBack(strikethroughCharacterRun);
+      ++strikethroughCharacterRunIndex;
+    }
+
     // Increase reference
     ++tagReference;
   }
@@ -813,6 +866,18 @@ void ProcessSpanForRun(
         underlinedCharacterRun.characterRun.numberOfCharacters = characterIndex - underlinedCharacterRun.characterRun.characterIndex;
       }
 
+      if(span.isBackgroundColorDefined)
+      {
+        ColorRun& backgroundColorRun                       = *(backgroundColorRuns.Begin() + span.backgroundColorRunIndex);
+        backgroundColorRun.characterRun.numberOfCharacters = characterIndex - backgroundColorRun.characterRun.characterIndex;
+      }
+
+      if(span.isStrikethroughDefined)
+      {
+        StrikethroughCharacterRun& strikethroughCharacterRun      = *(strikethroughCharacterRuns.Begin() + span.strikethroughCharacterRunIndex);
+        strikethroughCharacterRun.characterRun.numberOfCharacters = characterIndex - strikethroughCharacterRun.characterRun.characterIndex;
+      }
+
       --tagReference;
     }
   }
@@ -821,10 +886,11 @@ void ProcessSpanForRun(
 /**
  * @brief Resizes the model's vectors
  *
- * @param[in/out] markupProcessData The markup process data
+ * @param[inout] markupProcessData The markup process data
  * @param[in] fontRunIndex The font run index
  * @param[in] colorRunIndex The color run index
  * @param[in] underlinedCharacterRunIndex The underlined character run index
+ * @param[in] strikethroughCharacterRunIndex The strikethroughed character run index
  * @param[in] backgroundRunIndex The background run index
  * @param[in] boundedParagraphRunIndex The bounded paragraph run index
  *
@@ -833,12 +899,14 @@ void ResizeModelVectors(MarkupProcessData& markupProcessData,
                         const RunIndex     fontRunIndex,
                         const RunIndex     colorRunIndex,
                         const RunIndex     underlinedCharacterRunIndex,
+                        const RunIndex     strikethroughCharacterRunIndex,
                         const RunIndex     backgroundRunIndex,
                         const RunIndex     boundedParagraphRunIndex)
 {
   markupProcessData.fontRuns.Resize(fontRunIndex);
   markupProcessData.colorRuns.Resize(colorRunIndex);
   markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
+  markupProcessData.strikethroughCharacterRuns.Resize(strikethroughCharacterRunIndex);
   markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
   markupProcessData.boundedParagraphRuns.Resize(boundedParagraphRunIndex);
 
@@ -983,6 +1051,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
+  markupProcessData.strikethroughCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
 
   // Get the mark-up string buffer.
   const char*       markupStringBuffer    = markupString.c_str();
@@ -1072,7 +1141,20 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
       }
       else if(TokenComparison(XHTML_SPAN_TAG, tag.buffer, tag.length))
       {
-        ProcessSpanForRun(tag, spanStack, markupProcessData.colorRuns, markupProcessData.fontRuns, markupProcessData.underlinedCharacterRuns, colorRunIndex, fontRunIndex, underlinedCharacterRunIndex, characterIndex, spanTagReference);
+        ProcessSpanForRun(tag,
+                          spanStack,
+                          markupProcessData.colorRuns,
+                          markupProcessData.fontRuns,
+                          markupProcessData.underlinedCharacterRuns,
+                          markupProcessData.backgroundColorRuns,
+                          markupProcessData.strikethroughCharacterRuns,
+                          colorRunIndex,
+                          fontRunIndex,
+                          underlinedCharacterRunIndex,
+                          backgroundRunIndex,
+                          strikethroughCharacterRunIndex,
+                          characterIndex,
+                          spanTagReference);
       }
       else if(TokenComparison(XHTML_STRIKETHROUGH_TAG, tag.buffer, tag.length))
       {
@@ -1093,10 +1175,11 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   }
 
   // Resize the model's vectors.
-  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex);
+  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, strikethroughCharacterRunIndex, backgroundRunIndex, boundedParagraphRunIndex);
 
   // Handle the nested tags
   OverrideNestedUnderlinedCharacterRuns(markupProcessData.underlinedCharacterRuns);
+  OverrideNestedStrikethroughCharacterRuns(markupProcessData.strikethroughCharacterRuns);
 }
 
 } // namespace Text
index 291c187..e30564e 100644 (file)
@@ -161,31 +161,6 @@ struct AtlasRenderer::Impl
     mQuadVertexFormat["aColor"]    = Property::VECTOR4;
   }
 
-  bool
-  doGlyphHaveStrikethrough(GlyphIndex                           index,
-                           const Vector<StrikethroughGlyphRun>& strikethroughRuns,
-                           Vector4&                             strikethroughColor)
-  {
-    for(Vector<StrikethroughGlyphRun>::ConstIterator it    = strikethroughRuns.Begin(),
-                                                     endIt = strikethroughRuns.End();
-        it != endIt;
-        ++it)
-    {
-      const StrikethroughGlyphRun& run = *it;
-
-      if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs))
-      {
-        if(run.isColorSet)
-        {
-          strikethroughColor = run.color;
-        }
-
-        return true;
-      }
-    }
-
-    return false;
-  }
   void CacheGlyph(const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot)
   {
     const Size& defaultTextAtlasSize = mFontClient.GetDefaultTextAtlasSize(); //Retrieve default size of text-atlas-block from font-client.
@@ -337,6 +312,10 @@ struct AtlasRenderer::Impl
       vertex.mColor = color;
     }
 
+    // Since Free Type font doesn't contain the strikethrough-position property,
+    // strikethrough position will be calculated by moving the underline position upwards by half the value of the line height.
+    float strikethroughStartingYPosition = (position.y + glyph.yBearing + currentUnderlinePosition) - ((glyph.height) * HALF);
+
     // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
     StitchTextMesh(meshContainer,
                    newMesh,
@@ -347,7 +326,7 @@ struct AtlasRenderer::Impl
                    currentlineThickness,
                    slot,
                    underlineChunkId,
-                   position.y + (glyph.height * HALF),
+                   strikethroughStartingYPosition,
                    strikethroughChunkId);
   }
 
@@ -453,9 +432,6 @@ struct AtlasRenderer::Impl
     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.
@@ -496,14 +472,18 @@ struct AtlasRenderer::Impl
     strikethroughRuns.Resize(numberOfStrikethroughRuns);
     view.GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
 
-    bool thereAreUnderlinedGlyphs = false;
-    bool strikethroughGlyphsExist = false;
+    const StrikethroughStyleProperties viewStrikethroughProperties{view.GetStrikethroughColor(),
+                                                                   view.GetStrikethroughHeight(),
+                                                                   true,
+                                                                   true};
+
+    float maxStrikethroughHeight = viewStrikethroughProperties.height;
 
-    float  currentUnderlinePosition   = ZERO;
-    float  currentStrikethroughHeight = strikethroughHeight;
-    float  maxStrikethroughHeight     = currentStrikethroughHeight;
-    FontId lastFontId                 = 0;
-    Style  style                      = STYLE_NORMAL;
+    FontId lastFontId                  = 0;
+    Style  style                       = STYLE_NORMAL;
+    float  currentUnderlinePosition    = ZERO;
+    bool   thereAreUnderlinedGlyphs    = false;
+    bool   thereAreStrikethroughGlyphs = false;
 
     if(fabsf(shadowOffset.x) > Math::MACHINE_EPSILON_1 || fabsf(shadowOffset.y) > Math::MACHINE_EPSILON_1)
     {
@@ -525,8 +505,12 @@ struct AtlasRenderer::Impl
     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.
+    //For septated strikethrough chunks. (this is for Markup case)
+    uint32_t                                         strikethroughChunkId = 0u;                                // give id for each chunk.
+    bool                                             isPreStrikethrough   = false;                             // status of strikethrough for previous glyph.
+    std::map<uint32_t, StrikethroughStyleProperties> mapStrikethroughChunkIdWithProperties;                    // mapping strikethroughChunkId with StrikethroughStyleProperties to get properties of strikethrough chunk
+    StrikethroughStyleProperties                     preStrikethroughProperties = viewStrikethroughProperties; // the previous StrikethroughStyleProperties
+
     const Character*              textBuffer                = view.GetTextBuffer();
     float                         calculatedAdvance         = 0.f;
     const Vector<CharacterIndex>& glyphToCharacterMap       = view.GetGlyphsToCharacters();
@@ -568,16 +552,17 @@ struct AtlasRenderer::Impl
       float                                     currentUnderlineHeight      = currentUnderlineProperties.height;
       thereAreUnderlinedGlyphs                                              = thereAreUnderlinedGlyphs || isGlyphUnderlined;
 
-      currentStrikethroughColor       = strikethroughColor;
-      const bool isStrikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(i, strikethroughRuns, currentStrikethroughColor);
-      strikethroughGlyphsExist        = strikethroughGlyphsExist || isStrikethroughGlyph;
+      Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End();
+      const bool                                   isGlyphStrikethrough           = strikethroughEnabled || IsGlyphStrikethrough(i, strikethroughRuns, currentStrikethroughGlyphRunIt);
+      const StrikethroughStyleProperties           currentStrikethroughProperties = GetCurrentStrikethroughProperties(i, isGlyphStrikethrough, strikethroughRuns, currentStrikethroughGlyphRunIt, viewStrikethroughProperties);
+      float                                        currentStrikethroughHeight     = currentStrikethroughProperties.height;
+      thereAreStrikethroughGlyphs                                                 = thereAreStrikethroughGlyphs || isGlyphStrikethrough;
 
       // No operation for white space
       if(glyph.width && glyph.height)
       {
         // Check and update decorative-lines informations
-        if((isGlyphUnderlined || isStrikethroughGlyph) &&
-           ((glyph.fontId != lastDecorativeLinesFontId) || !(currentUnderlineProperties.IsHeightEqualTo(preUnderlineProperties))))
+        if(isGlyphUnderlined || isGlyphStrikethrough)
         {
           bool isDecorativeLinesFontIdUpdated = false;
           // Are we still using the same fontId as previous
@@ -588,7 +573,7 @@ struct AtlasRenderer::Impl
             isDecorativeLinesFontIdUpdated = true;
             fontClient.GetFontMetrics(lastDecorativeLinesFontId, lastDecorativeLinesFontMetrics);
 
-            if(isStrikethroughGlyph || isGlyphUnderlined)
+            if(isGlyphStrikethrough || isGlyphUnderlined)
             {
               //The currentUnderlinePosition will be used for both Underline and/or Strikethrough
               currentUnderlinePosition = FetchUnderlinePositionFromFontMetrics(lastDecorativeLinesFontMetrics);
@@ -606,8 +591,14 @@ struct AtlasRenderer::Impl
             CalcualteUnderlineHeight(lastDecorativeLinesFontMetrics, currentUnderlineHeight, maxUnderlineHeight);
           }
 
-          if(isDecorativeLinesFontIdUpdated && isStrikethroughGlyph)
+          if(isGlyphStrikethrough && (isDecorativeLinesFontIdUpdated || !(currentStrikethroughProperties.IsHeightEqualTo(preStrikethroughProperties))))
           {
+            //If the Strikethrough Height is changed then we need to recalculate height.
+            if(!(currentStrikethroughProperties.IsHeightEqualTo(preStrikethroughProperties)))
+            {
+              maxStrikethroughHeight = currentStrikethroughHeight;
+            }
+
             CalcualteStrikethroughHeight(currentStrikethroughHeight, maxStrikethroughHeight);
           }
         } // decorative-lines
@@ -680,14 +671,22 @@ struct AtlasRenderer::Impl
                        false,
                        0u);
 
-          if(isStrikethroughGlyph)
+          if(isGlyphStrikethrough)
           {
+            //The new strikethrough chunk. Add new id if they are not consecutive indices (this is for Markup case)
+            // Examples: "Hello <s>World</s> Hello <s>World</s>", "<s>World</s> Hello <s>World</s>", "<s>   World</s> Hello <s>World</s>"
+            if((!isPreStrikethrough) || (preStrikethroughProperties != currentStrikethroughProperties))
+            {
+              strikethroughChunkId++;
+              mapStrikethroughChunkIdWithProperties.insert(std::pair<uint32_t, StrikethroughStyleProperties>(strikethroughChunkId, currentStrikethroughProperties));
+            }
+
             GenerateMesh(glyph,
                          positionPlusOutlineOffset,
                          color,
                          NO_OUTLINE,
                          slot,
-                         strikethroughGlyphsExist,
+                         isGlyphStrikethrough,
                          0.0f,
                          maxStrikethroughHeight,
                          meshContainer,
@@ -698,6 +697,10 @@ struct AtlasRenderer::Impl
                          strikethroughChunkId);
           }
 
+          //Keep status of Strikethrough for previous glyph to check consecutive indices
+          isPreStrikethrough         = isGlyphStrikethrough;
+          preStrikethroughProperties = currentStrikethroughProperties;
+
           lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId.
         }
 
@@ -718,13 +721,6 @@ struct AtlasRenderer::Impl
                        false,
                        0u);
         }
-
-        if(isPrevGlyphStrikethrough && !isStrikethroughGlyph)
-        {
-          strikethroughChunkId++;
-        }
-
-        isPrevGlyphStrikethrough = isStrikethroughGlyph;
       }
 
       if(addHyphen)
@@ -743,10 +739,10 @@ struct AtlasRenderer::Impl
       GenerateUnderlines(meshContainer, extents, viewUnderlineProperties, mapUnderlineChunkIdWithProperties);
     }
 
-    if(strikethroughGlyphsExist)
+    if(thereAreStrikethroughGlyphs)
     {
       // Check to see if any of the text needs a strikethrough
-      GenerateStrikethrough(meshContainer, strikethroughExtents, currentStrikethroughColor);
+      GenerateStrikethrough(meshContainer, strikethroughExtents, viewStrikethroughProperties, mapStrikethroughChunkIdWithProperties);
     }
 
     // For each MeshData object, create a mesh actor and add to the renderable actor
@@ -1226,9 +1222,10 @@ struct AtlasRenderer::Impl
     }
   }
 
-  void GenerateStrikethrough(std::vector<MeshRecord>& meshRecords,
-                             Vector<Extent>&          extents,
-                             const Vector4&           strikethroughColor)
+  void GenerateStrikethrough(std::vector<MeshRecord>&                                meshRecords,
+                             Vector<Extent>&                                         extents,
+                             const StrikethroughStyleProperties&                     viewStrikethroughProperties,
+                             const std::map<uint32_t, StrikethroughStyleProperties>& mapStrikethroughChunkIdWithProperties)
   {
     AtlasManager::Mesh2D newMesh;
     unsigned short       faceIndex = 0;
@@ -1241,6 +1238,14 @@ struct AtlasRenderer::Impl
       uint32_t               index = eIt->mMeshRecordIndex;
       Vector2                uv    = mGlyphManager.GetAtlasSize(meshRecords[index].mAtlasId);
 
+      auto pairStrikethroughChunkIdWithProperties = mapStrikethroughChunkIdWithProperties.find(eIt->mStrikethroughChunkId);
+
+      const StrikethroughStyleProperties strikethroughProperties = (pairStrikethroughChunkIdWithProperties == mapStrikethroughChunkIdWithProperties.end())
+                                                                     ? viewStrikethroughProperties
+                                                                     : pairStrikethroughChunkIdWithProperties->second;
+
+      const Vector4& strikethroughColor = strikethroughProperties.colorDefined ? strikethroughProperties.color : viewStrikethroughProperties.color;
+
       // 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;
index c87fe88..76b8ce3 100644 (file)
@@ -24,7 +24,58 @@ namespace Toolkit
 {
 namespace Text
 {
-/// Helper method to fetch the underline metrics for the specified font glyph
+bool IsGlyphStrikethrough(GlyphIndex                                    index,
+                          const Vector<StrikethroughGlyphRun>&          strikethroughRuns,
+                          Vector<StrikethroughGlyphRun>::ConstIterator& currentStrikethroughGlyphRunIt)
+{
+  for(Vector<StrikethroughGlyphRun>::ConstIterator it    = strikethroughRuns.Begin(),
+                                                   endIt = strikethroughRuns.End();
+      it != endIt;
+      ++it)
+  {
+    const StrikethroughGlyphRun& run = *it;
+
+    if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs))
+    {
+      currentStrikethroughGlyphRunIt = it;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+StrikethroughStyleProperties GetCurrentStrikethroughProperties(GlyphIndex                                    index,
+                                                               const bool&                                   isGlyphStrikethrough,
+                                                               const Vector<StrikethroughGlyphRun>&          strikethroughRuns,
+                                                               Vector<StrikethroughGlyphRun>::ConstIterator& currentStrikethroughGlyphRunIt,
+                                                               const StrikethroughStyleProperties&           commonStrikethroughProperties)
+{
+  StrikethroughStyleProperties currentStrikethroughStyleProperties = commonStrikethroughProperties;
+
+  if(isGlyphStrikethrough && (currentStrikethroughGlyphRunIt != strikethroughRuns.End()))
+  {
+    // Retrieve the latest run to handle the nested case.
+    for(Vector<StrikethroughGlyphRun>::ConstIterator it    = currentStrikethroughGlyphRunIt + 1,
+                                                     endIt = strikethroughRuns.End();
+        it != endIt;
+        ++it)
+    {
+      const StrikethroughGlyphRun& run = *it;
+
+      if((run.glyphRun.glyphIndex <= index) && (index < (run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs)))
+      {
+        currentStrikethroughGlyphRunIt = it;
+      }
+    }
+
+    currentStrikethroughStyleProperties.OverrideByDefinedProperties(currentStrikethroughGlyphRunIt->properties);
+  }
+
+  return currentStrikethroughStyleProperties;
+}
+
+/// Helper method to fetch the strikethrough metrics for the specified font glyph
 void CalcualteStrikethroughHeight(float& currentStrikethroughHeight, float& maxStrikethroughHeight)
 {
   //Height of strikethrough represents the thickness of line.
index b3df7ef..d9c86e4 100644 (file)
@@ -23,7 +23,7 @@
 #include <dali/public-api/common/dali-vector.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/internal/text/underlined-glyph-run.h>
+#include <dali-toolkit/internal/text/strikethrough-glyph-run.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
 
 namespace Dali
@@ -33,7 +33,37 @@ namespace Toolkit
 namespace Text
 {
 /**
- * @brief Calculate the current underline height and update maximum underline height
+ * @brief Whether the glyph at index is strikethrough or not. If true then return iterator to the run containes index.
+ *
+ * @param[in] index the index of glyph.
+ * @param[in] strikethroughRuns the strikethrough runs.
+ * @param[out] currentStrikethroughGlyphRunIt the iterator of current strikethrough glyph run.
+ *
+ * @return true if glyph at index is strikethrough
+ */
+bool IsGlyphStrikethrough(GlyphIndex                                    index,
+                          const Vector<StrikethroughGlyphRun>&          strikethroughRuns,
+                          Vector<StrikethroughGlyphRun>::ConstIterator& currentStrikethroughGlyphRunIt);
+
+/**
+ * @brief Check the current strikethrough glyph run iterator if not empty and isGlyphStrikethrough is true then return its StrikethroughProperties. Otherwise return the common strikethrough properties.
+ *
+ * @param[in] index the index of glyph.
+ * @param[in] isGlyphStrikethrough whether the glyph is strikethrough.
+ * @param[in] strikethroughRuns the strikethrough runs.
+ * @param[in] currentStrikethroughGlyphRunIt the iterator of current strikethrough glyph run.
+ * @param[in] commonStrikethroughProperties the common strikethrough properties.
+ *
+ * @return the determined strikethrough properties
+ */
+StrikethroughStyleProperties GetCurrentStrikethroughProperties(GlyphIndex                                    index,
+                                                               const bool&                                   isGlyphStrikethrough,
+                                                               const Vector<StrikethroughGlyphRun>&          strikethroughRuns,
+                                                               Vector<StrikethroughGlyphRun>::ConstIterator& currentStrikethroughGlyphRunIt,
+                                                               const StrikethroughStyleProperties&           commonStrikethroughProperties);
+
+/**
+ * @brief Calculate the current strikethrough height and update maximum strikethrough height
  *
  * @param[inout] currentStrikethroughHeight the current strikethrough height.
  * @param[inout] maxStrikethroughHeight the maximum strikethrough height.
index 4dc9775..9d58934 100644 (file)
@@ -260,31 +260,6 @@ void TypesetGlyph(GlyphData&           data,
   }
 }
 
-bool doGlyphHaveStrikethrough(GlyphIndex                           index,
-                              const Vector<StrikethroughGlyphRun>& strikethroughRuns,
-                              Vector4&                             strikethroughColor)
-{
-  for(Vector<StrikethroughGlyphRun>::ConstIterator it    = strikethroughRuns.Begin(),
-                                                   endIt = strikethroughRuns.End();
-      it != endIt;
-      ++it)
-  {
-    const StrikethroughGlyphRun& run = *it;
-
-    if((run.glyphRun.glyphIndex <= index) && (index < run.glyphRun.glyphIndex + run.glyphRun.numberOfGlyphs))
-    {
-      if(run.isColorSet)
-      {
-        strikethroughColor = run.color;
-      }
-
-      return true;
-    }
-  }
-
-  return false;
-}
-
 /// Draws the specified color to the pixel buffer
 void WriteColorToPixelBuffer(
   GlyphData&         glyphData,
@@ -546,18 +521,20 @@ Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuff
 }
 
 /// Draws the specified strikethrough color to the buffer
-void DrawStrikethrough(
-  const Vector4&     strikethroughColor,
-  const unsigned int bufferWidth,
-  const unsigned int bufferHeight,
-  GlyphData&         glyphData,
-  const float        baseline,
-  const LineRun&     line,
-  const float        maxStrikethroughHeight,
-  const float        lineExtentLeft,
-  const float        lineExtentRight,
-  float              strikethroughStartingYPosition)
+void DrawStrikethrough(const unsigned int                  bufferWidth,
+                       const unsigned int                  bufferHeight,
+                       GlyphData&                          glyphData,
+                       const float                         baseline,
+                       const float                         strikethroughStartingYPosition,
+                       const float                         maxStrikethroughHeight,
+                       const float                         lineExtentLeft,
+                       const float                         lineExtentRight,
+                       const StrikethroughStyleProperties& commonStrikethroughProperties,
+                       const StrikethroughStyleProperties& currentStrikethroughProperties,
+                       const LineRun&                      line)
 {
+  const Vector4& strikethroughColor = currentStrikethroughProperties.colorDefined ? currentStrikethroughProperties.color : commonStrikethroughProperties.color;
+
   uint32_t* bitmapBuffer = reinterpret_cast<uint32_t*>(glyphData.bitmapBuffer.GetBuffer());
 
   for(unsigned int y = strikethroughStartingYPosition; y < strikethroughStartingYPosition + maxStrikethroughHeight; y++)
@@ -840,7 +817,6 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
   // Whether to use the default color.
   const bool     useDefaultColor = (NULL == colorsBuffer);
   const Vector4& defaultColor    = mModel->GetDefaultColor();
-  Vector4        currentStrikethroughColor;
 
   // Create and initialize the pixel buffer.
   GlyphData glyphData;
@@ -901,11 +877,9 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       }
     }
 
-    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();
+    const bool  underlineEnabled     = mModel->IsUnderlineEnabled();
+    const bool  strikethroughEnabled = mModel->IsStrikethroughEnabled();
+    const float characterSpacing     = mModel->GetCharacterSpacing();
 
     // Aggregate underline-style-properties from mModel
     const UnderlineStyleProperties modelUnderlineProperties{mModel->GetUnderlineType(),
@@ -919,6 +893,12 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
                                                             true,
                                                             true};
 
+    // Aggregate strikethrough-style-properties from mModel
+    const StrikethroughStyleProperties modelStrikethroughProperties{mModel->GetStrikethroughColor(),
+                                                                    mModel->GetStrikethroughHeight(),
+                                                                    true,
+                                                                    true};
+
     // Get the underline runs.
     const Length               numberOfUnderlineRuns = mModel->GetNumberOfUnderlineRuns();
     Vector<UnderlinedGlyphRun> underlineRuns;
@@ -931,16 +911,17 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
     strikethroughRuns.Resize(numberOfStrikethroughRuns);
     mModel->GetStrikethroughRuns(strikethroughRuns.Begin(), 0u, numberOfStrikethroughRuns);
 
-    bool thereAreUnderlinedGlyphs = false;
-    bool strikethroughGlyphsExist = false;
+    bool thereAreUnderlinedGlyphs    = false;
+    bool thereAreStrikethroughGlyphs = false;
 
     float currentUnderlinePosition   = 0.0f;
     float currentUnderlineHeight     = modelUnderlineProperties.height;
     float maxUnderlineHeight         = currentUnderlineHeight;
     auto  currentUnderlineProperties = modelUnderlineProperties;
 
-    float currentStrikethroughHeight     = strikethroughHeight;
+    float currentStrikethroughHeight     = modelStrikethroughProperties.height;
     float maxStrikethroughHeight         = currentStrikethroughHeight;
+    auto  currentStrikethroughProperties = modelStrikethroughProperties;
     float strikethroughStartingYPosition = 0.0f;
 
     FontId lastFontId = 0;
@@ -1008,9 +989,11 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
       currentUnderlineHeight                                                = currentUnderlineProperties.height;
       thereAreUnderlinedGlyphs                                              = thereAreUnderlinedGlyphs || underlineGlyph;
 
-      currentStrikethroughColor     = strikethroughColor;
-      const bool strikethroughGlyph = strikethroughEnabled || doGlyphHaveStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughColor);
-      strikethroughGlyphsExist      = strikethroughGlyphsExist || strikethroughGlyph;
+      Vector<StrikethroughGlyphRun>::ConstIterator currentStrikethroughGlyphRunIt = strikethroughRuns.End();
+      const bool                                   strikethroughGlyph             = strikethroughEnabled || IsGlyphStrikethrough(glyphIndex, strikethroughRuns, currentStrikethroughGlyphRunIt);
+      currentStrikethroughProperties                                              = GetCurrentStrikethroughProperties(glyphIndex, strikethroughGlyph, strikethroughRuns, currentStrikethroughGlyphRunIt, modelStrikethroughProperties);
+      currentStrikethroughHeight                                                  = currentStrikethroughProperties.height;
+      thereAreStrikethroughGlyphs                                                 = thereAreStrikethroughGlyphs || strikethroughGlyph;
 
       // Are we still using the same fontId as previous
       if((glyphInfo->fontId != lastFontId) && (strikethroughGlyph || underlineGlyph))
@@ -1163,11 +1146,11 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer(const unsigned int bufferWidth,
     }
 
     // Draw the strikethrough from the leftmost glyph to the rightmost glyph
-    if(strikethroughGlyphsExist && style == Typesetter::STYLE_STRIKETHROUGH)
+    if(thereAreStrikethroughGlyphs && style == Typesetter::STYLE_STRIKETHROUGH)
     {
       //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, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, strikethroughStartingYPosition);
+      DrawStrikethrough(bufferWidth, bufferHeight, glyphData, baseline, strikethroughStartingYPosition, maxStrikethroughHeight, lineExtentLeft, lineExtentRight, modelStrikethroughProperties, currentStrikethroughProperties, line);
     }
 
     // Increases the vertical offset with the line's descender.
index 3f0e1f4..66214b7 100644 (file)
@@ -23,6 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/internal/text/strikethrough-style-properties.h>
 
 namespace Dali
 {
@@ -35,9 +36,17 @@ namespace Text
  */
 struct StrikethroughCharacterRun
 {
-  CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
-  Vector4      color;        ///< The color of strikethrough.
-  bool         isColorSet;   ///< If the color of strikethrough is set.
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  StrikethroughCharacterRun()
+  : characterRun{},
+    properties{}
+  {
+  }
+
+  CharacterRun                 characterRun; ///< The initial character index and the number of characters of the run.
+  StrikethroughStyleProperties properties;   /// The properties of strikethrough style
 };
 
 } // namespace Text
index 34be0af..61536bc 100644 (file)
@@ -23,6 +23,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/glyph-run.h>
+#include <dali-toolkit/internal/text/strikethrough-style-properties.h>
 
 namespace Dali
 {
@@ -35,9 +36,17 @@ namespace Text
  */
 struct StrikethroughGlyphRun
 {
-  GlyphRun glyphRun;   ///< The initial glyph index and the number of glyphs in the run.
-  Vector4  color;      ///< The color of strikethrough.
-  bool     isColorSet; ///< If the color of strikethrough is set.
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  StrikethroughGlyphRun()
+  : glyphRun{},
+    properties{}
+  {
+  }
+
+  GlyphRun                     glyphRun;   ///< The initial glyph index and the number of glyphs in the run.
+  StrikethroughStyleProperties properties; /// The properties of strikethrough style
 };
 
 } // namespace Text
diff --git a/dali-toolkit/internal/text/strikethrough-style-properties.h b/dali-toolkit/internal/text/strikethrough-style-properties.h
new file mode 100644 (file)
index 0000000..79597c9
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef DALI_TOOLKIT_TEXT_STRIKETHROUGH_STYLE_PROPERTIES_H
+#define DALI_TOOLKIT_TEXT_STRIKETHROUGH_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>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+/**
+ * @brief Properties of strikethrough style.
+ */
+struct StrikethroughStyleProperties
+{
+  // Constructors
+
+  /**
+   * Default constructor to set the default values of bitfields
+   */
+  StrikethroughStyleProperties()
+  : color{Color::BLACK},
+    height{0u},
+    colorDefined{false},
+    heightDefined{false}
+  {
+  }
+
+  StrikethroughStyleProperties(Vector4 color,
+                               float   height,
+                               bool    colorDefined,
+                               bool    heightDefined)
+  : color{color},
+    height{height},
+    colorDefined{colorDefined},
+    heightDefined{heightDefined}
+
+  {
+  }
+
+  // Overloading operators
+
+  bool operator==(const StrikethroughStyleProperties& other) const
+  {
+    //The property is similar when both are not defined or when both are defined and have the same value.
+    return ((!colorDefined && !other.colorDefined) || ((colorDefined && other.colorDefined) && (color == other.color))) &&
+           ((!heightDefined && !other.heightDefined) || ((heightDefined && other.heightDefined) && (height == other.height)));
+  }
+
+  bool operator!=(const StrikethroughStyleProperties& other) const
+  {
+    return !(*this == other);
+  }
+
+  bool IsHeightEqualTo(const StrikethroughStyleProperties& other) const
+  {
+    return ((!heightDefined && !other.heightDefined) || ((heightDefined && other.heightDefined) && (height == other.height)));
+  }
+
+  StrikethroughStyleProperties& CopyIfNotDefined(const StrikethroughStyleProperties& other)
+  {
+    //Copy only the defined properties in other and not defined in this from other to this
+
+    if(!heightDefined && other.heightDefined)
+    {
+      height        = other.height;
+      heightDefined = true;
+    }
+
+    if(!colorDefined && other.colorDefined)
+    {
+      color        = other.color;
+      colorDefined = true;
+    }
+
+    // to chain this method
+    return *this;
+  }
+
+  StrikethroughStyleProperties& OverrideByDefinedProperties(const StrikethroughStyleProperties& other)
+  {
+    //Copy only the defined properties in other from other to this
+
+    if(other.heightDefined)
+    {
+      height        = other.height;
+      heightDefined = true;
+    }
+
+    if(other.colorDefined)
+    {
+      color        = other.color;
+      colorDefined = true;
+    }
+
+    // to chain this method
+    return *this;
+  }
+
+  //Attributes
+  Vector4 color;  ///< The color of strikethrough.
+  float   height; ///< The height of strikethrough.
+
+  bool colorDefined : 1;  ///< Whether the color is defined.
+  bool heightDefined : 1; ///< Whether the height is defined.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_STRIKETHROUGH_STYLE_PROPERTIES_H
index 72bfcde..a129c5e 100644 (file)
@@ -44,6 +44,18 @@ struct BackgroundMesh
 };
 } // unnamed namespace
 
+Length CalculateBackgroundLineHeight(LineRun lineRun)
+{
+  Length height = lineRun.ascender + -(lineRun.descender);
+
+  if(lineRun.lineSpacing > 0)
+  {
+    height += lineRun.lineSpacing;
+  }
+
+  return height;
+}
+
 Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr& textVisualModel, const LogicalModelPtr& textLogicalModel, Shader& textShaderBackground)
 {
   // NOTE: Currently we only support background color for left-to-right text.
@@ -110,11 +122,16 @@ Actor CreateControllerBackgroundActor(const View& textView, const VisualModelPtr
       const Vector4&   backgroundColor          = isDefaultBackgroundColor ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
 
       textVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
-      Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
+      Length lineHeight = CalculateBackgroundLineHeight(lineRun[lineIndex]);
 
       if(lineIndex != prevLineIndex)
       {
-        yLineOffset += lineHeight;
+        yLineOffset += CalculateBackgroundLineHeight(lineRun[prevLineIndex]);
+
+        if(lineRun[prevLineIndex].lineSpacing < 0)
+        {
+          yLineOffset += lineRun[prevLineIndex].lineSpacing;
+        }
       }
 
       // Only create quads for glyphs with a background color
index cf49df5..e97535c 100644 (file)
@@ -1679,8 +1679,7 @@ void Controller::Impl::CopyStrikethroughFromLogicalToVisualModels()
     }
 
     StrikethroughGlyphRun strikethroughGlyphRun;
-    strikethroughGlyphRun.color                   = it->color;
-    strikethroughGlyphRun.isColorSet              = it->isColorSet;
+    strikethroughGlyphRun.properties              = it->properties;
     strikethroughGlyphRun.glyphRun.glyphIndex     = charactersToGlyph[characterIndex];
     strikethroughGlyphRun.glyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex];
 
index 7ac183e..410d638 100644 (file)
@@ -155,6 +155,8 @@ public:
       PAGE_DOWN, ///< Move keyboard focus towards the next page direction @SINCE_1_2.14
       FORWARD,   ///< Move keyboard focus towards the forward direction @SINCE_2_1.10
       BACKWARD,  ///< Move keyboard focus towards the backward direction @SINCE_2_1.10
+      CLOCKWISE,  ///< Move keyboard focus towards the clockwise direction @SINCE_2_1.14
+      COUNTER_CLOCKWISE,  ///< Move keyboard focus towards the counter clockwise direction @SINCE_2_1.14
     };
   };
 
index cb55cd0..9323093 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 = 14;
+const unsigned int TOOLKIT_MICRO_VERSION = 15;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 74dfe63..3e50c92 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.1.14
+Version:    2.1.15
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT