Multiple text background color support for left-to-right text only in TextField 75/218675/6
authorRichard Huang <r.huang@samsung.com>
Tue, 26 Nov 2019 16:45:43 +0000 (16:45 +0000)
committerRichard Huang <r.huang@samsung.com>
Fri, 29 Nov 2019 15:02:50 +0000 (15:02 +0000)
Change-Id: I9beee6072fb72997c94b05b3d1cfebe9ee1217bb

20 files changed:
automated-tests/src/dali-toolkit-internal/CMakeLists.txt
automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp [new file with mode: 0755]
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
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-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/text/text-model-interface.h
dali-toolkit/internal/text/text-model.cpp
dali-toolkit/internal/text/text-model.h
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h
dali-toolkit/internal/text/visual-model-impl.h

index 984e177..9954a74 100755 (executable)
@@ -25,6 +25,7 @@ SET(TC_SOURCES
  utc-Dali-Text-Shaping.cpp
  utc-Dali-Text-Typesetter.cpp
  utc-Dali-Text-ViewModel.cpp
+ utc-Dali-TextField-internal.cpp
  utc-Dali-TextureManager.cpp
  utc-Dali-Visuals-internal.cpp
  utc-Dali-VisualModel.cpp
diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextField-internal.cpp
new file mode 100755 (executable)
index 0000000..5ac4ab1
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+
+#include <dali-toolkit/internal/controls/text-controls/text-field-impl.h>
+#include <dali-toolkit/internal/text/text-controller.h>
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+
+using namespace Dali;
+using namespace Toolkit;
+using namespace Text;
+
+int UtcDaliTextFieldMultipleBackgroundText(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline( "UtcDaliTextFieldMultipleBackgroundText" );
+
+  // Create a text field
+  TextField textField = TextField::New();
+  textField.SetSize( 400.f, 60.f );
+  textField.SetParentOrigin( ParentOrigin::TOP_LEFT );
+  textField.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+
+  // Add the text field to the stage
+  Stage::GetCurrent().Add( textField );
+
+  application.SendNotification();
+  application.Render();
+
+  Toolkit::Internal::TextField& textFieldImpl = GetImpl( textField );
+  ControllerPtr controller = textFieldImpl.GetTextController();
+  Controller::Impl& controllerImpl = Controller::Impl::GetImplementation( *controller.Get() );
+
+  // Add multiple background colors for the text.
+  ColorRun backgroundColorRun1;
+  backgroundColorRun1.characterRun.characterIndex = 0u;
+  backgroundColorRun1.characterRun.numberOfCharacters = 1u;
+  backgroundColorRun1.color = Color::RED;
+  controllerImpl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun1 );
+
+  ColorRun backgroundColorRun2;
+  backgroundColorRun2.characterRun.characterIndex = 5u;
+  backgroundColorRun2.characterRun.numberOfCharacters = 8u;
+  backgroundColorRun2.color = Color::CYAN;
+  controllerImpl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun2 );
+
+  ColorRun backgroundColorRun3;
+  backgroundColorRun3.characterRun.characterIndex = 23u;
+  backgroundColorRun3.characterRun.numberOfCharacters = 6u;
+  backgroundColorRun3.color = Color::GREEN;
+  controllerImpl.mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun3 );
+
+  // Check the case where there is only one character in the text
+  controller->SetText( "S" );
+
+  application.SendNotification();
+  application.Render();
+
+  // The offscreen root actor should have one child: the renderable.
+  Actor stencil = textField.GetChildAt( 0u );
+  DALI_TEST_CHECK( stencil.GetChildCount() == 1u );
+
+  // The renderable actor should have two children: the text and the background.
+  Actor renderableActor = stencil.GetChildAt( 0u );
+  DALI_TEST_CHECK( renderableActor.GetChildCount() == 2u );
+
+  // Check that the background is created
+  Actor backgroundActor = renderableActor.GetChildAt( 0u );
+  DALI_TEST_CHECK( backgroundActor );
+  DALI_TEST_CHECK( backgroundActor.GetName() == "TextBackgroundColorActor" );
+
+  // Change the text to contain more characters
+  controller->SetText( "Text Multiple Background Test" );
+
+  application.SendNotification();
+  application.Render();
+
+  // Highlight the whole text
+  textFieldImpl.SelectWholeText();
+
+  application.SendNotification();
+  application.Render();
+
+  // Now the offscreen root actor should have three children: the renderable, the highlight, and the background.
+  DALI_TEST_CHECK( stencil.GetChildCount() == 3u );
+  // The renderable actor should have one child only: the text
+  DALI_TEST_CHECK( renderableActor.GetChildCount() == 1u );
+
+  // The background should now be lowered below the highlight
+  backgroundActor = stencil.GetChildAt( 0u );
+  DALI_TEST_CHECK( backgroundActor );
+  DALI_TEST_CHECK( backgroundActor.GetName() == "TextBackgroundColorActor" );
+
+  END_TEST;
+}
index 0def1bc..6a1f1c9 100755 (executable)
@@ -1463,8 +1463,14 @@ void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
 
     if( renderableActor != mRenderableActor )
     {
+      UnparentAndReset( mBackgroundActor );
       UnparentAndReset( mRenderableActor );
       mRenderableActor = renderableActor;
+
+      if ( mRenderableActor )
+      {
+        mBackgroundActor = mController->CreateBackgroundActor();
+      }
     }
   }
 
