Prevent revisiting nodes in GetMatches* 79/318379/4
authorYoungsun Suh <youngsun.suh@samsung.com>
Fri, 27 Sep 2024 08:20:19 +0000 (17:20 +0900)
committerYoungsun Suh <youngsun.suh@samsung.com>
Sun, 29 Sep 2024 23:41:58 +0000 (08:41 +0900)
Change-Id: I55c93244b1c4e1804c7e00baaca4fcf44d404718

dali/devel-api/atspi-interfaces/collection.h
dali/internal/accessibility/bridge/bridge-collection.cpp
dali/internal/accessibility/bridge/bridge-collection.h
dali/internal/accessibility/bridge/collection.cpp [new file with mode: 0644]
dali/internal/accessibility/file.list

index 7a8407957941494207824715ac327bebc4974e2d..369eae1482ea08c632259f317f4b84b78c10b14e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_ADAPTOR_ATSPI_COLLECTION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -30,6 +30,21 @@ namespace Dali::Accessibility
  */
 class DALI_ADAPTOR_API Collection : public virtual Accessible
 {
+public:
+  /**
+   * MatchRule type is a tuple that only carries data of de-serialized parameter from BridgeCollection::GetMatches dbus method.
+   */
+  using MatchRule = std::tuple<
+    std::array<int32_t, 2>,
+    int32_t,
+    std::unordered_map<std::string, std::string>,
+    int32_t,
+    std::array<int32_t, 4>,
+    int32_t,
+    std::vector<std::string>,
+    int32_t,
+    bool>;
+
   /**
    * @brief Downcasts an Accessible to a Collection.
    *
@@ -39,6 +54,28 @@ class DALI_ADAPTOR_API Collection : public virtual Accessible
    * @see Dali::Accessibility::Accessible::DownCast()
    */
   static inline Collection* DownCast(Accessible* obj);
+
+  /**
+   * @brief Gets the matching Accessible objects with MatchRule.
+   *
+   * @param[in] rule Collection::MatchRule
+   * @param[in] sortBy SortOrder::CANONICAL or SortOrder::REVERSE_CANONICAL
+   * @param[in] maxCount The maximum number of objects; returns all matches if 0
+   * @return The matching Accessible objects
+   */
+  std::vector<Accessible*> GetMatches(MatchRule rule, uint32_t sortBy, size_t maxCount);
+
+  /**
+   * @brief Gets the matching Accessible objects with two MatchRules.
+   *
+   * @param[in] firstRule The initial Collection::MatchRule.
+   * @param[in] secondRule An secondary Collection::MatchRule.
+   * @param[in] sortBy SortOrder::CANONICAL or SortOrder::REVERSE_CANONICAL
+   * @param[in] firstCount The maximum number of objects to return for the initial match.; returns all matches if 0
+   * @param[in] secondCount The maximum number of objects to return for the secondary match.; returns all matches if 0
+   * @return The matching Accessible objects
+   */
+  std::vector<Accessible*> GetMatchesInMatches(MatchRule firstRule, MatchRule secondRule, uint32_t sortBy, int32_t firstCount, int32_t secondCount);
 };
 
 namespace Internal
index 20111301dbf2d4cff647cbe525d5fcdfc25ea242..c7aaa1cfddf0d93dca6927775396253f10bc8508 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
 
 using namespace Dali::Accessibility;
 
-namespace
-{
-/**
- * @brief Enumeration used for quering Accessibility objects.
- *
- * Refer to MatchType enumeration.
- */
-enum class AtspiCollection
-{
-  MATCH_INVALID,
-  MATCH_ALL,
-  MATCH_ANY,
-  MATCH_NONE,
-  MATCH_EMPTY,
-  MATCH_LAST_DEFINED,
-};
-} // anonymous namespace
-
 void BridgeCollection::RegisterInterfaces()
 {
   DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::COLLECTION)};
@@ -57,513 +39,22 @@ Collection* BridgeCollection::FindSelf() const
   return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::COLLECTION>();
 }
 
