Added TEXT_COLOR, UNDERLINE_ENABLED and UNDERLINE_COLOR to properties and atlas renderer 84/37584/7
authorRichard Underhill <r.underhill@partner.samsung.com>
Thu, 2 Apr 2015 14:46:04 +0000 (15:46 +0100)
committerRichard Underhill <r.underhill@partner.samsung.com>
Thu, 2 Apr 2015 14:46:04 +0000 (15:46 +0100)
Change-Id: I0bc2f5a71a64b145c600fd9015dd02db131e5fe7
Signed-off-by: Richard Underhill <r.underhill@partner.samsung.com>
16 files changed:
dali-toolkit/internal/atlas-manager/atlas-manager-impl.cpp
dali-toolkit/internal/atlas-manager/atlas-manager-impl.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.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.cpp
dali-toolkit/internal/text/visual-model-impl.h
dali-toolkit/public-api/controls/text-controls/text-label.h

index 826ea1e..83bb423 100644 (file)
@@ -37,12 +37,14 @@ namespace
   const Vector2 DEFAULT_BLOCK_SIZE( 32.0f, 32.0f );
   const uint32_t SINGLE_PIXEL_PADDING( 1u );
   const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
+  const uint32_t FILLED_PIXEL( -1 );
 }
 
 AtlasManager::AtlasManager()
 : mNewAtlasSize( DEFAULT_ATLAS_SIZE ),
   mNewBlockSize( DEFAULT_BLOCK_SIZE ),
-  mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES )
+  mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
+  mFilledPixel( FILLED_PIXEL )
 {
 }
 
@@ -103,7 +105,8 @@ Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( SizeType width,
                                                      SINGLE_PIXEL_PADDING,
                                                      blockHeight - DOUBLE_PIXEL_PADDING,
                                                      pixelformat );
-
+  atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
+  atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
   mAtlasList.push_back( atlasDescriptor );
   return mAtlasList.size();
 }
@@ -413,7 +416,6 @@ void AtlasManager::CreateMesh( SizeType atlas,
 
   meshData.SetFaceIndices( faces );
   meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
-  //PrintMeshData( meshData );
 }
 
 void AtlasManager::PrintMeshData( const MeshData& meshData )
@@ -510,9 +512,6 @@ void AtlasManager::StitchMesh( MeshData& first,
   }
 
   first.SetFaceIndices( f1 );
-
-  // TODO rather than set the material to the second, check to see if there's a match and return if not
-  first.SetMaterial( second.GetMaterial() );
 }
 
 void AtlasManager::StitchMesh( const MeshData& first,
@@ -565,8 +564,7 @@ void AtlasManager::StitchMesh( const MeshData& first,
     out.SetVertices( vertices );
   }
 
-  // TODO rather than set the material to the second, check to see if there's a match and return if not
-  out.SetMaterial( second.GetMaterial() );
+  out.SetMaterial( first.GetMaterial() );
   out.SetFaceIndices( faces );
 }
 
@@ -604,20 +602,25 @@ void AtlasManager::UploadImage( const BufferImage& image,
     DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
   }
 
-  // Blit top strip
-  if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
-                                           blockOffsetX,
-                                           blockOffsetY ) )
+  // If this is the first block then we need to keep the first pixel free for underline texture
+  if ( block )
   {
-    DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
-  }
 
-  // Blit left strip
-  if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
-                                           blockOffsetX,
-                                           blockOffsetY + SINGLE_PIXEL_PADDING ) )
-  {
-    DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
+    // Blit top strip
+    if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
+                                             blockOffsetX,
+                                             blockOffsetY ) )
+    {
+      DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
+    }
+
+    // Blit left strip
+    if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
+                                             blockOffsetX,
+                                             blockOffsetY + SINGLE_PIXEL_PADDING ) )
+    {
+      DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
+    }
   }
 
   // Blit bottom strip
@@ -743,7 +746,7 @@ Vector2 AtlasManager::GetBlockSize( AtlasId atlas )
   }
   else
   {
-    return Vector2( 0.0f, 0.0f );
+    return Vector2::ZERO;
   }
 }
 
@@ -756,7 +759,7 @@ Vector2 AtlasManager::GetAtlasSize( AtlasId atlas )
   }
   else
   {
-    return Vector2( 0.0f, 0.0f );
+    return Vector2::ZERO;
   }
 }
 
index 6f1411e..0656da7 100644 (file)
@@ -67,6 +67,7 @@ public:
     Pixel::Format mPixelFormat;                                         // pixel format used by atlas
     BufferImage mHorizontalStrip;                                       // Image used to pad upload
     BufferImage mVerticalStrip;                                         // Image used to pad upload
+    BufferImage mFilledPixelImage;                                      // Image used by atlas for operations such as underline
     PixelBuffer* mStripBuffer;                                          // Blank image buffer used to pad upload
     Material mMaterial;                                                 // material used for atlas texture
     SizeType mNextFreeBlock;                                            // next free block will be placed here ( actually +1 )