@@ -1472,9 +1478,12 @@ void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
   {
     const Vector2& scrollOffset = mController->GetTextModel()->GetScrollPosition();
 
+    float renderableActorPositionX, renderableActorPositionY;
+
     if( mStencil )
     {
-      mRenderableActor.SetPosition( scrollOffset.x + mAlignmentOffset, scrollOffset.y );
+      renderableActorPositionX = scrollOffset.x + mAlignmentOffset;
+      renderableActorPositionY = scrollOffset.y;
     }
     else
     {
@@ -1488,13 +1497,17 @@ void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
         std::swap( padding.start, padding.end );
       }
 
-      mRenderableActor.SetPosition( scrollOffset.x + mAlignmentOffset + padding.start, scrollOffset.y + padding.top );
+      renderableActorPositionX = scrollOffset.x + mAlignmentOffset + padding.start;
+      renderableActorPositionY = scrollOffset.y + padding.top;
     }
 
+    mRenderableActor.SetPosition( 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;
@@ -1502,10 +1515,31 @@ void TextField::RenderText( Text::Controller::UpdateTextType updateTextType )
     {
       self.Add( *it );
       it->LowerToBottom();
+
+      if ( it->GetName() == "HighlightActor" )
+      {
+        highlightActor = *it;
+      }
     }
     mClippingDecorationActors.clear();
 
     self.Add( mRenderableActor );
+
+    if ( mBackgroundActor )
+    {
+      if ( mDecorator && mDecorator->IsHighlightVisible() )
+      {
+        self.Add( mBackgroundActor );
+        mBackgroundActor.SetPosition( renderableActorPositionX, renderableActorPositionY); // In text field's coords.
+        mBackgroundActor.LowerBelow( highlightActor );
+      }
+      else
+      {
+        mRenderableActor.Add( mBackgroundActor );
+        mBackgroundActor.SetPosition( 0.0f, 0.0f ); // In renderable actor's coords.
+        mBackgroundActor.LowerToBottom();
+      }
+    }
   }
 }
 
index 3b1062e..25bd4bd 100755 (executable)
@@ -268,6 +268,10 @@ private: // Implementation
   // Connection needed to re-render text, when a Text Field returns to the stage.
   void OnStageConnect( Dali::Actor actor );
 
+public: // For UTC only
+
+  Text::ControllerPtr GetTextController() { return mController; }
+
 private: // Data
 
   // Signals
