Merge "Add a callback to get textfitted font size." into devel/master
authorjoogab yun <joogab.yun@samsung.com>
Mon, 22 Nov 2021 06:40:15 +0000 (06:40 +0000)
committerGerrit Code Review <gerrit@review>
Mon, 22 Nov 2021 06:40:15 +0000 (06:40 +0000)
1  2 
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller-relayouter.cpp
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h

@@@ -82,6 -82,8 +82,8 @@@ const unsigned int EMOJI_FONT_SIZE = 38
  static bool gAnchorClickedCallBackCalled;
  static bool gAnchorClickedCallBackNotCalled;
  
+ static bool gTextFitChangedCallBackCalled;
  struct CallbackFunctor
  {
    CallbackFunctor(bool* callbackFlag)
@@@ -108,6 -110,12 +110,12 @@@ static void TestAnchorClickedCallback(T
    }
  }
  
+ static void TestTextFitChangedCallback(TextLabel control)
+ {
+   tet_infoline(" TestTextFitChangedCallback");
+   gTextFitChangedCallBackCalled = true;
+ }
  bool DaliTestCheckMaps( const Property::Map& mapGet, const Property::Map& mapSet, const std::vector<std::string>& indexConversionTable = std::vector<std::string>() )
  {
    const Property::Map::SizeType size = mapGet.Count();
@@@ -843,37 -851,6 +851,37 @@@ int UtcDaliToolkitTextLabelEmojisP(void
    application.SendNotification();
    application.Render();
  
 +  // EMOJI Sequences case for coverage.
 +  std::string emojiSequences =
 +       "Text VS15 &#x262a;&#xfe0e;\n"                                                         //text presentation sequence and selector
 +      "Color VS16 &#x262a;&#xfe0f;\n"                                                        //emoji presentation sequence and selector
 +      "Default &#x262a; \n"                                                                  //default presentation
 +      "FamilyManWomanGirlBoy &#x1F468;&#x200D;&#x1F469;&#x200D;&#x1F467;&#x200D;&#x1F466;\n" // emoji multi zwj sequence
 +      "WomanScientist &#x1f469;&#x200d;&#x1f52c;\n"                                          // emoji zwj sequence
 +      "WomanScientistLightSkinTone&#x1F469;&#x1F3FB;&#x200D;&#x1F52C; \n"                    //emoji modifier sequence: skin tone & JWZ
 +      "LeftRightArrowText&#x2194;&#xfe0e;\n"                                                 //text presentation sequence and selector
 +      "LeftRightArrowEmoji&#x2194;&#xfe0f;\n"                                                //emoji presentation sequence and selector
 +      "SouthKoreaFlag&#x1f1f0;&#x1f1f7;\n"                                                   //emoji flag sequence
 +      "JordanFlag&#x1f1ef;&#x1f1f4;\n"                                                       // emoji flag sequence
 +      "EnglandFlag&#x1F3F4;&#xE0067;&#xE0062;&#xE0065;&#xE006E;&#xE0067;&#xE007F;\n"         //emoji tag sequence like England flag
 +      "Runner &#x1f3c3;&#x200d;&#x27a1;&#xfe0f; \n"
 +      "VictoryHandMediumLightSkinTone:&#x270C;&#xFE0F;&#x1F3FC;\n"               //emoji modifier sequence: skin tone
 +      "RainbowFlag:&#x1F3F3;&#xFE0F;&#x200D;&#x1F308; \n"                        //emoji zwj sequence: Rainbow Flag
 +      "keycap# &#x0023;&#xFE0F;&#x20E3; \n"                                      // fully-qualified  emoji keycap sequence
 +      "keycap#_text &#x0023;&#x20E3; \n"                                         // unqualified emoji keycap sequence
 +      "keycap3 &#x0033;&#xfe0f;&#x20e3; \n"                                      // fully-qualified  emoji keycap sequence
 +      "keycap3_text &#x0033;&#x20e3; \n"                                         // unqualified emoji keycap sequence
 +      "two adjacent glyphs &#x262a;&#xfe0f;&#xfe0f;&#xfe0f;&#x262a;&#xfe0f;\n"   //This line should be rendered as two adjacent glyphs
 +      "Digit 8&#xfe0f; 8&#xfe0e; 8\n"                                            // should be rendered according to selector
 +      "Surfing Medium Skin Female:  &#x1f3c4;&#x1f3fc;&#x200d;&#x2640;&#xfe0f;"; // Person Surfing + Medium Skin Tone +? Zero Width Joiner + Female Sign
 +
 +  label.SetProperty( TextLabel::Property::TEXT, emojiSequences );
 +  label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true );
 +  label.SetProperty( TextLabel::Property::MULTI_LINE, true);
 +  label.SetProperty( TextLabel::Property::ELLIPSIS, false);
 +
 +  application.SendNotification();
 +  application.Render();
    END_TEST;
  }
  
