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=4fc28f87383f2adae5e4054f0e8c87727b6ebe27;hp=54a746a4f2ad40513224a267092da7738944b622;hb=01c086f17e2af89f6c6b1bd30a0240da2fda1e75;hpb=268b84c52355a70b2f3090fc9381d269a17cbeaf diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp old mode 100644 new mode 100755 index 54a746a..4fc28f8 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * 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. @@ -21,7 +21,6 @@ // EXTERNAL INCLUDES #include #include -#include #include #include #include @@ -50,7 +49,7 @@ attribute mediump vec2 aPosition; attribute mediump vec2 aTexCoord; attribute mediump vec4 aColor; uniform mediump vec2 uOffset; -uniform mediump mat4 uMvpMatrix; +uniform highp mat4 uMvpMatrix; varying mediump vec2 vTexCoord; varying mediump vec4 vColor; @@ -94,7 +93,7 @@ const float HALF( 0.5f ); const float ONE( 1.0f ); const uint32_t DEFAULT_ATLAS_WIDTH = 512u; const uint32_t DEFAULT_ATLAS_HEIGHT = 512u; -const int NO_OUTLINE( 0 ); +const uint16_t NO_OUTLINE = 0u; } struct AtlasRenderer::Impl @@ -114,7 +113,6 @@ struct AtlasRenderer::Impl uint32_t mAtlasId; AtlasManager::Mesh2D mMesh; - FrameBufferImage mBuffer; }; /** @@ -170,15 +168,21 @@ struct AtlasRenderer::Impl struct TextCacheEntry { TextCacheEntry() - : mFontId( 0 ), - mIndex( 0 ), - mImageId( 0 ) + : mFontId{ 0u }, + mIndex{ 0u }, + mImageId{ 0u }, + mOutlineWidth{ 0u }, + isItalic{ false }, + isBold{ false } { } FontId mFontId; Text::GlyphIndex mIndex; uint32_t mImageId; + uint16_t mOutlineWidth; + bool isItalic:1; + bool isBold:1; }; Impl() @@ -211,9 +215,9 @@ struct AtlasRenderer::Impl return false; } - void CacheGlyph( const GlyphInfo& glyph, FontId lastFontId, AtlasManager::AtlasSlot& slot ) + void CacheGlyph( const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot ) { - bool glyphNotCached = !mGlyphManager.IsCached( glyph.fontId, glyph.index, slot ); // Check FontGlyphRecord vector for entry with glyph index and fontId + const bool glyphNotCached = !mGlyphManager.IsCached( glyph.fontId, glyph.index, style, slot ); // Check FontGlyphRecord vector for entry with glyph index and fontId DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached)?"not cached":"cached" ); @@ -242,62 +246,71 @@ struct AtlasRenderer::Impl // Create a new image for the glyph PixelData bitmap; + // Whether the glyph is an outline. + const bool isOutline = 0u != style.outline; + // Whether the current glyph is a color one. const bool isColorGlyph = mFontClient.IsColorGlyph( glyph.fontId, glyph.index ); - // Retrieve the emoji's bitmap. - TextAbstraction::FontClient::GlyphBufferData glyphBufferData; - glyphBufferData.width = isColorGlyph ? glyph.width : 0; // Desired width and height. - glyphBufferData.height = isColorGlyph ? glyph.height : 0; - - mFontClient.CreateBitmap( glyph.fontId, - glyph.index, - glyphBufferData, - NO_OUTLINE ); - - // Create the pixel data. - bitmap = PixelData::New( glyphBufferData.buffer, - glyph.width * glyph.height * GetBytesPerPixel( glyphBufferData.format ), - glyph.width, - glyph.height, - glyphBufferData.format, - PixelData::DELETE_ARRAY ); - - if( bitmap ) + if( !isOutline || ( isOutline && !isColorGlyph) ) { - // Ensure that the next image will fit into the current block size - if( bitmap.GetWidth() > blockSize.mNeededBlockWidth ) + // Retrieve the emoji's bitmap. + TextAbstraction::FontClient::GlyphBufferData glyphBufferData; + glyphBufferData.width = isColorGlyph ? glyph.width : 0; // Desired width and height. + glyphBufferData.height = isColorGlyph ? glyph.height : 0; + + mFontClient.CreateBitmap( glyph.fontId, + glyph.index, + glyph.isItalicRequired, + glyph.isBoldRequired, + glyphBufferData, + style.outline ); + + // Create the pixel data. + bitmap = PixelData::New( glyphBufferData.buffer, + glyphBufferData.width * glyphBufferData.height * GetBytesPerPixel( glyphBufferData.format ), + glyphBufferData.width, + glyphBufferData.height, + glyphBufferData.format, + PixelData::DELETE_ARRAY ); + + if( bitmap ) { - blockSize.mNeededBlockWidth = bitmap.GetWidth(); - } + // Ensure that the next image will fit into the current block size + if( bitmap.GetWidth() > blockSize.mNeededBlockWidth ) + { + blockSize.mNeededBlockWidth = bitmap.GetWidth(); + } - if( bitmap.GetHeight() > blockSize.mNeededBlockHeight ) - { - blockSize.mNeededBlockHeight = bitmap.GetHeight(); - } + if( bitmap.GetHeight() > blockSize.mNeededBlockHeight ) + { + blockSize.mNeededBlockHeight = bitmap.GetHeight(); + } - // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas + // If CheckAtlas in AtlasManager::Add can't fit the bitmap in the current atlas it will create a new atlas - // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice. - mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH, - DEFAULT_ATLAS_HEIGHT, - blockSize.mNeededBlockWidth, - blockSize.mNeededBlockHeight ); + // Setting the block size and size of new atlas does not mean a new one will be created. An existing atlas may still surffice. + mGlyphManager.SetNewAtlasSize( DEFAULT_ATLAS_WIDTH, + DEFAULT_ATLAS_HEIGHT, + blockSize.mNeededBlockWidth, + blockSize.mNeededBlockHeight ); - // Locate a new slot for our glyph - mGlyphManager.Add( glyph, bitmap, slot ); // slot will be 0 is glyph not added + // Locate a new slot for our glyph + mGlyphManager.Add( glyph, style, bitmap, slot ); // slot will be 0 is glyph not added + } } } else { // We have 2+ copies of the same glyph - mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, 1/*increment*/ ); + mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, style, 1 ); //increment } } void GenerateMesh( const GlyphInfo& glyph, const Vector2& position, const Vector4& color, + uint16_t outline, AtlasManager::AtlasSlot& slot, bool underlineGlyph, float currentUnderlinePosition, @@ -314,6 +327,9 @@ struct AtlasRenderer::Impl textCacheEntry.mFontId = glyph.fontId; textCacheEntry.mImageId = slot.mImageId; textCacheEntry.mIndex = glyph.index; + textCacheEntry.mOutlineWidth = outline; + textCacheEntry.isItalic = glyph.isItalicRequired; + textCacheEntry.isBold = glyph.isBoldRequired; newTextCache.PushBack( textCacheEntry ); @@ -342,21 +358,21 @@ struct AtlasRenderer::Impl void CreateActors( const std::vector& meshContainer, const Size& textSize, - const Vector4& defaultColor, + const Vector4& color, const Vector4& shadowColor, const Vector2& shadowOffset, - Style style, Actor textControl, - Property::Index animatablePropertyIndex ) + Property::Index animatablePropertyIndex, + bool drawShadow ) { if( !mActor ) { // Create a container actor to act as a common parent for text and shadow, to avoid color inheritence issues. mActor = Actor::New(); - mActor.SetParentOrigin( ParentOrigin::TOP_LEFT ); - mActor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - mActor.SetSize( textSize ); - mActor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); + mActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT ); + mActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT ); + mActor.SetProperty( Actor::Property::SIZE, textSize ); + mActor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR ); } for( std::vector< MeshRecord >::const_iterator it = meshContainer.begin(), @@ -365,14 +381,14 @@ struct AtlasRenderer::Impl { const MeshRecord& meshRecord = *it; - Actor actor = CreateMeshActor( textControl, animatablePropertyIndex, defaultColor, meshRecord, textSize, STYLE_NORMAL ); + Actor actor = CreateMeshActor( textControl, animatablePropertyIndex, color, meshRecord, textSize, STYLE_NORMAL ); // Whether the actor has renderers. const bool hasRenderer = actor.GetRendererCount() > 0u; // Create an effect if necessary if( hasRenderer && - ( style == STYLE_DROP_SHADOW ) ) + drawShadow ) { // Change the color of the vertices. for( Vector::Iterator vIt = meshRecord.mMesh.mVertices.Begin(), @@ -385,9 +401,9 @@ struct AtlasRenderer::Impl vertex.mColor = shadowColor; } - Actor shadowActor = CreateMeshActor(textControl, animatablePropertyIndex, defaultColor, meshRecord, textSize, STYLE_DROP_SHADOW ); + Actor shadowActor = CreateMeshActor(textControl, animatablePropertyIndex, color, meshRecord, textSize, STYLE_DROP_SHADOW ); #if defined(DEBUG_ENABLED) - shadowActor.SetName( "Text Shadow renderable actor" ); + shadowActor.SetProperty( Dali::Actor::Property::NAME, "Text Shadow renderable actor" ); #endif // Offset shadow in x and y shadowActor.RegisterProperty("uOffset", shadowOffset ); @@ -416,7 +432,15 @@ struct AtlasRenderer::Impl float minLineOffset ) { AtlasManager::AtlasSlot slot; + slot.mImageId = 0u; + slot.mAtlasId = 0u; + + AtlasManager::AtlasSlot slotOutline; + slotOutline.mImageId = 0u; + slotOutline.mAtlasId = 0u; + std::vector< MeshRecord > meshContainer; + std::vector< MeshRecord > meshContainerOutline; Vector< Extent > extents; mDepth = depth; @@ -424,9 +448,12 @@ struct AtlasRenderer::Impl const Vector2 halfTextSize( textSize * 0.5f ); const Vector2& shadowOffset( view.GetShadowOffset() ); const Vector4& shadowColor( view.GetShadowColor() ); - const bool underlineEnabled( view.IsUnderlineEnabled() ); + const bool underlineEnabled = view.IsUnderlineEnabled(); const Vector4& underlineColor( view.GetUnderlineColor() ); - const float underlineHeight( view.GetUnderlineHeight() ); + const float underlineHeight = view.GetUnderlineHeight(); + const uint16_t outlineWidth = view.GetOutlineWidth(); + const Vector4& outlineColor( view.GetOutlineColor() ); + const bool isOutline = 0u != outlineWidth; const bool useDefaultColor = ( NULL == colorsBuffer ); @@ -462,14 +489,14 @@ struct AtlasRenderer::Impl for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i ) { const GlyphInfo& glyph = *( glyphsBuffer + i ); - const bool underlineGlyph = underlineEnabled || IsGlyphUnderlined( i, underlineRuns ); - thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || underlineGlyph; + const bool isGlyphUnderlined = underlineEnabled || IsGlyphUnderlined( i, underlineRuns ); + thereAreUnderlinedGlyphs = thereAreUnderlinedGlyphs || isGlyphUnderlined; // No operation for white space if( glyph.width && glyph.height ) { // Are we still using the same fontId as previous - if( underlineGlyph && ( glyph.fontId != lastUnderlinedFontId ) ) + if( isGlyphUnderlined && ( glyph.fontId != lastUnderlinedFontId ) ) { // We need to fetch fresh font underline metrics FontMetrics fontMetrics; @@ -507,23 +534,44 @@ struct AtlasRenderer::Impl lastUnderlinedFontId = glyph.fontId; } // underline + AtlasGlyphManager::GlyphStyle style; + style.isItalic = glyph.isItalicRequired; + style.isBold = glyph.isBoldRequired; + // Retrieves and caches the glyph's bitmap. - CacheGlyph( glyph, lastFontId, slot ); + CacheGlyph( glyph, lastFontId, style, slot ); + + // Retrieves and caches the outline glyph's bitmap. + if( isOutline ) + { + style.outline = outlineWidth; + CacheGlyph( glyph, lastFontId, style, slotOutline ); + } // Move the origin (0,0) of the mesh to the center of the actor - const Vector2 position = *( positionsBuffer + i ) - halfTextSize - lineOffsetPosition; + const Vector2& temp = *( positionsBuffer + i ); + const Vector2 position = Vector2( roundf( temp.x ), temp.y ) - halfTextSize - lineOffsetPosition; // roundf() avoids pixel alignment issues. if ( 0u != slot.mImageId ) // invalid slot id, glyph has failed to be added to atlas { + Vector2 positionPlusOutlineOffset = position; + if( isOutline ) + { + // Add an offset to the text. + const float outlineWidthOffset = static_cast( outlineWidth ); + positionPlusOutlineOffset += Vector2( outlineWidthOffset, outlineWidthOffset ); + } + // Get the color of the character. const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i ); const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u ); GenerateMesh( glyph, - position, + positionPlusOutlineOffset, color, + NO_OUTLINE, slot, - underlineGlyph, + isGlyphUnderlined, currentUnderlinePosition, currentUnderlineThickness, meshContainer, @@ -532,6 +580,21 @@ struct AtlasRenderer::Impl lastFontId = glyph.fontId; // Prevents searching for existing blocksizes when string of the same fontId. } + + if( isOutline && ( 0u != slotOutline.mImageId ) ) // invalid slot id, glyph has failed to be added to atlas + { + GenerateMesh( glyph, + position, + outlineColor, + outlineWidth, + slotOutline, + false, + currentUnderlinePosition, + currentUnderlineThickness, + meshContainerOutline, + newTextCache, + extents); + } } } // glyphs @@ -546,16 +609,34 @@ struct AtlasRenderer::Impl } // For each MeshData object, create a mesh actor and add to the renderable actor + bool isShadowDrawn = false; + if( !meshContainerOutline.empty() ) + { + const bool drawShadow = STYLE_DROP_SHADOW == style; + CreateActors( meshContainerOutline, + textSize, + outlineColor, + shadowColor, + shadowOffset, + textControl, + animatablePropertyIndex, + drawShadow ); + + isShadowDrawn = drawShadow; + } + + // For each MeshData object, create a mesh actor and add to the renderable actor if( !meshContainer.empty() ) { + const bool drawShadow = !isShadowDrawn && ( STYLE_DROP_SHADOW == style ); CreateActors( meshContainer, textSize, defaultColor, shadowColor, shadowOffset, - style, textControl, - animatablePropertyIndex ); + animatablePropertyIndex, + drawShadow ); } #if defined(DEBUG_ENABLED) @@ -586,7 +667,11 @@ struct AtlasRenderer::Impl { for( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter ) { - mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, -1/*decrement*/ ); + AtlasGlyphManager::GlyphStyle style; + style.outline = oldTextIter->mOutlineWidth; + style.isItalic = oldTextIter->isItalic; + style.isBold = oldTextIter->isBold; + mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, style, -1/*decrement*/ ); } mTextCache.Resize( 0 ); } @@ -594,7 +679,7 @@ struct AtlasRenderer::Impl Actor CreateMeshActor( Actor textControl, Property::Index animatablePropertyIndex, const Vector4& defaultColor, const MeshRecord& meshRecord, const Vector2& actorSize, Style style ) { - PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat ); + VertexBuffer quadVertices = VertexBuffer::New( mQuadVertexFormat ); quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ), meshRecord.mMesh.mVertices.Size() ); Geometry quadGeometry = Geometry::New(); @@ -652,15 +737,16 @@ struct AtlasRenderer::Impl Actor actor = Actor::New(); #if defined(DEBUG_ENABLED) - actor.SetName( "Text renderable actor" ); + actor.SetProperty( Dali::Actor::Property::NAME, "Text renderable actor" ); #endif actor.AddRenderer( renderer ); // Keep all of the origins aligned - actor.SetParentOrigin( ParentOrigin::TOP_LEFT ); - actor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); - actor.SetSize( actorSize ); + actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT ); + actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT ); + actor.SetProperty( Actor::Property::SIZE, actorSize ); actor.RegisterProperty("uOffset", Vector2::ZERO ); - actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR ); + actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR ); + return actor; }