[dali_2.1.12] Merge branch 'devel/master' 92/271992/1
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 4 Mar 2022 10:01:38 +0000 (10:01 +0000)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 4 Mar 2022 10:01:38 +0000 (10:01 +0000)
Change-Id: I2a0872b530289bff273fb088251aa7fe30f72e8e

41 files changed:
automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp
dali/devel-api/adaptor-framework/accessibility-bitset.h
dali/devel-api/adaptor-framework/accessibility.cpp
dali/devel-api/adaptor-framework/accessibility.h
dali/devel-api/atspi-interfaces/accessible.h
dali/devel-api/atspi-interfaces/action.h
dali/devel-api/atspi-interfaces/application.h
dali/devel-api/atspi-interfaces/collection.h
dali/devel-api/atspi-interfaces/component.h
dali/devel-api/atspi-interfaces/editable-text.h
dali/devel-api/atspi-interfaces/hyperlink.h
dali/devel-api/atspi-interfaces/hypertext.h
dali/devel-api/atspi-interfaces/selection.h
dali/devel-api/atspi-interfaces/text.h
dali/devel-api/atspi-interfaces/value.h
dali/internal/accessibility/bridge/accessibility-common.h
dali/internal/accessibility/bridge/accessible.cpp
dali/internal/accessibility/bridge/bridge-accessible.cpp
dali/internal/accessibility/bridge/bridge-accessible.h
dali/internal/accessibility/bridge/bridge-action.cpp
dali/internal/accessibility/bridge/bridge-application.cpp
dali/internal/accessibility/bridge/bridge-base.cpp
dali/internal/accessibility/bridge/bridge-base.h
dali/internal/accessibility/bridge/bridge-collection.cpp
dali/internal/accessibility/bridge/bridge-component.cpp
dali/internal/accessibility/bridge/bridge-editable-text.cpp
dali/internal/accessibility/bridge/bridge-hyperlink.cpp
dali/internal/accessibility/bridge/bridge-hypertext.cpp
dali/internal/accessibility/bridge/bridge-impl.cpp
dali/internal/accessibility/bridge/bridge-object.cpp
dali/internal/accessibility/bridge/bridge-selection.cpp
dali/internal/accessibility/bridge/bridge-text.cpp
dali/internal/accessibility/bridge/bridge-value.cpp
dali/internal/imaging/common/alpha-mask.cpp
dali/internal/imaging/common/alpha-mask.h
dali/internal/imaging/common/image-operations.cpp
dali/internal/imaging/common/image-operations.h
dali/internal/imaging/common/pixel-buffer-impl.cpp
dali/internal/imaging/common/pixel-manipulation.cpp
dali/public-api/dali-adaptor-version.cpp
packaging/dali-adaptor.spec

index 17b7c06..e7414ff 100644 (file)
@@ -950,6 +950,26 @@ int UtcDaliImageOperationsHalveScanlineInPlace1Byte(void)
 /**
  * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
  */
