(TextController/ScrollView) Reduced LOC 50/266850/5
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 19 Nov 2021 12:20:32 +0000 (12:20 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 19 Nov 2021 17:00:32 +0000 (17:00 +0000)
 - TextController - Moved some methods to the Impl class
 - TextControllerImpl - Moved a lot of functionality outside of the class
 - ScrollView - Added a class which handles the properties

Change-Id: I69127a9bc3dbd3e892f1fe0019cac9ad41fc2f3e

13 files changed:
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h [new file with mode: 0644]
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp
dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h
dali-toolkit/internal/file.list
dali-toolkit/internal/text/text-controller-impl-data-clearer.cpp [new file with mode: 0644]
dali-toolkit/internal/text/text-controller-impl-data-clearer.h [new file with mode: 0644]
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller-relayouter.cpp
dali-toolkit/internal/text/text-controller-text-updater.cpp
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h

diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp
new file mode 100644 (file)
index 0000000..9c1272c
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2021 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 <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
+#include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h>
+
+namespace Dali::Toolkit::Internal
+{
+
+void ScrollViewPropertyHandler::Set(BaseObject* object, Property::Index index, const Property::Value& value)
+{
+  Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object));
+
+  if(scrollView)
+  {
+    ScrollView& scrollViewImpl(GetImpl(scrollView));
+    switch(index)
+    {
+      case Toolkit::ScrollView::Property::WRAP_ENABLED:
+      {
+        scrollViewImpl.SetWrapMode(value.Get<bool>());
+        break;
+      }
+      case Toolkit::ScrollView::Property::PANNING_ENABLED:
+      {
+        scrollViewImpl.SetScrollSensitive(value.Get<bool>());
+        break;
+      }
+      case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
+      {
+        scrollViewImpl.SetAxisAutoLock(value.Get<bool>());
+        break;
+      }
+      case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        scrollViewImpl.SetWheelScrollDistanceStep(value.Get<Vector2>());
+        break;
+      }
+      case Toolkit::ScrollView::Property::SCROLL_MODE:
+      {
+        const Property::Map* map = value.GetMap();
+        if(map)
+        {
+          SetScrollMode(scrollViewImpl, *map);
+        }
+      }
+    }
+  }
+}
+
+Property::Value ScrollViewPropertyHandler::Get(BaseObject* object, Property::Index index)
+{
+  Property::Value value;
+
+  Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object));
+
+  if(scrollView)
+  {
+    ScrollView& scrollViewImpl(GetImpl(scrollView));
+    switch(index)
+    {
+      case Toolkit::ScrollView::Property::WRAP_ENABLED:
+      {
+        value = scrollViewImpl.GetWrapMode();
+        break;
+      }
+      case Toolkit::ScrollView::Property::PANNING_ENABLED:
+      {
+        value = scrollViewImpl.GetScrollSensitive();
+        break;
+      }
+      case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
+      {
+        value = scrollViewImpl.GetAxisAutoLock();
+        break;
+      }
+      case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
+      {
+        value = scrollViewImpl.GetWheelScrollDistanceStep();
+        break;
+      }
+    }
+  }
+
+  return value;
+}
+
+void ScrollViewPropertyHandler::SetScrollMode(ScrollView& scrollView, const Property::Map& scrollModeMap)
+{
+  Toolkit::RulerPtr rulerX, rulerY;
+
+  // Check the scroll mode in the X axis
+  bool             xAxisScrollEnabled = true;
+  Property::Value* valuePtr           = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_ENABLED, "xAxisScrollEnabled");
+  if(valuePtr && valuePtr->GetType() == Property::BOOLEAN)
+  {
+    valuePtr->Get(xAxisScrollEnabled);
+  }
+
+  if(!xAxisScrollEnabled)
+  {
+    // Default ruler and disabled
+    rulerX = new Toolkit::DefaultRuler();
+    rulerX->Disable();
+  }
+  else
+  {
+    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SNAP_TO_INTERVAL, "xAxisSnapToInterval");
+    float xAxisSnapToInterval = 0.0f;
+    if(valuePtr && valuePtr->Get(xAxisSnapToInterval))
+    {
+      // Fixed ruler and enabled
+      rulerX = new Toolkit::FixedRuler(xAxisSnapToInterval);
+    }
+    else
+    {
+      // Default ruler and enabled
+      rulerX = new Toolkit::DefaultRuler();
+    }
+
+    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_BOUNDARY, "xAxisScrollBoundary");
+    float xAxisScrollBoundary = 0.0f;
+    if(valuePtr && valuePtr->Get(xAxisScrollBoundary))
+    {
+      // By default ruler domain is disabled unless set
+      rulerX->SetDomain(Toolkit::RulerDomain(0, xAxisScrollBoundary, true));
+    }
+  }
+
+  // Check the scroll mode in the Y axis
+  bool yAxisScrollEnabled = true;
+  valuePtr                = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_ENABLED, "yAxisScrollEnabled");
+  if(valuePtr && valuePtr->GetType() == Property::BOOLEAN)
+  {
+    valuePtr->Get(yAxisScrollEnabled);
+  }
+
+  if(!yAxisScrollEnabled)
+  {
+    // Default ruler and disabled
+    rulerY = new Toolkit::DefaultRuler();
+    rulerY->Disable();
+  }
+  else
+  {
+    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SNAP_TO_INTERVAL, "yAxisSnapToInterval");
+    float yAxisSnapToInterval = 0.0f;
+    if(valuePtr && valuePtr->Get(yAxisSnapToInterval))
+    {
+      // Fixed ruler and enabled
+      rulerY = new Toolkit::FixedRuler(yAxisSnapToInterval);
+    }
+    else
+    {
+      // Default ruler and enabled
+      rulerY = new Toolkit::DefaultRuler();
+    }
+
+    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_BOUNDARY, "yAxisScrollBoundary");
+    float yAxisScrollBoundary = 0.0f;
+    if(valuePtr && valuePtr->Get(yAxisScrollBoundary))
+    {
+      // By default ruler domain is disabled unless set
+      rulerY->SetDomain(Toolkit::RulerDomain(0, yAxisScrollBoundary, true));
+    }
+  }
+
+  scrollView.SetRulerX(rulerX);
+  scrollView.SetRulerY(rulerY);
+}
+
+void ScrollViewPropertyHandler::UpdatePropertyDomain(ScrollView& scrollView)
+{
+  Actor   self                  = scrollView.Self();
+  Vector3 size                  = self.GetTargetSize();
+  Vector2 min                   = scrollView.mMinScroll;
+  Vector2 max                   = scrollView.mMaxScroll;
+  bool    scrollPositionChanged = false;
+  bool    domainChanged         = false;
+
+  bool canScrollVertical   = false;
+  bool canScrollHorizontal = false;
+  scrollView.UpdateLocalScrollProperties();
+  if(scrollView.mRulerX->IsEnabled())
+  {
+    const Toolkit::RulerDomain& rulerDomain = scrollView.mRulerX->GetDomain();
+    if(fabsf(min.x - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.x - rulerDomain.max) > Math::MACHINE_EPSILON_100)
+    {
+      domainChanged = true;
+      min.x         = rulerDomain.min;
+      max.x         = rulerDomain.max;
+
+      // make sure new scroll value is within new domain
+      if(scrollView.mScrollPrePosition.x < min.x || scrollView.mScrollPrePosition.x > max.x)
+      {
+        scrollPositionChanged = true;
+        scrollView.mScrollPrePosition.x  = Clamp(scrollView.mScrollPrePosition.x, -(max.x - size.x), -min.x);
+      }
+    }
+    if((fabsf(rulerDomain.max - rulerDomain.min) - size.x) > Math::MACHINE_EPSILON_100)
+    {
+      canScrollHorizontal = true;
+    }
+  }
+  else if(fabs(min.x) > Math::MACHINE_EPSILON_100 || fabs(max.x) > Math::MACHINE_EPSILON_100)
+  {
+    // need to reset to 0
+    domainChanged       = true;
+    min.x               = 0.0f;
+    max.x               = 0.0f;
+    canScrollHorizontal = false;
+  }
+
+  if(scrollView.mRulerY->IsEnabled())
+  {
+    const Toolkit::RulerDomain& rulerDomain = scrollView.mRulerY->GetDomain();
+    if(fabsf(min.y - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.y - rulerDomain.max) > Math::MACHINE_EPSILON_100)
+    {
+      domainChanged = true;
+      min.y         = rulerDomain.min;
+      max.y         = rulerDomain.max;
+
+      // make sure new scroll value is within new domain
+      if(scrollView.mScrollPrePosition.y < min.y || scrollView.mScrollPrePosition.y > max.y)
+      {
+        scrollPositionChanged = true;
+        scrollView.mScrollPrePosition.y  = Clamp(scrollView.mScrollPrePosition.y, -(max.y - size.y), -min.y);
+      }
+    }
+    if((fabsf(rulerDomain.max - rulerDomain.min) - size.y) > Math::MACHINE_EPSILON_100)
+    {
+      canScrollVertical = true;
+    }
+  }
+  else if(fabs(min.y) > Math::MACHINE_EPSILON_100 || fabs(max.y) > Math::MACHINE_EPSILON_100)
+  {
+    // need to reset to 0
+    domainChanged     = true;
+    min.y             = 0.0f;
+    max.y             = 0.0f;
+    canScrollVertical = false;
+  }
+
+  // avoid setting properties if possible, otherwise this will cause an entire update as well as triggering constraints using each property we update
+  if(scrollView.mCanScrollVertical != canScrollVertical)
+  {
+    scrollView.mCanScrollVertical = canScrollVertical;
+    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, canScrollVertical);
+  }
+  if(scrollView.mCanScrollHorizontal != canScrollHorizontal)
+  {
+    scrollView.mCanScrollHorizontal = canScrollHorizontal;
+    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, canScrollHorizontal);
+  }
+  if(scrollPositionChanged)
+  {
+    self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, scrollView.mScrollPrePosition);
+  }
+  if(domainChanged)
+  {
+    scrollView.mMinScroll = min;
+    scrollView.mMaxScroll = max;
+    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, scrollView.mMinScroll);
+    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, scrollView.mMaxScroll);
+  }
+}
+
+} // namespace Dali::Toolkit::Internal
diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h
new file mode 100644 (file)
index 0000000..1923cfc
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_IMPL_PROPERTY_HANDLER_H
+#define DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_IMPL_PROPERTY_HANDLER_H
+
+/*
+ * Copyright (c) 2021 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/property.h>
+
+namespace Dali::Toolkit::Internal
+{
+class ScrollView;
+
+/// Handles the properties in scroll view calling the appropriate scroll view methods
+struct ScrollViewPropertyHandler
+{
+  /**
+   * @brief Sets the property on the given scroll-view object.
+   *
+   * @param object The scrollview object
+   * @param index The index to set
+   * @param value The value to set
+   */
+  static void Set(BaseObject* object, Property::Index index, const Property::Value& value);
+
+  /**
+   * @brief Retrieves the value of a scroll-view property.
+   *
+   * @param object The scrollview object
+   * @param index The index whose value is to be retrieved
+   * @return
+   */
+  static Property::Value Get(BaseObject* object, Property::Index index);
+
+  /**
+   * Set up default rulers using a property map
+   * @param[in] scrollView    The scroll view to apply this on
+   * @param[in] scrollModeMap A map defining the characteristics of X and Y scrolling
+   * using either FixedRuler or DefaultRuler.
+   */
+  static void SetScrollMode(ScrollView& scrollView, const Property::Map& scrollModeMap);
+
+  /**
+   * This is called whenever the Scroll Rulers are modified.
+   *
+   * This will update the properties: 'scrollPositionMin' * and 'scrollPositionMax' to reflect the changes.
+   * @param scrollView The Scroll View to modify
+   */
+  static void UpdatePropertyDomain(ScrollView& scrollView);
+};
+
+} // namespace Dali::Toolkit::Internal
+
+#endif // DALI_TOOLKIT_INTERNAL_SCROLL_VIEW_IMPL_PROPERTY_HANDLER_H
index 86cfc56..712cb17 100644 (file)
@@ -36,6 +36,7 @@
 #include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.h>
 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
