Merge "[AT-SPI] text: add "GetRangeExtents" interface" into devel/master
authorShinwoo Kim <cinoo.kim@samsung.com>
Thu, 10 Mar 2022 01:36:03 +0000 (01:36 +0000)
committerGerrit Code Review <gerrit@review>
Thu, 10 Mar 2022 01:36:03 +0000 (01:36 +0000)
automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.h
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h

index ab7f8bf..073138a 100644 (file)
@@ -199,6 +199,59 @@ int utcDaliAccessibilityTextEditorRemoveSelection(void)
   END_TEST;
 }
 
+int utcDaliAccessibilityTextEditorGetRangeExtents(void)
+{
+  ToolkitTestApplication application;
+
+  auto editor = Dali::Toolkit::TextEditor::New();
+  auto q     = Dali::Accessibility::Accessible::Get( editor );
+  auto x     = dynamic_cast< Dali::Accessibility::Text* >( q );
+  DALI_TEST_CHECK( x );
+
+  if( x )
+  {
+    auto rangeExtents = x->GetRangeExtents( 0, 0, Dali::Accessibility::CoordinateType::WINDOW );
+    DALI_TEST_EQUALS( (int)rangeExtents.x, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.y, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.width, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.height, 0, TEST_LOCATION );
+
+    application.GetScene().Add( editor );
+
+    editor.SetProperty( Toolkit::TextEditor::Property::POINT_SIZE, 7.f );
+    editor.SetProperty( Actor::Property::SIZE, Vector2(200.f, 200.f) );
+    editor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+    editor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+    editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "text editor test sentence" );
+
+    // Avoid a crash when core load gl resources.
+    application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
+
+    // Render and notify
+    application.SendNotification();
+    application.Render();
+
+    auto characterCount = x->GetCharacterCount();
+    rangeExtents        = x->GetRangeExtents( 0, characterCount, Dali::Accessibility::CoordinateType::WINDOW );
+
+    Vector<Vector2> positionList = Toolkit::DevelTextEditor::GetTextPosition(editor, 0, characterCount);
+    Vector<Vector2> sizeList     = Toolkit::DevelTextEditor::GetTextSize(editor, 0, characterCount);
+
+    DALI_TEST_EQUALS(positionList.Size() == sizeList.Size(), true, TEST_LOCATION);
+
+    unsigned int sizeListSize = sizeList.Size();
+    for(unsigned int i = 0; i < sizeListSize; i++)
+    {
+      DALI_TEST_EQUALS((int)positionList[i].x >= rangeExtents.x, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)positionList[i].y >= rangeExtents.y, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)sizeList[i].x <= rangeExtents.width, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)sizeList[i].y <= rangeExtents.height, true, TEST_LOCATION);
+    }
+  }
+
+  END_TEST;
+}
+
 int utcDaliAccessibilityTextFieldGetName(void)
 {
   ToolkitTestApplication application;
@@ -390,6 +443,59 @@ int utcDaliAccessibilityTextFieldRemoveSelection(void)
   END_TEST;
 }
 
+int utcDaliAccessibilityTextFieldGetRangeExtents(void)
+{
+  ToolkitTestApplication application;
+
+  auto field = Dali::Toolkit::TextField::New();
+  auto q     = Dali::Accessibility::Accessible::Get( field );
+  auto x     = dynamic_cast< Dali::Accessibility::Text* >( q );
+  DALI_TEST_CHECK( x );
+
+  if( x )
+  {
+    auto rangeExtents = x->GetRangeExtents( 0, 0, Dali::Accessibility::CoordinateType::WINDOW );
+    DALI_TEST_EQUALS( (int)rangeExtents.x, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.y, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.width, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.height, 0, TEST_LOCATION );
+
+    application.GetScene().Add( field );
+
+    field.SetProperty( Toolkit::TextField::Property::POINT_SIZE, 7.f );
+    field.SetProperty( Actor::Property::SIZE, Vector2(200.f, 200.f) );
+    field.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+    field.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+    field.SetProperty( Toolkit::TextField::Property::TEXT, "text field test sentence" );
+
+    // Avoid a crash when core load gl resources.
+    application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
+
+    // Render and notify
+    application.SendNotification();
+    application.Render();
+
+    auto characterCount = x->GetCharacterCount();
+    rangeExtents        = x->GetRangeExtents( 0, characterCount, Dali::Accessibility::CoordinateType::WINDOW );
+
+    Vector<Vector2> positionList = Toolkit::DevelTextField::GetTextPosition(field, 0, characterCount);
+    Vector<Vector2> sizeList     = Toolkit::DevelTextField::GetTextSize(field, 0, characterCount);
+
+    DALI_TEST_EQUALS(positionList.Size() == sizeList.Size(), true, TEST_LOCATION);
+
+    unsigned int sizeListSize = sizeList.Size();
+    for(unsigned int i = 0; i < sizeListSize; i++)
+    {
+      DALI_TEST_EQUALS((int)positionList[i].x >= rangeExtents.x, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)positionList[i].y >= rangeExtents.y, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)sizeList[i].x <= rangeExtents.width, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)sizeList[i].y <= rangeExtents.height, true, TEST_LOCATION);
+    }
+  }
+
+  END_TEST;
+}
+
 int utcDaliAccessibilityTextLabelGetName(void)
 {
   ToolkitTestApplication application;
@@ -520,3 +626,57 @@ int utcDaliAccessibilityTextLabelRemoveSelection( void )
 
   END_TEST;
 }