+int UtcDaliImageOperationsAverageScanlines1ExceptTest(void)
+{
+  // Edge cases for averagescanlines1:
+  unsigned char shortEven1[]   = {0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x02, 0x03, 0x00, 0x01};
+  unsigned char shortEven2[]   = {0x00, 0xff, 0x00, 0xff, 0x01, 0x01, 0xff, 0xfe, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x03, 0x02};
+  unsigned char expectBuffer[] = {0x00, 0x7f, 0x7f, 0xff, 0x80, 0x7f, 0x80, 0x7f, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines1(shortEven1, shortEven2, outputBuffer, sizeof(shortEven1));
+  for(unsigned i = 0; i < sizeof(shortEven1); ++i)
+  {
+    DALI_TEST_EQUALS(unsigned(outputBuffer[i]), unsigned(expectBuffer[i]), TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
+ */
 int UtcDaliImageOperationsAverageScanlines1(void)
 {
   // Red and cyan, averaging to grey:
@@ -964,19 +984,55 @@ int UtcDaliImageOperationsAverageScanlines1(void)
   }
 
   // Longer test reusing RGBA setup/test logic:
-  const size_t           scanlineLength = 4096u;
-  Dali::Vector<uint32_t> scanline1;
-  Dali::Vector<uint32_t> scanline2;
-  Dali::Vector<uint32_t> reference;
-  Dali::Vector<uint32_t> output;
-  SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+  {
+    const size_t           scanlineLength = 4096u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+  // Longer test reusing RGBA setup/test logic with none-8-divisable length
+  {
+    const size_t           scanlineLength = 1003u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  // Check the output matches the independently generated reference:
-  size_t numMatches = 0;
-  MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
-  DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  // Very short test reusing RGBA setup/test logic with less-than-8 length
+  {
+    const size_t           scanlineLength = 1003u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines1((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
   END_TEST;
 }
@@ -999,19 +1055,55 @@ int UtcDaliImageOperationsAverageScanlines2(void)
   }
 
   // Longer test reusing RGBA setup/test logic:
-  const size_t           scanlineLength = 4096u;
-  Dali::Vector<uint32_t> scanline1;
-  Dali::Vector<uint32_t> scanline2;
-  Dali::Vector<uint32_t> reference;
-  Dali::Vector<uint32_t> output;
-  SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+  {
+    const size_t           scanlineLength = 4096u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+  // Longer test reusing RGBA setup/test logic with none-8-divisable length
+  {
+    const size_t           scanlineLength = 501u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  // Check the output matches the independently generated reference:
-  size_t numMatches = 0;
-  MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
-  DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  // Very short test reusing RGBA setup/test logic with less-than-8 length
+  {
+    const size_t           scanlineLength = 3u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines2((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 2);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
   END_TEST;
 }
@@ -1033,19 +1125,55 @@ int UtcDaliImageOperationsAverageScanlines3(void)
   }
 
   // Longer test reusing RGBA setup/test logic:
-  const size_t           scanlineLength = 3 * 4 * 90u;
-  Dali::Vector<uint32_t> scanline1;
-  Dali::Vector<uint32_t> scanline2;
-  Dali::Vector<uint32_t> reference;
-  Dali::Vector<uint32_t> output;
-  SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+  {
+    const size_t           scanlineLength = 3 * 4 * 90u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+  // Longer test reusing RGBA setup/test logic with none-8-divisable length
+  {
+    const size_t           scanlineLength = 3 * 501u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
-  // Check the output matches the independently generated reference:
-  size_t numMatches = 0;
-  MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
-  DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  // Very short test reusing RGBA setup/test logic with less-than-8 length
+  {
+    const size_t           scanlineLength = 3u;
+    Dali::Vector<uint32_t> scanline1;
+    Dali::Vector<uint32_t> scanline2;
+    Dali::Vector<uint32_t> reference;
+    Dali::Vector<uint32_t> output;
+    SetupScanlinesRGBA8888(scanlineLength, scanline1, scanline2, reference, output);
+
+    AverageScanlines3((const unsigned char*)&scanline1[0], (const unsigned char*)&scanline2[0], (unsigned char*)&output[0], scanlineLength * 4 / 3);
+
+    // Check the output matches the independently generated reference:
+    size_t numMatches = 0;
+    MatchScanlinesRGBA8888(reference, output, numMatches, TEST_LOCATION);
+    DALI_TEST_EQUALS(numMatches, reference.Count(), TEST_LOCATION);
+  }
 
   END_TEST;
 }
index cdb5410..d9c0159 100644 (file)
@@ -169,6 +169,22 @@ public:
   /**
    * @brief Constructs a new BitSet with all bits initialized with bits from the specified integer.
    *
+   * This constructor is only available for BitSets with 32-bit capacity. Equivalent to the pseudocode:
+   * @code
+   * for(i = 0; i < 32; ++i) bits[i] = (data >> i) & 0x1;
+   * @endcode
+   *
+   * @param data 32-bit integer with the initial values.
+   */
+  template<std::size_t I = N, typename = std::enable_if_t<(I == N && N == 1u)>>
+  explicit BitSet(std::uint32_t data)
+  {
+    mData[0] = data;
+  }
+
+  /**
+   * @brief Constructs a new BitSet with all bits initialized with bits from the specified integer.
+   *
    * This constructor is only available for BitSets with 64-bit capacity. Equivalent to the pseudocode:
    * @code
    * for(i = 0; i < 64; ++i) bits[i] = (data >> i) & 0x1;
@@ -360,6 +376,21 @@ public:
   /**
    * @brief Obtains a copy of the internal storage serialized as a single integer.
    *
+   * This method is only available for BitSets with 32-bit capacity.
+   *
+   * @return A copy of the internal storage.
+   *
+   * @see BitSet::BitSet(std::uint32_t)
+   */
+  template<std::size_t I = N, typename = std::enable_if_t<(I == N && N == 1u)>>
+  std::uint32_t GetRawData32() const
+  {
+    return mData[0];
+  }
+
+  /**
+   * @brief Obtains a copy of the internal storage serialized as a single integer.
+   *
    * This method is only available for BitSets with 64-bit capacity.
    *
    * @return A copy of the internal storage.
@@ -424,6 +455,38 @@ public:
   // Operators
 
   /**
+   * @copydoc BitSet::operator~() const
+   */
+  EnumBitSet operator~() const
+  {
+    return BitSet<N>::operator~();
+  }
+
+  /**
+   * @copydoc BitSet::operator|(const BitSet&) const
+   */
+  EnumBitSet operator|(const EnumBitSet& other) const
+  {
+    return BitSet<N>::operator|(other);
+  }
+
+  /**
+   * @copydoc BitSet::operator&(const BitSet&) const
+   */
+  EnumBitSet operator&(const EnumBitSet& other) const
+  {
+    return BitSet<N>::operator&(other);
+  }
+
+  /**
+   * @copydoc BitSet::operator^(const BitSet&) const
+   */
+  EnumBitSet operator^(const EnumBitSet& other) const
+  {
+    return BitSet<N>::operator^(other);
+  }
+
+  /**
    * @copydoc BitSet::operator[](IndexType) const
    */
   bool operator[](Enum index) const
@@ -440,6 +503,12 @@ public:
   }
 
 private:
+  // For operators '~|&^'
+  EnumBitSet(BitSet<N>&& bitSet)
+  : BitSet<N>(bitSet)
+  {
+  }
+
   // No data members (non-virtual destructor)
 };
 
index cea55f3..196ab60 100644 (file)
 #include <dali/devel-api/adaptor-framework/proxy-accessible.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/atspi-interfaces/accessible.h>
+#include <dali/devel-api/atspi-interfaces/action.h>
+#include <dali/devel-api/atspi-interfaces/application.h>
 #include <dali/devel-api/atspi-interfaces/collection.h>
 #include <dali/devel-api/atspi-interfaces/component.h>
+#include <dali/devel-api/atspi-interfaces/editable-text.h>
+#include <dali/devel-api/atspi-interfaces/hyperlink.h>
+#include <dali/devel-api/atspi-interfaces/hypertext.h>
+#include <dali/devel-api/atspi-interfaces/selection.h>
+#include <dali/devel-api/atspi-interfaces/text.h>
+#include <dali/devel-api/atspi-interfaces/value.h>
 #include <dali/internal/adaptor/common/adaptor-impl.h>
 #include <dali/public-api/dali-adaptor-common.h>
 
@@ -185,6 +193,99 @@ std::string Accessible::GetRoleName() const
   return std::string{it->second};
 }
 
+AtspiInterfaces Accessible::GetInterfaces() const
+{
+  if(!mInterfaces)
+  {
+    mInterfaces = DoGetInterfaces();
+    DALI_ASSERT_DEBUG(mInterfaces); // There has to be at least AtspiInterface::ACCESSIBLE
+  }
+
+  return mInterfaces;
+}
+
+std::vector<std::string> Accessible::GetInterfacesAsStrings() const
+{
+  std::vector<std::string> ret;
+  AtspiInterfaces          interfaces = GetInterfaces();
+
+  for(std::size_t i = 0u; i < static_cast<std::size_t>(AtspiInterface::MAX_COUNT); ++i)
+  {
+    auto interface = static_cast<AtspiInterface>(i);
+
+    if(interfaces[interface])
+    {
+      auto name = GetInterfaceName(interface);
+
+      DALI_ASSERT_DEBUG(!name.empty());
+      ret.emplace_back(std::move(name));
+    }
+  }
+
+  return ret;
+}
+
+AtspiInterfaces Accessible::DoGetInterfaces() const
+{
+  AtspiInterfaces interfaces;
+
+  interfaces[AtspiInterface::ACCESSIBLE]    = true;
+  interfaces[AtspiInterface::ACTION]        = dynamic_cast<const Action*>(this);
+  interfaces[AtspiInterface::APPLICATION]   = dynamic_cast<const Application*>(this);
+  interfaces[AtspiInterface::COLLECTION]    = dynamic_cast<const Collection*>(this);
+  interfaces[AtspiInterface::COMPONENT]     = dynamic_cast<const Component*>(this);
+  interfaces[AtspiInterface::EDITABLE_TEXT] = dynamic_cast<const EditableText*>(this);
+  interfaces[AtspiInterface::HYPERLINK]     = dynamic_cast<const Hyperlink*>(this);
+  interfaces[AtspiInterface::HYPERTEXT]     = dynamic_cast<const Hypertext*>(this);
+  interfaces[AtspiInterface::SELECTION]     = dynamic_cast<const Selection*>(this);
+  interfaces[AtspiInterface::TEXT]          = dynamic_cast<const Text*>(this);
+  interfaces[AtspiInterface::VALUE]         = dynamic_cast<const Value*>(this);
+
+  return interfaces;
+}
+
+std::string Accessible::GetInterfaceName(AtspiInterface interface)
+{
+  static const std::unordered_map<AtspiInterface, std::string_view> interfaceMap{
+    {AtspiInterface::ACCESSIBLE, "org.a11y.atspi.Accessible"},
+    {AtspiInterface::ACTION, "org.a11y.atspi.Action"},
+    {AtspiInterface::APPLICATION, "org.a11y.atspi.Application"},
+    {AtspiInterface::CACHE, "org.a11y.atspi.Cache"},
+    {AtspiInterface::COLLECTION, "org.a11y.atspi.Collection"},
+    {AtspiInterface::COMPONENT, "org.a11y.atspi.Component"},
+    {AtspiInterface::DEVICE_EVENT_CONTROLLER, "org.a11y.atspi.DeviceEventController"},
+    {AtspiInterface::DEVICE_EVENT_LISTENER, "org.a11y.atspi.DeviceEventListener"},
+    {AtspiInterface::DOCUMENT, "org.a11y.atspi.Document"},
+    {AtspiInterface::EDITABLE_TEXT, "org.a11y.atspi.EditableText"},
+    {AtspiInterface::EVENT_DOCUMENT, "org.a11y.atspi.Event.Document"},
+    {AtspiInterface::EVENT_FOCUS, "org.a11y.atspi.Event.Focus"},
+    {AtspiInterface::EVENT_KEYBOARD, "org.a11y.atspi.Event.Keyboard"},
+    {AtspiInterface::EVENT_MOUSE, "org.a11y.atspi.Event.Mouse"},
+    {AtspiInterface::EVENT_OBJECT, "org.a11y.atspi.Event.Object"},
+    {AtspiInterface::EVENT_TERMINAL, "org.a11y.atspi.Event.Terminal"},
+    {AtspiInterface::EVENT_WINDOW, "org.a11y.atspi.Event.Window"},
+    {AtspiInterface::HYPERLINK, "org.a11y.atspi.Hyperlink"},
+    {AtspiInterface::HYPERTEXT, "org.a11y.atspi.Hypertext"},
+    {AtspiInterface::IMAGE, "org.a11y.atspi.Image"},
+    {AtspiInterface::REGISTRY, "org.a11y.atspi.Registry"},
+    {AtspiInterface::SELECTION, "org.a11y.atspi.Selection"},
+    {AtspiInterface::SOCKET, "org.a11y.atspi.Socket"},
+    {AtspiInterface::TABLE, "org.a11y.atspi.Table"},
+    {AtspiInterface::TABLE_CELL, "org.a11y.atspi.TableCell"},
+    {AtspiInterface::TEXT, "org.a11y.atspi.Text"},
+    {AtspiInterface::VALUE, "org.a11y.atspi.Value"},
+  };
+
+  auto it = interfaceMap.find(interface);
+
+  if(it == interfaceMap.end())
+  {
+    return {};
+  }
+
+  return std::string{it->second};
+}
+
 Dali::Actor Accessible::GetCurrentlyHighlightedActor()
 {
   return IsUp() ? Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor : Dali::Actor{};
index ef54cd3..1142576 100644 (file)
@@ -428,10 +428,77 @@ enum class ReadingInfoType
   MAX_COUNT\r
 };\r
 \r
+/**\r
+ * @brief Enumeration of all AT-SPI interfaces.\r
+ *\r
+ * @see Dali::Accessibility::Accessible::GetInterfaceName()\r
+ * @see Dali::Accessibility::AtspiInterfaceType\r
+ */\r
+enum class AtspiInterface\r
+{\r
+  ACCESSIBLE,\r
+  ACTION,\r
+  APPLICATION,\r
+  CACHE,\r
+  COLLECTION,\r
+  COMPONENT,\r
+  DEVICE_EVENT_CONTROLLER,\r
+  DEVICE_EVENT_LISTENER,\r
+  DOCUMENT,\r
+  EDITABLE_TEXT,\r
+  EVENT_DOCUMENT,\r
+  EVENT_FOCUS,\r
+  EVENT_KEYBOARD,\r
+  EVENT_MOUSE,\r
+  EVENT_OBJECT,\r
+  EVENT_TERMINAL,\r
+  EVENT_WINDOW,\r
+  HYPERLINK,\r
+  HYPERTEXT,\r
+  IMAGE,\r
+  REGISTRY,\r
+  SELECTION,\r
+  SOCKET,\r
+  TABLE,\r
+  TABLE_CELL,\r
+  TEXT,\r
+  VALUE,\r
+  MAX_COUNT\r
+};\r
+\r
+using AtspiInterfaces  = EnumBitSet<AtspiInterface, AtspiInterface::MAX_COUNT>;\r
 using ReadingInfoTypes = EnumBitSet<ReadingInfoType, ReadingInfoType::MAX_COUNT>;\r
 using States           = EnumBitSet<State, State::MAX_COUNT>;\r
 using Attributes       = std::unordered_map<std::string, std::string>;\r
 \r
+namespace Internal\r
+{\r
+/*\r
+ * AT-SPI interfaces exposed as native C++ types should specialize this like so:\r
+ *\r
+ * template<>\r
+ * struct AtspiInterfaceTypeHelper<AtspiInterface::ACCESSIBLE>\r
+ * {\r
+ *   using Type = Dali::Accessibility::Accessible;\r
+ * };\r
+ */\r
+template<AtspiInterface I>\r
+struct AtspiInterfaceTypeHelper; // no default definition\r
+\r
+} // namespace Internal\r
+\r
+/**\r
+ * @brief Resolves to the native C++ type that represents the given AT-SPI interface.\r
+ *\r
+ * For example, @code AtspiInterfaceType<AtspiInterface::ACCESSIBLE> @endcode is the same as\r
+ * @code Dali::Accessibility::Accessible @endcode. Not all AT-SPI interfaces have native C++\r
+ * representations (in which case, such an expression will not compile).\r
+ *\r
+ * @tparam I Enumeration value indicating the requested AT-SPI interface.\r
+ */\r
+template<AtspiInterface I>\r
+using AtspiInterfaceType = typename Internal::AtspiInterfaceTypeHelper<I>::Type;\r
+\r
 /**\r
  * @brief Class representing unique object address on accessibility bus\r
  * @see Dali::Accessibility::Accessible::GetAddress\r
index 0eb7794..b0b3ba1 100644 (file)
@@ -336,9 +336,26 @@ public:
   /**
    * @brief Gets all implemented interfaces.
    *
-   * @return The collection of strings with implemented interfaces
+   * Override DoGetInterfaces() to customize the return value of this method.
+   *
+   * @return The collection of implemented interfaces
+   *
+   * @see DoGetInterfaces()
+   */
+  AtspiInterfaces GetInterfaces() const;
+
+  /**
+   * @brief Gets all implemented interfaces.
+   *
+   * Converts all interfaces returned by GetInterfaces() to their DBus names
+   * using GetInterfaceName().
+   *
+   * @return The collection of names of implemented interfaces
+   *
+   * @see GetInterfaces()
+   * @see GetInterfaceName()
    */
-  std::vector<std::string> GetInterfaces() const;
+  std::vector<std::string> GetInterfacesAsStrings() const;
 
   /**
    * @brief Checks if object is on root level.
@@ -358,6 +375,20 @@ protected:
   Accessible&                   operator=(Accessible&&) = delete;
   std::shared_ptr<Bridge::Data> GetBridgeData() const;
 
+  /**
+   * @brief Returns the collection of AT-SPI interfaces implemented by this Accessible.
+   *
+   * This method is called only once and its return value is cached. The default implementation
+   * uses dynamic_cast to determine which interfaces are implemented. Override this if you
+   * conceptually provide fewer interfaces than dynamic_cast can see.
+   *
+   * @return The collection of implemented interfaces
+   *
+   * @see GetInterfaces()
+   * @see GetInterfaceName()
+   */
+  virtual AtspiInterfaces DoGetInterfaces() const;
+
 public:
   /**
    * @brief Gets the highlight actor.
@@ -412,14 +443,52 @@ public:
    */
   static Accessible* Get(Dali::Actor actor, bool isRoot = false);
 
+  /**
+   * @brief Obtains the DBus interface name for the specified AT-SPI interface.
+   *
+   * @param interface AT-SPI interface identifier (e.g. AtspiInterface::ACCESSIBLE)
+   * @return AT-SPI interface name (e.g. "org.a11y.atspi.Accessible")
+   */
+  static std::string GetInterfaceName(AtspiInterface interface);
+
+  /**
+   * @brief Downcasts an Accessible pointer to an AT-SPI interface pointer.
+   *
+   * @tparam I Desired AT-SPI interface
+   *
+   * @param obj Object to cast.
+   *
+   * @return Pointer to an AT-SPI interface or null if the interface is not implemented.
+   */
+  template<AtspiInterface I>
+  static AtspiInterfaceType<I>* DownCast(Accessible* obj)
+  {
+    if(!obj || !obj->GetInterfaces()[I])
+    {
+      return nullptr;
+    }
+
+    return dynamic_cast<AtspiInterfaceType<I>*>(obj);
+  }
+
 private:
   friend class Bridge;
 
   mutable std::weak_ptr<Bridge::Data> mBridgeData;
+  mutable AtspiInterfaces             mInterfaces;
   bool                                mIsOnRootLevel = false;
 
 }; // Accessible class
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::ACCESSIBLE>
+{
+  using Type = Accessible;
+};
+} // namespace Internal
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_ACCESSIBLE_H
index b3d9717..b168f63 100644 (file)
@@ -93,8 +93,32 @@ public:
    * @return true on success, false otherwise
    */
   virtual bool DoAction(const std::string& name) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to an Action.
+   *
+   * @param obj The Accessible
+   * @return An Action or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Action* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::ACTION>
+{
+  using Type = Action;
+};
+} // namespace Internal
+
+inline Action* Action::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::ACTION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_ACTION_H
index 5e37f6b..44b26ba 100644 (file)
@@ -48,8 +48,32 @@ public:
    * @return String with version
    */
   virtual std::string GetVersion() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to an Application.
+   *
+   * @param obj The Accessible
+   * @return An Application or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Application* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::APPLICATION>
+{
+  using Type = Application;
+};
+} // namespace Internal
+
+inline Application* Application::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::APPLICATION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_APPLICATION_H
index 6452854..7a84079 100644 (file)
@@ -25,13 +25,36 @@ namespace Dali::Accessibility
 /**
  * @brief Interface enabling advanced quering of accessibility objects.
  *
- * @note since all mathods can be implemented inside bridge,
- * none methods have to be overrided
+ * @note Since all methods can be implemented inside bridge,
+ * no methods have to be overriden.
  */
 class DALI_ADAPTOR_API Collection : public virtual Accessible
 {
+  /**
+   * @brief Downcasts an Accessible to a Collection.
+   *
+   * @param obj The Accessible
+   * @return A Collection or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Collection* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::COLLECTION>
+{
+  using Type = Collection;
+};
+} // namespace Internal
+
+inline Collection* Collection::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::COLLECTION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_COLLECTION_H
index 1853313..682b97c 100644 (file)
@@ -131,8 +131,32 @@ public:
    * @see Dali::Accessibility::Point
    */
   virtual bool IsAccessibleContainingPoint(Point point, CoordinateType type) const;
+
+  /**
+   * @brief Downcasts an Accessible to a Component.
+   *
+   * @param obj The Accessible
+   * @return A Component or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Component* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::COMPONENT>
+{
+  using Type = Component;
+};
+} // namespace Internal
+
+inline Component* Component::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::COMPONENT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_COMPONENT_H
index 66c822e..1aa141f 100644 (file)
@@ -84,8 +84,32 @@ public:
    * @return true on success, false otherwise
    */
   virtual bool SetTextContents(std::string newContents) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to an EditableText.
+   *
+   * @param obj The Accessible
+   * @return An EditableText or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline EditableText* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::EDITABLE_TEXT>
+{
+  using Type = EditableText;
+};
+} // namespace Internal
+
+inline EditableText* EditableText::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::EDITABLE_TEXT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_EDITABLE_TEXT_H
index 5f7c8f5..aef9f4e 100644 (file)
@@ -77,8 +77,32 @@ public:
    * @return True if hyperlink object is valid, false otherwise
    */
   virtual bool IsValid() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Hyperlink.
+   *
+   * @param obj The Accessible
+   * @return A Hyperlink or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Hyperlink* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::HYPERLINK>
+{
+  using Type = Hyperlink;
+};
+} // namespace Internal
+
+inline Hyperlink* Hyperlink::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::HYPERLINK>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_HYPERLINK_H
index e9b4deb..903aebc 100644 (file)
@@ -56,8 +56,32 @@ public:
    * @return The number of hyperlinks (zero if none or -1 if the number cannot be determined)
    */
   virtual std::int32_t GetLinkCount() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Hypertext.
+   *
+   * @param obj The Accessible
+   * @return A Hypertext or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Hypertext* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::HYPERTEXT>
+{
+  using Type = Hypertext;
+};
+} // namespace Internal
+
+inline Hypertext* Hypertext::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::HYPERTEXT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_HYPERTEXT_H
index 2aadd67..0ce68c4 100644 (file)
@@ -103,8 +103,32 @@ public:
    * @see Dali::Accessibility::Selection::DeselectSelectedChild
    */
   virtual bool DeselectChild(int childIndex) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Selection.
+   *
+   * @param obj The Accessible
+   * @return A Selection or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Selection* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::SELECTION>
+{
+  using Type = Selection;
+};
+} // namespace Internal
+
+inline Selection* Selection::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::SELECTION>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_SELECTION_H
index bd2981c..f632807 100644 (file)
@@ -118,8 +118,32 @@ public:
    * @remarks This method is `SetSelection` in DBus method.
    */
   virtual bool SetRangeOfSelection(std::size_t selectionIndex, std::size_t startOffset, std::size_t endOffset) = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Text.