+#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl-property-handler.h>
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-mode.h>
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view-constraints.h>
 #include <dali-toolkit/public-api/controls/scrollable/scroll-view/scroll-view.h>
@@ -673,7 +674,7 @@ void ScrollView::OnInitialize()
   self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, mCanScrollVertical);
   self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, mCanScrollHorizontal);
 
-  UpdatePropertyDomain();
+  ScrollViewPropertyHandler::UpdatePropertyDomain(*this);
   mConstraints.SetInternalConstraints(*this);
 
   // Connect wheel event
@@ -794,7 +795,7 @@ void ScrollView::SetRulerX(RulerPtr ruler)
 {
   mRulerX = ruler;
 
-  UpdatePropertyDomain();
+  ScrollViewPropertyHandler::UpdatePropertyDomain(*this);
   mConstraints.UpdateMainInternalConstraint(*this);
 }
 
@@ -802,107 +803,10 @@ void ScrollView::SetRulerY(RulerPtr ruler)
 {
   mRulerY = ruler;
 
-  UpdatePropertyDomain();
+  ScrollViewPropertyHandler::UpdatePropertyDomain(*this);
   mConstraints.UpdateMainInternalConstraint(*this);
 }
 
-void ScrollView::UpdatePropertyDomain()
-{
-  Actor   self                  = Self();
-  Vector3 size                  = self.GetTargetSize();
-  Vector2 min                   = mMinScroll;
-  Vector2 max                   = mMaxScroll;
-  bool    scrollPositionChanged = false;
-  bool    domainChanged         = false;
-
-  bool canScrollVertical   = false;
-  bool canScrollHorizontal = false;
-  UpdateLocalScrollProperties();
-  if(mRulerX->IsEnabled())
-  {
-    const Toolkit::RulerDomain& rulerDomain = mRulerX->GetDomain();
-    if(fabsf(min.x - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.x - rulerDomain.max) > Math::MACHINE_EPSILON_100)
-    {
-      domainChanged = true;
-      min.x         = rulerDomain.min;
-      max.x         = rulerDomain.max;
-
-      // make sure new scroll value is within new domain
-      if(mScrollPrePosition.x < min.x || mScrollPrePosition.x > max.x)
-      {
-        scrollPositionChanged = true;
-        mScrollPrePosition.x  = Clamp(mScrollPrePosition.x, -(max.x - size.x), -min.x);
-      }
-    }
-    if((fabsf(rulerDomain.max - rulerDomain.min) - size.x) > Math::MACHINE_EPSILON_100)
-    {
-      canScrollHorizontal = true;
-    }
-  }
-  else if(fabs(min.x) > Math::MACHINE_EPSILON_100 || fabs(max.x) > Math::MACHINE_EPSILON_100)
-  {
-    // need to reset to 0
-    domainChanged       = true;
-    min.x               = 0.0f;
-    max.x               = 0.0f;
-    canScrollHorizontal = false;
-  }
-
-  if(mRulerY->IsEnabled())
-  {
-    const Toolkit::RulerDomain& rulerDomain = mRulerY->GetDomain();
-    if(fabsf(min.y - rulerDomain.min) > Math::MACHINE_EPSILON_100 || fabsf(max.y - rulerDomain.max) > Math::MACHINE_EPSILON_100)
-    {
-      domainChanged = true;
-      min.y         = rulerDomain.min;
-      max.y         = rulerDomain.max;
-
-      // make sure new scroll value is within new domain
-      if(mScrollPrePosition.y < min.y || mScrollPrePosition.y > max.y)
-      {
-        scrollPositionChanged = true;
-        mScrollPrePosition.y  = Clamp(mScrollPrePosition.y, -(max.y - size.y), -min.y);
-      }
-    }
-    if((fabsf(rulerDomain.max - rulerDomain.min) - size.y) > Math::MACHINE_EPSILON_100)
-    {
-      canScrollVertical = true;
-    }
-  }
-  else if(fabs(min.y) > Math::MACHINE_EPSILON_100 || fabs(max.y) > Math::MACHINE_EPSILON_100)
-  {
-    // need to reset to 0
-    domainChanged     = true;
-    min.y             = 0.0f;
-    max.y             = 0.0f;
-    canScrollVertical = false;
-  }
-
-  // avoid setting properties if possible, otherwise this will cause an entire update as well as triggering constraints using each property we update
-  if(mCanScrollVertical != canScrollVertical)
-  {
-    mCanScrollVertical = canScrollVertical;
-    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, canScrollVertical);
-  }
-  if(mCanScrollHorizontal != canScrollHorizontal)
-  {
-    mCanScrollHorizontal = canScrollHorizontal;
-    self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, canScrollHorizontal);
-  }
-  if(scrollPositionChanged)
-  {
-    DALI_LOG_SCROLL_STATE("[0x%X] Domain Changed, setting SCROLL_PRE_POSITION To[%.2f, %.2f]", this, mScrollPrePosition.x, mScrollPrePosition.y);
-    self.SetProperty(Toolkit::ScrollView::Property::SCROLL_PRE_POSITION, mScrollPrePosition);
-  }
-  if(domainChanged)
-  {
-    mMinScroll = min;
-    mMaxScroll = max;
-    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, mMinScroll);
-    self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, mMaxScroll);
-  }
-}
-
 void ScrollView::SetScrollSensitive(bool sensitive)
 {
   Actor              self = Self();
@@ -1482,7 +1386,7 @@ bool ScrollView::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface*
 void ScrollView::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
 {
   // need to update domain properties for new size
-  UpdatePropertyDomain();
+  ScrollViewPropertyHandler::UpdatePropertyDomain(*this);
 }
 
 void ScrollView::OnSizeSet(const Vector3& size)
@@ -1497,7 +1401,7 @@ void ScrollView::OnSizeSet(const Vector3& size)
       mMaxOvershoot = mUserMaxOvershoot;
     }
   }
-  UpdatePropertyDomain();
+  ScrollViewPropertyHandler::UpdatePropertyDomain(*this);
   mConstraints.UpdateMainInternalConstraint(*this);
   if(IsOvershootEnabled())
   {
@@ -2180,45 +2084,6 @@ void ScrollView::FinishTransform()
   }
 }
 