@@ -217,6 +218,7 @@ private:
   Vector2 mNewAtlasSize;
   Vector2 mNewBlockSize;
   Toolkit::AtlasManager::AddFailPolicy mAddFailPolicy;
+  uint32_t mFilledPixel;
 };
 
 } // namespace Internal
index 4ff2035..6149e29 100644 (file)
@@ -83,9 +83,11 @@ DALI_PROPERTY_REGISTRATION( TextLabel, "point-size",           FLOAT,   POINT_SI
 DALI_PROPERTY_REGISTRATION( TextLabel, "multi-line",           BOOLEAN, MULTI_LINE           )
 DALI_PROPERTY_REGISTRATION( TextLabel, "horizontal-alignment", STRING,  HORIZONTAL_ALIGNMENT )
 DALI_PROPERTY_REGISTRATION( TextLabel, "vertical-alignment",   STRING,  VERTICAL_ALIGNMENT   )
-DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-offset",     VECTOR2, SHADOW_OFFSET     )
-DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-color",      VECTOR4, SHADOW_COLOR      )
-
+DALI_PROPERTY_REGISTRATION( TextLabel, "text-color",           VECTOR4, TEXT_COLOR           )
+DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-offset",        VECTOR2, SHADOW_OFFSET        )
+DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-color",         VECTOR4, SHADOW_COLOR         )
+DALI_PROPERTY_REGISTRATION( TextLabel, "underline-enabled",    BOOLEAN, UNDERLINE_ENABLED    )
+DALI_PROPERTY_REGISTRATION( TextLabel, "underline-color",      VECTOR4, UNDERLINE_COLOR      )
 DALI_TYPE_REGISTRATION_END()
 
 } // namespace
@@ -220,7 +222,22 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         }
         break;
       }
-     case Toolkit::TextLabel::Property::SHADOW_OFFSET:
+
+      case Toolkit::TextLabel::Property::TEXT_COLOR:
+      {
+        if ( impl.mController )
+        {
+          Vector4 textColor = value.Get< Vector4 >();
+          if ( impl.mController->GetTextColor() != textColor )
+          {
+            impl.mController->SetTextColor( textColor );
+            impl.RequestTextRelayout();
+          }
+        }
+        break;
+      }
+
+      case Toolkit::TextLabel::Property::SHADOW_OFFSET:
       {
         if( impl.mController )
         {
@@ -246,6 +263,32 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr
         }
         break;
       }
+      case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
+      {
+        if( impl.mController )
+        {
+          Vector4 color = value.Get< Vector4 >();
+          if ( impl.mController->GetUnderlineColor() != color )
+          {
+            impl.mController->SetUnderlineColor( color );
+            impl.RequestTextRelayout();
+          }
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
+      {
+        if( impl.mController )
+        {
+          bool enabled = value.Get< bool >();
+          if ( impl.mController->IsUnderlineEnabled() != enabled )
+          {
+            impl.mController->SetUnderlineEnabled( enabled );
+            impl.RequestTextRelayout();
+          }
+        }
+        break;
+      }
     }
   }
 }
@@ -304,7 +347,15 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde
         }
         break;
       }
-     case Toolkit::TextLabel::Property::SHADOW_OFFSET:
+      case Toolkit::TextLabel::Property::TEXT_COLOR:
+      {
+        if ( impl.mController )
+        {
+          value = impl.mController->GetTextColor();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::SHADOW_OFFSET:
       {
         if ( impl.mController )
         {
@@ -320,6 +371,22 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde
         }
         break;
       }
+      case Toolkit::TextLabel::Property::UNDERLINE_COLOR:
+      {
+        if ( impl.mController )
+        {
+          value = impl.mController->GetUnderlineColor();
+        }
+        break;
+      }
+      case Toolkit::TextLabel::Property::UNDERLINE_ENABLED:
+      {
+        if ( impl.mController )
+        {
+          value = impl.mController->IsUnderlineEnabled();
+        }
+        break;
+      }
     }
   }
 
index 03091e5..16fdc8a 100644 (file)
@@ -108,6 +108,11 @@ void AtlasGlyphManager::Cached( Text::FontId fontId,
   slot.mImageId = 0;
 }
 
+Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
+{
+  return mAtlasManager.GetAtlasSize( atlasId );
+}
+
 void AtlasGlyphManager::SetNewAtlasSize( const Vector2& size,
                                          const Vector2& blockSize )
 {
index 868add6..5068426 100644 (file)
@@ -93,6 +93,11 @@ public:
                Dali::Toolkit::AtlasManager::AtlasSlot& slot );
 
   /**
+   * @copydoc Toolkit::AtlasGlyphManager::GetAtlasSize
+   */
+  Vector2 GetAtlasSize( uint32_t atlasId );
+
+  /**
    * @copydoc Toolkit::AtlasGlyphManager::SetNewAtlasSize
    */
   void SetNewAtlasSize( const Vector2& size,
index 275836c..d46ef18 100644 (file)
@@ -104,6 +104,11 @@ void AtlasGlyphManager::SetNewAtlasSize( const Vector2& size,
   GetImplementation(*this).SetNewAtlasSize( size, blockSize );
 }
 
+Vector2 AtlasGlyphManager::GetAtlasSize( uint32_t atlasId )
+{
+  return GetImplementation(*this).GetAtlasSize( atlasId );
+}
+
 void AtlasGlyphManager::Remove( uint32_t imageId )
 {
   GetImplementation(*this).Remove( imageId );
index 6a53481..cbfa754 100644 (file)
@@ -111,6 +111,15 @@ public:
                AtlasManager::AtlasSlot& slot );
 
   /**
+   * @brief Retrieve the size of an atlas
+   *
+   * @param[in] atlasId Id of the atlas to interrogate
+   *
+   * @return The pixel size of the atlas
+   */
+  Vector2 GetAtlasSize( uint32_t atlasId );
+
+  /**
    * @brief Set the Atlas size and block size for subsequent atlas generation
    *
    * @param[in] size size of the atlas in pixels
index 63deea2..fda82f4 100644 (file)
@@ -54,9 +54,21 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   struct MeshRecord
   {
+    Vector4 mColor;
     uint32_t mAtlasId;
     MeshData mMeshData;
     FrameBufferImage mBuffer;
+    bool mIsUnderline;
+  };
+
+  struct Extent
+  {
+    float mBaseLine;
+    float mLeft;
+    float mRight;
+    float mUnderlinePosition;
+    float mUnderlineThickness;
+    uint32_t mMeshRecordIndex;
   };
 
   struct AtlasRecord
@@ -79,19 +91,30 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     mBasicShader = BasicShader::New();
     mBgraShader = BgraShader::New();
     mBasicShadowShader = BasicShadowShader::New();
+
+    mFace.reserve( 6u );
+    mFace.push_back( 0 ); mFace.push_back( 2u ); mFace.push_back( 1u );
+    mFace.push_back( 1u ); mFace.push_back( 2u ); mFace.push_back( 3u );
   }
 
   void AddGlyphs( const std::vector<Vector2>& positions,
                   const Vector<GlyphInfo>& glyphs,
+                  const Vector4& textColor,
                   const Vector2& shadowOffset,
-                  const Vector4& shadowColor )
+                  const Vector4& shadowColor,
+                  float underlineEnabled,
+                  const Vector4& underlineColor )
   {
     AtlasManager::AtlasSlot slot;
     std::vector< MeshRecord > meshContainer;
+    Vector< Extent > extents;
+
+    float currentUnderlinePosition = 0.0f;
+    float currentUnderlineThickness = 0.0f;
     FontId lastFontId = 0;
     Style style = STYLE_NORMAL;
 
-    if ( shadowOffset.x > 0.0f || shadowOffset.y > 0.0f )
+    if ( shadowOffset.x != 0.0f || shadowOffset.y != 0.0f )
     {
       style = STYLE_DROP_SHADOW;
     }
@@ -111,6 +134,22 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       // No operation for white space
       if ( glyph.width && glyph.height )
       {
+        // Are we still using the same fontId as previous
+        if ( glyph.fontId != lastFontId )
+        {
+          // We need to fetch fresh font underline metrics
+          FontMetrics fontMetrics;
+          mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
+          currentUnderlinePosition = fontMetrics.underlinePosition;
+          currentUnderlineThickness = fontMetrics.underlineThickness;
+
+          // Ensure that an underline is at least 1 pixel high
+          if ( currentUnderlineThickness < 1.0f )
+          {
+            currentUnderlineThickness = 1.0f;
+          }
+        }
+
         Vector2 position = positions[ i ];
         MeshData newMeshData;
         mGlyphManager.Cached( glyph.fontId, glyph.index, slot );
@@ -151,25 +190,46 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           }
         }
         // Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
-        StitchTextMesh( meshContainer, newMeshData, slot );
+        StitchTextMesh( meshContainer,
+                        newMeshData,
+                        extents,
+                        textColor,
+                        position.y + glyph.yBearing,
+                        currentUnderlinePosition,
+                        currentUnderlineThickness,
+                        slot );
       }
     }
 
+    if ( underlineEnabled )
+    {
+      // Check to see if any of the text needs an underline
+      GenerateUnderlines( meshContainer, extents, underlineColor, textColor );
+    }
+
     // For each MeshData object, create a mesh actor and add to the renderable actor
     if ( meshContainer.size() )
     {
-      for ( uint32_t i = 0; i < meshContainer.size(); ++i )
+      for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
       {
-        MeshActor actor = MeshActor::New( Mesh::New( meshContainer[ i ].mMeshData ) );
-        actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+        MeshActor actor = MeshActor::New( Mesh::New( mIt->mMeshData ) );
+        actor.SetColor( mIt->mColor );
+        if ( mIt->mIsUnderline )
+        {
+          actor.SetColorMode( USE_OWN_COLOR );
+        }
+        else
+        {
+          actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+        }
 
         // Check to see what pixel format the shader should be
-        if ( mGlyphManager.GetPixelFormat( meshContainer[ i ].mAtlasId ) == Pixel::L8 )
+        if ( mGlyphManager.GetPixelFormat( mIt->mAtlasId ) == Pixel::L8 )
         {
           // Create an effect if necessary
           if ( style == STYLE_DROP_SHADOW )
           {
-            actor.Add( GenerateEffect( meshContainer[ i ], shadowOffset, shadowColor ) );
+            actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
           }
           actor.SetShaderEffect( mBasicShader );
         }
@@ -178,7 +238,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
           actor.SetShaderEffect( mBgraShader );
         }
 
-        if ( i )
+        if ( mActor )
         {
           mActor.Add( actor );
         }
@@ -212,17 +272,36 @@ struct AtlasRenderer::Impl : public ConnectionTracker
 
   void StitchTextMesh( std::vector< MeshRecord >& meshContainer,
                        MeshData& newMeshData,
+                       Vector< Extent >& extents,
+                       const Vector4& color,
+                       float baseLine,
+                       float underlinePosition,
+                       float underlineThickness,
                        AtlasManager::AtlasSlot& slot )
   {
     if ( slot.mImageId )
     {
+      MeshData::VertexContainer verts = newMeshData.GetVertices();
+      float left = verts[ 0 ].x;
+      float right = verts[ 1 ].x;
+
       // Check to see if there's a mesh data object that references the same atlas ?
-      for ( uint32_t i = 0; i < meshContainer.size(); ++i )
+      uint32_t index = 0;
+      for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index )
       {
-        if ( slot.mAtlasId == meshContainer[ i ].mAtlasId )
+        if ( slot.mAtlasId == mIt->mAtlasId )
         {
-          // Stitch the mesh to the existing mesh
-          mGlyphManager.StitchMesh( meshContainer[ i ].mMeshData, newMeshData );
+          // Stitch the mesh to the existing mesh and adjust any extents
+          mGlyphManager.StitchMesh( mIt->mMeshData, newMeshData );
+          AdjustExtents( extents,
+                         meshContainer,
+                         index,
+                         color,
+                         left,
+                         right,
+                         baseLine,
+                         underlinePosition,
+                         underlineThickness );
           return;
         }
       }
@@ -231,7 +310,73 @@ struct AtlasRenderer::Impl : public ConnectionTracker
       MeshRecord meshRecord;
       meshRecord.mAtlasId = slot.mAtlasId;
       meshRecord.mMeshData = newMeshData;
+      meshRecord.mColor = color;
+      meshRecord.mIsUnderline = false;
       meshContainer.push_back( meshRecord );
+
+      // Adjust extents for this new meshrecord
+      AdjustExtents( extents,
+                     meshContainer,
+                     meshContainer.size() - 1u,
+                     color,
+                     left,
+                     right,
+                     baseLine,
+                     underlinePosition,
+                     underlineThickness );
+
+    }
+  }
+
+  void AdjustExtents( Vector< Extent >& extents,
+                      std::vector< MeshRecord>& meshRecords,
+                      uint32_t index,
+                      const Vector4& color,
+                      float left,
+                      float right,
+                      float baseLine,
+                      float underlinePosition,
+                      float underlineThickness )
+  {
+    bool foundExtent = false;
+    for ( Vector< Extent >::Iterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
+    {
+      if ( Equals( baseLine, eIt->mBaseLine ) )
+      {
+        // If we've found an extent with the same color then we don't need to create a new extent
+        if ( color == meshRecords[ index ].mColor )
+        {
+          foundExtent = true;
+          if ( left < eIt->mLeft )
+          {
+            eIt->mLeft = left;
+          }
+          if ( right > eIt->mRight  )
+          {
+            eIt->mRight = right;
+          }
+        }
+        // Font metrics use negative values for lower underline positions
+        if ( underlinePosition < eIt->mUnderlinePosition )
+        {
+          eIt->mUnderlinePosition = underlinePosition;
+        }
+        if ( underlineThickness > eIt->mUnderlineThickness )
+        {
+          eIt->mUnderlineThickness = underlineThickness;
+        }
+      }
+    }
+    if ( !foundExtent )
+    {
+      Extent extent;
+      extent.mLeft = left;
+      extent.mRight = right;
+      extent.mBaseLine = baseLine;
+      extent.mUnderlinePosition = underlinePosition;
+      extent.mUnderlineThickness = underlineThickness;
+      extent.mMeshRecordIndex = index;
+      extents.PushBack( extent );
     }
   }
 
@@ -286,14 +431,77 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     }
   }
 
-  MeshActor GenerateEffect( MeshRecord& meshRecord,
+  void GenerateUnderlines( std::vector< MeshRecord>& meshRecords,
+                           Vector< Extent >& extents,
+                           const Vector4& underlineColor,
+                           const Vector4& textColor )
+  {
+    MeshData newMeshData;
+    const float zero = 0.0f;
+    const float half = 0.5f;
+
+    for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
+    {
+      MeshData::VertexContainer newVerts;
+      newVerts.reserve( 4u );
+      uint32_t index = eIt->mMeshRecordIndex;
+      Vector2 uv = mGlyphManager.GetAtlasSize( meshRecords[ index ].mAtlasId );
+
+      // Make sure we don't hit texture edge for single pixel texture ( filled pixel is in top left of every atlas )
+      float u = half / uv.x;
+      float v = half / uv.y;
+      float thickness = eIt->mUnderlineThickness;
+      float baseLine = eIt->mBaseLine - eIt->mUnderlinePosition - ( thickness * 0.5f );
+      float tlx = eIt->mLeft;
+      float brx = eIt->mRight;
+
+      newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine, zero ),
+                                            Vector2( zero, zero ),
+                                            Vector3( zero, zero, zero ) ) );
+
+      newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, zero ),
+                                            Vector2( u, zero ),
+                                            Vector3( zero, zero, zero ) ) );
+
+      newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, zero ),
+                                            Vector2( zero, v ),
+                                            Vector3( zero, zero, zero ) ) );
+
+      newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, zero ),
+                                            Vector2( u, v ),
+                                            Vector3( zero, zero, zero ) ) );
+
+      newMeshData.SetVertices( newVerts );
+      newMeshData.SetFaceIndices( mFace );
+
+      if ( underlineColor == textColor )
+      {
+        mGlyphManager.StitchMesh( meshRecords[ index ].mMeshData, newMeshData );
+      }
+      else
+      {
+        MeshRecord record;
+        newMeshData.SetMaterial( meshRecords[ index ].mMeshData.GetMaterial() );
+        newMeshData.SetHasNormals( true );
+        newMeshData.SetHasColor( false );
+        newMeshData.SetHasTextureCoords( true );
+        record.mMeshData = newMeshData;
+        record.mAtlasId = meshRecords[ index ].mAtlasId;
+        record.mColor = underlineColor;
+        record.mIsUnderline = true;
+        meshRecords.push_back( record );
+      }
+    }
+  }
+
+  MeshActor GenerateShadow( MeshRecord& meshRecord,
                             const Vector2& shadowOffset,
                             const Vector4& shadowColor )
   {
     // Scan vertex buffer to determine width and height of effect buffer needed
     MeshData::VertexContainer verts = meshRecord.mMeshData.GetVertices();
-    const float zero = 0.0f;
     const float one = 1.0f;
+    const float zero = 0.0f;
     float tlx = verts[ 0 ].x;
     float tly = verts[ 0 ].y;
     float brx = zero;
@@ -325,7 +533,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     float divHeight = 2.0f / height;
 
     // Create a buffer to render to
-    // TODO bloom style filter from this buffer
     meshRecord.mBuffer = FrameBufferImage::New( width, height );
 
     // Create a mesh actor to contain the post-effect render
@@ -348,15 +555,12 @@ struct AtlasRenderer::Impl : public ConnectionTracker
                                           Vector2( one, one ),
                                           Vector3( zero, zero, zero ) ) );
 
-    face.push_back( 0 ); face.push_back( 2u ); face.push_back( 1u );
-    face.push_back( 1u ); face.push_back( 2u ); face.push_back( 3u );
-
     MeshData meshData;
     Material newMaterial = Material::New("effect buffer");
     newMaterial.SetDiffuseTexture( meshRecord.mBuffer );
     meshData.SetMaterial( newMaterial );
     meshData.SetVertices( vertices );
-    meshData.SetFaceIndices( face );
+    meshData.SetFaceIndices( mFace );
     meshData.SetHasNormals( true );
     meshData.SetHasColor( false );
     meshData.SetHasTextureCoords( true );
@@ -364,7 +568,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
     actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
     actor.SetShaderEffect( mBgraShader );
     actor.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR );
-    actor.SetSortModifier( one ); // force behind main text
+    actor.SetSortModifier( 0.1f ); // force behind main text
 
     // Create a sub actor to render once with normalized vertex positions
     MeshData newMeshData;
@@ -441,6 +645,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker
   ShaderEffect mBgraShader;                           ///> Shader used to render BGRA glyphs
   ShaderEffect mBasicShadowShader;                    ///> Shader used to render drop shadow into buffer
   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
+  std::vector< MeshData::FaceIndex > mFace;           ///> Face indices for a quad
 };
 
 Text::RendererPtr AtlasRenderer::New()
@@ -467,8 +672,11 @@ RenderableActor AtlasRenderer::Render( Text::ViewInterface& view )
     view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs );
     mImpl->AddGlyphs( positions,
                       glyphs,
+                      view.GetTextColor(),
                       view.GetShadowOffset(),
-                      view.GetShadowColor() );
+                      view.GetShadowColor(),
+                      view.IsUnderlineEnabled(),
+                      view.GetUnderlineColor() );
   }
   return mImpl->mActor;
 }
@@ -482,4 +690,4 @@ AtlasRenderer::AtlasRenderer()
 AtlasRenderer::~AtlasRenderer()
 {
   delete mImpl;
-}
+}
\ No newline at end of file
index 219d8e5..15d79a1 100644 (file)
@@ -651,9 +651,11 @@ struct Controller::Impl
 
     mView.SetVisualModel( mVisualModel );
 
-    // Set the shadow properties to default
+    // Set the text properties to default
+    mVisualModel->SetTextColor( Color::WHITE );
     mVisualModel->SetShadowOffset( Vector2::ZERO );
     mVisualModel->SetShadowColor( Vector4::ZERO );
+    mVisualModel->SetUnderlineEnabled( false );
   }
 
   ~Impl()
@@ -849,6 +851,11 @@ void Controller::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharact
   }
 }
 
+const Vector4& Controller::GetTextColor() const
+{
+  return mImpl->mVisualModel->GetTextColor();
+}
+
 const Vector2& Controller::GetShadowOffset() const
 {
   return mImpl->mVisualModel->GetShadowOffset();
@@ -859,6 +866,21 @@ const Vector4& Controller::GetShadowColor() const
   return mImpl->mVisualModel->GetShadowColor();
 }
 
+const Vector4& Controller::GetUnderlineColor() const
+{
+  return mImpl->mVisualModel->GetUnderlineColor();
+}
+
+bool Controller::IsUnderlineEnabled() const
+{
+  return mImpl->mVisualModel->IsUnderlineEnabled();
+}
+
+void Controller::SetTextColor( const Vector4& textColor )
+{
+  mImpl->mVisualModel->SetTextColor( textColor );
+}
+
 void Controller::SetShadowOffset( const Vector2& shadowOffset )
 {
   mImpl->mVisualModel->SetShadowOffset( shadowOffset );
@@ -869,6 +891,16 @@ void Controller::SetShadowColor( const Vector4& shadowColor )
   mImpl->mVisualModel->SetShadowColor( shadowColor );
 }
 
+void Controller::SetUnderlineColor( const Vector4& color )
+{
+  mImpl->mVisualModel->SetUnderlineColor( color );
+}
+
+void Controller::SetUnderlineEnabled( bool enabled )
+{
+  mImpl->mVisualModel->SetUnderlineEnabled( enabled );
+}
+
 void Controller::EnableTextInput( DecoratorPtr decorator )
 {
   if( !mImpl->mTextInput )
index ddb1051..129459b 100644 (file)
@@ -173,32 +173,74 @@ public:
   void GetDefaultFonts( Dali::Vector<FontRun>& fonts, Length numberOfCharacters );
 
   /**
+   * @brief Set the text color
+   *
+   * @param textColor The text color
+   */
+  void SetTextColor( const Vector4& textColor );
+
+  /**
+   * @brief Retrieve the text color
+   *
+   * @return The text color
+   */
+  const Vector4& GetTextColor() const;
+
+  /**
    * @brief Set the shadow offset.
    *
    * @param[in] shadowOffset The shadow offset, 0,0 indicates no shadow.
    */
-   void SetShadowOffset( const Vector2& shadowOffset );
+  void SetShadowOffset( const Vector2& shadowOffset );
 
   /**
    * @brief Retrieve the shadow offset.
    *
    * @return The shadow offset.
    */
-   const Vector2& GetShadowOffset() const;
+  const Vector2& GetShadowOffset() const;
 
   /**
    * @brief Set the shadow color.
    *
    * @param[in] shadowColor The shadow color.
    */
-   void SetShadowColor( const Vector4& shadowColor );
+  void SetShadowColor( const Vector4& shadowColor );
 
   /**
    * @brief Retrieve the shadow color.
    *
    * @return The shadow color.
    */
-   const Vector4& GetShadowColor() const;
+  const Vector4& GetShadowColor() const;
+
+  /**
+   * @brief Set the underline color.
+   *
+   * @param[in] color color of underline.
+   */
+  void SetUnderlineColor( const Vector4& color );
+
+  /**
+   * @brief Retrieve the underline color.
+   *
+   * @return The underline color.
+   */
+  const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @brief Set the underline enabled flag.
+   *
+   * @param[in] enabled The underline enabled flag.
+   */
+  void SetUnderlineEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether the text is underlined or not.
+   *
+   * @return The underline state.
+   */
+  bool IsUnderlineEnabled() const;
 
   /**
    * @brief Called to enable text input.
index 4220b66..116ad50 100644 (file)
@@ -89,7 +89,14 @@ public:
                                   Length numberOfGlyphs ) const = 0;
 
   /**
-   * @brief Retrieves the shadow offset, 0,0 indicates no shadow.
+   * @brief Retrieves the text color
+   *
+   * @return The text color
+   */
+  virtual const Vector4& GetTextColor() const = 0;
+
+  /**
+   * @brief Retrieves the shadow offset, 0 indicates no shadow.
    *
    * @return The shadow offset.
    */
@@ -101,6 +108,21 @@ public:
    * @return The shadow color.
    */
   virtual const Vector4& GetShadowColor() const = 0;
+
+  /**
+   * @brief Retrieves the underline color.
+   *
+   * @return The underline color.
+   */
+  virtual const Vector4& GetUnderlineColor() const = 0;
+
+  /**
+   * @brief Returns whether is underline is enabled or not.
+   *
+   * @return The underline state.
+   */
+  virtual bool IsUnderlineEnabled() const = 0;
+
 };
 
 } // namespace Text
