Dali-Text: Keyboard Shortcuts
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
old mode 100755 (executable)
new mode 100644 (file)
index e333be2..0a8fe4b
 
 // 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,50 @@ 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
+};
+
+const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB4( 0.58f, 0.87f, 0.96f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB5( 0.83f, 0.94f, 0.98f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB6( 1.f, 0.5f, 0.5f, 1.f );
+const Dali::Vector4 BACKGROUND_SUB7( 1.f, 0.8f, 0.8f, 1.f );
+
 } // namespace
 
 namespace Dali
@@ -110,7 +158,8 @@ EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodCon
   mIsPlaceholderPixelSize( false ),
   mIsPlaceholderElideEnabled( false ),
   mPlaceholderEllipsisFlag( false ),
-  mShiftSelectionFlag( true )
+  mShiftSelectionFlag( true ),
+  mUpdateAlignment( false )
 {
 }
 
@@ -172,6 +221,11 @@ bool Controller::Impl::ProcessInputEvents()
           OnSelectAllEvent();
           break;
         }
+        case Event::SELECT_NONE:
+        {
+          OnSelectNoneEvent();
+          break;
+        }
       }
     }
   }
@@ -504,11 +558,6 @@ void Controller::Impl::ClearFullModelData( OperationsMask operations )
     mModel->mLogicalModel->mParagraphInfo.Clear();
   }
 
-  if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
-  {
-    mModel->mLogicalModel->mLineBreakInfo.Clear();
-  }
-
   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
   {
     mModel->mLogicalModel->mScriptRuns.Clear();
@@ -562,6 +611,7 @@ void Controller::Impl::ClearFullModelData( OperationsMask operations )
   if( NO_OPERATION != ( COLOR & operations ) )
   {
     mModel->mVisualModel->mColorIndices.Clear();
+    mModel->mVisualModel->mBackgroundColorIndices.Clear();
   }
 }
 
@@ -583,15 +633,6 @@ void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, Chara
                         mModel->mLogicalModel->mParagraphInfo );
   }
 
-  if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
-  {
-    // Clear the word break info.
-    WordBreakInfo* wordBreakInfoBuffer = mModel->mLogicalModel->mWordBreakInfo.Begin();
-
-    mModel->mLogicalModel->mWordBreakInfo.Erase( wordBreakInfoBuffer + startIndex,
-                                         wordBreakInfoBuffer + endIndexPlusOne );
-  }
-
   if( NO_OPERATION != ( GET_SCRIPTS & operations ) )
   {
     // Clear the scripts.
@@ -754,6 +795,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 );
+    }
   }
 }
 
@@ -814,7 +862,7 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 
   // Check whether the indices for updating the text is valid
   if ( numberOfCharacters > 0u &&
-       ( mTextUpdateInfo.mParagraphCharacterIndex >= numberOfCharacters ||
+       ( mTextUpdateInfo.mParagraphCharacterIndex > numberOfCharacters ||
          mTextUpdateInfo.mRequestedNumberOfCharacters > numberOfCharacters ) )
   {
     std::string currentText;
@@ -876,19 +924,6 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     updated = true;
   }
 
-  Vector<WordBreakInfo>& wordBreakInfo = mModel->mLogicalModel->mWordBreakInfo;
-  if( NO_OPERATION != ( GET_WORD_BREAKS & operations ) )
-  {
-    // Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
-    wordBreakInfo.Resize( numberOfCharacters, TextAbstraction::WORD_NO_BREAK );
-
-    SetWordBreakInfo( utf32Characters,
-                      startIndex,
-                      requestedNumberOfCharacters,
-                      wordBreakInfo );
-    updated = true;
-  }
-
   const bool getScripts = NO_OPERATION != ( GET_SCRIPTS & operations );
   const bool validateFonts = NO_OPERATION != ( VALIDATE_FONTS & operations );
 
@@ -1052,6 +1087,136 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     updated = true;
   }
 
