X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Ftext%2Frendering%2Fatlas%2Ftext-atlas-renderer.cpp;h=b655772532e9d9ab37035e19dc4ca022b2fbe5c5;hp=e6d548fca1eaadf4c1cc8cdade03abe3795cf3d2;hb=7c53e2bd8999b5a488d6b701b240c708b5341584;hpb=e2aa6c795f24794c33e2d2bfde3adeefefad6cf4 diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp index e6d548f..b655772 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -19,17 +19,20 @@ #include // EXTERNAL INCLUDES -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include +#include #include -#include + // INTERNAL INCLUDES #include +#include #include +#include using namespace Dali; using namespace Dali::Toolkit; @@ -50,7 +53,6 @@ const uint32_t DEFAULT_ATLAS_HEIGHT = 512u; } struct AtlasRenderer::Impl : public ConnectionTracker { - enum Style { STYLE_NORMAL, @@ -59,15 +61,34 @@ struct AtlasRenderer::Impl : public ConnectionTracker struct MeshRecord { + MeshRecord() + : mColor( Color::BLACK ), + mAtlasId( 0 ) + { + } + Vector4 mColor; uint32_t mAtlasId; AtlasManager::Mesh2D mMesh; FrameBufferImage mBuffer; - bool mIsUnderline; }; + /** + * brief Struct used to generate the underline mesh. + * There is one Extent per line of text. + */ 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; @@ -78,6 +99,13 @@ struct AtlasRenderer::Impl : public ConnectionTracker struct MaxBlockSize { + MaxBlockSize() + : mFontId( 0 ), + mNeededBlockWidth( 0 ), + mNeededBlockHeight( 0 ) + { + } + FontId mFontId; uint32_t mNeededBlockWidth; uint32_t mNeededBlockHeight; @@ -85,12 +113,25 @@ struct AtlasRenderer::Impl : public ConnectionTracker 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; @@ -107,8 +148,30 @@ struct AtlasRenderer::Impl : public ConnectionTracker mQuadIndexFormat[ "indices" ] = Property::INTEGER; } + bool IsGlyphUnderlined( GlyphIndex index, + const Vector& underlineRuns ) + { + // TODO: At the moment it works because we always traverse the glyphs starting from the beginning + // and there is only one glyph run! If there are more they should be ordered. + + for( Vector::ConstIterator it = underlineRuns.Begin(), + endIt = underlineRuns.End(); + it != endIt; + ++it ) + { + const GlyphRun& run = *it; + + if( ( run.glyphIndex <= index ) && ( index < run.glyphIndex + run.numberOfGlyphs ) ) + { + return true; + } + } + + return false; + } + void AddGlyphs( Text::ViewInterface& view, - const std::vector& positions, + const Vector& positions, const Vector& glyphs, int depth ) { @@ -119,18 +182,29 @@ struct AtlasRenderer::Impl : public ConnectionTracker mDepth = depth; const Vector2& actorSize( view.GetControlSize() ); - Vector2 halfActorSize( actorSize * 0.5f ); + const 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 bool underlineEnabled( view.IsUnderlineEnabled() ); const Vector4& underlineColor( view.GetUnderlineColor() ); - float underlineHeight( view.GetUnderlineHeight() ); + const float underlineHeight( view.GetUnderlineHeight() ); + + // Get the underline runs. + const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns(); + Vector underlineRuns; + underlineRuns.Resize( numberOfUnderlineRuns ); + view.GetUnderlineRuns( underlineRuns.Begin(), + 0u, + numberOfUnderlineRuns ); + + bool thereAreUnderlinedGlyphs = false; float currentUnderlinePosition = ZERO; float currentUnderlineThickness = underlineHeight; uint32_t currentBlockSize = 0; FontId lastFontId = 0; + FontId lastUnderlinedFontId = 0; Style style = STYLE_NORMAL; if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 ) @@ -142,22 +216,27 @@ struct AtlasRenderer::Impl : public ConnectionTracker // Avoid emptying mTextCache (& removing references) until after incremented references for the new text Vector< TextCacheEntry > newTextCache; + const GlyphInfo* const glyphsBuffer = glyphs.Begin(); + const Vector2* const positionsBuffer = positions.Begin(); for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i ) { - const GlyphInfo& glyph = glyphs[ i ]; + const GlyphInfo& glyph = *( glyphsBuffer + i ); + + const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( i, underlineRuns ); + thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph; // No operation for white space if ( glyph.width && glyph.height ) { // Are we still using the same fontId as previous - if ( glyph.fontId != lastFontId ) + if ( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) ) { // We need to fetch fresh font underline metrics 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 ) { @@ -184,7 +263,9 @@ struct AtlasRenderer::Impl : public ConnectionTracker // Move offset down by one ( EFL behavior ) currentUnderlinePosition = ONE; } - } + + lastUnderlinedFontId = glyph.fontId; + } // underline if ( !mGlyphManager.Cached( glyph.fontId, glyph.index, slot ) ) { @@ -240,7 +321,7 @@ struct AtlasRenderer::Impl : public ConnectionTracker } // Move the origin (0,0) of the mesh to the center of the actor - Vector2 position = positions[ i ] - halfActorSize; + Vector2 position = *( positionsBuffer + i ) - halfActorSize; // Generate mesh data for this quad, plugging in our supplied position AtlasManager::Mesh2D newMesh; @@ -250,24 +331,35 @@ struct AtlasRenderer::Impl : public ConnectionTracker textCacheEntry.mIndex = glyph.index; newTextCache.PushBack( textCacheEntry ); + // Adjust the vertices if the fixed-size font should be down-scaled + if( glyph.scaleFactor > 0 ) + { + for( unsigned int i=0; i& extents, const Vector4& color, float baseLine, + bool underlineGlyph, float underlinePosition, float underlineThickness, AtlasManager::AtlasSlot& slot ) @@ -379,20 +465,28 @@ struct AtlasRenderer::Impl : public ConnectionTracker // 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 ) { // Stitch the mesh to the existing mesh and adjust any extents mGlyphManager.StitchMesh( mIt->mMesh, newMesh ); - AdjustExtents( extents, - meshContainer, - index, - left, - right, - baseLine, - underlinePosition, - underlineThickness ); + + if( underlineGlyph ) + { + AdjustExtents( extents, + meshContainer, + index, + left, + right, + baseLine, + underlinePosition, + underlineThickness ); + } + return; } } @@ -402,19 +496,20 @@ struct AtlasRenderer::Impl : public ConnectionTracker meshRecord.mAtlasId = slot.mAtlasId; meshRecord.mMesh = newMesh; meshRecord.mColor = color; - meshRecord.mIsUnderline = false; meshContainer.push_back( meshRecord ); - // Adjust extents for this new meshrecord - AdjustExtents( extents, - meshContainer, - meshContainer.size() - 1u, - left, - right, - baseLine, - underlinePosition, - underlineThickness ); - + if( underlineGlyph ) + { + // Adjust extents for this new meshrecord + AdjustExtents( extents, + meshContainer, + meshContainer.size() - 1u, + left, + right, + baseLine, + underlinePosition, + underlineThickness ); + } } } @@ -428,7 +523,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker 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 ) ) { @@ -491,14 +589,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker } } - 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; @@ -553,7 +654,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker record.mMesh = newMesh; record.mAtlasId = meshRecords[ index ].mAtlasId; record.mColor = underlineColor; - record.mIsUnderline = true; meshRecords.push_back( record ); } } @@ -623,8 +723,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker Dali::Renderer renderer = Dali::Renderer::New( quadGeometry, material ); - // Ensure shadow is behind the text... - renderer.SetDepthIndex( CONTENT_DEPTH_INDEX + mDepth - 1 ); + // Set depth index to -1.0 to make sure shadow is rendered first in 3D layers + renderer.SetDepthIndex( -1.0f ); Actor actor = Actor::New(); actor.AddRenderer( renderer ); actor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned @@ -657,29 +757,43 @@ struct AtlasRenderer::Impl : public ConnectionTracker subActor.AddRenderer( normRenderer ); subActor.SetParentOrigin( ParentOrigin::CENTER ); // Keep all of the origins aligned subActor.SetSize( actorSize ); - subActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); subActor.SetColor( shadowColor ); + // Discard redundant render-tasks + RemoveShadowRenderTask(); + // Create a render task to render the effect - RenderTask task = Stage::GetCurrent().GetRenderTaskList().CreateTask(); - task.SetTargetFrameBuffer( meshRecord.mBuffer ); - task.SetSourceActor( subActor ); - task.SetClearEnabled( true ); - task.SetClearColor( Vector4::ZERO ); - task.SetExclusive( true ); - task.SetRefreshRate( RenderTask::REFRESH_ONCE ); - task.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete ); + mShadowTask = Stage::GetCurrent().GetRenderTaskList().CreateTask(); + mShadowTask.SetTargetFrameBuffer( meshRecord.mBuffer ); + mShadowTask.SetSourceActor( subActor ); + mShadowTask.SetClearEnabled( true ); + mShadowTask.SetClearColor( Vector4::ZERO ); + mShadowTask.SetExclusive( true ); + mShadowTask.SetRefreshRate( RenderTask::REFRESH_ONCE ); + mShadowTask.FinishedSignal().Connect( this, &AtlasRenderer::Impl::RenderComplete ); actor.Add( subActor ); return actor; } - void RenderComplete( RenderTask& renderTask ) + void RemoveShadowRenderTask() { - // Disconnect and remove this single shot render task - renderTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete ); - Stage::GetCurrent().GetRenderTaskList().RemoveTask( renderTask ); + if( mShadowTask ) + { + mShadowTask.FinishedSignal().Disconnect( this, &AtlasRenderer::Impl::RenderComplete ); + + // Guard to prevent accessing Stage after dali-core destruction + if( Stage::IsInstalled() ) + { + Stage::GetCurrent().GetRenderTaskList().RemoveTask( mShadowTask ); + } + + mShadowTask.Reset(); + } + } + void RenderComplete( RenderTask& renderTask ) + { // Get the actor used for render to buffer and remove it from the parent Actor renderActor = renderTask.GetSourceActor(); if ( renderActor ) @@ -690,10 +804,13 @@ struct AtlasRenderer::Impl : public ConnectionTracker parent.Remove( renderActor ); } } + + RemoveShadowRenderTask(); } Actor mActor; ///< The actor parent which renders the text AtlasGlyphManager mGlyphManager; ///< Glyph Manager to handle upload and caching + RenderTask mShadowTask; ///< Used to render shadows TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information std::vector< MaxBlockSize > mBlockSizes; ///> Maximum size needed to contain a glyph in a block within a new atlas std::vector< uint32_t > mFace; ///> Face indices for a quad @@ -721,15 +838,15 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth ) Vector glyphs; glyphs.Resize( numberOfGlyphs ); - std::vector positions; - positions.resize( numberOfGlyphs ); + Vector positions; + positions.Resize( numberOfGlyphs ); numberOfGlyphs = view.GetGlyphs( glyphs.Begin(), - &positions[0], + positions.Begin(), 0u, numberOfGlyphs ); glyphs.Resize( numberOfGlyphs ); - positions.resize( numberOfGlyphs ); + positions.Resize( numberOfGlyphs ); mImpl->AddGlyphs( view, positions, @@ -748,6 +865,8 @@ AtlasRenderer::AtlasRenderer() AtlasRenderer::~AtlasRenderer() { + mImpl->RemoveShadowRenderTask(); + mImpl->RemoveText(); delete mImpl; }