Fix text label anchor extents 37/324937/2
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 06:51:12 +0000 (15:51 +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 d12660fd50e7859972bcc1ad11562a6bdf1d4c5f..adae0d368575f1c06b3b5e5f4325d51fa180355e 100644 (file)
@@ -1017,6 +1017,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);
 
@@ -1053,7 +1056,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);
@@ -1062,8 +1065,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 b18cb98047068de79f819b5755f74ff9d36b4c7b..7060eb2d2ddeea8f47fa707e7e376185f929aee3 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,
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 0c27fadd537a62b03a796e963270b1dcc869ac85..dee04364cd8aa504402989c576683c7b96b6bbcd 100644 (file)
@@ -1319,12 +1319,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;
-    }
     case Toolkit::Control::Property::BACKGROUND:
     {
       if(mController->IsTextCutout())
@@ -1577,6 +1571,11 @@ void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container)
       SetUpAutoScrolling();
     }
 
+    if(Dali::Accessibility::IsUp())
+    {
+      CommonTextUtils::SynchronizeTextAnchorsInParent(Self(), mController, mAnchorActors);
+    }
+
     mTextUpdateNeeded = false;
   }
 
index 20aeb95bb09f117590b820bea66429e5d255ca35..2f972c8f0278eceb4592b8a17038d80b9b27850f 100644 (file)
@@ -26,6 +26,7 @@
 #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/controller/text-controller-impl-data-clearer.h>
 #include <dali-toolkit/internal/text/controller/text-controller-impl-event-handler.h>
@@ -1732,27 +1733,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 a538a509fb477e4951b58b526ae11643a2f52114..edecbbbec1afe4675b34959d960aa75b7f37bf0e 100644 (file)
@@ -987,24 +987,6 @@ public:
    */
   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 89e25471d851ee1a8b7faf477547e0607ac7936b..983453b3653311f24b578baf39962e1fe124f7f5 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.
@@ -29,6 +29,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>
@@ -40,6 +41,7 @@
 #include <dali-toolkit/internal/text/controller/text-controller-text-updater.h>
 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
 #include <dali-toolkit/internal/text/text-geometry.h>
+
 namespace
 {
 #if defined(DEBUG_ENABLED)
@@ -1693,41 +1695,7 @@ int Controller::GetCharacterIndexAtPosition(float visualX, float visualY)
 
 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()