GetLineCount() after GetTextDirection() returns wrong value.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller.cpp
index 36314c9..139fbfd 100755 (executable)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <limits>
+#include <cmath>
 #include <memory.h>
 #include <dali/public-api/adaptor-framework/key.h>
 #include <dali/integration-api/debug.h>
@@ -69,6 +70,17 @@ float ConvertToEven( float value )
   return static_cast<float>( intValue + ( intValue & 1 ) );
 }
 
+int ConvertPixelToPint( float pixel )
+{
+  unsigned int horizontalDpi = 0u;
+  unsigned int verticalDpi = 0u;
+  Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+  fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+  return ( pixel * 72.f ) / static_cast< float >( horizontalDpi );
+}
+
+
 } // namespace
 
 namespace Dali
@@ -384,6 +396,18 @@ void Controller::SetHorizontalAlignment( Text::HorizontalAlignment::Type alignme
     // Set the flag to redo the alignment operation.
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | ALIGN );
 
+    if( mImpl->mEventData )
+    {
+      mImpl->mEventData->mUpdateAlignment = true;
+
+      // Update the cursor if it's in editing mode
+      if( EventData::IsEditingState( mImpl->mEventData->mState ) )
+      {
+        mImpl->ChangeState( EventData::EDITING );
+        mImpl->mEventData->mUpdateCursorPosition = true;
+      }
+    }
+
     mImpl->RequestRelayout();
   }
 }
@@ -480,6 +504,92 @@ bool Controller::IsTextElideEnabled() const
   return mImpl->mModel->mElideEnabled;
 }
 
