From: Paul Wisbey Date: Thu, 12 Feb 2015 11:35:25 +0000 (+0000) Subject: Added some LayoutEngine skeleton code X-Git-Tag: new_text_0.1~50 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=20d79594120aa5db8769cff09a021e9641655bec Added some LayoutEngine skeleton code Change-Id: Ib3b99cd62311b937b2bab8bdc14133daf618bcc0 --- diff --git a/base/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/base/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 38335ee..c498f0e 100644 --- a/base/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/base/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -22,6 +22,12 @@ #include #include +// INTERNAL INCLUDES +#include +#include // TODO - Get from RendererFactory + +using Dali::Toolkit::Text::LayoutEngine; + namespace { @@ -33,7 +39,8 @@ namespace Dali namespace Toolkit { -const Property::Index TextLabel::PROPERTY_TEXT( Internal::TextLabel::TEXTLABEL_PROPERTY_START_INDEX ); +const Property::Index TextLabel::PROPERTY_TEXT( Internal::TextLabel::TEXTLABEL_PROPERTY_START_INDEX ); +const Property::Index TextLabel::PROPERTY_MULTI_LINE( Internal::TextLabel::TEXTLABEL_PROPERTY_START_INDEX + 1 ); namespace Internal { @@ -49,7 +56,8 @@ BaseHandle Create() TypeRegistration mType( typeid(Toolkit::TextLabel), typeid(Toolkit::Control), Create ); -PropertyRegistration property1( mType, "text", Toolkit::TextLabel::PROPERTY_TEXT, Property::STRING, &TextLabel::SetProperty, &TextLabel::GetProperty ); +PropertyRegistration property1( mType, "text", Toolkit::TextLabel::PROPERTY_TEXT, Property::STRING, &TextLabel::SetProperty, &TextLabel::GetProperty ); +PropertyRegistration property2( mType, "multi-line", Toolkit::TextLabel::PROPERTY_MULTI_LINE, Property::STRING, &TextLabel::SetProperty, &TextLabel::GetProperty ); } // namespace @@ -87,6 +95,11 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr labelImpl.SetText( value.Get< std::string >() ); break; } + case Toolkit::TextLabel::PROPERTY_MULTI_LINE: + { + labelImpl.SetMultiLine( value.Get< bool >() ); + break; + } } } } @@ -117,12 +130,15 @@ void TextLabel::OnInitialize() mController = Text::Controller::New(); } -void TextLabel::SetText( const std::string& text ) +void TextLabel::OnRelayout( const Vector2& size, ActorSizeContainer& container ) { - if( mController ) + if( mController->Relayout( size ) ) { - // The Controller updates the View for the renderer - mController->SetText( text ); + if( !mRenderer ) + { + // TODO - Get from RendererFactory + mRenderer = Dali::Toolkit::Text::BasicRenderer::New(); + } if( mRenderer ) { @@ -136,6 +152,30 @@ void TextLabel::SetText( const std::string& text ) } } +void TextLabel::SetText( const std::string& text ) +{ + if( mController ) + { + // The Controller updates the View for the renderer + mController->SetText( text ); + } +} + +void TextLabel::SetMultiLine( bool multiLine ) +{ + if( mController ) + { + if( multiLine ) + { + mController->GetLayoutEngine().SetLayout( LayoutEngine::MULTI_LINE_BOX ); + } + else + { + mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX ); + } + } +} + TextLabel::TextLabel() : Control( ControlBehaviour( CONTROL_BEHAVIOUR_NONE ) ) { diff --git a/base/dali-toolkit/internal/controls/text-controls/text-label-impl.h b/base/dali-toolkit/internal/controls/text-controls/text-label-impl.h index b3ecd0e..3ea01f2 100644 --- a/base/dali-toolkit/internal/controls/text-controls/text-label-impl.h +++ b/base/dali-toolkit/internal/controls/text-controls/text-label-impl.h @@ -81,6 +81,11 @@ private: // From Control */ virtual void OnInitialize(); + /** + * @copydoc Control::OnInitialize() + */ + virtual void OnRelayout( const Vector2& size, ActorSizeContainer& container ); + private: // Implementation /** @@ -90,6 +95,12 @@ private: // Implementation void SetText( const std::string& text ); /** + * Helper for SetProperty. + * @param[in] multiLine The new "multi-line" property value. + */ + void SetMultiLine( bool multiLine ); + + /** * Construct a new TextLabel. */ TextLabel(); diff --git a/base/dali-toolkit/public-api/controls/text-controls/text-label.cpp b/base/dali-toolkit/public-api/controls/text-controls/text-label.cpp index 946de46..15bb52c 100644 --- a/base/dali-toolkit/public-api/controls/text-controls/text-label.cpp +++ b/base/dali-toolkit/public-api/controls/text-controls/text-label.cpp @@ -27,6 +27,9 @@ namespace Dali namespace Toolkit { +const std::string TextLabel::TEXT_PROPERTY_NAME("text"); +const std::string TextLabel::MULTI_LINE_PROPERTY_NAME("multi-line"); + TextLabel TextLabel::New() { return Internal::TextLabel::New(); diff --git a/base/dali-toolkit/public-api/controls/text-controls/text-label.h b/base/dali-toolkit/public-api/controls/text-controls/text-label.h index 04ec993..449d23b 100644 --- a/base/dali-toolkit/public-api/controls/text-controls/text-label.h +++ b/base/dali-toolkit/public-api/controls/text-controls/text-label.h @@ -41,10 +41,12 @@ class DALI_IMPORT_API TextLabel : public Control public: // Property indices - static const Property::Index PROPERTY_TEXT; ///< name "text", type STRING + static const Property::Index PROPERTY_TEXT; ///< name "text", type STRING + static const Property::Index PROPERTY_MULTI_LINE; ///< name "multi-line", type BOOLEAN // Property names - static const std::string TEXT_PROPERTY_NAME; ///< Property, name "text", type STRING + static const std::string TEXT_PROPERTY_NAME; ///< Property, name "text", type STRING + static const std::string MULTI_LINE_PROPERTY_NAME; ///< Property, name "multi-line", type BOOLEAN /** * Create the TextLabel control. diff --git a/base/dali-toolkit/public-api/file.list b/base/dali-toolkit/public-api/file.list index 0c43428..5755eba 100755 --- a/base/dali-toolkit/public-api/file.list +++ b/base/dali-toolkit/public-api/file.list @@ -46,6 +46,7 @@ public_api_base_src_files = \ $(public_api_base_src_dir)/text/text-view.cpp \ $(public_api_base_src_dir)/text/text-view-interface.cpp \ $(public_api_base_src_dir)/text/visual-model.cpp \ + $(public_api_base_src_dir)/text/layouts/layout-engine.cpp \ $(public_api_base_src_dir)/text/rendering/text-renderer.cpp \ $(public_api_base_src_dir)/text/rendering/basic/text-basic-renderer.cpp \ $(public_api_base_src_dir)/text/rendering/shaders/text-basic-shader.cpp \ @@ -137,6 +138,9 @@ public_api_base_text_header_files = \ $(public_api_base_src_dir)/text/text-view-interface.h \ $(public_api_base_src_dir)/text/visual-model.h +public_api_base_text_layouts_header_files = \ + $(public_api_base_src_dir)/text/layouts/layout-engine.h + public_api_base_text_rendering_header_files = \ $(public_api_base_src_dir)/text/rendering/text-renderer.h diff --git a/base/dali-toolkit/public-api/text/layouts/layout-engine.cpp b/base/dali-toolkit/public-api/text/layouts/layout-engine.cpp new file mode 100644 index 0000000..65cfc61 --- /dev/null +++ b/base/dali-toolkit/public-api/text/layouts/layout-engine.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct LayoutEngine::Impl +{ + Impl() + : mLayout( LayoutEngine::SINGLE_LINE_BOX ) + { + mFontClient = TextAbstraction::FontClient::Get(); + } + + void UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel ) + { + // TODO Switch between different layouts + + TextAbstraction::FontId fontId = mFontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 13*64 ); + + const Length characterCount = logicalModel.GetNumberOfCharacters(); + + Vector glyphs; + glyphs.Reserve( characterCount ); + + Vector characterIndices; + characterIndices.Reserve( characterCount ); + + std::vector charactersPerGlyph; + charactersPerGlyph.assign( characterCount, 1 ); + + for( unsigned int i=0; i glyphPositions; + glyphPositions.reserve( glyphCount ); + + if( glyphCount > 0 ) + { + // FIXME Single font assumption + Text::FontMetrics fontMetrics; + GlyphInfo firstGlyph; + visualModel.GetGlyphs( 0, &firstGlyph, 1 ); + mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics ); + + float penX( 0 ); + float penY( fontMetrics.ascender ); // Move to baseline + + for( unsigned int i=0; i glyphPositions; + glyphPositions.reserve( glyphCount ); + + if( glyphCount > 0 ) + { + // FIXME Single font assumption + Text::FontMetrics fontMetrics; + GlyphInfo firstGlyph; + visualModel.GetGlyphs( 0, &firstGlyph, 1 ); + mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics ); + + float penX( 0 ); + float penY( fontMetrics.ascender ); // Move to baseline + + unsigned int i=0; + while( i < glyphCount ) + { + // Skip initial whitespace + for( ; i 0 && + glyph.height > 0 ) + { + break; + } + else + { + glyphPositions.push_back( Vector2( penX + glyph.xBearing, + penY - glyph.yBearing ) ); + } + } + + // Find last glyph for the next line + unsigned int endIndex = i; + float endPenX = penX; + unsigned int j=i; + for( ; j boundingBox.width ) + { + break; + } + } + + // If end of text or no whitespace found + if( glyphCount == j || + endIndex == i ) + { + endIndex = j; + } + + for( ; imLayout = layout; +} + +void LayoutEngine::UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel ) +{ + mImpl->UpdateVisualModel( boundingBox, logicalModel, visualModel ); +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/base/dali-toolkit/public-api/text/layouts/layout-engine.h b/base/dali-toolkit/public-api/text/layouts/layout-engine.h new file mode 100644 index 0000000..55483de --- /dev/null +++ b/base/dali-toolkit/public-api/text/layouts/layout-engine.h @@ -0,0 +1,93 @@ +#ifndef __DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H__ +#define __DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H__ + +/* + * Copyright (c) 2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Dali +{ + +struct Vector2; + +namespace Toolkit +{ + +namespace Text +{ + +class LogicalModel; +class VisualModel; + +/** + * @brief LayoutEngine is responsible for calculating the visual position of glyphs in layout. + */ +class LayoutEngine +{ +public: + + enum Layout + { + SINGLE_LINE_BOX, + MULTI_LINE_BOX + }; + + /** + * @brief Create a new instance of a LayoutEngine. + */ + LayoutEngine(); + + /** + * @brief Virtual destructor. + */ + ~LayoutEngine(); + + /** + * @brief Choose the required layout. + * + * @param[in] layout The required layout. + */ + void SetLayout( Layout layout ); + + /** + * @brief Store the visual position of glyphs in the VisualModel. + * + * @param[in] boundingBox The size of the box containing the text. + * @param[in] logicalModel The logical model. + * @param[in] visualModel The visual model to update. + */ + void UpdateVisualModel( const Vector2& boundingBox, const LogicalModel& logicalModel, VisualModel& visualModel ); + +private: + + // Undefined + LayoutEngine( const LayoutEngine& handle ); + + // Undefined + LayoutEngine& operator=( const LayoutEngine& handle ); + +private: + + struct Impl; + Impl* mImpl; +}; +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_LAYOUT_ENGINE_H__ diff --git a/base/dali-toolkit/public-api/text/text-controller.cpp b/base/dali-toolkit/public-api/text/text-controller.cpp index 441ac62..a5763d5 100644 --- a/base/dali-toolkit/public-api/text/text-controller.cpp +++ b/base/dali-toolkit/public-api/text/text-controller.cpp @@ -18,8 +18,12 @@ // CLASS HEADER #include +// EXTERNAL INCLUDES +#include + // INTERNAL INCLUDES #include +#include #include #include #include @@ -36,6 +40,7 @@ namespace Text struct Controller::Impl { Impl() + : mNewTextArrived( false ) { mLogicalModel = LogicalModel::New(); mVisualModel = VisualModel::New(); @@ -45,11 +50,16 @@ struct Controller::Impl mFontClient = TextAbstraction::FontClient::Get(); } + std::string mNewText; + bool mNewTextArrived; + LogicalModelPtr mLogicalModel; VisualModelPtr mVisualModel; View mView; + LayoutEngine mLayoutEngine; + TextAbstraction::FontClient mFontClient; }; @@ -60,19 +70,42 @@ ControllerPtr Controller::New() void Controller::SetText( const std::string& text ) { - // Convert text into UTF-32 - Vector utf32Characters; - utf32Characters.Resize( text.size() ); + // Keep until size negotiation + mImpl->mNewText = text; + mImpl->mNewTextArrived = true; +} + +bool Controller::Relayout( const Vector2& size ) +{ + bool viewUpdated( false ); + + if( mImpl->mNewTextArrived ) + { + 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] ); - // This is a bit horrible but std::string returns a (signed) char* - const uint8_t* utf8 = reinterpret_cast( text.c_str() ); + // Manipulate the logical model + mImpl->mLogicalModel->SetText( &utf32Characters[0], characterCount ); - Length characterCount = Utf8ToUtf32( utf8, text.size(), &utf32Characters[0] ); + // Update the visual model + mImpl->mLayoutEngine.UpdateVisualModel( size, *mImpl->mLogicalModel, *mImpl->mVisualModel ); - // Manipulate the logical model - mImpl->mLogicalModel->SetText( &utf32Characters[0], characterCount ); + // Discard temporary text + mImpl->mNewTextArrived = false; + text.clear(); - UpdateVisualModel(); + viewUpdated = true; + } + + return viewUpdated; } View& Controller::GetView() @@ -80,6 +113,11 @@ View& Controller::GetView() return mImpl->mView; } +LayoutEngine& Controller::GetLayoutEngine() +{ + return mImpl->mLayoutEngine; +} + Controller::~Controller() { delete mImpl; @@ -91,91 +129,6 @@ Controller::Controller() mImpl = new Controller::Impl(); } -// TODO - Move this with LayoutEngine -void Controller::UpdateVisualModel() -{ - if( mImpl->mLogicalModel && - mImpl->mVisualModel ) - { - const LogicalModel& logicalModel = *(mImpl->mLogicalModel); - VisualModel& visualModel = *(mImpl->mVisualModel); - - TextAbstraction::FontId fontId = mImpl->mFontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 13*64 ); - - const Length characterCount = logicalModel.GetNumberOfCharacters(); - - Vector glyphs; - glyphs.Reserve( characterCount ); - - Vector characterIndices; - characterIndices.Reserve( characterCount ); - - std::vector charactersPerGlyph; - charactersPerGlyph.assign( characterCount, 1 ); - - for( unsigned int i=0; imFontClient.GetGlyphIndex( fontId, charcode ); - - glyphs.PushBack( GlyphInfo(fontId, glyphIndex) ); - characterIndices.PushBack( 1 ); - } - - if( mImpl->mFontClient.GetGlyphMetrics( &glyphs[0], glyphs.Size() ) ) - { - visualModel.SetGlyphs( &glyphs[0], - &characterIndices[0], - &charactersPerGlyph[0], - characterCount ); - - UpdateVisualPositions(); - } - } -} - -// TODO - Move this with LayoutEngine -void Controller::UpdateVisualPositions() -{ - if( mImpl->mVisualModel ) - { - VisualModel& visualModel = *(mImpl->mVisualModel); - - Length glyphCount = visualModel.GetNumberOfGlyphs(); - - std::vector glyphPositions; - glyphPositions.reserve( glyphCount ); - - if( glyphCount > 0 ) - { - // FIXME Single font assumption - Text::FontMetrics fontMetrics; - GlyphInfo firstGlyph; - visualModel.GetGlyphs( 0, &firstGlyph, 1 ); - mImpl->mFontClient.GetFontMetrics( firstGlyph.fontId, fontMetrics ); - - float penX( 0 ); - float penY( fontMetrics.ascender ); // Move to baseline - - for( unsigned int i=0; i ControllerPtr; /** @@ -54,8 +56,6 @@ public: */ static ControllerPtr New(); - // TODO - Layouting options e.g. single vs multi-line - /** * @brief Replaces any text previously set. * @@ -65,9 +65,25 @@ public: void SetText( const std::string& text ); /** + * @brief Triggers a relayout which updates View (if necessary). + * + * @note UI Controls are expected to minimize calls to this method e.g. call once after size negotiation. + * @param[in] size A the size of a bounding box to layout text within. + * @return True if the View was updated. + */ + bool Relayout( const Vector2& size ); + + /** + * @brief Return the layout engine. + * + * @return A reference to the layout engine. + */ + LayoutEngine& GetLayoutEngine(); + + /** * @brief Return a view of the text. * - * @return An interface to the view. + * @return A reference to the view. */ View& GetView(); @@ -86,10 +102,9 @@ private: Controller(); /** - * TODO - Move these with LayoutEngine + * @brief Populates the visual model. */ void UpdateVisualModel(); - void UpdateVisualPositions(); // Undefined Controller( const Controller& handle ); diff --git a/build/tizen/dali-toolkit/Makefile.am b/build/tizen/dali-toolkit/Makefile.am index 94deea2..3be1007 100644 --- a/build/tizen/dali-toolkit/Makefile.am +++ b/build/tizen/dali-toolkit/Makefile.am @@ -116,6 +116,7 @@ publicapibasescrollviewdir = $(publicapibasedir)/controls/scrollable/scroll-view publicapibasetableviewdir = $(publicapibasedir)/controls/table-view publicapibasetextcontrolsdir = $(publicapibasedir)/controls/text-controls publicapibasetextdir = $(publicapibasedir)/text +publicapibasetextlayoutsdir = $(publicapibasedir)/text/layouts publicapibasetextrenderingdir = $(publicapibasedir)/text/rendering publicapibasetextrenderingbasicdir = $(publicapibasedir)/text/rendering/basic publicapibasetextrenderingshadersdir = $(publicapibasedir)/text/rendering/shaders @@ -140,6 +141,7 @@ publicapibasescrollview_HEADERS = $(public_api_base_scroll_view_header_files) publicapibasetableview_HEADERS = $(public_api_base_table_view_header_files) publicapibasetextcontrols_HEADERS = $(public_api_base_text_controls_header_files) publicapibasetext_HEADERS = $(public_api_base_text_header_files) +publicapibasetextlayouts_HEADERS = $(public_api_base_text_layouts_header_files) publicapibasetextrendering_HEADERS = $(public_api_base_text_rendering_header_files) publicapibasetextrenderingbasic_HEADERS = $(public_api_base_text_rendering_basic_header_files) publicapibasetextrenderingshaders_HEADERS = $(public_api_base_text_rendering_shaders_header_files) diff --git a/optional/dali-toolkit/dali-toolkit.h b/optional/dali-toolkit/dali-toolkit.h index 09a9421..772bb85 100644 --- a/optional/dali-toolkit/dali-toolkit.h +++ b/optional/dali-toolkit/dali-toolkit.h @@ -62,14 +62,15 @@ #include #include #include +#include #include #include -#include #include #include #include #include #include +#include #include #include #include