add support for background markup tag 73/259073/11
authorabdullah <abdullahhasan10@gmail.com>
Mon, 31 May 2021 14:38:06 +0000 (17:38 +0300)
committerBowon Ryu <bowon.ryu@samsung.com>
Thu, 24 Jun 2021 08:20:53 +0000 (17:20 +0900)
using namespace Dali;
using namespace Dali::Toolkit;

class SimpleApp : public ConnectionTracker
{
public:
  SimpleApp(Application& application)
  : mApplication(application)
  {
    mApplication.InitSignal().Connect(this, &SimpleApp::Create);
  }

  void Create(Application& application)
  {
    Window window = mApplication.GetWindow();
    mEditor = TextEditor::New();
    mEditor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER);
    mEditor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
    mEditor.SetProperty(Actor::Property::POSITION, Vector3(0.f, 0.0f, 0.f));
    mEditor.SetProperty(Actor::Property::SIZE, Vector2(300, 300.0f));
    window.SetBackgroundColor(Vector4(0.04f, 0.345f, 0.392f, 1.0f));
    mEditor.SetProperty(TextEditor::Property::POINT_SIZE, 26.f);
    mEditor.SetProperty(TextEditor::Property::ENABLE_MARKUP, true);
    mEditor.SetProperty(TextEditor::Property::TEXT, "<background color='red'>W</background><background color='blue'>oo</background>d");
    window.Add(mEditor);
  }

private:
  Application& mApplication;
  TextEditor mEditor;
};

int DALI_EXPORT_API main(int argc, char** argv)
{
  Application application = Application::New(&argc, &argv);
  SimpleApp test(application);
  application.MainLoop();

  return 0;
}

Change-Id: Ib3259932cb1bf0efc3f8690e7bdcdd8ca37423fd

24 files changed:
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextEditor-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-TextLabel-internal.cpp
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.h
dali-toolkit/internal/file.list
dali-toolkit/internal/text/markup-processor-background.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-background.h [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor.cpp
dali-toolkit/internal/text/markup-processor.h
dali-toolkit/internal/text/rendering/text-typesetter.cpp
dali-toolkit/internal/text/rendering/view-model.cpp
dali-toolkit/internal/text/rendering/view-model.h
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-text-updater.cpp
dali-toolkit/internal/text/text-model-interface.h
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h

index 0a426b0..9f77f91 100755 (executable)
@@ -112,7 +112,8 @@ void CreateTextModel( const std::string& text,
                                        logicalModel->mFontDescriptionRuns,
                                        logicalModel->mEmbeddedItems,
                                        logicalModel->mAnchors,
-                                       logicalModel->mUnderlinedCharacterRuns);
+                                       logicalModel->mUnderlinedCharacterRuns,
+                                       logicalModel->mBackgroundColorRuns);
 
   Length textSize = 0u;
   const uint8_t* utf8 = NULL;
index f46c401..1a4b5e1 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -186,7 +186,8 @@ namespace
     Vector<EmbeddedItem> items;
     Vector<Anchor> anchors;
     Vector<UnderlinedCharacterRun> underlinedCharacterRuns;
-    MarkupProcessData markupProcessData( colorRuns, fontRuns, items, anchors, underlinedCharacterRuns );
+    Vector<ColorRun> backgroundColorRuns;
+    MarkupProcessData markupProcessData( colorRuns, fontRuns, items, anchors, underlinedCharacterRuns, backgroundColorRuns );
     ProcessMarkupString( data.xHTMLEntityString, markupProcessData );
 
     for( Vector<EmbeddedItem>::Iterator it = items.Begin(),
index b19d653..73d9e12 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -167,4 +167,35 @@ int UtcDaliTextEditorFontPointSizeLargerThanAtlasPlaceholderCase(void)
   DALI_TEST_EQUALS( countAtlas, 1, TEST_LOCATION );
 
   END_TEST;
+}
+
+int UtcDaliTextEditorBackgroundTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextEditorBackgroundTag\n");
+
+  TextEditor editor = TextEditor::New();
+  DALI_TEST_CHECK( editor );
+
+  editor.SetProperty( TextEditor ::Property::ENABLE_MARKUP,  true );
+  editor.SetProperty( TextEditor::Property::TEXT, "H<background color='red'>e</background> Worl<background color='yellow'>d</background>" );
+  application.GetScene().Add( editor );
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextEditor& editorImpl = GetImpl( editor );
+  const ColorIndex* const backgroundColorIndicesBuffer = editorImpl.getController()->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;
 }