@@ -285,6 +289,7 @@ private: // Data
 
   Actor mRenderableActor;
   Actor mActiveLayer;
+  Actor mBackgroundActor;
   CallbackBase* mIdleCallback;
 
   float mAlignmentOffset;
index d0f89d9..0cb8b4c 100644 (file)
@@ -1148,9 +1148,7 @@ struct Decorator::Impl : public ConnectionTracker
     {
       mHighlightActor = Actor::New();
 
-#ifdef DECORATOR_DEBUG
       mHighlightActor.SetName( "HighlightActor" );
-#endif
       mHighlightActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
       mHighlightActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
       mHighlightActor.SetColor( mHighlightColor );
index 66c6d89..3d9440e 100755 (executable)
@@ -289,6 +289,14 @@ void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharac
                                  mColorRuns,
                                  removedColorRuns );
 
+  // Process the background color runs.
+  Vector<ColorRun> removedBackgroundColorRuns;
+  UpdateCharacterRuns<ColorRun>( index,
+                                 numberOfCharacters,
+                                 totalNumberOfCharacters,
+                                 mBackgroundColorRuns,
+                                 removedBackgroundColorRuns );
+
   // Process the font description runs.
   Vector<FontDescriptionRun> removedFontDescriptionRuns;
   UpdateCharacterRuns<FontDescriptionRun>( index,
index 040444f..3c01dc6 100755 (executable)
@@ -211,6 +211,7 @@ public:
   Vector<ScriptRun>                     mScriptRuns;
   Vector<FontRun>                       mFontRuns;
   Vector<ColorRun>                      mColorRuns;
+  Vector<ColorRun>                      mBackgroundColorRuns;
   Vector<FontDescriptionRun>            mFontDescriptionRuns;
   Vector<LineBreakInfo>                 mLineBreakInfo;
   Vector<ParagraphRun>                  mParagraphInfo;
index 83a518b..c79dbd4 100755 (executable)
@@ -153,6 +153,16 @@ const ColorIndex* const ViewModel::GetColorIndices() const
   return mModel->GetColorIndices();
 }
 
+const Vector4* const ViewModel::GetBackgroundColors() const
+{
+  return mModel->GetBackgroundColors();
+}
+
+const ColorIndex* const ViewModel::GetBackgroundColorIndices() const
+{
+  return mModel->GetBackgroundColorIndices();
+}
+
 const Vector4& ViewModel::GetDefaultColor() const
 {
   return mModel->GetDefaultColor();
index bc7d45f..fe77f67 100755 (executable)
@@ -139,6 +139,16 @@ public:
   virtual const ColorIndex* const GetColorIndices() const;
 
   /**
+   * @copydoc ModelInterface::GetBackgroundColors()
+   */
+  virtual const Vector4* const GetBackgroundColors() const;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColorIndices()
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const;
+
+  /**
    * @copydoc ModelInterface::GetDefaultColor()
    */
   virtual const Vector4& GetDefaultColor() const;
index 6908f04..fa48e52 100755 (executable)
 
 // EXTERNAL INCLUDES
 #include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/rendering/renderer.h>
 #include <dali/integration-api/debug.h>
 #include <limits>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 #include <dali-toolkit/internal/text/color-segmentation.h>
@@ -34,6 +36,8 @@
 #include <dali-toolkit/internal/text/text-control-interface.h>
 #include <dali-toolkit/internal/text/text-run-container.h>
 
+using namespace Dali;
+
 namespace
 {
 
@@ -56,6 +60,44 @@ const float MAX_FLOAT = std::numeric_limits<float>::max();
 const float MIN_FLOAT = std::numeric_limits<float>::min();
 const Dali::Toolkit::Text::CharacterDirection LTR = false; ///< Left To Right direction
 
+#define MAKE_SHADER(A)#A
+
+const char* VERTEX_SHADER_BACKGROUND = MAKE_SHADER(
+attribute mediump vec2    aPosition;
+attribute mediump vec4    aColor;
+varying   mediump vec4    vColor;
+uniform   highp mat4      uMvpMatrix;
+
+void main()
+{
+  mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
+  gl_Position = uMvpMatrix * position;
+  vColor = aColor;
+}
+);
+
+const char* FRAGMENT_SHADER_BACKGROUND = MAKE_SHADER(
+varying mediump vec4      vColor;
+uniform lowp    vec4      uColor;
+
+void main()
+{
+  gl_FragColor = vColor * uColor;
+}
+);
+
+struct BackgroundVertex
+{
+  Vector2 mPosition;        ///< Vertex posiiton
+  Vector4 mColor;           ///< Vertex color
+};
+
+struct BackgroundMesh
+{
+  Vector< BackgroundVertex > mVertices;    ///< container of vertices
+  Vector< unsigned short > mIndices;       ///< container of indices
+};
+
 } // namespace
 
 namespace Dali
@@ -558,6 +600,7 @@ void Controller::Impl::ClearFullModelData( OperationsMask operations )
   if( NO_OPERATION != ( COLOR & operations ) )
   {
     mModel->mVisualModel->mColorIndices.Clear();
+    mModel->mVisualModel->mBackgroundColorIndices.Clear();
   }
 }
 