+   *
+   * @param obj The Accessible
+   * @return A Text or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Text* DownCast(Accessible* obj);
 };
 
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::TEXT>
+{
+  using Type = Text;
+};
+} // namespace Internal
+
+inline Text* Text::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::TEXT>(obj);
+}
+
 } // namespace Dali::Accessibility
 
 #endif // DALI_ADAPTOR_ATSPI_TEXT_H
index 350e2be..6c9a963 100644 (file)
@@ -64,7 +64,31 @@ public:
    * @return The lowest increment
   */
   virtual double GetMinimumIncrement() const = 0;
+
+  /**
+   * @brief Downcasts an Accessible to a Value.
+   *
+   * @param obj The Accessible
+   * @return A Value or null
+   *
+   * @see Dali::Accessibility::Accessible::DownCast()
+   */
+  static inline Value* DownCast(Accessible* obj);
+};
+
+namespace Internal
+{
+template<>
+struct AtspiInterfaceTypeHelper<AtspiInterface::VALUE>
+{
+  using Type = Value;
 };
+} // namespace Internal
+
+inline Value* Value::DownCast(Accessible* obj)
+{
+  return Accessible::DownCast<AtspiInterface::VALUE>(obj);
+}
 
 } // namespace Dali::Accessibility
 
index 4da5e3c..4f61522 100644 (file)
 #include <dali/internal/accessibility/bridge/dbus.h>
 #include <dali/public-api/dali-adaptor-common.h>
 
-/* DBus Interfaces */
+// DBus names
 
 #define A11yDbusName "org.a11y.Bus"
-#define A11yDbusPath "/org/a11y/bus"
 #define A11yDbusStatusInterface "org.a11y.Status"
 #define AtspiDbusNameRegistry "org.a11y.atspi.Registry"
+#define DirectReadingDBusName "org.tizen.ScreenReader"
+#define DirectReadingDBusInterface "org.tizen.DirectReading"
+
+// DBus paths
+
+#define A11yDbusPath "/org/a11y/bus"
+#define AtspiDbusPathCache "/org/a11y/atspi/cache"
+#define AtspiDbusPathDec "/org/a11y/atspi/registry/deviceeventcontroller"
 #define AtspiDbusPathRegistry "/org/a11y/atspi/registry"
-#define AtspiDbusInterfaceRegistry "org.a11y.atspi.Registry"
 #define AtspiDbusPathRoot "/org/a11y/atspi/accessible/root"
-#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket"
 #define AtspiPath "/org/a11y/atspi/accessible"
-#define AtspiDbusInterfaceAccessible "org.a11y.atspi.Accessible"
-#define AtspiDbusInterfaceAction "org.a11y.atspi.Action"
-#define AtspiDbusInterfaceApplication "org.a11y.atspi.Application"
-#define AtspiDbusInterfaceCache "org.a11y.atspi.Cache"
-#define AtspiDbusPathCache "/org/a11y/atspi/cache"
-#define AtspiDbusInterfaceCollection "org.a11y.atspi.Collection"
-#define AtspiDbusInterfaceComponent "org.a11y.atspi.Component"
-#define AtspiDbusInterfaceDocument "org.a11y.atspi.Document"
-#define AtspiDbusInterfaceEditableText "org.a11y.atspi.EditableText"
-#define AtspiDbusInterfaceEventKeyboard "org.a11y.atspi.Event.Keyboard"
-#define AtspiDbusInterfaceEventMouse "org.a11y.atspi.Event.Mouse"
-#define AtspiDbusInterfaceEventObject "org.a11y.atspi.Event.Object"
-#define AtspiDbusInterfaceHyperlink "org.a11y.atspi.Hyperlink"
-#define AtspiDbusInterfaceHypertext "org.a11y.atspi.Hypertext"
-#define AtspiDbusInterfaceImage "org.a11y.atspi.Image"
-#define AtspiDbusInterfaceSelection "org.a11y.atspi.Selection"
-#define AtspiDbusInterfaceTable "org.a11y.atspi.Table"
-#define AtspiDbusInterfaceTableCell "org.a11y.atspi.TableCell"
-#define AtspiDbusInterfaceText "org.a11y.atspi.Text"
-#define AtspiDbusInterfaceValue "org.a11y.atspi.Value"
-#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket"
-#define AtspiDbusInterfaceEventWindow "org.a11y.atspi.Event.Window"
-
-#define AtspiDbusPathDec "/org/a11y/atspi/registry/deviceeventcontroller"
-#define AtspiDbusInterfaceDec "org.a11y.atspi.DeviceEventController"
-#define AtspiDbusInterfaceDeviceEventListener "org.a11y.atspi.DeviceEventListener"
-
-#define DirectReadingDBusName "org.tizen.ScreenReader"
 #define DirectReadingDBusPath "/org/tizen/DirectReading"
-#define DirectReadingDBusInterface "org.tizen.DirectReading"
 
 struct ObjectPath;
 
index 26ec0aa..aaf2584 100644 (file)
 
 //INTERNAL INCLUDES
 #include <dali/devel-api/atspi-interfaces/accessible.h>
-#include <dali/devel-api/atspi-interfaces/action.h>
-#include <dali/devel-api/atspi-interfaces/application.h>
-#include <dali/devel-api/atspi-interfaces/collection.h>
-#include <dali/devel-api/atspi-interfaces/component.h>
-#include <dali/devel-api/atspi-interfaces/editable-text.h>
-#include <dali/devel-api/atspi-interfaces/hyperlink.h>
-#include <dali/devel-api/atspi-interfaces/hypertext.h>
-#include <dali/devel-api/atspi-interfaces/selection.h>
-#include <dali/devel-api/atspi-interfaces/text.h>
-#include <dali/devel-api/atspi-interfaces/value.h>
 #include <dali/devel-api/adaptor-framework/accessibility-bridge.h>
 #include <dali/internal/accessibility/bridge/accessibility-common.h>
 #include <third-party/libunibreak/linebreak.h>
 
 using namespace Dali::Accessibility;
 