\ No newline at end of file
index 619e5f4..73fe7e2 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -251,4 +251,35 @@ int UtcDaliTextFieldFontPointSizeLargerThanAtlasPlaceholderCase(void)
 
 
   END_TEST;
+}
+
+int UtcDaliTextFieldBackgroundTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextFieldBackgroundTag\n");
+
+  TextField field = TextField::New();
+  DALI_TEST_CHECK( field );
+
+  field.SetProperty( TextField ::Property::ENABLE_MARKUP,  true );
+  field.SetProperty( TextField::Property::TEXT, "H<background color='red'>e</background> Worl<background color='yellow'>d</background>" );
+  application.GetScene().Add( field );
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextField& fieldImpl = GetImpl( field );
+  const ColorIndex* const backgroundColorIndicesBuffer = fieldImpl.getController()->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;
 }
\ No newline at end of file
index e85ea21..f67d88a 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -66,4 +66,35 @@ int UtcDaliTextLabelMarkupUnderline(void)
 
   END_TEST;
 
+}
+
+int UtcDaliTextLabelBackgroundTag(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliTextLabelBackgroundTag\n");
+
+  TextLabel label = TextLabel::New();
+  DALI_TEST_CHECK( label );
+
+  label.SetProperty( TextLabel ::Property::ENABLE_MARKUP,  true );
+  label.SetProperty( TextLabel::Property::TEXT, "H<background color='red'>e</background> Worl<background color='yellow'>d</background>" );
+  application.GetScene().Add( label );
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextLabel& labelImpl = GetImpl( label );
+  const ColorIndex* const backgroundColorIndicesBuffer = labelImpl.getController()->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;
 }
\ No newline at end of file
index a4dbce4..99ff139 100644 (file)
@@ -174,7 +174,8 @@ void ShapeTextPreprocess(const RendererParameters& textParameters, TextAbstracti
                                       fontDescriptionRuns,
                                       textModel->mLogicalModel->mEmbeddedItems,
                                       textModel->mLogicalModel->mAnchors,
-                                      textModel->mLogicalModel->mUnderlinedCharacterRuns);
+                                      textModel->mLogicalModel->mUnderlinedCharacterRuns,
+                                      textModel->mLogicalModel->mBackgroundColorRuns);
 
   if(textParameters.markupEnabled)
   {
index 9b9e7d9..db7096a 100644 (file)
@@ -1560,16 +1560,50 @@ void TextEditor::RenderText(Text::Controller::UpdateTextType updateTextType)
 
     if(renderableActor != mRenderableActor)
     {
+      UnparentAndReset(mBackgroundActor);
       UnparentAndReset(mRenderableActor);
       mRenderableActor = renderableActor;
+
+      if(mRenderableActor)
+      {
+        mBackgroundActor = mController->CreateBackgroundActor();
+      }
     }
   }
 
   if(mRenderableActor)
   {
+    const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
+
+    float renderableActorPositionX, renderableActorPositionY;
+
+    if(mStencil)
+    {
+      renderableActorPositionX = scrollOffset.x + mAlignmentOffset;
+      renderableActorPositionY = scrollOffset.y;
+    }
+    else
+    {
+      Extents padding;
+      padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
+
+      // Support Right-To-Left of padding
+      Dali::LayoutDirection::Type layoutDirection = static_cast<Dali::LayoutDirection::Type>(Self().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+      if(Dali::LayoutDirection::RIGHT_TO_LEFT == layoutDirection)
+      {
+        std::swap(padding.start, padding.end);
+      }
+
+      renderableActorPositionX = scrollOffset.x + mAlignmentOffset + padding.start;
+      renderableActorPositionY = scrollOffset.y + padding.top;
+    }
+
+    mRenderableActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY));
     // Make sure the actors are parented correctly with/without clipping
     Actor self = mStencil ? mStencil : Self();
 
+    Actor highlightActor;
+
     for(std::vector<Actor>::iterator it    = mClippingDecorationActors.begin(),
                                      endIt = mClippingDecorationActors.end();
         it != endIt;
@@ -1577,11 +1611,32 @@ void TextEditor::RenderText(Text::Controller::UpdateTextType updateTextType)
     {
       self.Add(*it);
       it->LowerToBottom();
+
+      if(it->GetProperty<std::string>(Dali::Actor::Property::NAME) == "HighlightActor")
+      {
+        highlightActor = *it;
+      }
     }
     mClippingDecorationActors.clear();
 
     self.Add(mRenderableActor);
 
+    if(mBackgroundActor)
+    {
+      if(mDecorator && mDecorator->IsHighlightVisible())
+      {
+        self.Add(mBackgroundActor);
+        mBackgroundActor.SetProperty(Actor::Property::POSITION, Vector2(renderableActorPositionX, renderableActorPositionY)); // In text field's coords.
+        mBackgroundActor.LowerBelow(highlightActor);
+      }
+      else
+      {
+        mRenderableActor.Add(mBackgroundActor);
+        mBackgroundActor.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f)); // In renderable actor's coords.
+        mBackgroundActor.LowerToBottom();
+      }
+    }
+
     ApplyScrollPosition();
   }
   UpdateScrollBar();
