#include <dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.h>
// EXTERNAL INCLUDES
-#include <dali/dali.h>
-#include <dali/devel-api/object/property-buffer.h>
-#include <dali/devel-api/rendering/geometry.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/images/frame-buffer-image.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
#include <dali/devel-api/rendering/renderer.h>
-#include <dali/devel-api/rendering/sampler.h>
-#include <dali/devel-api/rendering/shader.h>
+#include <dali/devel-api/rendering/geometry.h>
#include <dali/devel-api/text-abstraction/font-client.h>
-#include <dali/integration-api/debug.h>
+
// INTERNAL INCLUDES
#include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
#include <dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h>
+#include <dali-toolkit/internal/text/text-view.h>
using namespace Dali;
using namespace Dali::Toolkit;
}
struct AtlasRenderer::Impl : public ConnectionTracker
{
-
enum Style
{
STYLE_NORMAL,
struct MeshRecord
{
+ MeshRecord()
+ : mColor( Color::BLACK ),
+ mAtlasId( 0 )
+ {
+ }
+
Vector4 mColor;
uint32_t mAtlasId;
AtlasManager::Mesh2D mMesh;
FrameBufferImage mBuffer;
- bool mIsUnderline;
};
struct Extent
{
+ Extent()
+ : mBaseLine( 0.0f ),
+ mLeft( 0.0f ),
+ mRight( 0.0f ),
+ mUnderlinePosition( 0.0f ),
+ mUnderlineThickness( 0.0f ),
+ mMeshRecordIndex( 0 )
+ {
+ }
+
float mBaseLine;
float mLeft;
float mRight;
struct MaxBlockSize
{
+ MaxBlockSize()
+ : mFontId( 0 ),
+ mNeededBlockWidth( 0 ),
+ mNeededBlockHeight( 0 )
+ {
+ }
+
FontId mFontId;
uint32_t mNeededBlockWidth;
uint32_t mNeededBlockHeight;
struct CheckEntry
{
+ CheckEntry()
+ : mFontId( 0 ),
+ mIndex( 0 )
+ {
+ }
+
FontId mFontId;
Text::GlyphIndex mIndex;
};
struct TextCacheEntry
{
+ TextCacheEntry()
+ : mFontId( 0 ),
+ mIndex( 0 ),
+ mImageId( 0 )
+ {
+ }
+
FontId mFontId;
Text::GlyphIndex mIndex;
uint32_t mImageId;
mQuadIndexFormat[ "indices" ] = Property::INTEGER;
}
- void AddGlyphs( const std::vector<Vector2>& positions,
+ void AddGlyphs( Text::ViewInterface& view,
+ const std::vector<Vector2>& positions,
const Vector<GlyphInfo>& glyphs,
- const Vector4& textColor,
- const Vector2& shadowOffset,
- const Vector4& shadowColor,
- bool underlineEnabled,
- const Vector4& underlineColor,
- float underlineHeight,
int depth )
{
AtlasManager::AtlasSlot slot;
TextCacheEntry textCacheEntry;
mDepth = depth;
+ const Vector2& actorSize( view.GetControlSize() );
+ Vector2 halfActorSize( actorSize * 0.5f );
+ const Vector4& textColor( view.GetTextColor() );
+ const Vector2& shadowOffset( view.GetShadowOffset() );
+ const Vector4& shadowColor( view.GetShadowColor() );
+ bool underlineEnabled( view.IsUnderlineEnabled() );
+ const Vector4& underlineColor( view.GetUnderlineColor() );
+ float underlineHeight( view.GetUnderlineHeight() );
+
float currentUnderlinePosition = ZERO;
float currentUnderlineThickness = underlineHeight;
uint32_t currentBlockSize = 0;
style = STYLE_DROP_SHADOW;
}
- if ( mTextCache.Size() )
- {
- // Update the glyph cache with any changes to current text
- RemoveText( glyphs );
- }
-
CalculateBlocksSize( glyphs );
+ // Avoid emptying mTextCache (& removing references) until after incremented references for the new text
+ Vector< TextCacheEntry > newTextCache;
+ const GlyphInfo* const glyphsBuffer = glyphs.Begin();
+
for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
{
- const GlyphInfo& glyph = glyphs[ i ];
+ const GlyphInfo& glyph = *( glyphsBuffer + i );
// No operation for white space
if ( glyph.width && glyph.height )
FontMetrics fontMetrics;
mFontClient.GetFontMetrics( glyph.fontId, fontMetrics );
currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) );
- float descender = ceil( fabsf( fontMetrics.descender ) );
+ const float descender = ceil( fabsf( fontMetrics.descender ) );
if ( underlineHeight == ZERO )
{
}
}
- const Vector2& position = positions[ i ];
- AtlasManager::Mesh2D newMesh;
-
if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) )
{
// Select correct size for new atlas if needed....?
mGlyphManager.Add( glyph, bitmap, slot );
}
}
+ else
+ {
+ // We have 2+ copies of the same glyph
+ mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, 1/*increment*/ );
+ }
+
+ // Move the origin (0,0) of the mesh to the center of the actor
+ Vector2 position = positions[ i ] - halfActorSize;
// Generate mesh data for this quad, plugging in our supplied position
+ AtlasManager::Mesh2D newMesh;
mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
textCacheEntry.mFontId = glyph.fontId;
textCacheEntry.mImageId = slot.mImageId;
textCacheEntry.mIndex = glyph.index;
- mTextCache.PushBack( textCacheEntry );
+ newTextCache.PushBack( textCacheEntry );
// 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,
slot );
lastFontId = glyph.fontId;
}
- }
+ } // glyphs
+
+ // Now remove references for the old text
+ RemoveText();
+ mTextCache.Swap( newTextCache );
if ( underlineEnabled )
{
{
for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt )
{
- Actor actor = CreateMeshActor( *mIt );
+ Actor actor = CreateMeshActor( *mIt, actorSize );
// Create an effect if necessary
if ( style == STYLE_DROP_SHADOW )
{
- actor.Add( GenerateShadow( *mIt, shadowOffset, shadowColor ) );
+ actor.Add( GenerateShadow( *mIt, actorSize, shadowOffset, shadowColor ) );
}
if( mActor )
{
- actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
mActor.Add( actor );
}
else
metrics.mGlyphCount,
metrics.mAtlasMetrics.mAtlasCount,
metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%s\n", metrics.mVerboseGlyphCounts.c_str() );
+
for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, " Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
i + 1, i > 8 ? "" : " ",
metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8 " : "BGRA",
metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
#endif
}
- Actor CreateMeshActor( const MeshRecord& meshRecord )
+ void RemoveText()
+ {
+ for ( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter )
+ {
+ mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, -1/*decrement*/ );
+ }
+ mTextCache.Resize( 0 );
+ }
+
+ Actor CreateMeshActor( const MeshRecord& meshRecord, const Vector2& actorSize )
{
PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, meshRecord.mMesh.mVertices.Size() );
PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat, meshRecord.mMesh.mIndices.Size() );
actor.SetName( "Text renderable actor" );
#endif
actor.AddRenderer( renderer );
- actor.SetSize( 1.0f, 1.0f );
+ actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
+ actor.SetSize( actorSize );
actor.SetColor( meshRecord.mColor );
-
- if ( meshRecord.mIsUnderline )
- {
- actor.SetColorMode( USE_OWN_COLOR );
- }
- else
- {
- actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
- }
return actor;
}
// Check to see if there's a mesh data object that references the same atlas ?
uint32_t index = 0;
- for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index )
+ for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(),
+ mEndIt = meshContainer.end();
+ mIt != mEndIt;
+ ++mIt, ++index )
{
if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor )
{
meshRecord.mAtlasId = slot.mAtlasId;
meshRecord.mMesh = newMesh;
meshRecord.mColor = color;
- meshRecord.mIsUnderline = false;
meshContainer.push_back( meshRecord );
// Adjust extents for this new meshrecord
float underlineThickness )
{
bool foundExtent = false;
- for ( Vector< Extent >::Iterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
+ for ( Vector< Extent >::Iterator eIt = extents.Begin(),
+ eEndIt = extents.End();
+ eIt != eEndIt;
+ ++eIt )
{
if ( Equals( baseLine, eIt->mBaseLine ) )
{
}
}
- void RemoveText( const Vector<GlyphInfo>& glyphs )
- {
- Vector< CheckEntry > checked;
- CheckEntry checkEntry;
-
- for ( Vector< TextCacheEntry >::Iterator tCit = mTextCache.Begin(); tCit != mTextCache.End(); ++tCit )
- {
- uint32_t index = tCit->mIndex;
- uint32_t fontId = tCit->mFontId;
-
- // Check that this character has not already been checked...
- bool wasChecked = false;
- for ( Vector< CheckEntry >::Iterator cEit = checked.Begin(); cEit != checked.End(); ++cEit )
- {
- if ( fontId == cEit->mFontId && index == cEit->mIndex )
- {
- wasChecked = true;
- }
- }
-
- if ( !wasChecked )
- {
-
- int32_t newCount = 0;
- int32_t oldCount = 0;
-
- // How many times does this character occur in the old text ?
- for ( Vector< TextCacheEntry >::Iterator oTcit = mTextCache.Begin(); oTcit != mTextCache.End(); ++oTcit )
- {
- if ( fontId == oTcit->mFontId && index == oTcit->mIndex )
- {
- oldCount++;
- }
- }
-
- // And how many times in the new ?
- for ( Vector< GlyphInfo >::Iterator cGit = glyphs.Begin(); cGit != glyphs.End(); ++cGit )
- {
- if ( fontId == cGit->fontId && index == cGit->index )
- {
- newCount++;
- }
- }
- mGlyphManager.AdjustReferenceCount( fontId, tCit->mImageId, newCount - oldCount );
- checkEntry.mIndex = index;
- checkEntry.mFontId = fontId;
- checked.PushBack( checkEntry );
- }
- }
- mTextCache.Resize( 0 );
- }
-
void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
{
MaxBlockSize maxBlockSize;
}
}
- void GenerateUnderlines( std::vector< MeshRecord>& meshRecords,
+ void GenerateUnderlines( std::vector< MeshRecord >& meshRecords,
Vector< Extent >& extents,
const Vector4& underlineColor,
const Vector4& textColor )
{
AtlasManager::Mesh2D newMesh;
unsigned short faceIndex = 0;
- for ( Vector< Extent >::ConstIterator eIt = extents.Begin(); eIt != extents.End(); ++eIt )
+ for ( Vector< Extent >::ConstIterator eIt = extents.Begin(),
+ eEndIt = extents.End();
+ eIt != eEndIt;
+ ++eIt )
{
AtlasManager::Vertex2D vert;
uint32_t index = eIt->mMeshRecordIndex;
record.mMesh = newMesh;
record.mAtlasId = meshRecords[ index ].mAtlasId;
record.mColor = underlineColor;
- record.mIsUnderline = true;
meshRecords.push_back( record );
}
}
}
Actor GenerateShadow( MeshRecord& meshRecord,
+ const Vector2& actorSize,
const Vector2& shadowOffset,
const Vector4& shadowColor )
{
renderer.SetDepthIndex( CONTENT_DEPTH_INDEX + mDepth - 1 );
Actor actor = Actor::New();
actor.AddRenderer( renderer );
- actor.SetSize( 1.0f, 1.0f );
+ actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
+ actor.SetSize( actorSize );
// Create a sub actor to render the source with normalized vertex positions
Vector< AtlasManager::Vertex2D > normVertexList;
Dali::Renderer normRenderer = Dali::Renderer::New( normGeometry, normMaterial );
Actor subActor = Actor::New();
subActor.AddRenderer( normRenderer );
- subActor.SetSize( 1.0f, 1.0f );
+ subActor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned
+ subActor.SetSize( actorSize );
subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
subActor.SetColor( shadowColor );
glyphs.Resize( numberOfGlyphs );
positions.resize( numberOfGlyphs );
- mImpl->AddGlyphs( positions,
+ mImpl->AddGlyphs( view,
+ positions,
glyphs,
- view.GetTextColor(),
- view.GetShadowOffset(),
- view.GetShadowColor(),
- view.IsUnderlineEnabled(),
- view.GetUnderlineColor(),
- view.GetUnderlineHeight(),
depth );
}
AtlasRenderer::~AtlasRenderer()
{
- Vector< GlyphInfo > emptyGlyphs;
- mImpl->RemoveText( emptyGlyphs );
+ mImpl->RemoveText();
delete mImpl;
}