@@ -741,6 +784,13 @@ void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, Character
       mModel->mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
                                                  colorIndexBuffer + endGlyphIndexPlusOne );
     }
+
+    if( 0u != mModel->mVisualModel->mBackgroundColorIndices.Count() )
+    {
+      ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
+      mModel->mVisualModel->mBackgroundColorIndices.Erase( backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                           backgroundColorIndexBuffer + endGlyphIndexPlusOne );
+    }
   }
 }
 
@@ -1026,21 +1076,6 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     updated = true;
   }
 
-  if( NO_OPERATION != ( COLOR & operations ) )
-  {
-    // Set the color runs in glyphs.
-    SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
-                              mModel->mVisualModel->mCharactersToGlyph,
-                              mModel->mVisualModel->mGlyphsPerCharacter,
-                              startIndex,
-                              mTextUpdateInfo.mStartGlyphIndex,
-                              requestedNumberOfCharacters,
-                              mModel->mVisualModel->mColors,
-                              mModel->mVisualModel->mColorIndices );
-
-    updated = true;
-  }
-
   if( ( NULL != mEventData ) &&
       mEventData->mPreEditFlag &&
       ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
@@ -1076,6 +1111,32 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     }
   }
 
+  if( NO_OPERATION != ( COLOR & operations ) )
+  {
+    // Set the color runs in glyphs.
+    SetColorSegmentationInfo( mModel->mLogicalModel->mColorRuns,
+                              mModel->mVisualModel->mCharactersToGlyph,
+                              mModel->mVisualModel->mGlyphsPerCharacter,
+                              startIndex,
+                              mTextUpdateInfo.mStartGlyphIndex,
+                              requestedNumberOfCharacters,
+                              mModel->mVisualModel->mColors,
+                              mModel->mVisualModel->mColorIndices );
+
+    // Set the background color runs in glyphs.
+    SetColorSegmentationInfo( mModel->mLogicalModel->mBackgroundColorRuns,
+                              mModel->mVisualModel->mCharactersToGlyph,
+                              mModel->mVisualModel->mGlyphsPerCharacter,
+                              startIndex,
+                              mTextUpdateInfo.mStartGlyphIndex,
+                              requestedNumberOfCharacters,
+                              mModel->mVisualModel->mBackgroundColors,
+                              mModel->mVisualModel->mBackgroundColorIndices );
+
+    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() );
 