+  if( ( NULL != mEventData ) &&
+      mEventData->mPreEditFlag &&
+      ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
+  {
+    Dali::InputMethodContext::PreEditAttributeDataContainer attrs;
+    mEventData->mInputMethodContext.GetPreeditStyle( attrs );
+    Dali::InputMethodContext::PreeditStyle type = Dali::InputMethodContext::PreeditStyle::NONE;
+
+    // Check the type of preedit and run it.
+    for( Dali::InputMethodContext::PreEditAttributeDataContainer::Iterator it = attrs.Begin(), endIt = attrs.End(); it != endIt; it++ )
+    {
+      Dali::InputMethodContext::PreeditAttributeData attrData = *it;
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel PreeditStyle type : %d  start %d end %d \n", attrData.preeditType, attrData.startIndex, attrData.endIndex  );
+      type = attrData.preeditType;
+
+      // Check the number of commit characters for the start position.
+      unsigned int numberOfCommit = mEventData->mPrimaryCursorPosition - mEventData->mPreEditLength;
+      Length numberOfIndices = attrData.endIndex - attrData.startIndex;
+
+      switch( type )
+      {
+        case Dali::InputMethodContext::PreeditStyle::UNDERLINE:
+        {
+          // Add the underline for the pre-edit text.
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::REVERSE:
+        {
+          Vector4 textColor = mModel->mVisualModel->GetTextColor();
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = textColor;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          Vector4 backgroundColor = mModel->mVisualModel->GetBackgroundColor();
+          Vector<ColorRun>  colorRuns;
+          colorRuns.Resize( 1u );
+          ColorRun& colorRun = *( colorRuns.Begin() );
+          colorRun.color = backgroundColor;
+          colorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          colorRun.characterRun.numberOfCharacters = numberOfIndices;
+
+          mModel->mLogicalModel->mColorRuns.PushBack( colorRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::HIGHLIGHT:
+        {
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = LIGHT_BLUE;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1:
+        {
+          // CUSTOM_PLATFORM_STYLE_1 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB4;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2:
+        {
+          // CUSTOM_PLATFORM_STYLE_2 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB5;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3:
+        {
+          // CUSTOM_PLATFORM_STYLE_3 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB6;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4:
+        {
+          // CUSTOM_PLATFORM_STYLE_4 should be drawn with background and underline together.
+          ColorRun backgroundColorRun;
+          backgroundColorRun.characterRun.characterIndex = attrData.startIndex + numberOfCommit;
+          backgroundColorRun.characterRun.numberOfCharacters = numberOfIndices;
+          backgroundColorRun.color = BACKGROUND_SUB7;
+          mModel->mLogicalModel->mBackgroundColorRuns.PushBack( backgroundColorRun );
+
+          GlyphRun underlineRun;
+          underlineRun.glyphIndex = attrData.startIndex + numberOfCommit;
+          underlineRun.numberOfGlyphs = numberOfIndices;
+          mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
+          break;
+        }
+        case Dali::InputMethodContext::PreeditStyle::NONE:
+        default:
+        {
+          break;
+        }
+      }
+    }
+    attrs.Clear();
+    updated = true;
+  }
+
   if( NO_OPERATION != ( COLOR & operations ) )
   {
     // Set the color runs in glyphs.
@@ -1064,29 +1229,19 @@ bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                               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;
   }
 
-  if( ( NULL != mEventData ) &&
-      mEventData->mPreEditFlag &&
-      ( 0u != mModel->mVisualModel->mCharactersToGlyph.Count() ) )
-  {
-    // Add the underline for the pre-edit text.
-    const GlyphIndex* const charactersToGlyphBuffer = mModel->mVisualModel->mCharactersToGlyph.Begin();
-    const Length* const glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
-
-    const GlyphIndex glyphStart = *( charactersToGlyphBuffer + mEventData->mPreEditStartPosition );
-    const CharacterIndex lastPreEditCharacter = mEventData->mPreEditStartPosition + ( ( mEventData->mPreEditLength > 0u ) ? mEventData->mPreEditLength - 1u : 0u );
-    const Length numberOfGlyphsLastCharacter = *( glyphsPerCharacterBuffer + lastPreEditCharacter );
-    const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + lastPreEditCharacter ) + ( numberOfGlyphsLastCharacter > 1u ? numberOfGlyphsLastCharacter - 1u : 0u );
-
-    GlyphRun underlineRun;
-    underlineRun.glyphIndex = glyphStart;
-    underlineRun.numberOfGlyphs = 1u + glyphEnd - glyphStart;
-
-    // TODO: At the moment the underline runs are only for pre-edit.
-    mModel->mVisualModel->mUnderlineRuns.PushBack( underlineRun );
-  }
 
   // The estimated number of lines. Used to avoid reallocations when layouting.
   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count() );
@@ -1446,17 +1601,16 @@ void Controller::Impl::OnPanEvent( const Event& event )
     return;
   }
 
-  const int state = event.p1.mInt;
-
+  const GestureState state = static_cast<GestureState>( event.p1.mInt );
   switch( state )
   {
-    case Gesture::Started:
+    case GestureState::STARTED:
     {
       // Will remove the cursor, handles or text's popup, ...
       ChangeState( EventData::TEXT_PANNING );
       break;
     }
-    case Gesture::Continuing:
+    case GestureState::CONTINUING:
     {
       const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
       const Vector2 currentScroll = mModel->mScrollPosition;
@@ -1480,8 +1634,8 @@ void Controller::Impl::OnPanEvent( const Event& event )
       mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
       break;
     }
-    case Gesture::Finished:
-    case Gesture::Cancelled: // FALLTHROUGH
+    case GestureState::FINISHED:
+    case GestureState::CANCELLED: // FALLTHROUGH
     {
       // Will go back to the previous state to show the cursor, handles, the text's popup, ...
       ChangeState( mEventData->mPreviousState );
@@ -1865,6 +2019,27 @@ void Controller::Impl::OnSelectAllEvent()
   }
 }
 
+void Controller::Impl::OnSelectNoneEvent()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectNoneEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
+
+  if( NULL == mEventData )
+  {
+    // Nothing to do if there is no text.
+    return;
+  }
+
+  if( mEventData->mSelectionEnabled && mEventData->mState == EventData::SELECTING)
+  {
+    mEventData->mPrimaryCursorPosition = 0u;
+    mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+    ChangeState( EventData::INACTIVE );
+    mEventData->mUpdateCursorPosition = true;
+    mEventData->mUpdateInputStyle = true;
+    mEventData->mScrollAfterUpdatePosition = true;
+  }
+}
+
 void Controller::Impl::RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval )
 {
   if( mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition )
@@ -3074,6 +3249,170 @@ 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();
+    const Vector4& defaultBackgroundColor = mModel->mVisualModel->IsBackgroundEnabled() ? mModel->mVisualModel->GetBackgroundColor() : Color::TRANSPARENT;
+
+    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 ) ? defaultBackgroundColor : *( 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;
+
+      VertexBuffer quadVertices = VertexBuffer::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.SetProperty( Dali::Actor::Property::NAME, "TextBackgroundColorActor" );
+      actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+      actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+      actor.SetProperty( Actor::Property::SIZE, textSize );
+      actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR );
+      actor.AddRenderer( renderer );
+    }
+  }
+
+  return actor;
+}
+
 } // namespace Text
 
 } // namespace Toolkit