+
+int utcDaliAccessibilityTextLabelGetRangeExtents(void)
+{
+  ToolkitTestApplication application;
+
+  auto label = Dali::Toolkit::TextLabel::New();
+  auto q     = Dali::Accessibility::Accessible::Get( label );
+  auto x     = dynamic_cast< Dali::Accessibility::Text* >( q );
+  DALI_TEST_CHECK( x );
+
+  if( x )
+  {
+    auto rangeExtents = x->GetRangeExtents( 0, 0, Dali::Accessibility::CoordinateType::WINDOW );
+    DALI_TEST_EQUALS( (int)rangeExtents.x, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.y, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.width, 0, TEST_LOCATION );
+    DALI_TEST_EQUALS( (int)rangeExtents.height, 0, TEST_LOCATION );
+
+    application.GetScene().Add( label );
+
+    label.SetProperty( Toolkit::TextLabel::Property::POINT_SIZE, 7.f );
+    label.SetProperty( Toolkit::TextLabel::Property::MULTI_LINE, true );
+    label.SetProperty( Actor::Property::SIZE, Vector2(200.f, 200.f) );
+    label.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+    label.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+    label.SetProperty( Toolkit::TextLabel::Property::TEXT, "text label\n test sentence" );
+
+    // Avoid a crash when core load gl resources.
+    application.GetGlAbstraction().SetCheckFramebufferStatusResult(GL_FRAMEBUFFER_COMPLETE);
+
+    // Render and notify
+    application.SendNotification();
+    application.Render();
+
+    auto characterCount = x->GetCharacterCount();
+    rangeExtents        = x->GetRangeExtents( 0, characterCount, Dali::Accessibility::CoordinateType::WINDOW );
+
+    Vector<Vector2> positionList = Toolkit::DevelTextLabel::GetTextPosition(label, 0, characterCount);
+    Vector<Vector2> sizeList     = Toolkit::DevelTextLabel::GetTextSize(label, 0, characterCount);
+
+    DALI_TEST_EQUALS(positionList.Size() == sizeList.Size(), true, TEST_LOCATION);
+
+    unsigned int sizeListSize = sizeList.Size();
+    for(unsigned int i = 0; i < sizeListSize; i++)
+    {
+      DALI_TEST_EQUALS((int)positionList[i].x >= rangeExtents.x, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)positionList[i].y >= rangeExtents.y, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)sizeList[i].x <= rangeExtents.width, true, TEST_LOCATION);
+      DALI_TEST_EQUALS((int)sizeList[i].y <= rangeExtents.height, true, TEST_LOCATION);
+    }
+  }
+
+  END_TEST;
+}
index 6fc1a3d..6202c8f 100644 (file)
@@ -1537,6 +1537,24 @@ bool TextEditor::AccessibleImpl::SetRangeOfSelection(size_t selectionIndex, size
   return true;
 }
 