index bfe3f70..b0825f6 100644 (file)
@@ -51,6 +51,16 @@ void View::SetVisualModel( VisualModelPtr visualModel )
   mImpl->mVisualModel = visualModel;
 }
 
+const Vector4& View::GetTextColor() const
+{
+  if ( mImpl->mVisualModel )
+  {
+    VisualModel& model = *mImpl->mVisualModel;
+    return model.GetTextColor();
+  }
+  return Vector4::ZERO;
+}
+
 const Vector2& View::GetShadowOffset() const
 {
   if ( mImpl->mVisualModel )
@@ -71,6 +81,26 @@ const Vector4& View::GetShadowColor() const
   return Vector4::ZERO;
 }
 
+const Vector4& View::GetUnderlineColor() const
+{
+  if ( mImpl->mVisualModel )
+  {
+    VisualModel& model = *mImpl->mVisualModel;
+    return model.GetUnderlineColor();
+  }
+  return Vector4::ZERO;
+}
+
+bool View::IsUnderlineEnabled() const
+{
+  if ( mImpl->mVisualModel )
+  {
+    VisualModel& model = *mImpl->mVisualModel;
+    return model.IsUnderlineEnabled();
+  }
+  return false;
+}
+
 Length View::GetNumberOfGlyphs() const
 {
   if( mImpl->mVisualModel )
index ba4d3bd..b9bd7fc 100644 (file)
@@ -77,6 +77,11 @@ public:
                                   Length numberOfGlyphs ) const;
 
   /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetTextColor()