-std::vector<std::string> Accessible::GetInterfaces() const
-{
-  std::vector<std::string> tmp;
-  tmp.push_back(AtspiDbusInterfaceAccessible);
-  if(dynamic_cast<const Collection*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceCollection);
-  }
-  if(dynamic_cast<const Text*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceText);
-  }
-  if(dynamic_cast<const EditableText*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceEditableText);
-  }
-  if(dynamic_cast<const Value*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceValue);
-  }
-  if(dynamic_cast<const Component*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceComponent);
-  }
-  if(auto action = dynamic_cast<const Action*>(this))
-  {
-    if(action->GetActionCount() > 0)
-    {
-      tmp.push_back(AtspiDbusInterfaceAction);
-    }
-  }
-  if(dynamic_cast<const Selection*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceSelection);
-  }
-  if(dynamic_cast<const Hypertext*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceHypertext);
-  }
-  if(dynamic_cast<const Hyperlink*>(this))
-  {
-    tmp.push_back(AtspiDbusInterfaceHyperlink);
-  }
-  return tmp;
-}
-
 Accessible::Accessible()
 {
 }
index 59481d3..5f71a60 100644 (file)
@@ -400,7 +400,7 @@ BridgeAccessible::BridgeAccessible()
 
 void BridgeAccessible::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAccessible};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::ACCESSIBLE)};
   AddGetPropertyToInterface(desc, "ChildCount", &BridgeAccessible::GetChildCount);
   AddGetPropertyToInterface(desc, "Name", &BridgeAccessible::GetName);
   AddGetPropertyToInterface(desc, "Description", &BridgeAccessible::GetDescription);
@@ -410,7 +410,7 @@ void BridgeAccessible::RegisterInterfaces()
   AddFunctionToInterface(desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName);
   AddFunctionToInterface(desc, "GetState", &BridgeAccessible::GetStates);
   AddFunctionToInterface(desc, "GetAttributes", &BridgeAccessible::GetAttributes);
-  AddFunctionToInterface(desc, "GetInterfaces", &BridgeAccessible::GetInterfaces);
+  AddFunctionToInterface(desc, "GetInterfaces", &BridgeAccessible::GetInterfacesAsStrings);
   AddFunctionToInterface(desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex);
   AddFunctionToInterface(desc, "GetChildren", &BridgeAccessible::GetChildren);
   AddFunctionToInterface(desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent);
@@ -423,6 +423,11 @@ void BridgeAccessible::RegisterInterfaces()
   mDbusServer.addInterface("/", desc, true);
 }
 