+Rect<> TextEditor::AccessibleImpl::GetRangeExtents(size_t startOffset, size_t endOffset, Accessibility::CoordinateType type)
+{
+  if (endOffset <= startOffset || endOffset <= 0)
+  {
+    return {0, 0, 0, 0};
+  }
+
+  auto self = Toolkit::TextEditor::DownCast(Self());
+  auto rect = Dali::Toolkit::GetImpl(self).GetTextController()->GetTextBoundingRectangle(startOffset, endOffset - 1);
+
+  auto componentExtents = this->GetExtents(type);
+
+  rect.x += componentExtents.x;
+  rect.y += componentExtents.y;
+
+  return rect;
+}
+
 bool TextEditor::AccessibleImpl::CopyText(size_t startPosition, size_t endPosition)
 {
   if(endPosition <= startPosition)
index a2521ed..8a96a13 100644 (file)
@@ -629,6 +629,11 @@ private: // Data
     bool SetRangeOfSelection(size_t selectionIndex, size_t startOffset, size_t endOffset) override;
 
     /**
+     * @copydoc Dali::Accessibility::Text::GetRangeExtents()
+     */
+    Rect<> GetRangeExtents(size_t startOffset, size_t endOffset, Accessibility::CoordinateType type) override;
+
+    /**
      * @copydoc Dali::Accessibility::EditableText::CopyText()
      */
     bool CopyText(size_t startPosition, size_t endPosition) override;
index f0d6c68..35d06ea 100644 (file)
@@ -1404,6 +1404,24 @@ bool TextField::AccessibleImpl::SetRangeOfSelection(size_t selectionIndex, size_
   return true;
 }
 
+Rect<> TextField::AccessibleImpl::GetRangeExtents(size_t startOffset, size_t endOffset, Accessibility::CoordinateType type)
+{
+  if (endOffset <= startOffset || endOffset <= 0)
+  {
+    return {0, 0, 0, 0};
+  }
+
+  auto self = Toolkit::TextField::DownCast(Self());
+  auto rect = Dali::Toolkit::GetImpl(self).GetTextController()->GetTextBoundingRectangle(startOffset, endOffset - 1);
+
+  auto componentExtents = this->GetExtents(type);
+
+  rect.x += componentExtents.x;
+  rect.y += componentExtents.y;
+
+  return rect;
+}
+
 bool TextField::AccessibleImpl::CopyText(size_t startPosition, size_t endPosition)
 {
   if(endPosition <= startPosition)
index 3ba2954..c10dd51 100644 (file)
@@ -578,6 +578,11 @@ protected:
     bool SetRangeOfSelection(size_t selectionIndex, size_t startOffset, size_t endOffset) override;
 
     /**
+     * @copydoc Dali::Accessibility::Text::GetRangeExtents()
+     */
+    Rect<> GetRangeExtents(size_t startOffset, size_t endOffset, Accessibility::CoordinateType type) override;
+
+    /**
      * @copydoc Dali::Accessibility::EditableText::CopyText()
      */
     bool CopyText(size_t startPosition, size_t endPosition) override;
index 10b05a0..fa9c6c0 100644 (file)
@@ -1379,6 +1379,24 @@ bool TextLabel::AccessibleImpl::SetRangeOfSelection(size_t selectionIndex, size_
   return true;
 }
 
+Rect<> TextLabel::AccessibleImpl::GetRangeExtents(size_t startOffset, size_t endOffset, Accessibility::CoordinateType type)
+{
+  if (endOffset <= startOffset || endOffset <= 0)
+  {
+    return {0, 0, 0, 0};
+  }
+
+  auto self = Toolkit::TextLabel::DownCast(Self());
+  auto rect = Dali::Toolkit::GetImpl(self).GetTextController()->GetTextBoundingRectangle(startOffset, endOffset - 1);
+
+  auto componentExtents = this->GetExtents(type);
+
+  rect.x += componentExtents.x;
+  rect.y += componentExtents.y;
+
+  return rect;
+}
+
 int32_t TextLabel::AccessibleImpl::GetLinkCount() const
 {
   auto self = Toolkit::TextLabel::DownCast(Self());
index 978ad97..9cba1c4 100644 (file)
@@ -293,6 +293,11 @@ protected:
     bool SetRangeOfSelection(size_t selectionIndex, size_t startOffset, size_t endOffset) override;
 
     /**
+     * @copydoc Dali::Accessibility::Text::GetRangeExtents()
+     */
+    Rect<> GetRangeExtents(size_t startOffset, size_t endOffset, Accessibility::CoordinateType type) override;
+
+    /**
      * @copydoc Dali::Accessibility::Text::GetNameRaw()
      */
     std::string GetNameRaw() const override;
index 9de7dba..b0f740d 100644 (file)
@@ -1391,6 +1391,34 @@ Vector<Vector2> Controller::GetTextPosition(CharacterIndex startIndex, Character
   return positionsList;
 }
 
+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 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);
+  }
+
+  return {minX, minY, maxRight - minX, maxBottom - minY};
+}
+
 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
 {
   return mImpl->IsInputStyleChangedSignalsQueueEmpty();
index 2a37c3b..81a0318 100644 (file)
@@ -1696,6 +1696,15 @@ public: // Queries & retrieves.
   Vector<Vector2> GetTextPosition(CharacterIndex startIndex, CharacterIndex endIndex);
 
   /**
+   * @brief Gets the bounding box of a specific text range.
+   *
+   * @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.
+   */
+  Rect<> GetTextBoundingRectangle(CharacterIndex startIndex, CharacterIndex endIndex);
+
+  /**
    * @brief Sets the layout direction changed.
    */
   void ChangedLayoutDirection();