-/**
- * @brief The BridgeCollection::Comparer structure.
- *
- * Once the data is de-serialized by DBusWrapper, the data of match rule is passed
- * to Comparer type which do the comparison against a single accessible object.
- */
-struct BridgeCollection::Comparer
+DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatches(Collection::MatchRule rule, uint32_t sortBy, int32_t count, bool traverse)
 {
-  using Mode = MatchType;
-
-  /**
-   * @brief Enumeration to check the object is found first.
-   */
-  enum class CompareFuncExit
+  if(auto collection = FindSelf())
   {
-    FIRST_FOUND,
-    FIRST_NOT_FOUND
-  };
-
-  static Mode ConvertToMatchType(int32_t mode)
-  {
-    switch(mode)
-    {
-      case static_cast<int32_t>(AtspiCollection::MATCH_INVALID):
-      {
-        return Mode::INVALID;
-      }
-      case static_cast<int32_t>(AtspiCollection::MATCH_ALL):
-      {
-        return Mode::ALL;
-      }
-      case static_cast<int32_t>(AtspiCollection::MATCH_ANY):
-      {
-        return Mode::ANY;
-      }
-      case static_cast<int32_t>(AtspiCollection::MATCH_NONE):
-      {
-        return Mode::NONE;
-      }
-      case static_cast<int32_t>(AtspiCollection::MATCH_EMPTY):
-      {
-        return Mode::EMPTY;
-      }
-    }
-    return Mode::INVALID;
+    return collection->GetMatches(std::move(rule), sortBy, count);
   }
 
-  /**
-   * @brief The ComparerInterfaces structure
-   */
-  struct ComparerInterfaces
-  {
-    std::unordered_set<std::string> mObject;
-    std::vector<std::string>        mRequested;
-    Mode                            mMode = Mode::INVALID;
-
-    ComparerInterfaces(MatchRule* rule)
-    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::INTERFACES_MATCH_TYPE)>(*rule)))
-    {
-      mRequested = {std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).begin(), std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).end()};
-    }
-
-    void Update(Accessible* obj)
-    {
-      mObject.clear();
-      for(auto& interface : obj->GetInterfacesAsStrings())
-      {
-        mObject.insert(std::move(interface));
-      }
-    }
-
-    bool IsRequestEmpty() const
-    {
-      return mRequested.empty();
-    }
-
-    bool IsObjectEmpty() const
-    {
-      return mObject.empty();
-    }
-
-    bool Compare(CompareFuncExit exit)
-    {
-      bool foundAny = false;
-      for(auto& iname : mRequested)
-      {
-        bool found = (mObject.find(iname) != mObject.end());
-        if(found)
-        {
-          foundAny = true;
-        }
-
-        if(found == (exit == CompareFuncExit::FIRST_FOUND))
-        {
-          return found;
-        }
-      }
-      return foundAny;
-    }
-  }; // ComparerInterfaces struct
-
-  /**
-   * @brief The ComparerAttributes structure
-   */
-  struct ComparerAttributes
-  {
-    std::unordered_map<std::string, std::string> mRequested;
-    std::unordered_map<std::string, std::string> mObject;
-    Mode                                         mMode = Mode::INVALID;
-
-    ComparerAttributes(MatchRule* rule)
-    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ATTRIBUTES_MATCH_TYPE)>(*rule)))
-    {
-      mRequested = std::get<static_cast<std::size_t>(Index::ATTRIBUTES)>(*rule);
-    }
-
-    void Update(Accessible* obj)
-    {
-      mObject = obj->GetAttributes();
-    }
-
-    bool IsRequestEmpty() const
-    {
-      return mRequested.empty();
-    }
-
-    bool IsObjectEmpty() const
-    {
-      return mObject.empty();
-    }
-
-    bool Compare(CompareFuncExit exit)
-    {
-      bool foundAny = false;
-      for(auto& iname : mRequested)
-      {
-        auto it    = mObject.find(iname.first);
-        bool found = it != mObject.end() && iname.second == it->second;
-        if(found)
-        {
-          foundAny = true;
-        }
-
-        if(found == (exit == CompareFuncExit::FIRST_FOUND))
-        {
-          return found;
-        }
-      }
-      return foundAny;
-    }
-  }; // ComparerAttributes struct
-
-  /**
-   * @brief The ComparerRoles structure
-   */
-  struct ComparerRoles
-  {
-    using Roles = EnumBitSet<Role, Role::MAX_COUNT>;
-
-    Roles mRequested;
-    Roles mObject;
-    Mode  mMode = Mode::INVALID;
-
-    ComparerRoles(MatchRule* rule)
-    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ROLES_MATCH_TYPE)>(*rule)))
-    {
-      mRequested = Roles{std::get<static_cast<std::size_t>(Index::ROLES)>(*rule)};
-    }
-
-    void Update(Accessible* obj)
-    {
-      mObject                 = {};
-      mObject[obj->GetRole()] = true;
-      assert(mObject);
-    }
-
-    bool IsRequestEmpty() const
-    {
-      return !mRequested;
-    }
-
-    bool IsObjectEmpty() const
-    {
-      return !mObject;
-    }
-
-    bool Compare(CompareFuncExit exit)
-    {
-      switch(mMode)
-      {
-        case Mode::INVALID:
-        {
-          return true;
-        }
-        case Mode::EMPTY:
-        case Mode::ALL:
-        {
-          return mRequested == (mObject & mRequested);
-        }
-        case Mode::ANY:
-        {
-          return bool(mObject & mRequested);
-        }
-        case Mode::NONE:
-        {
-          return bool(mObject & mRequested);
-        }
-      }
-      return false;
-    }
-  }; // ComparerRoles struct
-
-  /**
-   * @brief The ComparerStates structure
-   */
-  struct ComparerStates
-  {
-    States mRequested;
-    States mObject;
-    Mode   mMode = Mode::INVALID;
-
-    ComparerStates(MatchRule* rule)
-    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::STATES_MATCH_TYPE)>(*rule)))
-    {
-      mRequested = States{std::get<static_cast<std::size_t>(Index::STATES)>(*rule)};
-    }
-
-    void Update(Accessible* obj)
-    {
-      mObject = obj->GetStates();
-    }
-
-    bool IsRequestEmpty() const
-    {
-      return !mRequested;
-    }
-
-    bool IsObjectEmpty() const
-    {
-      return !mObject;
-    }
-
-    bool Compare(CompareFuncExit exit)
-    {
-      switch(mMode)
-      {
-        case Mode::INVALID:
-        {
-          return true;
-        }
-        case Mode::EMPTY:
-        case Mode::ALL:
-        {
-          return mRequested == (mObject & mRequested);
-        }
-        case Mode::ANY:
-        {
-          return bool(mObject & mRequested);
-        }
-        case Mode::NONE:
-        {
-          return bool(mObject & mRequested);
-        }
-      }
-      return false;
-    }
-  }; // ComparerStates struct
-
-  template<typename T>
-  bool CompareFunc(T& cmp, Accessible* obj)
-  {
-    if(cmp.mMode == Mode::INVALID)
-    {
-      return true;
-    }
-
-    cmp.Update(obj);
-    switch(cmp.mMode)
-    {
-      case Mode::ANY:
-      {
-        if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
-        {
-          return false;
-        }
-        break;
-      }
-      case Mode::ALL:
-      {
-        if(cmp.IsRequestEmpty())
-        {
-          return true;
-        }
-        if(cmp.IsObjectEmpty())
-        {
-          return false;
-        }
-        break;
-      }
-      case Mode::NONE:
-      {
-        if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
-        {
-          return true;
-        }
-        break;
-      }
-      case Mode::EMPTY:
-      {
-        if(cmp.IsRequestEmpty() && cmp.IsObjectEmpty())
-        {
-          return true;
-        }
-        if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
-        {
-          return false;
-        }
-        break;
-      }
-      case Mode::INVALID:
-      {
-        return true;
-      }
-    }
-
-    switch(cmp.mMode)
-    {
-      case Mode::EMPTY:
-      case Mode::ALL:
-      {
-        if(!cmp.Compare(CompareFuncExit::FIRST_NOT_FOUND))
-        {
-          return false;
-        }
-        break;
-      }
-      case Mode::ANY:
-      {
-        if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
-        {
-          return true;
-        }
-        break;
-      }
-      case Mode::NONE:
-      {
-        if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
-        {
-          return false;
-        }
-        break;
-      }
-      case Mode::INVALID:
-      {
-        return true;
-      }
-    }
-
-    switch(cmp.mMode)
-    {
-      case Mode::EMPTY:
-      case Mode::ALL:
-      case Mode::NONE:
-      {
-        return true;
-      }
-      case Mode::ANY:
-      {
-        return false;
-      }
-      case Mode::INVALID:
-      {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  Comparer(MatchRule* rule)
-  : mInterface(rule),
-    mAttribute(rule),
-    mRole(rule),
-    mState(rule)
-  {
-  }
-
-  bool operator()(Accessible* obj)
-  {
-    return CompareFunc(mInterface, obj) &&
-           CompareFunc(mAttribute, obj) &&
-           CompareFunc(mRole, obj) &&
-           CompareFunc(mState, obj);
-  }
-
-  bool IsShowing(Accessible* obj)
-  {
-    if (mState.mMode == Mode::NONE) return true;
-    mState.Update(obj);
-    if (mState.IsRequestEmpty() || mState.IsObjectEmpty()) return true;
-    if (!mState.mRequested[State::SHOWING] ) return true;
-    if (mState.mObject[State::SHOWING]) return true;
-
-    return false;
-  }
-
-  ComparerInterfaces mInterface;
-  ComparerAttributes mAttribute;
-  ComparerRoles      mRole;
-  ComparerStates     mState;
-}; // BridgeCollection::Comparer struct
-
-
-void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& result, Comparer& comparer, size_t maxCount)
-{
-  if(maxCount > 0 && result.size() >= maxCount)
-  {
-    return;
-  }
-
-  if(comparer(obj))
-  {
-    result.emplace_back(obj);
-    // the code below will never return for maxCount equal 0
-    if(result.size() == maxCount)
-    {
-      return;
-    }
-  }
-
-  if (!comparer.IsShowing(obj))
-  {
-    return;
-  }
-
-  for(auto i = 0u; i < obj->GetChildCount(); ++i)
-  {
-    VisitNodes(obj->GetChildAtIndex(i), result, comparer, maxCount);
-  }
+  return {};
 }
 
-DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse)
+DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatchesInMatches(Collection::MatchRule firstRule, Collection::MatchRule secondRule, uint32_t sortBy, int32_t firstCount, int32_t secondCount, bool traverse)
 {
-  std::vector<Accessible*> res;
-  auto                     self    = BridgeBase::FindCurrentObject();
-  auto                     matcher = Comparer{&rule};
-  VisitNodes(self, res, matcher, count);
-
-  switch(static_cast<SortOrder>(sortBy))
+  if(auto collection = FindSelf())
   {
-    case SortOrder::CANONICAL:
-    {
-      break;
-    }
-
-    case SortOrder::REVERSE_CANONICAL:
-    {
-      std::reverse(res.begin(), res.end());
-      break;
-    }
-
-    default:
-    {
-      throw std::domain_error{"unsupported sorting order"};
-    }
-      //TODO: other cases
-  }
-
-  return res;
-}
-
-DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatchesInMatches(MatchRule firstRule, MatchRule secondRule, uint32_t sortBy, int32_t firstCount, int32_t secondCount, bool traverse)
-{
-  std::vector<Accessible*> res;
-  std::vector<Accessible*> firstRes;
-  std::vector<Accessible*> secondRes;
-  auto                     self          = BridgeBase::FindCurrentObject();
-  auto                     firstMatcher  = Comparer{&firstRule};
-  auto                     secondMatcher = Comparer{&secondRule};
-  VisitNodes(self, firstRes, firstMatcher, firstCount);
-
-  for (auto &obj : firstRes)
-  {
-    VisitNodes(obj, secondRes, secondMatcher, secondCount);
-
-    res.insert(res.end(), secondRes.begin(), secondRes.end());
-    secondRes.clear();
-  }
-
-  switch(static_cast<SortOrder>(sortBy))
-  {
-    case SortOrder::CANONICAL:
-    {
-      break;
-    }
-
-    case SortOrder::REVERSE_CANONICAL:
-    {
-      std::reverse(res.begin(), res.end());
-      break;
-    }
-
-    default:
-    {
-      throw std::domain_error{"unsupported sorting order"};
-    }
-      //TODO: other cases
+    return collection->GetMatchesInMatches(std::move(firstRule), std::move(secondRule), sortBy, firstCount, secondCount);
   }
 
-  return res;
+  return {};
 }