+void Controller::SetTextFitEnabled(bool enabled)
+{
+  mImpl->mTextFitEnabled = enabled;
+}
+
+bool Controller::IsTextFitEnabled() const
+{
+  return mImpl->mTextFitEnabled;
+}
+
+void Controller::SetTextFitMinSize( float minSize, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitMinSize = minSize;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitMinSize = ConvertPixelToPint( minSize );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitMinSize() const
+{
+  return mImpl->mTextFitMinSize;
+}
+
+void Controller::SetTextFitMaxSize( float maxSize, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitMaxSize = maxSize;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitMaxSize = ConvertPixelToPint( maxSize );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitMaxSize() const
+{
+  return mImpl->mTextFitMaxSize;
+}
+
+void Controller::SetTextFitStepSize( float step, FontSizeType type )
+{
+  switch( type )
+  {
+    case POINT_SIZE:
+    {
+      mImpl->mTextFitStepSize = step;
+      break;
+    }
+    case PIXEL_SIZE:
+    {
+      mImpl->mTextFitStepSize = ConvertPixelToPint( step );
+      break;
+    }
+  }
+}
+
+float Controller::GetTextFitStepSize() const
+{
+  return mImpl->mTextFitStepSize;
+}
+
+void Controller::SetTextFitContentSize(Vector2 size)
+{
+  mImpl->mTextFitContentSize = size;
+}
+
+Vector2 Controller::GetTextFitContentSize() const
+{
+  return mImpl->mTextFitContentSize;
+}
+
 void Controller::SetPlaceholderTextElideEnabled( bool enabled )
 {
   mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
@@ -1145,6 +1255,10 @@ void Controller::SetDefaultColor( const Vector4& color )
   {
     mImpl->mModel->mVisualModel->SetTextColor( color );
 
+    mImpl->mModel->mLogicalModel->mColorRuns.Clear();
+
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
+
     mImpl->RequestRelayout();
   }
 }
@@ -1343,7 +1457,7 @@ const std::string& Controller::GetDefaultOutlineProperties() const
 
 bool Controller::SetDefaultLineSpacing( float lineSpacing )
 {
-  if( std::abs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000 )
+  if( std::fabs( lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing() ) > Math::MACHINE_EPSILON_1000 )
   {
     mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
     mImpl->mRecalculateNaturalSize = true;
@@ -1991,6 +2105,98 @@ Vector3 Controller::GetNaturalSize()
   return naturalSize;
 }
 
+bool Controller::CheckForTextFit( float pointSize, Size& layoutSize )
+{
+  Size textSize;
+  mImpl->mFontDefaults->mFitPointSize = pointSize;
+  mImpl->mFontDefaults->sizeDefined = true;
+  ClearFontData();
+
+  // 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 );
+
+  mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+  mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+
+  // Make sure the model is up-to-date before layouting
+  mImpl->UpdateModel( onlyOnceOperations );
+
+  DoRelayout( Size( layoutSize.width, MAX_FLOAT ),
+              static_cast<OperationsMask>( onlyOnceOperations | LAYOUT),
+              textSize);
+
+  // Clear the update info. This info will be set the next time the text is updated.
+  mImpl->mTextUpdateInfo.Clear();
+  mImpl->mTextUpdateInfo.mClearAll = true;
+
+  if( textSize.width > layoutSize.width || textSize.height > layoutSize.height )
+  {
+    return false;
+  }
+  return true;
+}
+
+void Controller::FitPointSizeforLayout( Size layoutSize )
+{
+  const OperationsMask operations  = mImpl->mOperationsPending;
+  if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) )
+  {
+    bool actualellipsis = mImpl->mModel->mElideEnabled;
+    float minPointSize = mImpl->mTextFitMinSize;
+    float maxPointSize = mImpl->mTextFitMaxSize;
+    float pointInterval = mImpl->mTextFitStepSize;
+
+    mImpl->mModel->mElideEnabled = false;
+    Vector<float> pointSizeArray;
+
+    // check zero value
+    if( pointInterval < 1.f )
+    {
+      mImpl->mTextFitStepSize = pointInterval = 1.0f;
+    }
+
+    pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) );
+
+    for( float i = minPointSize; i < maxPointSize; i += pointInterval )
+    {
+      pointSizeArray.PushBack( i );
+    }
+
+    pointSizeArray.PushBack( maxPointSize );
+
+    int bestSizeIndex = 0;
+    int min = bestSizeIndex + 1;
+    int max = pointSizeArray.Size() - 1;
+    while( min <= max )
+    {
+      int destI = ( min + max ) / 2;
+
+      if( CheckForTextFit( pointSizeArray[destI], layoutSize ) )
+      {
+        bestSizeIndex = min;
+        min = destI + 1;
+      }
+      else
+      {
+        max = destI - 1;
+        bestSizeIndex = max;
+      }
+    }
+
+    mImpl->mModel->mElideEnabled = actualellipsis;
+    mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
+    mImpl->mFontDefaults->sizeDefined = true;
+    ClearFontData();
+  }
+}
+
 float Controller::GetHeightForWidth( float width )
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width );
@@ -2253,6 +2459,9 @@ Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
     // Clear the update info. This info will be set the next time the text is updated.
     mImpl->mTextUpdateInfo.Clear();
 
+    // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
+    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+
     mImpl->mUpdateTextDirection = false;
   }
 
@@ -3585,7 +3794,7 @@ bool Controller::DoRelayout( const Size& size,
     // Make sure the index is not out of bound
     if ( charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
          requestedNumberOfCharacters > charactersToGlyph.Count() ||
-         ( lastIndex >= charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
+         ( lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u ) )
     {
       std::string currentText;
       GetText( currentText );
@@ -3751,11 +3960,23 @@ bool Controller::DoRelayout( const Size& size,
     // The laid-out lines.
     Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
 
+    CharacterIndex alignStartIndex = startIndex;
+    Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
+
+    // the whole text needs to be full aligned.
+    // If you do not do a full aligned, only the last line of the multiline input is aligned.
+    if(  mImpl->mEventData && mImpl->mEventData->mUpdateAlignment )
+    {
+      alignStartIndex = 0u;
+      alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
+      mImpl->mEventData->mUpdateAlignment = false;
+    }
+
     // Need to align with the control's size as the text may contain lines
     // starting either with left to right text or right to left.
     mImpl->mLayoutEngine.Align( size,
-                                startIndex,
-                                requestedNumberOfCharacters,
+                                alignStartIndex,
+                                alignRequestedNumberOfCharacters,
                                 mImpl->mModel->mHorizontalAlignment,
                                 lines,
                                 mImpl->mModel->mAlignmentOffset,