-Vector2 ScrollView::GetOvershoot(Vector2& position) const
-{
-  Vector3 size = Self().GetCurrentProperty<Vector3>(Actor::Property::SIZE);
-  Vector2 overshoot;
-
-  const RulerDomain rulerDomainX = mRulerX->GetDomain();
-  const RulerDomain rulerDomainY = mRulerY->GetDomain();
-
-  if(mRulerX->IsEnabled() && rulerDomainX.enabled)
-  {
-    const float left  = rulerDomainX.min - position.x;
-    const float right = size.width - rulerDomainX.max - position.x;
-    if(left < 0)
-    {
-      overshoot.x = left;
-    }
-    else if(right > 0)
-    {
-      overshoot.x = right;
-    }
-  }
-
-  if(mRulerY->IsEnabled() && rulerDomainY.enabled)
-  {
-    const float top    = rulerDomainY.min - position.y;
-    const float bottom = size.height - rulerDomainY.max - position.y;
-    if(top < 0)
-    {
-      overshoot.y = top;
-    }
-    else if(bottom > 0)
-    {
-      overshoot.y = bottom;
-    }
-  }
-
-  return overshoot;
-}
-
 bool ScrollView::OnAccessibilityPan(PanGesture gesture)
 {
   // Keep track of whether this is an AccessibilityPan
@@ -2263,164 +2128,12 @@ void ScrollView::WrapPosition(Vector2& position) const
 
 void ScrollView::SetProperty(BaseObject* object, Property::Index index, const Property::Value& value)
 {
-  Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object));
-
-  if(scrollView)
-  {
-    ScrollView& scrollViewImpl(GetImpl(scrollView));
-    switch(index)
-    {
-      case Toolkit::ScrollView::Property::WRAP_ENABLED:
-      {
-        scrollViewImpl.SetWrapMode(value.Get<bool>());
-        break;
-      }
-      case Toolkit::ScrollView::Property::PANNING_ENABLED:
-      {
-        scrollViewImpl.SetScrollSensitive(value.Get<bool>());
-        break;
-      }
-      case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
-      {
-        scrollViewImpl.SetAxisAutoLock(value.Get<bool>());
-        break;
-      }
-      case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
-      {
-        scrollViewImpl.SetWheelScrollDistanceStep(value.Get<Vector2>());
-        break;
-      }
-      case Toolkit::ScrollView::Property::SCROLL_MODE:
-      {
-        const Property::Map* map = value.GetMap();
-        if(map)
-        {
-          scrollViewImpl.SetScrollMode(*map);
-        }
-      }
-    }
-  }
+  ScrollViewPropertyHandler::Set(object, index, value);
 }
 
 Property::Value ScrollView::GetProperty(BaseObject* object, Property::Index index)
 {
-  Property::Value value;
-
-  Toolkit::ScrollView scrollView = Toolkit::ScrollView::DownCast(Dali::BaseHandle(object));
-
-  if(scrollView)
-  {
-    ScrollView& scrollViewImpl(GetImpl(scrollView));
-    switch(index)
-    {
-      case Toolkit::ScrollView::Property::WRAP_ENABLED:
-      {
-        value = scrollViewImpl.GetWrapMode();
-        break;
-      }
-      case Toolkit::ScrollView::Property::PANNING_ENABLED:
-      {
-        value = scrollViewImpl.GetScrollSensitive();
-        break;
-      }
-      case Toolkit::ScrollView::Property::AXIS_AUTO_LOCK_ENABLED:
-      {
-        value = scrollViewImpl.GetAxisAutoLock();
-        break;
-      }
-      case Toolkit::ScrollView::Property::WHEEL_SCROLL_DISTANCE_STEP:
-      {
-        value = scrollViewImpl.GetWheelScrollDistanceStep();
-        break;
-      }
-    }
-  }
-
-  return value;
-}
-
-void ScrollView::SetScrollMode(const Property::Map& scrollModeMap)
-{
-  Toolkit::RulerPtr rulerX, rulerY;
-
-  // Check the scroll mode in the X axis
-  bool             xAxisScrollEnabled = true;
-  Property::Value* valuePtr           = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_ENABLED, "xAxisScrollEnabled");
-  if(valuePtr && valuePtr->GetType() == Property::BOOLEAN)
-  {
-    valuePtr->Get(xAxisScrollEnabled);
-  }
-
-  if(!xAxisScrollEnabled)
-  {
-    // Default ruler and disabled
-    rulerX = new Toolkit::DefaultRuler();
-    rulerX->Disable();
-  }
-  else
-  {
-    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SNAP_TO_INTERVAL, "xAxisSnapToInterval");
-    float xAxisSnapToInterval = 0.0f;
-    if(valuePtr && valuePtr->Get(xAxisSnapToInterval))
-    {
-      // Fixed ruler and enabled
-      rulerX = new Toolkit::FixedRuler(xAxisSnapToInterval);
-    }
-    else
-    {
-      // Default ruler and enabled
-      rulerX = new Toolkit::DefaultRuler();
-    }
-
-    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::X_AXIS_SCROLL_BOUNDARY, "xAxisScrollBoundary");
-    float xAxisScrollBoundary = 0.0f;
-    if(valuePtr && valuePtr->Get(xAxisScrollBoundary))
-    {
-      // By default ruler domain is disabled unless set
-      rulerX->SetDomain(Toolkit::RulerDomain(0, xAxisScrollBoundary, true));
-    }
-  }
-
-  // Check the scroll mode in the Y axis
-  bool yAxisScrollEnabled = true;
-  valuePtr                = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_ENABLED, "yAxisScrollEnabled");
-  if(valuePtr && valuePtr->GetType() == Property::BOOLEAN)
-  {
-    valuePtr->Get(yAxisScrollEnabled);
-  }
-
-  if(!yAxisScrollEnabled)
-  {
-    // Default ruler and disabled
-    rulerY = new Toolkit::DefaultRuler();
-    rulerY->Disable();
-  }
-  else
-  {
-    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SNAP_TO_INTERVAL, "yAxisSnapToInterval");
-    float yAxisSnapToInterval = 0.0f;
-    if(valuePtr && valuePtr->Get(yAxisSnapToInterval))
-    {
-      // Fixed ruler and enabled
-      rulerY = new Toolkit::FixedRuler(yAxisSnapToInterval);
-    }
-    else
-    {
-      // Default ruler and enabled
-      rulerY = new Toolkit::DefaultRuler();
-    }
-
-    valuePtr                  = scrollModeMap.Find(Toolkit::ScrollMode::Y_AXIS_SCROLL_BOUNDARY, "yAxisScrollBoundary");
-    float yAxisScrollBoundary = 0.0f;
-    if(valuePtr && valuePtr->Get(yAxisScrollBoundary))
-    {
-      // By default ruler domain is disabled unless set
-      rulerY->SetDomain(Toolkit::RulerDomain(0, yAxisScrollBoundary, true));
-    }
-  }
-
-  SetRulerX(rulerX);
-  SetRulerY(rulerY);
+  return ScrollViewPropertyHandler::Get(object, index);
 }
 
 ScrollView::LockAxis GetLockAxis(const Vector2& panDelta, ScrollView::LockAxis currentLockAxis, float lockGradient)
index 4d871a7..4061727 100644 (file)
@@ -47,6 +47,8 @@ typedef IntrusivePtr<ScrollInternalConstraints> ScrollInternalConstraintsPtr;
 class ScrollOvershootIndicator;
 typedef IntrusivePtr<ScrollOvershootIndicator> ScrollOvershootIndicatorPtr;
 
+class ScrollViewPropertyHandler;
+
 /**
  * @copydoc Toolkit::ScrollView
  */
@@ -774,13 +776,6 @@ private:
   void SnapInternalYTo(float position);
 
   /**
-   * This is called internally whenever the Scroll Rulers are
-   * modified. This will update the properties: 'scrollPositionMin'
-   * and 'scrollPositionMax' to reflect the changes.
-   */
-  void UpdatePropertyDomain();
-
-  /**
    * Called when the gesture starts.
    */
   void GestureStarted();
@@ -821,20 +816,6 @@ private:
   void FinishTransform();
 
   /**
-   * Returns overshoot vector based on current position
-   *
-   * Overshoot vector is defined as how far outside of bounds
-   * the viewport is trying to view (prior to being clamped).
-   *
-   * an overshoot of (100,50), means user is in bottom right corner,
-   * trying to pan +100 to the right, and +50 below. This can be used
-   * to determine an effect, such as stretching.
-   *
-   * @param[in] position The position for which you wish to obtain overshoot vector
-   */
-  Vector2 GetOvershoot(Vector2& position) const;
-
-  /**
    * Clamps position within the domain set up by X/Y Rulers
    *
    * @param[in,out] position The position you wish to clamp
@@ -924,13 +905,6 @@ private:
    */
   void OnScrollUpdateNotification(Dali::PropertyNotification& source);
 
-  /**
-   * Set up default rulers using a property map
-   * @param[in] scrollModeMap A map defining the characteristics of X and Y scrolling
-   * using either FixedRuler or DefaultRuler.
-   */
-  void SetScrollMode(const Property::Map& scrollModeMap);
-
 private:
   // Undefined
   ScrollView(const ScrollView&);
@@ -1020,6 +994,7 @@ private:
   bool mTransientScrollBar : 1;         ///< True if scroll-bar should be automatically show/hidden during/after panning
 
   friend ScrollViewConstraints;