index 32ea9c15461106c0b57fb86ff13be4755389fdfe..234d7d3f4a4996dbbf333594cdca81e3dd347416 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
  */
 class BridgeCollection : public virtual BridgeBase
 {
-private:
-  struct Comparer;
-
-  /**
-   * @brief Visits all nodes of Accessible object and pushes the object to 'result' container.
-   *
-   * To query the entire tree, the BridgeCollection::Comparer is used inside this method,
-   * which traverse the tree using GetChildAtIndex().
-   * @param[in] obj The Accessible object to search
-   * @param[out] result The vector container for result
-   * @param[in] comparer BridgeCollection::Comparer which do the comparison against a single accessible object
-   * @param[in] maxCount The maximum count of containing Accessible object
-   */
-  static void VisitNodes(Dali::Accessibility::Accessible* obj, std::vector<Dali::Accessibility::Accessible*>& result, Comparer& comparer, size_t maxCount);
-
 protected:
   BridgeCollection() = default;
 
@@ -74,57 +59,14 @@ protected:
 
 public:
   /**
-   * MatchRule type is a tuple that only carries data of de-serialized parameter from BridgeCollection::GetMatches dbus method.
+   * @copydoc Dali::Accessibility::Collection::GetMatches()
    */
-  using MatchRule = std::tuple<
-    std::array<int32_t, 2>,
-    int32_t,
-    std::unordered_map<std::string, std::string>,
-    int32_t,
-    std::array<int32_t, 4>,
-    int32_t,
-    std::vector<std::string>,
-    int32_t,
-    bool>;
+  DBus::ValueOrError<std::vector<Dali::Accessibility::Accessible*> > GetMatches(Dali::Accessibility::Collection::MatchRule rule, uint32_t sortBy, int32_t count, bool traverse);
 
   /**
-   * @brief Enumeration for Collection Index.
-   */
-  enum class Index
-  {
-    STATES,
-    STATES_MATCH_TYPE,
-    ATTRIBUTES,
-    ATTRIBUTES_MATCH_TYPE,
-    ROLES,
-    ROLES_MATCH_TYPE,
-    INTERFACES,
-    INTERFACES_MATCH_TYPE,
-  };
-
-  /**
-   * @brief Gets the matching Accessible objects with MatchRule.
-   *
-   * @param[in] rule BridgeCollection::MatchRule
-   * @param[in] sortBy SortOrder::CANONICAL or SortOrder::REVERSE_CANONICAL
-   * @param[in] count The maximum number of objects
-   * @param[in] traverse True if it is traverse, otherwise false.
-   * @return The matching Accessible objects
-   */
-  DBus::ValueOrError<std::vector<Dali::Accessibility::Accessible*> > GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse);
-
-  /**
-   * @brief Gets the matching Accessible objects with two MatchRules.
-   *
-   * @param[in] firstRule The initial BridgeCollection::MatchRule.
-   * @param[in] secondRule An secondary BridgeCollection::MatchRule.
-   * @param[in] sortBy SortOrder::CANONICAL or SortOrder::REVERSE_CANONICAL
-   * @param[in] firstCount The maximum number of objects to return for the initial match.
-   * @param[in] secondCount The maximum number of objects to return for the secondary match.
-   * @param[in] traverse True if it is traverse, otherwise false.
-   * @return The matching Accessible objects
+   * @copydoc Dali::Accessibility::Collection::GetMatchesInMatches()
    */