@@ -2323,7 +2378,7 @@ Dali::Accessibility::States TextEditor::AccessibleImpl::CalculateStates()
   return states;
 }
 
-bool TextEditor::AccessibleImpl::InsertText(size_t startPosition,
+bool TextEditor::AccessibleImpl::InsertText(size_t      startPosition,
                                             std::string text)
 {
   auto slf = Toolkit::TextEditor::DownCast(Self());
index 9a06ea5..0286da2 100644 (file)
@@ -413,6 +413,7 @@ private: // Data
 
   Actor         mRenderableActor;
   Actor         mActiveLayer;
+  Actor         mBackgroundActor;
   CallbackBase* mIdleCallback;
 
   float mAlignmentOffset;
index eca4322..f712e9f 100644 (file)
@@ -136,6 +136,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/markup-processor-embedded-item.cpp
    ${toolkit_src_dir}/text/markup-processor-anchor.cpp
    ${toolkit_src_dir}/text/markup-processor-font.cpp
+   ${toolkit_src_dir}/text/markup-processor-background.cpp
    ${toolkit_src_dir}/text/markup-processor-helper-functions.cpp
    ${toolkit_src_dir}/text/multi-language-support.cpp
    ${toolkit_src_dir}/text/hidden-text.cpp
diff --git a/dali-toolkit/internal/text/markup-processor-background.cpp b/dali-toolkit/internal/text/markup-processor-background.cpp
new file mode 100644 (file)
index 0000000..8a9910e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-background.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <memory.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+namespace
+{
+const std::string XHTML_COLOR_ATTRIBUTE("color");
+} // namespace
+
+void ProcessBackground(const Tag& tag, ColorRun& colorRun)
+{
+  for(auto&& attribute : tag.attributes)
+  {
+    if(TokenComparison(XHTML_COLOR_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength))
+    {
+      ColorStringToVector4(attribute.valueBuffer, attribute.valueLength, colorRun.color);
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-toolkit/internal/text/markup-processor-background.h b/dali-toolkit/internal/text/markup-processor-background.h
new file mode 100644 (file)
index 0000000..331d2c8
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
+#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Text
+{
+struct Tag;
+struct ColorRun;
+
+/**
+ * @brief Retrieves the @e background from the @p tag.
+ *
+ * @param[in] tag The background tag and its attributes.
+ * @param[in,out] colorRun The color run to be filled.
+ */
+void ProcessBackground(const Tag& tag, ColorRun& colorRun);
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_BACKGROUND_H
\ No newline at end of file
index ea7f869..6fef092 100644 (file)
@@ -26,6 +26,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 #include <dali-toolkit/internal/text/markup-processor-anchor.h>
+#include <dali-toolkit/internal/text/markup-processor-background.h>
 #include <dali-toolkit/internal/text/markup-processor-color.h>
 #include <dali-toolkit/internal/text/markup-processor-embedded-item.h>
 #include <dali-toolkit/internal/text/markup-processor-font.h>
@@ -53,6 +54,7 @@ const std::string XHTML_GLOW_TAG("glow");
 const std::string XHTML_OUTLINE_TAG("outline");
 const std::string XHTML_ITEM_TAG("item");
 const std::string XHTML_ANCHOR_TAG("a");
+const std::string XHTML_BACKGROUND_TAG("background");
 
 const char LESS_THAN      = '<';
 const char GREATER_THAN   = '>';
@@ -631,12 +633,14 @@ void ProcessAnchorTag(
  * @param[in] fontRunIndex The font run index
  * @param[in] colorRunIndex The color run index
  * @param[in] underlinedCharacterRunIndex The underlined character run index
+ * @param[in] backgroundRunIndex The background run index
  */
-void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex, const StyleStack::RunIndex underlinedCharacterRunIndex)
+void ResizeModelVectors(MarkupProcessData& markupProcessData, const StyleStack::RunIndex fontRunIndex, const StyleStack::RunIndex colorRunIndex, const StyleStack::RunIndex underlinedCharacterRunIndex, const StyleStack::RunIndex backgroundRunIndex)
 {
   markupProcessData.fontRuns.Resize(fontRunIndex);
   markupProcessData.colorRuns.Resize(colorRunIndex);
   markupProcessData.underlinedCharacterRuns.Resize(underlinedCharacterRunIndex);
+  markupProcessData.backgroundColorRuns.Resize(backgroundRunIndex);
 
 #ifdef DEBUG_ENABLED
   for(unsigned int i = 0; i < colorRunIndex; ++i)
@@ -753,21 +757,24 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   StyleStack styleStack;
 
   // Points the next free position in the vector of runs.
-  StyleStack::RunIndex colorRunIndex                = 0u;
-  StyleStack::RunIndex fontRunIndex                 = 0u;
-  StyleStack::RunIndex underlinedCharacterRunIndex  = 0u;
+  StyleStack::RunIndex colorRunIndex               = 0u;
+  StyleStack::RunIndex fontRunIndex                = 0u;
+  StyleStack::RunIndex underlinedCharacterRunIndex = 0u;
+  StyleStack::RunIndex backgroundRunIndex          = 0u;
 
   // check tag reference
-  int colorTagReference = 0u;
-  int fontTagReference  = 0u;
-  int iTagReference     = 0u;
-  int bTagReference     = 0u;
-  int uTagReference     = 0u;
+  int colorTagReference      = 0u;
+  int fontTagReference       = 0u;
+  int iTagReference          = 0u;
+  int bTagReference          = 0u;
+  int uTagReference          = 0u;
+  int backgroundTagReference = 0u;
 
   // Give an initial default value to the model's vectors.
   markupProcessData.colorRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.fontRuns.Reserve(DEFAULT_VECTOR_SIZE);
   markupProcessData.underlinedCharacterRuns.Reserve(DEFAULT_VECTOR_SIZE);
+  markupProcessData.backgroundColorRuns.Reserve(DEFAULT_VECTOR_SIZE);
 
   // Get the mark-up string buffer.
   const char*       markupStringBuffer    = markupString.c_str();
@@ -798,8 +805,8 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
       else if(TokenComparison(XHTML_U_TAG, tag.buffer, tag.length))
       {
         ProcessTagForRun<UnderlinedCharacterRun>(
-          markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) {  });
-      }  // <u></u>
+          markupProcessData.underlinedCharacterRuns, styleStack, tag, characterIndex, underlinedCharacterRunIndex, uTagReference, [](const Tag& tag, UnderlinedCharacterRun& run) {});
+      } // <u></u>
       else if(TokenComparison(XHTML_B_TAG, tag.buffer, tag.length))
       {
         ProcessTagForRun<FontDescriptionRun>(
@@ -844,6 +851,11 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
       {
         ProcessItemTag(markupProcessData, tag, characterIndex);
       }
+      else if(TokenComparison(XHTML_BACKGROUND_TAG, tag.buffer, tag.length))
+      {
+        ProcessTagForRun<ColorRun>(
+          markupProcessData.backgroundColorRuns, styleStack, tag, characterIndex, backgroundRunIndex, backgroundTagReference, [](const Tag& tag, ColorRun& run) { ProcessBackground(tag, run); });
+      }
     } // end if( IsTag() )
     else if(markupStringBuffer < markupStringEndBuffer)
     {
@@ -852,7 +864,7 @@ void ProcessMarkupString(const std::string& markupString, MarkupProcessData& mar
   }
 
   // Resize the model's vectors.
-  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex);
+  ResizeModelVectors(markupProcessData, fontRunIndex, colorRunIndex, underlinedCharacterRunIndex, backgroundRunIndex);
 }
 
 } // namespace Text
index ec45957..e84b892 100644 (file)
@@ -40,16 +40,18 @@ namespace Text
  */
 struct MarkupProcessData
 {
-  MarkupProcessData(Vector<ColorRun>&           colorRuns,
-                    Vector<FontDescriptionRun>& fontRuns,
-                    Vector<EmbeddedItem>&       items,
-                    Vector<Anchor>&             anchors,
-                    Vector<UnderlinedCharacterRun>& underlinedCharacterRuns)
+  MarkupProcessData(Vector<ColorRun>&               colorRuns,
+                    Vector<FontDescriptionRun>&     fontRuns,
+                    Vector<EmbeddedItem>&           items,
+                    Vector<Anchor>&                 anchors,
+                    Vector<UnderlinedCharacterRun>& underlinedCharacterRuns,
+                    Vector<ColorRun>&               backgroundColorRuns)
   : colorRuns(colorRuns),
     fontRuns(fontRuns),
     items(items),
     anchors(anchors),
     underlinedCharacterRuns(underlinedCharacterRuns),
+    backgroundColorRuns(backgroundColorRuns),
     markupProcessedText()
   {
   }
@@ -59,6 +61,7 @@ struct MarkupProcessData
   Vector<EmbeddedItem>&           items;                   ///< The embedded items.
   Vector<Anchor>&                 anchors;                 ///< The anchors.
   Vector<UnderlinedCharacterRun>& underlinedCharacterRuns; ///< The underlined character runs.
+  Vector<ColorRun>&               backgroundColorRuns;     ///< The background color runs.
   std::string                     markupProcessedText;     ///< The mark-up string.
 };
 
index 83d67d5..17a5c61 100644 (file)
@@ -417,6 +417,116 @@ void DrawBackgroundColor(
   }
 }
 
+Devel::PixelBuffer DrawGlyphsBackground(const ViewModel* model, Devel::PixelBuffer& buffer, const unsigned int bufferWidth, const unsigned int bufferHeight, bool ignoreHorizontalAlignment, int horizontalOffset, int verticalOffset)
+{
+  // Retrieve lines, glyphs, positions and colors from the view model.
+  const Length            modelNumberOfLines           = model->GetNumberOfLines();
+  const LineRun* const    modelLinesBuffer             = model->GetLines();
+  const Length            numberOfGlyphs               = model->GetNumberOfGlyphs();
+  const GlyphInfo* const  glyphsBuffer                 = model->GetGlyphs();
+  const Vector2* const    positionBuffer               = model->GetLayout();
+  const Vector4* const    backgroundColorsBuffer       = model->GetBackgroundColors();
+  const ColorIndex* const backgroundColorIndicesBuffer = model->GetBackgroundColorIndices();
+
+  // Create and initialize the pixel buffer.
+  GlyphData glyphData;
+  glyphData.verticalOffset   = verticalOffset;
+  glyphData.width            = bufferWidth;
+  glyphData.height           = bufferHeight;
+  glyphData.bitmapBuffer     = buffer;
+  glyphData.horizontalOffset = 0;
+
+  ColorIndex prevBackgroundColorIndex = 0;
+  ColorIndex backgroundColorIndex     = 0;
+
+  // Traverses the lines of the text.
+  for(LineIndex lineIndex = 0u; lineIndex < modelNumberOfLines; ++lineIndex)
+  {
+    const LineRun& line = *(modelLinesBuffer + lineIndex);
+
+    // Sets the horizontal offset of the line.
+    glyphData.horizontalOffset = ignoreHorizontalAlignment ? 0 : static_cast<int>(line.alignmentOffset);
+    glyphData.horizontalOffset += horizontalOffset;
+
+    // Increases the vertical offset with the line's ascender.
+    glyphData.verticalOffset += static_cast<int>(line.ascender);
+
+    // Include line spacing after first line
+    if(lineIndex > 0u)
+    {
+      glyphData.verticalOffset += static_cast<int>(line.lineSpacing);
+    }
+
+    float left     = bufferWidth;
+    float right    = 0.0f;
+    float baseline = 0.0f;
+
+    // Traverses the glyphs of the line.
+    const GlyphIndex endGlyphIndex = std::min(numberOfGlyphs, line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs);
+    for(GlyphIndex glyphIndex = line.glyphRun.glyphIndex; glyphIndex < endGlyphIndex; ++glyphIndex)
+    {
+      // Retrieve the glyph's info.
+      const GlyphInfo* const glyphInfo = glyphsBuffer + glyphIndex;
+
+      if((glyphInfo->width < Math::MACHINE_EPSILON_1000) ||
+         (glyphInfo->height < Math::MACHINE_EPSILON_1000))
+      {
+        // Nothing to do if default background color, the glyph's width or height is zero.
+        continue;
+      }
+
+      backgroundColorIndex = (nullptr == backgroundColorsBuffer) ? 0u : *(backgroundColorIndicesBuffer + glyphIndex);
+
+      if((backgroundColorIndex != prevBackgroundColorIndex) &&
+         (prevBackgroundColorIndex != 0u))
+      {
+        const Vector4& backgroundColor = *(backgroundColorsBuffer + prevBackgroundColorIndex - 1u);
+        DrawBackgroundColor(backgroundColor, bufferWidth, bufferHeight, glyphData, baseline, line, left, right);
+      }
+
+      if(backgroundColorIndex == 0u)
+      {
+        prevBackgroundColorIndex = backgroundColorIndex;
+        //if background color is the default do nothing
+        continue;
+      }
+
+      // Retrieves the glyph's position.
+      const Vector2* const position = positionBuffer + glyphIndex;
+
+      if(baseline < position->y + glyphInfo->yBearing)
+      {
+        baseline = position->y + glyphInfo->yBearing;
+      }
+
+      // Calculate the positions of leftmost and rightmost glyphs in the current line
+      if((position->x < left) || (backgroundColorIndex != prevBackgroundColorIndex))
+      {
+        left = position->x - glyphInfo->xBearing;
+      }
+
+      if(position->x + glyphInfo->width > right)
+      {
+        right = position->x - glyphInfo->xBearing + glyphInfo->advance;
+      }
+
+      prevBackgroundColorIndex = backgroundColorIndex;
+    }
+
+    //draw last background at line end if not default
+    if(backgroundColorIndex != 0u)
+    {
+      const Vector4& backgroundColor = *(backgroundColorsBuffer + backgroundColorIndex - 1u);
+      DrawBackgroundColor(backgroundColor, bufferWidth, bufferHeight, glyphData, baseline, line, left, right);
+    }
+
+    // Increases the vertical offset with the line's descender.
+    glyphData.verticalOffset += static_cast<int>(-line.descender);
+  }
+
+  return glyphData.bitmapBuffer;
+}
+
 } // namespace
 
 TypesetterPtr Typesetter::New(const ModelInterface* const model)
@@ -587,10 +697,25 @@ PixelData Typesetter::Render(const Vector2& size, Toolkit::DevelText::TextDirect
     }
 
     // Generate the background if enabled
-    const bool backgroundEnabled = mModel->IsBackgroundEnabled();
-    if(backgroundEnabled)
+    const bool backgroundEnabled   = mModel->IsBackgroundEnabled();
+    const bool backgroundMarkupSet = mModel->IsMarkupBackgroundColorSet();
+    if(backgroundEnabled || backgroundMarkupSet)
     {
-      Devel::PixelBuffer backgroundImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_BACKGROUND, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1);
+      Devel::PixelBuffer backgroundImageBuffer;
+
+      if(backgroundEnabled)
+      {
+        backgroundImageBuffer = CreateImageBuffer(bufferWidth, bufferHeight, Typesetter::STYLE_BACKGROUND, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs - 1);
+      }
+      else
+      {
+        backgroundImageBuffer = Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat);
+      }
+
+      if(backgroundMarkupSet)
+      {
+        DrawGlyphsBackground(mModel, backgroundImageBuffer, bufferWidth, bufferHeight, ignoreHorizontalAlignment, penX, penY);
+      }
 
       // Combine the two buffers
       imageBuffer = CombineImageBuffer(imageBuffer, backgroundImageBuffer, bufferWidth, bufferHeight);