@@ -3062,6 +3123,169 @@ 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!
+
+  Actor actor;
+
+  Length numberOfGlyphs = mView.GetNumberOfGlyphs();
+  if( numberOfGlyphs > 0u )
+  {
+    Vector<GlyphInfo> glyphs;
+    glyphs.Resize( numberOfGlyphs );
+
+    Vector<Vector2> positions;
+    positions.Resize( numberOfGlyphs );
+
+    // Get the line where the glyphs are laid-out.
+    const LineRun* lineRun = mModel->mVisualModel->mLines.Begin();
+    float alignmentOffset = lineRun->alignmentOffset;
+    numberOfGlyphs = mView.GetGlyphs( glyphs.Begin(),
+                                      positions.Begin(),
+                                      alignmentOffset,
+                                      0u,
+                                      numberOfGlyphs );
+
+    glyphs.Resize( numberOfGlyphs );
+    positions.Resize( numberOfGlyphs );
+
+    const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+    const Vector2* const positionsBuffer = positions.Begin();
+
+    BackgroundMesh mesh;
+    mesh.mVertices.Reserve( 4u * glyphs.Size() );
+    mesh.mIndices.Reserve( 6u * glyphs.Size() );
+
+    const Vector2 textSize = mView.GetLayoutSize();
+
+    const float offsetX = textSize.width * 0.5f;
+    const float offsetY = textSize.height * 0.5f;
+
+    const Vector4* const backgroundColorsBuffer = mView.GetBackgroundColors();
+    const ColorIndex* const backgroundColorIndicesBuffer = mView.GetBackgroundColorIndices();
+
+    Vector4 quad;
+    uint32_t numberOfQuads = 0u;
+
+    for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
+    {
+      const GlyphInfo& glyph = *( glyphsBuffer + i );
+
+      // Get the background color of the character.
+      // The color index zero is reserved for the default background color (i.e. Color::TRANSPARENT)
+      const ColorIndex backgroundColorIndex = ( nullptr == backgroundColorsBuffer ) ? 0u : *( backgroundColorIndicesBuffer + i );
+      const Vector4& backgroundColor = ( 0u == backgroundColorIndex ) ? Color::TRANSPARENT : *( backgroundColorsBuffer + backgroundColorIndex - 1u );
+
+      // Only create quads for glyphs with a background color
+      if ( backgroundColor != Color::TRANSPARENT )
+      {
+        const Vector2 position = *( positionsBuffer + i );
+
+        if ( i == 0u && glyphSize == 1u ) // Only one glyph in the whole text
+        {
+          quad.x = position.x;
+          quad.y = 0.0f;
+          quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
+          quad.w = textSize.height;
+        }
+        else if ( i == 0u ) // The first glyph in the whole text
+        {
+          quad.x = position.x;
+          quad.y = 0.0f;
+          quad.z = quad.x - glyph.xBearing + glyph.advance;
+          quad.w = textSize.height;
+        }
+        else if ( i == glyphSize - 1u ) // The last glyph in the whole text
+        {
+          quad.x = position.x - glyph.xBearing;
+          quad.y = 0.0f;
+          quad.z = quad.x + std::max( glyph.advance, glyph.xBearing + glyph.width );
+          quad.w = textSize.height;
+        }
+        else // The glyph in the middle of the text
+        {
+          quad.x = position.x - glyph.xBearing;
+          quad.y = 0.0f;
+          quad.z = quad.x + glyph.advance;
+          quad.w = textSize.height;
+        }
+
+        BackgroundVertex vertex;
+
+        // Top left
+        vertex.mPosition.x = quad.x - offsetX;
+        vertex.mPosition.y = quad.y - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Top right
+        vertex.mPosition.x = quad.z - offsetX;
+        vertex.mPosition.y = quad.y - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Bottom left
+        vertex.mPosition.x = quad.x - offsetX;
+        vertex.mPosition.y = quad.w - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Bottom right
+        vertex.mPosition.x = quad.z - offsetX;
+        vertex.mPosition.y = quad.w - offsetY;
+        vertex.mColor = backgroundColor;
+        mesh.mVertices.PushBack( vertex );
+
+        // Six indices in counter clockwise winding
+        mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 0u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 2u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 3u + 4 * numberOfQuads );
+        mesh.mIndices.PushBack( 1u + 4 * numberOfQuads );
+
+        numberOfQuads++;
+      }
+    }
+
+    // Only create the background actor if there are glyphs with background color
+    if ( mesh.mVertices.Count() > 0u )
+    {
+      Property::Map quadVertexFormat;
+      quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
+      quadVertexFormat[ "aColor" ] = Property::VECTOR4;
+
+      PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
+      quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
+
+      Geometry quadGeometry = Geometry::New();
+      quadGeometry.AddVertexBuffer( quadVertices );
+      quadGeometry.SetIndexBuffer( &mesh.mIndices[ 0 ], mesh.mIndices.Size() );
+
+      if( !mShaderBackground )
+      {
+        mShaderBackground = Shader::New( VERTEX_SHADER_BACKGROUND, FRAGMENT_SHADER_BACKGROUND );
+      }
+
+      Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, mShaderBackground );
+      renderer.SetProperty( Dali::Renderer::Property::BLEND_MODE, BlendMode::ON );
+      renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
+
+      actor = Actor::New();
+      actor.SetName( "TextBackgroundColorActor" );
+      actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+      actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+      actor.SetSize( textSize );
+      actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+      actor.AddRenderer( renderer );
+    }
+  }
+
+  return actor;
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index 5dd231a..064d644 100755 (executable)
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/devel-api/adaptor-framework/clipboard.h>
 #include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/public-api/rendering/shader.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/input-style.h>
