From: Richard Underhill Date: Tue, 14 Apr 2015 09:21:45 +0000 (+0100) Subject: Added UNDERLINE_HEIGHT Property to override font metrics X-Git-Tag: dali_1.0.38~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=de8dbd015aacaf2bcaa3a451c7a4aa5a949833e6 Added UNDERLINE_HEIGHT Property to override font metrics Change-Id: I04398e2ef68a758ed6524a6fa7640e9a35c6532c Signed-off-by: Richard Underhill --- diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 0cfec05..afe74e2 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -88,6 +88,7 @@ DALI_PROPERTY_REGISTRATION( TextLabel, "shadow-offset", VECTOR2, SHADOW_O 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_PROPERTY_REGISTRATION( TextLabel, "underline-height", FLOAT, UNDERLINE_HEIGHT ) DALI_TYPE_REGISTRATION_END() } // namespace @@ -289,6 +290,20 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr } break; } + + case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT: + { + if( impl.mController ) + { + float height = value.Get< float >(); + if ( impl.mController->GetUnderlineHeight() != height ) + { + impl.mController->SetUnderlineHeight( height ); + impl.RequestTextRelayout(); + } + } + break; + } } } } @@ -387,6 +402,14 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde } break; } + case Toolkit::TextLabel::Property::UNDERLINE_HEIGHT: + { + if ( impl.mController ) + { + value = impl.mController->GetUnderlineHeight(); + } + break; + } } } 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 fda82f4..b06d4e6 100644 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -41,6 +41,10 @@ namespace const Vector2 DEFAULT_ATLAS_SIZE( 512.0f, 512.0f ); const Vector2 DEFAULT_BLOCK_SIZE( 16.0f, 16.0f ); const Vector2 PADDING( 4.0f, 4.0f ); // Allow for variation in font glyphs + const float ZERO( 0.0f ); + const float HALF( 0.5f ); + const float ONE( 1.0f ); + const float TWO( 2.0f ); } struct AtlasRenderer::Impl : public ConnectionTracker @@ -102,19 +106,21 @@ struct AtlasRenderer::Impl : public ConnectionTracker const Vector4& textColor, const Vector2& shadowOffset, const Vector4& shadowColor, - float underlineEnabled, - const Vector4& underlineColor ) + bool underlineEnabled, + const Vector4& underlineColor, + float underlineHeight ) { AtlasManager::AtlasSlot slot; std::vector< MeshRecord > meshContainer; Vector< Extent > extents; - float currentUnderlinePosition = 0.0f; - float currentUnderlineThickness = 0.0f; + float currentUnderlinePosition = ZERO; + float currentUnderlineThickness = underlineHeight; + FontId lastFontId = 0; Style style = STYLE_NORMAL; - if ( shadowOffset.x != 0.0f || shadowOffset.y != 0.0f ) + if ( fabsf( shadowOffset.x ) > Math::MACHINE_EPSILON_1 || fabsf( shadowOffset.y ) > Math::MACHINE_EPSILON_1 ) { style = STYLE_DROP_SHADOW; } @@ -140,13 +146,33 @@ struct AtlasRenderer::Impl : public ConnectionTracker // We need to fetch fresh font underline metrics FontMetrics fontMetrics; mFontClient.GetFontMetrics( glyph.fontId, fontMetrics ); - currentUnderlinePosition = fontMetrics.underlinePosition; - currentUnderlineThickness = fontMetrics.underlineThickness; + currentUnderlinePosition = ceil( fabsf( fontMetrics.underlinePosition ) ); + float descender = ceil( fabsf( fontMetrics.descender ) ); + + if ( underlineHeight == ZERO ) + { + currentUnderlineThickness = fontMetrics.underlineThickness; + + // Ensure underline will be at least a pixel high + if ( currentUnderlineThickness < ONE ) + { + currentUnderlineThickness = ONE; + } + else + { + currentUnderlineThickness = ceil( currentUnderlineThickness ); + } + } - // Ensure that an underline is at least 1 pixel high - if ( currentUnderlineThickness < 1.0f ) + // Clamp the underline position at the font descender and check for ( as EFL describes it ) a broken font + if ( currentUnderlinePosition > descender ) { - currentUnderlineThickness = 1.0f; + currentUnderlinePosition = descender; + } + if ( ZERO == currentUnderlinePosition ) + { + // Move offset down by one ( EFL behavior ) + currentUnderlinePosition = ONE; } } @@ -289,14 +315,13 @@ struct AtlasRenderer::Impl : public ConnectionTracker uint32_t index = 0; for ( std::vector< MeshRecord >::iterator mIt = meshContainer.begin(); mIt != meshContainer.end(); ++mIt, ++index ) { - if ( slot.mAtlasId == mIt->mAtlasId ) + if ( slot.mAtlasId == mIt->mAtlasId && color == mIt->mColor ) { // Stitch the mesh to the existing mesh and adjust any extents mGlyphManager.StitchMesh( mIt->mMeshData, newMeshData ); AdjustExtents( extents, meshContainer, index, - color, left, right, baseLine, @@ -318,7 +343,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker AdjustExtents( extents, meshContainer, meshContainer.size() - 1u, - color, left, right, baseLine, @@ -331,7 +355,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker void AdjustExtents( Vector< Extent >& extents, std::vector< MeshRecord>& meshRecords, uint32_t index, - const Vector4& color, float left, float right, float baseLine, @@ -343,21 +366,17 @@ struct AtlasRenderer::Impl : public ConnectionTracker { 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 ) { - foundExtent = true; - if ( left < eIt->mLeft ) - { - eIt->mLeft = left; - } - if ( right > eIt->mRight ) - { - eIt->mRight = right; - } + eIt->mLeft = left; } - // Font metrics use negative values for lower underline positions - if ( underlinePosition < eIt->mUnderlinePosition ) + if ( right > eIt->mRight ) + { + eIt->mRight = right; + } + + if ( underlinePosition > eIt->mUnderlinePosition ) { eIt->mUnderlinePosition = underlinePosition; } @@ -437,9 +456,6 @@ struct AtlasRenderer::Impl : public ConnectionTracker 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; @@ -448,28 +464,28 @@ struct AtlasRenderer::Impl : public ConnectionTracker 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 u = HALF / uv.x; + float v = HALF / uv.y; float thickness = eIt->mUnderlineThickness; - float baseLine = eIt->mBaseLine - eIt->mUnderlinePosition - ( thickness * 0.5f ); + float baseLine = eIt->mBaseLine + eIt->mUnderlinePosition - ( thickness * HALF ); 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( tlx, baseLine, ZERO ), + Vector2::ZERO, + Vector3::ZERO ) ); - newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, zero ), - Vector2( u, zero ), - Vector3( zero, zero, zero ) ) ); + newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine, ZERO ), + Vector2( u, ZERO ), + Vector3::ZERO ) ); - newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, zero ), - Vector2( zero, v ), - Vector3( zero, zero, zero ) ) ); + newVerts.push_back( MeshData::Vertex( Vector3( tlx, baseLine + thickness, ZERO ), + Vector2( ZERO, v ), + Vector3::ZERO ) ); - newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, zero ), + newVerts.push_back( MeshData::Vertex( Vector3( brx, baseLine + thickness, ZERO ), Vector2( u, v ), - Vector3( zero, zero, zero ) ) ); + Vector3::ZERO ) ); newMeshData.SetVertices( newVerts ); newMeshData.SetFaceIndices( mFace ); @@ -500,12 +516,10 @@ struct AtlasRenderer::Impl : public ConnectionTracker { // Scan vertex buffer to determine width and height of effect buffer needed MeshData::VertexContainer verts = meshRecord.mMeshData.GetVertices(); - const float one = 1.0f; - const float zero = 0.0f; float tlx = verts[ 0 ].x; float tly = verts[ 0 ].y; - float brx = zero; - float bry = zero; + float brx = ZERO; + float bry = ZERO; for ( uint32_t i = 0; i < verts.size(); ++i ) { @@ -529,8 +543,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker float width = brx - tlx; float height = bry - tly; - float divWidth = 2.0f / width; - float divHeight = 2.0f / height; + float divWidth = TWO / width; + float divHeight = TWO / height; // Create a buffer to render to meshRecord.mBuffer = FrameBufferImage::New( width, height ); @@ -539,21 +553,21 @@ struct AtlasRenderer::Impl : public ConnectionTracker MeshData::VertexContainer vertices; MeshData::FaceIndices face; - vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, zero ), - Vector2( zero, zero ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, tly + shadowOffset.y, ZERO ), + Vector2::ZERO, + Vector3::ZERO ) ); - vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, zero ), - Vector2( one, zero ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, tly + shadowOffset.y, ZERO ), + Vector2( ONE, ZERO ), + Vector3::ZERO ) ); - vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, zero ), - Vector2( zero, one ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( tlx + shadowOffset.x, bry + shadowOffset.y, ZERO ), + Vector2( ZERO, ONE ), + Vector3::ZERO ) ); - vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, zero ), - Vector2( one, one ), - Vector3( zero, zero, zero ) ) ); + vertices.push_back( MeshData::Vertex( Vector3( brx + shadowOffset.x, bry + shadowOffset.y, ZERO ), + Vector2::ONE, + Vector3::ZERO ) ); MeshData meshData; Material newMaterial = Material::New("effect buffer"); @@ -578,8 +592,8 @@ struct AtlasRenderer::Impl : public ConnectionTracker for ( uint32_t i = 0; i < verts.size(); ++i ) { MeshData::Vertex vertex = verts[ i ]; - vertex.x = ( ( vertex.x - tlx ) * divWidth ) - one; - vertex.y = ( ( vertex.y - tly ) * divHeight ) - one; + vertex.x = ( ( vertex.x - tlx ) * divWidth ) - ONE; + vertex.y = ( ( vertex.y - tly ) * divHeight ) - ONE; newVerts.push_back( vertex ); } @@ -676,7 +690,8 @@ RenderableActor AtlasRenderer::Render( Text::ViewInterface& view ) view.GetShadowOffset(), view.GetShadowColor(), view.IsUnderlineEnabled(), - view.GetUnderlineColor() ); + view.GetUnderlineColor(), + view.GetUnderlineHeight() ); } return mImpl->mActor; } diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 1e9ee89..705b44b 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -989,6 +989,7 @@ struct Controller::Impl mVisualModel->SetShadowOffset( Vector2::ZERO ); mVisualModel->SetShadowColor( Vector4::ZERO ); mVisualModel->SetUnderlineEnabled( false ); + mVisualModel->SetUnderlineHeight( 0.0f ); } ~Impl() @@ -1212,6 +1213,11 @@ bool Controller::IsUnderlineEnabled() const return mImpl->mVisualModel->IsUnderlineEnabled(); } +float Controller::GetUnderlineHeight() const +{ + return mImpl->mVisualModel->GetUnderlineHeight(); +} + void Controller::SetTextColor( const Vector4& textColor ) { mImpl->mVisualModel->SetTextColor( textColor ); @@ -1237,6 +1243,11 @@ void Controller::SetUnderlineEnabled( bool enabled ) mImpl->mVisualModel->SetUnderlineEnabled( enabled ); } +void Controller::SetUnderlineHeight( float height ) +{ + mImpl->mVisualModel->SetUnderlineHeight( height ); +} + void Controller::EnableTextInput( DecoratorPtr decorator ) { if( !mImpl->mTextInput ) diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 0234e7c..a5dd91b 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -243,6 +243,20 @@ public: bool IsUnderlineEnabled() const; /** + * @brief Set the override used for underline height, 0 indicates height will be supplied by font metrics + * + * @param[in] height The height in pixels of the underline + */ + void SetUnderlineHeight( float height ); + + /** + * @brief Retrieves the override height of an underline, 0 indicates height is supplied by font metrics + * + * @return The height of the underline, or 0 if height is not overrided. + */ + float GetUnderlineHeight() const; + + /** * @brief Called to enable text input. * * @note Only selectable or editable controls should calls this. diff --git a/dali-toolkit/internal/text/text-view-interface.h b/dali-toolkit/internal/text/text-view-interface.h index 116ad50..68d5e97 100644 --- a/dali-toolkit/internal/text/text-view-interface.h +++ b/dali-toolkit/internal/text/text-view-interface.h @@ -117,12 +117,19 @@ public: virtual const Vector4& GetUnderlineColor() const = 0; /** - * @brief Returns whether is underline is enabled or not. + * @brief Returns whether underline is enabled or not. * * @return The underline state. */ virtual bool IsUnderlineEnabled() const = 0; + /** + * @brief Retrieves the underline height override + * + * @return Returns the override height for an underline, 0 indicates that adaptor will determine the height + */ + virtual float GetUnderlineHeight() const = 0; + }; } // namespace Text diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp index b0825f6..61073fe 100644 --- a/dali-toolkit/internal/text/text-view.cpp +++ b/dali-toolkit/internal/text/text-view.cpp @@ -101,6 +101,16 @@ bool View::IsUnderlineEnabled() const return false; } +float View::GetUnderlineHeight() const +{ + if ( mImpl->mVisualModel ) + { + VisualModel& model = *mImpl->mVisualModel; + return model.GetUnderlineHeight(); + } + return 0.0f; +} + Length View::GetNumberOfGlyphs() const { if( mImpl->mVisualModel ) diff --git a/dali-toolkit/internal/text/text-view.h b/dali-toolkit/internal/text/text-view.h index b9bd7fc..e611c3c 100644 --- a/dali-toolkit/internal/text/text-view.h +++ b/dali-toolkit/internal/text/text-view.h @@ -101,6 +101,11 @@ public: */ virtual bool IsUnderlineEnabled() const; + /** + * @copydoc Dali::Toolkit::Text::ViewInterface::GetUnderlineHeight() + */ + virtual float GetUnderlineHeight() const; + private: // Undefined diff --git a/dali-toolkit/internal/text/visual-model-impl.cpp b/dali-toolkit/internal/text/visual-model-impl.cpp index c070179..922f309 100644 --- a/dali-toolkit/internal/text/visual-model-impl.cpp +++ b/dali-toolkit/internal/text/visual-model-impl.cpp @@ -441,6 +441,11 @@ void VisualModel::SetUnderlineEnabled( bool enabled ) mUnderlineEnabled = enabled; } +void VisualModel::SetUnderlineHeight( float height ) +{ + mUnderlineHeight = height; +} + const Vector4& VisualModel::GetTextColor() const { return mTextColor; @@ -466,6 +471,11 @@ bool VisualModel::IsUnderlineEnabled() const return mUnderlineEnabled; } +float VisualModel::GetUnderlineHeight() const +{ + return mUnderlineHeight; +} + void VisualModel::ClearCaches() { mCachedLineIndex = 0u; @@ -487,6 +497,7 @@ VisualModel::VisualModel() mShadowColor(), mUnderlineColor(), mShadowOffset(), + mUnderlineHeight( 0.0f ), mNaturalSize(), mActualSize(), mCachedLineIndex( 0u ), diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h index aa8a75f..fb9f7bc 100644 --- a/dali-toolkit/internal/text/visual-model-impl.h +++ b/dali-toolkit/internal/text/visual-model-impl.h @@ -477,6 +477,20 @@ public: */ void ClearCaches(); + /** + * @brief Set the override used for underline height, 0 indicates height will be come from font metrics + * + * @param[in] height The height in pixels of the underline + */ + void SetUnderlineHeight( float height ); + + /** + * @brief Retrieves the underline height override + * + * @return Returns the override height for an underline, 0 indicates that font metrics will determine the height + */ + float GetUnderlineHeight() const; + protected: /** @@ -511,6 +525,9 @@ public: Vector4 mShadowColor; ///< Color of drop shadow Vector4 mUnderlineColor; ///< Color of underline Vector2 mShadowOffset; ///< Offset for drop shadow, 0 indicates no shadow + float mUnderlineHeight; ///< Fixed height for underline to override font metrics. + + private: @@ -521,8 +538,10 @@ private: LineIndex mCachedLineIndex; ///< Used to increase performance in consecutive calls to GetLineOfGlyph() or GetLineOfCharacter() with consecutive glyphs or characters. public: + bool mUnderlineEnabled:1; ///< Underline enabled flag bool mUnderlineColorSet:1; ///< Has the underline color been explicitly set? + }; } // namespace Text diff --git a/dali-toolkit/public-api/controls/text-controls/text-label.h b/dali-toolkit/public-api/controls/text-controls/text-label.h index 7ecb200..b11bd13 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-label.h +++ b/dali-toolkit/public-api/controls/text-controls/text-label.h @@ -57,19 +57,20 @@ public: { enum { - RENDERING_BACKEND = PROPERTY_START_INDEX, ///< name "rendering-backend", The type or rendering e.g. bitmap-based, type INT - TEXT, ///< name "text", The text to display in UTF-8 format, type STRING - FONT_FAMILY, ///< name "font-family", The requested font family, type STRING - FONT_STYLE, ///< name "font-style", The requested font style e.g. Regular/Italic, type STRING - 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" - 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 - UNDERLINE_ENABLED, ///< name "underline-enabled", The underline enabled flag type BOOLEAN - UNDERLINE_COLOR, ///< name "underline-color", The color of the underline type VECTOR4 + RENDERING_BACKEND = PROPERTY_START_INDEX, ///< name "rendering-backend", The type or rendering e.g. bitmap-based, type INT + TEXT, ///< name "text", The text to display in UTF-8 format, type STRING + FONT_FAMILY, ///< name "font-family", The requested font family, type STRING + FONT_STYLE, ///< name "font-style", The requested font style e.g. Regular/Italic, type STRING + 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" + 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 + UNDERLINE_ENABLED, ///< name "underline-enabled", The underline enabled flag, type BOOLEAN + UNDERLINE_COLOR, ///< name "underline-color", The color of the underline, type VECTOR4 + UNDERLINE_HEIGHT ///< name "underline-height", Overrides the underline height from font metrics, type FLOAT }; };