+ // Do the size related operations again.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
+
+ // Stores the natural size to avoid recalculate it again
+ // unless the text/style changes.
+ mImpl->mVisualModel->SetNaturalSize( naturalSize.GetVectorXY() );
+
+ mImpl->mRecalculateNaturalSize = false;
+ }
+ else
+ {
+ naturalSize = mImpl->mVisualModel->GetNaturalSize();
+ }
+
+ return naturalSize;
+}
+
+float Controller::GetHeightForWidth( float width )
+{
+ // Make sure the model is up-to-date before layouting
+ ProcessModifyEvents();
+
+ Size layoutSize;
+ if( width != mImpl->mControlSize.width )
+ {
+ // Operations that can be done only once until the text changes.
+ const OperationsMask onlyOnceOperations = static_cast<OperationsMask>( CONVERT_TO_UTF32 |
+ GET_SCRIPTS |
+ VALIDATE_FONTS |
+ GET_LINE_BREAKS |
+ GET_WORD_BREAKS |
+ BIDI_INFO |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS );
+ // Make sure the model is up-to-date before layouting
+ UpdateModel( onlyOnceOperations );
+
+ // Operations that need to be done if the size changes.
+ const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
+ ALIGN |
+ REORDER );
+
+ DoRelayout( Size( width, MAX_FLOAT ),
+ static_cast<OperationsMask>( onlyOnceOperations |
+ sizeOperations ),
+ layoutSize );
+
+ // Do not do again the only once operations.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
+
+ // Do the size related operations again.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
+ }
+ else
+ {
+ layoutSize = mImpl->mVisualModel->GetActualSize();
+ }
+
+ return layoutSize.height;
+}
+
+bool Controller::Relayout( const Size& size )
+{
+ if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
+ {
+ bool glyphsRemoved( false );
+ if( 0u != mImpl->mVisualModel->GetNumberOfGlyphPositions() )
+ {
+ mImpl->mVisualModel->SetGlyphPositions( NULL, 0u );
+ glyphsRemoved = true;
+ }
+
+ // Not worth to relayout if width or height is equal to zero.
+ return glyphsRemoved;
+ }
+
+ if( size != mImpl->mControlSize )
+ {
+ // Operations that need to be done if the size changes.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ LAYOUT |
+ ALIGN |
+ UPDATE_ACTUAL_SIZE |
+ REORDER );
+
+ mImpl->mControlSize = size;
+ }
+
+ // Make sure the model is up-to-date before layouting
+ ProcessModifyEvents();
+ UpdateModel( mImpl->mOperationsPending );
+
+ Size layoutSize;
+ bool updated = DoRelayout( mImpl->mControlSize,
+ mImpl->mOperationsPending,
+ layoutSize );
+
+ // Do not re-do any operation until something changes.
+ mImpl->mOperationsPending = NO_OPERATION;
+
+ // After doing the text layout, the alignment offset to place the actor in the desired position can be calculated.
+ CalculateTextAlignment( size );
+
+ if( mImpl->mTextInput )
+ {
+ // Move the cursor, grab handle etc.
+ updated = mImpl->mTextInput->ProcessInputEvents( mImpl->mControlSize, mImpl->mAlignmentOffset ) || updated;
+ }
+
+ return updated;
+}
+
+void Controller::ProcessModifyEvents()
+{
+ std::vector<ModifyEvent>& events = mImpl->mModifyEvents;
+
+ for( unsigned int i=0; i<events.size(); ++i )
+ {
+ if( REPLACE_TEXT == events[0].type )
+ {
+ // A (single) replace event should come first, otherwise we wasted time processing NOOP events
+ DALI_ASSERT_DEBUG( 0 == i && "Unexpected REPLACE event" );
+
+ ReplaceTextEvent( events[0].text );
+ }
+ else if( INSERT_TEXT == events[0].type )
+ {
+ InsertTextEvent( events[0].text );
+ }
+ else if( DELETE_TEXT == events[0].type )
+ {
+ DeleteTextEvent();
+ }
+ }
+
+ // Discard temporary text
+ events.clear();
+}
+
+void Controller::ReplaceTextEvent( const std::string& text )
+{
+ // Reset buffers.
+ mImpl->mLogicalModel->mText.Clear();
+ mImpl->mLogicalModel->mScriptRuns.Clear();
+ mImpl->mLogicalModel->mFontRuns.Clear();
+ mImpl->mLogicalModel->mLineBreakInfo.Clear();
+ mImpl->mLogicalModel->mWordBreakInfo.Clear();
+ mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+ mImpl->mLogicalModel->mCharacterDirections.Clear();
+ mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
+ mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
+ mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
+ mImpl->mVisualModel->mGlyphs.Clear();
+ mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+ mImpl->mVisualModel->mCharactersToGlyph.Clear();
+ mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+ mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+ mImpl->mVisualModel->mGlyphPositions.Clear();
+ mImpl->mVisualModel->mLines.Clear();
+
+ // Convert text into UTF-32
+ Vector<Character>& utf32Characters = mImpl->mLogicalModel->mText;
+ utf32Characters.Resize( text.size() );
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
+
+ // Transform a text array encoded in utf8 into an array encoded in utf32.
+ // It returns the actual number of characters.
+ Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
+ utf32Characters.Resize( characterCount );
+
+ // Reset the cursor position
+ if( mImpl->mTextInput )
+ {
+ mImpl->mTextInput->mPrimaryCursorPosition = characterCount;
+ // TODO - handle secondary cursor
+ }
+
+ // The natural size needs to be re-calculated.
+ mImpl->mRecalculateNaturalSize = true;
+
+ // Apply modifications to the model
+ mImpl->mOperationsPending = ALL_OPERATIONS;
+ UpdateModel( ALL_OPERATIONS );
+ mImpl->mOperationsPending = static_cast<OperationsMask>( LAYOUT |
+ ALIGN |
+ UPDATE_ACTUAL_SIZE |
+ REORDER );
+}
+
+void Controller::InsertTextEvent( const std::string& text )
+{
+ DALI_ASSERT_DEBUG( NULL != mImpl->mTextInput && "Unexpected InsertTextEvent" );
+
+ // TODO - Optimize this
+ mImpl->mLogicalModel->mScriptRuns.Clear();
+ mImpl->mLogicalModel->mFontRuns.Clear();
+ mImpl->mLogicalModel->mLineBreakInfo.Clear();
+ mImpl->mLogicalModel->mWordBreakInfo.Clear();
+ mImpl->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+ mImpl->mLogicalModel->mCharacterDirections.Clear();
+ mImpl->mLogicalModel->mBidirectionalLineInfo.Clear();
+ mImpl->mLogicalModel->mLogicalToVisualMap.Clear();
+ mImpl->mLogicalModel->mVisualToLogicalMap.Clear();
+ mImpl->mVisualModel->mGlyphs.Clear();
+ mImpl->mVisualModel->mGlyphsToCharacters.Clear();
+ mImpl->mVisualModel->mCharactersToGlyph.Clear();
+ mImpl->mVisualModel->mCharactersPerGlyph.Clear();
+ mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
+ mImpl->mVisualModel->mGlyphPositions.Clear();
+ mImpl->mVisualModel->mLines.Clear();
+
+ // Convert text into UTF-32