[Tizen] Fix text label anchor extents 64/324964/1 accepted/tizen/7.0/unified/20250530.022403
authorYoungsun Suh <youngsun.suh@samsung.com>
Thu, 29 May 2025 01:37:01 +0000 (10:37 +0900)
committerYoungsun Suh <youngsun.suh@samsung.com>
Thu, 29 May 2025 08:52:34 +0000 (17:52 +0900)
- Update to actually calculate anchor extents

Change-Id: I028ca0ed406407c55f5dbe3aeb20535c96835883

automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls.cpp
dali-toolkit/internal/controls/text-controls/common-text-utils.cpp
dali-toolkit/internal/controls/text-controls/common-text-utils.h
dali-toolkit/internal/controls/text-controls/text-anchor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/text/controller/text-controller-impl.cpp
dali-toolkit/internal/text/controller/text-controller-impl.h
dali-toolkit/internal/text/controller/text-controller.cpp

index 76744be3c8a6dd9fbcf969a7be2bfa94cf96549c..3f3401e75d8c9d181f480f826347d38f444bfdaf 100644 (file)
@@ -948,6 +948,9 @@ int UtcDaliAccessibilityTextLabel(void)
   auto textlabel = TextLabel::New();
   DALI_TEST_CHECK(textlabel);
 
+  application.GetScene().Add(textlabel);
+  application.SendNotification();
+
   textlabel.SetProperty(Actor::Property::NAME, "test");
   DALI_TEST_EQUALS(textlabel.GetProperty<std::string>(Actor::Property::NAME), "test", TEST_LOCATION);
 
@@ -984,7 +987,7 @@ int UtcDaliAccessibilityTextLabel(void)
   DALI_TEST_EQUALS(hypertext->GetLink(-1) == nullptr, true, TEST_LOCATION);
   DALI_TEST_EQUALS(hypertext->GetLink(0) == nullptr, true, TEST_LOCATION);
   DALI_TEST_EQUALS(hypertext->GetLink(5) == nullptr, true, TEST_LOCATION);
-  // text with the anchors markup and ENABLE_MARKUP property set (by default) to false
+  // text with the anchors; No anchor created until layout
   textlabel.SetProperty(Toolkit::TextLabel::Property::TEXT, "12345<a href = 'https://www.tizen.org'>anchor1</a>12345<a href = 'https://www.tizen.org' >veryveryveryveryveryveryveryverylonganchor2</a>12345<a href = 'https://www.tizen.org'>anchor3</a>12345");
   DALI_TEST_EQUALS(hypertext->GetLinkCount(), 0, TEST_LOCATION);
   DALI_TEST_EQUALS(hypertext->GetLinkIndex(-1), -1, TEST_LOCATION);
@@ -993,8 +996,11 @@ int UtcDaliAccessibilityTextLabel(void)
   DALI_TEST_EQUALS(hypertext->GetLink(-1) == nullptr, true, TEST_LOCATION);
   DALI_TEST_EQUALS(hypertext->GetLink(0) == nullptr, true, TEST_LOCATION);
   DALI_TEST_EQUALS(hypertext->GetLink(5) == nullptr, true, TEST_LOCATION);
-  // text with the anchors markup and ENABLE_MARKUP property set to true
   textlabel.SetProperty(Toolkit::TextLabel::Property::ENABLE_MARKUP, true);
+  // Triggers text layout
+  application.SendNotification();
+  application.Render(1);
+  // Anchors are created after layout
   DALI_TEST_EQUALS(hypertext->GetLinkCount(), 3, TEST_LOCATION);
   DALI_TEST_EQUALS(hypertext->GetLinkIndex(-1), -1, TEST_LOCATION);
   DALI_TEST_EQUALS(hypertext->GetLinkIndex(0), -1, TEST_LOCATION);
index c73a2165438f3fee8086d517aae61f7460c889e0..c21dc552c0c14deeba3837a7472c725819073e8b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
 #include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
 #include <dali-toolkit/internal/text/hidden-text.h>