+  friend ScrollViewPropertyHandler;
 };
 
 /**
index 591915d..855df54 100644 (file)
@@ -93,6 +93,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-effect-impl.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl-constraints.cpp
+   ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-impl-property-handler.cpp
    ${toolkit_src_dir}/controls/scrollable/scroll-view/scroll-view-page-path-effect-impl.cpp
    ${toolkit_src_dir}/controls/scene3d-view/scene3d-view-impl.cpp
    ${toolkit_src_dir}/controls/scene3d-view/gltf-loader.cpp
@@ -158,6 +159,7 @@ SET( toolkit_src_files
    ${toolkit_src_dir}/text/text-controller.cpp
    ${toolkit_src_dir}/text/text-controller-event-handler.cpp
    ${toolkit_src_dir}/text/text-controller-impl.cpp
+   ${toolkit_src_dir}/text/text-controller-impl-data-clearer.cpp
    ${toolkit_src_dir}/text/text-controller-impl-event-handler.cpp
    ${toolkit_src_dir}/text/text-controller-impl-model-updater.cpp
    ${toolkit_src_dir}/text/text-controller-input-font-handler.cpp
diff --git a/dali-toolkit/internal/text/text-controller-impl-data-clearer.cpp b/dali-toolkit/internal/text/text-controller-impl-data-clearer.cpp
new file mode 100644 (file)
index 0000000..87099da
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2021 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 <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-controller-impl.h>
+#include <dali-toolkit/internal/text/text-run-container.h>
+
+namespace Dali::Toolkit::Text
+{
+
+void ControllerImplDataClearer::ClearFullModelData(Controller::Impl& impl, Controller::OperationsMask operations)
+{
+  ModelPtr& model = impl.mModel;
+
+  if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
+  {
+    model->mLogicalModel->mLineBreakInfo.Clear();
+    model->mLogicalModel->mParagraphInfo.Clear();
+  }
+
+  if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations))
+  {
+    model->mLogicalModel->mScriptRuns.Clear();
+  }
+
+  if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations))
+  {
+    model->mLogicalModel->mFontRuns.Clear();
+  }
+
+  if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count())
+  {
+    if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
+    {
+      model->mLogicalModel->mBidirectionalParagraphInfo.Clear();
+      model->mLogicalModel->mCharacterDirections.Clear();
+    }
+
+    if(Controller::NO_OPERATION != (Controller::REORDER & operations))
+    {
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for(Vector<BidirectionalLineInfoRun>::Iterator it    = model->mLogicalModel->mBidirectionalLineInfo.Begin(),
+                                                     endIt = model->mLogicalModel->mBidirectionalLineInfo.End();
+          it != endIt;
+          ++it)
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free(bidiLineInfo.visualToLogicalMap);
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+      model->mLogicalModel->mBidirectionalLineInfo.Clear();
+    }
+  }
+
+  if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
+  {
+    model->mVisualModel->mGlyphs.Clear();
+    model->mVisualModel->mGlyphsToCharacters.Clear();
+    model->mVisualModel->mCharactersToGlyph.Clear();
+    model->mVisualModel->mCharactersPerGlyph.Clear();
+    model->mVisualModel->mGlyphsPerCharacter.Clear();
+    model->mVisualModel->mGlyphPositions.Clear();
+  }
+
+  if(Controller::NO_OPERATION != (Controller::LAYOUT & operations))
+  {
+    model->mVisualModel->mLines.Clear();
+  }
+
+  if(Controller::NO_OPERATION != (Controller::COLOR & operations))
+  {
+    model->mVisualModel->mColorIndices.Clear();
+    model->mVisualModel->mBackgroundColorIndices.Clear();
+  }
+}
+
+void ControllerImplDataClearer::ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
+{
+  const CharacterIndex endIndexPlusOne = endIndex + 1u;
+  ModelPtr& model = impl.mModel;
+
+  if(Controller::NO_OPERATION != (Controller::GET_LINE_BREAKS & operations))
+  {
+    // Clear the line break info.
+    LineBreakInfo* lineBreakInfoBuffer = model->mLogicalModel->mLineBreakInfo.Begin();
+
+    model->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex,
+                                                     lineBreakInfoBuffer + endIndexPlusOne);
+
+    // Clear the paragraphs.
+    ClearCharacterRuns(startIndex,
+                       endIndex,
+                       model->mLogicalModel->mParagraphInfo);
+  }
+
+  if(Controller::NO_OPERATION != (Controller::GET_SCRIPTS & operations))
+  {
+    // Clear the scripts.
+    ClearCharacterRuns(startIndex,
+                       endIndex,
+                       model->mLogicalModel->mScriptRuns);
+  }
+
+  if(Controller::NO_OPERATION != (Controller::VALIDATE_FONTS & operations))
+  {
+    // Clear the fonts.
+    ClearCharacterRuns(startIndex,
+                       endIndex,
+                       model->mLogicalModel->mFontRuns);
+  }
+
+  if(0u != model->mLogicalModel->mBidirectionalParagraphInfo.Count())
+  {
+    if(Controller::NO_OPERATION != (Controller::BIDI_INFO & operations))
+    {
+      // Clear the bidirectional paragraph info.
+      ClearCharacterRuns(startIndex,
+                         endIndex,
+                         model->mLogicalModel->mBidirectionalParagraphInfo);
+
+      // Clear the character's directions.
+      CharacterDirection* characterDirectionsBuffer = model->mLogicalModel->mCharacterDirections.Begin();
+
+      model->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex,
+                                                       characterDirectionsBuffer + endIndexPlusOne);
+    }
+
+    if(Controller::NO_OPERATION != (Controller::REORDER & operations))
+    {
+      uint32_t startRemoveIndex = model->mLogicalModel->mBidirectionalLineInfo.Count();
+      uint32_t endRemoveIndex   = startRemoveIndex;
+      ClearCharacterRuns(startIndex,
+                         endIndex,
+                         model->mLogicalModel->mBidirectionalLineInfo,
+                         startRemoveIndex,
+                         endRemoveIndex);
+
+      BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = model->mLogicalModel->mBidirectionalLineInfo.Begin();
+
+      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+      for(Vector<BidirectionalLineInfoRun>::Iterator it    = bidirectionalLineInfoBuffer + startRemoveIndex,
+                                                     endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
+          it != endIt;
+          ++it)
+      {
+        BidirectionalLineInfoRun& bidiLineInfo = *it;
+
+        free(bidiLineInfo.visualToLogicalMap);
+        bidiLineInfo.visualToLogicalMap = NULL;
+      }
+
+      model->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex,
+                                                         bidirectionalLineInfoBuffer + endRemoveIndex);
+    }
+  }
+}
+
+void ControllerImplDataClearer::ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
+{
+  const CharacterIndex endIndexPlusOne           = endIndex + 1u;
+  const Length         numberOfCharactersRemoved = endIndexPlusOne - startIndex;
+  ModelPtr&            model                     = impl.mModel;
+  TextUpdateInfo&      textUpdateInfo            = impl.mTextUpdateInfo;
+
+
+  // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
+  GlyphIndex* charactersToGlyphBuffer  = model->mVisualModel->mCharactersToGlyph.Begin();
+  Length*     glyphsPerCharacterBuffer = model->mVisualModel->mGlyphsPerCharacter.Begin();
+
+  const GlyphIndex endGlyphIndexPlusOne  = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex);
+  const Length     numberOfGlyphsRemoved = endGlyphIndexPlusOne - textUpdateInfo.mStartGlyphIndex;
+
+  if(Controller::NO_OPERATION != (Controller::SHAPE_TEXT & operations))
+  {
+    // Update the character to glyph indices.
+    for(Vector<GlyphIndex>::Iterator it    = charactersToGlyphBuffer + endIndexPlusOne,
+                                     endIt = charactersToGlyphBuffer + model->mVisualModel->mCharactersToGlyph.Count();
+        it != endIt;
+        ++it)
+    {
+      CharacterIndex& index = *it;
+      index -= numberOfGlyphsRemoved;
+    }
+
+    // Clear the character to glyph conversion table.
+    model->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex,
+                                                  charactersToGlyphBuffer + endIndexPlusOne);
+
+    // Clear the glyphs per character table.
+    model->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex,
+                                                   glyphsPerCharacterBuffer + endIndexPlusOne);
+
+    // Clear the glyphs buffer.
+    GlyphInfo* glyphsBuffer = model->mVisualModel->mGlyphs.Begin();
+    model->mVisualModel->mGlyphs.Erase(glyphsBuffer + textUpdateInfo.mStartGlyphIndex,
+                                       glyphsBuffer + endGlyphIndexPlusOne);
+
+    CharacterIndex* glyphsToCharactersBuffer = model->mVisualModel->mGlyphsToCharacters.Begin();
+
+    // Update the glyph to character indices.
+    for(Vector<CharacterIndex>::Iterator it    = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
+                                         endIt = glyphsToCharactersBuffer + model->mVisualModel->mGlyphsToCharacters.Count();
+        it != endIt;
+        ++it)
+    {
+      CharacterIndex& index = *it;
+      index -= numberOfCharactersRemoved;
+    }
+
+    // Clear the glyphs to characters buffer.
+    model->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + textUpdateInfo.mStartGlyphIndex,
+                                                   glyphsToCharactersBuffer + endGlyphIndexPlusOne);
+
+    // Clear the characters per glyph buffer.
+    Length* charactersPerGlyphBuffer = model->mVisualModel->mCharactersPerGlyph.Begin();
+    model->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + textUpdateInfo.mStartGlyphIndex,
+                                                   charactersPerGlyphBuffer + endGlyphIndexPlusOne);
+
+    // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout
+    if(0u != model->mVisualModel->mGlyphPositions.Count())
+    {
+      // Clear the positions buffer.
+      Vector2* positionsBuffer = model->mVisualModel->mGlyphPositions.Begin();
+      model->mVisualModel->mGlyphPositions.Erase(positionsBuffer + textUpdateInfo.mStartGlyphIndex,
+                                                 positionsBuffer + endGlyphIndexPlusOne);
+    }
+  }
+
+  if(Controller::NO_OPERATION != (Controller::LAYOUT & operations))
+  {
+    // Clear the lines.
+    uint32_t startRemoveIndex = model->mVisualModel->mLines.Count();
+    uint32_t endRemoveIndex   = startRemoveIndex;
+    ClearCharacterRuns(startIndex,
+                       endIndex,
+                       model->mVisualModel->mLines,
+                       startRemoveIndex,
+                       endRemoveIndex);
+
+    // Will update the glyph runs.
+    startRemoveIndex = model->mVisualModel->mLines.Count();
+    endRemoveIndex   = startRemoveIndex;
+    ClearGlyphRuns(textUpdateInfo.mStartGlyphIndex,
+                   endGlyphIndexPlusOne - 1u,
+                   model->mVisualModel->mLines,
+                   startRemoveIndex,
+                   endRemoveIndex);
+
+    // Set the line index from where to insert the new laid-out lines.
+    textUpdateInfo.mStartLineIndex = startRemoveIndex;
+
+    LineRun* linesBuffer = model->mVisualModel->mLines.Begin();
+    model->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
+                                      linesBuffer + endRemoveIndex);
+  }
+
+  if(Controller::NO_OPERATION != (Controller::COLOR & operations))
+  {
+    if(0u != model->mVisualModel->mColorIndices.Count())
+    {
+      ColorIndex* colorIndexBuffer = model->mVisualModel->mColorIndices.Begin();
+      model->mVisualModel->mColorIndices.Erase(colorIndexBuffer + textUpdateInfo.mStartGlyphIndex,
+                                                colorIndexBuffer + endGlyphIndexPlusOne);
+    }
+
+    if(0u != model->mVisualModel->mBackgroundColorIndices.Count())
+    {
+      ColorIndex* backgroundColorIndexBuffer = model->mVisualModel->mBackgroundColorIndices.Begin();
+      model->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + textUpdateInfo.mStartGlyphIndex,
+                                                         backgroundColorIndexBuffer + endGlyphIndexPlusOne);
+    }
+  }
+}
+
+void ControllerImplDataClearer::ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations)
+{
+  TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
+
+  if(textUpdateInfo.mClearAll ||
+     ((0u == startIndex) &&
+      (textUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
+  {
+    ClearFullModelData(impl, operations);
+  }
+  else
+  {
+    // Clear the model data related with characters.
+    ClearCharacterModelData(impl, startIndex, endIndex, operations);
+
+    // Clear the model data related with glyphs.
+    ClearGlyphModelData(impl, startIndex, endIndex, operations);
+  }
+
+  ModelPtr& model = impl.mModel;
+
+  // The estimated number of lines. Used to avoid reallocations when layouting.
+  textUpdateInfo.mEstimatedNumberOfLines = std::max(model->mVisualModel->mLines.Count(), model->mLogicalModel->mParagraphInfo.Count());
+
+  model->mVisualModel->ClearCaches();
+}
+
+} // namespace Dali::Toolkit::Text
diff --git a/dali-toolkit/internal/text/text-controller-impl-data-clearer.h b/dali-toolkit/internal/text/text-controller-impl-data-clearer.h
new file mode 100644 (file)
index 0000000..87d6e24
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
+#define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
+
+/*
+ * Copyright (c) 2021 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/text-controller.h>
+
+namespace Dali::Toolkit::Text
+{
+
+/// Provides methods to clear some of the model data in the Text::Controller::Impl
+struct ControllerImplDataClearer
+{
+
+  /**
+   * @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.
+   *
+   * @param[in] impl The text controller impl.
+   * @param[in] operations The operations required.
+   */
+  static void ClearFullModelData(Controller::Impl& impl, Controller::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] impl The text controller impl.
+   * @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.
+   */
+  static void ClearCharacterModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::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] impl The text controller impl.
+   * @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.
+   */
+  static void ClearGlyphModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::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.
+   *
+   * @param[in] impl The text controller impl.
+   * @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.
+   */
+  static void ClearModelData(Controller::Impl& impl, CharacterIndex startIndex, CharacterIndex endIndex, Controller::OperationsMask operations);
+};
+
+} // namespace Dali::Toolkit::Text
+
+#endif // DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_DATA_CLEARER_H
index 4334f0e..8a1dd76 100644 (file)
 #include <dali-toolkit/internal/text/text-controller-impl.h>
 
 // EXTERNAL INCLUDES