+   */
+  virtual const Vector4& GetTextColor() const;
+
+  /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetShadowOffset()
    */
   virtual const Vector2& GetShadowOffset() const;
@@ -86,6 +91,16 @@ public:
    */
   virtual const Vector4& GetShadowColor() const;
 
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineColor()
+   */
+  virtual const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::IsUnderlineEnabled()
+   */
+  virtual bool IsUnderlineEnabled() const;
+
 private:
 
   // Undefined
index 0c056ad..ec94ecc 100644 (file)
@@ -370,6 +370,16 @@ const Vector2& VisualModel::GetActualSize() const
   return mActualSize;
 }
 
+void VisualModel::SetTextColor( const Vector4& textColor )
+{
+  mTextColor = textColor;
+
+  if ( !mUnderlineColorSet )
+  {
+    mUnderlineColor = textColor;
+  }
+}
+
 void VisualModel::SetShadowOffset( const Vector2& shadowOffset )
 {
   mShadowOffset = shadowOffset;
@@ -380,6 +390,22 @@ void VisualModel::SetShadowColor( const Vector4& shadowColor )
   mShadowColor = shadowColor;
 }
 
+void VisualModel::SetUnderlineColor( const Vector4& color )
+{
+  mUnderlineColor = color;
+  mUnderlineColorSet = true;
+}
+
+void VisualModel::SetUnderlineEnabled( bool enabled )
+{
+  mUnderlineEnabled = enabled;
+}
+
+const Vector4& VisualModel::GetTextColor() const
+{
+  return mTextColor;
+}
+
 const Vector2& VisualModel::GetShadowOffset() const
 {
   return mShadowOffset;
@@ -390,12 +416,22 @@ const Vector4& VisualModel::GetShadowColor() const
   return mShadowColor;
 }
 