index f695cd2..4ad0b14 100644 (file)
@@ -160,6 +160,11 @@ const ColorIndex* const ViewModel::GetBackgroundColorIndices() const
   return mModel->GetBackgroundColorIndices();
 }
 
+bool const ViewModel::IsMarkupBackgroundColorSet() const
+{
+  return mModel->IsMarkupBackgroundColorSet();
+}
+
 const Vector4& ViewModel::GetDefaultColor() const
 {
   return mModel->GetDefaultColor();
index 9272956..e51a075 100644 (file)
@@ -146,6 +146,11 @@ public:
   const ColorIndex* const GetBackgroundColorIndices() const override;
 
   /**
+   * @copydoc ModelInterface::IsMarkupBackgroundColorSet()
+   */
+  bool const IsMarkupBackgroundColorSet() const override;
+
+  /**
    * @copydoc ModelInterface::GetDefaultColor()
    */
   const Vector4& GetDefaultColor() const override;
index 417eaed..a513d70 100644 (file)
@@ -847,7 +847,7 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
     mModel->mVisualModel->CreateGlyphsPerCharacterTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
     mModel->mVisualModel->CreateCharacterToGlyphTable(startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters);
 
-   updated = true;
+    updated = true;
   }
 
   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
@@ -1056,9 +1056,9 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
   }
 
   if((NO_OPERATION != (SHAPE_TEXT & operations)) &&
-      ! ((nullptr != mEventData) &&
-         mEventData->mPreEditFlag &&
-         (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
+     !((nullptr != mEventData) &&
+       mEventData->mPreEditFlag &&
+       (0u != mModel->mVisualModel->mCharactersToGlyph.Count())))
   {
     //Mark-up processor case
     if(mModel->mVisualModel->IsMarkupProcessorEnabled())
@@ -1069,7 +1069,6 @@ bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
     updated = true;
   }
 
-
   // The estimated number of lines. Used to avoid reallocations when layouting.
   mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
 
@@ -2018,8 +2017,7 @@ void Controller::Impl::RequestRelayout()
 
 Actor Controller::Impl::CreateBackgroundActor()
 {
-  // NOTE: Currently we only support background color for one line left-to-right text,
-  //       so the following calculation is based on one line left-to-right text only!
+  // NOTE: Currently we only support background color for left-to-right text.
 
   Actor actor;
 
@@ -2060,8 +2058,12 @@ Actor Controller::Impl::CreateBackgroundActor()
     const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
     const Vector4&          defaultBackgroundColor       = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
 
-    Vector4  quad;
-    uint32_t numberOfQuads = 0u;
+    Vector4   quad;
+    uint32_t  numberOfQuads = 0u;
+    Length    yLineOffset   = 0;
+    Length    prevLineIndex = 0;
+    LineIndex lineIndex;
+    Length    numberOfLines;
 
     for(uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i)
     {
@@ -2072,6 +2074,14 @@ Actor Controller::Impl::CreateBackgroundActor()
       const ColorIndex backgroundColorIndex = (nullptr == backgroundColorsBuffer) ? 0u : *(backgroundColorIndicesBuffer + i);
       const Vector4&   backgroundColor      = (0u == backgroundColorIndex) ? defaultBackgroundColor : *(backgroundColorsBuffer + backgroundColorIndex - 1u);
 
+      mModel->mVisualModel->GetNumberOfLines(i, 1, lineIndex, numberOfLines);
+      Length lineHeight = lineRun[lineIndex].ascender + -(lineRun[lineIndex].descender) + lineRun[lineIndex].lineSpacing;
+
+      if(lineIndex != prevLineIndex)
+      {
+        yLineOffset += lineHeight;
+      }
+
       // Only create quads for glyphs with a background color
       if(backgroundColor != Color::TRANSPARENT)
       {
@@ -2080,30 +2090,30 @@ Actor Controller::Impl::CreateBackgroundActor()
         if(i == 0u && glyphSize == 1u) // Only one glyph in the whole text
         {
           quad.x = position.x;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
-          quad.w = textSize.height;
+          quad.w = lineHeight;
         }
-        else if(i == 0u) // The first glyph in the whole text
+        else if((lineIndex != prevLineIndex) || (i == 0u)) // The first glyph in the line
         {
           quad.x = position.x;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x - glyph.xBearing + glyph.advance;
-          quad.w = textSize.height;
+          quad.w = quad.y + lineHeight;
         }
         else if(i == glyphSize - 1u) // The last glyph in the whole text
         {
           quad.x = position.x - glyph.xBearing;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x + std::max(glyph.advance, glyph.xBearing + glyph.width);
-          quad.w = textSize.height;
+          quad.w = quad.y + lineHeight;
         }
         else // The glyph in the middle of the text
         {
           quad.x = position.x - glyph.xBearing;
-          quad.y = 0.0f;
+          quad.y = yLineOffset;
           quad.z = quad.x + glyph.advance;
-          quad.w = textSize.height;
+          quad.w = quad.y + lineHeight;
         }
 
         BackgroundVertex vertex;
@@ -2142,6 +2152,11 @@ Actor Controller::Impl::CreateBackgroundActor()
 
         numberOfQuads++;
       }
+
+      if(lineIndex != prevLineIndex)
+      {
+        prevLineIndex = lineIndex;
+      }
     }
 
     // Only create the background actor if there are glyphs with background color
@@ -2182,28 +2197,28 @@ Actor Controller::Impl::CreateBackgroundActor()
 
 void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearPreUnderlineRuns)
 {
-    //Underlined character runs for markup-processor
-    const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
-    const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
-    const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
+  //Underlined character runs for markup-processor
+  const Vector<UnderlinedCharacterRun>& underlinedCharacterRuns = mModel->mLogicalModel->mUnderlinedCharacterRuns;
+  const Vector<GlyphIndex>&             charactersToGlyph       = mModel->mVisualModel->mCharactersToGlyph;
+  const Vector<Length>&                 glyphsPerCharacter      = mModel->mVisualModel->mGlyphsPerCharacter;
 
-    if(shouldClearPreUnderlineRuns)
-    {
-        mModel->mVisualModel->mUnderlineRuns.Clear();
-    }
+  if(shouldClearPreUnderlineRuns)
+  {
+    mModel->mVisualModel->mUnderlineRuns.Clear();
+  }
 
-    for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+  for(Vector<UnderlinedCharacterRun>::ConstIterator it = underlinedCharacterRuns.Begin(), endIt = underlinedCharacterRuns.End(); it != endIt; ++it)
+  {
+    CharacterIndex characterIndex     = it->characterRun.characterIndex;
+    Length         numberOfCharacters = it->characterRun.numberOfCharacters;
+    for(Length index = 0u; index < numberOfCharacters; index++)
     {
-        CharacterIndex characterIndex = it->characterRun.characterIndex;
-        Length numberOfCharacters = it->characterRun.numberOfCharacters;
-        for(Length index=0u; index<numberOfCharacters; index++)
-        {
-          GlyphRun underlineGlyphRun;
-          underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
-          underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
-          mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
-        }
+      GlyphRun underlineGlyphRun;
+      underlineGlyphRun.glyphIndex     = charactersToGlyph[characterIndex + index];
+      underlineGlyphRun.numberOfGlyphs = glyphsPerCharacter[characterIndex + index];
+      mModel->mVisualModel->mUnderlineRuns.PushBack(underlineGlyphRun);
     }
+  }
 }
 
 } // namespace Text
index 36a2133..d946365 100644 (file)
@@ -83,7 +83,8 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string&
                                         logicalModel->mFontDescriptionRuns,
                                         logicalModel->mEmbeddedItems,
                                         logicalModel->mAnchors,
-                                        logicalModel->mUnderlinedCharacterRuns);
+                                        logicalModel->mUnderlinedCharacterRuns,
+                                        logicalModel->mBackgroundColorRuns);
 
     Length         textSize = 0u;
     const uint8_t* utf8     = NULL;