@@ -724,6 +725,13 @@ struct Controller::Impl
    */
   void ScrollTextToMatchCursor( const CursorInfo& cursorInfo );
 
+  /**
+   * @brief Create an actor that renders the text background color
+   *
+   * @return the created actor or an empty handle if no background color needs to be rendered.
+   */
+  Actor CreateBackgroundActor();
+
 public:
 
   /**
@@ -780,6 +788,8 @@ public:
   bool mShouldClearFocusOnEscape:1;        ///< Whether text control should clear key input focus
   LayoutDirection::Type mLayoutDirection;  ///< Current system language direction
 
+  Shader mShaderBackground;                ///< The shader for text background.
+
   float mTextFitMinSize;                   ///< Minimum Font Size for text fit. Default 10
   float mTextFitMaxSize;                   ///< Maximum Font Size for text fit. Default 100
   float mTextFitStepSize;                  ///< Step Size for font intervalse. Default 1
index 76c7fdd..c017039 100755 (executable)
@@ -4297,6 +4297,11 @@ bool Controller::ShouldClearFocusOnEscape() const
   return mImpl->mShouldClearFocusOnEscape;
 }
 
+Actor Controller::CreateBackgroundActor()
+{
+  return mImpl->CreateBackgroundActor();
+}
+
 // private : Private contructors & copy operator.
 
 Controller::Controller()
index 3e2a50d..82a7a15 100755 (executable)
@@ -1487,6 +1487,13 @@ public: // Text-input Event Queuing.
    */
   bool ShouldClearFocusOnEscape() const;
 