@@@ -1663,6 -1640,13 +1671,13 @@@ int UtcDaliToolkitTextlabelTextFit(void
    label.SetProperty( Actor::Property::SIZE, size );
    label.SetProperty( TextLabel::Property::TEXT, "Hello world" );
  
+    // connect to the text git changed signal.
+   ConnectionTracker* testTracker = new ConnectionTracker();
+   DevelTextLabel::TextFitChangedSignal(label).Connect(&TestTextFitChangedCallback);
+   bool textFitChangedSignal = false;
+   label.ConnectSignal(testTracker, "textFitChanged", CallbackFunctor(&textFitChangedSignal));
+   gTextFitChangedCallBackCalled = false;
    // check point size
    Property::Map textFitMapSet;
    textFitMapSet["enable"] = true;
    const Vector3 EXPECTED_NATURAL_SIZE( 450.0f, 96.0f, 0.0f );
    DALI_TEST_EQUALS( EXPECTED_NATURAL_SIZE, label.GetNaturalSize(), TEST_LOCATION );
  
+   DALI_TEST_CHECK(gTextFitChangedCallBackCalled);
+   DALI_TEST_CHECK(textFitChangedSignal);
    // check pixel size
    textFitMapSet.Clear();
    textFitMapSet["enable"] = true;
@@@ -2058,4 -2045,4 +2076,4 @@@ int UtcDaliToolkitTextlabelEllipsisPosi
  
  
    END_TEST;
- }
+ }
@@@ -545,11 -545,6 +545,11 @@@ struct Controller::Imp
    }
  
    /**
 +   * @copydoc Controller::GetLayoutDirection()
 +   */
 +  Dali::LayoutDirection::Type GetLayoutDirection(Dali::Actor& actor) const;
 +
 +  /**
     * @brief Calculates the start character index of the first paragraph to be updated and
     * the end character index of the last paragraph to be updated.
     *
    void CalculateTextUpdateIndices(Length& numberOfCharacters);
  
    /**
 -   * @brief Helper to clear completely the parts of the model specified by the given @p operations.
 -   *
 -   * @note It never clears the text stored in utf32.
 -   */
 -  void ClearFullModelData(OperationsMask operations);
 -
 -  /**
 -   * @brief Helper to clear completely the parts of the model related with the characters specified by the given @p operations.
 -   *
 -   * @note It never clears the text stored in utf32.
 -   *
 -   * @param[in] startIndex Index to the first character to be cleared.
 -   * @param[in] endIndex Index to the last character to be cleared.
 -   * @param[in] operations The operations required.
 -   */
 -  void ClearCharacterModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations);
 -
 -  /**
 -   * @brief Helper to clear completely the parts of the model related with the glyphs specified by the given @p operations.
 -   *
 -   * @note It never clears the text stored in utf32.
 -   * @note Character indices are transformed to glyph indices.
 -   *
 -   * @param[in] startIndex Index to the first character to be cleared.
 -   * @param[in] endIndex Index to the last character to be cleared.
 -   * @param[in] operations The operations required.
 -   */
 -  void ClearGlyphModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations);
 -
 -  /**
     * @brief Helper to clear the parts of the model specified by the given @p operations and from @p startIndex to @p endIndex.
     *
     * @note It never clears the text stored in utf32.
    float GetDefaultFontLineHeight();
  
    /**
 +   * @copydoc Controller::SetDefaultLineSpacing
 +   */
 +  bool SetDefaultLineSpacing(float lineSpacing);
 +
 +  /**
 +   * @copydoc Controller::SetDefaultLineSize
 +   */
 +  bool SetDefaultLineSize(float lineSize);
 +
 +  /**
     * @copydoc Text::Controller::GetPrimaryCursorPosition()
     */
    CharacterIndex GetPrimaryCursorPosition() const;
    void SetEditable(bool editable);
  
    /**
 +   * @copydoc Controller::UpdateAfterFontChange
 +   */
 +  void UpdateAfterFontChange(const std::string& newDefaultFont);
 +
 +  /**
     * @brief Retrieves the selected text. It removes the text if the @p deleteAfterRetrieval parameter is @e true.
     *
     * @param[out] selectedText The selected text encoded in utf8.
     */
    Actor CreateBackgroundActor();
  
 +  /**
 +   * @brief fill needed relayout parameters when line size is changed & request relayout.
 +   */
 +  void RelayoutForNewLineSize();
 +
 +  /**
 +   * @copydoc Controller::IsInputStyleChangedSignalsQueueEmpty
 +   */
 +  bool IsInputStyleChangedSignalsQueueEmpty();
 +
 +  /**
 +   * @copydoc Controller::ProcessInputStyleChangedSignals
 +   */
 +  void ProcessInputStyleChangedSignals();
 +
 +  /**
 +   * @copydoc Controller::ScrollBy()
 +   */
 +  void ScrollBy(Vector2 scroll);
 +
 +  /**
 +   * @copydoc Controller::GetHorizontalScrollPosition()
 +   */
 +  float GetHorizontalScrollPosition();
 +
 +  /**
 +   * @copydoc Controller::GetVerticalScrollPosition()
 +   */
 +  float GetVerticalScrollPosition();
 +
 +  /**
 +   * @copydoc Controller::SetAutoScrollEnabled()
 +   */
 +  void SetAutoScrollEnabled(bool enable);
 +
 +  /**
 +   * @copydoc Controller::SetEnableCursorBlink()
 +   */
 +  void SetEnableCursorBlink(bool enable);
 +
 +  /**
 +   * @copydoc Controller::SetMultiLineEnabled()
 +   */
 +  void SetMultiLineEnabled(bool enable);
 +
 +  /**
 +   * @copydoc Controller::SetHorizontalAlignment()
 +   */
 +  void SetHorizontalAlignment(HorizontalAlignment::Type alignment);
 +
 +  /**
 +   * @copydoc Controller::SetVerticalAlignment()
 +   */
 +  void SetVerticalAlignment(VerticalAlignment::Type alignment);
 +
 +  /**
 +   * @copydoc Controller::SetLineWrapMode()
 +   */
 +  void SetLineWrapMode(Text::LineWrap::Mode textWarpMode);
 +
 +  /**
 +   * @copydoc Controller::SetDefaultColor()
 +   */
 +  void SetDefaultColor(const Vector4& color);
 +
 +  /**
 +   * @brief Helper to clear font-specific data (only).
 +   */
 +  void ClearFontData();
 +
 +  /**
 +   * @brief Helper to clear text's style data.
 +   */
 +  void ClearStyleData();
 +
 +  /**
 +   * @brief Used to reset the scroll position after setting a new text.
 +   */
 +  void ResetScrollPosition();
 +
  public:
    /**
     * @brief Gets implementation from the controller handle.
@@@ -911,6 -841,7 +911,7 @@@ public
    float mTextFitMaxSize;               ///< Maximum Font Size for text fit. Default 100
    float mTextFitStepSize;              ///< Step Size for font intervalse. Default 1
    bool  mTextFitEnabled : 1;           ///< Whether the text's fit is enabled.
+   float mTextFitChanged;               ///< Whether the text fit property has changed.
    float mFontSizeScale;                ///< Scale value for Font Size. Default 1.0
    bool  mIsLayoutDirectionChanged : 1; ///< Whether the layout has changed.
  
@@@ -170,7 -170,7 +170,7 @@@ bool Controller::Relayouter::CheckForTe
    TextUpdateInfo&   textUpdateInfo  = impl.mTextUpdateInfo;
    impl.mFontDefaults->mFitPointSize = pointSize;
    impl.mFontDefaults->sizeDefined   = true;
 -  controller.ClearFontData();
 +  impl.ClearFontData();
  
    // Operations that can be done only once until the text changes.
    const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
@@@ -216,6 -216,7 +216,7 @@@ void Controller::Relayouter::FitPointSi
      float minPointSize   = impl.mTextFitMinSize;
      float maxPointSize   = impl.mTextFitMaxSize;
      float pointInterval  = impl.mTextFitStepSize;
+     float currentFitPointSize = impl.mFontDefaults->mFitPointSize;
  
      model->mElideEnabled = false;
      Vector<float> pointSizeArray;
      }
  
      model->mElideEnabled              = actualellipsis;
+     if(currentFitPointSize != pointSizeArray[bestSizeIndex])
+     {
+       impl.mTextFitChanged = true;
+     }
      impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
      impl.mFontDefaults->sizeDefined   = true;
 -    controller.ClearFontData();
 +    impl.ClearFontData();
    }
  }
  
@@@ -561,7 -566,7 +566,7 @@@ bool Controller::Relayouter::DoRelayout
        // Reset the scroll position in inactive state
        if(elideTextEnabled && (impl.mEventData->mState == EventData::INACTIVE))
        {
 -        controller.ResetScrollPosition();
 +        impl.ResetScrollPosition();
        }
      }
  
@@@ -31,7 -31,6 +31,7 @@@
  #include <dali-toolkit/internal/text/text-controller-event-handler.h>
  #include <dali-toolkit/internal/text/text-controller-impl.h>
  #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
 +#include <dali-toolkit/internal/text/text-controller-input-properties.h>
  #include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
  #include <dali-toolkit/internal/text/text-controller-relayouter.h>
  #include <dali-toolkit/internal/text/text-controller-text-updater.h>
@@@ -138,7 -137,7 +138,7 @@@ void Controller::SetGlyphType(TextAbstr
    mImpl->mMetrics->SetGlyphType(glyphType);
  
    // Clear the font-specific data
 -  ClearFontData();
 +  mImpl->ClearFontData();
  
    mImpl->RequestRelayout();
  }
@@@ -170,12 -169,39 +170,12 @@@ bool Controller::HasAnchors() cons
  void Controller::SetAutoScrollEnabled(bool enable)
  {
    DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable) ? "true" : "false", (mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) ? "true" : "false", this);
 -
 -  if(mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
 -  {
 -    mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
 -                                                            LAYOUT |
 -                                                            ALIGN |
 -                                                            UPDATE_LAYOUT_SIZE |
 -                                                            REORDER);
 -
 -    if(enable)
 -    {
 -      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
 -      mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | UPDATE_DIRECTION);
 -    }
 -    else
 -    {
 -      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
 -    }
 -
 -    mImpl->mIsAutoScrollEnabled = enable;
 -    mImpl->RequestRelayout();
 -  }
 -  else
 -  {
 -    DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
 -    mImpl->mIsAutoScrollEnabled = false;
 -  }
 +  mImpl->SetAutoScrollEnabled(enable);
  }
  
  bool Controller::IsAutoScrollEnabled() const
  {
    DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false");
 -
    return mImpl->mIsAutoScrollEnabled;
  }
  
@@@ -245,7 -271,17 +245,7 @@@ int Controller::GetMaximumNumberOfChara
  
  void Controller::SetEnableCursorBlink(bool enable)
  {
 -  DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "TextInput disabled");
 -
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mCursorBlinkEnabled = enable;
 -
 -    if(!enable && mImpl->mEventData->mDecorator)
 -    {
 -      mImpl->mEventData->mDecorator->StopCursorBlink();
 -    }
 -  }
 +  mImpl->SetEnableCursorBlink(enable);
  }
  
  bool Controller::GetEnableCursorBlink() const
  
  void Controller::SetMultiLineEnabled(bool enable)
  {
 -  const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
 -
 -  if(layout != mImpl->mLayoutEngine.GetLayout())
 -  {
 -    // Set the layout type.
 -    mImpl->mLayoutEngine.SetLayout(layout);
 -
 -    // Set the flags to redo the layout operations
 -    const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
 -                                                                        UPDATE_LAYOUT_SIZE |
 -                                                                        ALIGN |
 -                                                                        REORDER);
 -
 -    mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
 -    mImpl->mOperationsPending                  = static_cast<OperationsMask>(mImpl->mOperationsPending | layoutOperations);
 -
 -    // Need to recalculate natural size
 -    mImpl->mRecalculateNaturalSize = true;
 -
 -    mImpl->RequestRelayout();
 -  }
 +  mImpl->SetMultiLineEnabled(enable);
  }
  
  bool Controller::IsMultiLineEnabled() const
  
  void Controller::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
  {
 -  if(alignment != mImpl->mModel->mHorizontalAlignment)
 -  {
 -    // Set the alignment.
 -    mImpl->mModel->mHorizontalAlignment = alignment;
 -
 -    // 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();
 -  }
 +  mImpl->SetHorizontalAlignment(alignment);
  }
  
  Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
  
  void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
  {
 -  if(alignment != mImpl->mModel->mVerticalAlignment)
 -  {
 -    // Set the alignment.
 -    mImpl->mModel->mVerticalAlignment = alignment;
 -    mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
 -    mImpl->RequestRelayout();
 -  }
 +  mImpl->SetVerticalAlignment(alignment);
  }
  
  VerticalAlignment::Type Controller::GetVerticalAlignment() const
@@@ -333,7 -416,31 +333,7 @@@ bool Controller::IsShowingRealText() co
  
  void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
  {
 -  if(lineWrapMode != mImpl->mModel->mLineWrapMode)
 -  {
 -    // Update Text layout for applying wrap mode
 -    mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
 -                                                            ALIGN |
 -                                                            LAYOUT |
 -                                                            UPDATE_LAYOUT_SIZE |
 -                                                            REORDER);
 -
 -    if((mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
 -       (mImpl->mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
 -    {
 -      mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | GET_LINE_BREAKS);
 -    }
 -
 -    // Set the text wrap mode.
 -    mImpl->mModel->mLineWrapMode = lineWrapMode;
 -
 -    mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
 -    mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
 -    mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
 -
 -    // Request relayout
 -    mImpl->RequestRelayout();
 -  }
 +  mImpl->SetLineWrapMode(lineWrapMode);
  }
  
  Text::LineWrap::Mode Controller::GetLineWrapMode() const
@@@ -362,6 -469,16 +362,16 @@@ bool Controller::IsTextFitEnabled() con
    return mImpl->mTextFitEnabled;
  }
  
+ void Controller::SetTextFitChanged(bool changed)
+ {
+   mImpl->mTextFitChanged = changed;
+ }
+ bool Controller::IsTextFitChanged() const
+ {
+   return mImpl->mTextFitChanged;
+ }
  void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
  {
    mImpl->mTextFitMinSize = (type == POINT_SIZE) ? minSize : ConvertPixelToPoint(minSize);
@@@ -402,6 -519,11 +412,11 @@@ Vector2 Controller::GetTextFitContentSi
    return mImpl->mTextFitContentSize;
  }
  
+ float Controller::GetTextFitPointSize() const
+ {
+   return mImpl->mFontDefaults ? mImpl->mFontDefaults->mFitPointSize : 0.0f;
+ }
  void Controller::SetPlaceholderTextElideEnabled(bool enabled)
  {
    PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
@@@ -482,7 -604,17 +497,7 @@@ void Controller::GetPlaceholderText(Pla
  
  void Controller::UpdateAfterFontChange(const std::string& newDefaultFont)
  {
 -  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
 -
 -  if(!mImpl->mFontDefaults->familyDefined) // If user defined font then should not update when system font changes
 -  {
 -    DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str());
 -    mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
 -
 -    ClearFontData();
 -
 -    mImpl->RequestRelayout();
 -  }
 +  mImpl->UpdateAfterFontChange(newDefaultFont);
  }
  
  void Controller::RetrieveSelection(std::string& selectedText) const
@@@ -522,7 -654,7 +537,7 @@@ void Controller::SetDefaultFontFamily(c
    UpdateCursorPosition(mImpl->mEventData);
  
    // Clear the font-specific data
 -  ClearFontData();
 +  mImpl->ClearFontData();
  
    mImpl->RequestRelayout();
  }
@@@ -553,7 -685,7 +568,7 @@@ void Controller::SetDefaultFontWeight(F
    UpdateCursorPosition(mImpl->mEventData);
  
    // Clear the font-specific data
 -  ClearFontData();
 +  mImpl->ClearFontData();
  
    mImpl->RequestRelayout();
  }
@@@ -594,7 -726,7 +609,7 @@@ void Controller::SetDefaultFontWidth(Fo
    UpdateCursorPosition(mImpl->mEventData);
  
    // Clear the font-specific data
 -  ClearFontData();
 +  mImpl->ClearFontData();
  
    mImpl->RequestRelayout();
  }
@@@ -635,7 -767,7 +650,7 @@@ void Controller::SetDefaultFontSlant(Fo
    UpdateCursorPosition(mImpl->mEventData);
  
    // Clear the font-specific data
 -  ClearFontData();
 +  mImpl->ClearFontData();
  
    mImpl->RequestRelayout();
  }
@@@ -673,7 -805,7 +688,7 @@@ void Controller::SetFontSizeScale(floa
    UpdateCursorPosition(mImpl->mEventData);
  
    // Clear the font-specific data
 -  ClearFontData();
 +  mImpl->ClearFontData();
  
    mImpl->RequestRelayout();
  }
@@@ -694,7 -826,7 +709,7 @@@ void Controller::SetDefaultFontSize(flo
    UpdateCursorPosition(mImpl->mEventData);
  
    // Clear the font-specific data
 -  ClearFontData();
 +  mImpl->ClearFontData();
  
    mImpl->RequestRelayout();
  }
@@@ -720,7 -852,15 +735,7 @@@ float Controller::GetPlaceholderTextFon
  
  void Controller::SetDefaultColor(const Vector4& color)
  {
 -  mImpl->mTextColor = color;
 -
 -  if(!mImpl->IsShowingPlaceholderText())
 -  {
 -    mImpl->mModel->mVisualModel->SetTextColor(color);
 -    mImpl->mModel->mLogicalModel->mColorRuns.Clear();
 -    mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
 -    mImpl->RequestRelayout();
 -  }
 +  mImpl->SetDefaultColor(color);
  }
  
  const Vector4& Controller::GetDefaultColor() const
@@@ -873,9 -1013,34 +888,9 @@@ const std::string& Controller::GetDefau
    return mImpl->mOutlineDefaults ? mImpl->mOutlineDefaults->properties : EMPTY_STRING;
  }
  
 -void Controller::RelayoutForNewLineSize()
 -{
 -  // relayout all characters
 -  mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
 -  mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
 -  mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
 -  mImpl->mOperationsPending                          = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT);
 -
 -  //remove selection
 -  if(mImpl->mEventData && mImpl->mEventData->mState == EventData::SELECTING)
 -  {
 -    mImpl->ChangeState(EventData::EDITING);
 -  }
 -
 -  mImpl->RequestRelayout();
 -}
 -
  bool Controller::SetDefaultLineSpacing(float lineSpacing)
  {
 -  if(std::fabs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
 -  {
 -    mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
 -    mImpl->mRecalculateNaturalSize = true;
 -
 -    RelayoutForNewLineSize();
 -    return true;
 -  }
 -  return false;
 +  return mImpl->SetDefaultLineSpacing(lineSpacing);
  }
  
  float Controller::GetDefaultLineSpacing() const
  
  bool Controller::SetDefaultLineSize(float lineSize)
  {
 -  if(std::fabs(lineSize - mImpl->mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
 -  {
 -    mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
 -    mImpl->mRecalculateNaturalSize = true;
 -
 -    RelayoutForNewLineSize();
 -    return true;
 -  }
 -  return false;
 +  return mImpl->SetDefaultLineSize(lineSize);
  }
  
  float Controller::GetDefaultLineSize() const
  
  void Controller::SetInputColor(const Vector4& color)
  {
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mInputStyle.textColor      = color;
 -    mImpl->mEventData->mInputStyle.isDefaultColor = false;
 -
 -    if(EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState)
 -    {
 -      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->mModel->mLogicalModel->mColorRuns.Count();
 -        mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
 -
 -        ColorRun& colorRun                       = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
 -        colorRun.color                           = color;
 -        colorRun.characterRun.characterIndex     = startOfSelectedText;
 -        colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
 -
 -        mImpl->mTextUpdateInfo.mCharacterIndex             = startOfSelectedText;
 -        mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
 -        mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = lengthOfSelectedText;
 -      }
 -      else
 -      {
 -        mImpl->mTextUpdateInfo.mCharacterIndex             = 0;
 -        mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
 -        mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
 -      }
 -
 -      // Request to relayout.
 -      mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
 -      mImpl->RequestRelayout();
 -    }
 -  }
 +  InputProperties::SetInputColor(*this, color);
  }
  
  const Vector4& Controller::GetInputColor() const
  {
 -  // Return event text input color if we have it, otherwise just return the default text's color
 -  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.textColor : mImpl->mTextColor;
 +  return InputProperties::GetInputColor(*this);
  }
  
  void Controller::SetInputFontFamily(const std::string& fontFamily)
@@@ -970,62 -1183,81 +985,62 @@@ float Controller::GetInputFontPointSize
  
  void Controller::SetInputLineSpacing(float lineSpacing)
  {
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mInputStyle.lineSpacing          = lineSpacing;
 -    mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
 -  }
 +  InputProperties::SetInputLineSpacing(*this, lineSpacing);
  }
  
  float Controller::GetInputLineSpacing() const
  {
 -  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.lineSpacing : 0.0f;
 +  return InputProperties::GetInputLineSpacing(*this);
  }
  
  void Controller::SetInputShadowProperties(const std::string& shadowProperties)
  {
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
 -  }
 +  InputProperties::SetInputShadowProperties(*this, shadowProperties);
  }
  
  const std::string& Controller::GetInputShadowProperties() const
  {
 -  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.shadowProperties : EMPTY_STRING;
 +  return InputProperties::GetInputShadowProperties(*this);
  }
  
  void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
  {
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
 -  }
 +  InputProperties::SetInputUnderlineProperties(*this, underlineProperties);
  }
  
  const std::string& Controller::GetInputUnderlineProperties() const
  {
 -  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.underlineProperties : EMPTY_STRING;
 +  return InputProperties::GetInputUnderlineProperties(*this);
  }
  
  void Controller::SetInputEmbossProperties(const std::string& embossProperties)
  {
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
 -  }
 +  InputProperties::SetInputEmbossProperties(*this, embossProperties);
  }
  
  const std::string& Controller::GetInputEmbossProperties() const
  {
 -  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.embossProperties : GetDefaultEmbossProperties();
 +  return InputProperties::GetInputEmbossProperties(*this);
  }
  
  void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
  {
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
 -  }
 +  InputProperties::SetInputOutlineProperties(*this, outlineProperties);
  }
  
  const std::string& Controller::GetInputOutlineProperties() const
  {
 -  return mImpl->mEventData ? mImpl->mEventData->mInputStyle.outlineProperties : GetDefaultOutlineProperties();
 +  return InputProperties::GetInputOutlineProperties(*this);
  }
  
  void Controller::SetInputModePassword(bool passwordInput)
  {
 -  if(mImpl->mEventData)
 -  {
 -    mImpl->mEventData->mPasswordInput = passwordInput;
 -  }
 +  InputProperties::SetInputModePassword(*this, passwordInput);
  }
  
  bool Controller::IsInputModePassword()
  {
 -  return mImpl->mEventData && mImpl->mEventData->mPasswordInput;
 +  return InputProperties::IsInputModePassword(*this);
  }
  
  void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
@@@ -1274,12 -1506,23 +1289,12 @@@ void Controller::RequestRelayout(
  
  bool Controller::IsInputStyleChangedSignalsQueueEmpty()
  {
 -  return (NULL == mImpl->mEventData) || (0u == mImpl->mEventData->mInputStyleChangedQueue.Count());
 +  return mImpl->IsInputStyleChangedSignalsQueueEmpty();
  }
  
  void Controller::ProcessInputStyleChangedSignals()
  {
 -  if(mImpl->mEventData)
 -  {
 -    if(mImpl->mEditableControlInterface)
 -    {
 -      // Emit the input style changed signal for each mask
 -      std::for_each(mImpl->mEventData->mInputStyleChangedQueue.begin(),
 -                    mImpl->mEventData->mInputStyleChangedQueue.end(),
 -                    [&](const auto mask) { mImpl->mEditableControlInterface->InputStyleChanged(mask); } );
 -    }
 -
 -    mImpl->mEventData->mInputStyleChangedQueue.Clear();
 -  }
 +  mImpl->ProcessInputStyleChangedSignals();
  }
  
  void Controller::KeyboardFocusGainEvent()
@@@ -1476,21 -1719,52 +1491,21 @@@ bool Controller::IsEditable() cons
  void Controller::SetEditable(bool editable)
  {
    mImpl->SetEditable(editable);
 -  if(mImpl->mEventData && mImpl->mEventData->mDecorator)
 -  {
 -    mImpl->mEventData->mDecorator->SetEditable(editable);
 -  }
  }
  
  void Controller::ScrollBy(Vector2 scroll)
  {
 -  if(mImpl->mEventData && (fabs(scroll.x) > Math::MACHINE_EPSILON_0 || fabs(scroll.y) > Math::MACHINE_EPSILON_0))
 -  {
 -    const Vector2& layoutSize    = mImpl->mModel->mVisualModel->GetLayoutSize();
 -    const Vector2  currentScroll = mImpl->mModel->mScrollPosition;
 -
 -    scroll.x = -scroll.x;
 -    scroll.y = -scroll.y;
 -
 -    if(fabs(scroll.x) > Math::MACHINE_EPSILON_0)
 -    {
 -      mImpl->mModel->mScrollPosition.x += scroll.x;
 -      mImpl->ClampHorizontalScroll(layoutSize);
 -    }
 -
 -    if(fabs(scroll.y) > Math::MACHINE_EPSILON_0)
 -    {
 -      mImpl->mModel->mScrollPosition.y += scroll.y;
 -      mImpl->ClampVerticalScroll(layoutSize);
 -    }
 -
 -    if(mImpl->mModel->mScrollPosition != currentScroll)
 -    {
 -      mImpl->mEventData->mDecorator->UpdatePositions(mImpl->mModel->mScrollPosition - currentScroll);
 -      mImpl->RequestRelayout();
 -    }
 -  }
 +  mImpl->ScrollBy(scroll);
  }
  
  float Controller::GetHorizontalScrollPosition()
  {
 -  // Scroll values are negative internally so we convert them to positive numbers
 -  return mImpl->mEventData ? -mImpl->mModel->mScrollPosition.x : 0.0f;
 +  return mImpl->GetHorizontalScrollPosition();
  }
  
  float Controller::GetVerticalScrollPosition()
  {
 -  // Scroll values are negative internally so we convert them to positive numbers
 -  return mImpl->mEventData ? -mImpl->mModel->mScrollPosition.y : 0.0f;
 +  return mImpl->GetVerticalScrollPosition();
  }
  
  void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
@@@ -1589,6 -1863,39 +1604,6 @@@ void Controller::ShowPlaceholderText(
    PlaceholderHandler::ShowPlaceholderText(*this);
  }
  
 -void Controller::ClearFontData()
 -{
 -  if(mImpl->mFontDefaults)
 -  {
 -    mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
 -  }
 -
 -  // Set flags to update the model.
 -  mImpl->mTextUpdateInfo.mCharacterIndex             = 0u;
 -  mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
 -  mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd    = mImpl->mModel->mLogicalModel->mText.Count();
 -
 -  mImpl->mTextUpdateInfo.mClearAll           = true;
 -  mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
 -  mImpl->mRecalculateNaturalSize             = true;
 -
 -  mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
 -                                                          VALIDATE_FONTS |
 -                                                          SHAPE_TEXT |
 -                                                          BIDI_INFO |
 -                                                          GET_GLYPH_METRICS |
 -                                                          LAYOUT |
 -                                                          UPDATE_LAYOUT_SIZE |
 -                                                          REORDER |
 -                                                          ALIGN);
 -}
 -
 -void Controller::ClearStyleData()
 -{
 -  mImpl->mModel->mLogicalModel->mColorRuns.Clear();
 -  mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
 -}
 -
  void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
  {
    // Reset the cursor position
  
  CharacterIndex Controller::GetCursorPosition()
  {
 -  if(!mImpl->mEventData)
 -    return 0;
 -
 -  return mImpl->mEventData->mPrimaryCursorPosition;
 -}
 -
 -void Controller::ResetScrollPosition()
 -{
 -  if(mImpl->mEventData)
 -  {
 -    // Reset the scroll position.
 -    mImpl->mModel->mScrollPosition                = Vector2::ZERO;
 -    mImpl->mEventData->mScrollAfterUpdatePosition = true;
 -  }
 +  return mImpl->mEventData ? mImpl->mEventData->mPrimaryCursorPosition : 0;
  }
  
  void Controller::SetControlInterface(ControlInterface* controlInterface)
@@@ -482,6 -482,27 +482,27 @@@ public: // Configure the text controlle
    Vector2 GetTextFitContentSize() const;
  
    /**
+    * @brief Retrieve the fited point size.
+    *
+    * @return The fited point size.
+    */
+   float GetTextFitPointSize() const;
+   /**
+    * @brief Sets whether the text fit properties have changed.
+    *
+    * @param[in] changed Whether to changed the text fit.
+    */
+   void SetTextFitChanged(bool changed);
+   /**
+    * @brief Whether the text fit properties are changed or not.
+    *
+    * @return True if the text fit properties are changed
+    */
+   bool IsTextFitChanged() const;
+   /**
     * @brief Enable or disable the placeholder text elide.
     * @param enabled Whether to enable the placeholder text elide.
     */
@@@ -1881,6 -1902,26 +1902,6 @@@ private: // Helpers
     */
    void ShowPlaceholderText();
  
 -  /**
 -   * @brief Helper to clear font-specific data (only).
 -   */
 -  void ClearFontData();
 -
 -  /**
 -   * @brief Helper to clear text's style data.
 -   */
 -  void ClearStyleData();
 -
 -  /**
 -   * @brief Used to reset the scroll position after setting a new text.
 -   */
 -  void ResetScrollPosition();
 -
 -  /**
 -   * @brief fill needed relayout parameters when line size is changed & request relayout.
 -   */
 -  void RelayoutForNewLineSize();
 -
  private: // Private contructors & copy operator.
    /**
     * @brief Private constructor.
@@@ -1921,7 -1962,6 +1942,7 @@@ public
  private:
    struct EventHandler;
    struct InputFontHandler;
 +  struct InputProperties;
    struct PlaceholderHandler;
    struct Relayouter;
    struct TextUpdater;