+const Vector4& VisualModel::GetUnderlineColor() const
+{
+  return mUnderlineColor;
+}
+
+bool VisualModel::IsUnderlineEnabled() const
+{
+  return mUnderlineEnabled;
+}
 
 VisualModel::~VisualModel()
 {
 }
 
 VisualModel::VisualModel()
+: mUnderlineColorSet( false )
 {
 }
 
index 9deaea7..c8ea7e9 100644 (file)
@@ -385,6 +385,20 @@ public:
   const Vector2& GetActualSize() const;
 
   /**
+   * @brief Set the text's color
+   *
+   * @param[in] textColor The text's color
+   */
+  void SetTextColor( const Vector4& textColor );
+
+  /**
+   * @brief Retrieve the text's color
+   *
+   * @return The text's color
+   */
+  const Vector4& GetTextColor() const;
+
+  /**
    * @brief Sets the text's shadow offset.
    *
    * @param[in] shadowOffset The shadow offset, 0,0 indicates no shadow.
@@ -412,6 +426,34 @@ public:
    */
   const Vector4& GetShadowColor() const;
 
+  /**
+   * @brief Sets the text's underline color.
+   *
+   * @param[in] color The text's underline color.
+   */
+  void SetUnderlineColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the text's underline color.
+   *
+   * @return The text's underline color.
+   */
+  const Vector4& GetUnderlineColor() const;
+
+  /**
+   * @brief Sets the text underline flag.
+   *
+   * @param[in] enabled true if underlined.
+   */
+  void SetUnderlineEnabled( bool enabled );
+
+  /**
+   * @brief Returns whether the text is underlined or not.
+   *
+   * @return underline state.
+   */
+  bool IsUnderlineEnabled() const;
+
 protected:
 
   /**
@@ -434,16 +476,20 @@ private:
 
 public:
 
-  Vector<GlyphInfo>      mGlyphs;             ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
-  Vector<CharacterIndex> mGlyphsToCharacters; ///< For each glyph, the index of the first character.
-  Vector<GlyphIndex>     mCharactersToGlyph;  ///< For each character, the index of the first glyph.
-  Vector<Length>         mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph.
-  Vector<Length>         mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
-  Vector<Vector2>        mGlyphPositions;     ///< For each glyph, the position.
-  Vector<LineRun>        mLines;              ///< The laid out lines.
-
-  Vector2                mShadowOffset;       ///< Offset for drop shadow, 0.0 indicates no shadow
-  Vector4                mShadowColor;        ///< Color of drop shadow
+  Vector<GlyphInfo>      mGlyphs;               ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
+  Vector<CharacterIndex> mGlyphsToCharacters;   ///< For each glyph, the index of the first character.
+  Vector<GlyphIndex>     mCharactersToGlyph;    ///< For each character, the index of the first glyph.
+  Vector<Length>         mCharactersPerGlyph;   ///< For each glyph, the number of characters that form the glyph.
+  Vector<Length>         mGlyphsPerCharacter;   ///< For each character, the number of glyphs that are shaped.
+  Vector<Vector2>        mGlyphPositions;       ///< For each glyph, the position.
+  Vector<LineRun>        mLines;                ///< The laid out lines.
+
+  Vector4                mTextColor;            ///< The text color
+  Vector2                mShadowOffset;         ///< Offset for drop shadow, 0 indicates no shadow
+  Vector4                mShadowColor;          ///< Color of drop shadow
+  Vector4                mUnderlineColor;       ///< Color of underline
+  bool                   mUnderlineEnabled:1;   ///< Underline enabled flag
+  bool                   mUnderlineColorSet:1;  ///< Has the underline color been explicitly set?
 
 private:
 
index ac64fe6..7ecb200 100644 (file)
@@ -64,9 +64,12 @@ public:
       POINT_SIZE,                               ///< name "point-size",           The size of font in points,                   type FLOAT
       MULTI_LINE,                               ///< name "multi-line",           The single-line or multi-line layout option,  type BOOLEAN
       HORIZONTAL_ALIGNMENT,                     ///< name "horizontal-alignment", The line horizontal alignment,                type STRING,  values "BEGIN", "CENTER", "END"
-      VERTICAL_ALIGNMENT,                        ///< name "vertical-alignment",   The line vertical alignment,                  type STRING,  values   "TOP",   "CENTER",   "BOTTOM"
+      VERTICAL_ALIGNMENT,                       ///< name "vertical-alignment",   The line vertical alignment,                  type STRING,  values   "TOP",   "CENTER",   "BOTTOM"
+      TEXT_COLOR,                               ///< name "text-color",           The text color,                               type VECTOR4
       SHADOW_OFFSET,                            ///< name "shadow-offset",        The drop shadow offset 0 indicates no shadow, type VECTOR2
-      SHADOW_COLOR,                             ///< name "shadow-color",         The color of a drop shadow                  , type VECTOR4
+      SHADOW_COLOR,                             ///< name "shadow-color",         The color of a drop shadow,                   type VECTOR4
+      UNDERLINE_ENABLED,                        ///< name "underline-enabled",    The underline enabled flag                    type BOOLEAN
+      UNDERLINE_COLOR,                          ///< name "underline-color",      The color of the underline                    type VECTOR4
     };
   };