+#include <dali-toolkit/internal/text/text-geometry.h>
 #include <dali-toolkit/internal/text/text-view.h>
 
 namespace Dali::Toolkit::Internal
 {
+Rect<> CommonTextUtils::GetTextBoundingRectangle(Text::ModelPtr model, TextAbstraction::CharacterIndex startIndex, TextAbstraction::CharacterIndex endIndex)
+{
+  Vector<Vector2> sizeList;
+  Vector<Vector2> positionList;
+
+  GetTextGeometry(model, startIndex, endIndex, sizeList, positionList);
+
+  if(sizeList.Empty() || sizeList.Size() != positionList.Size())
+  {
+    return {0, 0, 0, 0};
+  }
+
+  auto controlWidth = model->mVisualModel->mControlSize.width;
+  auto minX         = positionList[0].x;
+  auto minY         = positionList[0].y;
+  auto maxRight     = positionList[0].x + sizeList[0].x;
+  auto maxBottom    = positionList[0].y + sizeList[0].y;
+
+  for(unsigned int i = 1; i < sizeList.Size(); i++)
+  {
+    minX      = std::min(minX, positionList[i].x);
+    minY      = std::min(minY, positionList[i].y);
+    maxRight  = std::max(maxRight, positionList[i].x + sizeList[i].x);
+    maxBottom = std::max(maxBottom, positionList[i].y + sizeList[i].y);
+  }
+
+  if(minX < 0.0f)
+  {
+    minX = 0.0f;
+  }
+
+  if(maxRight > controlWidth)
+  {
+    maxRight = controlWidth;
+  }
+
+  return {minX, minY, maxRight - minX, maxBottom - minY};
+}
+
 void CommonTextUtils::SynchronizeTextAnchorsInParent(
   Actor                             parent,
   Text::ControllerPtr               controller,
@@ -316,7 +356,7 @@ Accessibility::Range TextControlAccessible::GetTextAtOffset(std::size_t offset,
       break;
     }
 
-    case Dali::Accessibility::TextBoundary::SENTENCE: // Not supported by default
+    case Dali::Accessibility::TextBoundary::SENTENCE:  // Not supported by default
     case Dali::Accessibility::TextBoundary::PARAGRAPH: // Not supported by libunibreak library
     default:
     {
index a21dc86fe28e7d9c1b1f55f6f7f36492fd87e0f4..3d049c45f42d57ebc726e60d72525e3348973509 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_TEXT_CONTROLS_COMMON_TEXT_UTILS_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-accessible.h>
 #include <dali-toolkit/devel-api/controls/text-controls/text-anchor-devel.h>
+#include <dali-toolkit/internal/text/controller/text-controller.h>
 #include <dali-toolkit/internal/text/decorator/text-decorator.h>
 #include <dali-toolkit/internal/text/rendering/text-renderer.h>
-#include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/text-model.h>
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/controls/text-controls/text-editor.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
 
 namespace Dali::Toolkit::Internal
 {
@@ -53,18 +55,18 @@ public:
    * @param[in] updateTextType How the text has been updated
    */
   static void RenderText(
-    Actor                            textActor,
-    Text::RendererPtr                renderer,
-    Text::ControllerPtr              controller,
-    Text::DecoratorPtr               decorator,
-    float&                           alignmentOffset,
-    Actor&                           renderableActor,
-    Actor&                           backgroundActor,
-    Actor&                           cursorLayerActor,
-    Toolkit::Control&                stencil,
-    std::vector<Actor>&              clippingDecorationActors,
+    Actor                             textActor,
+    Text::RendererPtr                 renderer,
+    Text::ControllerPtr               controller,
+    Text::DecoratorPtr                decorator,
+    float&                            alignmentOffset,
+    Actor&                            renderableActor,
+    Actor&                            backgroundActor,
+    Actor&                            cursorLayerActor,
+    Toolkit::Control&                 stencil,
+    std::vector<Actor>&               clippingDecorationActors,
     std::vector<Toolkit::TextAnchor>& anchorActors,
-    Text::Controller::UpdateTextType updateTextType);
+    Text::Controller::UpdateTextType  updateTextType);
 
   /**
    * Common method to synchronize TextAnchor actors with Anchor objects in text's logical model.
@@ -76,6 +78,16 @@ public:
     Actor                             parent,
     Text::ControllerPtr               controller,
     std::vector<Toolkit::TextAnchor>& anchorActors);
+
+  /**
+   * @brief Gets the bounding box of a specific text range.
+   *
+   * @param[in] model pointer to the text model.
+   * @param[in] startIndex start index of the text requested to get bounding box to.
+   * @param[in] endIndex end index(included) of the text requested to get bounding box to.
+   * @return bounding box of the requested text.
+   */
+  static Rect<> GetTextBoundingRectangle(Text::ModelPtr model, TextAbstraction::CharacterIndex startIndex, TextAbstraction::CharacterIndex endIndex);
 };
 
 class TextControlAccessible : public DevelControl::ControlAccessible,
index 2bc12b01a30509d4da515b6fbc55ccef977a03cb..fd6db2b9fcbbb2a8f7efc775911b134655306927 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -26,6 +26,7 @@
 #include <dali/public-api/object/type-registry-helper.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
 
 // DEVEL INCLUDES
 #include <dali-toolkit/devel-api/controls/control-devel.h>
index 7884e7b76ebc3cd91ecc343eb8044f6d0aa0e64a..a19e90b38abfc5ce2bbdc49bdd18311f18c56a7a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -70,7 +70,7 @@ const unsigned int DEFAULT_RENDERING_BACKEND = Dali::Toolkit::DevelText::DEFAULT
  * The alignment depends on the alignment value of the text label (Use Text::VerticalAlignment enumerations).
  */
 const float VERTICAL_ALIGNMENT_TABLE[Text::VerticalAlignment::BOTTOM + 1] =
-{
+  {
     0.0f, // VerticalAlignment::TOP
     0.5f, // VerticalAlignment::CENTER
     1.0f  // VerticalAlignment::BOTTOM
@@ -88,7 +88,7 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT
 #endif
 
 const Scripting::StringEnum AUTO_SCROLL_STOP_MODE_TABLE[] =
-{
+  {
     {"IMMEDIATE", Toolkit::TextLabel::AutoScrollStopMode::IMMEDIATE},
     {"FINISH_LOOP", Toolkit::TextLabel::AutoScrollStopMode::FINISH_LOOP},
 };
@@ -1030,12 +1030,6 @@ void TextLabel::OnPropertySet(Property::Index index, const Property::Value& prop
       }
       break;
     }
-    case Toolkit::TextLabel::Property::TEXT:
-    case Toolkit::TextLabel::Property::ENABLE_MARKUP:
-    {
-      CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
-      break;
-    }
     default:
     {
       Control::OnPropertySet(index, propertyValue); // up call to control for non-handled properties
@@ -1153,6 +1147,11 @@ void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container)
       SetUpAutoScrolling();
     }
 
+    if(Dali::Accessibility::IsUp())
+    {
+      CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
+    }
+
     mTextUpdateNeeded = false;
   }
 
index 5e338bb07571be75d8d392a8e769eecc3b03c5d7..263f87354ada5b75a00f27713a852397c13c838c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
 #include <cmath>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
-#include <dali-toolkit/internal/text/cursor-helper-functions.h>
-#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
-#include <dali-toolkit/internal/text/text-control-interface.h>
 #include <dali-toolkit/internal/text/controller/text-controller-impl-data-clearer.h>
 #include <dali-toolkit/internal/text/controller/text-controller-impl-event-handler.h>
 #include <dali-toolkit/internal/text/controller/text-controller-impl-model-updater.h>
 #include <dali-toolkit/internal/text/controller/text-controller-placeholder-handler.h>
 #include <dali-toolkit/internal/text/controller/text-controller-relayouter.h>
+#include <dali-toolkit/internal/text/cursor-helper-functions.h>
+#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
+#include <dali-toolkit/internal/text/text-control-interface.h>
 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
 #include <dali-toolkit/internal/text/text-run-container.h>
@@ -481,14 +482,14 @@ void Controller::Impl::UpdateAnchorColor()
       if(mModel->mLogicalModel->mColorRuns.Count() > anchor.colorRunIndex)
       {
         ColorRun& colorRun = *(mModel->mLogicalModel->mColorRuns.Begin() + anchor.colorRunIndex);
-        colorRun.color = mAnchorColor;
-        updateNeeded = true;
+        colorRun.color     = mAnchorColor;
+        updateNeeded       = true;
       }
       if(mModel->mLogicalModel->mUnderlinedCharacterRuns.Count() > anchor.underlinedCharacterRunIndex)
       {
         UnderlinedCharacterRun& underlineRun = *(mModel->mLogicalModel->mUnderlinedCharacterRuns.Begin() + anchor.underlinedCharacterRunIndex);
-        underlineRun.properties.color = mAnchorColor;
-        updateNeeded = true;
+        underlineRun.properties.color        = mAnchorColor;
+        updateNeeded                         = true;
       }
     }
     else if(!anchor.isMarkupClickedColorSet && anchor.isClicked)
@@ -496,14 +497,14 @@ void Controller::Impl::UpdateAnchorColor()
       if(mModel->mLogicalModel->mColorRuns.Count() > anchor.colorRunIndex)
       {
         ColorRun& colorRun = *(mModel->mLogicalModel->mColorRuns.Begin() + anchor.colorRunIndex);
-        colorRun.color = mAnchorClickedColor;
-        updateNeeded = true;
+        colorRun.color     = mAnchorClickedColor;
+        updateNeeded       = true;
       }
       if(mModel->mLogicalModel->mUnderlinedCharacterRuns.Count() > anchor.underlinedCharacterRunIndex)
       {
         UnderlinedCharacterRun& underlineRun = *(mModel->mLogicalModel->mUnderlinedCharacterRuns.Begin() + anchor.underlinedCharacterRunIndex);
-        underlineRun.properties.color = mAnchorClickedColor;
-        updateNeeded = true;
+        underlineRun.properties.color        = mAnchorClickedColor;
+        updateNeeded                         = true;
       }
     }
   }