+Accessible* BridgeAccessible::FindSelf() const
+{
+  return FindCurrentObject();
+}
+
 Component* BridgeAccessible::GetObjectInRelation(Accessible* obj, RelationType relationType)
 {
   if(!obj)
@@ -513,7 +518,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
   double minimumIncrement = 0.0;
   double maximumValue     = 0.0;
   double minimumValue     = 0.0;
-  auto*  valueInterface   = dynamic_cast<Dali::Accessibility::Value*>(self);
+  auto*  valueInterface   = Value::DownCast(self);
   if(valueInterface)
   {
     currentValue     = valueInterface->GetCurrent();
@@ -524,7 +529,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
 
   int32_t firstSelectedChildIndex = -1;
   int32_t selectedChildCount      = 0;
-  auto*   selfSelectionInterface  = dynamic_cast<Dali::Accessibility::Selection*>(self);
+  auto*   selfSelectionInterface  = Selection::DownCast(self);
   if(selfSelectionInterface)
   {
     selectedChildCount      = selfSelectionInterface->GetSelectedChildrenCount();
@@ -558,7 +563,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
     listChildrenCount = GetItemCountOfFirstDescendantContainer(self, Role::POPUP_MENU, Role::MENU_ITEM, false);
   }
 
-  auto*       textInterface         = dynamic_cast<Dali::Accessibility::Text*>(self);
+  auto*       textInterface         = Text::DownCast(self);
   std::string nameFromTextInterface = "";
   if(textInterface)
   {
@@ -578,7 +583,7 @@ BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
   auto  parentChildCount         = parent ? static_cast<int32_t>(parent->GetChildCount()) : 0;
   auto  parentStateSet           = parent ? parent->GetStates() : States{};
   bool  isSelectedInParent       = false;
-  auto* parentSelectionInterface = dynamic_cast<Dali::Accessibility::Selection*>(parent);
+  auto* parentSelectionInterface = Selection::DownCast(parent);
   if(parentSelectionInterface)
   {
     isSelectedInParent = parentSelectionInterface->IsChildSelected(indexInParent);
@@ -1014,9 +1019,9 @@ DBus::ValueOrError<std::unordered_map<std::string, std::string>> BridgeAccessibl
   return attributes;
 }
 
-DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfaces()
+DBus::ValueOrError<std::vector<std::string>> BridgeAccessible::GetInterfacesAsStrings()
 {
-  return FindSelf()->GetInterfaces();
+  return FindSelf()->GetInterfacesAsStrings();
 }
 
 int BridgeAccessible::GetChildCount()
index 3ca2223..219c530 100644 (file)
@@ -45,6 +45,13 @@ protected:
    */
   void RegisterInterfaces();
 
+  /**
+   * @brief Returns the Accessible object of the currently executed DBus method call.
+   *
+   * @return The Accessible object
+   */
+  Dali::Accessibility::Accessible* FindSelf() const;
+
 public:
   /**
    * @brief Enumeration for NeighborSearchMode.
@@ -147,9 +154,9 @@ public:
   DBus::ValueOrError<std::unordered_map<std::string, std::string>> GetAttributes();
 
   /**
-   * @copydoc Dali::Accessibility::Accessible::GetInterfaces()
+   * @copydoc Dali::Accessibility::Accessible::GetInterfacesAsStrings()
    */
-  DBus::ValueOrError<std::vector<std::string>> GetInterfaces();
+  DBus::ValueOrError<std::vector<std::string>> GetInterfacesAsStrings();
 
   /**
    * @brief Gets Accessible object on which surface lies the point with given coordinates.
index 9db679f..90d1674 100644 (file)
 // CLASS HEADER
 #include <dali/internal/accessibility/bridge/bridge-action.h>
 
-// EXTERNAL INCLUDES
-#include <iostream>
-
 using namespace Dali::Accessibility;
 
 void BridgeAction::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAction};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::ACTION)};
 
   AddGetPropertyToInterface(desc, "NActions", &BridgeAction::GetActionCount);
 
@@ -40,14 +37,7 @@ void BridgeAction::RegisterInterfaces()
 
 Action* BridgeAction::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto actionInterface = dynamic_cast<Action*>(self);
-  if(!actionInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Action interface"};
-  }
-  return actionInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::ACTION>();
 }
 
 DBus::ValueOrError<std::string> BridgeAction::GetActionName(int32_t index)
index 00e5c19..9806bad 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeApplication::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceApplication};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::APPLICATION)};
   AddGetPropertyToInterface(desc, "ToolkitName", &BridgeApplication::GetToolkitName);
   AddGetPropertyToInterface(desc, "Version", &BridgeApplication::GetVersion);
   mDbusServer.addInterface("/", desc, true);
@@ -33,14 +33,7 @@ void BridgeApplication::RegisterInterfaces()
 
 Application* BridgeApplication::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto appInterface = dynamic_cast<Application*>(self);
-  if(!appInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Application interface"};
-  }
-  return appInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::APPLICATION>();
 }
 
 std::string BridgeApplication::GetToolkitName()
index 8e4f805..983bbe3 100644 (file)
@@ -135,17 +135,17 @@ BridgeBase::ForceUpResult BridgeBase::ForceUp()
   mDbusServer     = {mConnectionPtr};
 
   {
-    DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCache};
+    DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::CACHE)};
     AddFunctionToInterface(desc, "GetItems", &BridgeBase::GetItems);
     mDbusServer.addInterface(AtspiDbusPathCache, desc);
   }
   {
-    DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceApplication};
+    DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::APPLICATION)};
     AddGetSetPropertyToInterface(desc, "Id", &BridgeBase::GetId, &BridgeBase::SetId);
     mDbusServer.addInterface(AtspiPath, desc);
   }
 
-  mRegistry = {AtspiDbusNameRegistry, AtspiDbusPathRegistry, AtspiDbusInterfaceRegistry, mConnectionPtr};
+  mRegistry = {AtspiDbusNameRegistry, AtspiDbusPathRegistry, Accessible::GetInterfaceName(AtspiInterface::REGISTRY), mConnectionPtr};
 
   UpdateRegisteredEvents();
 
@@ -317,7 +317,7 @@ Accessible* BridgeBase::Find(const Address& ptr) const
   return Find(ptr.GetPath());
 }
 
-Accessible* BridgeBase::FindSelf() const
+Accessible* BridgeBase::FindCurrentObject() const
 {
   auto path = DBus::DBusServer::getCurrentObjectPath();
   auto size = strlen(AtspiPath);
@@ -385,7 +385,7 @@ auto BridgeBase::CreateCacheElement(Accessible* item) -> CacheElementType
     root->GetAddress(),
     parent ? parent->GetAddress() : Address{},
     children,
-    item->GetInterfaces(),
+    item->GetInterfacesAsStrings(),
     item->GetName(),
     item->GetRole(),
     item->GetDescription(),
index cdffa9e..5e1ffca 100644 (file)
@@ -425,14 +425,52 @@ public:
   /**
    * @brief Returns the target object of the currently executed DBus method call.
    *
-   * And any subclasses redefine `FindSelf` with a different return type as a convenient wrapper around dynamic_cast.
    * @return The Accessible object
    * @note When a DBus method is called on some object, this target object (`currentObject`) is temporarily saved by the bridge,
    * because DBus handles the invocation target separately from the method arguments.
    * We then use the saved object inside the 'glue' method (e.g. BridgeValue::GetMinimum)
    * to call the equivalent method on the respective C++ object (this could be ScrollBar::AccessibleImpl::GetMinimum in the example given).
    */
-  Dali::Accessibility::Accessible* FindSelf() const;
+  Dali::Accessibility::Accessible* FindCurrentObject() const;
+
+  /**
+   * @brief Returns the target object of the currently executed DBus method call.
+   *
+   * This method tries to downcast the return value of FindCurrentObject() to the requested type,
+   * issuing an error reply to the DBus caller if the requested type is not implemented. Whether
+   * a given type is implemented is decided based on the return value of Accessible::GetInterfaces()
+   * for the current object.
+   *
+   * @tparam I The requested AT-SPI interface
+   * @return The Accessible object (cast to a more derived type)
+   *
+   * @see FindCurrentObject()
+   * @see Dali::Accessibility::AtspiInterface
+   * @see Dali::Accessibility::AtspiInterfaceType
+   * @see Dali::Accessibility::Accessible::GetInterfaces()
+   */
+  template<Dali::Accessibility::AtspiInterface I>
+  auto* FindCurrentObjectWithInterface() const
+  {
+    using Type = Dali::Accessibility::AtspiInterfaceType<I>;
+
+    Type* result;
+    auto* currentObject = FindCurrentObject();
+    DALI_ASSERT_DEBUG(currentObject); // FindCurrentObject() throws domain_error
+
+    if(!(result = Dali::Accessibility::Accessible::DownCast<I>(currentObject)))
+    {
+      std::stringstream s;
+
+      s << "Object " << currentObject->GetAddress().ToString();
+      s << " does not implement ";
+      s << Dali::Accessibility::Accessible::GetInterfaceName(I);
+
+      throw std::domain_error{s.str()};
+    }
+
+    return result;
+  }
 
   /**
    * @copydoc Dali::Accessibility::Bridge::FindByPath()
index 413e23c..497863b 100644 (file)
@@ -20,7 +20,6 @@
 
 // EXTERNAL INCLUDES
 #include <algorithm>
-#include <iostream>
 #include <unordered_set>
 #include <vector>
 
@@ -46,21 +45,14 @@ enum class AtspiCollection
 
 void BridgeCollection::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCollection};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::COLLECTION)};
   AddFunctionToInterface(desc, "GetMatches", &BridgeCollection::GetMatches);
   mDbusServer.addInterface("/", desc, true);
 }
 
 Collection* BridgeCollection::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto collectionInterface = dynamic_cast<Collection*>(self);
-  if(!collectionInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Collection interface"};
-  }
-  return collectionInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::COLLECTION>();
 }
 
 /**
@@ -128,7 +120,7 @@ struct BridgeCollection::Comparer
     void Update(Accessible* obj)
     {
       mObject.clear();
-      for(auto& interface : obj->GetInterfaces())
+      for(auto& interface : obj->GetInterfacesAsStrings())
       {
         mObject.insert(std::move(interface));
       }
@@ -485,7 +477,7 @@ void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& res
 DBus::ValueOrError<std::vector<Accessible*> > BridgeCollection::GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse)
 {
   std::vector<Accessible*> res;
-  auto                     self    = BridgeBase::FindSelf();
+  auto                     self    = BridgeBase::FindCurrentObject();
   auto                     matcher = Comparer{&rule};
   VisitNodes(self, res, matcher, count);
 
index 64694ca..2a297f5 100644 (file)
@@ -18,9 +18,6 @@
 // CLASS HEADER
 #include <dali/internal/accessibility/bridge/bridge-component.h>
 
-// EXTERNAL INCLUDES
-#include <iostream>
-
 #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
 
 using namespace Dali::Accessibility;
@@ -35,7 +32,7 @@ void BridgeComponent::RegisterInterfaces()
   // Screen Reader will call the methods with the exact names as specified in the AT-SPI Component interface:
   // https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/master/xml/Component.xml
 
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceComponent};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::COMPONENT)};
   AddFunctionToInterface(desc, "Contains", &BridgeComponent::IsAccessibleContainingPoint);
   AddFunctionToInterface(desc, "GetAccessibleAtPoint", &BridgeComponent::GetAccessibleAtPoint);
   AddFunctionToInterface(desc, "GetExtents", &BridgeComponent::GetExtents);
@@ -52,14 +49,7 @@ void BridgeComponent::RegisterInterfaces()
 
 Component* BridgeComponent::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto componentInterface = dynamic_cast<Component*>(self);
-  if(!componentInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Component interface"};
-  }
-  return componentInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::COMPONENT>();
 }
 
 DBus::ValueOrError<bool> BridgeComponent::IsAccessibleContainingPoint(int32_t x, int32_t y, uint32_t coordType)
index 3de8dc5..034885a 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeEditableText::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceEditableText};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::EDITABLE_TEXT)};
   AddFunctionToInterface(desc, "CopyText", &BridgeEditableText::CopyText);
   AddFunctionToInterface(desc, "CutText", &BridgeEditableText::CutText);
   AddFunctionToInterface(desc, "DeleteText", &BridgeEditableText::DeleteText);
@@ -37,14 +37,7 @@ void BridgeEditableText::RegisterInterfaces()
 
 EditableText* BridgeEditableText::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto editableTextInterface = dynamic_cast<EditableText*>(self);
-  if(!editableTextInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Text interface"};
-  }
-  return editableTextInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::EDITABLE_TEXT>();
 }
 
 DBus::ValueOrError<bool> BridgeEditableText::CopyText(int32_t startPosition, int32_t endPosition)
index 4395ff0..992d2cf 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeHyperlink::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceHyperlink};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::HYPERLINK)};
   AddGetPropertyToInterface(desc, "NAnchors", &BridgeHyperlink::GetAnchorCount);
   AddGetPropertyToInterface(desc, "StartIndex", &BridgeHyperlink::GetStartIndex);
   AddGetPropertyToInterface(desc, "EndIndex", &BridgeHyperlink::GetEndIndex);
@@ -37,14 +37,7 @@ void BridgeHyperlink::RegisterInterfaces()
 
 Hyperlink* BridgeHyperlink::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto hyperlinkInterface = dynamic_cast<Hyperlink*>(self);
-  if(!hyperlinkInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Hyperlink interface"};
-  }
-  return hyperlinkInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::HYPERLINK>();
 }
 
 DBus::ValueOrError<int32_t> BridgeHyperlink::GetEndIndex()
index 3a42d8d..b5f3b3b 100644 (file)
@@ -25,7 +25,7 @@ using namespace Dali::Accessibility;
 
 void BridgeHypertext::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceHypertext};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::HYPERTEXT)};
   AddFunctionToInterface(desc, "GetNLinks", &BridgeHypertext::GetLinkCount);
   AddFunctionToInterface(desc, "GetLink", &BridgeHypertext::GetLink);
   AddFunctionToInterface(desc, "GetLinkIndex", &BridgeHypertext::GetLinkIndex);
@@ -34,14 +34,7 @@ void BridgeHypertext::RegisterInterfaces()
 
 Hypertext* BridgeHypertext::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto hypertextInterface = dynamic_cast<Hypertext*>(self);
-  if(!hypertextInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Hypertext interface"};
-  }
-  return hypertextInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::HYPERTEXT>();
 }
 
 DBus::ValueOrError<int32_t> BridgeHypertext::GetLinkCount()
index 0d48895..e5bc0ca 100644 (file)
@@ -329,7 +329,7 @@ public:
 
     RegisterOnBridge(&mApplication);
 
-    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, mConnectionPtr};
+    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, Accessible::GetInterfaceName(AtspiInterface::DEVICE_EVENT_CONTROLLER), mConnectionPtr};
     mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
 
     mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
@@ -344,7 +344,7 @@ public:
       }
     });
 
-    auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, mConnectionPtr};
+    auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, Accessible::GetInterfaceName(AtspiInterface::SOCKET), mConnectionPtr};
     Address root{"", "root"};
     auto    res = proxy.method<Address(Address)>("Embed").call(root);
     if(!res)
index 5a3847c..fc1834b 100644 (file)
@@ -41,7 +41,7 @@ BridgeObject::BridgeObject()
 
 void BridgeObject::RegisterInterfaces()
 {
-  // DBus::DBusInterfaceDescription desc{ AtspiDbusInterfaceEventObject };
+  // DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT)};
   // mStateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
   // mDbusServer.addInterface("/", desc, true);
 }
@@ -57,7 +57,7 @@ void BridgeObject::EmitActiveDescendantChanged(Accessible* obj, Accessible* chil
 
   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<Address>, Address>(
     GetAccessiblePath(obj),
-    AtspiDbusInterfaceEventObject,
+    Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
     "ActiveDescendantChanged",
     "",
     index,
@@ -87,7 +87,7 @@ void BridgeObject::Emit(Accessible* obj, ObjectPropertyChangeEvent event)
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "PropertyChange",
       std::string{eventName->second},
       0,
@@ -132,7 +132,7 @@ void BridgeObject::Emit(Accessible* obj, WindowEvent event, unsigned int detail)
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventWindow,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_WINDOW),
       std::string{eventName->second},
       "",
       detail,
@@ -204,7 +204,7 @@ void BridgeObject::EmitStateChanged(Accessible* obj, State state, int newValue,
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "StateChanged",
       std::string{stateName->second},
       newValue,
@@ -227,7 +227,7 @@ void BridgeObject::EmitBoundsChanged(Accessible* obj, Dali::Rect<> rect)
   AddFilteredEvent(FilteredEvents::BOUNDS_CHANGED, obj, 1.0f, [=]() {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::tuple<int32_t, int32_t, int32_t, int32_t> >, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "BoundsChanged",
       "",
       0,
@@ -246,7 +246,7 @@ void BridgeObject::EmitCursorMoved(Accessible* obj, unsigned int cursorPosition)
 
   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
     GetAccessiblePath(obj),
-    AtspiDbusInterfaceEventObject,
+    Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
     "TextCaretMoved",
     "",
     cursorPosition,
@@ -273,7 +273,7 @@ void BridgeObject::EmitTextChanged(Accessible* obj, TextChangedState state, unsi
   {
     mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<std::string>, Address>(
       GetAccessiblePath(obj),
-      AtspiDbusInterfaceEventObject,
+      Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
       "TextChanged",
       std::string{stateName->second},
       position,
@@ -292,7 +292,7 @@ void BridgeObject::EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType
 
   mDbusServer.emit2<std::string, int, int, DBus::EldbusVariant<int>, Address>(
     GetAccessiblePath(obj),
-    AtspiDbusInterfaceEventObject,
+    Accessible::GetInterfaceName(AtspiInterface::EVENT_OBJECT),
     "MoveOuted",
     "",
     static_cast<int>(type),
index 942bd97..0713670 100644 (file)
@@ -22,7 +22,7 @@ using namespace Dali::Accessibility;
 
 void BridgeSelection::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceSelection};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::SELECTION)};
   AddGetPropertyToInterface(desc, "NSelectedChildren", &BridgeSelection::GetSelectedChildrenCount);
   AddFunctionToInterface(desc, "GetSelectedChild", &BridgeSelection::GetSelectedChild);
   AddFunctionToInterface(desc, "SelectChild", &BridgeSelection::SelectChild);
@@ -36,14 +36,7 @@ void BridgeSelection::RegisterInterfaces()
 
 Selection* BridgeSelection::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto selectionInterface = dynamic_cast<Selection*>(self);
-  if(!selectionInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Selection interface"};
-  }
-  return selectionInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::SELECTION>();
 }
 
 DBus::ValueOrError<int32_t> BridgeSelection::GetSelectedChildrenCount()
index 1ba0073..aec0ada 100644 (file)
@@ -29,7 +29,7 @@ void BridgeText::RegisterInterfaces()
   // Screen Reader will call the methods with the exact names as specified in the AT-SPI Text interface:
   // https://gitlab.gnome.org/GNOME/at-spi2-core/-/blob/master/xml/Text.xml
 
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceText};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::TEXT)};
   AddFunctionToInterface(desc, "GetText", &BridgeText::GetText);
   AddGetPropertyToInterface(desc, "CharacterCount", &BridgeText::GetCharacterCount);
   AddGetPropertyToInterface(desc, "CaretOffset", &BridgeText::GetCursorOffset);
@@ -43,14 +43,7 @@ void BridgeText::RegisterInterfaces()
 
 Text* BridgeText::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto textInterface = dynamic_cast<Text*>(self);
-  if(!textInterface)
-  {
-    throw std::domain_error{"Object " + self->GetAddress().ToString() + " doesn't have Text interface"};
-  }
-  return textInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::TEXT>();
 }
 
 DBus::ValueOrError<std::string> BridgeText::GetText(int startOffset, int endOffset)
index 7f81a32..8ac9007 100644 (file)
@@ -18,9 +18,6 @@
 // CLASS HEADER
 #include <dali/internal/accessibility/bridge/bridge-value.h>
 
-// EXTERNAL INCLUDES
-#include <iostream>
-
 using namespace Dali::Accessibility;
 
 BridgeValue::BridgeValue()
@@ -29,7 +26,7 @@ BridgeValue::BridgeValue()
 
 void BridgeValue::RegisterInterfaces()
 {
-  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceValue};
+  DBus::DBusInterfaceDescription desc{Accessible::GetInterfaceName(AtspiInterface::VALUE)};
   AddGetSetPropertyToInterface(desc, "CurrentValue", &BridgeValue::GetCurrentValue, &BridgeValue::SetCurrentValue);
   AddGetPropertyToInterface(desc, "MaximumValue", &BridgeValue::GetMaximumValue);
   AddGetPropertyToInterface(desc, "MinimumIncrement", &BridgeValue::GetMinimumIncrement);
@@ -39,14 +36,7 @@ void BridgeValue::RegisterInterfaces()
 
 Value* BridgeValue::FindSelf() const
 {
-  auto self = BridgeBase::FindSelf();
-  assert(self);
-  auto valueInterface = dynamic_cast<Value*>(self);
-  if(!valueInterface)
-  {
-    throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have Value interface"};
-  }
-  return valueInterface;
+  return FindCurrentObjectWithInterface<Dali::Accessibility::AtspiInterface::VALUE>();
 }
 
 double BridgeValue::GetCurrentValue()
index d7f7016..5205da5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -55,30 +55,47 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask)
   int srcOffset  = 0;
   int destOffset = 0;
 
-  float srcAlphaValue = 1.0f;
-
   // if image is premultiplied, the other channels of the image need to multiply by alpha.
   if(buffer.IsAlphaPreMultiplied())
   {
-    for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
+    // Collect all valid channel list before lookup whole buffer
+    std::vector<Channel> validChannelList;
+    for(const Channel& channel : {Adaptor::RED, Adaptor::GREEN, Adaptor::BLUE, Adaptor::LUMINANCE, Adaptor::ALPHA})
     {
-      for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
+      if(HasChannel(destPixelFormat, channel))
       {
-        auto srcAlpha      = ReadChannel(srcBuffer + srcOffset, srcPixelFormat, Adaptor::ALPHA);
-        auto destRed       = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::RED);
-        auto destGreen     = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::GREEN);
-        auto destBlue      = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::BLUE);
-        auto destLuminance = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::LUMINANCE);
-        auto destAlpha     = ReadChannel(destBuffer + destOffset, destPixelFormat, Adaptor::ALPHA);
-
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::RED, destRed * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::GREEN, destGreen * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::BLUE, destBlue * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::LUMINANCE, destLuminance * srcAlpha / 255);
-        WriteChannel(destBuffer + destOffset, destPixelFormat, Adaptor::ALPHA, destAlpha * srcAlpha / 255);
-
-        srcOffset += srcBytesPerPixel;
-        destOffset += destBytesPerPixel;
+        validChannelList.emplace_back(channel);
+      }
+    }
+    if(DALI_LIKELY(!validChannelList.empty()))
+    {
+      for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
+      {
+        for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
+        {
+          auto srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+          if(srcAlpha < 255)
+          {
+            // If alpha is 255, we don't need to change color. Skip current pixel
+            // But if alpha is not 255, we should change color.
+            if(srcAlpha > 0)
+            {
+              for(const Channel& channel : validChannelList)
+              {
+                auto color = ReadChannel(destBuffer + destOffset, destPixelFormat, channel);
+                WriteChannel(destBuffer + destOffset, destPixelFormat, channel, color * srcAlpha / 255);
+              }
+            }
+            else
+            {
+              // If alpha is 0, just set all pixel as zero.
+              memset(destBuffer + destOffset, 0, destBytesPerPixel);
+            }
+          }
+
+          srcOffset += srcBytesPerPixel;
+          destOffset += destBytesPerPixel;
+        }
       }
     }
   }
@@ -88,12 +105,11 @@ void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask)
     {
       for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
       {
-        unsigned char alpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
-        srcAlphaValue       = float(alpha) / 255.0f;
+        unsigned char srcAlpha  = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+        unsigned char destAlpha = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
+
+        destAlpha = (static_cast<std::uint16_t>(destAlpha) * static_cast<std::uint16_t>(srcAlpha)) / 255;
 
-        unsigned char destAlpha      = destBuffer[destOffset + destAlphaByteOffset] & destAlphaMask;
-        float         destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
-        destAlpha                    = destAlphaValue;
         destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
         destBuffer[destOffset + destAlphaByteOffset] |= (destAlpha & destAlphaMask);
 
@@ -143,27 +159,24 @@ PixelBufferPtr CreateNewMaskedBuffer(const PixelBuffer& buffer, const PixelBuffe
   int  destOffset     = 0;
   bool hasAlpha       = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
 
-  float         srcAlphaValue = 1.0f;
-  unsigned char destAlpha     = 0;
+  unsigned char destAlpha = 0;
 
   for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
   {
     for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
     {
-      unsigned char alpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
-      srcAlphaValue       = float(alpha) / 255.0f;
+      unsigned char srcAlpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
 
       ConvertColorChannelsToRGBA8888(oldBuffer, srcColorOffset, srcColorPixelFormat, destBuffer, destOffset);
 
       if(hasAlpha)
       {
-        destAlpha            = ConvertAlphaChannelToA8(oldBuffer, srcColorOffset, srcColorPixelFormat);
-        float destAlphaValue = Clamp(float(destAlpha) * srcAlphaValue, 0.0f, 255.0f);
-        destAlpha            = destAlphaValue;
+        destAlpha = ConvertAlphaChannelToA8(oldBuffer, srcColorOffset, srcColorPixelFormat);
+        destAlpha = (static_cast<std::uint16_t>(destAlpha) * static_cast<std::uint16_t>(srcAlpha)) / 255;
       }
       else
       {
-        destAlpha = floorf(Clamp(srcAlphaValue * 255.0f, 0.0f, 255.0f));
+        destAlpha = srcAlpha;
       }
 
       destBuffer[destOffset + destAlphaByteOffset] &= ~destAlphaMask;
index 44f8c03..8caaca5 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_ADAPTOR_ALPHA_MASK_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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,17 +25,19 @@ namespace Internal
 namespace Adaptor
 {
 /**
- * Apply the mask to a buffer's alpha channel
+ * @brief Apply the mask to a buffer's alpha channel
+ * @note It works well only if mask's alpha mask is 8bit
  * @param[in] buffer The buffer to apply the mask to
  * @param[in] mask The mask to apply
  */
 void ApplyMaskToAlphaChannel(PixelBuffer& buffer, const PixelBuffer& mask);
 
 /**
- * Create a new PixelBuffer with an alpha channel large enough to handle the alpha from
+ * @brief Create a new PixelBuffer with an alpha channel large enough to handle the alpha from
  * the mask, converting the color values to the new size, and either multiplying the mask's
  * alpha into the existing alpha value, or writing the mask's alpha value directly into
  * the new buffer's alpha channel.
+ * @note It works well only if mask's alpha mask is 8bit
  *
  * @param[in] buffer The buffer to apply the mask to
  * @param[in] mask The mask to apply
index d0c7f79..772d26f 100644 (file)
@@ -1367,10 +1367,51 @@ void HalveScanlineInPlace1Byte(unsigned char* const pixels, const unsigned int w
   }
 }
 
+// AverageScanline
+
+namespace
+{
 /**
- * @ToDo: Optimise for ARM using a 4 bytes at a time loop wrapped around the single ARMV6 instruction: UHADD8  R4, R0, R5. Note, this is not neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro, or extra power for clocking-up the idle copro.
- * if (widthInComponents >= 7) { word32* aligned1 = scanline1 + 3 & 3; word32* aligned1_end = scanline1 + widthInPixels & 3; while(aligned1 < aligned1_end) { UHADD8  *aligned1++, *aligned2++, *alignedoutput++ } .. + 0 to 3 spare pixels at each end.
+ * @copydoc AverageScanlines1
+ * @note This API average eight components in one operation.
+ * It will give performance benifit.
  */
+inline void AverageScanlinesWithEightComponents(
+  const unsigned char* const scanline1,
+  const unsigned char* const __restrict__ scanline2,
+  unsigned char* const outputScanline,
+  const unsigned int   totalComponentCount)
+{
+  unsigned int component = 0;
+  if(DALI_LIKELY(totalComponentCount >= 8))
+  {
+    // Jump 8 components in one step
+    const std::uint64_t* const scanline18Step = reinterpret_cast<const std::uint64_t* const>(scanline1);
+    const std::uint64_t* const scanline28Step = reinterpret_cast<const std::uint64_t* const>(scanline2);
+    std::uint64_t* const       output8step    = reinterpret_cast<std::uint64_t* const>(outputScanline);
+
+    const std::uint32_t totalStepCount = (totalComponentCount) >> 3;
+    component                          = totalStepCount << 3;
+
+    // and for each step, calculate average of 8 bytes.
+    for(std::uint32_t i = 0; i < totalStepCount; ++i)
+    {
+      const auto& c1     = *(scanline18Step + i);
+      const auto& c2     = *(scanline28Step + i);
+      *(output8step + i) = static_cast<std::uint64_t>((((c1 ^ c2) & 0xfefefefefefefefeull) >> 1) + (c1 & c2));
+    }
+  }
+  // remaining components calculate
+  for(; component < totalComponentCount; ++component)
+  {
+    const auto& c1            = scanline1[component];
+    const auto& c2            = scanline2[component];
+    outputScanline[component] = static_cast<std::uint8_t>(((c1 ^ c2) >> 1) + (c1 & c2));
+  }
+}
+
+} // namespace
+
 void AverageScanlines1(const unsigned char* const scanline1,
                        const unsigned char* const __restrict__ scanline2,
                        unsigned char* const outputScanline,
@@ -1378,10 +1419,15 @@ void AverageScanlines1(const unsigned char* const scanline1,
 {
   DebugAssertDualScanlineParameters(scanline1, scanline2, outputScanline, width);
 
-  for(unsigned int component = 0; component < width; ++component)
-  {
-    outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
-  }
+  /**
+   * @code
+   * for(unsigned int component = 0; component < width; ++component)
+   * {
+   *   outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
+   * }
+   * @endcode
+   */
+  AverageScanlinesWithEightComponents(scanline1, scanline2, outputScanline, width);
 }
 
 void AverageScanlines2(const unsigned char* const scanline1,
@@ -1391,10 +1437,15 @@ void AverageScanlines2(const unsigned char* const scanline1,
 {
   DebugAssertDualScanlineParameters(scanline1, scanline2, outputScanline, width * 2);
 
-  for(unsigned int component = 0; component < width * 2; ++component)
-  {
-    outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
-  }
+  /**
+   * @code
+   * for(unsigned int component = 0; component < width * 2; ++component)
+   * {
+   *   outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
+   * }
+   * @endcode
+   */
+  AverageScanlinesWithEightComponents(scanline1, scanline2, outputScanline, width * 2);
 }
 
 void AverageScanlines3(const unsigned char* const scanline1,
@@ -1404,10 +1455,15 @@ void AverageScanlines3(const unsigned char* const scanline1,
 {
   DebugAssertDualScanlineParameters(scanline1, scanline2, outputScanline, width * 3);
 
-  for(unsigned int component = 0; component < width * 3; ++component)
-  {
-    outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
-  }
+  /**
+   * @code
+   * for(unsigned int component = 0; component < width * 3; ++component)
+   * {
+   *   outputScanline[component] = static_cast<unsigned char>(AverageComponent(scanline1[component], scanline2[component]));
+   * }
+   * @endcode
+   */
+  AverageScanlinesWithEightComponents(scanline1, scanline2, outputScanline, width * 3);
 }
 
 void AverageScanlinesRGBA8888(const unsigned char* const scanline1,
@@ -1472,29 +1528,38 @@ void DownscaleInPlacePow2(unsigned char* const pixels,
     {
       const BoxDimensionTest dimensionTest = DimensionTestForScalingMode(fittingMode);
 
-      if(pixelFormat == Pixel::RGBA8888)
-      {
-        Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::RGB888)
-      {
-        Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::RGB565)
-      {
-        Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::LA88)
-      {
-        Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else if(pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
+      switch(pixelFormat)
       {
-        Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
-      }
-      else
-      {
-        DALI_ASSERT_DEBUG(false && "Inner branch conditions don't match outer branch.");
+        case Pixel::RGBA8888:
+        {
+          Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          break;
+        }
+        case Pixel::RGB888:
+        {
+          Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          break;
+        }
+        case Pixel::RGB565:
+        {
+          Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          break;
+        }
+        case Pixel::LA88:
+        {
+          Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          break;
+        }
+        case Pixel::L8:
+        case Pixel::A8:
+        {
+          Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+          break;
+        }
+        default:
+        {
+          DALI_ASSERT_DEBUG(false && "Inner branch conditions don't match outer branch.");
+        }
       }
     }
   }
@@ -1570,6 +1635,8 @@ void DownscaleInPlacePow2SingleBytePerPixel(unsigned char*   pixels,
   DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
 }
 
+// Point sampling group below
+
 namespace
 {
 /**
@@ -1731,25 +1798,34 @@ void PointSample(const unsigned char* inPixels,
   // Check the pixel format is one that is supported:
   if(pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
   {
-    if(pixelFormat == Pixel::RGB888)
+    switch(pixelFormat)
     {
-      PointSample3BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else if(pixelFormat == Pixel::RGBA8888)
-    {
-      PointSample4BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else if(pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88)
-    {
-      PointSample2BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else if(pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
-    {
-      PointSample1BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
-    }
-    else
-    {
-      DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      case Pixel::RGB888:
+      {
+        PointSample3BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      case Pixel::RGBA8888:
+      {
+        PointSample4BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      case Pixel::RGB565:
+      case Pixel::LA88:
+      {
+        PointSample2BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      case Pixel::L8:
+      case Pixel::A8:
+      {
+        PointSample1BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      }
     }
   }
   else
@@ -2134,29 +2210,38 @@ void LinearSample(const unsigned char* __restrict__ inPixels,
   // Check the pixel format is one that is supported:
   if(pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::RGB565)
   {
-    if(pixelFormat == Pixel::RGB888)
-    {
-      LinearSample3BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::RGBA8888)
-    {
-      LinearSample4BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8)
-    {
-      LinearSample1BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::LA88)
+    switch(pixelFormat)
     {
-      LinearSample2BPP(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else if(pixelFormat == Pixel::RGB565)
-    {
-      LinearSampleRGB565(inPixels, inDimensions, outPixels, outDimensions);
-    }
-    else
-    {
-      DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      case Pixel::RGB888:
+      {
+        LinearSample3BPP(inPixels, inDimensions, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::RGBA8888:
+      {
+        LinearSample4BPP(inPixels, inDimensions, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::L8:
+      case Pixel::A8:
+      {
+        LinearSample1BPP(inPixels, inDimensions, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::LA88:
+      {
+        LinearSample2BPP(inPixels, inDimensions, outPixels, outDimensions);
+        break;
+      }
+      case Pixel::RGB565:
+      {
+        LinearSampleRGB565(inPixels, inDimensions, outPixels, outDimensions);
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_DEBUG(0 == "Inner branch conditions don't match outer branch.");
+      }
     }
   }
   else
index dd8db98..d1105ad 100644 (file)
@@ -580,9 +580,14 @@ inline uint32_t AveragePixelRGB565(uint32_t a, uint32_t b)
 inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend)
 {
   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
-  const unsigned int weightedAFixed = a * (65535u - fractBlend);
-  const unsigned int weightedBFixed = b * fractBlend;
-  const unsigned     blended        = (weightedAFixed + weightedBFixed);
+  /**
+   * @code
+   * const unsigned int weightedAFixed = a * (65535u - fractBlend);
+   * const unsigned int weightedBFixed = b * fractBlend;
+   * const unsigned     blended        = (weightedAFixed + weightedBFixed);
+   * @endcode
+   */
+  const unsigned int blended = (a << 16) - a + (static_cast<int32_t>(b) - static_cast<int32_t>(a)) * fractBlend;
   return blended;
 }
 
@@ -590,10 +595,15 @@ inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b,
 inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend)
 {
   DALI_ASSERT_DEBUG(fractBlend <= 65535u && "Factor should be in 0.16 fixed-point.");
-  // Blend while promoting intermediates to 16.32 fixed point:
-  const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
-  const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
-  const uint64_t blended        = (weightedAFixed + weightedBFixed);
+  /**
+   * @code
+   * // Blend while promoting intermediates to 16.32 fixed point:
+   * const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
+   * const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
+   * const uint64_t blended        = (weightedAFixed + weightedBFixed);
+   * @endcode
+   */
+  const uint64_t blended = (static_cast<uint64_t>(a) << 16) - a + (static_cast<int64_t>(b) - static_cast<int64_t>(a)) * fractBlend;
   return blended;
 }
 
@@ -605,9 +615,44 @@ inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, u
   DALI_ASSERT_DEBUG(fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point.");
   DALI_ASSERT_DEBUG(fractBlendVertical <= 65535u && "Factor should be in 0.16 fixed-point.");
 
-  const unsigned int topBlend   = WeightedBlendIntToFixed1616(tl, tr, fractBlendHorizontal);
-  const unsigned int botBlend   = WeightedBlendIntToFixed1616(bl, br, fractBlendHorizontal);
-  const uint64_t     blended2x2 = WeightedBlendFixed1616ToFixed1632(topBlend, botBlend, fractBlendVertical);
+  /**
+   * @code
+   * const unsigned int topBlend   = WeightedBlendIntToFixed1616(tl, tr, fractBlendHorizontal);
+   * const unsigned int botBlend   = WeightedBlendIntToFixed1616(bl, br, fractBlendHorizontal);
+   * const uint64_t     blended2x2 = WeightedBlendFixed1616ToFixed1632(topBlend, botBlend, fractBlendVertical);
+   * const unsigned int rounded    = (blended2x2 + (1u << 31u)) >> 32u;
+   * @endcode
+   */
+
+  /**
+   * Hard-coding optimize!
+   *
+   * Let p = 65536, s.t we can optimze it as << 16.
+   * Let x = fractBlendHorizontal, y = fractBlendVertical.
+   * topBlend = (tl*p - tl - tl*x + tr*x)
+   * botBlend = (bl*p - bl - bl*x + br*x)
+   * blended2x2 = topBlend*p - topBlend - topBlend*y + botBlend*y
+   *
+   * And now we can split all values.
+   * tl*p*p - tl*p - tl*x*p + tr*x*p  -  tl*p + tl + tl*x - tr*x  -  tl*y*p + tl*y + tl*x*y - tr*x*y  +  bl*y*p - bl*y - bl*x*y + br*x*y;
+   * --> (collect by p, x, and y)
+   * (tl)*p*p + (-2tl + (-tl + tr)*x + (-tl+bl)*y)*p + tl + (tl - tr)*x + (tl - bl)*y + (tl - tr - bl + br)*x*y
+   *
+   * A = (tl - tr) * x;
+   * B = (tl - bl) * y;
+   * C = (tl - tr - bl + br) * x * y;
+   * D = (2*tl + A + B)
+   * -->
+   * (tl << 32) - (D << 16) + tl + A + B + C
+   *
+   * Becareful of overflow and negative value.
+   */
+  const int32_t A = (static_cast<int32_t>(tl) - static_cast<int32_t>(tr)) * static_cast<int32_t>(fractBlendHorizontal);
+  const int32_t B = (static_cast<int32_t>(tl) - static_cast<int32_t>(bl)) * static_cast<int32_t>(fractBlendVertical);
+  const int64_t C = (static_cast<int64_t>(tl) - static_cast<int64_t>(tr) - static_cast<int64_t>(bl) + static_cast<int64_t>(br)) * static_cast<int64_t>(fractBlendHorizontal) * static_cast<int64_t>(fractBlendVertical);
+  const int64_t D = ((static_cast<int64_t>(tl) << 1) + A + B);
+
+  const uint64_t     blended2x2 = (static_cast<int64_t>(tl) << 32u) - (D << 16u) + tl + A + B + C;
   const unsigned int rounded    = (blended2x2 + (1u << 31u)) >> 32u;
   return rounded;
 }
index 747dcb3..4ff2250 100644 (file)
@@ -446,31 +446,41 @@ void PixelBuffer::MultiplyColorByAlpha()
     unsigned char*     pixel      = mBuffer;
     const unsigned int bufferSize = mWidth * mHeight;
 
-    for(unsigned int i = 0; i < bufferSize; ++i)
+    // Collect all valid channel list before lookup whole buffer
+    std::vector<Channel> validChannelList;
+    for(const Channel& channel : {Adaptor::RED, Adaptor::GREEN, Adaptor::BLUE, Adaptor::LUMINANCE})
     {
-      unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
-      if(alpha < 255)
+      if(HasChannel(mPixelFormat, channel))
       {
-        // If alpha is 255, we don't need to change color. Skip current pixel
-        // But if alpha is not 255, we should change color.
-        if(alpha > 0)
-        {
-          auto red       = ReadChannel(pixel, mPixelFormat, Adaptor::RED);
-          auto green     = ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
-          auto blue      = ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
-          auto luminance = ReadChannel(pixel, mPixelFormat, Adaptor::LUMINANCE);
-          WriteChannel(pixel, mPixelFormat, Adaptor::RED, red * alpha / 255);
-          WriteChannel(pixel, mPixelFormat, Adaptor::GREEN, green * alpha / 255);
-          WriteChannel(pixel, mPixelFormat, Adaptor::BLUE, blue * alpha / 255);
-          WriteChannel(pixel, mPixelFormat, Adaptor::LUMINANCE, luminance * alpha / 255);
-        }
-        else
+        validChannelList.emplace_back(channel);
+      }
+    }
+
+    if(DALI_LIKELY(!validChannelList.empty()))
+    {
+      for(unsigned int i = 0; i < bufferSize; ++i)
+      {
+        unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
+        if(alpha < 255)
         {
-          // If alpha is 0, just set all pixel as zero.
-          memset(pixel, 0, bytesPerPixel);
+          // If alpha is 255, we don't need to change color. Skip current pixel
+          // But if alpha is not 255, we should change color.
+          if(alpha > 0)
+          {
+            for(const Channel& channel : validChannelList)
+            {
+              auto color = ReadChannel(pixel, mPixelFormat, channel);
+              WriteChannel(pixel, mPixelFormat, channel, color * alpha / 255);
+            }
+          }
+          else
+          {
+            // If alpha is 0, just set all pixel as zero.
+            memset(pixel, 0, bytesPerPixel);
+          }
         }
+        pixel += bytesPerPixel;
       }
-      pixel += bytesPerPixel;
     }
   }
   mPreMultiplied = true;
index e4c3fe0..93418d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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,13 +29,20 @@ namespace Adaptor
 {
 namespace
 {
-constexpr Channel ALPHA_CHANNEL_ONLY[]       = {ALPHA};
-constexpr Channel LUMINANCE_CHANNEL_ONLY[]   = {LUMINANCE};
-constexpr Channel LUMINANCE_ALPHA_CHANNELS[] = {LUMINANCE, ALPHA};
-constexpr Channel RGB_CHANNELS[]             = {RED, GREEN, BLUE};
-constexpr Channel BGR_CHANNELS[]             = {BLUE, GREEN, RED};
-constexpr Channel RGBA_CHANNELS[]            = {RED, GREEN, BLUE, ALPHA};
-constexpr Channel BGRA_CHANNELS[]            = {BLUE, GREEN, RED, ALPHA};
+// clang-format off
+/**
+ * @brief Pre-defined offset tables for each Channel.
+ * If invalid channel, return -1. else, return the offset bytes.
+ */
+//                                                                           | LUMINANCE | RED | GREEN | BLUE | ALPHA | DEPTH | STENCIL |
+constexpr std::int8_t ALPHA_ONLY_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]      = {        -1 ,  -1 ,    -1 ,   -1 ,     0 ,    -1 ,      -1 };
+constexpr std::int8_t LUMINANCE_ONLY_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]  = {         0 ,  -1 ,    -1 ,   -1 ,    -1 ,    -1 ,      -1 };
+constexpr std::int8_t LUMINANCE_ALPHA_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS] = {         0 ,  -1 ,    -1 ,   -1 ,     1 ,    -1 ,      -1 };
+constexpr std::int8_t RGB_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]             = {        -1 ,   0 ,     1 ,    2 ,    -1 ,    -1 ,      -1 };
+constexpr std::int8_t BGR_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]             = {        -1 ,   2 ,     1 ,    0 ,    -1 ,    -1 ,      -1 };
+constexpr std::int8_t RGBA_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]            = {        -1 ,   0 ,     1 ,    2 ,     3 ,    -1 ,      -1 };
+constexpr std::int8_t BGRA_OFFSET_TABLE[MAX_NUMBER_OF_CHANNELS]            = {        -1 ,   2 ,     1 ,    0 ,     3 ,    -1 ,      -1 };
+// clang-format on
 
 /**
  * @brief Template to Read from a buffer with pixel formats that have one byte per channel.
@@ -43,22 +50,15 @@ constexpr Channel BGRA_CHANNELS[]            = {BLUE, GREEN, RED, ALPHA};
  * @tparam NumberOfChannels The number of channels to check
  * @param pixelData The pixel data to retrieve the value from
  * @param channel The channel we're after
- * @param channels The array of channels in the pixel format
+ * @param offsetTable The array of offset bytes for each channels in the pixel format
  * @return The value of the required channel
  */
-template<size_t NumberOfChannels>
-unsigned int ReadChannel(unsigned char* pixelData, Channel channel, const Channel (&channels)[NumberOfChannels])
+unsigned int ReadChannelTable(unsigned char* pixelData, Channel channel, const std::int8_t (&offsetTable)[MAX_NUMBER_OF_CHANNELS])
 {
-  auto num    = 0u;
   auto retVal = 0u;
-  for(auto current : channels)
+  if(offsetTable[channel] >= 0)
   {
-    if(channel == current)
-    {
-      retVal = static_cast<unsigned int>(*(pixelData + num));
-      break;
-    }
-    ++num;
+    retVal = static_cast<unsigned int>(*(pixelData + offsetTable[channel]));
   }
   return retVal;
 }
@@ -70,20 +70,13 @@ unsigned int ReadChannel(unsigned char* pixelData, Channel channel, const Channe
  * @param pixelData The pixel data to write the value to
  * @param channel The channel we're after
  * @param channelValue The value of the channel to set
- * @param channels The array of channels in the pixel format
+ * @param offsetTable The array of offset bytes for each channels in the pixel format
  */
-template<size_t NumberOfChannels>
-void WriteChannel(unsigned char* pixelData, Channel channel, unsigned int channelValue, const Channel (&channels)[NumberOfChannels])
+void WriteChannelTable(unsigned char* pixelData, Channel channel, unsigned int channelValue, const std::int8_t (&offsetTable)[MAX_NUMBER_OF_CHANNELS])
 {
-  auto num = 0u;
-  for(auto current : channels)
+  if(offsetTable[channel] >= 0)
   {
-    if(channel == current)
-    {
-      *(pixelData + num) = static_cast<unsigned char>(channelValue & 0xFF);
-      break;
-    }
-    ++num;
+    *(pixelData + offsetTable[channel]) = static_cast<unsigned char>(channelValue & 0xFF);
   }
 }
 
@@ -412,15 +405,15 @@ unsigned int ReadChannel(unsigned char*      pixelData,
   {
     case Dali::Pixel::A8:
     {
-      return ReadChannel(pixelData, channel, ALPHA_CHANNEL_ONLY);
+      return ReadChannelTable(pixelData, channel, ALPHA_ONLY_OFFSET_TABLE);
     }
     case Dali::Pixel::L8:
     {
-      return ReadChannel(pixelData, channel, LUMINANCE_CHANNEL_ONLY);
+      return ReadChannelTable(pixelData, channel, LUMINANCE_ONLY_OFFSET_TABLE);
     }
     case Dali::Pixel::LA88:
     {
-      return ReadChannel(pixelData, channel, LUMINANCE_ALPHA_CHANNELS);
+      return ReadChannelTable(pixelData, channel, LUMINANCE_ALPHA_OFFSET_TABLE);
     }
     case Dali::Pixel::RGB565:
     {
@@ -435,22 +428,22 @@ unsigned int ReadChannel(unsigned char*      pixelData,
     case Dali::Pixel::RGB888:
     case Dali::Pixel::RGB8888:
     {
-      return ReadChannel(pixelData, channel, RGB_CHANNELS);
+      return ReadChannelTable(pixelData, channel, RGB_OFFSET_TABLE);
     }
 
     case Dali::Pixel::BGR8888:
     {
-      return ReadChannel(pixelData, channel, BGR_CHANNELS);
+      return ReadChannelTable(pixelData, channel, BGR_OFFSET_TABLE);
     }
 
     case Dali::Pixel::RGBA8888:
     {
-      return ReadChannel(pixelData, channel, RGBA_CHANNELS);
+      return ReadChannelTable(pixelData, channel, RGBA_OFFSET_TABLE);
     }
 
     case Dali::Pixel::BGRA8888:
     {
-      return ReadChannel(pixelData, channel, BGRA_CHANNELS);
+      return ReadChannelTable(pixelData, channel, BGRA_OFFSET_TABLE);
     }
 
     case Dali::Pixel::RGBA4444:
@@ -496,17 +489,17 @@ void WriteChannel(unsigned char*      pixelData,
   {
     case Dali::Pixel::A8:
     {
-      WriteChannel(pixelData, channel, channelValue, ALPHA_CHANNEL_ONLY);
+      WriteChannelTable(pixelData, channel, channelValue, ALPHA_ONLY_OFFSET_TABLE);
       break;
     }
     case Dali::Pixel::L8:
     {
-      WriteChannel(pixelData, channel, channelValue, LUMINANCE_CHANNEL_ONLY);
+      WriteChannelTable(pixelData, channel, channelValue, LUMINANCE_ONLY_OFFSET_TABLE);
       break;
     }
     case Dali::Pixel::LA88:
     {
-      WriteChannel(pixelData, channel, channelValue, LUMINANCE_ALPHA_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, LUMINANCE_ALPHA_OFFSET_TABLE);
       break;
     }
     case Dali::Pixel::RGB565:
@@ -524,25 +517,25 @@ void WriteChannel(unsigned char*      pixelData,
     case Dali::Pixel::RGB888:
     case Dali::Pixel::RGB8888:
     {
-      WriteChannel(pixelData, channel, channelValue, RGB_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, RGB_OFFSET_TABLE);
       break;
     }
 
     case Dali::Pixel::BGR8888:
     {
-      WriteChannel(pixelData, channel, channelValue, BGR_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, BGR_OFFSET_TABLE);
       break;
     }
 
     case Dali::Pixel::RGBA8888:
     {
-      WriteChannel(pixelData, channel, channelValue, RGBA_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, RGBA_OFFSET_TABLE);
       break;
     }
 
     case Dali::Pixel::BGRA8888:
     {
-      WriteChannel(pixelData, channel, channelValue, BGRA_CHANNELS);
+      WriteChannelTable(pixelData, channel, channelValue, BGRA_OFFSET_TABLE);
       break;
     }
 
index 1e161c9..7ed74e0 100644 (file)
@@ -27,7 +27,7 @@ namespace Dali
 {
 const unsigned int ADAPTOR_MAJOR_VERSION = 2;
 const unsigned int ADAPTOR_MINOR_VERSION = 1;
-const unsigned int ADAPTOR_MICRO_VERSION = 11;
+const unsigned int ADAPTOR_MICRO_VERSION = 12;
 const char* const  ADAPTOR_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index a974081..5690ce9 100644 (file)
@@ -17,7 +17,7 @@
 
 Name:       dali2-adaptor
 Summary:    The DALi Tizen Adaptor
-Version:    2.1.11
+Version:    2.1.12
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT