From 53daf86a69225c2409e7912a0b4a99c7bc28c852 Mon Sep 17 00:00:00 2001 From: Victor Cebollada Date: Fri, 20 Feb 2015 08:45:23 +0000 Subject: [PATCH] TextLabel::GetHeightForWidth() implementation. Change-Id: Iaa9e3895668b0e38246c4a5c06a18086d3f2ab4d Signed-off-by: Victor Cebollada --- .../text-controls/text-label-impl.cpp | 10 + .../controls/text-controls/text-label-impl.h | 10 + .../public-api/text/layouts/layout-engine.cpp | 19 +- .../public-api/text/layouts/layout-engine.h | 1 - .../rendering/basic/text-basic-renderer.cpp | 4 +- .../public-api/text/text-controller.cpp | 217 +++++++++++++++--- .../public-api/text/text-controller.h | 46 +++- .../public-api/text/text-view-interface.h | 10 +- dali-toolkit/public-api/text/text-view.cpp | 12 +- dali-toolkit/public-api/text/text-view.h | 8 +- dali-toolkit/public-api/text/visual-model.cpp | 17 +- dali-toolkit/public-api/text/visual-model.h | 10 +- 12 files changed, 290 insertions(+), 74 deletions(-) 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 c498f0e4dd..93c550076d 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -130,6 +130,16 @@ void TextLabel::OnInitialize() mController = Text::Controller::New(); } +Vector3 TextLabel::GetNaturalSize() +{ + return mController->GetNaturalSize(); +} + +float TextLabel::GetHeightForWidth( float width ) +{ + return mController->GetHeightForWidth( width ); +} + void TextLabel::OnRelayout( const Vector2& size, ActorSizeContainer& container ) { if( mController->Relayout( size ) ) diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.h b/dali-toolkit/internal/controls/text-controls/text-label-impl.h index 3ea01f20c2..ab29fc96f1 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.h @@ -86,6 +86,16 @@ private: // From Control */ virtual void OnRelayout( const Vector2& size, ActorSizeContainer& container ); + /** + * @copydoc Control::GetNaturalSize() + */ + virtual Vector3 GetNaturalSize(); + + /** + * @copydoc Control::GetHeightForWidth() + */ + virtual float GetHeightForWidth( float width ); + private: // Implementation /** diff --git a/dali-toolkit/public-api/text/layouts/layout-engine.cpp b/dali-toolkit/public-api/text/layouts/layout-engine.cpp index 698832d92c..cfdd9d43d7 100644 --- a/dali-toolkit/public-api/text/layouts/layout-engine.cpp +++ b/dali-toolkit/public-api/text/layouts/layout-engine.cpp @@ -84,7 +84,7 @@ struct LayoutEngine::Impl // FIXME Single font assumption Text::FontMetrics fontMetrics; GlyphInfo firstGlyph; - visualModel.GetGlyphs( 0, &firstGlyph, 1 ); + visualModel.GetGlyphs( &firstGlyph, 0, 1 ); mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics ); float penX( 0 ); @@ -93,7 +93,7 @@ struct LayoutEngine::Impl for( unsigned int i=0; i 0 ) { + Size actualSize; + // FIXME Single font assumption Text::FontMetrics fontMetrics; GlyphInfo firstGlyph; - visualModel.GetGlyphs( 0, &firstGlyph, 1 ); + visualModel.GetGlyphs( &firstGlyph, 0, 1 ); mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics ); float penX( 0 ); @@ -131,7 +133,7 @@ struct LayoutEngine::Impl for( ; i 0 && glyph.height > 0 ) @@ -152,7 +154,7 @@ struct LayoutEngine::Impl for( ; j boundingBox.width ) { + actualSize.width = ( actualSize.width < endPenX - glyph.advance ) ? endPenX - glyph.advance : actualSize.width; break; } } @@ -178,7 +181,7 @@ struct LayoutEngine::Impl for( ; i glyphs; glyphs.Resize( numberOfGlyphs ); - view.GetGlyphs( 0, &glyphs[0], numberOfGlyphs ); + view.GetGlyphs( &glyphs[0], 0, numberOfGlyphs ); std::vector positions; positions.resize( numberOfGlyphs ); - view.GetGlyphPositions( 0, &positions[0], numberOfGlyphs ); + view.GetGlyphPositions( &positions[0], 0, numberOfGlyphs ); Atlas atlas = mImpl->CreateAtlas( glyphs ); diff --git a/dali-toolkit/public-api/text/text-controller.cpp b/dali-toolkit/public-api/text/text-controller.cpp index 2592653453..ceae8ca605 100644 --- a/dali-toolkit/public-api/text/text-controller.cpp +++ b/dali-toolkit/public-api/text/text-controller.cpp @@ -18,9 +18,6 @@ // CLASS HEADER #include -// EXTERNAL INCLUDES -#include - // INTERNAL INCLUDES #include #include @@ -31,6 +28,10 @@ #include #include +// EXTERNAL INCLUDES +#include +#include + namespace Dali { @@ -43,7 +44,8 @@ namespace Text struct Controller::Impl { Impl() - : mNewTextArrived( false ) + : mNewText(), + mOperations( NO_OPERATION ) { mLogicalModel = LogicalModel::New(); mVisualModel = VisualModel::New(); @@ -54,7 +56,6 @@ struct Controller::Impl } std::string mNewText; - bool mNewTextArrived; LogicalModelPtr mLogicalModel; VisualModelPtr mVisualModel; @@ -64,6 +65,8 @@ struct Controller::Impl LayoutEngine mLayoutEngine; TextAbstraction::FontClient mFontClient; + + OperationsMask mOperations; }; ControllerPtr Controller::New() @@ -75,45 +78,111 @@ void Controller::SetText( const std::string& text ) { // Keep until size negotiation mImpl->mNewText = text; - mImpl->mNewTextArrived = true; + mImpl->mOperations = ALL_OPERATIONS; } bool Controller::Relayout( const Vector2& size ) +{ + if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) ) + { + // Not worth to relayout if width or height is equal to zero. + return false; + } + + bool viewUpdated = false; + + if( size != mControlSize ) + { + viewUpdated = DoRelayout( size, mImpl->mOperations ); + + // Do not re-do any operation until something changes. + mImpl->mOperations = NO_OPERATION; + + mControlSize = size; + } + + return viewUpdated; +} + +bool Controller::DoRelayout( const Vector2& size, OperationsMask operations ) { bool viewUpdated( false ); - if( mImpl->mNewTextArrived ) + Vector utf32Characters; + Length characterCount = 0u; + if( CONVERT_TO_UTF32 & operations ) { std::string& text = mImpl->mNewText; // Convert text into UTF-32 - Vector utf32Characters; utf32Characters.Resize( text.size() ); // This is a bit horrible but std::string returns a (signed) char* const uint8_t* utf8 = reinterpret_cast( text.c_str() ); - Length characterCount = Utf8ToUtf32( utf8, text.size(), &utf32Characters[0] ); + // Transform a text array encoded in utf8 into an array encoded in utf32. + // It returns the actual number of characters. + characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() ); utf32Characters.Resize( characterCount ); - Vector scripts; + // Sets the text into the model. + mImpl->mLogicalModel->SetText( utf32Characters.Begin(), characterCount ); + + // Discard temporary text + text.clear(); + } + + const bool getScripts = GET_SCRIPTS & operations; + const bool validateFonts = VALIDATE_FONTS & operations; + + Vector scripts; + Vector fonts; + if( getScripts || validateFonts ) + { + // Validates the fonts assigned by the application or assigns default ones. + // It makes sure all the characters are going to be rendered by the correct font. MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get(); - multilanguageSupport.SetScripts( utf32Characters, - scripts ); + if( getScripts ) + { + // Retrieves the scripts used in the text. + multilanguageSupport.SetScripts( utf32Characters, + scripts ); - Vector fonts; - multilanguageSupport.ValidateFonts( utf32Characters, - scripts, - fonts ); + // Sets the scripts into the model. + mImpl->mLogicalModel->SetScripts( scripts.Begin(), scripts.Count() ); + } - Vector lineBreakInfo; - lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK ); + if( validateFonts ) + { + // Validates the fonts. If there is a character with no assigned font it sets a default one. + // After this call, fonts are validated. + multilanguageSupport.ValidateFonts( utf32Characters, + scripts, + fonts ); + + // Sets the fonts into the model. + mImpl->mLogicalModel->SetFonts( fonts.Begin(), fonts.Count() ); + } + } - Vector glyphs; - Vector characterIndices; - Vector charactersPerGlyph; + Vector lineBreakInfo; + if( GET_LINE_BREAKS & operations ) + { + // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to + // calculate the bidirectional info for each 'paragraph'. + // It's also used to layout the text (where it should be a new line) or to shape the text (text in different lines + // is not shaped together). + lineBreakInfo.Resize( characterCount, TextAbstraction::LINE_NO_BREAK ); + mImpl->mLogicalModel->SetLineBreakInfo( lineBreakInfo.Begin(), characterCount ); + } + Vector glyphs; + Vector characterIndices; + Vector charactersPerGlyph; + if( SHAPE_TEXT & operations ) + { + // Shapes the text. ShapeText( utf32Characters, lineBreakInfo, scripts, @@ -121,26 +190,42 @@ bool Controller::Relayout( const Vector2& size ) glyphs, characterIndices, charactersPerGlyph ); + } - // Manipulate the logical model - mImpl->mLogicalModel->SetText( &utf32Characters[0], characterCount ); - mImpl->mLogicalModel->SetLineBreakInfo( &lineBreakInfo[0], characterCount ); - mImpl->mLogicalModel->SetScripts( &scripts[0], scripts.Count() ); - mImpl->mLogicalModel->SetFonts( &fonts[0], fonts.Count() ); + if( GET_GLYPH_METRICS & operations ) + { + TextAbstraction::FontClient::Get().GetGlyphMetrics( glyphs.Begin(), glyphs.Count() ); + } - if( TextAbstraction::FontClient::Get().GetGlyphMetrics( &glyphs[0], glyphs.Size() ) ) + if( LAYOUT & operations ) + { + if( 0u == glyphs.Count() ) { - // Update the visual model - mImpl->mLayoutEngine.UpdateVisualModel( size, - glyphs, - characterIndices, - charactersPerGlyph, - *mImpl->mVisualModel ); + const Length numberOfGlyphs = mImpl->mVisualModel->GetNumberOfGlyphs(); + + glyphs.Resize( numberOfGlyphs ); + characterIndices.Resize( numberOfGlyphs ); + charactersPerGlyph.Resize( numberOfGlyphs ); + + mImpl->mVisualModel->GetGlyphs( glyphs.Begin(), + 0u, + numberOfGlyphs ); + + mImpl->mVisualModel->GetGlyphToCharacterMap( characterIndices.Begin(), + 0u, + numberOfGlyphs ); + + mImpl->mVisualModel->GetCharactersPerGlyphMap( charactersPerGlyph.Begin(), + 0u, + numberOfGlyphs ); } - // Discard temporary text - mImpl->mNewTextArrived = false; - text.clear(); + // Update the visual model + mImpl->mLayoutEngine.UpdateVisualModel( size, + glyphs, + characterIndices, + charactersPerGlyph, + *mImpl->mVisualModel ); viewUpdated = true; } @@ -148,6 +233,63 @@ bool Controller::Relayout( const Vector2& size ) return viewUpdated; } +Vector3 Controller::GetNaturalSize() +{ + // Operations that can be done only once until the text changes. + const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | + GET_SCRIPTS | + VALIDATE_FONTS | + GET_LINE_BREAKS | + GET_WORD_BREAKS | + SHAPE_TEXT | + GET_GLYPH_METRICS ); + + // Operations that need to be done if the size or the text changes. + const OperationsMask sizeOperations = static_cast( LAYOUT | + REORDER ); + + const float maxFloat = std::numeric_limits::max(); + DoRelayout( Vector2( maxFloat, maxFloat ), + static_cast( onlyOnceOperations | + sizeOperations ) ); + + // Do not do again the only once operations. + mImpl->mOperations = static_cast( mImpl->mOperations & ~onlyOnceOperations ); + + // Do the size related operations again. + mImpl->mOperations = static_cast( mImpl->mOperations | sizeOperations ); + + return Vector3( mImpl->mVisualModel->GetNaturalSize() ); +} + +float Controller::GetHeightForWidth( float width ) +{ + // Operations that can be done only once until the text changes. + const OperationsMask onlyOnceOperations = static_cast( CONVERT_TO_UTF32 | + GET_SCRIPTS | + VALIDATE_FONTS | + GET_LINE_BREAKS | + GET_WORD_BREAKS | + SHAPE_TEXT | + GET_GLYPH_METRICS ); + + // Operations that need to be done if the size or the text changes. + const OperationsMask sizeOperations = static_cast( LAYOUT | + REORDER ); + + DoRelayout( Size( width, 0.f ), + static_cast( onlyOnceOperations | + sizeOperations ) ); + + // Do not do again the only once operations. + mImpl->mOperations = static_cast( mImpl->mOperations & ~onlyOnceOperations ); + + // Do the size related operations again. + mImpl->mOperations = static_cast( mImpl->mOperations | sizeOperations ); + + return mImpl->mVisualModel->GetActualSize().height; +} + View& Controller::GetView() { return mImpl->mView; @@ -164,7 +306,8 @@ Controller::~Controller() } Controller::Controller() -: mImpl( NULL ) +: mImpl( NULL ), + mControlSize() { mImpl = new Controller::Impl(); } diff --git a/dali-toolkit/public-api/text/text-controller.h b/dali-toolkit/public-api/text/text-controller.h index 3155015d22..25ad189962 100644 --- a/dali-toolkit/public-api/text/text-controller.h +++ b/dali-toolkit/public-api/text/text-controller.h @@ -19,11 +19,13 @@ */ // INTERNAL INCLUDES -#include -#include #include // EXTERNAL INCLUDES +#include +#include +#include +#include #include namespace Dali @@ -48,6 +50,28 @@ typedef IntrusivePtr ControllerPtr; */ class Controller : public RefObject { +private: + + /** + * @brief Text related operations to be done in the relayout process. + */ + enum OperationsMask + { + NO_OPERATION = 0x0, + CONVERT_TO_UTF32 = 0x1, + GET_SCRIPTS = 0x2, + VALIDATE_FONTS = 0x4, + GET_LINE_BREAKS = 0x8, + GET_WORD_BREAKS = 0x10, + SHAPE_TEXT = 0x20, + GET_GLYPH_METRICS = 0x40, + LAYOUT = 0x80, + REORDER = 0x100, + ALIGNEMENT = 0x200, + RENDER = 0x400, + ALL_OPERATIONS = 0xFFF + }; + public: /** @@ -74,6 +98,21 @@ public: */ bool Relayout( const Vector2& size ); + /** + * + */ + bool DoRelayout( const Vector2& size, OperationsMask operations ); + + /** + * @copydoc Control::GetNaturalSize() + */ + Vector3 GetNaturalSize(); + + /** + * @copydoc Control::GetHeightForWidth() + */ + float GetHeightForWidth( float width ); + /** * @brief Return the layout engine. * @@ -117,7 +156,10 @@ private: struct Impl; Impl* mImpl; + + Size mControlSize; }; + } // namespace Text } // namespace Toolkit diff --git a/dali-toolkit/public-api/text/text-view-interface.h b/dali-toolkit/public-api/text/text-view-interface.h index a440209611..c15cda1054 100644 --- a/dali-toolkit/public-api/text/text-view-interface.h +++ b/dali-toolkit/public-api/text/text-view-interface.h @@ -69,20 +69,20 @@ public: * @param[in] glyphIndex Index to the first glyph. * @param[in] numberOfGlyphs Number of glyphs to be copied. */ - virtual void GetGlyphs( GlyphIndex glyphIndex, - GlyphInfo* glyphs, + virtual void GetGlyphs( GlyphInfo* glyphs, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const = 0; /** * @brief Retrieves the glyph positions. * * @pre The size of the @p positions buffer needs to be big enough to copy the @p numberOfGlyphs positions. - * @param[in] glyphIndex Index to the first glyph position. * @param[out] glyphPositions Pointer to a buffer where the glyph positions are copied. + * @param[in] glyphIndex Index to the first glyph position. * @param[in] numberOfGlyphs The number of positions to be copied. */ - virtual void GetGlyphPositions( GlyphIndex glyphIndex, - Vector2* glyphPositions, + virtual void GetGlyphPositions( Vector2* glyphPositions, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const = 0; }; diff --git a/dali-toolkit/public-api/text/text-view.cpp b/dali-toolkit/public-api/text/text-view.cpp index 37dbbbb048..01e7531d32 100644 --- a/dali-toolkit/public-api/text/text-view.cpp +++ b/dali-toolkit/public-api/text/text-view.cpp @@ -61,23 +61,23 @@ Length View::GetNumberOfGlyphs() const return 0; } -void View::GetGlyphs( GlyphIndex glyphIndex, - GlyphInfo* glyphs, +void View::GetGlyphs( GlyphInfo* glyphs, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const { if( mImpl->mVisualModel ) { - mImpl->mVisualModel->GetGlyphs( glyphIndex, glyphs, numberOfGlyphs ); + mImpl->mVisualModel->GetGlyphs( glyphs, glyphIndex, numberOfGlyphs ); } } -void View::GetGlyphPositions( GlyphIndex glyphIndex, - Vector2* glyphPositions, +void View::GetGlyphPositions( Vector2* glyphPositions, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const { if( mImpl->mVisualModel ) { - mImpl->mVisualModel->GetGlyphPositions( glyphIndex, glyphPositions, numberOfGlyphs ); + mImpl->mVisualModel->GetGlyphPositions( glyphPositions, glyphIndex, numberOfGlyphs ); } } diff --git a/dali-toolkit/public-api/text/text-view.h b/dali-toolkit/public-api/text/text-view.h index 81c63dd23a..432f5c53a9 100644 --- a/dali-toolkit/public-api/text/text-view.h +++ b/dali-toolkit/public-api/text/text-view.h @@ -65,15 +65,15 @@ public: /** * @copydoc Dali::Toolkit::Text::ViewInterface::GetGlyphs() */ - virtual void GetGlyphs( GlyphIndex glyphIndex, - GlyphInfo* glyphs, + virtual void GetGlyphs( GlyphInfo* glyphs, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const; /** * @copydoc Dali::Toolkit::Text::ViewInterface::GetGlyphPositions() */ - virtual void GetGlyphPositions( GlyphIndex glyphIndex, - Vector2* glyphPositions, + virtual void GetGlyphPositions( Vector2* glyphPositions, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const; private: diff --git a/dali-toolkit/public-api/text/visual-model.cpp b/dali-toolkit/public-api/text/visual-model.cpp index 20285a6541..b75005d723 100644 --- a/dali-toolkit/public-api/text/visual-model.cpp +++ b/dali-toolkit/public-api/text/visual-model.cpp @@ -44,6 +44,9 @@ struct VisualModel::Impl Vector mGlyphsToCharacters; Vector mCharactersPerGlyph; std::vector mGlyphPositions; + + Size mNaturalSize; + Size mActualSize; }; VisualModelPtr VisualModel::New() @@ -74,8 +77,8 @@ Length VisualModel::GetNumberOfGlyphs() const return mImpl->mGlyphs.Count(); } -void VisualModel::GetGlyphs( GlyphIndex glyphIndex, - GlyphInfo* glyphs, +void VisualModel::GetGlyphs( GlyphInfo* glyphs, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const { Vector& modelGlyphs = mImpl->mGlyphs; @@ -139,8 +142,8 @@ void VisualModel::SetGlyphPositions( const Vector2* glyphPositions, memcpy( &modelPositions[0], glyphPositions, numberOfGlyphs*sizeof(Vector2) ); } -void VisualModel::GetGlyphPositions( GlyphIndex glyphIndex, - Vector2* glyphPositions, +void VisualModel::GetGlyphPositions( Vector2* glyphPositions, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const { std::vector& modelPositions = mImpl->mGlyphPositions; @@ -182,20 +185,22 @@ void VisualModel::GetLinesOfGlyphRange( LineRun* lines, void VisualModel::SetNaturalSize( const Vector2& size ) { + mImpl->mNaturalSize = size; } const Vector2& VisualModel::GetNaturalSize() const { - return Vector2::ZERO; + return mImpl->mNaturalSize; } void VisualModel::SetActualSize( const Vector2& size ) { + mImpl->mActualSize = size; } const Vector2& VisualModel::GetActualSize() const { - return Vector2::ZERO; + return mImpl->mActualSize; } VisualModel::~VisualModel() diff --git a/dali-toolkit/public-api/text/visual-model.h b/dali-toolkit/public-api/text/visual-model.h index 71b0514a53..0cfa4b52df 100644 --- a/dali-toolkit/public-api/text/visual-model.h +++ b/dali-toolkit/public-api/text/visual-model.h @@ -86,8 +86,8 @@ public: * @param[in] glyphIndex Index to the first glyph. * @param[in] numberOfGlyphs Number of glyphs to be copied. */ - void GetGlyphs( GlyphIndex glyphIndex, - GlyphInfo* glyphs, + void GetGlyphs( GlyphInfo* glyphs, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const; /** @@ -181,12 +181,12 @@ public: * @brief Retrieves the glyph positions. * * @pre The size of the @p positions buffer needs to be big enough to copy the @p numberOfGlyphs positions. - * @param[in] glyphIndex Index to the first glyph position. * @param[out] glyphPositions Pointer to a buffer where the glyph positions are copied. + * @param[in] glyphIndex Index to the first glyph position. * @param[in] numberOfGlyphs The number of positions to be copied. */ - void GetGlyphPositions( GlyphIndex glyphIndex, - Vector2* glyphPositions, + void GetGlyphPositions( Vector2* glyphPositions, + GlyphIndex glyphIndex, Length numberOfGlyphs ) const; /** -- 2.34.1