+#include <cmath>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/rendering/renderer.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
@@ -28,6 +30,7 @@
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 #include <dali-toolkit/internal/text/cursor-helper-functions.h>
 #include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller-impl-data-clearer.h>
 #include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
 #include <dali-toolkit/internal/text/text-controller-impl-model-updater.h>
 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
@@ -129,6 +132,243 @@ void SetDefaultInputStyle(InputStyle& inputStyle, const FontDefaults* const font
     }
   }
 }
+
+void ChangeTextControllerState(Controller::Impl& impl, EventData::State newState)
+{
+  EventData* eventData = impl.mEventData;
+
+  if(nullptr == eventData)
+  {
+    // Nothing to do if there is no text input.
+    return;
+  }
+
+  DecoratorPtr& decorator = eventData->mDecorator;
+  if(!decorator)
+  {
+    // Nothing to do if there is no decorator.
+    return;
+  }
+
+  DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", eventData->mState, newState);
+
+  if(eventData->mState != newState)
+  {
+    eventData->mPreviousState = eventData->mState;
+    eventData->mState         = newState;
+
+    switch(eventData->mState)
+    {
+      case EventData::INACTIVE:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        decorator->SetPopupActive(false);
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::INTERRUPTED:
+      {
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        decorator->SetPopupActive(false);
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::SELECTING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
+        }
+        decorator->SetHighlightActive(true);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          impl.SetPopupButtons();
+          decorator->SetPopupActive(true);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::EDITING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        // Grab handle is not shown until a tap is received whilst EDITING
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_POPUP:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        if(eventData->mSelectionEnabled)
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+          decorator->SetHighlightActive(false);
+        }
+        else if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          impl.SetPopupButtons();
+          decorator->SetPopupActive(true);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+      case EventData::EDITING_WITH_GRAB_HANDLE:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        // Grab handle is not shown until a tap is received whilst EDITING
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::SELECTION_HANDLE_PANNING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
+        }
+        decorator->SetHighlightActive(true);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::GRAB_HANDLE_PANNING:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::EDITING_WITH_PASTE_POPUP:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
+
+        decorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
+        if(eventData->mCursorBlinkEnabled)
+        {
+          decorator->StartCursorBlink();
+        }
+
+        if(eventData->mGrabHandleEnabled)
+        {
+          decorator->SetHandleActive(GRAB_HANDLE, true);
+        }
+        decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+        decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+        decorator->SetHighlightActive(false);
+
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          impl.SetPopupButtons();
+          decorator->SetPopupActive(true);
+        }
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+
+      case EventData::TEXT_PANNING:
+      {
+        decorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
+        decorator->StopCursorBlink();
+        decorator->SetHandleActive(GRAB_HANDLE, false);
+        if(eventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
+            decorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
+        {
+          decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
+          decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+          decorator->SetHighlightActive(true);
+        }
+
+        if(eventData->mGrabHandlePopupEnabled)
+        {
+          decorator->SetPopupActive(false);
+        }
+
+        eventData->mDecoratorUpdated = true;
+        break;
+      }
+    }
+  }
+}
+
 } // unnamed Namespace
 
 EventData::EventData(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
@@ -268,6 +508,19 @@ void Controller::Impl::GetText(CharacterIndex index, std::string& text) const
   }
 }
 
