+ return EMPTY_STRING;
+}
+
+void Controller::SetUnderlineColor( const Vector4& color )
+{
+ mImpl->mVisualModel->SetUnderlineColor( color );
+
+ mImpl->RequestRelayout();
+}
+
+const Vector4& Controller::GetUnderlineColor() const
+{
+ return mImpl->mVisualModel->GetUnderlineColor();
+}
+
+void Controller::SetUnderlineEnabled( bool enabled )
+{
+ mImpl->mVisualModel->SetUnderlineEnabled( enabled );
+
+ mImpl->RequestRelayout();
+}
+
+bool Controller::IsUnderlineEnabled() const
+{
+ return mImpl->mVisualModel->IsUnderlineEnabled();
+}
+
+void Controller::SetUnderlineHeight( float height )
+{
+ mImpl->mVisualModel->SetUnderlineHeight( height );
+
+ mImpl->RequestRelayout();
+}
+
+float Controller::GetUnderlineHeight() const
+{
+ return mImpl->mVisualModel->GetUnderlineHeight();
+}
+
+void Controller::SetDefaultUnderlineProperties( const std::string& underlineProperties )
+{
+ if( NULL == mImpl->mUnderlineDefaults )
+ {
+ mImpl->mUnderlineDefaults = new UnderlineDefaults();
+ }
+
+ mImpl->mUnderlineDefaults->properties = underlineProperties;
+}
+
+const std::string& Controller::GetDefaultUnderlineProperties() const
+{
+ if( NULL != mImpl->mUnderlineDefaults )
+ {
+ return mImpl->mUnderlineDefaults->properties;
+ }
+
+ return EMPTY_STRING;
+}
+
+void Controller::SetDefaultEmbossProperties( const std::string& embossProperties )
+{
+ if( NULL == mImpl->mEmbossDefaults )
+ {
+ mImpl->mEmbossDefaults = new EmbossDefaults();
+ }
+
+ mImpl->mEmbossDefaults->properties = embossProperties;
+}
+
+const std::string& Controller::GetDefaultEmbossProperties() const
+{
+ if( NULL != mImpl->mEmbossDefaults )
+ {
+ return mImpl->mEmbossDefaults->properties;
+ }
+
+ return EMPTY_STRING;
+}
+
+void Controller::SetDefaultOutlineProperties( const std::string& outlineProperties )
+{
+ if( NULL == mImpl->mOutlineDefaults )
+ {
+ mImpl->mOutlineDefaults = new OutlineDefaults();
+ }
+
+ mImpl->mOutlineDefaults->properties = outlineProperties;
+}
+
+const std::string& Controller::GetDefaultOutlineProperties() const
+{
+ if( NULL != mImpl->mOutlineDefaults )
+ {
+ return mImpl->mOutlineDefaults->properties;
+ }
+
+ return EMPTY_STRING;
+}
+
+void Controller::SetDefaultLineSpacing( float lineSpacing )
+{
+ //TODO finish implementation
+ mImpl->mLayoutEngine.SetDefaultLineSpacing( lineSpacing );
+}
+
+float Controller::GetDefaultLineSpacing() const
+{
+ return mImpl->mLayoutEngine.GetDefaultLineSpacing();
+}
+
+void Controller::SetInputColor( const Vector4& color )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.textColor = color;
+ mImpl->mEventData->mInputStyle.isDefaultColor = false;
+
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
+
+ // Get start and end position of selection
+ const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
+ const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
+
+ // Add the color run.
+ const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
+ mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
+
+ ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
+ colorRun.color = color;
+ colorRun.characterRun.characterIndex = startOfSelectedText;
+ colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
+
+ // Request to relayout.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
+ mImpl->RequestRelayout();
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+ }
+ }
+}
+
+const Vector4& Controller::GetInputColor() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.textColor;
+ }
+
+ // Return the default text's color if there is no EventData.
+ return mImpl->mTextColor;
+
+}
+
+void Controller::SetInputFontFamily( const std::string& fontFamily )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.familyName = fontFamily;
+ mImpl->mEventData->mInputStyle.isFamilyDefined = true;
+
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.familyLength = fontFamily.size();
+ fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
+ memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength );
+ fontDescriptionRun.familyDefined = true;
+
+ // The memory allocated for the font family name is freed when the font description is removed from the logical model.
+
+ // Request to relayout.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN );
+ mImpl->mRecalculateNaturalSize = true;
+ mImpl->RequestRelayout();
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
+ // As the font changes, recalculate the handle positions is needed.
+ mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
+ mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+const std::string& Controller::GetInputFontFamily() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.familyName;
+ }
+
+ // Return the default font's family if there is no EventData.
+ return GetDefaultFontFamily();
+}
+
+void Controller::SetInputFontWeight( FontWeight weight )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.weight = weight;
+ mImpl->mEventData->mInputStyle.isWeightDefined = true;
+
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.weight = weight;
+ fontDescriptionRun.weightDefined = true;
+
+ // Request to relayout.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN );
+ mImpl->mRecalculateNaturalSize = true;
+ mImpl->RequestRelayout();
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
+ // As the font might change, recalculate the handle positions is needed.
+ mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
+ mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+bool Controller::IsInputFontWeightDefined() const
+{
+ bool defined = false;
+
+ if( NULL != mImpl->mEventData )
+ {
+ defined = mImpl->mEventData->mInputStyle.isWeightDefined;
+ }
+
+ return defined;
+}
+
+FontWeight Controller::GetInputFontWeight() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.weight;
+ }
+
+ return GetDefaultFontWeight();
+}
+
+void Controller::SetInputFontWidth( FontWidth width )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.width = width;
+ mImpl->mEventData->mInputStyle.isWidthDefined = true;
+
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.width = width;
+ fontDescriptionRun.widthDefined = true;
+
+ // Request to relayout.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN );
+ mImpl->mRecalculateNaturalSize = true;
+ mImpl->RequestRelayout();
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
+ // As the font might change, recalculate the handle positions is needed.
+ mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
+ mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+bool Controller::IsInputFontWidthDefined() const
+{
+ bool defined = false;
+
+ if( NULL != mImpl->mEventData )
+ {
+ defined = mImpl->mEventData->mInputStyle.isWidthDefined;
+ }
+
+ return defined;
+}
+
+FontWidth Controller::GetInputFontWidth() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.width;
+ }
+
+ return GetDefaultFontWidth();
+}
+
+void Controller::SetInputFontSlant( FontSlant slant )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.slant = slant;
+ mImpl->mEventData->mInputStyle.isSlantDefined = true;
+
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.slant = slant;
+ fontDescriptionRun.slantDefined = true;
+
+ // Request to relayout.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN );
+ mImpl->mRecalculateNaturalSize = true;
+ mImpl->RequestRelayout();
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
+ // As the font might change, recalculate the handle positions is needed.
+ mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
+ mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+bool Controller::IsInputFontSlantDefined() const
+{
+ bool defined = false;
+
+ if( NULL != mImpl->mEventData )
+ {
+ defined = mImpl->mEventData->mInputStyle.isSlantDefined;
+ }
+
+ return defined;
+}
+
+FontSlant Controller::GetInputFontSlant() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.slant;
+ }
+
+ return GetDefaultFontSlant();
+}
+
+void Controller::SetInputFontPointSize( float size )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.size = size;
+ mImpl->mEventData->mInputStyle.isSizeDefined = true;
+
+ if( EventData::SELECTING == mImpl->mEventData->mState )
+ {
+ CharacterIndex startOfSelectedText = 0u;
+ Length lengthOfSelectedText = 0u;
+ FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
+ mImpl->mLogicalModel,
+ startOfSelectedText,
+ lengthOfSelectedText );
+
+ fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
+ fontDescriptionRun.sizeDefined = true;
+
+ // Request to relayout.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ VALIDATE_FONTS |
+ SHAPE_TEXT |
+ GET_GLYPH_METRICS |
+ LAYOUT |
+ UPDATE_LAYOUT_SIZE |
+ REORDER |
+ ALIGN );
+ mImpl->mRecalculateNaturalSize = true;
+ mImpl->RequestRelayout();
+
+ mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
+ // As the font might change, recalculate the handle positions is needed.
+ mImpl->mEventData->mUpdateLeftSelectionPosition = true;
+ mImpl->mEventData->mUpdateRightSelectionPosition = true;
+ mImpl->mEventData->mUpdateHighlightBox = true;
+ mImpl->mEventData->mScrollAfterUpdatePosition = true;
+ }
+ }
+}
+
+float Controller::GetInputFontPointSize() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.size;
+ }
+
+ // Return the default font's point size if there is no EventData.
+ return GetDefaultPointSize();
+}
+
+void Controller::SetInputLineSpacing( float lineSpacing )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
+ mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
+ }
+}
+
+float Controller::GetInputLineSpacing() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.lineSpacing;
+ }
+
+ return 0.f;
+}
+
+void Controller::SetInputShadowProperties( const std::string& shadowProperties )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
+ }
+}
+
+const std::string& Controller::GetInputShadowProperties() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.shadowProperties;
+ }
+
+ return GetDefaultShadowProperties();
+}
+
+void Controller::SetInputUnderlineProperties( const std::string& underlineProperties )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
+ }
+}
+
+const std::string& Controller::GetInputUnderlineProperties() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.underlineProperties;
+ }
+
+ return GetDefaultUnderlineProperties();
+}
+
+void Controller::SetInputEmbossProperties( const std::string& embossProperties )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
+ }
+}
+
+const std::string& Controller::GetInputEmbossProperties() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.embossProperties;
+ }
+
+ return GetDefaultEmbossProperties();
+}
+
+void Controller::SetInputOutlineProperties( const std::string& outlineProperties )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
+ }
+}
+
+const std::string& Controller::GetInputOutlineProperties() const
+{
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mInputStyle.outlineProperties;
+ }
+
+ return GetDefaultOutlineProperties();
+}
+
+// public : Queries & retrieves.
+
+LayoutEngine& Controller::GetLayoutEngine()
+{
+ return mImpl->mLayoutEngine;
+}
+
+View& Controller::GetView()
+{
+ return mImpl->mView;
+}
+
+const Vector2& Controller::GetScrollPosition() const
+{
+ return mImpl->mScrollPosition;
+}
+
+Vector3 Controller::GetNaturalSize()
+{
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n" );
+ Vector3 naturalSize;
+
+ // Make sure the model is up-to-date before layouting
+ ProcessModifyEvents();
+
+ if( mImpl->mRecalculateNaturalSize )
+ {
+ // 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
+ mImpl->UpdateModel( onlyOnceOperations );
+
+ // Layout the text for the new width.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
+
+ // Set the update info to relayout the whole text.
+ mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+ mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
+
+ // Store the actual control's size to restore later.
+ const Size actualControlSize = mImpl->mVisualModel->mControlSize;
+
+ DoRelayout( Size( MAX_FLOAT, MAX_FLOAT ),
+ static_cast<OperationsMask>( onlyOnceOperations |
+ LAYOUT ),
+ naturalSize.GetVectorXY() );
+
+ // Do not do again the only once operations.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
+
+ // Do the size related operations again.
+ const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
+ ALIGN |
+ REORDER );
+ 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;
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ mImpl->mTextUpdateInfo.Clear();
+
+ // Restore the actual control's size.
+ mImpl->mVisualModel->mControlSize = actualControlSize;
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
+ }
+ else
+ {
+ naturalSize = mImpl->mVisualModel->GetNaturalSize();
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z );
+ }
+
+ naturalSize.x = ConvertToEven( naturalSize.x );
+ naturalSize.y = ConvertToEven( naturalSize.y );
+
+ return naturalSize;
+}
+
+float Controller::GetHeightForWidth( float width )
+{
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
+ // Make sure the model is up-to-date before layouting
+ ProcessModifyEvents();
+
+ Size layoutSize;
+ if( fabsf( width - mImpl->mVisualModel->mControlSize.width ) > Math::MACHINE_EPSILON_1000 )
+ {
+ // 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
+ mImpl->UpdateModel( onlyOnceOperations );
+
+
+ // Layout the text for the new width.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | LAYOUT );
+
+ // Set the update info to relayout the whole text.
+ mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+ mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mLogicalModel->mText.Count();
+
+ // Store the actual control's width.
+ const float actualControlWidth = mImpl->mVisualModel->mControlSize.width;
+
+ DoRelayout( Size( width, MAX_FLOAT ),
+ static_cast<OperationsMask>( onlyOnceOperations |
+ LAYOUT ),
+ layoutSize );
+
+ // Do not do again the only once operations.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending & ~onlyOnceOperations );
+
+ // Do the size related operations again.
+ const OperationsMask sizeOperations = static_cast<OperationsMask>( LAYOUT |
+ ALIGN |
+ REORDER );
+
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | sizeOperations );
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ mImpl->mTextUpdateInfo.Clear();
+
+ // Restore the actual control's width.
+ mImpl->mVisualModel->mControlSize.width = actualControlWidth;
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height );
+ }
+ else
+ {
+ layoutSize = mImpl->mVisualModel->GetLayoutSize();
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height );
+ }
+
+ return layoutSize.height;
+}
+
+// public : Relayout.
+
+Controller::UpdateTextType Controller::Relayout( const Size& size )
+{
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, (mImpl->mAutoScrollEnabled)?"true":"false" );
+
+ UpdateTextType updateTextType = NONE_UPDATED;
+
+ if( ( size.width < Math::MACHINE_EPSILON_1000 ) || ( size.height < Math::MACHINE_EPSILON_1000 ) )
+ {
+ if( 0u != mImpl->mVisualModel->mGlyphPositions.Count() )
+ {
+ mImpl->mVisualModel->mGlyphPositions.Clear();
+ updateTextType = MODEL_UPDATED;
+ }
+
+ // Clear the update info. This info will be set the next time the text is updated.
+ mImpl->mTextUpdateInfo.Clear();
+
+ // Not worth to relayout if width or height is equal to zero.
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
+
+ return updateTextType;
+ }
+
+ // Whether a new size has been set.
+ const bool newSize = ( size != mImpl->mVisualModel->mControlSize );
+
+ if( newSize )
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
+
+ // Layout operations that need to be done if the size changes.
+ mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+ LAYOUT |
+ ALIGN |
+ UPDATE_LAYOUT_SIZE |