@@ -1376,7 +1377,7 @@ CharacterIndex Controller::Impl::CalculateNewCursorIndex(CharacterIndex index) c
   else
   {
     Length textLength = mModel->mVisualModel->mCharactersToGlyph.Count();
-    cursorIndex = cursorIndex + numberOfCharacters > textLength ? textLength : cursorIndex + numberOfCharacters;
+    cursorIndex       = cursorIndex + numberOfCharacters > textLength ? textLength : cursorIndex + numberOfCharacters;
   }
 
   // Will update the cursor hook position.
@@ -1653,16 +1654,16 @@ bool Controller::Impl::IsScrollable(const Vector2& displacement)
   {
     const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
     const bool isVerticalScrollEnabled   = mEventData->mDecorator->IsVerticalScrollEnabled();
-    if(isHorizontalScrollEnabled ||isVerticalScrollEnabled)
+    if(isHorizontalScrollEnabled || isVerticalScrollEnabled)
     {
-      const Vector2& targetSize = mModel->mVisualModel->mControlSize;
-      const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
+      const Vector2& targetSize     = mModel->mVisualModel->mControlSize;
+      const Vector2& layoutSize     = mModel->mVisualModel->GetLayoutSize();
       const Vector2& scrollPosition = mModel->mScrollPosition;
 
       if(isHorizontalScrollEnabled)
       {
         const float displacementX = displacement.x;
-        const float positionX = scrollPosition.x + displacementX;
+        const float positionX     = scrollPosition.x + displacementX;
         if(layoutSize.width > targetSize.width && -positionX > 0.f && -positionX < layoutSize.width - targetSize.width)
         {
           isScrollable = true;
@@ -1672,7 +1673,7 @@ bool Controller::Impl::IsScrollable(const Vector2& displacement)
       if(isVerticalScrollEnabled)
       {
         const float displacementY = displacement.y;
-        const float positionY = scrollPosition.y + displacementY;
+        const float positionY     = scrollPosition.y + displacementY;
         if(layoutSize.height > targetSize.height && -positionY > 0 && -positionY < layoutSize.height - targetSize.height)
         {
           isScrollable = true;
@@ -1695,27 +1696,14 @@ float Controller::Impl::GetVerticalScrollPosition()
   return mEventData ? -mModel->mScrollPosition.y : 0.0f;
 }
 
-Vector3 Controller::Impl::GetAnchorPosition(Anchor anchor) const
-{
-  //TODO
-  return Vector3(10.f, 10.f, 10.f);
-}
-
-Vector2 Controller::Impl::GetAnchorSize(Anchor anchor) const
-{
-  //TODO
-  return Vector2(10.f, 10.f);
-}
-
 Toolkit::TextAnchor Controller::Impl::CreateAnchorActor(Anchor anchor)
 {
   auto actor = Toolkit::TextAnchor::New();
   actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
   actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
-  const Vector3 anchorPosition = GetAnchorPosition(anchor);
-  actor.SetProperty(Actor::Property::POSITION, anchorPosition);
-  const Vector2 anchorSize = GetAnchorSize(anchor);
-  actor.SetProperty(Actor::Property::SIZE, anchorSize);
+  auto rect = Toolkit::Internal::CommonTextUtils::GetTextBoundingRectangle(mModel, anchor.startIndex, anchor.endIndex - 1);
+  actor.SetProperty(Actor::Property::POSITION, Vector2(rect.x, rect.y));
+  actor.SetProperty(Actor::Property::SIZE, Vector2(rect.width, rect.height));
 
   std::string anchorText;
   std::string anchorHref               = anchor.href ? anchor.href : "";
index ef8b78c397a974bf9da2c5d2cefcdc044b6e8726..f9615d147596b8482cb8cf8921367632a1e8d13f 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_TEXT_CONTROLLER_IMPL_H
 
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -25,8 +25,8 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/styling/style-manager-devel.h>
-#include <dali-toolkit/internal/text/input-style.h>
 #include <dali-toolkit/internal/text/controller/text-controller.h>
+#include <dali-toolkit/internal/text/input-style.h>
 #include <dali-toolkit/internal/text/text-model.h>
 #include <dali-toolkit/internal/text/text-view.h>
 #include <dali-toolkit/public-api/styling/style-manager.h>
@@ -958,24 +958,6 @@ struct Controller::Impl
    */
   int32_t GetAnchorIndex(size_t characterOffset) const;
 
-  /**
-   * @brief Return the geometrical position of an anchor relative to the parent origin point.
-   *
-   * @param[in] anchor An anchor.
-   *
-   * @return The x, y, z coordinates of an anchor.
-   */
-  Vector3 GetAnchorPosition(Anchor anchor) const;
-
-  /**
-   * @brief Return the size of an anchor expresed as a vector containing anchor's width and height.
-   *
-   * @param[in] anchor An anchor.
-   *
-   * @return The width and height of an anchor.
-   */
-  Vector2 GetAnchorSize(Anchor anchor) const;
-
   /**
    * @brief Return the actor representing an anchor.
    *
index b7f19a679f977fe55484f4db83dabc5217efd006..984cc76c3a61a3fb6e467db6ba9c3d78bb521532 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 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.
@@ -28,6 +28,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/text/text-enumerations-devel.h>
+#include <dali-toolkit/internal/controls/text-controls/common-text-utils.h>
 #include <dali-toolkit/internal/text/controller/text-controller-background-actor.h>
 #include <dali-toolkit/internal/text/controller/text-controller-event-handler.h>
 #include <dali-toolkit/internal/text/controller/text-controller-impl.h>
@@ -1456,41 +1457,7 @@ Vector<Vector2> Controller::GetTextPosition(CharacterIndex startIndex, Character
 
 Rect<> Controller::GetTextBoundingRectangle(CharacterIndex startIndex, CharacterIndex endIndex)
 {
-  Vector<Vector2> sizeList;
-  Vector<Vector2> positionList;
-
-  GetTextGeometry(mImpl->mModel, startIndex, endIndex, sizeList, positionList);
-
-  if(sizeList.Empty() || sizeList.Size() != positionList.Size())
-  {
-    return {0, 0, 0, 0};
-  }
-
-  auto controlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
-  auto minX         = positionList[0].x;
-  auto minY         = positionList[0].y;
-  auto maxRight     = positionList[0].x + sizeList[0].x;
-  auto maxBottom    = positionList[0].y + sizeList[0].y;
-
-  for(unsigned int i = 1; i < sizeList.Size(); i++)
-  {
-    minX      = std::min(minX, positionList[i].x);
-    minY      = std::min(minY, positionList[i].y);
-    maxRight  = std::max(maxRight, positionList[i].x + sizeList[i].x);
-    maxBottom = std::max(maxBottom, positionList[i].y + sizeList[i].y);
-  }
-
-  if(minX < 0.0f)
-  {
-    minX = 0.0f;
-  }
-
-  if(maxRight > controlWidth)
-  {
-    maxRight = controlWidth;
-  }
-
-  return {minX, minY, maxRight - minX, maxBottom - minY};
+  return Toolkit::Internal::CommonTextUtils::GetTextBoundingRectangle(mImpl->mModel, startIndex, endIndex);
 }
 
 bool Controller::IsInputStyleChangedSignalsQueueEmpty()