index c116f8f..928c3f0 100644 (file)
@@ -174,6 +174,13 @@ public:
   virtual const ColorIndex* const GetBackgroundColorIndices() const = 0;
 
   /**
+   * @brief checks if there is background colors set using markup.
+   *
+   * @return boolean if there is background colors set using markup .
+   */
+  virtual bool const IsMarkupBackgroundColorSet() const = 0;
+
+  /**
    * @brief Retrieves the text's default color.
    *
    * @return The default color.
index 948044e..26a9be8 100644 (file)
@@ -119,6 +119,11 @@ const ColorIndex* const Model::GetBackgroundColorIndices() const
   return mVisualModel->mBackgroundColorIndices.Begin();
 }
 
+bool const Model::IsMarkupBackgroundColorSet() const
+{
+  return (mVisualModel->mBackgroundColorIndices.Count() > 0);
+}
+
 const Vector4& Model::GetDefaultColor() const
 {
   return mVisualModel->mTextColor;
index 4faa1bc..751f230 100644 (file)
@@ -143,6 +143,11 @@ public:
   const ColorIndex* const GetBackgroundColorIndices() const override;
 
   /**
+   * @copydoc ModelInterface::IsMarkupBackgroundColorSet()
+   */
+  bool const IsMarkupBackgroundColorSet() const override;
+
+  /**
    * @copydoc ModelInterface::GetDefaultColor()
    */
   const Vector4& GetDefaultColor() const override;