+Dali::LayoutDirection::Type Controller::Impl::GetLayoutDirection(Dali::Actor& actor) const
+{
+  if(mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::LOCALE ||
+     (mModel->mMatchLayoutDirection == DevelText::MatchLayoutDirection::INHERIT && !mIsLayoutDirectionChanged))
+  {
+    return static_cast<Dali::LayoutDirection::Type>(DevelWindow::Get(actor).GetRootLayer().GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+  }
+  else
+  {
+    return static_cast<Dali::LayoutDirection::Type>(actor.GetProperty(Dali::Actor::Property::LAYOUT_DIRECTION).Get<int>());
+  }
+}
+
 void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
 {
   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
@@ -353,286 +606,9 @@ void Controller::Impl::CalculateTextUpdateIndices(Length& numberOfCharacters)
   mTextUpdateInfo.mStartGlyphIndex             = *(mModel->mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex);
 }
 
-void Controller::Impl::ClearFullModelData(OperationsMask operations)
-{
-  if(NO_OPERATION != (GET_LINE_BREAKS & operations))
-  {
-    mModel->mLogicalModel->mLineBreakInfo.Clear();
-    mModel->mLogicalModel->mParagraphInfo.Clear();
-  }
-
-  if(NO_OPERATION != (GET_SCRIPTS & operations))
-  {
-    mModel->mLogicalModel->mScriptRuns.Clear();
-  }
-
-  if(NO_OPERATION != (VALIDATE_FONTS & operations))
-  {
-    mModel->mLogicalModel->mFontRuns.Clear();
-  }
-
-  if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
-  {
-    if(NO_OPERATION != (BIDI_INFO & operations))
-    {
-      mModel->mLogicalModel->mBidirectionalParagraphInfo.Clear();
-      mModel->mLogicalModel->mCharacterDirections.Clear();
-    }
-
-    if(NO_OPERATION != (REORDER & operations))
-    {
-      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
-      for(Vector<BidirectionalLineInfoRun>::Iterator it    = mModel->mLogicalModel->mBidirectionalLineInfo.Begin(),
-                                                     endIt = mModel->mLogicalModel->mBidirectionalLineInfo.End();
-          it != endIt;
-          ++it)
-      {
-        BidirectionalLineInfoRun& bidiLineInfo = *it;
-
-        free(bidiLineInfo.visualToLogicalMap);
-        bidiLineInfo.visualToLogicalMap = NULL;
-      }
-      mModel->mLogicalModel->mBidirectionalLineInfo.Clear();
-    }
-  }
-
-  if(NO_OPERATION != (SHAPE_TEXT & operations))
-  {
-    mModel->mVisualModel->mGlyphs.Clear();
-    mModel->mVisualModel->mGlyphsToCharacters.Clear();
-    mModel->mVisualModel->mCharactersToGlyph.Clear();
-    mModel->mVisualModel->mCharactersPerGlyph.Clear();
-    mModel->mVisualModel->mGlyphsPerCharacter.Clear();
-    mModel->mVisualModel->mGlyphPositions.Clear();
-  }
-
-  if(NO_OPERATION != (LAYOUT & operations))
-  {
-    mModel->mVisualModel->mLines.Clear();
-  }
-
-  if(NO_OPERATION != (COLOR & operations))
-  {
-    mModel->mVisualModel->mColorIndices.Clear();
-    mModel->mVisualModel->mBackgroundColorIndices.Clear();
-  }
-}
-
-void Controller::Impl::ClearCharacterModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
-{
-  const CharacterIndex endIndexPlusOne = endIndex + 1u;
-
-  if(NO_OPERATION != (GET_LINE_BREAKS & operations))
-  {
-    // Clear the line break info.
-    LineBreakInfo* lineBreakInfoBuffer = mModel->mLogicalModel->mLineBreakInfo.Begin();
-
-    mModel->mLogicalModel->mLineBreakInfo.Erase(lineBreakInfoBuffer + startIndex,
-                                                lineBreakInfoBuffer + endIndexPlusOne);
-
-    // Clear the paragraphs.
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mLogicalModel->mParagraphInfo);
-  }
-
-  if(NO_OPERATION != (GET_SCRIPTS & operations))
-  {
-    // Clear the scripts.
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mLogicalModel->mScriptRuns);
-  }
-
-  if(NO_OPERATION != (VALIDATE_FONTS & operations))
-  {
-    // Clear the fonts.
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mLogicalModel->mFontRuns);
-  }
-
-  if(0u != mModel->mLogicalModel->mBidirectionalParagraphInfo.Count())
-  {
-    if(NO_OPERATION != (BIDI_INFO & operations))
-    {
-      // Clear the bidirectional paragraph info.
-      ClearCharacterRuns(startIndex,
-                         endIndex,
-                         mModel->mLogicalModel->mBidirectionalParagraphInfo);
-
-      // Clear the character's directions.
-      CharacterDirection* characterDirectionsBuffer = mModel->mLogicalModel->mCharacterDirections.Begin();
-
-      mModel->mLogicalModel->mCharacterDirections.Erase(characterDirectionsBuffer + startIndex,
-                                                        characterDirectionsBuffer + endIndexPlusOne);
-    }
-
-    if(NO_OPERATION != (REORDER & operations))
-    {
-      uint32_t startRemoveIndex = mModel->mLogicalModel->mBidirectionalLineInfo.Count();
-      uint32_t endRemoveIndex   = startRemoveIndex;
-      ClearCharacterRuns(startIndex,
-                         endIndex,
-                         mModel->mLogicalModel->mBidirectionalLineInfo,
-                         startRemoveIndex,
-                         endRemoveIndex);
-
-      BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mModel->mLogicalModel->mBidirectionalLineInfo.Begin();
-
-      // Free the allocated memory used to store the conversion table in the bidirectional line info run.
-      for(Vector<BidirectionalLineInfoRun>::Iterator it    = bidirectionalLineInfoBuffer + startRemoveIndex,
-                                                     endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
-          it != endIt;
-          ++it)
-      {
-        BidirectionalLineInfoRun& bidiLineInfo = *it;
-
-        free(bidiLineInfo.visualToLogicalMap);
-        bidiLineInfo.visualToLogicalMap = NULL;
-      }
-
-      mModel->mLogicalModel->mBidirectionalLineInfo.Erase(bidirectionalLineInfoBuffer + startRemoveIndex,
-                                                          bidirectionalLineInfoBuffer + endRemoveIndex);
-    }
-  }
-}
-
-void Controller::Impl::ClearGlyphModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
-{
-  const CharacterIndex endIndexPlusOne           = endIndex + 1u;
-  const Length         numberOfCharactersRemoved = endIndexPlusOne - startIndex;
-
-  // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
-  GlyphIndex* charactersToGlyphBuffer  = mModel->mVisualModel->mCharactersToGlyph.Begin();
-  Length*     glyphsPerCharacterBuffer = mModel->mVisualModel->mGlyphsPerCharacter.Begin();
-
-  const GlyphIndex endGlyphIndexPlusOne  = *(charactersToGlyphBuffer + endIndex) + *(glyphsPerCharacterBuffer + endIndex);
-  const Length     numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
-
-  if(NO_OPERATION != (SHAPE_TEXT & operations))
-  {
-    // Update the character to glyph indices.
-    for(Vector<GlyphIndex>::Iterator it    = charactersToGlyphBuffer + endIndexPlusOne,
-                                     endIt = charactersToGlyphBuffer + mModel->mVisualModel->mCharactersToGlyph.Count();
-        it != endIt;
-        ++it)
-    {
-      CharacterIndex& index = *it;
-      index -= numberOfGlyphsRemoved;
-    }
-
-    // Clear the character to glyph conversion table.
-    mModel->mVisualModel->mCharactersToGlyph.Erase(charactersToGlyphBuffer + startIndex,
-                                                   charactersToGlyphBuffer + endIndexPlusOne);
-
-    // Clear the glyphs per character table.
-    mModel->mVisualModel->mGlyphsPerCharacter.Erase(glyphsPerCharacterBuffer + startIndex,
-                                                    glyphsPerCharacterBuffer + endIndexPlusOne);
-
-    // Clear the glyphs buffer.
-    GlyphInfo* glyphsBuffer = mModel->mVisualModel->mGlyphs.Begin();
-    mModel->mVisualModel->mGlyphs.Erase(glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                        glyphsBuffer + endGlyphIndexPlusOne);
-
-    CharacterIndex* glyphsToCharactersBuffer = mModel->mVisualModel->mGlyphsToCharacters.Begin();
-
-    // Update the glyph to character indices.
-    for(Vector<CharacterIndex>::Iterator it    = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
-                                         endIt = glyphsToCharactersBuffer + mModel->mVisualModel->mGlyphsToCharacters.Count();
-        it != endIt;
-        ++it)
-    {
-      CharacterIndex& index = *it;
-      index -= numberOfCharactersRemoved;
-    }
-
-    // Clear the glyphs to characters buffer.
-    mModel->mVisualModel->mGlyphsToCharacters.Erase(glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                    glyphsToCharactersBuffer + endGlyphIndexPlusOne);
-
-    // Clear the characters per glyph buffer.
-    Length* charactersPerGlyphBuffer = mModel->mVisualModel->mCharactersPerGlyph.Begin();
-    mModel->mVisualModel->mCharactersPerGlyph.Erase(charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                    charactersPerGlyphBuffer + endGlyphIndexPlusOne);
-
-    // Should pass if mGlyphPositions has already been cleared in Controller::Relayouter::Relayout
-    if(0u != mModel->mVisualModel->mGlyphPositions.Count())
-    {
-      // Clear the positions buffer.
-      Vector2* positionsBuffer = mModel->mVisualModel->mGlyphPositions.Begin();
-      mModel->mVisualModel->mGlyphPositions.Erase(positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                  positionsBuffer + endGlyphIndexPlusOne);
-    }
-  }
-
-  if(NO_OPERATION != (LAYOUT & operations))
-  {
-    // Clear the lines.
-    uint32_t startRemoveIndex = mModel->mVisualModel->mLines.Count();
-    uint32_t endRemoveIndex   = startRemoveIndex;
-    ClearCharacterRuns(startIndex,
-                       endIndex,
-                       mModel->mVisualModel->mLines,
-                       startRemoveIndex,
-                       endRemoveIndex);
-
-    // Will update the glyph runs.
-    startRemoveIndex = mModel->mVisualModel->mLines.Count();
-    endRemoveIndex   = startRemoveIndex;
-    ClearGlyphRuns(mTextUpdateInfo.mStartGlyphIndex,
-                   endGlyphIndexPlusOne - 1u,
-                   mModel->mVisualModel->mLines,
-                   startRemoveIndex,
-                   endRemoveIndex);
-
-    // Set the line index from where to insert the new laid-out lines.
-    mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
-
-    LineRun* linesBuffer = mModel->mVisualModel->mLines.Begin();
-    mModel->mVisualModel->mLines.Erase(linesBuffer + startRemoveIndex,
-                                       linesBuffer + endRemoveIndex);
-  }
-
-  if(NO_OPERATION != (COLOR & operations))
-  {
-    if(0u != mModel->mVisualModel->mColorIndices.Count())
-    {
-      ColorIndex* colorIndexBuffer = mModel->mVisualModel->mColorIndices.Begin();
-      mModel->mVisualModel->mColorIndices.Erase(colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                colorIndexBuffer + endGlyphIndexPlusOne);
-    }
-
-    if(0u != mModel->mVisualModel->mBackgroundColorIndices.Count())
-    {
-      ColorIndex* backgroundColorIndexBuffer = mModel->mVisualModel->mBackgroundColorIndices.Begin();
-      mModel->mVisualModel->mBackgroundColorIndices.Erase(backgroundColorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                                          backgroundColorIndexBuffer + endGlyphIndexPlusOne);
-    }
-  }
-}
-
 void Controller::Impl::ClearModelData(CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations)
 {
-  if(mTextUpdateInfo.mClearAll ||
-     ((0u == startIndex) &&
-      (mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u)))
-  {
-    ClearFullModelData(operations);
-  }
-  else
-  {
-    // Clear the model data related with characters.
-    ClearCharacterModelData(startIndex, endIndex, operations);
-
-    // Clear the model data related with glyphs.
-    ClearGlyphModelData(startIndex, endIndex, operations);
-  }
-
-  // The estimated number of lines. Used to avoid reallocations when layouting.
-  mTextUpdateInfo.mEstimatedNumberOfLines = std::max(mModel->mVisualModel->mLines.Count(), mModel->mLogicalModel->mParagraphInfo.Count());
-
-  mModel->mVisualModel->ClearCaches();
+  ControllerImplDataClearer::ClearModelData(*this, startIndex, endIndex, operations);
 }
 
 bool Controller::Impl::UpdateModel(OperationsMask operationsRequired)
@@ -664,6 +640,32 @@ float Controller::Impl::GetDefaultFontLineHeight()
   return (fontMetrics.ascender - fontMetrics.descender);
 }
 
+bool Controller::Impl::SetDefaultLineSpacing(float lineSpacing)
+{
+  if(std::fabs(lineSpacing - mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
+  {
+    mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
+    mRecalculateNaturalSize = true;
+
+    RelayoutForNewLineSize();
+    return true;
+  }
+  return false;
+}
+
+bool Controller::Impl::SetDefaultLineSize(float lineSize)
+{
+  if(std::fabs(lineSize - mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
+  {
+    mLayoutEngine.SetDefaultLineSize(lineSize);
+    mRecalculateNaturalSize = true;
+
+    RelayoutForNewLineSize();
+    return true;
+  }
+  return false;
+}
+
 void Controller::Impl::SetTextSelectionRange(const uint32_t* pStart, const uint32_t* pEnd)
 {
   if(nullptr == mEventData)
@@ -791,6 +793,21 @@ void Controller::Impl::SetEditable(bool editable)
   }
 }
 
+void Controller::Impl::UpdateAfterFontChange(const std::string& newDefaultFont)
+{
+  DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
+
+  if(!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());
+    mFontDefaults->mFontDescription.family = newDefaultFont;
+
+    ClearFontData();
+
+    RequestRelayout();
+  }
+}
+
 void Controller::Impl::RetrieveSelection(std::string& selectedText, bool deleteAfterRetrieval)
 {
   if(mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
@@ -1008,222 +1025,7 @@ void Controller::Impl::SetPopupButtons()
 
 void Controller::Impl::ChangeState(EventData::State newState)
 {
-  if(nullptr == mEventData)
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  DALI_LOG_INFO(gLogFilter, Debug::General, "ChangeState state:%d  newstate:%d\n", mEventData->mState, newState);
-
-  if(mEventData->mState != newState)
-  {
-    mEventData->mPreviousState = mEventData->mState;
-    mEventData->mState         = newState;
-
-    switch(mEventData->mState)
-    {
-      case EventData::INACTIVE:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        mEventData->mDecorator->SetPopupActive(false);
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::INTERRUPTED:
-      {
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        mEventData->mDecorator->SetPopupActive(false);
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::SELECTING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHighlightActive(true);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          SetPopupButtons();
-          mEventData->mDecorator->SetPopupActive(true);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        // Grab handle is not shown until a tap is received whilst EDITING
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING_WITH_POPUP:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_POPUP \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        if(mEventData->mSelectionEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHighlightActive(false);
-        }
-        else if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          SetPopupButtons();
-          mEventData->mDecorator->SetPopupActive(true);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING_WITH_GRAB_HANDLE:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_GRAB_HANDLE \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        // Grab handle is not shown until a tap is received whilst EDITING
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::SELECTION_HANDLE_PANNING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, true);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHighlightActive(true);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::GRAB_HANDLE_PANNING:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GRAB_HANDLE_PANNING \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::EDITING_WITH_PASTE_POPUP:
-      {
-        DALI_LOG_INFO(gLogFilter, Debug::Verbose, "EDITING_WITH_PASTE_POPUP \n", newState);
-
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_PRIMARY);
-        if(mEventData->mCursorBlinkEnabled)
-        {
-          mEventData->mDecorator->StartCursorBlink();
-        }
-
-        if(mEventData->mGrabHandleEnabled)
-        {
-          mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, true);
-        }
-        mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-        mEventData->mDecorator->SetHighlightActive(false);
-
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          SetPopupButtons();
-          mEventData->mDecorator->SetPopupActive(true);
-        }
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-      case EventData::TEXT_PANNING:
-      {
-        mEventData->mDecorator->SetActiveCursor(ACTIVE_CURSOR_NONE);
-        mEventData->mDecorator->StopCursorBlink();
-        mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
-        if(mEventData->mDecorator->IsHandleActive(LEFT_SELECTION_HANDLE) ||
-           mEventData->mDecorator->IsHandleActive(RIGHT_SELECTION_HANDLE))
-        {
-          mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
-          mEventData->mDecorator->SetHighlightActive(true);
-        }
-
-        if(mEventData->mGrabHandlePopupEnabled)
-        {
-          mEventData->mDecorator->SetPopupActive(false);
-        }
-
-        mEventData->mDecoratorUpdated = true;
-        break;
-      }
-    }
-  }
+  ChangeTextControllerState(*this, newState);
 }
 
 void Controller::Impl::GetCursorPosition(CharacterIndex logical,
@@ -1843,4 +1645,197 @@ void Controller::Impl::CopyUnderlinedFromLogicalToVisualModels(bool shouldClearP
   }
 }
 
+void Controller::Impl::SetAutoScrollEnabled(bool enable)
+{
+  if(mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
+  {
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+                                                     LAYOUT |
+                                                     ALIGN |
+                                                     UPDATE_LAYOUT_SIZE |
+                                                     REORDER);
+
+    if(enable)
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
+      mOperationsPending = static_cast<OperationsMask>(mOperationsPending | UPDATE_DIRECTION);
+    }
+    else
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
+    }
+
+    mIsAutoScrollEnabled = enable;
+    RequestRelayout();
+  }
+  else
+  {
+    DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
+    mIsAutoScrollEnabled = false;
+  }
+}
+
+void Controller::Impl::SetEnableCursorBlink(bool enable)
+{
+  DALI_ASSERT_DEBUG(NULL != mEventData && "TextInput disabled");
+
+  if(mEventData)
+  {
+    mEventData->mCursorBlinkEnabled = enable;
+
+    if(!enable && mEventData->mDecorator)
+    {
+      mEventData->mDecorator->StopCursorBlink();
+    }
+  }
+}
+
+void Controller::Impl::SetMultiLineEnabled(bool enable)
+{
+  const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
+
+  if(layout != mLayoutEngine.GetLayout())
+  {
+    // Set the layout type.
+    mLayoutEngine.SetLayout(layout);
+
+    // Set the flags to redo the layout operations
+    const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
+                                                                        UPDATE_LAYOUT_SIZE |
+                                                                        ALIGN |
+                                                                        REORDER);
+
+    mTextUpdateInfo.mFullRelayoutNeeded = true;
+    mOperationsPending                  = static_cast<OperationsMask>(mOperationsPending | layoutOperations);
+
+    // Need to recalculate natural size
+    mRecalculateNaturalSize = true;
+
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
+{
+  if(alignment != mModel->mHorizontalAlignment)
+  {
+    // Set the alignment.
+    mModel->mHorizontalAlignment = alignment;
+
+    // Set the flag to redo the alignment operation.
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
+
+    if(mEventData)
+    {
+      mEventData->mUpdateAlignment = true;
+
+      // Update the cursor if it's in editing mode
+      if(EventData::IsEditingState(mEventData->mState))
+      {
+        ChangeState(EventData::EDITING);
+        mEventData->mUpdateCursorPosition = true;
+      }
+    }
+
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetVerticalAlignment(VerticalAlignment::Type alignment)
+{
+  if(alignment != mModel->mVerticalAlignment)
+  {
+    // Set the alignment.
+    mModel->mVerticalAlignment = alignment;
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending | ALIGN);
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
+{
+  if(lineWrapMode != mModel->mLineWrapMode)
+  {
+    // Update Text layout for applying wrap mode
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+                                                     ALIGN |
+                                                     LAYOUT |
+                                                     UPDATE_LAYOUT_SIZE |
+                                                     REORDER);
+
+    if((mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+       (mModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED) || (lineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED)) // hyphen is treated as line break
+    {
+      mOperationsPending = static_cast<OperationsMask>(mOperationsPending | GET_LINE_BREAKS);
+    }
+
+    // Set the text wrap mode.
+    mModel->mLineWrapMode = lineWrapMode;
+
+    mTextUpdateInfo.mCharacterIndex             = 0u;
+    mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+    mTextUpdateInfo.mNumberOfCharactersToAdd    = mModel->mLogicalModel->mText.Count();
+
+    // Request relayout
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::SetDefaultColor(const Vector4& color)
+{
+  mTextColor = color;
+
+  if(!IsShowingPlaceholderText())
+  {
+    mModel->mVisualModel->SetTextColor(color);
+    mModel->mLogicalModel->mColorRuns.Clear();
+    mOperationsPending = static_cast<OperationsMask>(mOperationsPending | COLOR);
+    RequestRelayout();
+  }
+}
+
+void Controller::Impl::ClearFontData()
+{
+  if(mFontDefaults)
+  {
+    mFontDefaults->mFontId = 0u; // Remove old font ID
+  }
+
+  // Set flags to update the model.
+  mTextUpdateInfo.mCharacterIndex             = 0u;
+  mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+  mTextUpdateInfo.mNumberOfCharactersToAdd    = mModel->mLogicalModel->mText.Count();
+
+  mTextUpdateInfo.mClearAll           = true;
+  mTextUpdateInfo.mFullRelayoutNeeded = true;
+  mRecalculateNaturalSize             = true;
+
+  mOperationsPending = static_cast<OperationsMask>(mOperationsPending |
+                                                   VALIDATE_FONTS |
+                                                   SHAPE_TEXT |
+                                                   BIDI_INFO |
+                                                   GET_GLYPH_METRICS |
+                                                   LAYOUT |
+                                                   UPDATE_LAYOUT_SIZE |
+                                                   REORDER |
+                                                   ALIGN);
+}
+
+void Controller::Impl::ClearStyleData()
+{
+  mModel->mLogicalModel->mColorRuns.Clear();
+  mModel->mLogicalModel->ClearFontDescriptionRuns();
+}
+
+
+void Controller::Impl::ResetScrollPosition()
+{
+  if(mEventData)
+  {
+    // Reset the scroll position.
+    mModel->mScrollPosition                = Vector2::ZERO;
+    mEventData->mScrollAfterUpdatePosition = true;
+  }
+}
+
 } // namespace Dali::Toolkit::Text
index 219ca72..23d5d86 100644 (file)
@@ -545,6 +545,11 @@ struct Controller::Impl
   }
 
   /**
+   * @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.
    *
@@ -553,36 +558,6 @@ struct Controller::Impl
   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.
@@ -620,6 +595,16 @@ struct Controller::Impl
   float GetDefaultFontLineHeight();
 
   /**
+   * @copydoc Controller::SetDefaultLineSpacing
+   */
+  bool SetDefaultLineSpacing(float lineSpacing);
+
+  /**
+   * @copydoc Controller::SetDefaultLineSize
+   */
+  bool SetDefaultLineSize(float lineSize);
+
+  /**
    * @copydoc Text::Controller::GetPrimaryCursorPosition()
    */
   CharacterIndex GetPrimaryCursorPosition() const;
@@ -650,6 +635,11 @@ struct Controller::Impl
   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.
@@ -801,6 +791,55 @@ struct Controller::Impl
    */
   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:
   /**
index 4c71934..d04483a 100644 (file)
@@ -170,7 +170,7 @@ bool Controller::Relayouter::CheckForTextFit(Controller& controller, float point
   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 |
@@ -257,7 +257,7 @@ void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const
     model->mElideEnabled              = actualellipsis;
     impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
     impl.mFontDefaults->sizeDefined   = true;
-    controller.ClearFontData();
+    impl.ClearFontData();
   }
 }
 
@@ -561,7 +561,7 @@ bool Controller::Relayouter::DoRelayout(Controller& controller, const Size& size
       // Reset the scroll position in inactive state
       if(elideTextEnabled && (impl.mEventData->mState == EventData::INACTIVE))
       {
-        controller.ResetScrollPosition();
+        impl.ResetScrollPosition();
       }
     }
 
index 75ea73c..8a19786 100644 (file)
@@ -55,7 +55,7 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string&
   ResetText(controller);
 
   // Remove the style.
-  controller.ClearStyleData();
+  impl.ClearStyleData();
 
   CharacterIndex lastCursorIndex = 0u;
 
@@ -150,7 +150,7 @@ void Controller::TextUpdater::SetText(Controller& controller, const std::string&
   controller.ResetCursorPosition(lastCursorIndex);
 
   // Scrolls the text to make the cursor visible.
-  controller.ResetScrollPosition();
+  impl.ResetScrollPosition();
 
   impl.RequestRelayout();
 
index 19af999..0262929 100644 (file)
@@ -138,7 +138,7 @@ void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType)
   mImpl->mMetrics->SetGlyphType(glyphType);
 
   // Clear the font-specific data
-  ClearFontData();
+  mImpl->ClearFontData();
 
   mImpl->RequestRelayout();
 }
@@ -170,39 +170,12 @@ bool Controller::HasAnchors() const
 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;
 }
 
@@ -272,17 +245,7 @@ int Controller::GetMaximumNumberOfCharacters()
 
 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
@@ -292,27 +255,7 @@ 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
@@ -322,28 +265,7 @@ 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
@@ -353,13 +275,7 @@ 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
@@ -417,31 +333,7 @@ bool Controller::IsShowingRealText() const
 
 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
@@ -590,17 +482,7 @@ void Controller::GetPlaceholderText(PlaceholderType type, std::string& text) con
 
 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
@@ -640,7 +522,7 @@ void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
   UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
-  ClearFontData();
+  mImpl->ClearFontData();
 
   mImpl->RequestRelayout();
 }
@@ -671,7 +553,7 @@ void Controller::SetDefaultFontWeight(FontWeight weight)
   UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
-  ClearFontData();
+  mImpl->ClearFontData();
 
   mImpl->RequestRelayout();
 }
@@ -712,7 +594,7 @@ void Controller::SetDefaultFontWidth(FontWidth width)
   UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
-  ClearFontData();
+  mImpl->ClearFontData();
 
   mImpl->RequestRelayout();
 }
@@ -753,7 +635,7 @@ void Controller::SetDefaultFontSlant(FontSlant slant)
   UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
-  ClearFontData();
+  mImpl->ClearFontData();
 
   mImpl->RequestRelayout();
 }
@@ -791,7 +673,7 @@ void Controller::SetFontSizeScale(float scale)
   UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
-  ClearFontData();
+  mImpl->ClearFontData();
 
   mImpl->RequestRelayout();
 }
@@ -812,7 +694,7 @@ void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
   UpdateCursorPosition(mImpl->mEventData);
 
   // Clear the font-specific data
-  ClearFontData();
+  mImpl->ClearFontData();
 
   mImpl->RequestRelayout();
 }
@@ -838,15 +720,7 @@ float Controller::GetPlaceholderTextFontSize(FontSizeType type) const
 
 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
@@ -1001,15 +875,7 @@ const std::string& Controller::GetDefaultOutlineProperties() const
 
 bool Controller::SetDefaultLineSpacing(float lineSpacing)
 {
-  if(std::fabs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
-  {
-    mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
-    mImpl->mRecalculateNaturalSize = true;
-
-    mImpl->RelayoutForNewLineSize();
-    return true;
-  }
-  return false;
+  return mImpl->SetDefaultLineSpacing(lineSpacing);
 }
 
 float Controller::GetDefaultLineSpacing() const
@@ -1019,15 +885,7 @@ 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;
-
-    mImpl->RelayoutForNewLineSize();
-    return true;
-  }
-  return false;
+  return mImpl->SetDefaultLineSize(lineSize);
 }
 
 float Controller::GetDefaultLineSize() const
@@ -1731,39 +1589,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
@@ -1781,20 +1606,7 @@ void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
 
 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)
index ec3cbb9..85d78a3 100644 (file)
@@ -1881,21 +1881,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();
-
 private: // Private contructors & copy operator.
   /**
    * @brief Private constructor.