+  /**
+   * @brief Create an actor that renders the text background color
+   *
+   * @return the created actor or an empty handle if no background color needs to be rendered.
+   */
+  Actor CreateBackgroundActor();
+
 protected: // Inherit from Text::Decorator::ControllerInterface.
 
   /**
index a301d03..812ba7c 100755 (executable)
@@ -162,6 +162,20 @@ public:
   virtual const ColorIndex* const GetColorIndices() const = 0;
 
   /**
+   * @brief Retrieves the vector of background colors.
+   *
+   * @return Pointer to the vector of background colors.
+   */
+  virtual const Vector4* const GetBackgroundColors() const = 0;
+
+  /**
+   * @brief Retrieves the vector of indices to the vector of background colors.
+   *
+   * @return Pointer to a vector which stores for each glyph the index to the vector of background colors.
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const = 0;
+
+  /**
    * @brief Retrieves the text's default color.
    *
    * @return The default color.
index da87e0c..c1767d8 100755 (executable)
@@ -112,6 +112,16 @@ const ColorIndex* const Model::GetColorIndices() const
   return mVisualModel->mColorIndices.Begin();
 }
 
+const Vector4* const Model::GetBackgroundColors() const
+{
+  return mVisualModel->mBackgroundColors.Begin();
+}
+
+const ColorIndex* const Model::GetBackgroundColorIndices() const
+{
+  return mVisualModel->mBackgroundColorIndices.Begin();
+}
+
 const Vector4& Model::GetDefaultColor() const
 {
   return mVisualModel->mTextColor;
index 3230e47..5edb294 100755 (executable)
@@ -139,6 +139,16 @@ public:
   virtual const ColorIndex* const GetColorIndices() const override;
 
   /**
+   * @copydoc ModelInterface::GetBackgroundColors()
+   */
+  virtual const Vector4* const GetBackgroundColors() const override;
+
+  /**
+   * @copydoc ModelInterface::GetBackgroundColorIndices()
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const override;
+
+  /**
    * @copydoc ModelInterface::GetDefaultColor()
    */
   virtual const Vector4& GetDefaultColor() const override;
index 9e8020c..4aad47b 100755 (executable)
@@ -114,6 +114,20 @@ public:
   virtual const ColorIndex* const GetColorIndices() const = 0;
 
   /**
+   * @brief Retrieves the vector of background colors.
+   *
+   * @return Pointer to the vector of background colors.
+   */
+  virtual const Vector4* const GetBackgroundColors() const = 0;
+
+  /**
+   * @brief Retrieves the vector of indices to the vector of background colors.
+   *
+   * @return Pointer to a vector which stores for each glyph the index to the vector of background colors.
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const = 0;
+
+  /**
    * @brief Retrieves the text color
    *
    * @return The text color
index 929c17c..9d9f991 100755 (executable)
@@ -326,6 +326,26 @@ const ColorIndex* const View::GetColorIndices() const
   return NULL;
 }
 
+const Vector4* const View::GetBackgroundColors() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->mBackgroundColors.Begin();
+  }
+
+  return nullptr;
+}
+
+const ColorIndex* const View::GetBackgroundColorIndices() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->mBackgroundColorIndices.Begin();
+  }
+
+  return nullptr;
+}
+
 const Vector4& View::GetTextColor() const
 {
   if( mImpl->mVisualModel )
index e7d1942..91b7867 100755 (executable)
@@ -90,6 +90,16 @@ public:
   virtual const ColorIndex* const GetColorIndices() const;
 
   /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetBackgroundColors()
+   */
+  virtual const Vector4* const GetBackgroundColors() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetBackgroundColorIndices()
+   */
+  virtual const ColorIndex* const GetBackgroundColorIndices() const;
+
+  /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetTextColor()
    */
   virtual const Vector4& GetTextColor() const;
index 81ec9fe..853e946 100755 (executable)
@@ -389,6 +389,8 @@ public:
   Vector<GlyphRun>       mUnderlineRuns;        ///< Runs of glyphs that are underlined.
   Vector<Vector4>        mColors;               ///< Colors of the glyphs.
   Vector<ColorIndex>     mColorIndices;         ///< Indices to the vector of colors for each glyphs.
+  Vector<Vector4>        mBackgroundColors;     ///< Background colors of the glyphs.
+  Vector<ColorIndex>     mBackgroundColorIndices; ///< Indices to the vector of background colors for each glyphs.
 
   Vector4                mTextColor;            ///< The text color
   Vector4                mShadowColor;          ///< Color of drop shadow