index 63f7fd4..ee4c306 100644 (file)
@@ -124,6 +124,13 @@ public:
   virtual const ColorIndex* const GetBackgroundColorIndices() const = 0;
 
   /**
+   * @brief checks if there is background colors set using markup.
+   *
+   * @return boolean if there is background colors set using markup .
+   */
+  virtual bool const IsMarkupBackgroundColorSet() const = 0;
+
+  /**
    * @brief Retrieves the text color
    *
    * @return The text color
index 2f74699..74a83f5 100644 (file)
@@ -343,6 +343,16 @@ const ColorIndex* const View::GetBackgroundColorIndices() const
   return nullptr;
 }
 
+bool const View::IsMarkupBackgroundColorSet() const
+{
+  if(mImpl->mVisualModel)
+  {
+    return (mImpl->mVisualModel->mBackgroundColorIndices.Count() > 0);
+  }
+
+  return false;
+}
+
 const Vector4& View::GetTextColor() const
 {
   if(mImpl->mVisualModel)
index 3790fd0..7c61275 100644 (file)
@@ -96,6 +96,11 @@ public:
   const ColorIndex* const GetBackgroundColorIndices() const override;
 
   /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::IsMarkupBackgroundColorSet()
+   */
+  bool const IsMarkupBackgroundColorSet() const;
+
+  /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetTextColor()
    */
   const Vector4& GetTextColor() const override;