-  DBus::ValueOrError<std::vector<Dali::Accessibility::Accessible*> > GetMatchesInMatches(MatchRule firstRule, MatchRule secondRule, uint32_t sortBy, int32_t firstCount, int32_t secondCount,  bool traverse);
+  DBus::ValueOrError<std::vector<Dali::Accessibility::Accessible*> > GetMatchesInMatches(Dali::Accessibility::Collection::MatchRule firstRule, Dali::Accessibility::Collection::MatchRule secondRule, uint32_t sortBy, int32_t firstCount, int32_t secondCount, bool traverse);
 };
 
 #endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H
diff --git a/dali/internal/accessibility/bridge/collection.cpp b/dali/internal/accessibility/bridge/collection.cpp
new file mode 100644 (file)
index 0000000..5835733
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2024 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
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <set>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/atspi-interfaces/collection.h>
+#include <dali/internal/accessibility/bridge/accessibility-common.h>
+
+using namespace Dali::Accessibility;
+
+namespace
+{
+using MatchRule = Collection::MatchRule;
+
+/**
+   * @brief Enumeration for Collection Index.
+   */
+enum class Index
+{
+  STATES,
+  STATES_MATCH_TYPE,
+  ATTRIBUTES,
+  ATTRIBUTES_MATCH_TYPE,
+  ROLES,
+  ROLES_MATCH_TYPE,
+  INTERFACES,
+  INTERFACES_MATCH_TYPE,
+};
+
+/**
+ * @brief Enumeration used for quering Accessibility objects.
+ *
+ * Refer to MatchType enumeration.
+ */
+enum class AtspiCollection
+{
+  MATCH_INVALID,
+  MATCH_ALL,
+  MATCH_ANY,
+  MATCH_NONE,
+  MATCH_EMPTY,
+  MATCH_LAST_DEFINED,
+};
+
+/**
+ * @brief The Comparer structure.
+ *
+ * Once the data is de-serialized by DBusWrapper, the data of match rule is passed
+ * to Comparer type which do the comparison against a single accessible object.
+ */
+struct Comparer
+{
+  using Mode = MatchType;
+
+  /**
+   * @brief Enumeration to check the object is found first.
+   */
+  enum class CompareFuncExit
+  {
+    FIRST_FOUND,
+    FIRST_NOT_FOUND
+  };
+
+  static Mode ConvertToMatchType(int32_t mode)
+  {
+    switch(mode)
+    {
+      case static_cast<int32_t>(AtspiCollection::MATCH_INVALID):
+      {
+        return Mode::INVALID;
+      }
+      case static_cast<int32_t>(AtspiCollection::MATCH_ALL):
+      {
+        return Mode::ALL;
+      }
+      case static_cast<int32_t>(AtspiCollection::MATCH_ANY):
+      {
+        return Mode::ANY;
+      }
+      case static_cast<int32_t>(AtspiCollection::MATCH_NONE):
+      {
+        return Mode::NONE;
+      }
+      case static_cast<int32_t>(AtspiCollection::MATCH_EMPTY):
+      {
+        return Mode::EMPTY;
+      }
+    }
+    return Mode::INVALID;
+  }
+
+  /**
+   * @brief The ComparerInterfaces structure
+   */
+  struct ComparerInterfaces
+  {
+    std::unordered_set<std::string> mObject;
+    std::vector<std::string>        mRequested;
+    Mode                            mMode = Mode::INVALID;
+
+    ComparerInterfaces(MatchRule* rule)
+    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::INTERFACES_MATCH_TYPE)>(*rule)))
+    {
+      mRequested = {std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).begin(), std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).end()};
+    }
+
+    void Update(Accessible* obj)
+    {
+      mObject.clear();
+      for(auto& interface : obj->GetInterfacesAsStrings())
+      {
+        mObject.insert(std::move(interface));
+      }
+    }
+
+    bool IsRequestEmpty() const
+    {
+      return mRequested.empty();
+    }
+
+    bool IsObjectEmpty() const
+    {
+      return mObject.empty();
+    }
+
+    bool Compare(CompareFuncExit exit)
+    {
+      bool foundAny = false;
+      for(auto& iname : mRequested)
+      {
+        bool found = (mObject.find(iname) != mObject.end());
+        if(found)
+        {
+          foundAny = true;
+        }
+
+        if(found == (exit == CompareFuncExit::FIRST_FOUND))
+        {
+          return found;
+        }
+      }
+      return foundAny;
+    }
+  }; // ComparerInterfaces struct
+
+  /**
+   * @brief The ComparerAttributes structure
+   */
+  struct ComparerAttributes
+  {
+    std::unordered_map<std::string, std::string> mRequested;
+    std::unordered_map<std::string, std::string> mObject;
+    Mode                                         mMode = Mode::INVALID;
+
+    ComparerAttributes(MatchRule* rule)
+    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ATTRIBUTES_MATCH_TYPE)>(*rule)))
+    {
+      mRequested = std::get<static_cast<std::size_t>(Index::ATTRIBUTES)>(*rule);
+    }
+
+    void Update(Accessible* obj)
+    {
+      mObject = obj->GetAttributes();
+    }
+
+    bool IsRequestEmpty() const
+    {
+      return mRequested.empty();
+    }
+
+    bool IsObjectEmpty() const
+    {
+      return mObject.empty();
+    }
+
+    bool Compare(CompareFuncExit exit)
+    {
+      bool foundAny = false;
+      for(auto& iname : mRequested)
+      {
+        auto it    = mObject.find(iname.first);
+        bool found = it != mObject.end() && iname.second == it->second;
+        if(found)
+        {
+          foundAny = true;
+        }
+
+        if(found == (exit == CompareFuncExit::FIRST_FOUND))
+        {
+          return found;
+        }
+      }
+      return foundAny;
+    }
+  }; // ComparerAttributes struct
+
+  /**
+   * @brief The ComparerRoles structure
+   */
+  struct ComparerRoles
+  {
+    using Roles = EnumBitSet<Role, Role::MAX_COUNT>;
+
+    Roles mRequested;
+    Roles mObject;
+    Mode  mMode = Mode::INVALID;
+
+    ComparerRoles(MatchRule* rule)
+    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ROLES_MATCH_TYPE)>(*rule)))
+    {
+      mRequested = Roles{std::get<static_cast<std::size_t>(Index::ROLES)>(*rule)};
+    }
+
+    void Update(Accessible* obj)
+    {
+      mObject                 = {};
+      mObject[obj->GetRole()] = true;
+      assert(mObject);
+    }
+
+    bool IsRequestEmpty() const
+    {
+      return !mRequested;
+    }
+
+    bool IsObjectEmpty() const
+    {
+      return !mObject;
+    }
+
+    bool Compare(CompareFuncExit exit)
+    {
+      switch(mMode)
+      {
+        case Mode::INVALID:
+        {
+          return true;
+        }
+        case Mode::EMPTY:
+        case Mode::ALL:
+        {
+          return mRequested == (mObject & mRequested);
+        }
+        case Mode::ANY:
+        {
+          return bool(mObject & mRequested);
+        }
+        case Mode::NONE:
+        {
+          return bool(mObject & mRequested);
+        }
+      }
+      return false;
+    }
+  }; // ComparerRoles struct
+
+  /**
+   * @brief The ComparerStates structure
+   */
+  struct ComparerStates
+  {
+    States mRequested;
+    States mObject;
+    Mode   mMode = Mode::INVALID;
+
+    ComparerStates(MatchRule* rule)
+    : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::STATES_MATCH_TYPE)>(*rule)))
+    {
+      mRequested = States{std::get<static_cast<std::size_t>(Index::STATES)>(*rule)};
+    }
+
+    void Update(Accessible* obj)
+    {
+      mObject = obj->GetStates();
+    }
+
+    bool IsRequestEmpty() const
+    {
+      return !mRequested;
+    }
+
+    bool IsObjectEmpty() const
+    {
+      return !mObject;
+    }
+
+    bool Compare(CompareFuncExit exit)
+    {
+      switch(mMode)
+      {
+        case Mode::INVALID:
+        {
+          return true;
+        }
+        case Mode::EMPTY:
+        case Mode::ALL:
+        {
+          return mRequested == (mObject & mRequested);
+        }
+        case Mode::ANY:
+        {
+          return bool(mObject & mRequested);
+        }
+        case Mode::NONE:
+        {
+          return bool(mObject & mRequested);
+        }
+      }
+      return false;
+    }
+  }; // ComparerStates struct
+
+  template<typename T>
+  bool CompareFunc(T& cmp, Accessible* obj)
+  {
+    if(cmp.mMode == Mode::INVALID)
+    {
+      return true;
+    }
+
+    cmp.Update(obj);
+    switch(cmp.mMode)
+    {
+      case Mode::ANY:
+      {
+        if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
+        {
+          return false;
+        }
+        break;
+      }
+      case Mode::ALL:
+      {
+        if(cmp.IsRequestEmpty())
+        {
+          return true;
+        }
+        if(cmp.IsObjectEmpty())
+        {
+          return false;
+        }
+        break;
+      }
+      case Mode::NONE:
+      {
+        if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
+        {
+          return true;
+        }
+        break;
+      }
+      case Mode::EMPTY:
+      {
+        if(cmp.IsRequestEmpty() && cmp.IsObjectEmpty())
+        {
+          return true;
+        }
+        if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
+        {
+          return false;
+        }
+        break;
+      }
+      case Mode::INVALID:
+      {
+        return true;
+      }
+    }
+
+    switch(cmp.mMode)
+    {
+      case Mode::EMPTY:
+      case Mode::ALL:
+      {
+        if(!cmp.Compare(CompareFuncExit::FIRST_NOT_FOUND))
+        {
+          return false;
+        }
+        break;
+      }
+      case Mode::ANY:
+      {
+        if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
+        {
+          return true;
+        }
+        break;
+      }
+      case Mode::NONE:
+      {
+        if(cmp.Compare(CompareFuncExit::FIRST_FOUND))
+        {
+          return false;
+        }
+        break;
+      }
+      case Mode::INVALID:
+      {
+        return true;
+      }
+    }
+
+    switch(cmp.mMode)
+    {
+      case Mode::EMPTY:
+      case Mode::ALL:
+      case Mode::NONE:
+      {
+        return true;
+      }
+      case Mode::ANY:
+      {
+        return false;
+      }
+      case Mode::INVALID:
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  Comparer(MatchRule* rule)
+  : mInterface(rule),
+    mAttribute(rule),
+    mRole(rule),
+    mState(rule)
+  {
+  }
+
+  bool operator()(Accessible* obj)
+  {
+    return CompareFunc(mInterface, obj) &&
+           CompareFunc(mAttribute, obj) &&
+           CompareFunc(mRole, obj) &&
+           CompareFunc(mState, obj);
+  }
+
+  bool IsShowing(Accessible* obj)
+  {
+    if(mState.mMode == Mode::NONE) return true;
+    mState.Update(obj);
+    if(mState.IsRequestEmpty() || mState.IsObjectEmpty()) return true;
+    if(!mState.mRequested[State::SHOWING]) return true;
+    if(mState.mObject[State::SHOWING]) return true;
+
+    return false;
+  }
+
+  ComparerInterfaces mInterface;
+  ComparerAttributes mAttribute;
+  ComparerRoles      mRole;
+  ComparerStates     mState;
+}; // BridgeCollection::Comparer struct
+
+/**
+ * @brief Visits all nodes of Accessible object and pushes the object to 'result' container.
+ *
+ * To query the entire tree, the BridgeCollection::Comparer is used inside this method,
+ * which traverse the tree using GetChildAtIndex().
+ * @param[in] obj The Accessible object to search
+ * @param[out] result The vector container for result
+ * @param[in] comparer BridgeCollection::Comparer which do the comparison against a single accessible object
+ * @param[in] maxCount The maximum count of containing Accessible object
+ */
+void VisitNodes(Accessible* obj, std::vector<Accessible*>& result, Comparer& comparer, size_t maxCount, std::set<Accessible*>& visitedNodes)
+{
+  if(visitedNodes.count(obj) > 0)
+  {
+    return;
+  }
+
+  visitedNodes.insert(obj);
+
+  if(maxCount > 0 && result.size() >= maxCount)
+  {
+    return;
+  }
+
+  if(comparer(obj))
+  {
+    result.emplace_back(obj);
+    // the code below will never return for maxCount equal 0
+    if(result.size() == maxCount)
+    {
+      return;
+    }
+  }
+
+  if(!comparer.IsShowing(obj))
+  {
+    return;
+  }
+
+  for(auto i = 0u; i < obj->GetChildCount(); ++i)
+  {
+    VisitNodes(obj->GetChildAtIndex(i), result, comparer, maxCount, visitedNodes);
+  }
+}
+
+void SortMatchedResult(std::vector<Accessible*>& result, SortOrder sortBy)
+{
+  switch(sortBy)
+  {
+    case SortOrder::CANONICAL:
+    {
+      break;
+    }
+
+    case SortOrder::REVERSE_CANONICAL:
+    {
+      std::reverse(result.begin(), result.end());
+      break;
+    }
+
+    default:
+    {
+      throw std::domain_error{"unsupported sorting order"};
+    }
+      //TODO: other cases
+  }
+}
+
+} // namespace
+
+std::vector<Accessible*> Collection::GetMatches(MatchRule rule, uint32_t sortBy, size_t maxCount)
+{
+  std::vector<Accessible*> res;
+  auto                     matcher = Comparer{&rule};
+  std::set<Accessible*>    visitedNodes;
+  VisitNodes(this, res, matcher, maxCount, visitedNodes);
+  SortMatchedResult(res, static_cast<SortOrder>(sortBy));
+  return res;
+}
+
+std::vector<Accessible*> Collection::GetMatchesInMatches(MatchRule firstRule, MatchRule secondRule, uint32_t sortBy, int32_t firstCount, int32_t secondCount)
+{
+  std::vector<Accessible*> res;
+  std::vector<Accessible*> firstRes;
+  auto                     firstMatcher = Comparer{&firstRule};
+  std::set<Accessible*>    visitedNodes;
+  VisitNodes(this, firstRes, firstMatcher, firstCount, visitedNodes);
+
+  if(!firstRes.empty())
+  {
+    visitedNodes.clear();
+    auto secondMatcher = Comparer{&secondRule};
+    for(auto* obj : firstRes)
+    {
+      std::vector<Accessible*> secondRes;
+      VisitNodes(obj, secondRes, secondMatcher, secondCount, visitedNodes);
+
+      if(!secondRes.empty())
+      {
+        res.insert(res.end(), secondRes.begin(), secondRes.end());
+      }
+    }
+
+    SortMatchedResult(res, static_cast<SortOrder>(sortBy));
+  }
+
+  return res;
+}
index eccf2934828a175b8078f72ee4bfacb7bb3adce0..5aefe309f28cca19c68881daa12c6f28fa87945c 100644 (file)
@@ -78,6 +78,7 @@ SET( adaptor_accessibility_atspi_bridge_src_files
     ${adaptor_accessibility_dir}/bridge/bridge-table-cell.cpp
     ${adaptor_accessibility_dir}/bridge/bridge-text.cpp
     ${adaptor_accessibility_dir}/bridge/bridge-value.cpp
+    ${adaptor_accessibility_dir}/bridge/collection.cpp
     ${adaptor_accessibility_dir}/bridge/component.cpp
     ${adaptor_accessibility_dir}/bridge/dbus/dbus-tizen.cpp
 )